feat: unify JSON value schema DSL
This commit is contained in:
@@ -44,7 +44,7 @@ A `workflow` tool mirroring `dsh-tool-subagent`'s synchronous shape: start, awai
|
||||
|
||||
An output schema makes a schema-valid committed capture mandatory for successful child completion. The scoped runtime presents the capture tool and instruction, commits only a successful final outcome—including the enclosing `run_code` outcome for an SDK call—denies later side effects after capture becomes pending, and stops the child without another model step after commit. A validation failure remains a retryable tool error; clean completion without a committed capture settles as an error.
|
||||
|
||||
`StructuredOutputSchema` is the raw enforceable JSON-Schema subset in `dsh-tools` (single-string `type`, `properties`/`required`/`additionalProperties`, `items`, scalar `enum`/`const`), and unsupported keywords fail loudly because that wire data becomes the capture tool's parameters verbatim. The [agent-scope runtime-design Agent Note](../architecture/2026-07-12-agent-scope-runtime-design.md#structured-output-commits-only-authoritative-outcomes) owns the assembly, commit, guard, and terminal-stop correctness algorithms.
|
||||
`ObjectJsonSchema` is the object-rooted consumer view of the unified enforceable raw JSON Schema subset in `dsh-tools`; unsupported keywords fail loudly because that wire data becomes the capture tool's parameters verbatim. The [unified JSON-value schema Agent Note](../architecture/2026-07-20-unified-json-value-schema-dsl.md) owns the vocabulary and validation semantics, while the [agent-scope runtime-design Agent Note](../architecture/2026-07-12-agent-scope-runtime-design.md#structured-output-commits-only-authoritative-outcomes) owns the assembly, commit, guard, and terminal-stop algorithms.
|
||||
|
||||
## Testing
|
||||
|
||||
@@ -68,7 +68,7 @@ Worker-side logic runs through an in-process `MessageChannel` so V8 coverage mea
|
||||
- **Background execution as the default** (CC's shape): deferred; foreground-synchronous matches `dsh-tool-subagent`'s cut, and background semantics should be designed ONCE across bash/subagent/workflow rather than per-tool.
|
||||
- **Workflow-layer JSON parsing for `agent({schema})`**: duplicating a seam concern at one consumer while the seam's capability flag stayed dishonestly `false`.
|
||||
- **Meta embedded in the script as `export const meta = {...}`** (CC's exact format): keeps scripts self-contained and CC scripts drop-in, but obtaining meta requires evaluating model-written text on the host. Even an empty timed vm context cannot bound script-controlled getters when the host reads the resulting object. A JSON parameter removes the scanner, evaluation, and host-spin hole; the cost is that a CC script's meta header must move into the parameter (the body stays drop-in).
|
||||
- **`SchemaSpec` as the outputSchema type**: the author-facing DSL cannot express what arrives as data and cannot be validated against without conversion loss.
|
||||
- **`ValueSchemaSpec` as the `outputSchema` wire type**: the author form now has equivalent vocabulary, but a workflow supplies realm-foreign raw JSON Schema data; pretending that runtime data is a trusted author declaration would skip the raw-schema assertion boundary.
|
||||
- **A schema-object library (zod, or the repo's schemastery) for the structured-output subset**: the schema is wire data — plain JSON that crosses the vm realm boundary in `agent({schema})` and lands verbatim in the forced tool's parameters — exactly where live schema objects cannot sit; consuming raw JSON Schema at runtime would need a third-party converter on top (zod core only emits JSON Schema, not the reverse), and it would put a second schema language beside schemastery's config role.
|
||||
- **ajv for value validation**: it validates FULL JSON Schema, so the subset gate — the module's actual point, since every accepted keyword must be one the harness enforces — would remain hand-written regardless; it compiles validators through `new Function`; and it would be dsh-tools' first runtime dependency, all to replace the ~70-line value walker while the path-qualified, every-violation error reporting stays custom either way.
|
||||
- **Provider JSON mode instead of the capture tool:** it guarantees valid JSON, not schema conformance, and its interaction with tool calling is unclear. The capture tool preserves in-turn validation retries. Provider-side strict tool schemas can later narrow the accepted subset without changing this design.
|
||||
|
||||
@@ -32,7 +32,7 @@ Sandbox globals are deliberately small: a tagged write-through `console` (`[cord
|
||||
|
||||
Mount code crosses the vm boundary through three controls. Dual-realm `instanceof` recognizes both host and vm objects. `harness.defineTool` normalizes results into host-realm JSON and validates the `ToolExecuteReturn` shape before logging. The mounted plugin receives a whitelist context façade, not a raw or pass-through `Context`; framework plumbing and context-valued returns are rejected. Service reads require a declared `inject`, preserving Cordis activation and unload semantics. `ctx.tools.get` exposes only the schema view, so mounted code cannot bypass `ToolRegistry.execute` by calling a definition directly.
|
||||
|
||||
The boundary normalizes unambiguous JSON-Schema forms into `SchemaSpec`, including object wrappers, `integer`, and optional fields. Invalid vocabulary fails with the accepted alternatives. Parse, TypeScript, missing-return, Node-API, and duplicate-tool errors include the relevant source line or corrective contract without narrating implementation internals.
|
||||
The boundary normalizes unambiguous JSON-Schema forms into `ParameterSchemaSpec`, preserving `integer`, raw object openness, and required arrays. Direct DSL object nodes must declare `additionalProperties`; invalid vocabulary fails with the accepted alternatives. Parse, TypeScript, missing-return, Node-API, and duplicate-tool errors include the relevant source line or corrective contract without narrating implementation internals.
|
||||
|
||||
### The dynamic group and mount lifecycle
|
||||
|
||||
@@ -60,7 +60,7 @@ Model-visible ⟺ logged holds with no new session event type: a mount or unmoun
|
||||
|
||||
| Dimension | Structured per-capability tools | Single `cordis_mount` |
|
||||
|---|---|---|
|
||||
| Schema correctness | `parameters` is still a model-written JSON object needing SchemaSpec validation, merely one step earlier | The same validation runs at the sandbox boundary, with the same instructive errors |
|
||||
| Schema correctness | `parameters` is still model-written JSON needing unified-schema validation, merely one step earlier | The same validation runs at the sandbox boundary, with the same instructive errors |
|
||||
| The code field | An `execute` body is still model-written JS in a vm; the realm and service-call correctness problems are unchanged | One sandbox, one normalization path, one guarded registration |
|
||||
| Capability coverage | Tools only; listeners, services, `inject` relations each need another structured tool — a surface that grows without bound | One vocabulary (a cordis plugin) covers every effect, present and future |
|
||||
| Cross-mount composition | Not expressible in a tool-registration payload | Native `provide`/`inject`, ordinary cordis semantics |
|
||||
|
||||
Reference in New Issue
Block a user