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:
@@ -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,
|
||||
|
||||
@@ -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]:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user