agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
120 lines • 6.42 kB
TypeScript
/**
* What every row reader shares: the view, the declarations, the per-sentence
* catch, and the small pointer / var builders.
*
* `say` is THE way a reader writes a line. It fills the template and, when the
* fill throws (a programming error — a var the reader forgot), writes
* `unreadable.line@1` instead and counts it in `unread`. One bad line never
* crashes the account.
*/
import { parseMaybeJson, readEmptiness, type EmptinessReading } from '../../core/agent/emptiness.js';
import { type SentenceSpec } from '../render.js';
import type { TemplateId } from '../templates.js';
import type { AccountSource, AnswerAccountDeclarations, RecordPointer, Sentence, SentenceVar } from '../types.js';
import { type RecordingView, type ViewEvent } from '../view.js';
export interface ReadContext {
readonly view: RecordingView;
readonly declarations: AnswerAccountDeclarations;
/** A resumed leg: a `pause.resume`, or a `turn_end` with no `turn_start`. */
readonly resumedLeg: boolean;
/** The iteration of the last `stream.llm_start` before `turn_end` (the answering iteration). */
readonly answeringIteration?: number;
/** Write one line through the per-sentence catch. */
say(id: TemplateId, spec?: SentenceSpec): Sentence;
/** Count one row the account passed over because its shape did not fit. */
noteUnread(): void;
/** Items (and their characters) already printed — the readability budget. */
readonly budget: {
itemChars: number;
items: number;
};
}
/**
* The bulleted items the account prints IN TOTAL — declared coverage items and
* flagged values. Each item rides a sentence (its text three times: `text`,
* `parts`, `vars`, plus pointers, about 1 KB of structure), so both the count
* and the characters are bounded; past either, items fold into `items.more@1`
* for readability. `size.ts` separately enforces the serialized-byte bound.
*/
export declare const ITEM_BUDGET: {
readonly items: 12;
readonly chars: 3000;
};
/** Take one item of `chars` characters from the budget; `false` = fold it. */
export declare function takeItem(ctx: ReadContext, chars: number): boolean;
/** @internal — a test hook: force the fill of one template id to throw. */
export interface AccountInternals {
readonly failTemplate?: string;
}
/**
* Long text the account prints in TOTAL, past the first `SHORT_TEXT_CHARS` of
* each value: once spent, every later value is cut at `SHORT_TEXT_CHARS` (marked
* `clipped`, followed by `part.clipped@1`). This keeps ordinary accounts
* readable; `size.ts` separately enforces the serialized-byte bound.
*/
export declare const LONG_TEXT_BUDGET = 3000;
export declare const SHORT_TEXT_CHARS = 300;
/**
* A text value a call's FACT carries is cut here (the sentence that prints it
* carries up to 2,000). A cut that keeps an ordinary account readable; the
* account's size bound itself is measured in bytes (`../size.ts`).
*/
export declare const FACT_TEXT_CHARS = 200;
export declare function makeSay(internals: AccountInternals | undefined, onUnread: () => void, budget?: {
longChars: number;
}): (id: TemplateId, spec?: SentenceSpec) => Sentence;
export declare const jsonPointer: (...keys: readonly (string | number)[]) => string;
/**
* A pointer the account did not build itself — the standing fold's witnesses
* (`core/agent/assessment/assess.ts`) — with its identity cut as the
* builders below cut theirs.
*/
export declare function boundedPointer(p: RecordPointer): RecordPointer;
export declare function at(event: ViewEvent, ...keys: readonly (string | number)[]): RecordPointer;
/** A derived leaf on an event (`#emptiness`, `#meta/runId`). */
export declare function derived(event: ViewEvent, path: string): RecordPointer;
export declare const stateAt: (key: string, ...keys: readonly (string | number)[]) => RecordPointer;
export declare const historyAt: (index: number, path: string, toolCallId?: string) => RecordPointer;
export declare function declarationAt(declarations: AnswerAccountDeclarations, field: string): RecordPointer;
/** A tool name the LIBRARY recorded (its claims are vouched by the template). */
export declare const toolVar: (name: string, from?: RecordPointer) => SentenceVar;
/**
* The `{{name:skill}}` pair: the id (library) and, when there is one, its plain
* label — the recorded `title` (library) or the app's declared label (app).
*/
export declare function skillVars(ctx: ReadContext, name: string, id: string, from?: RecordPointer): Record<string, SentenceVar>;
export { parseMaybeJson, readEmptiness, type EmptinessReading };
/** The app's declared rows key for one tool, when it declared one. */
export declare const rowsAtOf: (declarations: AnswerAccountDeclarations, toolName: string) => string | undefined;
/** The source a sentence's emptiness claim rests on. */
export declare const emptinessSource: (reading: {
readonly source?: 'library' | 'app';
}) => AccountSource;
/**
* The count a fact carries from one reading — ONE owner for the three fact
* kinds (this run's calls, the calls before a pause, the earlier answers in
* view): how many rows, who counted them, and where in the value read the
* count was taken (a JSON pointer; "show me" points there — `shown.ts`).
*/
export declare const countedFields: (reading: EmptinessReading) => {
readonly rows?: number;
readonly emptinessSource?: 'library' | 'app';
readonly countedAt?: string;
};
/**
* `sharedState.history`, when it is an array — and EMPTY when the record keeps
* it out (a redaction policy's placeholder). It asks the view first, so the
* view's guard counts the kept-out history as handled; a reader that would
* otherwise say something about what the history lacks asks
* `view.isStateKeptOut('history')` itself (`inView.ts`, `checked.ts`).
*/
export declare function historyOf(view: RecordingView): readonly unknown[];
/**
* True when this recorded history entry is a message a PERSON wrote — the
* one rule (`lib/saidByPerson.ts` · `isSaidByPerson`), read off a record. A
* `role: 'user'` entry is not enough: the library writes frames in that role
* (an evidence correction, a budget wrap-up, a drop notice), and one that
* lands after a turn's results would move "the current request" past them.
*/
export declare function isPersonEntry(entry: unknown): boolean;
//# sourceMappingURL=common.d.ts.map