@dbx-tools/genie
v0.9.190
Published
Server-side Databricks Genie chat drivers
Readme
@dbx-tools/genie
Run Databricks Genie turns from Node or AppKit code as raw message snapshots or a typed event stream. AppKit requests keep their on-behalf-of-user (OBO) identity, standalone callers use the Databricks SDK authentication chain, and both modes support cancellation.
Quick start
import { chat } from "@dbx-tools/genie";
const spaceId = process.env.DATABRICKS_GENIE_SPACE_ID!;
for await (const event of chat.genieEventChat(spaceId, "Top stores by revenue?")) {
console.log(event.type, event);
}Pure Genie schemas and event detector helpers live in @dbx-tools/shared-genie.
The driver:
- Streams the Genie Agent Mode API by default, including reasoning, SQL calls, query output, and the synthesized answer.
- Starts new Genie conversations or continues an existing
conversationId. - Projects Agent Mode response items onto the existing
GenieMessagesnapshot and semantic-event contracts, including statement ids and visualization attachments. - Loads Agent Mode conversation items and groups them back into one
GenieMessageper turn for history replay. - Retains the Conversation API polling driver behind
agentMode: falseand as an automatic pre-stream fallback forFEATURE_DISABLEDor preview-toggle errors. - Converts raw Genie messages into semantic events for thinking text, generated SQL, row counts, final results, and errors.
- Preserves AppKit OBO auth when called during an AppKit request, but also works from standalone scripts with normal Databricks SDK auth.
- Accepts SDK
Contextor webAbortSignalcancellation for route handlers and CLI tools. - Fetches Genie space metadata and starter questions for UI suggestions.
Choose Genie integration
Use native AppKit's Genie plugin for a standalone Genie chat experience. It
provides named space aliases, SSE status updates, conversation
history replay, query result fetching, OBO execution, and the AppKit UI
GenieChat component.
Use direct Genie when one Genie space owns the conversation and answer. Use @dbx-tools/appkit-mastra when a supervising agent must combine Genie with other tools, Mastra memory, approvals, or workflows. Use this package directly when custom backend code needs the lower-level stream:
- You want a low-level async iterator rather than an AppKit HTTP route.
- You want raw message snapshots or a normalized event stream that can be fed into Mastra writer events, logs, tests, or custom SSE endpoints.
- You need to diff snapshots and emit only newly observed thinking, SQL, rows, result, and error events.
- You want to combine Genie answers with agent-side chart planning, statement row fetches, or durable thread storage owned elsewhere.
- You need the same driver to work inside AppKit with OBO auth and outside AppKit from scripts using normal Databricks SDK auth.
Handle semantic events
import { chat } from "@dbx-tools/genie";
for await (const event of chat.genieEventChat(spaceId, "Top stores by revenue?")) {
switch (event.type) {
case "thinking":
console.log(event.thought_type, event.text);
break;
case "query":
console.log(event.sql);
break;
case "rows":
console.log(event.row_count);
break;
case "result":
console.log(event.status);
break;
}
}chat.genieEventChat() wraps the lower-level snapshot stream and yields a
GenieChatEvent union. Use it for SSE streams, log pipelines, and tool writer
events where consumers care about progress and SQL rather than only the terminal
message.
Stream raw message snapshots
import { chat } from "@dbx-tools/genie";
for await (const message of chat.genieChat(spaceId, "Top stores by revenue?")) {
renderSnapshot(message);
}chat.genieChat() starts an Agent Mode response or continues an existing
conversation, projects SSE output into GenieMessage snapshots, filters
identical consecutive payloads, and stops after a terminal response. Set
agentMode: false to force the Conversation API start/create/get-message
polling flow. Use it when you want to run your own diffing or persist the
normalized wire shape. Agent Mode returns query output inline as Markdown and
copies a query output's statement_id onto the matching query attachment when
Databricks supplies one.
Continue a conversation
let conversationId: string | undefined;
for (const prompt of prompts) {
for await (const event of chat.genieEventChat(spaceId, prompt, { conversationId })) {
if ("conversation_id" in event && event.conversation_id) {
conversationId = event.conversation_id;
}
}
}Callers keep multi-turn state by reading the conversation id from a yielded message or event and passing it into the next turn. This works in stateless route handlers, durable thread stores, and one-off scripts. AppKit-Mastra stores the id with its thread and passes it back when a conversation continues.
Resolve a workspace client
import { createWorkspaceClient } from "@databricks/appkit";
import { chat } from "@dbx-tools/genie";
await chat.genieEventChat(spaceId, content, {
workspaceClient: createWorkspaceClient(),
});Client resolution order:
options.workspaceClient.- AppKit execution-context client, when present.
createWorkspaceClient()using AppKit's normal Databricks auth chain.
Pass options.context as an AbortSignal or SDK context to cancel the Agent
Mode stream, SDK calls, and any polling fallback sleep.
Read space metadata and starter questions
import { space } from "@dbx-tools/genie";
const genieSpace = await space.getGenieSpace(spaceId);
const questions = space.genieSampleQuestions(genieSpace);space.getGenieSpace() fetches the space definition, including serialized space
metadata by default. space.genieSampleQuestions() extracts curated starter
questions and returns [] when none are configured.
The serialized blob needs Can Edit on the space, while Can Run is enough for
title and description. When the workspace rejects the serialized request for
lack of permission, getGenieSpace() retries once without it and logs
serialized-space:forbidden, so an app service principal holding only Can Run
still resolves the space and reports no starter questions. Every other
failure - a cancelled request, a missing space, a retry that also fails - is
thrown.
Options
chat.GenieChatOptions is shared by both drivers:
conversationId- append to an existing Genie conversation.agentMode- use Agent Mode SSE, defaulttrue.falseforces polling.agentModeFallback- fall back to classic polling when Agent Mode is unavailable, defaulttrue. Direct Agent-only callers setfalse.enableVisualization- request Agent Mode visualization generation.workspaceClient- explicit Databricks SDK client.pollIntervalMs- fallback polling cadence, default500.context- SDKContextorAbortSignalfor cancellation.
Download a chart image
After requesting visualizations, select the message attachment with a viz
field and download its PNG using the same conversation and message IDs:
import { downloadGenieVisualization } from "@dbx-tools/genie";
const visualization = message.attachments?.find((attachment) => attachment.viz);
if (visualization?.attachment_id) {
const png = await downloadGenieVisualization(
{
space_id: message.space_id,
conversation_id: message.conversation_id,
message_id: message.message_id,
attachment_id: visualization.attachment_id,
},
{ workspaceClient },
);
}Use the visualization's attachment ID, not its linked query attachment ID.
The SDK's raw: true transport returns the binary body and keeps normal SDK
authentication and cancellation. The helper validates the PNG response, then
uses the optional sharp dependency to resize it to four times its original
width and height with Lanczos3 and apply a mild unsharp mask. If sharp is not
installed or cannot process the image, the helper returns the validated
original bytes. Processing happens before the bytes return to callers, so a
downstream cache stores the enhanced image when enhancement succeeds.
This is a raster cleanup fallback. If the source ECharts instance is available,
prefer getDataURL({ pixelRatio: 3 }) or SVG so chart text is re-rendered rather
than enlarged from a screenshot. The endpoint also accepts visualization
attachments from Agent Mode conversations.
Modules
chat-genieChat()raw snapshot stream andgenieEventChat()typed event stream.agentMode-genieAgentModeChat(), availability classification, and Agent Mode transport options plus Agent Mode conversation history.space-getGenieSpace()andgenieSampleQuestions().visualization-downloadGenieVisualization()for validated and optionally enhanced PNG downloads.
The AppKit-Mastra package builds its Genie tools on top of this driver. See @dbx-tools/appkit-mastra for the agent-level workflow.
