sync: to agentic-framework v1.1.192
This commit is contained in:
parent
6e9df3a7bb
commit
80fc6324fc
6 changed files with 38 additions and 19 deletions
|
|
@ -1 +1 @@
|
|||
1.1.191
|
||||
1.1.192
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ Accept self-check completion only when `## Implementation Checklist` or its supp
|
|||
## Work log
|
||||
|
||||
- Keep one dispatcher-owned `WORK_LOG.md` per task group.
|
||||
- Append chronological `START` and `FINISH` rows with UTC time, task artifact, plan loop, role, attempt, selected agent/model display, result, and locator.
|
||||
- Append chronological `START` and `FINISH` rows with KST (`Asia/Seoul`) time, task artifact, plan loop, role, attempt, selected agent/model display, result, and locator.
|
||||
- Archive the group log as the next `work_log_N.log` only after every observed task in the group is verified complete and idle.
|
||||
- Work-log write or archive failure is a retryable control-plane failure and prevents exit `0`.
|
||||
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@ import subprocess
|
|||
import sys
|
||||
import uuid
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
|
||||
_OBSERVATION_MODULE_NAME = "agent_task_dispatcher_observation"
|
||||
|
|
@ -152,7 +153,8 @@ DISPATCHER_CHILD_BOUNDARY_PROMPT = (
|
|||
)
|
||||
REPOSITORY_LANGUAGE_PROMPT = "Follow the repository's language and output rules."
|
||||
SELF_CHECK_PROMPT_PREFIX = REPOSITORY_LANGUAGE_PROMPT
|
||||
UTC = timezone.utc
|
||||
DISPATCHER_TIMEZONE_NAME = "Asia/Seoul"
|
||||
KST = ZoneInfo(DISPATCHER_TIMEZONE_NAME)
|
||||
DEFAULT_MAX_PARALLEL = 3
|
||||
|
||||
|
||||
|
|
@ -245,11 +247,11 @@ class ExecutionDecisionError(RuntimeError):
|
|||
|
||||
|
||||
def now_iso() -> str:
|
||||
return datetime.now(timezone.utc).isoformat()
|
||||
return datetime.now(KST).isoformat()
|
||||
|
||||
|
||||
def work_log_now_utc() -> str:
|
||||
return datetime.now(UTC).strftime("%y-%m-%d %H:%M:%SZ")
|
||||
def work_log_now_kst() -> str:
|
||||
return datetime.now(KST).strftime("%y-%m-%d %H:%M:%S KST")
|
||||
|
||||
|
||||
def sha256_file(path: Path | None) -> str:
|
||||
|
|
@ -452,7 +454,7 @@ def append_work_log_event(
|
|||
return str(value).replace("|", r"\|").replace("\n", " ")
|
||||
|
||||
stream.write(
|
||||
f"| {sequence} | {work_log_now_utc()} | {cell(event)} | "
|
||||
f"| {sequence} | {work_log_now_kst()} | {cell(event)} | "
|
||||
f"{cell(task_name)} | "
|
||||
f"{loop} | {cell(role)} | {attempt} | {cell(model)} | {cell(result)} | "
|
||||
f"{cell(locator.resolve())} |\n"
|
||||
|
|
@ -1773,7 +1775,7 @@ def select_execution_decision(
|
|||
transition = "resume" if prior_decision is not None else "initial"
|
||||
return selector.select_execution_target(
|
||||
_decision_file(task, stage), stage=stage,
|
||||
evaluated_at=evaluated_at or datetime.now(UTC),
|
||||
evaluated_at=evaluated_at or datetime.now(KST),
|
||||
catalog_path=EXECUTION_CATALOG_PATH,
|
||||
transition=transition,
|
||||
prior_decision=prior_decision,
|
||||
|
|
@ -1842,7 +1844,7 @@ def synthesized_official_review_decision(
|
|||
task: Task, *, evaluated_at: datetime | None = None
|
||||
) -> dict[str, Any]:
|
||||
lane, grade, work_unit_id = official_review_source_identity(task)
|
||||
evaluated = evaluated_at or datetime.now(UTC)
|
||||
evaluated = evaluated_at or datetime.now(KST)
|
||||
if evaluated.tzinfo is None or evaluated.utcoffset() is None:
|
||||
raise ExecutionDecisionError(
|
||||
"official review evaluated_at이 timezone-aware가 아니다"
|
||||
|
|
@ -2836,7 +2838,7 @@ def external_active_is_live(
|
|||
for path in root.glob("**/*.jsonl")
|
||||
]
|
||||
native = max(sessions, key=lambda path: path.stat().st_mtime_ns) if sessions else None
|
||||
now = datetime.now(timezone.utc).timestamp()
|
||||
now = datetime.now(KST).timestamp()
|
||||
runtime = locator.get("runtime")
|
||||
monitor_native_session = bool(
|
||||
isinstance(runtime, dict) and runtime.get("native_session_monitor")
|
||||
|
|
@ -3098,7 +3100,7 @@ async def invoke(
|
|||
resume_locator: Path | None = None,
|
||||
) -> tuple[int, str | None, Path]:
|
||||
attempt, identity = next_execution_identity(store, task, role)
|
||||
attempt_dir = store.runs / f"{datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ')}__{identity}"
|
||||
attempt_dir = store.runs / f"{datetime.now(KST).strftime('%Y%m%dT%H%M%S%z')}__{identity}"
|
||||
attempt_dir.mkdir(parents=True, exist_ok=False)
|
||||
locator_path = attempt_dir / "locator.json"
|
||||
stream_path = attempt_dir / "stream.log"
|
||||
|
|
@ -5845,7 +5847,7 @@ async def dispatch_with_store(
|
|||
):
|
||||
ready.append((task, stage))
|
||||
|
||||
admission_time = datetime.now(UTC)
|
||||
admission_time = datetime.now(KST)
|
||||
if args.dry_run:
|
||||
candidates, deferred, _ = select_dispatch_candidates(
|
||||
store,
|
||||
|
|
|
|||
|
|
@ -13,8 +13,9 @@ import json
|
|||
import os
|
||||
import re
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
|
||||
SCHEMA_VERSION = "2.0"
|
||||
|
|
@ -24,7 +25,8 @@ DEFAULT_CATALOG_PATH = (
|
|||
/ "assets"
|
||||
/ "default-execution-catalog.json"
|
||||
)
|
||||
TIMEZONE_NAME = "UTC"
|
||||
TIMEZONE_NAME = "Asia/Seoul"
|
||||
KST = ZoneInfo(TIMEZONE_NAME)
|
||||
_FILENAME_RE = re.compile(r"^(PLAN|CODE_REVIEW)-(local|cloud)-G(\d{2})\.md$")
|
||||
_MILESTONE_TASK_ID_PATTERN = r"[A-Za-z0-9]+(?:[-_+=][A-Za-z0-9]+){0,3}"
|
||||
_MILESTONE_TASK_ID_RE = re.compile(rf"\A{_MILESTONE_TASK_ID_PATTERN}\Z")
|
||||
|
|
@ -317,7 +319,7 @@ def _base_decision(
|
|||
"rule_id": route.rule_id,
|
||||
"policy_priority": route.policy_priority,
|
||||
"reason_codes": list(route.reason_codes),
|
||||
"evaluated_at": evaluated_at.astimezone(timezone.utc).isoformat(),
|
||||
"evaluated_at": evaluated_at.astimezone(KST).isoformat(),
|
||||
"timezone": TIMEZONE_NAME,
|
||||
"time_window": route.time_window,
|
||||
"pinned": pinned,
|
||||
|
|
@ -448,7 +450,7 @@ def select_execution_target(
|
|||
stage=inferred_stage,
|
||||
lane=lane,
|
||||
grade=grade,
|
||||
evaluated_at=evaluated_at or datetime.now(timezone.utc),
|
||||
evaluated_at=evaluated_at or datetime.now(KST),
|
||||
catalog_path=catalog_path,
|
||||
transition=transition,
|
||||
prior_decision=prior_decision,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import stat
|
|||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
from unittest import mock
|
||||
|
|
@ -98,6 +98,16 @@ class RuntimeCatalogDispatcherTests(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
dispatch.EXECUTION_CATALOG_PATH = self.previous_catalog
|
||||
|
||||
def test_dispatcher_default_timestamps_use_kst(self):
|
||||
timestamp = datetime.fromisoformat(dispatch.now_iso())
|
||||
|
||||
self.assertEqual(dispatch.DISPATCHER_TIMEZONE_NAME, "Asia/Seoul")
|
||||
self.assertEqual(timestamp.utcoffset(), timedelta(hours=9))
|
||||
self.assertRegex(
|
||||
dispatch.work_log_now_kst(),
|
||||
r"^\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} KST$",
|
||||
)
|
||||
|
||||
def test_agent_spec_is_loaded_from_persisted_catalog_evidence(self):
|
||||
with TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import os
|
|||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
from unittest import mock
|
||||
|
|
@ -189,6 +189,11 @@ class SelectorTests(unittest.TestCase):
|
|||
self.assertEqual(result["selected"]["model"], "model-one")
|
||||
self.assertEqual(result["catalog"]["source"], str(catalog.resolve()))
|
||||
self.assertEqual([item["target_id"] for item in result["candidates"]], ["first", "second"])
|
||||
self.assertEqual(result["decision"]["timezone"], "Asia/Seoul")
|
||||
self.assertEqual(
|
||||
datetime.fromisoformat(result["decision"]["evaluated_at"]).utcoffset(),
|
||||
timedelta(hours=9),
|
||||
)
|
||||
self.assertNotIn("quota", result)
|
||||
self.assertTrue(all("quota_status" not in item for item in result["candidates"]))
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue