agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
87 lines (86 loc) • 4.68 kB
TypeScript
/**
* nativeOutputFormat — the ONE builder of the JSON Schema that
* `.outputSchema(parser, { strategy: 'native' })` sends as the provider's
* structured-output format (Anthropic's `output_config.format`).
*
* Pattern: pure transform over plain JSON, run once at build
* (`AgentBuilder · resolveOutputEnforcement`); no scope, no I/O.
* Role: core/ agent leaf. Its input is the SAME schema the `'tool-forced'`
* strategy puts on its synthetic tool (`outputEnforcement.ts ·
* resolveJsonSchema`: the `jsonSchema` option, else the parser's own
* `toJsonSchema()`), and the SAME parser judges every answer after —
* so the wire copy may be looser than the contract, never different
* from it.
*
* THE RULES, from Anthropic's structured-outputs page ("JSON Schema
* limitations", fetched 2026-10-14 —
* https://platform.claude.com/docs/en/build-with-claude/structured-outputs),
* and the shape of the SDK's own transform (`@anthropic-ai/sdk` ·
* `transformJSONSchema`, which moves what the API does not take into the
* description):
* - KEPT: `type`, `properties`, `required`, `items`, `anyOf`, `allOf`,
* local `$ref` with `$defs` / `definitions`, `enum` and `const` of
* scalars, `default`, `description`, `title`, the ten supported string
* `format`s, `minItems` of 0 or 1, and a `pattern` with no backreference,
* lookaround or word boundary. `oneOf` is sent as `anyOf`.
* - CLOSED: every object gets `additionalProperties: false` — the only value
* the API takes.
* - MOVED INTO THE DESCRIPTION, on the wire copy only: every constraint the
* API does not take (`minimum`, `maximum`, `multipleOf`, `minLength`,
* `maxLength`, `minItems` above 1 — sent as 1 —, `maxItems`, an
* unsupported `format` or `pattern`, …). The model still reads them; the
* parser still enforces them.
* - REFUSED BY NAME (`NativeOutputSchemaError`): what the API cannot express
* — a recursive schema, an external or dangling `$ref` (checked on the
* source AND on the wire copy, whose renamed paths a reference could
* miss), an `enum` or `const` holding an object or array, `allOf` beside
* a `$ref`, a node with no type (an open `unknown` value), and an object
* with open keys (`additionalProperties` given a schema, `true` or `{}`
* on an object naming no properties, a bare `{ type: 'object' }`, or
* `patternProperties`: closing it would make every map empty while the
* parser accepted it), and object intersections through `allOf` (closing
* each branch can make the intersection impossible).
* - DROPPED: the meta keys `$schema`, `$id`, `$comment`, `$anchor`.
*
* THE RESERVED `_findings` KEY. With `.findings()` armed, the instruction tells
* the model it may carry its standings on a JSON answer as a top-level
* `_findings.previous`. Under `additionalProperties: false` a key the schema
* does not name cannot be written at all, so the answer standings would stop
* without a sound. Armed, the root gains the optional `_findings` property
* the served contract allows (`findings/reserved.ts · findingsAnswerSchema`) —
* unless the author's schema names its own `_findings`, which wins; a root
* that is not an object cannot carry it and is refused. Unarmed, the schema
* is the author's alone.
*
* @example
* nativeOutputFormat(
* { type: 'object', properties: { n: { type: 'integer', minimum: 1 } }, required: ['n'] },
* { findings: false },
* );
* // { type: 'json_schema', schema: { type: 'object',
* // properties: { n: { type: 'integer', description: '{minimum: 1}' } },
* // required: ['n'], additionalProperties: false } }
*/
type Json = Readonly<Record<string, unknown>>;
/** What `LLMRequest.outputFormat` carries. */
export interface NativeOutputFormat {
readonly type: 'json_schema';
readonly schema: Json;
}
/** A schema the provider's structured output cannot express, named. */
export declare class NativeOutputSchemaError extends Error {
/** JSON-pointer-like path of the node refused (`'#'` is the root). */
readonly path: string;
constructor(path: string, reason: string);
}
/**
* The structured-output format for `jsonSchema`, made API-compatible as the
* file header lists, with the reserved `_findings` property when the findings
* ledger is armed. Deep-frozen; the input is never edited.
*
* @throws NativeOutputSchemaError naming the node the API cannot express.
*/
export declare function nativeOutputFormat(jsonSchema: Json, arms: {
readonly findings: boolean;
}): NativeOutputFormat;
export {};