|
|
@@ -1,106 +1,135 @@
|
|
|
from __future__ import annotations
|
|
|
|
|
|
-from typing import Any, Literal
|
|
|
+from typing import Any, Literal, Optional
|
|
|
|
|
|
from pydantic import BaseModel, ConfigDict
|
|
|
|
|
|
|
|
|
-class StrictModel(BaseModel):
|
|
|
+class ViewModel(BaseModel):
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
|
|
|
-class Metric(StrictModel):
|
|
|
- label: str
|
|
|
- value: str
|
|
|
-
|
|
|
-
|
|
|
-class RecordEnvelope(StrictModel):
|
|
|
- model_name: str
|
|
|
- schema_version: str | None = None
|
|
|
- payload: dict[str, Any]
|
|
|
-
|
|
|
-
|
|
|
-class FlowNode(StrictModel):
|
|
|
- id: str
|
|
|
- node_type: Literal[
|
|
|
- "input",
|
|
|
- "contract",
|
|
|
- "operation",
|
|
|
- "worker",
|
|
|
- "attempt",
|
|
|
- "artifact",
|
|
|
- "validator",
|
|
|
- "validation",
|
|
|
- "decision",
|
|
|
- "checkpoint",
|
|
|
- "publication",
|
|
|
- "transaction",
|
|
|
- "readback",
|
|
|
- ]
|
|
|
- phase: Literal["phase-1", "phase-2", "phase-3", "delivery"]
|
|
|
- lane: str
|
|
|
+class RunSummary(ViewModel):
|
|
|
+ script_build_id: int
|
|
|
title: str
|
|
|
- subtitle: str
|
|
|
status: str
|
|
|
- agent_role: str | None = None
|
|
|
- task_kind: str | None = None
|
|
|
- sequence: int
|
|
|
- x: int
|
|
|
- y: int
|
|
|
- width: int = 268
|
|
|
- tags: list[str]
|
|
|
- metrics: list[Metric]
|
|
|
- record: RecordEnvelope
|
|
|
+ checkpoint: str
|
|
|
+ root_trace_id: str
|
|
|
+ revision: int
|
|
|
+ task_count: int
|
|
|
+ attempt_count: int
|
|
|
+ planner_turn_count: int
|
|
|
+ current_focus_task_id: Optional[str]
|
|
|
+ current_gap: str
|
|
|
+ created_at: str
|
|
|
+ updated_at: str
|
|
|
|
|
|
|
|
|
-class FlowEdge(StrictModel):
|
|
|
- id: str
|
|
|
- source: str
|
|
|
- target: str
|
|
|
- label: str | None = None
|
|
|
- kind: Literal["control", "artifact", "validation", "publication"] = "control"
|
|
|
- animated: bool = False
|
|
|
+class TaskNode(ViewModel):
|
|
|
+ task_id: str
|
|
|
+ display_path: str
|
|
|
+ parent_task_id: Optional[str]
|
|
|
+ child_task_ids: list[str]
|
|
|
+ task_kind: str
|
|
|
+ phase: str
|
|
|
+ objective: str
|
|
|
+ status: str
|
|
|
+ blocked_reason: Optional[str]
|
|
|
+ attempt_count: int
|
|
|
+ validation_count: int
|
|
|
+ decision_count: int
|
|
|
+ current_spec_version: int
|
|
|
+ acceptance_criteria: list[dict[str, Any]]
|
|
|
+ context_refs: list[str]
|
|
|
+ created_at: str
|
|
|
+ updated_at: str
|
|
|
|
|
|
|
|
|
-class PhaseFrame(StrictModel):
|
|
|
- id: str
|
|
|
- title: str
|
|
|
- subtitle: str
|
|
|
- x: int
|
|
|
- y: int
|
|
|
- width: int
|
|
|
- height: int
|
|
|
- tone: Literal["coral", "blue", "purple", "green"]
|
|
|
+class PlannerTurn(ViewModel):
|
|
|
+ turn_id: str
|
|
|
+ order: int
|
|
|
+ message_sequence: int
|
|
|
+ phase: str
|
|
|
+ action: str
|
|
|
+ action_label: str
|
|
|
+ summary: str
|
|
|
+ observable_reasoning: str
|
|
|
+ result_summary: str
|
|
|
+ status: Literal["succeeded", "failed", "unknown"]
|
|
|
+ focus_task_id: Optional[str]
|
|
|
+ affected_task_ids: list[str]
|
|
|
+ visible_task_ids: list[str]
|
|
|
+ tool_name: str
|
|
|
+ tool_arguments: dict[str, Any]
|
|
|
+ tokens: int
|
|
|
+ cost: float
|
|
|
+ created_at: str
|
|
|
|
|
|
|
|
|
-class RunSummary(StrictModel):
|
|
|
- script_build_id: int
|
|
|
+class LifecycleEvent(ViewModel):
|
|
|
+ event_id: str
|
|
|
+ kind: Literal["task", "attempt", "validation", "decision"]
|
|
|
title: str
|
|
|
status: str
|
|
|
- checkpoint: str
|
|
|
- root_trace_id: str
|
|
|
- publication_state: str
|
|
|
- node_count: int
|
|
|
+ summary: str
|
|
|
created_at: str
|
|
|
- updated_at: str
|
|
|
+ attempt_id: Optional[str] = None
|
|
|
|
|
|
|
|
|
-class RunGraph(StrictModel):
|
|
|
- schema_version: Literal["script-build-visualization/v1"]
|
|
|
- data_mode: Literal["fake"]
|
|
|
+class AgentStep(ViewModel):
|
|
|
+ sequence: int
|
|
|
+ role: str
|
|
|
+ step_kind: Literal["instruction", "explanation", "tool_call", "tool_result"]
|
|
|
+ title: str
|
|
|
+ text: str
|
|
|
+ tool_name: Optional[str]
|
|
|
+ tool_arguments: Optional[dict[str, Any]]
|
|
|
+ tokens: int
|
|
|
+ cost: float
|
|
|
+ duration_ms: Optional[float]
|
|
|
+ created_at: str
|
|
|
+
|
|
|
+
|
|
|
+class DataUsage(ViewModel):
|
|
|
+ inherited_inputs: list[dict[str, Any]]
|
|
|
+ confirmed_reads: list[dict[str, Any]]
|
|
|
+ produced_outputs: list[dict[str, Any]]
|
|
|
+ adoption: list[dict[str, Any]]
|
|
|
+
|
|
|
+
|
|
|
+class AttemptDetail(ViewModel):
|
|
|
+ attempt_id: str
|
|
|
+ task_id: str
|
|
|
+ status: str
|
|
|
+ worker_preset: Optional[str]
|
|
|
+ worker_trace_id: Optional[str]
|
|
|
+ execution_mode: Optional[str]
|
|
|
+ started_at: Optional[str]
|
|
|
+ completed_at: Optional[str]
|
|
|
+ total_tokens: int
|
|
|
+ total_cost: float
|
|
|
+ error: Optional[Any]
|
|
|
+ submission: Optional[dict[str, Any]]
|
|
|
+ validation: Optional[dict[str, Any]]
|
|
|
+ decision: Optional[dict[str, Any]]
|
|
|
+ prompt: str
|
|
|
+ steps: list[AgentStep]
|
|
|
+
|
|
|
+
|
|
|
+class TaskDetail(ViewModel):
|
|
|
+ task: TaskNode
|
|
|
+ contract: Optional[dict[str, Any]]
|
|
|
+ lifecycle: list[LifecycleEvent]
|
|
|
+ attempts: list[AttemptDetail]
|
|
|
+ data_usage: DataUsage
|
|
|
+
|
|
|
+
|
|
|
+class ExecutionView(ViewModel):
|
|
|
+ schema_version: Literal["script-build-execution-view/v1"]
|
|
|
+ data_mode: Literal["persisted-real-run"]
|
|
|
generated_at: str
|
|
|
run: RunSummary
|
|
|
- frames: list[PhaseFrame]
|
|
|
- nodes: list[FlowNode]
|
|
|
- edges: list[FlowEdge]
|
|
|
- schema_catalog: dict[str, list[str]]
|
|
|
- enum_catalog: dict[str, list[str]]
|
|
|
- declared_gaps: list[str]
|
|
|
-
|
|
|
-
|
|
|
-class NodeDetail(StrictModel):
|
|
|
- data_mode: Literal["fake"]
|
|
|
- run_id: int
|
|
|
- node: FlowNode
|
|
|
- incoming: list[FlowEdge]
|
|
|
- outgoing: list[FlowEdge]
|
|
|
+ planner_turns: list[PlannerTurn]
|
|
|
+ tasks: list[TaskNode]
|
|
|
+ snapshot_basis: str
|
|
|
+ warnings: list[str]
|