UNPKG

agentfootprint

Version:

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

148 lines • 7.46 kB
/** * time/bind — which of the person's windows a tool call carries (time * design § 5.6, § 7.3): fill from one mention, bind by quote, and record a * differing model window and run it. * * Pattern: Walker over recorded rows. The turn's WINDOWS are read from what * the record already holds — this turn's `time-answer` rows (a * mention the person settled in the time ask), a `model` reader's * `time-reading` rows (a reading, never the person's) and the * `clock` row's `control` window — never from words. A `rule` * reading settles nothing: it is a proposal the person confirms * (the owner's decision "Always confirm", time design TQ29). One call's decision * ({@link callWindowOf}) is a pure function of its arguments, the * tool's forms and those windows. * Role: L0 leaf (the time layer). Imports `convert.ts`, `range.ts`, * `rows.ts`, `resolve.ts`' types and `zone.ts` only. Asked by the * inputs layer (`arguments/resolve.ts`), which files the argument * rows and the `call-window` row the decision implies. * Emits: N/A. * * ## The laws * * - **Fill only when the turn has exactly one window.** A message holding two * mentions ("this morning vs yesterday morning") fills nothing: which one a * call means is the model's to say, through the quote. A mention whose * reading is still open (the person has not chosen) is counted and fills * nothing; a refused mention (its quote was not in the message) is not the * person's words and is not counted. A `control` window (`time.window`, set * in a UI) counts as one more mention with no quote. * - **Fill only what the model left out — exactly, else wider, never * narrower.** Every argument of every form must be missing; the window goes * into the first form that holds it exactly (`convert.ts` · `convertExact`), * else the first that holds MORE (`convertWidened`: a whole day, the * covering look-back — recorded with what it adds). No such form → the call * is REFUSED, `no-form-holds` (`convert.ts` · `convertForTool`, the one * answer): the tool's own rule never stands in for the person's window, so * an assumed `1h` never silently reads a time the person did not ask about. * - **Refuse before dispatch what the tool cannot honestly read (step * T5b).** A window — the person's to fill, or the model's sent — outside * the tool's declared `direction`, wholly beyond its `retention` or wider * than its `maxRange`; a range across days for a tool whose every form is a * `day`; a window of the person's no form can read (`no-form-holds`); a * sent wall time the zone skips. A window only partly beyond `retention` * runs, marked. An open reading the tool can read in NO reading is refused * too, and never asked. * - **A present window is never written over.** Bound by quote (the model's * declared `user` quote names a recorded mention) or by value (the sent * value, read back, IS a window of this turn); otherwise it runs as sent and * is recorded `model-chosen` beside the person's window — a drill-down, a * comparison and a baseline call are normal work. */ import { type Conversion, type PeriodFacts, type PeriodForm, type TimeRefusal, type WidenedConversion } from './convert.js'; import type { InstantText } from './instant.js'; import type { TimeRange } from './range.js'; import type { ZoneName } from './zone.js'; export { isOpenForPerson, offeredLookback, pendingQuotesOf, readerWindowsOf, turnWindowsOf, windowToConvert, type ReaderWindows, type RefusedWindow, type TurnWindow, type TurnWindows, type WindowSource, } from './windows.js'; import { type TurnWindow, type TurnWindows } from './windows.js'; /** What the inputs layer knows about one call to a tool that declares period forms. */ export interface CallToBind { readonly args: Readonly<Record<string, unknown>>; readonly forms: readonly PeriodForm[]; /** The argument is missing from the call (`tools/declare.ts` · `isMissing`). */ readonly isMissing: (argument: string) => boolean; /** * Under declared sources: the quotes the model declared (`source: 'user'`) * for this call's period arguments. Absent when the arm is off. */ readonly quotes?: readonly string[]; /** * The tool's declared facts (`direction`, `retention`, `maxRange`, * `filtersToAsked`) — a call whose window breaks one is refused before * dispatch (step T5b). Absent: nothing is checked. */ readonly facts?: PeriodFacts; } /** The clock and zones a decision reads. */ export interface BindContext { readonly now: InstantText; readonly zone: ZoneName; readonly appZone?: ZoneName; readonly granularityMs: number; } /** The decision for one call — see {@link callWindowOf}. */ export type CallWindow = /** The model left every period argument out and the turn's one window went into `form` exactly. */ { readonly how: 'filled'; readonly window: TurnWindow; /** Exact, or — when no form holds the window exactly — WIDENED (it carries `sent` and `extra`). */ readonly conversion: Conversion | WidenedConversion; /** Widened, and the tool declares `filtersToAsked`: it trims its rows to the asked window. */ readonly trimmedByTool?: true; readonly partlyBeyondRetention?: true; } /** The sent window IS one of the turn's windows — named by the model's quote (`quote`) or equal in value (`value`). */ | { readonly how: 'bound'; readonly form: number; readonly asked: TimeRange; readonly window: TurnWindow; readonly by: 'quote' | 'value'; readonly partlyBeyondRetention?: true; } /** The sent window differs from the person's: it runs as sent (§ 7.3, the v1 law). `person` when one window is the person's. */ | { readonly how: 'model-chosen'; readonly form: number; readonly asked: TimeRange; readonly person?: TurnWindow; readonly partlyBeyondRetention?: true; } /** The sent window, and no window of the person's to compare it with. */ | { readonly how: 'model'; readonly form: number; readonly asked: TimeRange; readonly partlyBeyondRetention?: true; } /** * Refused before dispatch (step T5b): the window breaks one of the tool's * facts, spans days for a tool that reads one, or a sent wall time is one * the zone skips (`argument` names it). `asked` and `person` when known. */ | { readonly how: 'refused'; readonly refused: TimeRefusal; readonly form?: number; readonly asked?: TimeRange; readonly person?: TurnWindow; readonly argument?: string; } /** A period argument was sent, and no form reads the call's arguments back as a range. */ | { readonly how: 'unread'; } /** The model left the period out and nothing was filled — why. */ | { readonly how: 'not-filled'; readonly why: 'no-window' | 'several-mentions' | 'open-reading'; }; /** * Which window one call carries (the module laws). Pure: the same call, forms * and windows always give the same decision. */ export declare function callWindowOf(call: CallToBind, turn: TurnWindows, ctx: BindContext): CallWindow; /** The range a decision says the call asks for — the person's on a fill, the sent one otherwise. */ export declare function askedRangeOf(decision: CallWindow): TimeRange | undefined; //# sourceMappingURL=bind.d.ts.map