fix review findings: own-property and plain-JSON discipline in the schema subset
Three Codex findings on json-schema.ts, one discipline: - required-declared and every value check now use Object.hasOwn — 'in' let inherited names (toString) satisfy required, dodge additionalProperties: false, and validate a declared property against the value's prototype member instead of a carried one - isObjectLike now means PLAIN JSON object (proto chain of at most one link, realm-agnostic): a Date annotation or a Map-as-properties no longer passes structurally and serializes lossily — they fail loud as subset violations - startInProcessRun asserts BEFORE the defensive structuredClone, so a hostile schema fails as OutputSchemaError, never a raw DataCloneError Also the type-equiv catalog gap: tools.md gains the structured-output subset vocabulary (4 blocks) with matching manifest entries. The driver index also drops the runtime internals from its public re-export (runs acquire it internally; no external consumer remains — see the following commit).
This commit is contained in:
@@ -138,6 +138,40 @@ type PostToolDecision =
|
||||
|
||||
Call `next()` to delegate to the default (allow / accept-unchanged), or return a decision to short-circuit. A `pre-execute` `deny` (or `ask`, which degrades to deny until the permission system lands) skips dispatch and yields an `isError` result; input rewrite is deliberately NOT offered on `PreToolDecision` (it would desync the pre-execution audit/history/UI from what ran — its own proposed RFC). A `post-execute` `accept` may replace the model-facing `content` (clean, because `tool/result` is logged after `execute()` returns); a `block` turns the call into an `isError` whose content is the corrective `feedback`. Core dispatch sits between the waterfalls as plain code; the tool body keeps its own try/catch so a thrown tool still reaches `post-execute` as an `isError`. An unregistered tool routes through the same catch as a tool-thrown error, so both failure classes get a structured `{ name, code }` (`ToolNotFoundError` → `UNKNOWN_TOOL`) — the loop records a failed tool call instead of failing the whole turn.
|
||||
|
||||
## The structured-output schema subset
|
||||
|
||||
The vocabulary a caller uses to demand a machine-readable result from a subagent (`SubagentStartRequest.outputSchema`, [subagent.md](subagent.md#the-start-request)) or a workflow `agent()` call. It is deliberately NOT full JSON Schema: the schema travels verbatim to the model as a forced tool's `parameters`, and the produced value is validated client-side by `validateStructuredValue` — so every accepted keyword must be one the validator actually enforces, and `assertSupportedOutputSchema` rejects anything else loud (`OutputSchemaError`, listing every violation). Both walkers reason over own enumerable properties only (JSON carries nothing else) and reject non-plain objects (`Date`, `Map`) that would serialize lossily.
|
||||
|
||||
```ts type-equiv
|
||||
type StructuredScalar = string | number | boolean | null
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
type StructuredSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null'
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
interface StructuredSchemaNode {
|
||||
type: StructuredSchemaType
|
||||
properties?: Record<string, StructuredSchemaNode>
|
||||
required?: string[]
|
||||
additionalProperties?: boolean
|
||||
items?: StructuredSchemaNode
|
||||
enum?: StructuredScalar[]
|
||||
const?: StructuredScalar
|
||||
description?: string
|
||||
title?: string
|
||||
default?: unknown
|
||||
examples?: unknown
|
||||
}
|
||||
```
|
||||
|
||||
A schema is an object-rooted node (`enum`/`const` are scalar-only; `description`/`title`/`default`/`examples` are annotations, allowed and ignored but still required to be JSON data — they ride the wire):
|
||||
|
||||
```ts type-equiv
|
||||
type StructuredOutputSchema = StructuredSchemaNode & { type: 'object' }
|
||||
```
|
||||
|
||||
## Tool-presentation UI vocabulary
|
||||
|
||||
How a tool wants its call shown in a UI (an editor tool-call card, a CLI log line), provider-neutral so a tool describes itself without depending on any client protocol. `presentCall`/`presentResult` return a **`card`-tagged render intent** — a discriminated union a UI bridge switches on:
|
||||
|
||||
Reference in New Issue
Block a user