api reference
The AI narrative and insights layer
The narrative module: summaries, insights and risk text over what the grid already holds. The grid.ai intent layer is documented on the platform API page.
API reference › The AI narrative and insights layer
All 13 pages Everything on one page → Developer guide →
The AI narrative / insights layer
modules/ai is an opt-in layer that produces a short, plain-language narrative of the grid's computed figures - a per-KPI / per-chart / per-column “Explain”, or an insights panel over the current (filtered) view. It is a separate bundle that adds no weight to a page that does not load it, changes nothing in grid core, and pulls in no dependency. The grid makes no AI call of its own: createAI never imports a provider SDK, never reads a key, and never makes a network request. It calls one async callback you supply, ask() - your model, your key, your privacy decision - exactly the philosophy of the data adapters, where auth and transport are always the caller's.
import { createAI } from '@toclocoinc/lattice-grid/modules/ai';
const ai = createAI(grid, {
ask: async ({ system, messages, tools, schema, signal }) => {
const r = await myProvider.chat({ system, messages, tools, signal });
return { text: r.text, toolCalls: r.toolCalls }; // or a bare string
},
maxRows: 50, // cap what any tool result carries to ask()
redact: ['ssn', 'salary'], // columns whose values never leave the browser
});
ai.insights(document.querySelector('#insights')); // the panel
const { text, flagged } = await ai.explain({ kind: 'column', colId: 'amount' });
Grounded, and reconciled. Where your provider offers tool-use, the model is given a curated read-only tool set (getSchema, getProfile, getStatistics, getForecast, runQuery) and our engine computes what it asks for; where it does not, the module builds a facts packet from the grid's computed results (grid.statistics, the profile, forecasts, view counts) and passes it in the prompt. Either way, every figure in the narrative is reconciled against the values the engine produced this render - an ungrounded number is stripped before the user sees it. The prompt is constrained to narrate-only; the layer is read-only and never mutates data. redact and maxRows bound what the module hands ask(), and the module sends nothing itself. An ask() error surfaces a friendly message and the grid stays fully usable - AI is additive, never load-bearing.
createAI is complementary to grid.ai: grid.ai is the intent/plan skill layer (a question becomes a validated filter/sort plan you preview and apply); createAI is the narrative/insights consumer that explains figures. They can share one host ask() - pass none to createAI and it adopts the grid's configured ai.ask, running the facts-packet path over it.
enable gates only the three DOM-mounting convenience methods: 'narrative'/'insights' is what lets insights() mount, 'query'/'ask' is what lets askBar() mount (see §Ask-your-data), and 'actor' is what lets actorBar() mount (see §AI as a governed actor). All three are allowed when enable is omitted. The programmatic API - explain(), query(), propose(), facts(), riskSummary() and the rest of the controller - is never gated by enable and runs regardless of the allowlist: a host that wants no AI surface at all simply never calls these methods.
| Member | Description |
|---|---|
| createAI(grid, config) | Create an AI narrative / insights controller over a live grid (headless or rendered). Config: ask (the host callback; falls back to the grid's ai.ask), enable (gates only insights()/askBar()/actorBar() - see above), maxRows, redact, tools, locale, reconcile ('strip'/'flag'), element, onNarrative, onError. |
| explain(target?, opts?) / narrate(...) | Produce a grounded, reconciled narrative. Always callable - not gated by enable. target is { kind: 'view' }, { kind: 'column', colId }, { kind: 'forecast', colId, options }, { kind: 'kpi'|'chart', facts }, or { kind: 'risk', gantt, board } for a board / Gantt risk summary. Resolves to { text, facts, grounded, flagged, rounds, mode }. |
| riskSummary(sources?, opts?) | A board / Gantt RISK SUMMARY - “3 tasks at risk on the critical path, SPI 0.67, 2 SLA breaches” - grounded on the separate Gantt / Kanban modules' outputs (gantt, board/sla, or their precomputed earnedValue/schedule/breaches). A convenience over explain({ kind: 'risk' }), through the same reconciliation guard. Always callable - not gated by enable. |
| insights(el?, opts?) | Mount (or re-target) the insights panel into an element, its generate control wired to a view narrative. Keeps the grid usable on an ask() error. Mounts only when enable allows 'narrative'/'insights'. |
| attachExplain(target, opts?) | Build an “Explain” button bound to a target (a KPI tile, a chart datum, a column). Clicking it narrates the target. |
| facts(target?, opts?) | Build the facts packet for a target without calling ask() - the exact grounded set a narrative would use, and what would leave the browser. |
| on(name, fn) / off(name, fn) / destroy() | Events: narrative and error. destroy() tears the controller down and leaves the grid untouched. |
Grounded, with the reconciliation guard, executed
A mock ask() returns one grounded figure (the row count) and one invented one.
The number-reconciliation guard strips the ungrounded figure and keeps the grounded one. Run headless on every build.
const { createHeadlessGrid } = await import('../packages/core/src/index.js');
const { createAI } = await import('../packages/modules/ai/index.js');
const grid = createHeadlessGrid({
rowKey: 'id',
columns: [{ field: 'id' }, { field: 'region' }, { field: 'amount', type: 'number' }],
rows: [
{ id: 1, region: 'EMEA', amount: 100 },
{ id: 2, region: 'AMER', amount: 300 },
{ id: 3, region: 'APAC', amount: 200 },
],
});
// Your model, your key. The grid makes no network call - it awaits this.
// This mock returns one grounded figure (3 rows) and one invented one (900%).
const ask = async () => ({ text: 'There are 3 rows in view. Confidence 900%.' });
const ai = createAI(grid, { ask, tools: false });
const result = await ai.explain({ kind: 'view' });
const kept = result.text.includes('3 rows'); // grounded - survives
const stripped = !result.text.includes('900%'); // hallucinated - removed
ai.destroy();
grid.destroy();
return `${result.flagged.length} flagged | ${kept} kept | ${stripped} stripped`;
Board / Gantt risk summary (modules/ai)
A project manager wants one line: “3 tasks at risk on the critical path, SPI 0.67, 2 SLA breaches.” ai.riskSummary(…) (and the { kind: 'risk' } target of explain) produces exactly that, grounded on figures the separate optional modules have already computed: gantt.earnedValue() for SPI/CPI and the schedule/cost variances, gantt.schedule for the critical path and the tasks at risk on it, and board.sla for the SLA breach and warning counts. Every figure runs through the same number-reconciliation guard as the rest of the narrative - an ungrounded figure is stripped before the user sees it.
The AI bundle imports neither the Gantt nor the Kanban module. You pass the module instances (or their already-computed outputs) on the target, and the layer reads them duck-typed - so a page that loads the AI module without those bundles carries none of their weight. buildRiskFacts(target, opts) is exported to build (and preview) the exact grounded facts a risk summary would use, without calling ask(). Redaction: a risk summary carries aggregates only by default - counts and the EVM indices/variances; it withholds task names and card contents. includeTaskNames adds the at-risk task names (bounded by maxTasks) and includeCost adds the money figures (BAC/PV/EV/AC), each the host's explicit opt-in, reported back in meta.exposed.
const { buildRiskFacts } = await import('../packages/modules/ai/index.js');
// The public outputs a host already holds from the SEPARATE gantt / kanban
// modules. The AI bundle imports neither - it reads these duck-typed.
const earnedValue = { ok: true, project: { spi: 0.8, cpi: 0.9, sv: -1000, cv: -500 } };
const schedule = {
ok: true,
order: ['a', 'b', 'c'],
critical: ['a', 'b', 'c'], // all three on the critical path
tasks: new Map([
['a', { id: 'a', name: 'Design', percentComplete: 100, totalFloat: 0 }],
['b', { id: 'b', name: 'Build', percentComplete: 40, totalFloat: 0 }],
['c', { id: 'c', name: 'Ship', percentComplete: 0, totalFloat: -2 }],
]),
};
const breaches = [{ key: 'CARD-1' }, { key: 'CARD-2' }]; // from board.sla.breaches()
const { facts } = buildRiskFacts({ kind: 'risk', earnedValue, schedule, breaches });
const by = Object.fromEntries(facts.map((f) => [f.id, f]));
// Two incomplete tasks (Build, Ship) are on the critical path - at risk.
return `${by['risk.atRisk'].display} at risk | SPI ${by['risk.spi'].display} | ${by['risk.sla.breaches'].display} breaches`;
Type reference
Generated from the type declarations, so it always matches the release. Each surface lists its properties, its methods and the events it raises as three tables; an option or value type lists its members once.
The AI module
AIFact
A single computed figure a narrative is grounded on.
| Property | Type | Description |
|---|---|---|
| id | string | A stable identifier for the figure, so a caller can find it again in the packet. |
| label | string | What the figure is, in words - the column's resolved title where it has one. |
| value | number | null | The raw numeric value, or null for a context-only fact. |
| display | string | The pre-formatted display string the model is told to use verbatim. |
| kind | string | What sort of figure it is, which is what the model is told alongside it. `context` marks a fact with no number: it may be mentioned but grounds nothing. |
| colId | string | The column the figure is about, where it is about one. (optional) |
AITarget
| Property | Type | Description |
|---|---|---|
| kind | AIBriefKind 'view' | 'column' | 'forecast' | 'kpi' | 'chart' | 'risk' | What to narrate. Defaults to `view` - the current filtered view - with `column` and `forecast` narrating one column, `kpi` and `chart` narrating figures you pass in `facts`, and `risk` assembling a project summary from a Gantt and a board. (optional) |
| colId | string | Which column to narrate, for `column` and `forecast`. A redacted column grounds nothing: the packet comes back empty and flagged as redacted rather than quietly narrating without it. (optional) |
| options | object | Forecast options, for `kind: 'forecast'`. (optional) |
| facts | Array<{ id?: string; label: string; value: unknown; display?: string; kind?: string; colId?: string }> | Caller-supplied figures for a KPI/chart Explain, grounded like the rest. (optional) |
| gantt | unknown | For `kind: 'risk'`: a Gantt instance (from `createGantt`). Read duck-typed for `earnedValue()` (SPI/CPI/variances) and `schedule` (critical path, float). The AI bundle never imports the Gantt module. (optional) |
| board | unknown | For `kind: 'risk'`: a Kanban board (from `createKanban`). Read for its `board.sla` monitor (breach / warning counts). The AI bundle never imports the Kanban module. (optional) |
| sla | unknown | For `kind: 'risk'`: an SLA monitor, if not reached through `board`. (optional) |
| earnedValue | object | For `kind: 'risk'`: a precomputed `gantt.earnedValue()` result. (optional) |
| schedule | object | For `kind: 'risk'`: a precomputed `gantt.schedule` result. (optional) |
| breaches | object[] | For `kind: 'risk'`: precomputed SLA breach states. (optional) |
| warnings | object[] | For `kind: 'risk'`: precomputed SLA warning states. (optional) |
| evmOptions | object | For `kind: 'risk'`: options passed to `gantt.earnedValue()`. (optional) |
| includeTaskNames | boolean | For `kind: 'risk'`: expose the at-risk task NAMES (off by default - a risk summary carries aggregates only unless the host opts in). (optional) |
| includeCost | boolean | For `kind: 'risk'`: expose the money figures BAC/PV/EV/AC (off by default). (optional) |
| maxTasks | number | For `kind: 'risk'`: cap on named at-risk tasks (default 10). (optional) |
AIFactsPacket
The facts packet a narrative grounds on.
| Property | Type | Description |
|---|---|---|
| target | AITarget | The target the packet was built for, as given. |
| facts | AIFact[] | Every figure the narrative may cite, each with the display string the model is told to use verbatim. |
| groundedValues | number[] | The numeric values seeding the reconciliation registry. |
| meta | { kind: string; filtered: boolean; factCount: number; redacted?: boolean; colId?: string; /** For `kind: 'risk'`: which module sources resolved. */ sources?: { schedule: boolean; earnedValue: boolean; sla: boolean }; /** For `kind: 'risk'`: which opt-in exposures were honoured. */ exposed?: { taskNames: boolean; cost: boolean }; } | What the packet is and how it was built: the target kind, whether the view was filtered, how many facts there are, and - where they apply - the redaction flag, the column, which module sources resolved for a risk summary, and which opt-in exposures were honoured. |
AIRiskFacts
The risk facts a board / Gantt risk summary grounds on, from {@link buildRiskFacts}: the facts plus which module sources resolved and which opt-in exposures (task names, cost) were honoured.
| Property | Type | Description |
|---|---|---|
| facts | AIFact[] | The risk figures the summary grounds on - schedule and earned-value indices, float, SLA breaches - and, when task names are allowed, the at-risk tasks as context facts carrying no number. |
| meta | { kind: 'risk'; sources: { schedule: boolean; earnedValue: boolean; sla: boolean }; exposed: { taskNames: boolean; cost: boolean }; } | Which of the three sources actually resolved (schedule, earned value, SLA) and which opt-in exposures were honoured. Nothing resolving warns, because there is then nothing to summarise. |
AINarrative
The result of a narrative: reconciled prose plus what grounded and what did not.
| Property | Type | Description |
|---|---|---|
| text | string | The narrative, with every ungrounded figure stripped (or flagged). |
| facts | AIFact[] | The figures the narrative was grounded on - the packet's facts, for showing beside the prose. |
| grounded | string[] | The figures that reconciled against a computed value. |
| flagged | string[] | The figures removed as ungrounded. |
| packet | AIFactsPacket | The whole facts packet the narrative was built from, for a host that wants to show its working. |
| rounds | number | How many ask() rounds ran (>1 only on the tool-use path). |
| mode | AINarrativeMode 'tools' | 'packet' | Which path ran: `tools` when the model was given read-only tools to call, `packet` when it was handed the facts up front. |
AIConfig
AI module configuration.
| Property | Type | Description |
|---|---|---|
| ask | AIAsk | The host's model callback. Falls back to the grid's `ai.ask` when omitted. (optional) |
| enable | string[] | Restricts which of the three DOM-mounting convenience methods are allowed to mount: `'narrative'`/`'insights'` for `insights()`, `'query'`/`'ask'` for `askBar()`, `'actor'` for `actorBar()`. All three are allowed when `enable` is omitted. This does NOT gate the programmatic API - `explain()`, `query()`, `propose()`, `facts()`, `riskSummary()` and the rest of the controller always run regardless of `enable` - because a host that wants no AI surface at all simply never calls these methods. (optional) |
| autoApply | boolean | Ask-your-data: apply a safe (read-only) query result without a confirm step. Off by default - the resolved query is shown and waits for Apply. (optional) |
| router | unknown | A Data Router instance; on applying a query the answer rows are fanned to its attached viewers (grid + chart + KPI together) via `load()`. (optional) |
| schemaOptions | object | Budgets passed to the schema builder for ask-your-data. (optional) |
| context | unknown | Extra context passed through to `ask()`. (optional) |
| board | unknown | A Kanban board (from `createKanban`) the governed actor writes moves through: an NL card move applies via the board's own `beforeMove` gate, never a kanban-specific write bypass. (optional) |
| maxRows | number | Cap on rows any tool result carries to `ask()`. (optional) |
| redact | string | string[] | ((colId: string) => boolean) | Columns whose values must never leave the browser. (optional) |
| tools | boolean | Force tool-use on or off; auto-detected from how `ask` was supplied otherwise. (optional) |
| locale | string | Locale for figure formatting. (optional) |
| maxColumns | number | Column cap for a view summary. (optional) |
| reconcile | AIReconcileMode 'strip' | 'flag' | What to do with an ungrounded figure: `'strip'` (default) or `'flag'`. (optional) |
| element | HTMLElement | An element to mount the insights panel into. (optional) |
| Method | Signature | Parameters | Returns | Description |
|---|---|---|---|---|
| onQuery | (result: AIQueryEvent) => void | result: AIQueryEvent | => void | Called with each ask-your-data result, alongside the `query` event. (optional) |
| onProposal | (result: AIProposalEvent) => void | result: AIProposalEvent | => void | Called with each governed-actor proposal (Play C), before any approval; alongside the `proposal` event. (optional) |
| onNarrative | (result: AINarrativeEvent) => void | result: AINarrativeEvent | => void | Called when a narrative is produced, alongside the `narrative` event. (optional) |
| onError | (error: AIErrorEvent) => void | error: AIErrorEvent | => void | Called when a run fails - no `ask()` is configured, or `ask()` threw - alongside the `error` event. The grid stays usable. (optional) |
AIApplyReport
The report from applying an ask-your-data query.
| Property | Type | Description |
|---|---|---|
| ok | boolean | Whether the query was applied. False when the read-only gate refused the plan, and when the grid could not apply it. |
| applied | string[] | The action types that were applied. |
| failed | Array<{ type: string; reason: string }> | Actions that threw while applying. |
| refused | Array<{ type: string; reason: string }> | Actions refused by the read-only gate - a mutation is never applied. |
| fannedOut | number | How many answer rows were fanned to a router's viewers. |
AIQueryResult
The result of an ask-your-data question: a validated, READ-ONLY query spec - never rows - that the host reviews before applying.
| Property | Type | Description |
|---|---|---|
| ok | boolean | True when the spec is safe to apply: at least one read, nothing unsafe. |
| question | string | The user's question. |
| plan | Record<string, unknown> | The core plan (from `grid.ai.plan`). |
| actions | object[] | The read-only actions that will run - the validated query spec. |
| unsafe | Array<{ type: string; reason: string }> | Actions refused as not read-only (a mutation the model asked for). |
| rejected | Array<{ at: string; what: string; reason: string }> | Parts the core validator dropped (unknown column, bad operator, …). |
| explain | string | The model's own one-line summary, if any. |
| spec | { actions: object[] } | The validated query spec as data. |
| applied | AIApplyReport | null | The apply report once applied, or null. |
| Method | Signature | Parameters | Returns | Description |
|---|---|---|---|---|
| describe | (): string | - | string | The resolved query in one human sentence, from the validated spec. |
| apply | (opts?: { router?: unknown; onResult?: (rows: object[]) => void }): AIApplyReport | opts?: { router?: unknown; onResult?: (rows: object[]) => void } | AIApplyReport | Apply the query (re-gated), fanning the answer to a router if configured. |
AIDiffEntry
One before/after change in a governed-actor proposal.
| Property | Type | Description |
|---|---|---|
| key | string | The target row key. |
| rowLabel | string | A human label identifying the row (a name-like column, else the key). |
| colId | string | The target column id. |
| colTitle | string | The column's title, for the diff header. |
| oldValue | unknown | The current stored value. |
| oldDisplay | string | The current value as shown (a lookup id mapped to its label). |
| newValue | unknown | The proposed stored value (a label resolved to its option id). |
| newDisplay | string | The proposed value as shown. |
AIProposal
| Property | Type | Description |
|---|---|---|
| ok | boolean | True when there is at least one applicable change and nothing needs a pick first. |
| instruction | string | The user's instruction. |
| scope | AIProposalScope 'view' | 'all' | `'view'` (the filtered set, the default) or `'all'` (an opted-in widen). |
| scopeCount | number | How many rows the scope covers. |
| scopeText | string | The scope in words, always stated in the confirm/diff. |
| bulk | boolean | Whether any proposal was a bulk (`scope:'view'`) edit. |
| diff | AIDiffEntry[] | The before/after diff - exactly what would change. Nothing is written yet. |
| rejected | Array<{ reason: string; [k: string]: unknown }> | Proposals refused before apply (unknown column, unknown label, bad type/range, no match). |
| ambiguous | Array<{ reason: string; candidates: Array<{ key: string; label: string }>; [k: string]: unknown }> | Matches needing a human pick (>1 row for one phrase), with candidates. |
| outOfView | Array<{ reason: string; candidates: Array<{ key: string; label: string }>; [k: string]: unknown }> | Named targets found only outside the view, offered for an opt-in widen. |
| noops | Array<{ reason: string; [k: string]: unknown }> | Matches whose value already equals the ask (nothing to change). |
| applied | AIProposalReport | null | The apply report once applied, or null. |
| Method | Signature | Parameters | Returns | Description |
|---|---|---|---|---|
| describe | (): string | - | string | The proposal in one human sentence, always stating the scope. |
| apply | (opts?: { board?: unknown }): Promise<AIProposalReport> | opts?: { board?: unknown } | Promise<AIProposalReport> | Apply the approved diff through the gate (`beforeEdit`, or `beforeMove` for a board). |
AIProposalReport
The report from applying a governed-actor proposal.
| Property | Type | Description |
|---|---|---|
| ok | boolean | True when at least one edit landed. |
| applied | number | How many edits landed through the gate. |
| requested | number | How many edits were attempted. |
| vetoed | number | How many were stopped by a before-handler veto. |
| via | string | Which gated path applied them: `'setCells'`, `'board.move'`, or `'none'`. |
AINarrativeEvent
`narrative`: a narrative run finished and its result is in hand. The result {@link AI.explain} resolves to, copied with `type` added by the module's emitter - the same figures, already reconciled, so a handler that only wants to paint the text need not await the call itself.
| Property | Type | Description |
|---|---|---|
| type | string | Which event this is: `narrative`. |
AIQueryEvent
`query`: an ask-your-data question resolved into a validated, read-only query spec. The result {@link AI.query} resolves to, copied with `type` added. It fires whether or not the spec is safe (`ok`) and whether or not `autoApply` applied it - the apply happens before the event, so `applied` is already filled in when it did.
| Property | Type | Description |
|---|---|---|
| type | string | Which event this is: `query`. |
AIProposalEvent
`proposal`: the governed actor produced a reviewable set of edits. The result {@link AI.propose} resolves to, copied with `type` added. Nothing has been written: this is the point at which a host shows the diff and asks a human.
| Property | Type | Description |
|---|---|---|
| type | string | Which event this is: `proposal`. |
AIErrorEvent
`error`: a run failed, and the call that started it is rejecting. Raised for a missing `ask()` and for an `ask()` that threw, on all three runs. The grid is untouched either way. Exactly one of `target`, `question` and `instruction` is present - whichever run failed.
| Property | Type | Description |
|---|---|---|
| type | string | Which event this is: `error`. |
| error | Error | What went wrong: the error `ask()` threw, or the one the module raised for a missing `ask()`. |
| target | AITarget | The narrative target, when {@link AI.explain} or {@link AI.riskSummary} failed. (optional) |
| question | string | The question, when {@link AI.query} failed. (optional) |
| instruction | string | The instruction, when {@link AI.propose} failed. (optional) |
AIEventPayloads
What a handler receives, per AI event.
| Property | Type | Description |
|---|---|---|
| narrative | AINarrativeEvent | The reconciled narrative. |
| query | AIQueryEvent | The validated query result. |
| proposal | AIProposalEvent | The proposed edits, with their before/after diff. |
| error | AIErrorEvent | What failed, and which run it was. |
AI
An AI controller over a live grid. It explains the grid's computed figures (Play A), answers questions with validated read-only query specs (Play B), and PROPOSES governed edits a human approves and the grid's own gate applies (Play C). `grid.ai` (in core) is the complementary intent/plan skill layer this consumes.
Properties
| Property | Type | Description |
|---|---|---|
| el | HTMLElement | null | The mounted insights panel element, or null. (read-only) |
| ready | boolean | Whether a usable `ask()` is configured. (read-only) |
Methods
| Method | Signature | Parameters | Returns | Description |
|---|---|---|---|---|
| explain | (target?: AITarget, opts?: object): Promise<AINarrative> | target?: AITargetopts?: object | Promise<AINarrative> | Produce a grounded, reconciled narrative for a target. |
| narrate | (target?: AITarget, opts?: object): Promise<AINarrative> | target?: AITargetopts?: object | Promise<AINarrative> | An alias for {@link AI.explain}. |
| riskSummary | (sources?: { gantt?: unknown; board?: unknown; sla?: unknown; earnedValue?: object; schedule?: object; breaches?: object[]; warnings?: object[]; includeTaskNames?: boolean; includeCost?: boolean; maxTasks?: number; evmOptions?: object; }, opts?: object): Promise<AINarrative> | sources?: { gantt?: unknown; board?: unknown; sla?: unknown; earnedValue?: object; schedule?: object; breaches?: object[]; warnings?: object[]; includeTaskNames?: boolean; includeCost?: boolean; maxTasks?: number; evmOptions?: object; }opts?: object | Promise<AINarrative> | Produce a grounded, reconciled board / Gantt RISK SUMMARY: a plain-language reading like "3 tasks at risk on the critical path, SPI 0.67, 2 SLA breaches". A convenience over `explain({ kind: 'risk', ... })`; the module sources go in `sources` (`gantt`, `board`/`sla`, or precomputed outputs). Every figure runs through the same reconciliation guard as {@link AI.explain}. |
| insights | (el?: HTMLElement, opts?: object): AI | el?: HTMLElementopts?: object | AI | Mount (or re-target) the insights panel into an element. |
| attachExplain | (target: AITarget, opts?: object): HTMLElement | null | target: AITargetopts?: object | HTMLElement | null | Build an "Explain" button bound to a target. |
| facts | (target?: AITarget, opts?: object): AIFactsPacket | target?: AITargetopts?: object | AIFactsPacket | Build the facts packet for a target without calling `ask()`. |
| query | (question: string, opts?: { autoApply?: boolean; router?: unknown; schemaOptions?: object; context?: unknown; tools?: boolean; signal?: AbortSignal; onResult?: (rows: object[]) => void; }): Promise<AIQueryResult> | question: stringopts?: { autoApply?: boolean; router?: unknown; schemaOptions?: object; context?: unknown; tools?: boolean; signal?: AbortSignal; onResult?: (rows: object[]) => void; } | Promise<AIQueryResult> | Ask-your-data: turn a question into a validated, read-only query spec, run it in the engine, and (on apply) fan the answer to router-attached viewers. Returns a result the host reviews; `autoApply` applies a safe read for you. |
| applyQuery | (result: AIQueryResult, opts?: { router?: unknown; onResult?: (rows: object[]) => void }): AIApplyReport | result: AIQueryResultopts?: { router?: unknown; onResult?: (rows: object[]) => void } | AIApplyReport | Apply a reviewed query result (the confirm path); re-gated at the seam. |
| askBar | (el?: HTMLElement, opts?: object): AI | el?: HTMLElementopts?: object | AI | Mount the ask-your-data bar (input, Ask, auto-apply toggle, preview, Apply/Discard). |
| propose | (instruction: string, opts?: { widen?: boolean; board?: unknown; schemaOptions?: object; maxRows?: number; context?: unknown; redact?: string | string[] | ((colId: string) => boolean); signal?: AbortSignal; }): Promise<AIProposal> | instruction: stringopts?: { widen?: boolean; board?: unknown; schemaOptions?: object; maxRows?: number; context?: unknown; redact?: string | string[] | ((colId: string) => boolean); signal?: AbortSignal; } | Promise<AIProposal> | Governed actor (Play C): ask the model for structured edit PROPOSALS over the current view, validate and resolve them (label -> stored value, locate a named row, reject unknown columns/labels/out-of-range), and return a reviewable {@link AIProposal} with a before/after diff. NOTHING is written - the model proposes; a human approves. |
| applyProposal | (result: AIProposal, opts?: { board?: unknown }): Promise<AIProposalReport> | result: AIProposalopts?: { board?: unknown } | Promise<AIProposalReport> | Apply an approved proposal - the human-approval step. Writes ONLY through the gate: a grid cell edit via `grid.edit.setCells({ origin: 'ai' })` (the `beforeEdit` veto), a kanban move via `board.move({ origin: 'ai' })` (the `beforeMove` veto). A vetoing host handler stops the write. |
| actorBar | (el?: HTMLElement, opts?: object): AI | el?: HTMLElementopts?: object | AI | Mount the governed-actor bar: an instruction input, Propose, a before/after diff preview stating the scope, and Approve/Discard. Approve applies through the gate. |
| on | (name: AIEventName, fn: (payload: AIEventPayloads[AIEventName]) => void): () => void | name: AIEventNamefn: (payload: AIEventPayloads[AIEventName]) => void | () => void | Register an event handler; returns a function that removes it. Any other name is warned about once. What each event carries is {@link AIEventPayloads}; the handler is declared with the widest of them, so narrow on the name inside it. |
| off | (name: AIEventName, fn: (payload: AIEventPayloads[AIEventName]) => void): void | name: AIEventNamefn: (payload: AIEventPayloads[AIEventName]) => void | void | Remove a handler registered with `on`. |
| destroy | (): void | - | void | Tear the controller down: empty anything it mounted and remove only the classes it added. The grid is left exactly as it was. |
Events
| Event | When | Payload | Cancellable |
|---|---|---|---|
| narrative | A narrative run finished; the payload is the reconciled result. | AINarrativeEvent | no |
| query | A question resolved into a validated read-only query spec, already applied when `autoApply` was on. | AIQueryEvent | no |
| proposal | The governed actor produced a reviewable proposal; nothing has been written. | AIProposalEvent | no |
| error | A run failed - no `ask()` is configured, or `ask()` threw - and the call is rejecting. | AIErrorEvent | no |