docs changes
This commit is contained in:
@@ -42,15 +42,20 @@ Examples:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"input": [
|
"input": [
|
||||||
{"target": "user.name", "path": "state.person.name"},
|
{
|
||||||
{"target": "user.email", "path": "state.digital.email"},
|
"target": {"root": "local", "parts": ["user", "name"]},
|
||||||
{"target": "job.title", "path": "state.job.title"},
|
"path": {"root": "state", "parts": ["person", "name"]}
|
||||||
{"target": "mode", "value": "fast"}
|
},
|
||||||
|
{
|
||||||
|
"target": {"root": "local", "parts": ["mode"]},
|
||||||
|
"value": "fast"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"output": [
|
"output": [
|
||||||
{"source": "job.wage", "target": "state.job.wage"},
|
{
|
||||||
{"source": "job.years", "target": "state.experience.years"},
|
"source": {"root": "local", "parts": ["job", "wage"]},
|
||||||
{"source": "user.age", "target": "state.person.age"}
|
"target": {"root": "state", "parts": ["job", "wage"]}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -59,8 +64,18 @@ Whole-object mapping remains valid:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"input": [{"target": "user", "path": "state.person"}],
|
"input": [
|
||||||
"output": [{"source": "user", "target": "state.person"}]
|
{
|
||||||
|
"target": {"root": "local", "parts": ["user"]},
|
||||||
|
"path": {"root": "state", "parts": ["person"]}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"output": [
|
||||||
|
{
|
||||||
|
"source": {"root": "local", "parts": ["user"]},
|
||||||
|
"target": {"root": "state", "parts": ["person"]}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -68,8 +83,18 @@ Whole-payload mapping uses the local root path `"."`:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"input": [{"target": ".", "path": "state.rates"}],
|
"input": [
|
||||||
"output": [{"source": ".", "target": "state.rates"}]
|
{
|
||||||
|
"target": {"root": "local", "parts": []},
|
||||||
|
"path": {"root": "state", "parts": ["rates"]}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"output": [
|
||||||
|
{
|
||||||
|
"source": {"root": "local", "parts": []},
|
||||||
|
"target": {"root": "state", "parts": ["rates"]}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -96,8 +121,14 @@ Valid:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
{"target": "user.name", "path": "state.person.name"},
|
{
|
||||||
{"target": "user.email", "path": "state.person.email"}
|
"target": {"root": "local", "parts": ["user", "name"]},
|
||||||
|
"path": {"root": "state", "parts": ["person", "name"]}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"target": {"root": "local", "parts": ["user", "email"]},
|
||||||
|
"path": {"root": "state", "parts": ["person", "email"]}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -105,8 +136,14 @@ Invalid:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
{"target": "user", "path": "state.person"},
|
{
|
||||||
{"target": "user.name", "path": "state.person.name"}
|
"target": {"root": "local", "parts": ["user"]},
|
||||||
|
"path": {"root": "state", "parts": ["person"]}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"target": {"root": "local", "parts": ["user", "name"]},
|
||||||
|
"path": {"root": "state", "parts": ["person", "name"]}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -122,8 +159,14 @@ Invalid:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
{"source": "user", "target": "state.person"},
|
{
|
||||||
{"source": "user.name", "target": "state.person.name"}
|
"source": {"root": "local", "parts": ["user"]},
|
||||||
|
"target": {"root": "state", "parts": ["person"]}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {"root": "local", "parts": ["user", "name"]},
|
||||||
|
"target": {"root": "state", "parts": ["person", "name"]}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# Path And Mapping Scratch
|
# Path And Mapping Scratch
|
||||||
|
|
||||||
|
> Historical note: this scratchpad records how the mapping model evolved.
|
||||||
|
> Current core behavior uses canonical `input`/`output` and interrupt
|
||||||
|
> `request`/`resume` binding lists. See `core_state_mapping_and_merge.md`.
|
||||||
|
|
||||||
This is a focused scratchpad for the `wf_core` path/mapping design thread.
|
This is a focused scratchpad for the `wf_core` path/mapping design thread.
|
||||||
Clean this into real docs later.
|
Clean this into real docs later.
|
||||||
|
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
# Graph as struct? workflow as struct
|
# Graph as struct? workflow as struct
|
||||||
|
|
||||||
|
> Historical note: this file preserves older design notes. Current binding
|
||||||
|
> shapes are documented in `core_state_mapping_and_merge.md`,
|
||||||
|
> `structural_refs.md`, and `workflow_drafts.md`.
|
||||||
|
|
||||||
This file is now mostly a working design note.
|
This file is now mostly a working design note.
|
||||||
|
|
||||||
The original top section was rough brainstorming around a few ideas that did end
|
The original top section was rough brainstorming around a few ideas that did end
|
||||||
@@ -71,15 +71,17 @@ limits and intended adapter seam.
|
|||||||
|
|
||||||
## What This Cleanup Does Not Solve Yet
|
## What This Cleanup Does Not Solve Yet
|
||||||
|
|
||||||
- Node-local mapping paths are still top-level only in the current runtime.
|
- Node-local input/output bindings now support nested local paths and atomic
|
||||||
The intended direction for nested node-local paths, patch commits, and future
|
state patch commits. The remaining mapping design notes for future reducer
|
||||||
nested merge metadata is documented in
|
metadata are documented in
|
||||||
[`core_state_mapping_and_merge.md`](core_state_mapping_and_merge.md).
|
[`core_state_mapping_and_merge.md`](core_state_mapping_and_merge.md).
|
||||||
- Foreach is still serial-only. Parallel foreach needs an explicit scheduling
|
- Foreach is still serial-only. Parallel foreach needs an explicit scheduling
|
||||||
model, not just `asyncio.gather`.
|
model, not just `asyncio.gather`. `ForeachNode.over` is typed as a
|
||||||
|
`GraphSourcePath`, but execution is still serial.
|
||||||
- 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. Interrupt `request` and `resume` are canonical binding lists; nested
|
||||||
|
child-workflow resume is still future work.
|
||||||
- Native subgraphs are not part of `wf_core` yet. The core `Step` model only
|
- Native subgraphs are not part of `wf_core` yet. The core `Step` model only
|
||||||
includes node, condition, foreach, join, and interrupt steps; `Workflow` does
|
includes node, condition, foreach, join, and interrupt steps; `Workflow` does
|
||||||
not contain nested workflow/subgraph steps.
|
not contain nested workflow/subgraph steps.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
- [docs/schema_validation.md](docs/schema_validation.md): current payload schema validation limits and intended validation seam.
|
- [docs/schema_validation.md](docs/schema_validation.md): current payload schema validation limits and intended validation seam.
|
||||||
- [docs/wf_mcp_plan.md](docs/wf_mcp_plan.md): `wf_mcp` direction as a namespaced MCP capability broker plus workflow build/run layer.
|
- [docs/wf_mcp_plan.md](docs/wf_mcp_plan.md): `wf_mcp` direction as a namespaced MCP capability broker plus workflow build/run layer.
|
||||||
- [docs/wf_mcp_architecture.md](docs/wf_mcp_architecture.md): current `wf_mcp` package boundaries and dependency rules.
|
- [docs/wf_mcp_architecture.md](docs/wf_mcp_architecture.md): current `wf_mcp` package boundaries and dependency rules.
|
||||||
- [docs/scratchpad.md](docs/scratchpad.md): rougher design history and intermediate spec notes that fed the current model.
|
- [docs/historical/scratchpad.md](docs/historical/scratchpad.md): historical design notes that fed the current model.
|
||||||
|
|
||||||
## What is this
|
## What is this
|
||||||
|
|
||||||
@@ -112,19 +112,42 @@ NodeUse
|
|||||||
.type: "node"
|
.type: "node"
|
||||||
.node // reference to NodeDef
|
.node // reference to NodeDef
|
||||||
.desc?
|
.desc?
|
||||||
.in_map // graph path -> node input field
|
.input[] // graph/value -> node-local input bindings
|
||||||
.out_map // node output field -> graph state path
|
.output[] // node-local output -> graph state bindings
|
||||||
.retry? // optional override
|
.retry? // optional override
|
||||||
.timeout_seconds? // optional override
|
.timeout_seconds? // optional override
|
||||||
```
|
```
|
||||||
|
|
||||||
The node does not get ambient access to all workflow state. It receives:
|
The node does not get ambient access to all workflow state. It receives:
|
||||||
|
|
||||||
- mapped input
|
- the payload built by explicit `input` bindings
|
||||||
- runtime context
|
- runtime context
|
||||||
|
|
||||||
This keeps nodes reusable instead of graph-coupled.
|
This keeps nodes reusable instead of graph-coupled.
|
||||||
|
|
||||||
|
Path bindings use structural paths in saved JSON:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"input": [
|
||||||
|
{
|
||||||
|
"target": {"root": "local", "parts": ["text"]},
|
||||||
|
"path": {"root": "input", "parts": ["text"]}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"output": [
|
||||||
|
{
|
||||||
|
"source": {"root": "local", "parts": ["echoed"]},
|
||||||
|
"target": {"root": "state", "parts": ["echoed"]}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Legacy `in_map`, `input_values`, and `out_map` shapes remain parse-only
|
||||||
|
compatibility inputs. New authored or saved plans should write `input` and
|
||||||
|
`output`.
|
||||||
|
|
||||||
### Control-flow nodes
|
### Control-flow nodes
|
||||||
|
|
||||||
#### **ConditionNode**
|
#### **ConditionNode**
|
||||||
@@ -161,8 +184,8 @@ Conditions are structured JSON, not freeform code strings.
|
|||||||
.id
|
.id
|
||||||
.type: "interrupt"
|
.type: "interrupt"
|
||||||
.kind // approval | text_input | choice | tool_auth | ...
|
.kind // approval | text_input | choice | tool_auth | ...
|
||||||
.request_map // graph state/input path -> interrupt payload field
|
.request[] // graph/value -> public interrupt payload bindings
|
||||||
.out_map // resume payload field -> graph state path
|
.resume[] // resume payload -> graph state bindings
|
||||||
.outcomes[] // ex: submitted, cancelled
|
.outcomes[] // ex: submitted, cancelled
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -247,9 +270,9 @@ State fields carry metadata, especially merge behavior.
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
StateField
|
StateField
|
||||||
.type
|
.path
|
||||||
.merge_strategy // replace | append | merge_object
|
.schema // JSON Schema with reducer extension metadata
|
||||||
.trace?
|
.reducer // wf.std.replace | wf.std.append | ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Rules:
|
Rules:
|
||||||
@@ -272,7 +295,7 @@ Executor steps:
|
|||||||
2. Validate workflow input
|
2. Validate workflow input
|
||||||
3. Copy input into state
|
3. Copy input into state
|
||||||
4. Start at the declared `start` node
|
4. Start at the declared `start` node
|
||||||
5. Resolve node input snapshot from `in_map`
|
5. Resolve node input snapshot from canonical `input` bindings
|
||||||
6. Execute node with mapped input plus runtime context
|
6. Execute node with mapped input plus runtime context
|
||||||
7. Validate typed node output
|
7. Validate typed node output
|
||||||
8. Commit mapped output into state
|
8. Commit mapped output into state
|
||||||
@@ -394,7 +417,7 @@ Resume should not jump back into the middle of arbitrary Python code.
|
|||||||
Instead:
|
Instead:
|
||||||
|
|
||||||
- resume data is delivered to the interrupt node
|
- resume data is delivered to the interrupt node
|
||||||
- the interrupt node maps resume fields back into state through explicit `out_map`
|
- the interrupt node maps resume fields back into state through explicit `resume` bindings
|
||||||
- graph routing continues normally from that node
|
- graph routing continues normally from that node
|
||||||
|
|
||||||
This means the primary interrupt design is node-based, not line-based.
|
This means the primary interrupt design is node-based, not line-based.
|
||||||
@@ -463,8 +486,8 @@ Before execution, the validator should be able to check:
|
|||||||
- every edge outcome is declared by its source node
|
- every edge outcome is declared by its source node
|
||||||
- each source + outcome pair is wired at most once
|
- each source + outcome pair is wired at most once
|
||||||
- every reachable outcome is wired
|
- every reachable outcome is wired
|
||||||
- every `in_map` destination exists in node input schema
|
- every `input` binding target is a valid node-local path
|
||||||
- every `out_map` source exists in node output schema
|
- every `output` binding source exists in node output schema where schema detail is known
|
||||||
- every condition path references valid `input`, `state`, or `context`
|
- every condition path references valid `input`, `state`, or `context`
|
||||||
- every `foreach.over` path references valid `input` or `state`
|
- every `foreach.over` path references valid `input` or `state`
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user