UNPKG

agentfootprint

Version:

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

140 lines • 7.21 kB
/** * hosting/artifactWire — the wire grammar for redeeming claim tickets, owned * once. * * The artifacts layer (9.21–9.22) taught tools and the model to route refs * instead of hauling data; `present({ ref, as })` hands one to the screen. * This module is the screen's half of that handshake: the two WIRE OPERATIONS * a hosting door answers so a frontend can redeem the ticket — * * `{ op: 'artifact-head', ref }` → the ticket's metadata (the render * decision: pick a component from `kind` * and `bytes` without paying for bytes) * `{ op: 'artifact-get', ref }` → metadata + the payload (render it) * * Read-only on purpose. The wire deliberately carries NO put/delete/list: * a screen redeems tickets, it does not mint or sweep, and `list` over a wire * would let a caller ENUMERATE a scope — possession of a ref is the whole * entitlement this door honours, and even that only under the requesting * session's identity-composed scope (`standingAgent` composes it; the store * enforces it). * * ── Why ONE owner ──────────────────────────────────────────────────────────── * Two shipped dialects speak these ops (`jsonWire`, and the managed-runtime * wire in `adapters/hosting/`) and any custom `HttpWire` may join them. An op * grammar re-derived per dialect is how one of them ends up accepting * `'artifact-head'` and another `'artifactHead'` — so the reader, the op names * and the standard reply body live here and every dialect calls them (the * `headerValue` precedent). * * ── The refusal law ────────────────────────────────────────────────────────── * A body that NAMES an `op` never falls through to a model turn. A caller who * typo'd `'artifact-head'` and silently got a conversation turn (with the ref * as garbage input) would be the accepted-and-silently-wrong failure, so an * unknown op — and a known op missing its `ref`, or naming one that is not a ref * (`isArtifactRef`) — throws {@link InvalidWireOpError}, which `httpHost` * answers as that request's 400. */ import type { ArtifactMeta } from '../artifacts/types.js'; import type { AnswerAccount, AnswerAccountShownLeaf } from '../answer-account/types.js'; /** * The refusal for a `ref` that is not a claim ticket — one sentence, shared by * the wire readers and the composer's own check, and never echoing the text. * * @internal */ export declare const NOT_A_REF: string; /** The wire spelling of `head` — metadata only, the render-by-ref decision. */ export declare const ARTIFACT_HEAD_OP: "artifact-head"; /** The wire spelling of `get` — metadata + payload. */ export declare const ARTIFACT_GET_OP: "artifact-get"; /** * The wire spelling of `account` — one answer's plain-words account, computed * on the server from the recording the ref names (explain-answer). * * @internal Read through `WIRE_OPS.answerAccount` from the barrel. */ export declare const ANSWER_ACCOUNT_OP: "answer-account"; /** The wire spelling of a port-side verb — what every refusal names. */ export declare function artifactOpWireName(op: ArtifactWireRequest['op']): string; /** * One artifact operation, as a request carries it — the port-side shape * behind the wire's `{ op, ref }`. * * `op` is the store's own verb vocabulary (`head` | `get`), not the wire * spelling: the wire says `'artifact-head'` because a body field named `op` * has to say which domain it belongs to; the port already knows. */ export interface ArtifactWireRequest { /** * Which read to run: `head`, `get`, or `account` — the answer account of the * recording the ref names (wire spelling `'answer-account'`). */ readonly op: 'head' | 'get' | 'account'; /** The claim ticket to redeem (`art_…`). */ readonly ref: string; } /** * What a resolved artifact operation hands the reply — everything a wire * needs to compose its body. */ export interface ArtifactWireResult { /** The verb that ran. `data` is present iff it was `get`; `answer` iff `account`. */ readonly op: 'head' | 'get' | 'account'; /** The ref as requested. */ readonly ref: string; /** * The claim ticket — what `head` returns and what `get` returns beside the * payload. For `account` it is the recording's ticket, which the reply body * does NOT carry (the body is the account and its show-me leaves, nothing * else). */ readonly meta: ArtifactMeta; /** The payload. Present iff `op` is `get`. */ readonly data?: unknown; /** The answer account and its show-me leaves. Present iff `op` is `account`. */ readonly answer?: AnswerAccountWireBody; } /** * What an `answer-account` request answers with: the account, and the leaf * values its "show me" pointers name that pass the allow-list — keyed by * `answerAccountPointerKey(pointer)` (`agentfootprint/observe`). Nothing else * from the recording leaves the server. * * Bounded in serialized JSON UTF-8 bytes: the account is at most 128 KiB; * `shown` reserves the account and JSON frame so this `{ account, shown }` * body is at most 192 KiB. An outer transport envelope is not part of this bound. */ export interface AnswerAccountWireBody { readonly account: AnswerAccount; readonly shown: Readonly<Record<string, AnswerAccountShownLeaf>>; } /** * Read an artifact operation out of a request body, if the body names one. * * Returns `undefined` for a body with no `op` field — an ordinary invoke, * untouched — and for an op that belongs to ANOTHER domain's reader (the * session-history ops, 9.26.0): declining is not the same as refusing, and a * reader that claimed a neighbour's op would be the fork this grammar has one * owner to prevent. Throws {@link InvalidWireOpError} for an `op` nobody * speaks, and for a known op whose `ref` is missing or blank: a request that * NAMED an operation must never quietly become something else. * * Exported for custom {@link import('./httpHost.js').HttpWire} dialects, so a * third dialect reads the ops exactly as the two shipped ones do. */ export declare function readArtifactWireOp(body: Readonly<Record<string, unknown>>): ArtifactWireRequest | undefined; /** * The standard reply body for a resolved artifact operation: * `{ artifact: { ref, meta } }` for `head`, `{ artifact: { ref, meta, data } }` * for `get`, and `{ account, shown }` for `answer-account`. * * Authored once so the two shipped dialects (and any custom one that wants * interop with the lens family's resolver) answer byte-compatibly; a dialect * that must add its own envelope fields spreads this and adds them beside * `artifact` (the managed-runtime wire adds its own `status`). */ export declare function artifactWireBody(result: ArtifactWireResult): { readonly artifact: Readonly<Record<string, unknown>>; } | AnswerAccountWireBody; //# sourceMappingURL=artifactWire.d.ts.map