/** * A single question, with nothing kept afterwards. * * Its own task and no session, so two `ask()`s in flight never supersede each * other and never queue behind one another for the same engine — which is what * would happen if this shared a session key with anything else. * * @param {import("./engine.js").ScheduledEngine} engine * @param {string | Array<{role: string, content: string}>} input * @param {object} [opts] anything `complete()` takes; `onDelta` to stream * @returns {Promise} the reply text */ export function ask(engine: import("./engine.js").ScheduledEngine, input: string | Array<{ role: string; content: string; }>, { onDelta, ...opts }?: object): Promise; /** * A multi-turn conversation that remembers its own history. * * Two things this gets right that hand-rolled history usually does not: * * **One task for the whole conversation.** Every turn carries the same `task`, * so a conversation holds at most one engine and a long reply can never occupy * the pool while another conversation waits. Turns within it are serialised, * which is what a conversation means anyway. * * **A bounded history, by default.** There is no cross-turn KV reuse on this * stack (AI.md: every turn re-prefills the whole history at ~5.27 ms/token), so * an unbounded conversation gets quadratically slower and a turn near the 4096 * limit waits ~22 s for its first token. `keep` bounds it. Set `keep: Infinity` * to opt out, having read that sentence. * * @param {import("./engine.js").ScheduledEngine} engine * @param {object} [opts] * @param {string} [opts.system] a system message, prepended and never trimmed * @param {number} [opts.keep] how many *exchanges* of history to carry * @param {string} [opts.task] defaults to a fresh id */ export function conversation(engine: import("./engine.js").ScheduledEngine, { system, keep, task, ...defaults }?: { system?: string; keep?: number; task?: string; }): { /** The messages as they would be sent, including the system message. */ readonly messages: any[]; /** Exchanges currently retained. */ readonly length: number; /** * Say something and get the reply, with the exchange appended to history. * * Serialised against the previous turn: a conversation whose turns * overlapped would interleave history and produce replies to the wrong * question. * * @param {string} content * @param {(delta: string) => void} [onDelta] */ say(content: string, onDelta?: (delta: string) => void): Promise<{ text: string; finishReason: "length" | "stop" | "abort"; }>; /** Forget the history. The system message and settings survive. */ reset(): /*elided*/ any; /** Drop the history in, e.g. when restoring a saved conversation. */ restore(messages: any): /*elided*/ any; }; /** * Ghost text: the scheduling discipline, with the prompt left to the caller. * * Every part of this exists because of a specific way ghost text goes wrong: * * | | | * | --- | --- | * | one stable `session` | a fresh id per keystroke makes every stale request still run — AI.md's first "getting these wrong" row | * | `interactive` priority | it is the one band that may preempt work that opted in | * | debounce | a request per keystroke queues faster than the GPU drains | * | short `max_tokens` | ghost text is a few words; paying for more is pure latency | * | resolves `null` when stale | so a superseded suggestion **cannot** be rendered by mistake | * * That last one is the difference between this and a wrapper. The engine * already supersedes stale requests; what a caller still has to remember is not * to paint the answer that comes back. Returning `null` removes the choice. * * @param {import("./engine.js").ScheduledEngine} engine * @param {object} opts * @param {(context: any) => string | Array} opts.prompt **required** — * builds the messages. Never defaulted: see the module header. * @param {number} [opts.debounceMs] * @param {number} [opts.maxTokens] * @param {string} [opts.session] */ export function ghostText(engine: import("./engine.js").ScheduledEngine, { prompt, debounceMs, maxTokens, session, ...defaults }?: { prompt: (context: any) => string | Array; debounceMs?: number; maxTokens?: number; session?: string; }): { /** * Ask for a suggestion. Debounced, superseding, and `null` when stale. * * @param {any} context whatever `prompt` takes * @returns {Promise} `null` if superseded or cancelled */ suggest(context: any): Promise; /** On blur, or on accept. Cancels in flight and invalidates anything pending. */ cancel(): number; };