UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

178 lines • 9.47 kB
/** * read — the ONE recognizer the tool-dispatch loop calls. * * Pattern: one reader, every dispatch door (the `applyResultCeiling` * precedent). The batch loop and the credential/resume execute * boundary both call this at the moment a handler's return lands, so * a resumed call declares its coverage exactly as an inline one; the * raise site (`../../core/agent/stages/toolCalls.ts` · `declareRaisedAbsence`) * calls it on the `absence` a `requestInput` declared (9.114.0). * Role: core/ layer, pure. Recognition and normalization only — the caller * owns the events, the scope write and the delivered status. * Emits: N/A. * * Zero-cost when unused: two `typeof` checks and a key lookup for every * result that is neither shape, and `undefined` back. Nothing is emitted, * nothing is written, and the value the model reads is the value the tool * returned — byte for byte. */ import type { ToolResultStatus } from '../toolOutcome.js'; import { type DeclaredProvenance } from '../described.js'; import { type DeclaredPeriod } from './period.js'; import type { ComposedCoverage } from './composedCoverage.js'; import type { Coverage, InProgressItem, TryInsteadTool } from './types.js'; /** * What the LIBRARY composed for a call of a tool that declares its `search` * (`search/compose.ts`) — the fields a {@link ComposedCoverage} row adds. The * typed items ride `CoverageFacts.coverage.checked`. */ export interface ComposedFacts { /** `'local'` for a first-party tool; `'remote'` over MCP or from a ToolProvider. */ readonly origin: ComposedCoverage['composed']; readonly resultId: string; readonly handle: string; readonly complete: boolean; readonly gaps: ComposedCoverage['gaps']; } /** One coverage statement found in a result, before the caller stamps it with * the call it came from. */ export interface CoverageFacts { readonly kind: 'absence' | 'ledger'; readonly coverage: Coverage; /** Present for `'absence'` — what the search was for. */ readonly lookedFor?: string; /** * Present for `'absence'` when it declared a sentence (9.113.0) — trimmed, * as `absent()` mints it, and never parsed for a tool name. Not a piece of * coverage, so it sits beside `coverage` rather than inside it. */ readonly tryInstead?: string; /** Present for `'absence'` when it declared a typed tool (9.113.0) — a copy. */ readonly tryInsteadTool?: TryInsteadTool; /** * Present for `'absence'` when it declared where it looked and when that * source was measured (honesty step 7b) — the record's camelCase form, read * by the ONE provenance rule a described result is held to; a copy. */ readonly provenance?: DeclaredProvenance; /** * The period the declaration's read covered (honesty step 7b) — the record's * camelCase form, read by the ONE period rule (`period.ts`); a copy. Absent * when none was declared, and when the envelope declared one the rule set * refuses — read, never repaired: it is left off the record (dev-warned) and * the model still reads what the tool wrote. */ readonly period?: DeclaredPeriod; /** * Present for a `coverage()` ledger that declared a well-formed, non-empty * `in_progress` — what its read found still running, its outcome not known * yet (`inProgress.ts`). A malformed list is left off the record (dev-warned) * and the model still reads what the tool wrote. */ readonly inProgress?: readonly InProgressItem[]; /** * Present only when the library composed this statement from the tool's * `search` — never read off an envelope: a value cannot forge it. */ readonly composed?: ComposedFacts; } /** What one recognized result declares. `undefined` from * {@link readCoverageResult} means "neither shape": untouched path. */ export interface CoverageReading { /** * The status the framework DELIVERS for this call. `'absent'` when an * absence is in play — never `'failure'`, and that is the point: a status * of `'failure'` would route an honest empty answer down the same edge as * a broken collector, which is the exact confusion the primitive removes. * Undefined for a bare ledger — a ledger says nothing about the outcome, * only about its boundary. */ readonly status?: ToolResultStatus; /** In declaration order: the outer ledger first, then the absence it * wraps. Usually one entry; two only when an author bounded an absence. */ readonly declared: readonly CoverageFacts[]; } /** * The value the MODEL is served for one finalized tool result: a recognized * envelope with `short` and `kind` removed from every coverage item. They are * RECORD-ONLY: the events, the tracked `coverageDeclared` rows and the answer * account carry them; the model's request never does, so a tool that * declares them costs no request byte. * * And one thing ADDED, derived from what the tool declared (honesty step 7b, * bench round 1): a declared `period` whose store did not hold all of the * time the read asked about is served with its verdict word and that word's * one note clause (see `withPeriodServed`). A `covered` period, a malformed * one and a result with none gain nothing. * * The shapes, and nesting: a bare absence; a ledger — its own lists AND * whatever it bounds, read by this same function (so `coverage(absent(…))`, * `coverage(coverage(…))` and a semantic envelope under a ledger are all * served stripped; the depth is whatever the author built); and a semantic * envelope's `coverage`. * * NOT stripped, because none is a recognized envelope OBJECT: a result * returned as JSON TEXT (an `mcpClient` result in its default text mode is * one), an `af_absent` whose `checked` is empty or missing (the recognizer * refuses it, so it is ordinary data — served and recorded as written), and * an absence buried inside a tool's own domain object or array. A key whose * value is `null` counts as omitted (a JSON producer's `None`), so it is * served as written and stamps nothing. * * Zero-cost when unused: the SAME reference back for every value that is not * a recognized envelope, and for every envelope whose items declare neither * key — so a caller that stamps `tool_end.modelResult` by reference * inequality stamps nothing new. A structural copy only when a key was * present. * * Asked at the ENTRY of `../../core/agent/stages/toolCalls.ts` · `afterMoment`, which every * dispatch path (the batch loop and the four resume doors) calls for a result * that ran — so every after-tool link is handed the served value, and none * can re-serve the fields — and by the result ceiling and the column judge at * both execute boundaries, which measure what the model will read. */ export declare function servedToModel(value: unknown): unknown; /** * True when `modelResult` is exactly what {@link servedToModel} produced from * `result` — the two channels carry ONE value and differ only by the * record-only fields. `../../core/agent/stages/toolCalls.ts` · `placeResults` then gives * both channels the ticket, as it does when they are one reference, so a * declaring tool never keeps its whole payload on `tool_end.result`. */ export declare function strippedOnly(result: unknown, modelResult: unknown): boolean; /** * Pure: the served form of `value`, and nothing remembered (the answer account * reads through this; the dispatch door asks {@link servedToModel}, which also * records the pair for `strippedOnly`). * * `seen` guards a ledger that bounds ITSELF (`v.result = v`, directly or * further down): a holder met twice is returned as found, so a pathological * cycle is served as written instead of overflowing the stack. */ export declare function strip(value: unknown, seen?: WeakSet<object>): unknown; /** * The inverse of the serve, for a reader of what the model was served: every * declaring object's verdict word and period clause removed (the note swap is * kept — it is the absence's own static note), the rest as found. The same * reference back when nothing was served. Asked by the evidence projection * (`evidence.ts` · `absenceEvidenceProjection`): words the library derived * never ground an answer. * * It walks the shapes the serve writes — an object with a `period`, and a * ledger's `af_coverage` and `result`, to any depth — and nothing else. */ export declare function withoutServedPeriod(value: unknown, seen?: WeakSet<object>): unknown; /** * Read one finalized tool result for coverage declarations — and, since * honesty step 7b, for the period each declaration's read covered and an * absence's source and time. `toolName` names the tool in the one dev * warning a malformed period or provenance gets (it is left off the record, * never repaired); the dispatch door passes it, a post-hoc reader need not. * * The two shapes compose: `coverage(absent({…}), {…})` is a search that found * nothing AND a boundary around the search, so both are declared and the * delivered status is still `'absent'` — the ledger bounds the answer, it * does not change what the answer was. */ export declare function readCoverageResult(value: unknown, toolName?: string): CoverageReading | undefined; //# sourceMappingURL=read.d.ts.map