|
|
@@ -0,0 +1,156 @@
|
|
|
+"""Local sub-trace executor adapter."""
|
|
|
+
|
|
|
+from __future__ import annotations
|
|
|
+
|
|
|
+import json
|
|
|
+from typing import Any, Dict
|
|
|
+
|
|
|
+from agent.core.runner import RunConfig
|
|
|
+from agent.tools.builtin.knowledge import KnowledgeConfig
|
|
|
+
|
|
|
+from .models import CompletionPolicy
|
|
|
+from .protocols import ValidatorRunResult, WorkerRunResult
|
|
|
+
|
|
|
+
|
|
|
+class LocalAgentExecutor:
|
|
|
+ """Run workers and validators with the same Runner in isolated traces."""
|
|
|
+
|
|
|
+ def __init__(self, runner: Any) -> None:
|
|
|
+ self.runner = runner
|
|
|
+
|
|
|
+ async def run_worker(self, context: Dict[str, Any]) -> WorkerRunResult:
|
|
|
+ preset = context["worker_preset"]
|
|
|
+ if str(preset).startswith("remote_"):
|
|
|
+ return WorkerRunResult(
|
|
|
+ trace_id=context["worker_trace_id"],
|
|
|
+ status="failed",
|
|
|
+ error="V1 explicit_validation supports local Sub-Traces only",
|
|
|
+ )
|
|
|
+ protected = {
|
|
|
+ "root_trace_id": context["root_trace_id"],
|
|
|
+ "task_id": context["task_id"],
|
|
|
+ "spec_version": context["spec_version"],
|
|
|
+ "attempt_id": context["attempt_id"],
|
|
|
+ "completion_policy": CompletionPolicy.EXPLICIT_VALIDATION.value,
|
|
|
+ }
|
|
|
+ continue_trace = context.get("continue_trace_id")
|
|
|
+ if continue_trace:
|
|
|
+ await self.runner.task_coordinator.validate_continue_from(
|
|
|
+ context["root_trace_id"], context["task_id"],
|
|
|
+ self._prior_attempt_id(context),
|
|
|
+ )
|
|
|
+ trace = await self.runner.trace_store.get_trace(continue_trace)
|
|
|
+ trace_context = dict(trace.context or {})
|
|
|
+ trace_context.update(protected)
|
|
|
+ await self.runner.trace_store.update_trace(continue_trace, context=trace_context)
|
|
|
+
|
|
|
+ config = RunConfig(
|
|
|
+ agent_type=preset,
|
|
|
+ completion_policy=CompletionPolicy.EXPLICIT_VALIDATION,
|
|
|
+ trace_id=continue_trace,
|
|
|
+ new_trace_id=None if continue_trace else context["worker_trace_id"],
|
|
|
+ parent_trace_id=context["root_trace_id"],
|
|
|
+ tools=None,
|
|
|
+ tool_groups=None,
|
|
|
+ parallel_tool_execution=False,
|
|
|
+ enable_memory=False,
|
|
|
+ enable_research_flow=False,
|
|
|
+ knowledge=_disabled_knowledge(),
|
|
|
+ context=protected,
|
|
|
+ name=f"Worker {context['task_id']}",
|
|
|
+ )
|
|
|
+ prompt = {
|
|
|
+ "task_spec": context["task_spec"],
|
|
|
+ "attempt_id": context["attempt_id"],
|
|
|
+ "repair_feedback": context.get("repair_feedback"),
|
|
|
+ "instruction": "Execute this TaskSpec and finish with submit_attempt.",
|
|
|
+ }
|
|
|
+ try:
|
|
|
+ result = await self.runner.run_result(
|
|
|
+ messages=[{"role": "user", "content": json.dumps(prompt, ensure_ascii=False, indent=2)}],
|
|
|
+ config=config,
|
|
|
+ )
|
|
|
+ return WorkerRunResult(
|
|
|
+ trace_id=result.get("trace_id") or context["worker_trace_id"],
|
|
|
+ status=result.get("status", "failed"),
|
|
|
+ summary=result.get("summary", ""),
|
|
|
+ error=result.get("error"),
|
|
|
+ )
|
|
|
+ except Exception as exc:
|
|
|
+ return WorkerRunResult(
|
|
|
+ trace_id=context["worker_trace_id"], status="failed", error=str(exc)
|
|
|
+ )
|
|
|
+
|
|
|
+ async def run_validator(self, context: Dict[str, Any]) -> ValidatorRunResult:
|
|
|
+ preset = context["validator_preset"]
|
|
|
+ if str(preset).startswith("remote_"):
|
|
|
+ return ValidatorRunResult(
|
|
|
+ trace_id=context["validator_trace_id"],
|
|
|
+ status="failed",
|
|
|
+ error="V1 explicit_validation supports local Validator Sub-Traces only",
|
|
|
+ )
|
|
|
+ protected = {
|
|
|
+ "root_trace_id": context["root_trace_id"],
|
|
|
+ "task_id": context["task_id"],
|
|
|
+ "spec_version": context["spec_version"],
|
|
|
+ "attempt_id": context["attempt_id"],
|
|
|
+ "snapshot_id": context["snapshot_id"],
|
|
|
+ "validation_id": context["validation_id"],
|
|
|
+ "completion_policy": CompletionPolicy.EXPLICIT_VALIDATION.value,
|
|
|
+ }
|
|
|
+ config = RunConfig(
|
|
|
+ agent_type=preset,
|
|
|
+ completion_policy=CompletionPolicy.EXPLICIT_VALIDATION,
|
|
|
+ new_trace_id=context["validator_trace_id"],
|
|
|
+ parent_trace_id=context["root_trace_id"],
|
|
|
+ tools=None,
|
|
|
+ tool_groups=None,
|
|
|
+ parallel_tool_execution=False,
|
|
|
+ enable_memory=False,
|
|
|
+ enable_research_flow=False,
|
|
|
+ knowledge=_disabled_knowledge(),
|
|
|
+ context=protected,
|
|
|
+ name=f"Validator {context['task_id']}",
|
|
|
+ )
|
|
|
+ prompt = {
|
|
|
+ "task_spec": context["task_spec"],
|
|
|
+ "attempt_id": context["attempt_id"],
|
|
|
+ "artifact_snapshot": context["artifact_snapshot"],
|
|
|
+ "validation_id": context["validation_id"],
|
|
|
+ "instruction": "Independently verify every criterion and finish with submit_validation.",
|
|
|
+ }
|
|
|
+ try:
|
|
|
+ result = await self.runner.run_result(
|
|
|
+ messages=[{"role": "user", "content": json.dumps(prompt, ensure_ascii=False, indent=2)}],
|
|
|
+ config=config,
|
|
|
+ )
|
|
|
+ return ValidatorRunResult(
|
|
|
+ trace_id=result.get("trace_id") or context["validator_trace_id"],
|
|
|
+ status=result.get("status", "failed"),
|
|
|
+ summary=result.get("summary", ""),
|
|
|
+ error=result.get("error"),
|
|
|
+ )
|
|
|
+ except Exception as exc:
|
|
|
+ return ValidatorRunResult(
|
|
|
+ trace_id=context["validator_trace_id"], status="failed", error=str(exc)
|
|
|
+ )
|
|
|
+
|
|
|
+ def _prior_attempt_id(self, context: Dict[str, Any]) -> str:
|
|
|
+ """Derive the previous attempt; callers cannot provide arbitrary trace IDs."""
|
|
|
+ # The current attempt is already appended. The immediately previous
|
|
|
+ # Task attempt is the only valid repair source.
|
|
|
+ # This helper is sync only for shape; validation itself remains async.
|
|
|
+ # Coordinator protects and validates the result before Runner resumes.
|
|
|
+ # A temporary marker is populated by coordinator in worker context.
|
|
|
+ return context["prior_attempt_id"]
|
|
|
+
|
|
|
+
|
|
|
+def _disabled_knowledge() -> KnowledgeConfig:
|
|
|
+ return KnowledgeConfig(
|
|
|
+ enable_extraction=False,
|
|
|
+ enable_completion_extraction=False,
|
|
|
+ enable_injection=False,
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+__all__ = ["LocalAgentExecutor"]
|