UNPKG

agentfootprint

Version:

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

224 lines • 11 kB
/** * time/periodForm — a tool's period FORMS as DECLARED (time design § 7.1): * the shapes, the sugar, each form's own rules, a declared value's spelling, * and the tool's facts against a range. * * Pattern: the declaration half of `convert.ts`, split from the conversions so * the SYNCHRONOUS doors — `defineTool({ period })` * (`tools/declare.ts`), a time answer's check at the resume * door (`ask.ts` · `checkTimeAnswer`) and the checkpoint door's * refusal codes (`rows.ts`) — reach it without the conversion * engine, which only an armed agent loads (`bind.ts`, `drift.ts`, * reached through `import()`: the optional-family law of docs-next's * site budget). `convert.ts` re-exports everything public here. * Role: L0 leaf (the time layer). Imports `instant.ts`, `duration.ts` * and `zone.ts` only. * Emits: N/A. * * @example * ```ts * const [form] = sugarForms({ argument: 'window', spelling: 'iso-range' }); * formIssue(form); // undefined — a well-formed form * parsesUnderForm('2026-10-09T08:00:00-07:00..2026-10-09T08:40:59-07:00', form, 'window'); // true * ``` */ import { type DurationText } from './duration.js'; import { type InstantText } from './instant.js'; import { type Edge, type TimeRange } from './range.js'; import { type WallTime } from './zone.js'; /** The single-argument spellings — today's three, and `wall-range` (wall times plus a zone argument). */ export type PeriodSpelling = 'lookback' | 'signed-lookback' | 'iso-range' | 'wall-range'; /** The spellings, in the order the docs list them. */ export declare const PERIOD_SPELLINGS: readonly PeriodSpelling[]; /** How one bound is written: an instant with its offset, epoch milliseconds or seconds, a calendar date, a wall time. */ export type BoundAs = 'iso' | 'epoch-ms' | 'epoch-s' | 'date' | 'wall'; export declare const BOUND_AS: readonly BoundAs[]; /** * One bound of a two-argument period. A `from` bound is inclusive (its `edge`, * when written, can only say so); a `to` bound MUST say its edge * ({@link ToBound}) — TQ18: the library never guesses a tool's edge, only the * sugar defaults (`inclusive`). */ export interface Bound { readonly argument: string; readonly as: BoundAs; readonly edge?: Edge; } /** The end bound of a `bounds` form — its edge is declared, never defaulted (TQ18). */ export interface ToBound extends Bound { readonly edge: Edge; } /** The argument a wall or date form reads its zone from. */ export interface ZoneArgument { readonly argument: string; } /** * Every shape a tool's period can take — one `TimeRange` onto one or more * arguments. Any form may carry its own `maxRange` — the widest window THAT * form reads at once — when the tool's forms differ (bounds capped at a day, * a look-back with no cap): it overrides the period's `maxRange` for that * form only ({@link formMaxRange}, the one owner). */ export type PeriodForm = { readonly kind: 'bounds'; readonly from: Bound; readonly to: ToBound; readonly zone?: ZoneArgument; readonly maxRange?: DurationText; } | { readonly kind: 'joined'; readonly argument: string; readonly as: BoundAs; readonly joiner: '..' | '/'; readonly edge?: Edge; readonly zone?: ZoneArgument; readonly maxRange?: DurationText; } | { readonly kind: 'object'; readonly argument: string; readonly keys: { readonly from: string; readonly to: string; }; readonly as: BoundAs; /** Declared, never defaulted (TQ18). */ readonly edge: Edge; readonly zone?: ZoneArgument; readonly maxRange?: DurationText; } | { readonly kind: 'day'; readonly argument: string; readonly zone?: ZoneArgument; readonly maxRange?: DurationText; } | { readonly kind: 'lookback'; readonly argument: string; readonly signed: boolean; /** A unit set ⊆ `smhdw`; absent → today's `mhdw`. */ readonly units?: string; readonly maxRange?: DurationText; }; export declare const FORM_KINDS: readonly PeriodForm['kind'][]; /** Which side of now a source can hold. */ export type PeriodDirection = 'past' | 'future' | 'any'; /** Facts about the source — never policy (§ 7.1). Durations are in `smhdw`. */ export interface PeriodFacts { readonly direction?: PeriodDirection; readonly retention?: DurationText; readonly maxRange?: DurationText; readonly granularity?: DurationText; readonly filtersToAsked?: boolean; } /** The unit set of a fact's duration (`retention`, `maxRange`, `granularity`). */ export declare const FACT_UNITS = "smhdw"; /** The step a look-back ending "at now" may miss by when no `granularity` is declared (§ 7.4). */ export declare const DEFAULT_GRANULARITY_MS = 60000; /** The form one single-argument spelling means (the module table). */ export declare function sugarForm(argument: string, spelling: PeriodSpelling, zoneArgument?: string): PeriodForm; /** The sugar and general halves of a period declaration, as `sugarForms` reads them. */ export interface PeriodShapes { readonly argument?: string; readonly spelling?: PeriodSpelling; readonly accepts?: readonly PeriodSpelling[]; readonly zoneArgument?: string; readonly forms?: readonly PeriodForm[]; } /** * Every form a declaration names, in preference order: `forms` as written, * else the sugar (`accepts`, else `spelling`). A declaration that names an * argument and no spelling has no form — today's "which argument", nothing * the library can convert into. */ export declare function sugarForms(period: PeriodShapes): readonly PeriodForm[]; type Plain = Record<string, unknown>; export declare const isPlain: (value: unknown) => value is Plain; /** * Why one form's own shape is not a form, or `undefined` when it is one. The * schema half (does the argument exist, is it the right type, does it carry a * rule) is `tools/declare.ts`'s — this is the shape alone. */ export declare function formIssue(form: unknown): string | undefined; /** Whether a form reads wall-clock values and so needs a zone (`wall`, `date`, a `day`). */ export declare function needsZone(form: PeriodForm): boolean; /** One argument a form names, and what the schema must say of it. */ export interface FormArgument { readonly argument: string; /** `bound`: carries a value of the window; `zone`: carries the zone; `object`: an object of both bounds. */ readonly role: 'bound' | 'zone' | 'object'; /** The JSON Schema type the property must have: a number for an epoch, else a string. */ readonly type: 'number' | 'string' | 'object'; /** For a `bound` of a `bounds` form — the bound it carries. */ readonly bound?: Bound; } /** Every argument a form names, the zone argument last. */ export declare function formArguments(form: PeriodForm): readonly FormArgument[]; /** The argument a form is known by — the results layer's join key (its first bound). */ export declare function primaryArgument(form: PeriodForm): string; /** A wall time written with no offset, and the step its spelling is precise to. */ export declare function wallOf(text: unknown): { readonly wall: WallTime; readonly stepMs: number; } | undefined; /** A calendar date `YYYY-MM-DD`, day-checked. */ export declare function dateOf(text: unknown): { readonly year: number; readonly month: number; readonly day: number; } | undefined; /** Whether a single bound value is written the way `as` declares. */ export declare function isBoundValue(value: unknown, as: BoundAs): boolean; export declare const epochFromText: (text: string) => number | undefined; /** * Whether a declared value (an `assume` default, an `ask` choice) of * `argument` is written the way `form` spells that argument. A format check: * no clock, no conversion. `true` for an argument the form does not name. */ export declare function parsesUnderForm(value: unknown, form: PeriodForm, argument: string): boolean; /** Why a range breaks one of the tool's facts — a code; the sentence is the catalog's. */ export type PeriodFactProblem = 'time-future' | 'time-past' | 'beyond-retention' | 'over-max-range'; /** * Which of the tool's declared facts a half-open range breaks, against the * turn's clock — or `undefined`. `past`: a range that starts after now; * `future`: one that ends before now; `retention`: only a range WHOLLY older * than `now − retention` (a partial overlap is the result's to judge); * `maxRange`: a range that REACHES further than it (`range.ts` · `reachMs`: * first instant to last, so a look-back exactly `maxRange` long fits — an * inclusive ceiling). A fact the tool does not declare is not checked. */ export declare function periodFactProblem(range: TimeRange, facts: PeriodFacts, now: InstantText): PeriodFactProblem | undefined; /** * The widest window ONE form reads at once: its own `maxRange`, else the * period's — the one owner every door asks (the conversion, a sent window's * check, the answer to a period argument). `undefined`: no cap for that form. * * @example * ```ts * formMaxRange({ kind: 'bounds', from, to, maxRange: '24h' }, { maxRange: '7d' }); // '24h' * formMaxRange({ kind: 'lookback', argument: 'w', signed: false }, { maxRange: '7d' }); // '7d' * ``` */ export declare function formMaxRange(form: PeriodForm, facts: PeriodFacts | undefined): DurationText | undefined; /** The facts ONE form is judged against: the period's, with the form's own `maxRange` in place. */ export declare function formFacts(form: PeriodForm, facts: PeriodFacts): PeriodFacts; /** * The facts the TOOL is judged against before any form is chosen (a window * of the person's to fill, a time ask's choices): `maxRange` is the widest * any form reads — none when one form reads with no cap — so a window is * refused `over-max-range` only when NO form can read it. The period's facts * as declared when no form declares its own `maxRange`. */ export declare function toolFacts(forms: readonly PeriodForm[], facts: PeriodFacts): PeriodFacts; /** * Why a call is refused before dispatch (§ 7.2, step T5b): one of the tool's * facts ({@link PeriodFactProblem}), a range across days to a tool that reads * one day (`multi-day`), a wall time the zone skips (`dst-gap`), or a window * of the person's that no form the tool declares can read, exactly or by * reading a wider one (`no-form-holds` — a look-back ends at now, so a window * still running is out of its reach, and a covering look-back wider than * `maxRange` is one the tool will not read). The tool's own rule never stands * in for the person's window: its default would read a time nobody asked about. */ export type TimeRefusal = PeriodFactProblem | 'multi-day' | 'dst-gap' | 'no-form-holds'; export declare const TIME_REFUSALS: readonly TimeRefusal[]; export {}; //# sourceMappingURL=periodForm.d.ts.map