feat: expose interrupt contracts in run inspect
This commit is contained in:
@@ -387,6 +387,8 @@ def _interrupt_payload(run: RunState) -> dict[str, Any] | None:
|
|||||||
"""Return a JSON-safe interrupt payload for the current run, if paused."""
|
"""Return a JSON-safe interrupt payload for the current run, if paused."""
|
||||||
if run.interrupt is None:
|
if run.interrupt is None:
|
||||||
return None
|
return None
|
||||||
|
# The interrupt contract is copied into RunState at pause time so clients
|
||||||
|
# can render/resume without reloading mutable workflow definitions.
|
||||||
payload = asdict(run.interrupt)
|
payload = asdict(run.interrupt)
|
||||||
route = payload.get("route")
|
route = payload.get("route")
|
||||||
if isinstance(route, dict) and "workflow_ref" in route:
|
if isinstance(route, dict) and "workflow_ref" in route:
|
||||||
|
|||||||
@@ -310,6 +310,8 @@ def test_wf_run_watch_stops_on_interrupted_run(tmp_path: Path) -> None:
|
|||||||
assert payload["run_id"] == run_id
|
assert payload["run_id"] == run_id
|
||||||
assert payload["status"] == "interrupted"
|
assert payload["status"] == "interrupted"
|
||||||
assert payload["resume_readiness"] == "ready"
|
assert payload["resume_readiness"] == "ready"
|
||||||
|
assert payload["interrupt"]["typed"] is True
|
||||||
|
assert payload["interrupt"]["request_schema"]["required"] == ["message"]
|
||||||
|
|
||||||
|
|
||||||
def test_wf_run_watch_can_include_trace_slice(tmp_path: Path) -> None:
|
def test_wf_run_watch_can_include_trace_slice(tmp_path: Path) -> None:
|
||||||
@@ -533,6 +535,17 @@ def _interrupt_artifact() -> WorkflowArtifact:
|
|||||||
"request": [input_binding("input.message", "message")],
|
"request": [input_binding("input.message", "message")],
|
||||||
"resume": [],
|
"resume": [],
|
||||||
"outcomes": ["submitted"],
|
"outcomes": ["submitted"],
|
||||||
|
"request_schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {"message": {"type": "string"}},
|
||||||
|
"required": ["message"],
|
||||||
|
"additionalProperties": False,
|
||||||
|
},
|
||||||
|
"resume_schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"additionalProperties": False,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{"id": "end_submitted", "type": "end", "outcome": "submitted"},
|
{"id": "end_submitted", "type": "end", "outcome": "submitted"},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -83,6 +83,18 @@ def _interrupt_plan() -> RawWorkflowPlan:
|
|||||||
],
|
],
|
||||||
"resume": [],
|
"resume": [],
|
||||||
"outcomes": ["submitted"],
|
"outcomes": ["submitted"],
|
||||||
|
"request_schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {"message": {"type": "string"}},
|
||||||
|
"required": ["message"],
|
||||||
|
"additionalProperties": False,
|
||||||
|
},
|
||||||
|
"resume_schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {"approved": {"type": "boolean"}},
|
||||||
|
"required": ["approved"],
|
||||||
|
"additionalProperties": False,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{"id": "end_submitted", "type": "end", "outcome": "submitted"},
|
{"id": "end_submitted", "type": "end", "outcome": "submitted"},
|
||||||
],
|
],
|
||||||
@@ -410,6 +422,10 @@ async def test_mcp_backed_rpc_resumes_interrupted_run_after_server_rebuild(
|
|||||||
|
|
||||||
assert started["status"] == "interrupted"
|
assert started["status"] == "interrupted"
|
||||||
assert started["interrupt"]["payload"]["message"] == "approve after restart?"
|
assert started["interrupt"]["payload"]["message"] == "approve after restart?"
|
||||||
|
assert started["interrupt"]["outcomes"] == ["submitted"]
|
||||||
|
assert started["interrupt"]["typed"] is True
|
||||||
|
assert started["interrupt"]["request_schema"]["required"] == ["message"]
|
||||||
|
assert started["interrupt"]["resume_schema"]["required"] == ["approved"]
|
||||||
|
|
||||||
rebuilt_server = build_workflow_server_from_workflow_config(workflow_config)
|
rebuilt_server = build_workflow_server_from_workflow_config(workflow_config)
|
||||||
async with httpx.AsyncClient(
|
async with httpx.AsyncClient(
|
||||||
@@ -423,7 +439,7 @@ async def test_mcp_backed_rpc_resumes_interrupted_run_after_server_rebuild(
|
|||||||
inspected = await rebuilt_client.inspect_run(run_id=started["run_id"])
|
inspected = await rebuilt_client.inspect_run(run_id=started["run_id"])
|
||||||
resumed = await rebuilt_client.resume_run(
|
resumed = await rebuilt_client.resume_run(
|
||||||
run_id=started["run_id"],
|
run_id=started["run_id"],
|
||||||
resume_payload={},
|
resume_payload={"approved": True},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert inspected["status"] == "interrupted"
|
assert inspected["status"] == "interrupted"
|
||||||
|
|||||||
Reference in New Issue
Block a user