|
|
@@ -18,7 +18,6 @@ from agent.orchestration.models import (
|
|
|
)
|
|
|
from agent.orchestration.protocols import ValidatorRunResult, WorkerRunResult
|
|
|
from agent.orchestration.store import FileSystemArtifactStore, FileSystemTaskStore, TraceEventSink
|
|
|
-from agent.trace.goal_models import GoalTree
|
|
|
from agent.trace.models import Trace
|
|
|
from agent.trace.store import FileSystemTraceStore
|
|
|
from agent.core.runner import AgentRunner
|
|
|
@@ -104,7 +103,6 @@ async def make_coordinator(
|
|
|
):
|
|
|
trace_store = trace_store or FileSystemTraceStore(str(tmp_path))
|
|
|
await trace_store.create_trace(Trace(trace_id="root", mode="agent", task="mission", agent_role="planner"))
|
|
|
- await trace_store.update_goal_tree("root", GoalTree(mission="mission"))
|
|
|
task_store = task_store or FileSystemTaskStore(str(tmp_path))
|
|
|
coordinator = TaskCoordinator(
|
|
|
task_store,
|
|
|
@@ -448,7 +446,6 @@ async def test_real_runner_local_executor_creates_independent_terminal_traces(tm
|
|
|
|
|
|
trace_store = FileSystemTraceStore(str(tmp_path))
|
|
|
await trace_store.create_trace(Trace(trace_id="root", mode="agent", task="mission", agent_role="planner"))
|
|
|
- await trace_store.update_goal_tree("root", GoalTree(mission="mission"))
|
|
|
runner = AgentRunner(trace_store=trace_store, llm_call=fake_llm)
|
|
|
coordinator = wire_orchestration(
|
|
|
runner,
|
|
|
@@ -483,35 +480,6 @@ class OneShotGetFailureArtifactStore(FileSystemArtifactStore):
|
|
|
return await super().get(root_trace_id, snapshot_id)
|
|
|
|
|
|
|
|
|
-class OneShotGoalProjectionFailureStore(FileSystemTraceStore):
|
|
|
- def __init__(self, base_path):
|
|
|
- super().__init__(base_path)
|
|
|
- self.fail_next_goal_update = False
|
|
|
-
|
|
|
- async def update_goal(self, trace_id, goal_id, cascade_completion=True, **updates):
|
|
|
- if self.fail_next_goal_update:
|
|
|
- self.fail_next_goal_update = False
|
|
|
- raise RuntimeError("injected goal projection failure")
|
|
|
- return await super().update_goal(
|
|
|
- trace_id,
|
|
|
- goal_id,
|
|
|
- cascade_completion=cascade_completion,
|
|
|
- **updates,
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-class OneShotGoalTreeProjectionFailureStore(FileSystemTraceStore):
|
|
|
- def __init__(self, base_path):
|
|
|
- super().__init__(base_path)
|
|
|
- self.fail_next_goal_tree_update = False
|
|
|
-
|
|
|
- async def update_goal_tree(self, trace_id, goal_tree):
|
|
|
- if self.fail_next_goal_tree_update:
|
|
|
- self.fail_next_goal_tree_update = False
|
|
|
- raise RuntimeError("injected goal tree projection failure")
|
|
|
- return await super().update_goal_tree(trace_id, goal_tree)
|
|
|
-
|
|
|
-
|
|
|
class FailingDispatchCompletionTaskStore(FileSystemTaskStore):
|
|
|
def __init__(self, base_path):
|
|
|
super().__init__(base_path)
|
|
|
@@ -605,49 +573,28 @@ async def test_batch_reservation_conflict_does_not_strand_other_tasks(tmp_path):
|
|
|
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
-async def test_goal_projection_failure_does_not_abort_committed_attempt(tmp_path):
|
|
|
+async def test_explicit_lifecycle_never_creates_goal_tree(tmp_path):
|
|
|
executor = FakeExecutor([ValidationVerdict.PASSED])
|
|
|
- trace_store = OneShotGoalProjectionFailureStore(str(tmp_path))
|
|
|
- coordinator, store, _ = await make_coordinator(
|
|
|
- tmp_path,
|
|
|
- executor,
|
|
|
- trace_store=trace_store,
|
|
|
- )
|
|
|
- task_id = await create_task(coordinator, "reservation-projection-failure")
|
|
|
- trace_store.fail_next_goal_update = True
|
|
|
+ coordinator, store, trace_store = await make_coordinator(tmp_path, executor)
|
|
|
+ task_id = await create_task(coordinator, "task-ledger-only")
|
|
|
|
|
|
result = (await coordinator.dispatch_tasks("root", [task_id]))[0]
|
|
|
|
|
|
- assert result.task_id == task_id
|
|
|
assert result.task_status == TaskStatus.AWAITING_DECISION
|
|
|
- assert result.attempt_id is not None
|
|
|
- assert result.error is None
|
|
|
- ledger = await store.load("root")
|
|
|
- assert ledger.tasks[task_id].status == TaskStatus.AWAITING_DECISION
|
|
|
- assert ledger.attempts[result.attempt_id].status.value == "submitted"
|
|
|
+ assert (await store.load("root")).tasks[task_id].status == TaskStatus.AWAITING_DECISION
|
|
|
+ assert await trace_store.get_goal_tree("root") is None
|
|
|
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
-async def test_task_creation_survives_goal_tree_projection_failure_and_reconciles(tmp_path):
|
|
|
- executor = FakeExecutor([])
|
|
|
- trace_store = OneShotGoalTreeProjectionFailureStore(str(tmp_path))
|
|
|
- coordinator, store, _ = await make_coordinator(
|
|
|
- tmp_path,
|
|
|
- executor,
|
|
|
- trace_store=trace_store,
|
|
|
- )
|
|
|
- trace_store.fail_next_goal_tree_update = True
|
|
|
-
|
|
|
- task_id = await create_task(coordinator, "projection-outage")
|
|
|
+async def test_task_context_is_rendered_from_ledger(tmp_path):
|
|
|
+ coordinator, _, _ = await make_coordinator(tmp_path, FakeExecutor([]))
|
|
|
+ await create_task(coordinator, "draft the answer")
|
|
|
|
|
|
- ledger = await store.load("root")
|
|
|
- assert ledger.tasks[task_id].status == TaskStatus.PENDING
|
|
|
- assert ledger.tasks[task_id].goal_id is None
|
|
|
+ context = await coordinator.task_context("root")
|
|
|
|
|
|
- result = await coordinator.reconcile_goal_tree("root")
|
|
|
- ledger = await store.load("root")
|
|
|
- assert result["reconciled_tasks"] == 2
|
|
|
- assert ledger.tasks[task_id].goal_id is not None
|
|
|
+ assert "## Current Task Plan" in context
|
|
|
+ assert "- 0 [waiting_children] mission" in context
|
|
|
+ assert "- 0.1 [pending] draft the answer" in context
|
|
|
|
|
|
|
|
|
@pytest.mark.asyncio
|