import * as React from 'react'; /** Which layer decided a field — lowest to highest. */ type ContextLayer = "default" | "page" | "agent" | "you"; type ContextDelivery = "inline" | "on_request" | "off"; /** * A client row's delivery: the server's three, plus `"server"` — an included * value the server resolves itself (`isServerResolved`), whose delivery the * client does not claim. Never on the wire or in a receipt. */ type ContextRowDelivery = ContextDelivery | "server"; /** One saved per-person rule (one key on one surface). Both fields optional. */ interface SavedContextRule { include?: boolean; max_inline_chars?: number; } /** The agent layer for one key (RULES.md §2). */ interface ContextAgentLayer { /** The agent's Context Policy declares this key (or the value is the agent's own seed). */ declared?: boolean; /** The policy's ceiling; only read when `declared`. */ max_inline_chars?: number | null; /** `auto_context_disabled` — closes every undeclared key. */ kill_switch?: boolean; } /** The page layer for one key: the surface that emitted the value. */ interface ContextSurfaceLayer { /** The surface declares this value (a `ui_surface_value` row / manifest entry). */ declared?: boolean; /** `false` drops the value unless the agent declares it. */ auto_context?: boolean | null; /** `inlineUpTo` / envelope `max_inline_chars` / DB column. */ max_inline_chars?: number | null; /** * The value is withheld because this conversation IS the page (`page_context` mode `own`): * nothing re-opens it — not the agent's Context Policy, not the person's rule. A page's own * chat never receives itself (Arman, 2026-10-01 / 2026-10-21). */ own?: boolean; } /** The non-person layers for one value — what the table's layer breakdown shows. */ interface ContextRuleLayers { /** The server's per-key default limit; `null`/absent = 200. */ default_max?: number | null; agent?: ContextAgentLayer | null; surface?: ContextSurfaceLayer | null; } interface ContextRuleResult { include: boolean; /** Effective limit, after the clamp. */ max_inline_chars: number; delivery: ContextDelivery; decided_by: { include: ContextLayer; max_inline_chars: ContextLayer; }; clamped: boolean; } /** * What the model read for one value or block, by SIZE and HASH only — never * the text (RULES.md §5b: a server-shaped value is fetched on demand, never * pushed). The text comes from the viewer (`ContextViewLoader`). */ interface ContextDeliveredRef { /** Code-point length of the whole text the model read. */ chars: number; /** SHA-256 hex of that text (UTF-8). */ sha256: string; } /** * What to view: a value's `delivered` element, its `on_request` text, a * `block`, or what the agent can `fetchable` for a value through a tool (the * Organization: its selected scopes' values via `scope_system` — rendered when * opened, never on the receipt; `source: "fetched_now"`). */ type ContextViewKind = "delivered" | "on_request" | "block" | "fetchable"; interface ContextViewTarget { kind: ContextViewKind; /** The value's key, or the block's id. */ key: string; } /** * The exact text the model received (a sent turn: `GET /ai/context/delivered`) * or will receive (the next turn: `POST /ai/context/preview` with `view`). */ interface ContextViewedText { kind: ContextViewKind; key: string; text: string; chars: number; sha256: string; /** * `fetched_now`: read at request time — a `fetchable` text (what the agent * gets if it asks now) or a lazy `on_request` value the agent never read. * `tool_result`: exactly what the `context` tool returned to the agent. */ source: "preview" | "wire" | "conversation_prompt" | "turn_record" | "fetched_now" | "tool_result"; /** * `fetchable` only: `false` when the turn's agent cannot call the tool that * returns it (tools off, excluded, a structured-output turn). `text` is then * `""`; the screen says so with state, never shows content as fetchable. */ available?: boolean; /** * A lazy `on_request` value of a SENT turn only (a document, a file family, * a scope — the turn never reads one): `true` — the agent called `context` * for it and `text` is what the tool returned; `false` — the agent never * read it and `text` is what it returns now (the screen says so). */ fetched?: boolean | null; } /** The host's door to the viewer API — called only when a person opens a value. */ type ContextViewLoader = (target: ContextViewTarget) => Promise; /** * One block of server text the model received this turn that is not a single * value — the turn's ``, earlier-turn context, the sandbox * briefing, skills, memory, the organization catalog… (receipt `blocks`, * RULES.md §5). `delivered` is its exact text, cut at the receipt's cap. */ interface ContextReceiptBlock { /** Stable id: the per-turn slot it rode in, or the system-prompt addition's name. */ id: string; /** The id in words (`humanizeIdentifier`, `@ai-matrx/kit/text-case`). */ label: string; /** Size and hash; the text comes from the viewer (`kind: "block"`). */ delivered: ContextDeliveredRef; } type ContextRowOrigin = "page" | "attached" | "system"; /** Why the server kept a value from the model on this turn (receipt `blocked_by`). */ type ContextBlockedBy = "model" | "self_check"; /** A client's resolved row: what its table renders and what `buildContextWire` sends. */ interface ResolvedContextRow extends Omit { delivery: ContextRowDelivery; /** * The server resolves this value (a resource reference, a `*_id` UUID): size * and delivery are unknown (`chars: null`, `delivery: "server"` when * included), and its default limit is not predicted. Include and the * person's own rule still resolve normally. */ serverResolved?: boolean; /** Display-only: chars / limit / delivery were filled from a receipt (`applyReceiptToRows`). */ fromReceipt?: boolean; /** From a receipt: why the server kept this value from the model this turn. */ blockedBy?: ContextBlockedBy; /** * Display-only, from a receipt: what the model read for this value. When set, * a detail view shows THIS — never `value`, the client's pre-send copy. */ delivered?: ContextDeliveredRef; /** Display-only, from a receipt: what the `context` tool returns for it (size + hash). */ onRequest?: ContextDeliveredRef; /** Display-only, from a receipt: blocks the model received as part of this value. */ deliveredBlocks?: ContextReceiptBlock[]; key: string; label: string; surfaceKey: string; origin: ContextRowOrigin; /** The raw value, or an already-rich envelope (`{ content, type, … }`). */ value: unknown; chars: number | null; /** The saved rule that was applied (merged `_default` + surface row), or null. */ userRule: SavedContextRule | null; description?: string; /** Context object type for the wire envelope (`text`, `json`, …). */ type?: string; /** The non-person layers the rule was resolved from. Absent = default only. */ layers?: ContextRuleLayers; } /** * THE HIERARCHY of the context rules table — where each value sits, and the * switch at every level (Arman, 2026-10-02: "AI Matrx" for the platform's own * values; the page by its section and real name; under it the page's own * declared groups; a switch per level). * * The package never knows a page's groups: the host PLACES each row (level + * group, both already-human labels) and may give a level a host switch (the * page's own on/off). Without a host placement every row is placed by its * origin. A level or group switch is NOT a new kind of rule: it is the * person's per-value include rules for every value in it, written at once * (`includeChanges`), so the server's gate and receipt see exactly the rules * they already honor. */ /** A level of the table: the platform, a page, the chat's attachments. */ interface ContextLevelRef { /** Stable id (a surface key, `ai_matrx`, `attached`). */ id: string; /** Heading, root first: `["Marketing", "Marketing Brand Cockpit"]`, `["AI Matrx"]`. */ path: readonly string[]; /** Sort order between levels (lower first). */ order?: number; } /** A group inside a level — the page's own declared group, label as declared. */ interface ContextGroupRef { id: string; label: string; order?: number; } /** Where one row sits. */ interface ContextRowPlace { level: ContextLevelRef; /** Null: directly under the level. */ group?: ContextGroupRef | null; } /** * A level whose switch is the host's own (the page on/off for this * conversation) rather than the person's per-value rules. Shown even when the * level has no rows, so the switch never disappears with its values. */ interface ContextLevelMaster { level: ContextLevelRef; on: boolean; onToggle?: ((next: boolean) => void) | undefined; } interface ContextHierarchy { place: (row: ResolvedContextRow) => ContextRowPlace; masters?: readonly ContextLevelMaster[]; } interface ContextGroupNode { ref: ContextGroupRef; rows: ResolvedContextRow[]; } interface ContextLevelNode { ref: ContextLevelRef; /** Rows directly under the level (no group). */ rows: ResolvedContextRow[]; groups: ContextGroupNode[]; master: ContextLevelMaster | null; } /** The platform's own values: the person, their organization, the client. */ declare const AI_MATRX_LEVEL: ContextLevelRef; /** Files and documents attached to the conversation. */ declare const ATTACHED_LEVEL: ContextLevelRef; /** A page the host has not named. */ declare const PAGE_LEVEL: ContextLevelRef; /** The placement a host without one gets: by origin. */ declare function placeByOrigin(row: ResolvedContextRow): ContextRowPlace; /** Rows → levels → groups, in the host's order (stable within equal orders). */ declare function buildContextLevels(rows: readonly ResolvedContextRow[], hierarchy?: ContextHierarchy | null): ContextLevelNode[]; /** * A heading of the table: one label of a level's path. A node with a `level` * IS that level (its rows, groups, switch); a node without one is a section * that only names the labels above deeper levels. */ interface ContextTreeNode { /** The path up to and including this label, lower-cased: one node per distinct path. */ id: string; /** This node's own label (the last one of its path). */ label: string; /** The full heading path to this node, root first. */ path: readonly string[]; level: ContextLevelNode | null; children: ContextTreeNode[]; } /** * Levels → ONE tree by path (Arman, 2026-10-21: "UNIFY and eliminate" — one * AI Matrx root, whatever the levels' paths): `["AI Matrx"]`, * `["AI Matrx", "Marketing"]` and `["AI Matrx", "Marketing", "Brands"]` nest as * AI Matrx → Marketing → Brands; a root named by two levels is still one root. * Order: a node sorts by the lowest `order` found in it or below it. */ declare function buildContextTree(levels: readonly ContextLevelNode[]): ContextTreeNode[]; /** Every level at or below a node. */ declare function treeLevels(node: ContextTreeNode): ContextLevelNode[]; /** Every row of a level, groups included. */ declare function levelRows(level: ContextLevelNode): ResolvedContextRow[]; /** What the row's include would be with no rule of the person's. */ declare function inheritedInclude(row: ResolvedContextRow, cap: number): boolean; /** One person-rule write: `rule: null` removes the person's rule for that value. */ interface ContextRuleChange { key: string; surfaceKey: string; rule: SavedContextRule | null; } /** * A level or group switch: the person's include rule for every value in it * that is not already `include`. A value whose default already gives * `include` loses its own include rule instead (back to the default) — the * saved rules stay minimal and "Reset all" means what it says. */ declare function includeChanges(rows: readonly ResolvedContextRow[], include: boolean, cap: number): ContextRuleChange[]; type ContextRulesDensity = "compact" | "comfortable"; interface ContextRulesTableProps { rows: readonly ResolvedContextRow[]; cap: number; readOnly?: boolean | undefined; /** `next === null` resets the person's rule for that key. */ onChange: (key: string, surfaceKey: string, next: SavedContextRule | null) => void; onOpenRow?: (key: string) => void; /** `comfortable` = 44px touch rows (the deciding layer stays in the row tooltip). Default `compact`. */ density?: ContextRulesDensity; /** Highlights the open row (master/detail). */ selectedKey?: string | null; /** * Where each row sits (level → group) and the host's level switches. Omit: * rows sit under their origin ("Page", "Attached", "AI Matrx"). */ hierarchy?: ContextHierarchy | null | undefined; /** * A level or group switch: the person's per-value rules for every value in * it, at once. Omit: level and group switches are hidden (a host master * switch still shows). */ onSetInclude?: ((changes: ContextRuleChange[]) => void) | undefined; /** * Host slots inside a row's Item cell, never a second renderer: `renderRowLead` * before the label (a status mark), `renderRowTrail` after it (an admin's * machine name). Each renders inline and truncates with the label. */ renderRowLead?: ((row: ResolvedContextRow) => React.ReactNode) | undefined; renderRowTrail?: ((row: ResolvedContextRow) => React.ReactNode) | undefined; className?: string; } declare function ContextRulesTable({ rows, cap, readOnly, onChange, onOpenRow, density, selectedKey, hierarchy, onSetInclude, renderRowLead, renderRowTrail, className, }: ContextRulesTableProps): React.JSX.Element; /** * The header's "N · chars" total. A row whose size is not known yet (an * attachment the server has not measured) never counts as 0: with some sizes * unknown the total is a floor ("1.2k+"), with none known it is "—". */ declare function summarizeContextRows(rows: readonly ResolvedContextRow[]): { count: number; chars: number; charsLabel: string; }; interface ContextRulesChipProps { /** * The group's own name — "Notes", "Invoice 1042". Empty or omitted: the chip * shows NO text (icon + count only). Never pass a generic word such as * "Context" here — when there is no real name, there is no label (Arman, * 2026-10-01). */ label?: string | null | undefined; rows: readonly ResolvedContextRow[]; cap: number; /** * Page context on/off (the face's eye). The header's master switch IS this * page switch — it never writes per-value rules, so on restores exactly the * previous per-value state; with a `hierarchy` the page's own switch also * sits on its level row (`hierarchy.masters`). Omitted: no page, no switch. */ on?: boolean | undefined; onToggleAll?: ((next: boolean) => void) | undefined; /** Levels and groups with a switch each (see `ContextRulesTable`). */ hierarchy?: ContextHierarchy | null | undefined; onSetInclude?: ((changes: ContextRuleChange[]) => void) | undefined; /** False: this turn's model cannot read context — muted face. */ modelReadsContext?: boolean | undefined; onChange: (key: string, surfaceKey: string, next: SavedContextRule | null) => void; onResetAll: () => void; onOpenFullView: () => void; onOpenRow?: (key: string) => void; /** Bottom sheet instead of a popover. */ isMobile?: boolean; readOnly?: boolean | undefined; open?: boolean; onOpenChange?: (open: boolean) => void; /** * The chip toggles a view the host shows elsewhere (a canvas tab): `true` * while that view is in front. Sets `aria-pressed` and the pressed face. * Omitted: the chip is a plain popover trigger, no pressed state. */ pressed?: boolean | undefined; /** * True while what decides INCLUSION (the person's saved rules, a kill switch) has not answered: * the face shows its eye and no number, and the opened surface shows no count and no switches * yet — never a number that changes when it is opened (live walk 2026-10-23: 5 on the face, 3 * in the popover). Omitted: the rows are final. */ countPending?: boolean | undefined; /** The face's skin: `outline` (default) or `quiet` (a composer row). */ variant?: "outline" | "quiet"; /** Placement only. */ className?: string; /** The face's glyph while context reaches the model (default: the open eye). The blind face * keeps the crossed-out eye so "nothing reaches it" still reads at a glance. */ faceIcon?: React.ReactNode; /** * A visible word on the FACE only, beside the eye, when the group has no name of its own — for a * host that asks for spelled-out controls (the beginner's first chat page). It never becomes the * group's name: the header, the accessible name and the tooltip still follow `label`. */ faceText?: string; } /** * The popover's width: 30rem, never under 340px (a narrow host column — a workflow * chat panel — must not squeeze the rows into each other), always inside the * viewport; Radix collision handling places it. */ declare const CONTEXT_POPOVER_CLASS = "w-[30rem] min-w-[min(21.25rem,calc(100vw-1rem))] max-w-[calc(100vw-1rem)] overflow-hidden p-0"; /** * The composer's value-group chip — far right of the composer's one row — and the surface it opens: a header (label, * "N · chars" summary, page master switch, reset-all, full view) over the * compact rules table. Popover on desktop, bottom sheet on mobile. */ declare function ContextRulesChip({ label, rows, cap, on, onToggleAll, hierarchy, onSetInclude, onChange, onResetAll, onOpenFullView, modelReadsContext, onOpenRow, isMobile, readOnly, open: openProp, onOpenChange, pressed, countPending, faceIcon, faceText, className, variant, }: ContextRulesChipProps): React.JSX.Element; interface ContextRulesPanelBodyProps { rows: readonly ResolvedContextRow[]; cap: number; /** The latest receipt's `blocks`: listed read-only under "Also sent". */ blocks?: readonly ContextReceiptBlock[]; /** The viewer door (RULES.md §5b): fetches a value's or block's exact text when it opens. */ loadView?: ContextViewLoader; readOnly?: boolean | undefined; onChange: (key: string, surfaceKey: string, next: SavedContextRule | null) => void; /** Levels and groups with a switch each (see `ContextRulesTable`). */ hierarchy?: ContextHierarchy | null | undefined; onSetInclude?: ((changes: ContextRuleChange[]) => void) | undefined; /** Host content under the built-in controls (a value preview, source link…). */ renderDetail?: (row: ResolvedContextRow) => React.ReactNode; isMobile?: boolean; /** Controlled selection; omit for internal state. */ selectedKey?: string | null; onSelectedKeyChange?: (key: string | null) => void; className?: string; } /** * Master/detail body for a docked context panel: search + compact table, and * the open row's controls, layer breakdown and host detail. Nothing open: the * list is the whole panel. Open and wide (≥ 40rem): list beside detail. Open * and narrow (or `isMobile`): the detail alone, with Back to the list. */ declare function ContextRulesPanelBody({ rows, cap, blocks, loadView, readOnly, onChange, hierarchy, onSetInclude, renderDetail, isMobile, selectedKey: selectedProp, onSelectedKeyChange, className, }: ContextRulesPanelBodyProps): React.JSX.Element; interface InlineMaxInputProps { /** The person's own limit, or null when inherited. */ value: number | null; /** What applies without the person's number (shown muted). */ inherited: number; /** Override the muted text shown when the person set no number (e.g. "auto"). */ placeholder?: string | undefined; cap: number; /** Next limit, or null to drop the person's number. */ onCommit: (next: number | null) => void; disabled?: boolean | undefined; /** Accessible name — the row's label. */ label: string; comfortable?: boolean; } /** * The Inline max cell: a 6ch numeric field. Inherited value shows as muted * placeholder text; an override shows a dot and a reset button. `0` reads * "Never". Commits on blur/Enter, Escape reverts, above-cap is clamped on * commit with a brief "Limit is {cap}" tooltip. */ declare function InlineMaxInput({ value, inherited, cap, onCommit, disabled, label, comfortable, placeholder, }: InlineMaxInputProps): React.JSX.Element; /** * What the model READ for one value — fetched from the viewer when the detail * opens, never pushed (RULES.md §5b): its own element (`delivered`), the blocks * it rode with (`deliveredBlocks` — the Organization's catalog), and for an * on-request value what the `context` tool returns (`onRequest`), and for a * value the agent reads through a tool (`CONTEXT_FETCHABLE_ROWS`) what that tool * returns now (`fetchable`, sized once loaded). Verbatim; * never the client's copy. With no receipt yet: a server-authoritative value * says the server fills it; anything else renders nothing (the host may show * the value the page will send, labeled so). */ declare function ContextDeliveredValue({ row, load, className, }: { row: Pick & Partial>; /** The host's viewer door; without one, sizes show and the text reads "—". */ load?: ContextViewLoader | undefined; className?: string; }): React.JSX.Element | null; /** One viewed text: its title and size, then the exact text, fetched on mount. */ declare function DeliveredSection({ title, target, ref_, load, }: { title: string; target: ContextViewTarget; /** The receipt's size; absent for a `fetchable` text, sized once it loads. */ ref_?: ContextDeliveredRef | undefined; load?: ContextViewLoader | undefined; }): React.JSX.Element; interface ContextReceiptBlocksProps { blocks: readonly ContextReceiptBlock[]; /** The open block (master/detail). */ selectedId?: string | null; onOpenBlock?: (id: string) => void; density?: ContextRulesDensity; className?: string; } /** * "Also sent" — every block of server text the model received that is not a * single value (receipt `blocks`, RULES.md §5): read-only rows, label + chars, * aligned to the context table's Chars column. Renders nothing when empty. */ declare function ContextReceiptBlocks({ blocks, selectedId, onOpenBlock, density, className, }: ContextReceiptBlocksProps): React.JSX.Element | null; /** One block's detail: its name, its size, and exactly what the agent received (on demand). */ declare function ContextReceiptBlockDetail({ block, load, className, }: { block: ContextReceiptBlock; load?: ContextViewLoader | undefined; className?: string; }): React.JSX.Element; export { AI_MATRX_LEVEL, ATTACHED_LEVEL, CONTEXT_POPOVER_CLASS, ContextDeliveredValue, ContextReceiptBlockDetail, ContextReceiptBlocks, ContextRulesChip, ContextRulesPanelBody, ContextRulesTable, DeliveredSection, InlineMaxInput, PAGE_LEVEL, buildContextLevels, buildContextTree, includeChanges, inheritedInclude, levelRows, placeByOrigin, summarizeContextRows, treeLevels }; export type { ContextGroupNode, ContextGroupRef, ContextHierarchy, ContextLevelMaster, ContextLevelNode, ContextLevelRef, ContextReceiptBlocksProps, ContextRowPlace, ContextRuleChange, ContextRulesChipProps, ContextRulesDensity, ContextRulesPanelBodyProps, ContextRulesTableProps, ContextTreeNode, InlineMaxInputProps };