docs update to the new stuff

This commit is contained in:
lda
2026-05-20 18:08:24 +07:00 Verified
parent 1a2349e017
commit 644b566668
5 changed files with 140 additions and 68 deletions
+15 -1
View File
@@ -58,6 +58,20 @@ Typical entry points:
- `connect(...)` - `connect(...)`
- `compile()` - `compile()`
`in_map` and `out_map` remain authoring convenience parameters. The compiled
core `NodeUse` shape is canonical `input` and `output` binding lists:
```json
{
"input": [{"target": "text", "path": "input.text"}],
"output": [{"source": "echoed", "target": "state.echoed"}]
}
```
Authoring should not teach client LLMs that `in_map`, `input_values`, or
`out_map` are the preferred core model. Those names are compatibility inputs
and Python-builder sugar.
### `NodeCatalog` ### `NodeCatalog`
LLM-facing registry of available nodes. LLM-facing registry of available nodes.
@@ -90,7 +104,7 @@ that references those known nodes. It should not usually generate new raw
2. client LLM selects nodes from the catalog 2. client LLM selects nodes from the catalog
3. client LLM emits graph structure: 3. client LLM emits graph structure:
- node uses - node uses
- mappings - canonical input/output bindings
- conditions - conditions
- foreach nodes - foreach nodes
- interrupt nodes - interrupt nodes
+98 -55
View File
@@ -22,68 +22,86 @@ future nested execution:
- nested state reducers can become a differentiator over systems that only merge - nested state reducers can become a differentiator over systems that only merge
whole top-level values whole top-level values
## Canonical Mapping Rule ## Canonical Binding Rule
The graph-facing side of a map is a graph path. The node-facing side is a The graph-facing side of a binding is a graph path. The node-facing side is a
node-local path. node-local path. Core stores node use-site wiring as explicit lists of binding
objects, not as path-keyed maps.
```text ```text
in_map: NodeUse.input:
graph source path -> node-local input path path binding: graph source path -> node-local input path
value binding: JSON value -> node-local input path
out_map: NodeUse.output:
node-local output path -> graph state destination path node-local output path -> graph state destination path
``` ```
Examples: Examples:
```python ```json
in_map = { {
"state.person.name": "user.name", "input": [
"state.digital.email": "user.email", {"target": "user.name", "path": "state.person.name"},
"state.job.title": "job.title", {"target": "user.email", "path": "state.digital.email"},
} {"target": "job.title", "path": "state.job.title"},
{"target": "mode", "value": "fast"}
out_map = { ],
"job.wage": "state.job.wage", "output": [
"job.years": "state.experience.years", {"source": "job.wage", "target": "state.job.wage"},
"user.age": "state.person.age", {"source": "job.years", "target": "state.experience.years"},
{"source": "user.age", "target": "state.person.age"}
]
} }
``` ```
Whole-object mapping remains valid: Whole-object mapping remains valid:
```python ```json
in_map = {"state.person": "user"} {
out_map = {"user": "state.person"} "input": [{"target": "user", "path": "state.person"}],
"output": [{"source": "user", "target": "state.person"}]
}
``` ```
The change from the current implementation is only on the node-local sides: Whole-payload mapping uses the local root path `"."`:
today they are top-level fields; in the target model they may be nested paths.
```json
{
"input": [{"target": ".", "path": "state.rates"}],
"output": [{"source": ".", "target": "state.rates"}]
}
```
Deprecated compatibility inputs are still accepted at model-parse boundaries:
`in_map`, `input_values`, and `out_map`. Validated `NodeUse` models store and
dump only canonical `input` and `output` bindings. `wf_authoring` may still
accept `in_map` and `out_map` as builder convenience parameters, but it compiles
them into canonical bindings.
## Explicitness Rules ## Explicitness Rules
### Node-local writes must not overlap ### Node-local writes must not overlap
`in_map` constructs node input payloads. Its destination node-local paths must `NodeUse.input` constructs node input payloads. Its target node-local paths must
be pairwise non-overlapping. be pairwise non-overlapping.
Valid: Valid:
```python ```json
{ [
"state.person.name": "user.name", {"target": "user.name", "path": "state.person.name"},
"state.person.email": "user.email", {"target": "user.email", "path": "state.person.email"}
} ]
``` ```
Invalid: Invalid:
```python ```json
{ [
"state.person": "user", {"target": "user", "path": "state.person"},
"state.person.name": "user.name", {"target": "user.name", "path": "state.person.name"}
} ]
``` ```
The invalid form would require implicit object patch precedence. Authors must The invalid form would require implicit object patch precedence. Authors must
@@ -91,16 +109,16 @@ choose either whole-object mapping or explicit child mapping.
### State writes must not overlap in one commit ### State writes must not overlap in one commit
`out_map` mutates workflow state. Its destination graph paths must be pairwise `NodeUse.output` mutates workflow state. Its target graph paths must be
non-overlapping inside one logical commit. pairwise non-overlapping inside one logical commit.
Invalid: Invalid:
```python ```json
{ [
"user": "state.person", {"source": "user", "target": "state.person"},
"user.name": "state.person.name", {"source": "user.name", "target": "state.person.name"}
} ]
``` ```
The target model rejects these writes before mutating state. The target model rejects these writes before mutating state.
@@ -115,8 +133,9 @@ target overlaps.
Mapped paths are assertions by the workflow author. Mapped paths are assertions by the workflow author.
- a missing graph source path in `in_map` is a runtime error - a missing graph source path in an input path binding is a runtime error
- a missing node-local output path in `out_map` is a runtime error - a missing node-local output path in an output binding is a runtime error
- an explicit `null` value is different from a missing path
- optional/default behavior must be modeled explicitly later, not inferred from - optional/default behavior must be modeled explicitly later, not inferred from
a missing path a missing path
@@ -140,19 +159,43 @@ creates a reusable boundary for:
## State Declarations and Merge Rules ## State Declarations and Merge Rules
State merge behavior is attached to declared exact state paths while keeping the State merge behavior is attached to declared exact state paths. The canonical
internal representation flat: schema shape is a list of declarations:
```python ```json
fields = { {
"person.name": StateField(type="string", reducer="wf.std.replace"), "fields": [
"person.tags": StateField(type="array", reducer="wf.std.append"), {
"profile": StateField(type="object", reducer="wf.std.merge_object"), "path": "state.person.name",
"schema": {"type": "string"},
"reducer": {"name": "wf.std.replace"}
},
{
"path": "state.person.tags",
"schema": {"type": "array"},
"reducer": {"name": "wf.std.append"}
},
{
"path": "state.profile",
"schema": {"type": "object"},
"reducer": {"name": "wf.std.merge_object"}
}
]
} }
``` ```
Presentation layers may rebuild a tree for humans. Core should keep the simpler Deprecated dict-shaped state fields are still accepted at parse boundaries:
path-keyed representation.
```json
{
"fields": {
"person.name": {"type": "string", "reducer": "wf.std.replace"}
}
}
```
Validated `StateSchema` models store and dump the canonical list shape.
Presentation layers may rebuild a tree for humans.
`wf_authoring` keeps authored schemas nested for humans and LLM clients, but `wf_authoring` keeps authored schemas nested for humans and LLM clients, but
projects nested authored state into this flat exact-path index. For example, a projects nested authored state into this flat exact-path index. For example, a
@@ -242,15 +285,15 @@ Examples a future reducer library could support:
### Phase 1: Nested node-local mappings ### Phase 1: Nested node-local mappings
- allow nested node-local paths on the destination side of `in_map` - allow nested node-local paths on canonical input binding targets
- allow nested node-local paths on the source side of `out_map` - allow nested node-local paths on canonical output binding sources
- reject overlapping write targets - reject overlapping write targets
- commit node output through a validated state patch - commit node output through a validated state patch
- validate top-level node-local roots statically; validate deeper shape when the - validate top-level node-local roots statically; validate deeper shape when the
existing node schema makes that practical existing node schema makes that practical
This phase immediately helps wrappers and structured tools while preserving This phase is implemented in core. It helps wrappers and structured tools while
current state merge behavior. preserving explicit state merge behavior.
### Phase 2: Nested declared state paths ### Phase 2: Nested declared state paths
+7 -4
View File
@@ -244,11 +244,14 @@ arguments:
"required": ["text"] "required": ["text"]
}, },
"state_schema": { "state_schema": {
"fields": { "fields": [
"echoed": { {
"type": "string" "path": "state.echoed",
"schema": {
"type": "string"
}
} }
} ]
}, },
"output_schema": { "output_schema": {
"type": "object", "type": "object",
+7 -4
View File
@@ -389,11 +389,14 @@ Minimal example:
"required": ["text"] "required": ["text"]
}, },
"state_schema": { "state_schema": {
"fields": { "fields": [
"echoed": { {
"type": "string" "path": "state.echoed",
"schema": {
"type": "string"
}
} }
} ]
}, },
"output_schema": { "output_schema": {
"type": "object", "type": "object",
+13 -4
View File
@@ -48,11 +48,14 @@ A minimal draft looks like this:
"required": ["text"] "required": ["text"]
}, },
"state_schema": { "state_schema": {
"fields": { "fields": [
"echoed": { {
"type": "string" "path": "state.echoed",
"schema": {
"type": "string"
}
} }
} ]
}, },
"output_schema": { "output_schema": {
"type": "object", "type": "object",
@@ -109,6 +112,12 @@ Both maps are source-to-destination.
| `in` | graph source path | node-local input path | `"input.text": "message"` | | `in` | graph source path | node-local input path | `"input.text": "message"` |
| `out` | node-local output path | graph state destination path | `"echoed": "state.echoed"` | | `out` | node-local output path | graph state destination path | `"echoed": "state.echoed"` |
Draft `in` and `out` maps are an authoring-layer shape. When a draft is
compiled, the core workflow uses canonical `NodeUse.input` and
`NodeUse.output` binding lists. The old core `in_map`, `input_values`, and
`out_map` fields are parse-only compatibility inputs, not the preferred saved
shape.
Graph source paths in `in` normally start with `input.`, `state.`, or Graph source paths in `in` normally start with `input.`, `state.`, or
`context.`. Node-local paths do not use those prefixes; they are paths inside `context.`. Node-local paths do not use those prefixes; they are paths inside
the target capability's input or output payload. the target capability's input or output payload.