agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
108 lines • 5.32 kB
TypeScript
/**
* time/present — time rendered for a PERSON, in a named zone.
*
* Pattern: one renderer, every person-facing line (time design § 3.1, § 10.2):
* the limits block's `Period:` line (`coverage/period.ts` ·
* `periodLine`) and, later, every time label the layer shows. A
* label is never parsed back; the typed record keeps the instants.
* Role: L0 leaf (the time layer). Imports `instant.ts`, `zone.ts` and
* `range.ts` only.
* Emits: N/A.
*
* ## The form — locale-neutral, the zone always named
*
* With no locale (no reader armed) there is no language to speak: the
* form is ISO-like and the same in every language — a date, a 24-hour wall
* time in the presentation zone, then the zone's name and its offset at that
* moment:
*
* ```
* 2026-10-09 08:00–08:40 America/Los_Angeles (UTC-07:00)
* 2026-10-09 23:00 – 2026-10-10 01:00 Asia/Kolkata (UTC+05:30)
* 2026-11-01 01:00 (UTC-07:00) – 2026-11-01 01:30 (UTC-08:00) America/Los_Angeles
* 2026-10-09 15:00–15:40 UTC
* ```
*
* The time is written as finely as either end needs it (minutes, seconds, or
* milliseconds), never finer. When the two ends sit on different offsets (the
* span crosses a DST change) each end names its own; otherwise the offset is
* named once.
*
* ## With a locale (the reader's, § 11)
*
* A {@link Presentation} with a `locale` — the armed reader's, the language
* the person wrote in — is rendered through `Intl.DateTimeFormat` in that
* locale, at the same precision, the zone named by its short name
* (`Fri, Oct 9, 2026, 8:00 – 8:40 AM PDT` in `en-US`). The words are the
* runtime's ICU data; the instants behind the label are the record.
*
* ## The said end (§ 3.3)
*
* Inside the library a person's range is half-open: "to 8:40" read to the end
* of its grain is `[08:00, 08:41)`. {@link presentRange} with that grain shows
* the end AS SAID — the last instant inside the range at the grain,
* `08:40` — never `08:41`. A declared period's `queried` / `held` is
* inclusive already, so {@link presentSpan} shows its ends as declared.
*
* @example
* ```ts
* const la = { zone: 'America/Los_Angeles' };
* presentRange({ from: '2026-10-09T08:00:00-07:00', to: '2026-10-09T08:41:00-07:00' }, la, 'minute');
* // '2026-10-09 08:00–08:40 America/Los_Angeles (UTC-07:00)'
* presentSpan('2026-10-09T15:00:00Z', '2026-10-09T15:40:00Z', la);
* // '2026-10-09 08:00–08:40 America/Los_Angeles (UTC-07:00)'
* presentInstant('2026-10-09T15:40:03Z', la);
* // '2026-10-09 08:40:03 America/Los_Angeles (UTC-07:00)'
* ```
*/
import { type InstantText } from './instant.js';
import type { TimeRange } from './range.js';
import { type ZoneName } from './zone.js';
/**
* Where a label is rendered — the presentation zone, and the locale when a
* reader is armed (its `locale`: the language the person wrote in). Without a
* locale the form is the locale-neutral one above.
*/
export interface Presentation {
readonly zone: ZoneName;
/** A BCP 47 language tag (`'en-US'`). Rendered through `Intl`; the zone is always named. */
readonly locale?: string;
}
/** How finely a person said a time (time design § 3.2). */
export type Grain = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
/**
* One instant for a person: its wall time in the presentation zone, written
* as finely as it needs (never coarser than minutes), and the zone named.
*/
export declare function presentInstant(value: InstantText, presentation: Presentation): string;
/**
* Two INCLUSIVE ends — a declared period's `queried` or `held` — for a
* person, each shown as declared (no end moved), in the presentation zone.
* Accepts the lenient profile: a period a result declares.
*/
export declare function presentSpan(from: InstantText, to: InstantText, presentation: Presentation): string;
/**
* A presentation bound into the three renderers the coverage limits lines use
* (`semantics/coverage/period.ts` · `periodLine` for a `Period:` line, and
* `periodCheckLine` for a result check's ranges). The coverage module is on every
* agent's graph and this one loads only under `.time()`, so it is HANDED the
* renderers (`agent/stages/prepareFinal.ts` loads this module through
* `import()`) and never imports them — the optional-family law of docs-next's
* site budget.
*/
export interface BoundPresentation {
readonly span: (from: InstantText, to: InstantText) => string;
readonly instant: (value: InstantText) => string;
readonly range: (range: TimeRange, grain?: Grain) => string;
}
/** {@link presentSpan}, {@link presentInstant} and {@link presentRange}, bound to one presentation. */
export declare function bindPresentation(presentation: Presentation): BoundPresentation;
/**
* A half-open range for a person. With the `grain` the person said, the end
* is the end AS SAID (§ 3.3): the last instant inside the range, written at
* that grain — `[08:00, 08:41)` at `'minute'` shows `08:00–08:40`, and a
* `'day'` range `[9 Oct, 10 Oct)` shows `2026-10-09`. Without a grain (an
* exact range) both ends are shown as they are.
*/
export declare function presentRange(range: TimeRange, presentation: Presentation, grain?: Grain): string;
//# sourceMappingURL=present.d.ts.map