feat(flow): FlowStep output_mapping, JSON-pointer input_mapping, dynamic params#454
Merged
Conversation
…mic params Implements three related FlowStep I/O wiring features that share the executor's input-binding and output-merge machinery: - output_mapping (#386): optional {context_key: output_key} that renames/prunes a tool's validated outputs before the context merge; raw outputs stay on the StepRecord. Honoured across linear/DAG, sync/async, resume/replay, the builder, serialization, the JSON schema, and compile_flow static validation. Adds OutputMappingError (CW-E041). - JSON-pointer input_mapping (#387): an input_mapping string starting with "/" resolves as an RFC-6901 pointer into the nested context. Plain keys unchanged; misses raise InputMappingError naming the pointer. Pointer logic extracted to a dependency-free chainweaver._pointer module shared with contrib json_pluck so core never imports the optional contrib extra. - dynamic_params (#316): execute_flow/execute_flow_async accept dynamic_params, merged into the running context after input_schema validation (via a run-scoped thread-local, mirroring dry_run) so they reach every step and the final output without appearing in the LLM-visible input_schema. Declarative Flow/DAGFlow.dynamic_params records expected params. Also wraps a pre-existing over-length line in tests/test_release_tooling.py to keep ruff green. https://claude.ai/code/session_019vrFkhFWxGApdEnaqdStiw
Contributor
There was a problem hiding this comment.
Pull request overview
Adds three flow wiring capabilities to ChainWeaver’s executor “data plane” (input binding + context merge): remapping tool outputs before merge, RFC-6901 JSON-pointer lookups for nested inputs, and runtime-injected dynamic parameters that stay out of model-visible input schemas.
Changes:
- Add
FlowStep.output_mappingplus executor/compiler/serialization/schema support and a newOutputMappingError(CW-E041). - Extend
FlowStep.input_mappingresolution to support RFC-6901 JSON pointers (leading/) via sharedchainweaver._pointer. - Add
dynamic_paramsinjection toexecute_flow/execute_flow_async, plus declarativeFlow.dynamic_params/DAGFlow.dynamic_params.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_step_io_wiring.py | New end-to-end tests covering pointer input mapping, output remapping, and dynamic param injection. |
| tests/test_release_tooling.py | Wraps an overlong assertion line to keep linting green. |
| tests/fixtures/public_api.json | Updates the public API fixture for OutputMappingError, Flow.dynamic_params, and FlowStep.output_mapping. |
| schemas/flow.schema.json | Documents and schemas dynamic_params and output_mapping, plus pointer semantics in FlowStep.input_mapping. |
| README.md | Adds user-facing examples for pointer input mapping, output mapping, and dynamic params injection. |
| docs/reference/error-table.md | Registers CW-E041 / OutputMappingError in the error table. |
| docs/concepts/tools-and-flows.md | Documents output_mapping semantics and dynamic_params behavior. |
| CHANGELOG.md | Adds Unreleased entries describing the three new wiring features and behavior change notes. |
| chainweaver/flow.py | Adds FlowStep.output_mapping, Flow.dynamic_params, and DAGFlow.dynamic_params with doc updates. |
| chainweaver/executor.py | Implements output mapping in merge/replay/resume/projection and adds JSON-pointer input resolution + dynamic params injection. |
| chainweaver/exceptions.py | Introduces OutputMappingError and assigns it CW-E041. |
| chainweaver/contrib/tools.py | Refactors contrib pointer handling to reuse chainweaver._pointer. |
| chainweaver/compiler.py | Adds static validation for pointer roots and output_mapping contributions + unknown output key detection. |
| chainweaver/builder.py | Extends FlowBuilder.step() to accept output_mapping=... and documents pointer lookup behavior. |
| chainweaver/_pointer.py | New shared dependency-free RFC-6901 pointer parser/resolver with structured internal error. |
| chainweaver/_execution/context.py | Adds apply_output_mapping() and wires it into merge_step_outputs(). |
| chainweaver/_execution/init.py | Re-exports apply_output_mapping alongside merge_step_outputs. |
| chainweaver/init.py | Exports OutputMappingError in the package public surface. |
| AGENTS.md | Updates the repo map + tables to document output_mapping, pointers, and dynamic_params. |
Address Copilot review on PR #454: - executor.py (#336): move run-scoped state (dynamic_params, active_flow_version, replay/resume markers, stream collector) from a threading.local slot to a per-instance contextvars.ContextVar. Each entry point binds a fresh per-scope copy via _run_scope, so concurrent execute_flow_async tasks sharing one event-loop thread no longer clobber each other's markers across an await (dynamic_params are often per-request secrets). Sub-flow recursion still inherits the parent's values via the scoped copy. Adds a deterministic concurrency regression test. - _execution/context.py: apply_output_mapping fast-paths the no-mapping common case, returning a plain dict unchanged instead of copying on the execution hot path. Callers already treat the result as read-only. - builder.py: document that FlowBuilder.step() reserves the output_mapping keyword and point callers with a tool input field of that name at step_from. - tests/test_step_io_wiring.py: correct the module docstring — input_mapping supports RFC-6901 JSON pointers, not "dotted-path". Docs: refresh the concurrency-contract notes in AGENTS.md and architecture.md and add a CHANGELOG Fixed entry. All four validation commands pass (ruff check, ruff format --check, mypy, pytest: 1697 passed). https://claude.ai/code/session_01NJHQCPbdAVqRR4bqRxnXrR
…triage-l0z4mx # Conflicts: # CHANGELOG.md # chainweaver/compiler.py # docs/concepts/tools-and-flows.md # tests/test_release_tooling.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements three related FlowStep I/O wiring features that share the executor's
input-binding and output-merge machinery:
FlowStep.output_mappingto rename and prune tool outputs before context merge #386): optional {context_key: output_key} that renames/prunesa tool's validated outputs before the context merge; raw outputs stay on the
StepRecord. Honoured across linear/DAG, sync/async, resume/replay, the builder,
serialization, the JSON schema, and compile_flow static validation. Adds
OutputMappingError (CW-E041).
FlowStep.input_mapping#387): an input_mapping string starting with "/"resolves as an RFC-6901 pointer into the nested context. Plain keys unchanged;
misses raise InputMappingError naming the pointer. Pointer logic extracted to a
dependency-free chainweaver._pointer module shared with contrib json_pluck so
core never imports the optional contrib extra.
merged into the running context after input_schema validation (via a run-scoped
thread-local, mirroring dry_run) so they reach every step and the final output
without appearing in the LLM-visible input_schema. Declarative
Flow/DAGFlow.dynamic_params records expected params.
Also wraps a pre-existing over-length line in tests/test_release_tooling.py to
keep ruff green.
https://claude.ai/code/session_019vrFkhFWxGApdEnaqdStiw