docs updates
This commit is contained in:
@@ -76,6 +76,16 @@ limits and intended adapter seam.
|
|||||||
- Interrupt lifecycle is still node-level and run-state-level. Long-lived
|
- Interrupt lifecycle is still node-level and run-state-level. Long-lived
|
||||||
external subscriptions or notification streams need a separate lifecycle
|
external subscriptions or notification streams need a separate lifecycle
|
||||||
design.
|
design.
|
||||||
|
- Native subgraphs are not part of `wf_core` yet. The core `Step` model only
|
||||||
|
includes node, condition, foreach, join, and interrupt steps; `Workflow` does
|
||||||
|
not contain nested workflow/subgraph steps.
|
||||||
|
- Nested subgraph interruption is not first-class yet. The current
|
||||||
|
`wf_authoring` subgraph helper wraps a child workflow as an ordinary node and
|
||||||
|
validates the child output; it does not preserve a child run state that can
|
||||||
|
interrupt, bubble to the parent, and later resume inside the child.
|
||||||
|
- Saved workflow-as-node execution with interrupts requires a core runtime
|
||||||
|
upgrade: nested run state, child-frame trace preservation, interrupt bubbling
|
||||||
|
with path metadata, and resume back into the child workflow.
|
||||||
- Runtime errors are still ordinary exceptions plus failed run status. A richer
|
- Runtime errors are still ordinary exceptions plus failed run status. A richer
|
||||||
error payload can be added later, but should be designed as part of trace/run
|
error payload can be added later, but should be designed as part of trace/run
|
||||||
state rather than scattered exceptions.
|
state rather than scattered exceptions.
|
||||||
|
|||||||
@@ -0,0 +1,546 @@
|
|||||||
|
# Workflow Artifacts
|
||||||
|
|
||||||
|
This document captures the current design direction for saved workflows. It is a
|
||||||
|
design note, not an implementation status document.
|
||||||
|
|
||||||
|
## Ownership Boundary
|
||||||
|
|
||||||
|
Saved workflows are not inherently MCP concerns. `wf_mcp` is one capability
|
||||||
|
provider and one client/proxy surface; it should not become the owner of
|
||||||
|
workflow artifact storage, deployments, schedules, run history, and UI policy.
|
||||||
|
|
||||||
|
Preferred conceptual stack:
|
||||||
|
|
||||||
|
```text
|
||||||
|
wf_core
|
||||||
|
execution model, runtime, validation
|
||||||
|
|
||||||
|
wf_authoring
|
||||||
|
ergonomic builders, @node, reusable ops
|
||||||
|
|
||||||
|
wf_mcp
|
||||||
|
MCP adapters, proxying, catalogs, connection auth
|
||||||
|
|
||||||
|
wf_artifacts
|
||||||
|
immutable saved workflow definitions, versions, dependency contracts
|
||||||
|
|
||||||
|
wf_platform
|
||||||
|
deployments, bindings, schedules, run history, UI/admin policy
|
||||||
|
```
|
||||||
|
|
||||||
|
The project does not need all of these as separate packages immediately, but
|
||||||
|
new names and docs should preserve the split. `wf_mcp` may host early
|
||||||
|
experiments when it is the first consumer, but the domain model should point
|
||||||
|
toward extraction rather than making MCP the center of the workflow platform.
|
||||||
|
|
||||||
|
`wf_mcp` may expose workflow artifacts to an LLM client, but only as a
|
||||||
|
projection over an artifact/platform service. It should not own artifact state.
|
||||||
|
|
||||||
|
Prefer a small stable MCP control surface over dynamically adding one MCP tool
|
||||||
|
per saved workflow:
|
||||||
|
|
||||||
|
```text
|
||||||
|
wf.workflow.list_artifacts
|
||||||
|
wf.workflow.inspect_artifact
|
||||||
|
wf.workflow.validate_deployment
|
||||||
|
wf.workflow.run_deployment
|
||||||
|
```
|
||||||
|
|
||||||
|
This is important because MCP clients may not reliably refresh `tools/list` when
|
||||||
|
new workflow artifacts are saved. A stable `run_deployment` tool lets an LLM
|
||||||
|
test saved workflows immediately without requiring dynamic tool registration or
|
||||||
|
tool-list notifications to work perfectly.
|
||||||
|
|
||||||
|
This control surface should not fork between broker mode and transparent proxy
|
||||||
|
mode. The project currently has two MCP exposure styles:
|
||||||
|
|
||||||
|
- compatibility broker tools such as list/call wrappers
|
||||||
|
- transparent proxy projection through MCP `tools/list` and `tools/call`
|
||||||
|
|
||||||
|
Workflow artifact operations should be defined once and projected through the
|
||||||
|
chosen MCP server surface. If broker and transparent modes remain as launch
|
||||||
|
options, they should share the same platform service instead of owning separate
|
||||||
|
workflow registries or separate run semantics.
|
||||||
|
|
||||||
|
Dynamic projection of saved workflows as individual MCP tools can exist later,
|
||||||
|
but it should be optional. The stable run tool is the reliable base layer.
|
||||||
|
|
||||||
|
For long-running workflow execution, prefer MCP-native execution mechanisms
|
||||||
|
where available:
|
||||||
|
|
||||||
|
- `notifications/progress` for progress updates while a request is still active
|
||||||
|
- MCP Tasks for call-now/fetch-later execution when the client and server
|
||||||
|
negotiate task support
|
||||||
|
|
||||||
|
Do not invent a separate `start` convention as the primary MCP shape if MCP
|
||||||
|
Tasks are available. A compatibility tool such as `wf.workflow.start_run` can be
|
||||||
|
added later for clients that do not support Tasks, but that should be treated as
|
||||||
|
a fallback platform API rather than the preferred MCP contract.
|
||||||
|
|
||||||
|
## Terms
|
||||||
|
|
||||||
|
### Workflow Artifact
|
||||||
|
|
||||||
|
A workflow artifact is a saved, validated workflow package. It is more than a
|
||||||
|
raw workflow JSON document because it needs enough metadata for reuse,
|
||||||
|
inspection, dependency checks, and migration.
|
||||||
|
|
||||||
|
Expected shape:
|
||||||
|
|
||||||
|
```text
|
||||||
|
WorkflowArtifact
|
||||||
|
id
|
||||||
|
title
|
||||||
|
description
|
||||||
|
version
|
||||||
|
input_schema
|
||||||
|
output_schema
|
||||||
|
outcomes
|
||||||
|
plan
|
||||||
|
required_sources
|
||||||
|
created_from_catalog_version
|
||||||
|
```
|
||||||
|
|
||||||
|
Workflow artifact versions are immutable. Once a version is saved, its plan,
|
||||||
|
schemas, declared outcomes, and dependency declarations do not change in place.
|
||||||
|
Repairs and migrations should create a new artifact version or an external
|
||||||
|
binding decision rather than rewriting the old version.
|
||||||
|
|
||||||
|
Artifacts should prefer logical source aliases over concrete connection ids.
|
||||||
|
For example, a saved workflow can require `context7.query-docs` while a
|
||||||
|
deployment binding maps `context7` to `context7.default` or
|
||||||
|
`context7.team_account`. This gives saved workflows dependency injection for MCP
|
||||||
|
capability sources.
|
||||||
|
|
||||||
|
Logical source aliases are part of the immutable artifact. Concrete source
|
||||||
|
bindings are deployment/runtime configuration.
|
||||||
|
|
||||||
|
In this context, an account means an MCP connection profile with its own auth
|
||||||
|
and catalog behavior. It does not imply multiple users of the workflow app. A
|
||||||
|
single operator may connect several MCP accounts and bind deployments to
|
||||||
|
different accounts.
|
||||||
|
|
||||||
|
### Saved Workflow As Node
|
||||||
|
|
||||||
|
A saved workflow can be projected as a workflow node spec. At the parent
|
||||||
|
workflow boundary it behaves like a node:
|
||||||
|
|
||||||
|
- one input schema
|
||||||
|
- one output schema
|
||||||
|
- multiple declared outcomes
|
||||||
|
- interrupt points discovered from declared interrupt nodes
|
||||||
|
- nested trace preservation
|
||||||
|
|
||||||
|
Internally, it still runs as a graph with its own nodes, state, frames, traces,
|
||||||
|
foreach behavior, and interrupts.
|
||||||
|
|
||||||
|
The public boundary should match what an ordinary node provides. Parent
|
||||||
|
workflows should depend on the saved workflow's declared input schema, output
|
||||||
|
schema, outcomes, and required logical sources. Internal child graph structure
|
||||||
|
is not part of the public contract.
|
||||||
|
|
||||||
|
`interrupt_kinds` is a likely future boundary field, but it is not part of the
|
||||||
|
current schema yet. Until then, interrupts should still bubble with trace/path
|
||||||
|
metadata at runtime without becoming a declared schema field.
|
||||||
|
|
||||||
|
Current core interrupt semantics are node-level. An `InterruptNode` has:
|
||||||
|
|
||||||
|
- `kind`
|
||||||
|
- `request_map`, mapping state/input/context paths to public interrupt payload
|
||||||
|
fields
|
||||||
|
- `out_map`, mapping resume payload fields back into state
|
||||||
|
- declared resume `outcomes`
|
||||||
|
|
||||||
|
That means an artifact can document interrupt boundaries by scanning its
|
||||||
|
declarative plan for interrupt nodes and deriving their request/resume payload
|
||||||
|
schemas from the maps and workflow state/input schemas. It should not need to
|
||||||
|
store unrelated child graph internals just to describe the public interrupt
|
||||||
|
points.
|
||||||
|
|
||||||
|
## Composition Rule
|
||||||
|
|
||||||
|
LLMs and users should compose saved workflows from the catalog as ordinary node
|
||||||
|
specs, for example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
workflow.summarize_docs.v1
|
||||||
|
input_schema: ...
|
||||||
|
output_schema: ...
|
||||||
|
outcomes: done, needs_input, failed
|
||||||
|
```
|
||||||
|
|
||||||
|
The authoring surface should not require the LLM to write Python. It should use
|
||||||
|
declarative workflow artifacts plus validation feedback.
|
||||||
|
|
||||||
|
Saved workflows need two projections:
|
||||||
|
|
||||||
|
- NodeSpec-shaped catalog entries for composition
|
||||||
|
- full artifact records for inspection, debugging, repair, and migration
|
||||||
|
|
||||||
|
The NodeSpec-shaped projection is what a planner or LLM should use by default:
|
||||||
|
|
||||||
|
```text
|
||||||
|
workflow.summarize_docs.v1
|
||||||
|
input_schema
|
||||||
|
output_schema
|
||||||
|
outcomes
|
||||||
|
description
|
||||||
|
required_sources
|
||||||
|
diagnostics
|
||||||
|
```
|
||||||
|
|
||||||
|
The full artifact projection exposes the declarative plan, dependency contract
|
||||||
|
snapshots, deployments, bindings, and validation diagnostics. This is for
|
||||||
|
humans, migration tools, and advanced LLM repair flows.
|
||||||
|
|
||||||
|
Default composition should not require the client to inspect internal graph
|
||||||
|
details.
|
||||||
|
|
||||||
|
The declarative graph plan is the canonical saved form. Compiled or runtime
|
||||||
|
forms are disposable caches:
|
||||||
|
|
||||||
|
```text
|
||||||
|
WorkflowArtifact
|
||||||
|
plan: declarative workflow graph
|
||||||
|
compiled_cache: optional, disposable
|
||||||
|
```
|
||||||
|
|
||||||
|
If a compiled cache is missing or stale, rebuild it from the plan. Do not treat
|
||||||
|
compiled state as the source of truth.
|
||||||
|
|
||||||
|
Workflow steps should reference catalog capabilities by logical name and keep
|
||||||
|
contract snapshots separately. Do not inline full executable node specs into
|
||||||
|
every step.
|
||||||
|
|
||||||
|
```text
|
||||||
|
step:
|
||||||
|
node_ref: context7.query-docs
|
||||||
|
|
||||||
|
required_capabilities:
|
||||||
|
context7.query-docs:
|
||||||
|
kind: tool
|
||||||
|
input_schema_hash
|
||||||
|
input_schema_snapshot
|
||||||
|
output_schema_hash
|
||||||
|
output_schema_snapshot
|
||||||
|
```
|
||||||
|
|
||||||
|
This is similar to import resolution. The artifact stores stable logical
|
||||||
|
imports. The deployment binds those imports to concrete sources. Dependency
|
||||||
|
validation checks that the concrete source still satisfies the recorded
|
||||||
|
contract.
|
||||||
|
|
||||||
|
## Dependency Rule
|
||||||
|
|
||||||
|
Workflow artifacts depend on capability sources. If a required source is removed,
|
||||||
|
disabled, or no longer exposes the needed capability, the workflow artifact must
|
||||||
|
remain visible but become unrunnable.
|
||||||
|
|
||||||
|
Unrunnable artifacts should return dependency diagnostics rather than disappear:
|
||||||
|
|
||||||
|
```text
|
||||||
|
workflow: workflow.summarize_docs.v1
|
||||||
|
status: unrunnable
|
||||||
|
missing_dependencies:
|
||||||
|
- source: context7.default
|
||||||
|
capability: context7.default.query_docs
|
||||||
|
reason: source disabled
|
||||||
|
```
|
||||||
|
|
||||||
|
Diagnostics should be structured and machine-readable:
|
||||||
|
|
||||||
|
```text
|
||||||
|
DependencyDiagnostic
|
||||||
|
severity: error | warning
|
||||||
|
code: source_missing | source_disabled | capability_missing | schema_changed | binding_missing
|
||||||
|
logical_ref
|
||||||
|
bound_source
|
||||||
|
message
|
||||||
|
repair_hint
|
||||||
|
```
|
||||||
|
|
||||||
|
Structured diagnostics let tests, dashboards, and LLM clients handle dependency
|
||||||
|
failures without parsing human-readable error strings.
|
||||||
|
|
||||||
|
This preserves repairability:
|
||||||
|
|
||||||
|
- users can inspect the saved workflow
|
||||||
|
- LLMs can explain what broke
|
||||||
|
- dashboards can offer rebind/restore actions
|
||||||
|
- future migration tools can map old sources to new ones
|
||||||
|
|
||||||
|
The artifact definition is immutable, but dependency status is live. A workflow
|
||||||
|
version can move between runnable and unrunnable as the surrounding capability
|
||||||
|
sources change.
|
||||||
|
|
||||||
|
Dependency checks should validate bindings, not just names. A concrete source
|
||||||
|
can satisfy a logical source alias only when it still exposes a compatible
|
||||||
|
capability contract.
|
||||||
|
|
||||||
|
Artifacts should store a dependency contract snapshot for each capability they
|
||||||
|
actually use:
|
||||||
|
|
||||||
|
```text
|
||||||
|
RequiredCapability
|
||||||
|
logical_source: context7
|
||||||
|
capability_name: query-docs
|
||||||
|
kind: tool
|
||||||
|
input_schema
|
||||||
|
output_schema
|
||||||
|
observed_concrete_source: context7.default
|
||||||
|
observed_at
|
||||||
|
```
|
||||||
|
|
||||||
|
The snapshot is not a full catalog pin. It is the minimum contract needed to
|
||||||
|
detect whether the currently bound source still satisfies the saved workflow.
|
||||||
|
|
||||||
|
Workflow artifacts may depend on other workflow artifacts. A parent stores only
|
||||||
|
its direct dependencies; it should not copy a child workflow's dependency
|
||||||
|
snapshots into itself. Runtime/deployment validation walks the transitive
|
||||||
|
dependency graph and reports the chain that failed.
|
||||||
|
|
||||||
|
```text
|
||||||
|
answer_question
|
||||||
|
depends on search_docs
|
||||||
|
depends on context7.query-docs
|
||||||
|
```
|
||||||
|
|
||||||
|
If `context7.query-docs` breaks, `answer_question` is unrunnable because
|
||||||
|
`search_docs` is unrunnable. Diagnostics should preserve that chain.
|
||||||
|
|
||||||
|
Saved workflow dependencies should start with exact artifact-version pins:
|
||||||
|
|
||||||
|
```text
|
||||||
|
direct_dependency:
|
||||||
|
workflow: search_docs
|
||||||
|
version: 3
|
||||||
|
```
|
||||||
|
|
||||||
|
Exact pins make saved workflow behavior reproducible. Leave room for a future
|
||||||
|
`version_constraint` field if a semver parser is added, but do not start with
|
||||||
|
floating latest-compatible behavior.
|
||||||
|
|
||||||
|
Workflow artifact dependencies must be acyclic. Reject dependency cycles during
|
||||||
|
save or deployment validation, before runtime execution.
|
||||||
|
|
||||||
|
```text
|
||||||
|
dependency_cycle:
|
||||||
|
chain: workflow.a@1 -> workflow.b@2 -> workflow.a@1
|
||||||
|
```
|
||||||
|
|
||||||
|
Cycles should be rejected even if branch logic appears to make them unreachable.
|
||||||
|
The static dependency graph must stay acyclic so validation, tracing, and future
|
||||||
|
resume behavior remain understandable.
|
||||||
|
|
||||||
|
Dependency validation happens in two phases.
|
||||||
|
|
||||||
|
At save time:
|
||||||
|
|
||||||
|
```text
|
||||||
|
validate graph shape
|
||||||
|
resolve logical references
|
||||||
|
record required contracts
|
||||||
|
reject obviously invalid workflows
|
||||||
|
```
|
||||||
|
|
||||||
|
At deployment or run time:
|
||||||
|
|
||||||
|
```text
|
||||||
|
resolve concrete bindings
|
||||||
|
check source enabled or missing
|
||||||
|
compare current contracts to recorded contracts
|
||||||
|
apply drift_policy
|
||||||
|
return diagnostics or run
|
||||||
|
```
|
||||||
|
|
||||||
|
Save-time validation proves that the artifact was valid when created.
|
||||||
|
Deployment/run-time validation proves that the current environment can still
|
||||||
|
satisfy it.
|
||||||
|
|
||||||
|
Important dependency failure cases:
|
||||||
|
|
||||||
|
- source missing: the configured MCP connection no longer exists
|
||||||
|
- source disabled: the user or admin turned off the source
|
||||||
|
- capability missing: the source exists but no longer exposes the required tool,
|
||||||
|
prompt, resource, or node spec
|
||||||
|
- capability changed: the source still exposes the capability but its schema or
|
||||||
|
behavior no longer matches the artifact's recorded expectation
|
||||||
|
|
||||||
|
Missing and disabled sources are hard unrunnable failures. Capability changes
|
||||||
|
should start as diagnostics and become hard failures when the recorded schema is
|
||||||
|
no longer compatible with the saved workflow boundary.
|
||||||
|
|
||||||
|
Initial compatibility checks can be conservative:
|
||||||
|
|
||||||
|
- exact input/output schema hash match: compatible
|
||||||
|
- missing source: unrunnable
|
||||||
|
- missing capability: unrunnable
|
||||||
|
- new required input fields: unrunnable
|
||||||
|
- removed input fields that the workflow sends: unrunnable
|
||||||
|
- changed fields that downstream workflow paths read: unrunnable
|
||||||
|
- description/title/metadata-only changes: warning
|
||||||
|
- unknown or changed-but-not-proven-incompatible schema: follow deployment drift
|
||||||
|
policy
|
||||||
|
|
||||||
|
## Binding Rule
|
||||||
|
|
||||||
|
Use binding when the workflow intent stays the same but the concrete source
|
||||||
|
changes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
artifact reference: context7.query-docs
|
||||||
|
runtime binding: context7 -> context7.default
|
||||||
|
```
|
||||||
|
|
||||||
|
or:
|
||||||
|
|
||||||
|
```text
|
||||||
|
artifact reference: context7.query-docs
|
||||||
|
runtime binding: context7 -> context7.team_account
|
||||||
|
```
|
||||||
|
|
||||||
|
Use migration when the graph, mappings, schemas, outcomes, or intended provider
|
||||||
|
semantics change. Migration creates a new immutable workflow artifact version.
|
||||||
|
|
||||||
|
The practical split:
|
||||||
|
|
||||||
|
- rebind: same capability contract, different concrete source
|
||||||
|
- migrate: changed workflow behavior, incompatible schema, or different
|
||||||
|
provider semantics
|
||||||
|
|
||||||
|
Bindings should live outside the immutable artifact, preferably on a deployment
|
||||||
|
or run configuration:
|
||||||
|
|
||||||
|
```text
|
||||||
|
WorkflowDeployment
|
||||||
|
artifact_id: summarize_docs
|
||||||
|
artifact_version: 1
|
||||||
|
deployment_id: summarize_docs.context7_default
|
||||||
|
bindings:
|
||||||
|
context7: context7.default
|
||||||
|
drift_policy: block
|
||||||
|
```
|
||||||
|
|
||||||
|
The default binding scope is deployment-level. A per-run override can be added
|
||||||
|
later for interactive or one-off runs. Bindings should not be modeled as
|
||||||
|
per-user until the application actually has user accounts and tenancy.
|
||||||
|
|
||||||
|
A deployment id identifies one configured way to run an artifact version. Two
|
||||||
|
deployments can point at the same immutable workflow artifact while binding
|
||||||
|
logical sources to different MCP accounts or connection profiles:
|
||||||
|
|
||||||
|
```text
|
||||||
|
deployment: summarize_docs.personal
|
||||||
|
artifact: summarize_docs@1
|
||||||
|
bindings:
|
||||||
|
context7: context7.personal
|
||||||
|
|
||||||
|
deployment: summarize_docs.work
|
||||||
|
artifact: summarize_docs@1
|
||||||
|
bindings:
|
||||||
|
context7: context7.work
|
||||||
|
```
|
||||||
|
|
||||||
|
This gives the stable MCP run tool a concrete target without requiring one MCP
|
||||||
|
tool per workflow or account.
|
||||||
|
|
||||||
|
Recommended drift-policy defaults:
|
||||||
|
|
||||||
|
- scheduled/offline deployments: `block`
|
||||||
|
- manual interactive runs: `warn`
|
||||||
|
- development runs: `warn` or `allow`
|
||||||
|
|
||||||
|
This prevents silent scheduled failures while still allowing local repair and
|
||||||
|
experimentation.
|
||||||
|
|
||||||
|
## Storage Direction
|
||||||
|
|
||||||
|
Workflow artifacts should use a store protocol rather than baking filesystem
|
||||||
|
paths into the models. The existing `wf_mcp.storage.Store` persists auth and
|
||||||
|
catalog snapshots; workflow artifacts have a different lifecycle, so start with
|
||||||
|
a sibling artifact-store protocol instead of immediately expanding the MCP store
|
||||||
|
interface.
|
||||||
|
|
||||||
|
Expected shape:
|
||||||
|
|
||||||
|
```text
|
||||||
|
WorkflowArtifactStore
|
||||||
|
save_artifact(artifact)
|
||||||
|
get_artifact(id, version)
|
||||||
|
list_artifacts()
|
||||||
|
resolve_latest(id)
|
||||||
|
```
|
||||||
|
|
||||||
|
The initial implementation can be file-backed and share the same root directory
|
||||||
|
family as the existing MCP store:
|
||||||
|
|
||||||
|
```text
|
||||||
|
.wf_mcp_store/
|
||||||
|
auth/
|
||||||
|
catalog/
|
||||||
|
workflows/
|
||||||
|
summarize_docs/
|
||||||
|
1.json
|
||||||
|
2.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Keeping the store behind a protocol makes it straightforward to move artifacts
|
||||||
|
to SQLite, Postgres, or another backend later.
|
||||||
|
|
||||||
|
## Runtime Direction
|
||||||
|
|
||||||
|
Saved workflow execution eventually needs first-class runtime support for:
|
||||||
|
|
||||||
|
- nested run state
|
||||||
|
- child-frame trace preservation
|
||||||
|
- interrupt bubbling with path metadata
|
||||||
|
- resume into child run state
|
||||||
|
- child final outcome mapping to parent node outcome
|
||||||
|
- dependency checks before execution
|
||||||
|
|
||||||
|
The first implementation should prefer artifact validation and dependency
|
||||||
|
diagnostics before attempting persistent nested resume.
|
||||||
|
|
||||||
|
Native subgraphs are not in `wf_core` yet. The current core `Step` model has
|
||||||
|
node, condition, foreach, join, and interrupt steps, but no subgraph step. The
|
||||||
|
current `wf_authoring.subgraph_node` helper executes a child workflow as a plain
|
||||||
|
node and validates the child output. Future saved-workflow-as-node execution
|
||||||
|
needs a real child run state if child interrupts should pause the parent and
|
||||||
|
later resume the child.
|
||||||
|
|
||||||
|
Until that core upgrade exists, artifact tooling must not assume that an
|
||||||
|
interrupting saved workflow can safely be used as a child node. Top-level saved
|
||||||
|
workflows with interrupt nodes are valid, but nested interrupting workflows
|
||||||
|
should be reported as unsupported for composition.
|
||||||
|
|
||||||
|
Blocking dependency failures happen before workflow execution and are not normal
|
||||||
|
workflow outcomes. A missing source, disabled source, unresolved binding, or
|
||||||
|
incompatible capability contract means the deployment is unrunnable.
|
||||||
|
|
||||||
|
```text
|
||||||
|
validate deployment dependencies
|
||||||
|
if blocking diagnostics exist:
|
||||||
|
return unrunnable dependency diagnostics
|
||||||
|
else:
|
||||||
|
run workflow
|
||||||
|
```
|
||||||
|
|
||||||
|
Dependency diagnostics may be shown to parent workflows, dashboards, and LLM
|
||||||
|
clients, but they should not be routed through ordinary business outcomes such
|
||||||
|
as `failed`.
|
||||||
|
|
||||||
|
MCP tool result errors are different from dependency failures. A generated MCP
|
||||||
|
tool wrapper can expose generic outcomes such as `ok` and `error`; workflow
|
||||||
|
authors must wire both outcomes explicitly. A `runtime_error` node is a valid
|
||||||
|
way to terminate generic tool errors.
|
||||||
|
|
||||||
|
Richer business outcomes should be modeled with wrapper graph-nodes rather than
|
||||||
|
by making every generated MCP node guess domain semantics. For example, a
|
||||||
|
workflow can wrap a raw MCP call and map result content to outcomes such as
|
||||||
|
`found`, `not_found`, `unauthorized`, or `rate_limited` when those meanings are
|
||||||
|
known for that tool.
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
|
||||||
|
- How should child workflow interrupts compose with parent workflow execution
|
||||||
|
once saved workflows can run as real subgraphs instead of plain node wrappers?
|
||||||
Reference in New Issue
Block a user