212 lines
5.6 KiB
Markdown
212 lines
5.6 KiB
Markdown
# Draft Bind From/To Design
|
|
|
|
## Status
|
|
|
|
Implemented. This design replaces `bind-output-to-state` with the general
|
|
`bind --from ... --to ...` operation. `bind-output-to-state` was introduced
|
|
recently as an incomplete narrow helper and should be removed rather than
|
|
preserved as compatibility.
|
|
|
|
## Problem
|
|
|
|
Agents authoring drafts repeatedly hit the same boundary: step input/output
|
|
bindings are not just path edits. They often require workflow-level schema
|
|
declarations too.
|
|
|
|
Today:
|
|
|
|
- `wf draft set-input` edits a step input map, but it does not declare
|
|
`input_schema.properties.<field>`.
|
|
- `wf draft bind-output-to-state` declares one root state field and writes a
|
|
step output binding, but only covers `local.output -> state.field`. It is too
|
|
narrow now that input-side schema projection is needed too.
|
|
- Agents interpret this split inconsistently, then fall back to raw JSON Patch.
|
|
|
|
The product needs one capability-aware operation with the mental model:
|
|
|
|
```text
|
|
bind <destination> from <source>
|
|
```
|
|
|
|
## User-Facing Shape
|
|
|
|
Primary CLI:
|
|
|
|
```powershell
|
|
wf draft bind <workspace_id> `
|
|
--revision <n> `
|
|
--step <step_id> `
|
|
--from <path> `
|
|
--to <path>
|
|
```
|
|
|
|
Examples:
|
|
|
|
```powershell
|
|
# Workflow input into a capability input.
|
|
wf draft bind browser_ws --revision 2 --step click `
|
|
--from input.simulate `
|
|
--to local.simulate
|
|
```
|
|
|
|
```powershell
|
|
# Capability output into workflow state.
|
|
wf draft bind browser_ws --revision 3 --step click `
|
|
--from local.after `
|
|
--to state.after
|
|
```
|
|
|
|
```powershell
|
|
# Capability output into final workflow output.
|
|
wf draft bind report_ws --revision 7 --step render `
|
|
--from local.markdown `
|
|
--to output.markdown
|
|
```
|
|
|
|
## Semantics
|
|
|
|
`bind` is capability-aware and step-scoped. The step must be a capability-backed
|
|
draft step with a `use` field.
|
|
|
|
Supported directions:
|
|
|
|
| From | To | Draft edit | Schema projection |
|
|
|---|---|---|---|
|
|
| `input.*` | `local.*` | add/merge step input binding | copy capability input schema for `local.*` into workflow `input_schema` at `input.*` |
|
|
| `state.*` | `local.*` | add/merge step input binding | copy capability input schema for `local.*` into workflow `state_schema` at `state.*` |
|
|
| `local.*` | `state.*` | add/merge step output binding | copy capability output schema for `local.*` into workflow `state_schema` at `state.*` |
|
|
| `local.*` | `output.*` | add/merge step output binding | copy capability output schema for `local.*` into workflow `output_schema` at `output.*` |
|
|
|
|
Unsupported directions should fail clearly:
|
|
|
|
- `local.* -> local.*`
|
|
- `input.* -> state.*`
|
|
- `state.* -> output.*`
|
|
- `output.* -> local.*`
|
|
- Any path root outside `input`, `state`, `output`, or `local`
|
|
|
|
## Schema Projection
|
|
|
|
The schema projection helper should be generalized from the current
|
|
output-to-state helper.
|
|
|
|
Requirements:
|
|
|
|
- Use `jsonschema.Draft202012Validator.check_schema` to validate input schemas
|
|
and projected schemas. Do not hand-roll JSON Schema validation.
|
|
- Copy the selected local field schema from the capability input/output schema.
|
|
- Preserve `$defs` and `definitions`, rejecting conflicting definitions.
|
|
- Insert the copied field schema at the target workflow path.
|
|
- Support nested target paths such as `state.options.timeout_seconds`.
|
|
- Create missing ancestor object schemas only when the ancestor does not exist.
|
|
- Reject inserting through an existing non-object ancestor.
|
|
- Reject overwriting an existing target property by default.
|
|
|
|
Nested insertion example:
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"options": {
|
|
"type": "object",
|
|
"properties": {
|
|
"timeout_seconds": { "type": "number" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
This is a schema projection operation, not a general JSON Schema editor. It only
|
|
copies one capability local input/output field schema to one workflow graph path.
|
|
|
|
## API Shape
|
|
|
|
Add the general method:
|
|
|
|
```python
|
|
async def bind_draft(
|
|
self,
|
|
*,
|
|
workspace_id: str,
|
|
revision: int,
|
|
step_id: str,
|
|
source_path: str,
|
|
target_path: str,
|
|
) -> dict[str, Any]:
|
|
...
|
|
```
|
|
|
|
Name notes:
|
|
|
|
- User-facing CLI says `bind --from ... --to ...`.
|
|
- Python/RPC names should avoid reserved words and use
|
|
`source_path` / `target_path`.
|
|
- Remove `bind_output_to_state` end-to-end. It has no long-lived compatibility
|
|
contract and is replaced by `bind_draft`.
|
|
|
|
## RPC And MCP
|
|
|
|
New JSON-RPC method:
|
|
|
|
```text
|
|
workflow.draft_workspaces.bind
|
|
```
|
|
|
|
Params:
|
|
|
|
```json
|
|
{
|
|
"workspace_id": "browser_ws",
|
|
"revision": 3,
|
|
"step_id": "click",
|
|
"source_path": "local.after",
|
|
"target_path": "state.after"
|
|
}
|
|
```
|
|
|
|
New MCP tool:
|
|
|
|
```text
|
|
wf.workflow.bind
|
|
```
|
|
|
|
Remove existing RPC/MCP `bind_output_to_state` surfaces during this slice.
|
|
|
|
## Repair Hints
|
|
|
|
Existing invalid-destination hints currently recommend:
|
|
|
|
```text
|
|
wf draft bind-output-to-state ...
|
|
```
|
|
|
|
They should instead recommend:
|
|
|
|
```text
|
|
wf draft bind <workspace_id> --revision <n> --step <step_id> --from local.<field> --to state.<field>
|
|
```
|
|
|
|
Future missing-input-schema diagnostics can also point to:
|
|
|
|
```text
|
|
wf draft bind <workspace_id> --revision <n> --step <step_id> --from input.<field> --to local.<field>
|
|
```
|
|
|
|
## Non-Goals
|
|
|
|
- Do not preserve `bind-output-to-state` as a compatibility alias.
|
|
- Do not add arbitrary schema editing commands.
|
|
- Do not support array item schema projection.
|
|
- Do not infer routes.
|
|
- Do not mutate bindings without revision checks.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- Agents can fix browser-click input schema issues with `wf draft bind --from
|
|
input.simulate --to local.simulate` instead of raw JSON Patch.
|
|
- Agents can bind outputs with `wf draft bind --from local.after --to
|
|
state.after`; the old `bind-output-to-state` command/method/tool is gone.
|
|
- Nested target paths are handled safely or rejected with clear errors.
|