even MORE code review

stateful to not deadhang, graph context -> output, more explicit state errors, other misc changes idfk any of those good thing theyre fixed tho
This commit is contained in:
lda
2026-05-26 02:33:41 +07:00 Verified
parent 9d11f78111
commit 95ec73d518
12 changed files with 159 additions and 14 deletions
+2 -3
View File
@@ -207,7 +207,7 @@ class WorkflowBuilder:
input_schema: SchemaLike
state_schema: StateSchemaLike
output_schema: SchemaLike
outcomes: Sequence[str] | None = None
outcomes: Sequence[str] = ("ok",)
start: str | None = None
reducers: ReducerCatalog | Mapping[str, ReducerDefinition] | None = None
node_specs: dict[str, NodeSpec[Any, Any]] = field(default_factory=dict)
@@ -222,7 +222,6 @@ class WorkflowBuilder:
self.input_schema = schema_ref_from(self.input_schema)
self.state_schema = state_schema_from(self.state_schema)
self.output_schema = schema_ref_from(self.output_schema)
self.outcomes = list(self.outcomes or ["ok"])
@overload
def use(
@@ -871,7 +870,7 @@ class WorkflowBuilder:
input_schema=cast(SchemaRef, self.input_schema),
state_schema=cast(StateSchema, self.state_schema),
output_schema=cast(SchemaRef, self.output_schema),
outcomes=list(self.outcomes or ["ok"]),
outcomes=list(self.outcomes),
node_defs=node_defs,
start=self.start,
nodes=self.nodes,
+4 -2
View File
@@ -363,8 +363,10 @@ def _state_write_from_metadata(raw: object) -> StateWrite:
visible_value=visible_value,
reducer=ReducerRef.model_validate(reducer),
)
except Exception as exc:
raise WorkflowExecutionError("malformed pending foreach write") from exc
except WorkflowExecutionError:
raise
except (TypeError, ValueError) as exc:
raise WorkflowExecutionError(f"malformed pending foreach write: {exc}") from exc
def _state_write_to_metadata(write: StateWrite) -> dict[str, Any]:
+6
View File
@@ -216,7 +216,13 @@ def _lineage_chain(
) -> Iterator[LineageState]:
lineage = _lineage(run, scope_id=scope_id, lineage_id=lineage_id)
reverse_chain: list[LineageState] = []
seen: set[str] = set()
while True:
if lineage.id in seen:
raise WorkflowExecutionError(
f"cycle detected in lineage chain at {lineage.id!r}"
)
seen.add(lineage.id)
reverse_chain.append(lineage)
if lineage.parent_id is None:
break
+1
View File
@@ -253,6 +253,7 @@ def _finish_subgraph(
prepared.workflow,
child_scope.committed_state,
workflow_input=child_scope.workflow_input,
context=frame_context_values(child_frame),
)
validate_payload_against_schema(
prepared.workflow.output_schema,
+16 -4
View File
@@ -141,7 +141,7 @@ class _SessionOwner:
tool_name: str,
payload: dict[str, object],
) -> CallToolResult:
"""Submit a tool call for execution in the transport owner task."""
"""Submit a call and fail promptly if its transport owner exits."""
task = self._task
if task is None:
raise RuntimeError("persistent MCP session is not started")
@@ -152,7 +152,13 @@ class _SessionOwner:
await self._requests.put(
_ToolCallRequest(tool_name=tool_name, payload=payload, result=result)
)
return await result
done, _pending = await asyncio.wait(
{result, task}, return_when=asyncio.FIRST_COMPLETED
)
if result in done:
return result.result()
await task
raise RuntimeError("persistent MCP session stopped unexpectedly")
async def close(self) -> None:
"""Ask the owner task to close the MCP transport in its own scope."""
@@ -187,5 +193,11 @@ class _SessionOwner:
except BaseException as exc:
if not ready.done():
ready.set_exception(exc)
else:
raise
return
# Calls already queued behind the failing request cannot otherwise
# observe that their sole transport owner has exited.
while not self._requests.empty():
pending = self._requests.get_nowait()
if pending is not None and not pending.result.done():
pending.result.set_exception(exc)
raise
+3 -2
View File
@@ -604,8 +604,9 @@ def register_workflow_tools(server: FastMCP[Any], service: WfMcpService) -> None
title="Run Workflow Deployment",
description=(
"Run deployment_id with workflow_input and return status, terminal "
"outcome, output, diagnostics, and trace_count. Debug traces can include resolved "
"inputs and state changes; pass trace_range only when needed."
"outcome when completed, output, diagnostics, and trace_count. "
"Debug traces can include resolved inputs and state changes; pass "
"trace_range only when needed."
),
)
async def run_deployment(