@dbx-tools/genie 0.1.20 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +177 -0
- package/package.json +3 -3
package/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# @dbx-tools/genie
|
|
2
|
+
|
|
3
|
+
Server-side Genie chat drivers. Two async generators that take a
|
|
4
|
+
`space_id` + a single `content` string for one turn against a Genie
|
|
5
|
+
space and yield either the raw `GenieMessage` snapshots
|
|
6
|
+
(`genieChat`) or a typed `GenieChatEvent` stream of flat
|
|
7
|
+
`{ type, ...fields }` records (`genieEventChat`).
|
|
8
|
+
|
|
9
|
+
Multi-turn conversations are caller-driven: read `conversation_id`
|
|
10
|
+
off the prior turn's terminal `GenieMessage` (or the `result`
|
|
11
|
+
event's `conversation_id`) and thread it into the next call's
|
|
12
|
+
`options.conversationId`.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { genieEventChat } from "@dbx-tools/genie";
|
|
16
|
+
|
|
17
|
+
for await (const event of genieEventChat(spaceId, "Top 5 stores?")) {
|
|
18
|
+
switch (event.type) {
|
|
19
|
+
case "thinking":
|
|
20
|
+
console.log("[think]", event.thought_type, event.text);
|
|
21
|
+
break;
|
|
22
|
+
case "query":
|
|
23
|
+
console.log("[sql]", event.title, "\n", event.sql);
|
|
24
|
+
break;
|
|
25
|
+
case "result":
|
|
26
|
+
console.log("[done]", event.status);
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Browser safety: `chat.ts` pulls in `WorkspaceClient` from
|
|
33
|
+
`@databricks/sdk-experimental` and is Node-only. Browser bundles
|
|
34
|
+
should import from [`@dbx-tools/genie-shared`](../genie-shared)
|
|
35
|
+
directly - the protocol types, the `GenieChatEvent` union, the pure
|
|
36
|
+
detectors, and `eventsFromMessage` all live there and are also
|
|
37
|
+
re-exported from `@dbx-tools/genie` for server-side convenience.
|
|
38
|
+
|
|
39
|
+
## `genieChat` - low-level snapshot stream
|
|
40
|
+
|
|
41
|
+
Yields every poll-observed `GenieMessage` for a single turn. Use it
|
|
42
|
+
when you want the raw stream (e.g. to drive a custom UI off the wire
|
|
43
|
+
shape, or to derive events yourself with the detectors in
|
|
44
|
+
`@dbx-tools/genie-shared`).
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { genieChat } from "@dbx-tools/genie";
|
|
48
|
+
|
|
49
|
+
// Single turn.
|
|
50
|
+
for await (const m of genieChat(spaceId, "Top 5 stores?")) {
|
|
51
|
+
render(m);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Multi-turn: caller threads the conversation id.
|
|
55
|
+
let conversationId: string | undefined;
|
|
56
|
+
for (const question of questions) {
|
|
57
|
+
for await (const m of genieChat(spaceId, question, { conversationId })) {
|
|
58
|
+
conversationId = m.conversation_id ?? conversationId;
|
|
59
|
+
render(m);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Turn lifecycle:
|
|
65
|
+
|
|
66
|
+
- **No `options.conversationId`**: opens a new conversation via
|
|
67
|
+
`client.genie.startConversation`. The assigned id surfaces on
|
|
68
|
+
every yielded `GenieMessage.conversation_id`.
|
|
69
|
+
- **With `options.conversationId`**: appends to that conversation
|
|
70
|
+
via `client.genie.createMessage`.
|
|
71
|
+
- In both cases, after the create/start the driver polls
|
|
72
|
+
`client.genie.getMessage` every `options.pollIntervalMs` (default
|
|
73
|
+
500ms) until the message hits a terminal status
|
|
74
|
+
(`COMPLETED` / `FAILED` / `CANCELLED`), then yields the terminal
|
|
75
|
+
snapshot and returns.
|
|
76
|
+
|
|
77
|
+
Identical consecutive snapshots are filtered out (deep equal)
|
|
78
|
+
because Genie often returns the exact same payload twice during
|
|
79
|
+
quiet periods.
|
|
80
|
+
|
|
81
|
+
## `genieEventChat` - high-level typed events
|
|
82
|
+
|
|
83
|
+
Wraps `genieChat` and yields a `GenieChatEvent` discriminated union.
|
|
84
|
+
Stream order per turn:
|
|
85
|
+
|
|
86
|
+
1. `{ type: "message", message }` - the raw `GenieMessage`, once
|
|
87
|
+
per poll yield.
|
|
88
|
+
2. `{ type: "question", content, message_id, ... }` - fires
|
|
89
|
+
exactly once, on the first `message` yield. Carries the prompt
|
|
90
|
+
text Genie echoed back and the assigned `message_id` so
|
|
91
|
+
subscribers can group everything for one Genie call under that
|
|
92
|
+
one key.
|
|
93
|
+
3. Any of `status` / `attachment` / `thinking` / `text` / `query` /
|
|
94
|
+
`statement` / `rows` / `suggested_questions` the diff against
|
|
95
|
+
the prior snapshot produced.
|
|
96
|
+
4. On the terminal snapshot, `{ type: "result", status, message }`
|
|
97
|
+
as the final yield.
|
|
98
|
+
|
|
99
|
+
See [`@dbx-tools/genie-shared`](../genie-shared) for the full event
|
|
100
|
+
catalogue, field shapes, and the pure detectors that derive each
|
|
101
|
+
event from a snapshot diff.
|
|
102
|
+
|
|
103
|
+
Errors propagate by the generator throwing - there is no `error`
|
|
104
|
+
variant. Wrap the `for await` in `try / catch` if you need to handle
|
|
105
|
+
failures.
|
|
106
|
+
|
|
107
|
+
## Options
|
|
108
|
+
|
|
109
|
+
`GenieChatOptions` is the same shape for both drivers:
|
|
110
|
+
|
|
111
|
+
| Option | Default | Description |
|
|
112
|
+
| ----------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
|
|
113
|
+
| `conversationId` | `undefined` | Seed conversation id. When set, this turn appends to the existing conversation via `createMessage`. |
|
|
114
|
+
| `workspaceClient` | resolved (see below) | Explicit `WorkspaceClient`. Defaults to AppKit's per-request client when available; otherwise env-var auth. |
|
|
115
|
+
| `pollIntervalMs` | `500` | Cadence between successive `getMessage` calls. |
|
|
116
|
+
| `context` | new internal `AbortController` per call | External cancellation. Accepts an `AbortSignal` or a fully-built SDK `Context` (`apiUtils.ContextLike`). |
|
|
117
|
+
|
|
118
|
+
### Workspace client resolution
|
|
119
|
+
|
|
120
|
+
Resolved in priority order:
|
|
121
|
+
|
|
122
|
+
1. Caller-supplied `options.workspaceClient`.
|
|
123
|
+
2. AppKit's per-request execution-context client, when
|
|
124
|
+
`@databricks/appkit` is installed AND we're inside an active
|
|
125
|
+
request scope. OBO auth is preserved automatically.
|
|
126
|
+
3. Fresh `new WorkspaceClient({})` (env-var auth via
|
|
127
|
+
`DATABRICKS_CONFIG_PROFILE` / `DATABRICKS_HOST` /
|
|
128
|
+
`DATABRICKS_TOKEN`).
|
|
129
|
+
|
|
130
|
+
AppKit is loaded lazily, so this package is usable from non-AppKit
|
|
131
|
+
environments (smoke scripts, batch jobs, tests, ...).
|
|
132
|
+
|
|
133
|
+
### Cancellation
|
|
134
|
+
|
|
135
|
+
A single internal `AbortController` covers each call. `options.context`
|
|
136
|
+
ties into that controller, so an external abort tears down every
|
|
137
|
+
in-flight SDK call AND the inter-poll sleep. Breaking out of the
|
|
138
|
+
`for await` does the same via the `try / finally`.
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const ac = new AbortController();
|
|
142
|
+
setTimeout(() => ac.abort(), 30_000); // hard 30s ceiling
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
for await (const event of genieEventChat(spaceId, content, { context: ac.signal })) {
|
|
146
|
+
handle(event);
|
|
147
|
+
}
|
|
148
|
+
} catch (err) {
|
|
149
|
+
if (ac.signal.aborted) console.log("timed out");
|
|
150
|
+
else throw err;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Smoke test
|
|
155
|
+
|
|
156
|
+
[`test/poll-chat.ts`](test/poll-chat.ts) drives `genieEventChat` from
|
|
157
|
+
argv / stdin / a REPL and writes every emitted event to a per-run tmp
|
|
158
|
+
directory so you can inspect deltas after the fact. One subdirectory
|
|
159
|
+
per `GenieChatEvent` variant, plus a `rows-data/` directory for paired
|
|
160
|
+
SQL fetches on terminals that carry a `query_result.statement_id`.
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# Required env (already in repo .env):
|
|
164
|
+
# DATABRICKS_GENIE_SPACE_ID
|
|
165
|
+
# DATABRICKS_CONFIG_PROFILE (or any SDK auth env)
|
|
166
|
+
|
|
167
|
+
bun packages/genie/test/poll-chat.ts # REPL
|
|
168
|
+
bun packages/genie/test/poll-chat.ts "Top 5 stores by revenue?"
|
|
169
|
+
echo "Top 5 stores by revenue?" | bun packages/genie/test/poll-chat.ts
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Stdout carries a one-line summary per event with the relative path;
|
|
173
|
+
the per-run directory is printed at the top.
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
Apache-2.0
|
package/package.json
CHANGED
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
11
|
"name": "@dbx-tools/genie",
|
|
12
|
-
"version": "0.1.
|
|
12
|
+
"version": "0.1.21",
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@databricks/sdk-experimental": "^0.17",
|
|
15
|
-
"@dbx-tools/genie-shared": "0.1.
|
|
16
|
-
"@dbx-tools/shared": "0.1.
|
|
15
|
+
"@dbx-tools/genie-shared": "0.1.21",
|
|
16
|
+
"@dbx-tools/shared": "0.1.21"
|
|
17
17
|
},
|
|
18
18
|
"module": "index.ts",
|
|
19
19
|
"type": "module",
|