UNPKG

agentfootprint

Version:

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

71 lines (70 loc) • 3.75 kB
/** Counts only: the initial prepared request at the library's provider port. * No token estimate, payload retention, retry total or vendor wire claim. */ export interface RequestJsonSize { /** UTF-16 code units in the JSON representation, including JSON punctuation. */ readonly jsonChars: number; /** UTF-8 bytes in that same JSON representation. */ readonly jsonBytes: number; } type MeasurementBoundary = { readonly boundary: 'initial-prepared-request'; readonly format: 'json-utf8-v1'; }; /** Sizes describe JSON of the canonical request, excluding its root `signal`. * Slot values are serialized separately and do not sum to the request total. * Missing slots were absent/undefined; an empty array still has JSON size. */ export type RequestMeasurement = MeasurementBoundary & ({ readonly status: 'measured'; readonly total: RequestJsonSize; readonly slots: { readonly systemPrompt?: RequestJsonSize; readonly messages?: RequestJsonSize; readonly tools?: RequestJsonSize; }; } | { readonly status: 'unavailable'; readonly reason: 'unsupported-value' | 'cyclic-value' | 'measurement-limit'; }); /** * One message object as {@link measureRequest} measured it at a request's * `messages[i]` — the counts its walk added and its JSON size, so a later call * that hands the same message adds the counts instead of walking it again. * Kept only for a walk that raised nothing (a value the walk refuses is walked * again, and refused again, every call). */ export interface MessageMeasure { /** Values the walk visited inside this message, the message included. */ readonly visited: number; /** Characters the walk counted inside it (string values and keys). */ readonly chars: number; /** The highest value-budget demand its walk made, relative to the count it * started from — `visited` plus the largest array/object it sized up front. */ readonly need: number; /** Its JSON, as one array element: UTF-16 code units and UTF-8 bytes. */ readonly json: RequestJsonSize; } /** Where {@link measureRequest} keeps a message's measurement across the calls * of one run — the receipt memo (`receiptDigests.ts`) is the one owner. */ export interface MessageMeasureCache { measureOf(message: object): MessageMeasure | undefined; keep(message: object, measure: MessageMeasure): void; } /** Internal receipt helper. Read plain data through descriptors so telemetry * does not invoke getters or custom toJSON. Unsupported values fail open with * a reason code, never exception text. Transport adapters remain authoritative * for what they actually serialize; this helper does not validate requests. * * INCREMENTAL. The request's `messages` are measured one element at a time and * the sizes composed (`[` + elements joined by `,` + `]`, spliced into the rest * of the request) — JSON is compositional, so the sum IS the size of the whole. * With a `cache`, a message object already measured this run adds its kept * counts and size instead of being walked again: an agent's request at call k * is call k−1's plus what the loop appended, and measuring it whole every call * grew with the square of the iteration count. Every limit is checked against * the same running counts as a whole walk, so the result — `measured` or the * reason it is `unavailable` — is the one the whole walk gives; pinned by * test/core/agent/receipt/receipt-incremental.test.ts. A cache hit assumes what * the receipt memo assumes: the message's nested values were not edited in * place (`receiptDigests.ts`). */ export declare function measureRequest(request: unknown, cache?: MessageMeasureCache): RequestMeasurement; export {};