fix: align agent timeline event contract
This commit is contained in:
@ -81,8 +81,8 @@ class SessionProcessProjector:
|
||||
root["summary"] = payload.get("reason") or ""
|
||||
root["metadata"] = {
|
||||
**root.get("metadata", {}),
|
||||
"plan_mode": payload.get("plan_mode"),
|
||||
"strategy": payload.get("strategy"),
|
||||
"plan_mode": plan_mode,
|
||||
"strategy": strategy,
|
||||
"node_ids": node_ids,
|
||||
"skill_queries": payload.get("skill_queries") or [],
|
||||
"selected_skill_names": payload.get("selected_skill_names") or [],
|
||||
@ -234,7 +234,6 @@ class SessionProcessProjector:
|
||||
"task_id": task_id,
|
||||
"attempt_index": attempt_index,
|
||||
"timeline_type": "agent_progress",
|
||||
"node_result": dict(item),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@ -137,6 +137,8 @@ def test_process_projection_maps_task_team_events(tmp_path: Path) -> None:
|
||||
|
||||
planned_event = next(event for event in projection["events"] if event["kind"] == "task_planned")
|
||||
assert planned_event["metadata"]["timeline_type"] == "plan"
|
||||
assert planned_event["metadata"]["plan_mode"] == "team"
|
||||
assert planned_event["metadata"]["strategy"] == "sequence"
|
||||
assert planned_event["metadata"]["selected_skill_names"] == ["research-workflow"]
|
||||
|
||||
skill_event = next(event for event in projection["events"] if event["kind"] == "skill_selected")
|
||||
@ -149,6 +151,7 @@ def test_process_projection_maps_task_team_events(tmp_path: Path) -> None:
|
||||
|
||||
node_event = next(event for event in projection["events"] if event["kind"] == "agent_finished")
|
||||
assert node_event["metadata"]["timeline_type"] == "agent_progress"
|
||||
assert "node_result" not in node_event["metadata"]
|
||||
|
||||
evidence_event = next(event for event in projection["events"] if event["kind"] == "task_result_ready")
|
||||
assert evidence_event["metadata"]["timeline_type"] == "result"
|
||||
@ -209,6 +212,32 @@ def test_process_projection_maps_failed_task_team_events(tmp_path: Path) -> None
|
||||
assert node_event["metadata"]["timeline_type"] == "agent_progress"
|
||||
|
||||
|
||||
def test_process_projection_uses_normalized_plan_metadata_defaults(tmp_path: Path) -> None:
|
||||
session = SessionManager(tmp_path)
|
||||
run_store = RunMemoryStore(tmp_path / "memory" / "runs")
|
||||
session.append_message(
|
||||
"web:test",
|
||||
role="system",
|
||||
event_type="task_execution_planned",
|
||||
event_payload={
|
||||
"task_id": "task-1",
|
||||
"attempt_index": 1,
|
||||
"plan_mode": None,
|
||||
"strategy": None,
|
||||
},
|
||||
context_visible=False,
|
||||
)
|
||||
|
||||
projection = SessionProcessProjector(session, run_store).project("web:test")
|
||||
|
||||
root_run = next(run for run in projection["runs"] if run["run_id"] == "task:task-1:attempt:1")
|
||||
assert root_run["metadata"]["plan_mode"] == "single"
|
||||
assert root_run["metadata"]["strategy"] == "single"
|
||||
planned_event = next(event for event in projection["events"] if event["kind"] == "task_planned")
|
||||
assert planned_event["metadata"]["plan_mode"] == "single"
|
||||
assert planned_event["metadata"]["strategy"] == "single"
|
||||
|
||||
|
||||
def test_process_projection_exposes_ephemeral_guidance_artifacts(tmp_path: Path) -> None:
|
||||
session = SessionManager(tmp_path)
|
||||
run_store = RunMemoryStore(tmp_path / "memory" / "runs")
|
||||
|
||||
@ -201,6 +201,28 @@ describe('buildTaskTimelineCards', () => {
|
||||
expect(cards.map((card) => card.id)).not.toContain('run-research:fallback-progress');
|
||||
});
|
||||
|
||||
it('maps agent_finished events without timeline metadata to agent progress cards', () => {
|
||||
const task = makeTask();
|
||||
const processEvents: ProcessEvent[] = [
|
||||
{
|
||||
event_id: 'evt-agent-finished',
|
||||
run_id: 'run-research',
|
||||
parent_run_id: 'run-main',
|
||||
kind: 'agent_finished',
|
||||
actor_type: 'agent',
|
||||
actor_id: 'research-agent',
|
||||
actor_name: 'Research Agent',
|
||||
text: 'Finished reading source documents.',
|
||||
status: 'done',
|
||||
created_at: '2026-05-26T10:02:00.000Z',
|
||||
},
|
||||
];
|
||||
|
||||
const cards = buildTaskTimelineCards({ task, processEvents });
|
||||
|
||||
expect(cards.find((card) => card.id === 'evt-agent-finished')?.type).toBe('agent_progress');
|
||||
});
|
||||
|
||||
it('sorts invalid timestamps after valid timestamps while preserving insertion order', () => {
|
||||
const task = makeTask();
|
||||
const processEvents: ProcessEvent[] = [
|
||||
|
||||
@ -95,6 +95,7 @@ function cardTypeForEvent(event: ProcessEvent): TaskTimelineCardType | null {
|
||||
return 'agent_team';
|
||||
case 'agent_handoff':
|
||||
return 'agent_handoff';
|
||||
case 'agent_finished':
|
||||
case 'run_progress':
|
||||
case 'run_finished':
|
||||
return 'agent_progress';
|
||||
|
||||
@ -455,6 +455,7 @@ export type ProcessEventKind =
|
||||
| 'tool_call_started'
|
||||
| 'tool_call_finished'
|
||||
| 'agent_team_created'
|
||||
| 'agent_finished'
|
||||
| 'agent_handoff'
|
||||
| 'task_result_ready'
|
||||
| 'task_acceptance_recorded'
|
||||
|
||||
Reference in New Issue
Block a user