/** * Genie chat driver. * * Drives a single turn against a Genie space from one `content` string; * multi-turn conversations are the caller's job (thread the `conversation_id` * returned on each `GenieMessage` back into the next turn's * `options.conversationId`). * * Two layers serve two kinds of consumer. The low-level layer yields every * poll-observed `GenieMessage` (validated against `GenieMessageSchema`, * falling back to the raw snapshot on a schema miss) and owns the messy parts * - cancellation, conversation seeding, distinct-filtering, and SDK quirks * (Waiter stripping); reach for it when you want the raw stream. The * high-level layer wraps it and emits semantic, deduplicated `{ type, payload }` * events (see {@link GenieChatEvent}), always closing a successful turn with a * terminal `result` event carrying the final `GenieMessage`; errors propagate * by throwing, with no `error` variant. Iterating UI / agent code that wants * every message verbatim takes the low-level stream; subscribers reacting to * "Genie is thinking about X" or "Genie produced text Y" take the event layer. * * @module */ import { type WorkspaceClient } from "@databricks/appkit"; import { databricks } from "@dbx-tools/appkit"; import { type GenieChatEvent, type GenieMessage } from "@dbx-tools/shared-genie"; /** Options accepted by both {@link genieChat} and {@link genieEventChat}. */ export interface GenieChatOptions { /** * Seed conversation id. When set, this turn appends to the existing * conversation (via `createMessage`) instead of opening a new one. Use it to * thread a multi-turn conversation: read `conversation_id` off the prior * turn's terminal `GenieMessage` (or the `result` event's * `payload.conversation_id`) and pass it into the next call. */ conversationId?: string; /** * Explicit `WorkspaceClient`. Defaults to AppKit's per-request * execution-context client when AppKit is installed and we're inside a * request; falls back to `createWorkspaceClient()` (default auth) * otherwise. */ workspaceClient?: WorkspaceClient; /** Poll cadence in milliseconds between successive `getMessage` calls (default 500). */ pollIntervalMs?: number; /** * External cancellation. Accepts a WHATWG `AbortSignal` or a fully-built SDK * `Context` (see `databricks.ContextLike`). Aborting it cancels every in-flight * SDK call and the next inter-poll sleep. */ context?: databricks.ContextLike; } /** * One turn against a Genie space, yielded as a stream of `GenieMessage` * snapshots. * * Turn lifecycle: * * - No `options.conversationId`: open a new conversation via * `client.genie.startConversation`. The opened conversation id surfaces on * every yielded `GenieMessage` (`.conversation_id`) so the caller can * thread it into a follow-up call. * - With `options.conversationId`: append to that conversation via * `client.genie.createMessage`. * - In both cases, after the create/start the driver polls * `client.genie.getMessage` every `options.pollIntervalMs` (default 500ms) * until the message reaches a terminal status, then yields the terminal * snapshot and returns. * * Cancellation: a single internal `AbortController` covers the whole turn. * `options.context` is tied into that controller so an external abort tears * down every in-flight SDK call AND the inter-poll sleep. Breaking out of the * `for await` does the same via the `try / finally`. * * @example * // Single turn. * for await (const m of genieChat(spaceId, "Top 5 stores?")) { * render(m); * } * * @example * // Multi-turn: caller threads the conversation id. * let conversationId: string | undefined; * for (const question of questions) { * for await (const m of genieChat(spaceId, question, { conversationId })) { * conversationId = m.conversation_id ?? conversationId; * render(m); * } * } */ export declare function genieChat(space_id: string, content: string, options?: GenieChatOptions): AsyncGenerator; /** * One turn against a Genie space, yielded as a typed {@link GenieChatEvent} * stream. Drives {@link genieChat} underneath and decorates each snapshot with * the derived events the field-level diff produced. Stream order: * * 1. `{ type: "message", message }` - the raw `GenieMessage`, once per poll * yield. * 2. `{ type: "question", content, message_id, ... }` fires exactly once, on * the FIRST `message` yield. We read `content` and `message_id` straight * off the snapshot so every downstream event for this turn shares the same * `message_id` (the question included) - subscribers can group everything * for one Genie call under that one key. * 3. Any of `status` / `attachment` / `thinking` / `text` / `query` / * `statement` / `rows` / `suggested_questions` the diff against the prior * snapshot produced. * 4. On the terminal snapshot, `{ type: "result", ... }` as the final yield. * * Errors propagate by the generator throwing - there's no `"error"` variant. * Wrap the `for await` in `try/catch` if you need to handle failures. * * @example * for await (const evt of genieEventChat(spaceId, "Top stores?")) { * switch (evt.type) { * case "thinking": * console.log("[thinking]", evt.thought_type, evt.text); * break; * case "text": * console.log("[text]", evt.text); * break; * case "result": * console.log("[done]", evt.status); * break; * } * } */ export declare function genieEventChat(space_id: string, content: string, options?: GenieChatOptions): AsyncGenerator;