From f3ab66e19ef79eefe69b71847f0d3eca2201bc80 Mon Sep 17 00:00:00 2001 From: Simbiot Harness Date: Thu, 15 Oct 2026 09:07:32 +0000 Subject: [PATCH] =?UTF-8?q?t-261015083454:=20=D0=BC=D0=B5=D1=82=D0=B0-?= =?UTF-8?q?=D0=B8=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B2=20=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8=D1=8F=D1=85=20?= =?UTF-8?q?=E2=80=94=20trace=5Fid+level+ts=20=D0=B2=20=D0=BA=D0=B0=D0=B6?= =?UTF-8?q?=D0=B4=D0=BE=D0=BC=20trace-=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8?= =?UTF-8?q?=D0=B8=20(ToolCalled/ToolResult=2068k=20=D0=B1=D1=8B=D0=BB?= =?UTF-8?q?=D0=B8=20=D0=B1=D0=B5=D0=B7=20=D1=81=D0=B2=D1=8F=D0=B7=D0=B8=20?= =?UTF-8?q?=D1=81=20=D1=82=D0=B8=D0=BA=D0=BE=D0=BC),=20duration=5Fms/ok/ex?= =?UTF-8?q?ception=20=D0=B2=20ToolResult,=20=D0=B8=D0=BC=D1=8F=20=D0=B8?= =?UTF-8?q?=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=20?= =?UTF-8?q?=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20'=3F',=20level+trace=5Fi?= =?UTF-8?q?d=20=D0=B2=20TaskCompleted/TaskFailed;=20=D1=81=D0=BC=D0=BE?= =?UTF-8?q?=D1=83=D0=BA=20+=205=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=20P?= =?UTF-8?q?ASS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- harness/_llm_worker.py | 3 ++- harness/runtime.py | 35 ++++++++++++++++++++++++++++++----- harness/scheduler.py | 4 ++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/harness/_llm_worker.py b/harness/_llm_worker.py index a7f3949..de94a5d 100644 --- a/harness/_llm_worker.py +++ b/harness/_llm_worker.py @@ -447,7 +447,8 @@ def main(): memory=False, skills=False, ) - agent = _wire_trace_hooks(agent, es, trace_id, model=payload.get("model")) + agent = _wire_trace_hooks(agent, es, trace_id, model=payload.get("model"), + level=level) agent = _wire_budget_hooks(agent, level, trace_id, model=payload.get("model")) # хард-кап шагов (e-260930031800): cancel_tool + end_turn. # ВАЖНО: НЕ используем limits={"turns": N} — нативный стоп SDK diff --git a/harness/runtime.py b/harness/runtime.py index f0712e0..1af9b39 100644 --- a/harness/runtime.py +++ b/harness/runtime.py @@ -77,12 +77,20 @@ def setup_provider(): os.environ["OPENAI_BASE_URL"] = _router_base_url() -def _wire_trace_hooks(agent, es, trace_id: str, model: str = None): +def _wire_trace_hooks(agent, es, trace_id: str, model: str = None, level: str = None): """Каждая стадия агентного цикла → событие агрегата trace. model (e-260930062120): model_id уровня в InvocationStarted — видно, КАКАЯ модель запускалась на тике (запрошенная; "auto" резолвится роутером на его стороне). + + t-261015083454 (аудит мета-информации в событиях): В КАЖДОМ + trace-событии теперь trace_id + ts + level (ToolCalled/ToolResult + раньше несли только tool/input — 68k событий без связи с тиком), + ToolResult дополнительно duration + ok/exception (из хука strands), + имя инструмента в ToolResult — из tool_use, а не заглушка "?". + Уровень недоступен (legacy-вызов) — поле не пишем, aggregate_id + по-прежнему "-:". """ from strands import Agent from strands.hooks import BeforeInvocationEvent, BeforeToolCallEvent, AfterToolCallEvent @@ -93,25 +101,42 @@ def _wire_trace_hooks(agent, es, trace_id: str, model: str = None): seq["n"] += 1 es.append_event("trace", f"{trace_id}:{seq['n']}", kind, payload) + def _meta(extra: dict = None) -> dict: + base = {"trace_id": trace_id, "ts": _now()} + if level: + base["level"] = level + if extra: + base.update(extra) + return base + def on_before_invocation(event): - data = {"trace_id": trace_id, "ts": _now()} + data = _meta() if model: data["model"] = model _trace("InvocationStarted", data) def on_before_tool(event): tool = getattr(event, "tool_use", None) or {} - _trace("ToolCalled", { + _trace("ToolCalled", _meta({ "tool": tool.get("name", "?"), "input": json.dumps(tool.get("input", {}), ensure_ascii=False, default=str)[:4000], - }) + })) def on_after_tool(event): + tool = getattr(event, "tool_use", None) or {} try: res = str(getattr(event, "result", ""))[:4000] except Exception: res = "" - _trace("ToolResult", {"tool": "?", "result": res}) + extra = {"tool": tool.get("name", "?"), "result": res} + duration = getattr(event, "duration", None) + if duration is not None: + extra["duration_ms"] = round(float(duration) * 1000) + exc = getattr(event, "exception", None) + extra["ok"] = exc is None + if exc is not None: + extra["exception"] = str(exc)[:500] + _trace("ToolResult", _meta(extra)) agent.add_hook(on_before_invocation, BeforeInvocationEvent) agent.add_hook(on_before_tool, BeforeToolCallEvent) diff --git a/harness/scheduler.py b/harness/scheduler.py index 3be5e32..81da892 100644 --- a/harness/scheduler.py +++ b/harness/scheduler.py @@ -624,6 +624,8 @@ def run_level_tick(level_cfg, seq: int, model: dict): if not _task_still_active(tid): continue es.append_event("task", tid, "TaskFailed", { + # t-261015083454: мета — уровень/тик-воркер и его трасса + "level": level_cfg.name, "trace_id": trace_id, "error": str(usage.get("error", "llm worker failed"))[:500], }) raise RuntimeError(str(usage.get("error", "llm worker failed"))) @@ -676,6 +678,8 @@ def run_level_tick(level_cfg, seq: int, model: dict): _log("skip батч-догзакрытие задач, решённых воркером: " + ", ".join(_skipped)) for tid in _resolve: es.append_event("task", tid, "TaskCompleted", { + # t-261015083454: мета-поля — какой тик/уровень закрыл задачу + "level": level_cfg.name, "trace_id": trace_id, "result_ref": trace_id, "answer": (text or "")[:2000], }) try: