@dbx-tools/shared-model 0.3.22 → 0.3.23

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/package.json CHANGED
@@ -12,14 +12,14 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "zod": "^4.3.6",
15
- "@dbx-tools/shared-core": "0.3.22"
15
+ "@dbx-tools/shared-core": "0.3.23"
16
16
  },
17
17
  "main": "index.ts",
18
18
  "license": "UNLICENSED",
19
19
  "publishConfig": {
20
20
  "access": "public"
21
21
  },
22
- "version": "0.3.22",
22
+ "version": "0.3.23",
23
23
  "types": "index.ts",
24
24
  "type": "module",
25
25
  "exports": {
package/src/display.ts CHANGED
@@ -103,11 +103,7 @@ function renderSegment(segment: string): string {
103
103
  const token = tokens[i]!;
104
104
  const lower = token.toLowerCase();
105
105
  // Glue a size unit onto the preceding number: `120` + `b` -> `120B`.
106
- if (
107
- SIZE_UNITS.has(lower) &&
108
- out.length > 0 &&
109
- /^\d+$/.test(out[out.length - 1]!)
110
- ) {
106
+ if (SIZE_UNITS.has(lower) && out.length > 0 && /^\d+$/.test(out[out.length - 1]!)) {
111
107
  out[out.length - 1] = `${out[out.length - 1]}${lower.toUpperCase()}`;
112
108
  continue;
113
109
  }
@@ -0,0 +1,45 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import { toModelDisplayName } from "../src/display";
4
+
5
+ describe("toModelDisplayName", () => {
6
+ it("strips a leading databricks prefix and dots the version", () => {
7
+ assert.equal(toModelDisplayName("databricks-claude-sonnet-4-6"), "Claude Sonnet 4.6");
8
+ });
9
+
10
+ it("strips the system.ai namespace and uppercases acronyms", () => {
11
+ assert.equal(toModelDisplayName("system.ai.bge_large_en"), "BGE Large En");
12
+ });
13
+
14
+ it("uppercases GPT/OSS and glues the size unit", () => {
15
+ assert.equal(toModelDisplayName("databricks-gpt-oss-120b"), "GPT OSS 120B");
16
+ });
17
+
18
+ it("restores AI casing", () => {
19
+ assert.equal(toModelDisplayName("databricks-ai-router"), "AI Router");
20
+ });
21
+
22
+ it("joins multi-part version runs with dots", () => {
23
+ assert.equal(
24
+ toModelDisplayName("databricks-meta-llama-3-3-70b-instruct"),
25
+ "Meta Llama 3.3 70B Instruct",
26
+ );
27
+ });
28
+
29
+ it("prefers a Databricks-provided name verbatim", () => {
30
+ assert.equal(
31
+ toModelDisplayName("databricks-claude-sonnet-4-6", "Claude Sonnet 4.6 (Preview)"),
32
+ "Claude Sonnet 4.6 (Preview)",
33
+ );
34
+ });
35
+
36
+ it("ignores a blank provided name and falls back to the derived label", () => {
37
+ assert.equal(toModelDisplayName("databricks-gpt-5-5", " "), "GPT 5.5");
38
+ });
39
+
40
+ it("title-cases a bare vendor token when nothing else remains", () => {
41
+ // Only leading vendor prefixes are stripped, and never the last
42
+ // remaining token, so a name that is *only* a vendor word stays.
43
+ assert.equal(toModelDisplayName("databricks"), "Databricks");
44
+ });
45
+ });
@@ -0,0 +1,80 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import {
4
+ UNSUPPORTED_CHAT_FIELDS,
5
+ chatContentToText,
6
+ stripUnsupportedChatFields,
7
+ } from "../src/openai-chat";
8
+
9
+ describe("chatContentToText", () => {
10
+ it("passes a string through and flattens typed parts", () => {
11
+ assert.equal(chatContentToText("hello"), "hello");
12
+ assert.equal(
13
+ chatContentToText([{ type: "input_text", text: "a" }, { type: "output_text", text: "b" }]),
14
+ "ab",
15
+ );
16
+ });
17
+
18
+ it("honors a separator and a type filter", () => {
19
+ const content = [
20
+ { type: "text", text: "one" },
21
+ { type: "thinking", text: "hidden" },
22
+ { type: "text", text: "two" },
23
+ ];
24
+ assert.equal(chatContentToText(content, { separator: "\n\n", types: ["text"] }), "one\n\ntwo");
25
+ });
26
+
27
+ it("yields empty string for anything it can't read", () => {
28
+ assert.equal(chatContentToText(null), "");
29
+ assert.equal(chatContentToText(undefined), "");
30
+ assert.equal(chatContentToText([{ type: "image_url" }]), "");
31
+ });
32
+ });
33
+
34
+ describe("stripUnsupportedChatFields", () => {
35
+ it("drops parallel_tool_calls, the field Databricks rejects outright", () => {
36
+ const body: Record<string, unknown> = {
37
+ model: "databricks-claude-opus-4-8",
38
+ messages: [],
39
+ parallel_tool_calls: false,
40
+ };
41
+ assert.deepEqual(stripUnsupportedChatFields(body), ["parallel_tool_calls"]);
42
+ assert.deepEqual(body, { model: "databricks-claude-opus-4-8", messages: [] });
43
+ });
44
+
45
+ it("drops a field present with a falsy or null value", () => {
46
+ const body: Record<string, unknown> = { store: false, metadata: null };
47
+ assert.deepEqual(stripUnsupportedChatFields(body).sort(), ["metadata", "store"]);
48
+ assert.deepEqual(body, {});
49
+ });
50
+
51
+ it("leaves a supported body untouched and reports nothing dropped", () => {
52
+ const body: Record<string, unknown> = {
53
+ model: "m",
54
+ messages: [{ role: "user", content: "hi" }],
55
+ stream: true,
56
+ tools: [],
57
+ tool_choice: "auto",
58
+ temperature: 0.2,
59
+ max_tokens: 64,
60
+ };
61
+ const before = structuredClone(body);
62
+ assert.deepEqual(stripUnsupportedChatFields(body), []);
63
+ assert.deepEqual(body, before);
64
+ });
65
+
66
+ it("drops caller-supplied extra fields alongside the built-in list", () => {
67
+ const body: Record<string, unknown> = { store: true, future_field: 1, keep: 2 };
68
+ assert.deepEqual(stripUnsupportedChatFields(body, ["future_field"]), [
69
+ "store",
70
+ "future_field",
71
+ ]);
72
+ assert.deepEqual(body, { keep: 2 });
73
+ });
74
+
75
+ it("covers every name it advertises", () => {
76
+ const body = Object.fromEntries(UNSUPPORTED_CHAT_FIELDS.map((field) => [field, 1]));
77
+ assert.deepEqual(stripUnsupportedChatFields(body), [...UNSUPPORTED_CHAT_FIELDS]);
78
+ assert.deepEqual(body, {});
79
+ });
80
+ });
@@ -0,0 +1,242 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import type { ChatMessage } from "../src/openai-chat";
4
+ import {
5
+ chatToResponse,
6
+ createResponsesStreamTranslator,
7
+ readResponsesOutput,
8
+ responsesToChat,
9
+ } from "../src/openai-responses";
10
+
11
+ /** The `messages` a lowered Responses body produced, typed for assertions. */
12
+ function messagesOf(body: Record<string, unknown>): ChatMessage[] {
13
+ const { chat } = responsesToChat(body);
14
+ return chat.messages as ChatMessage[];
15
+ }
16
+
17
+ /** Event names, in order, from a block of SSE text. */
18
+ function eventNames(sse: string): string[] {
19
+ return sse
20
+ .split("\n")
21
+ .filter((line) => line.startsWith("event: "))
22
+ .map((line) => line.slice("event: ".length));
23
+ }
24
+
25
+ /** Parsed `data:` payloads from a block of SSE text. */
26
+ function eventData(sse: string): Record<string, unknown>[] {
27
+ return sse
28
+ .split("\n")
29
+ .filter((line) => line.startsWith("data: "))
30
+ .map((line) => JSON.parse(line.slice("data: ".length)) as Record<string, unknown>);
31
+ }
32
+
33
+ describe("responsesToChat", () => {
34
+ it("lowers instructions and message items into a chat transcript", () => {
35
+ const messages = messagesOf({
36
+ instructions: "be terse",
37
+ input: [{ type: "message", role: "user", content: [{ type: "input_text", text: "hi" }] }],
38
+ });
39
+ assert.deepEqual(messages, [
40
+ { role: "system", content: "be terse" },
41
+ { role: "user", content: "hi" },
42
+ ]);
43
+ });
44
+
45
+ it("maps the developer role to system (chat has no developer role)", () => {
46
+ const [first] = messagesOf({ input: [{ role: "developer", content: "policy" }] });
47
+ assert.equal(first?.role, "system");
48
+ });
49
+
50
+ it("re-attaches a prior function_call to an assistant turn", () => {
51
+ const [first] = messagesOf({
52
+ input: [{ type: "function_call", call_id: "c1", name: "lookup", arguments: '{"q":1}' }],
53
+ });
54
+ assert.equal(first?.role, "assistant");
55
+ assert.equal(first?.content, null);
56
+ assert.deepEqual(first?.tool_calls, [
57
+ { id: "c1", type: "function", function: { name: "lookup", arguments: '{"q":1}' } },
58
+ ]);
59
+ });
60
+
61
+ it("keys a function_call_output back to the call it answers", () => {
62
+ const [first] = messagesOf({
63
+ input: [{ type: "function_call_output", call_id: "c1", output: "42" }],
64
+ });
65
+ assert.deepEqual(first, { role: "tool", tool_call_id: "c1", content: "42" });
66
+ });
67
+
68
+ it("nests flat Responses function tools and drops built-in tool types", () => {
69
+ const { chat } = responsesToChat({
70
+ input: [],
71
+ tools: [
72
+ { type: "function", name: "lookup", description: "d", parameters: { type: "object" } },
73
+ { type: "local_shell" },
74
+ { type: "web_search" },
75
+ ],
76
+ tool_choice: "auto",
77
+ });
78
+ assert.deepEqual(chat.tools, [
79
+ {
80
+ type: "function",
81
+ function: { name: "lookup", description: "d", parameters: { type: "object" } },
82
+ },
83
+ ]);
84
+ assert.equal(chat.tool_choice, "auto");
85
+ });
86
+
87
+ it("never forwards parallel_tool_calls (Databricks rejects unknown fields)", () => {
88
+ const { chat } = responsesToChat({
89
+ input: [],
90
+ parallel_tool_calls: true,
91
+ tools: [{ type: "function", name: "lookup" }],
92
+ });
93
+ assert.ok(!("parallel_tool_calls" in chat));
94
+ });
95
+
96
+ it("reports the streaming flag", () => {
97
+ assert.equal(responsesToChat({ input: [] }).stream, false);
98
+ assert.equal(responsesToChat({ input: [], stream: true }).stream, true);
99
+ });
100
+ });
101
+
102
+ describe("chatToResponse", () => {
103
+ it("lifts assistant text, tool calls, and usage into a response object", () => {
104
+ const response = chatToResponse(
105
+ {
106
+ id: "chatcmpl-1",
107
+ created: 1700000000,
108
+ choices: [
109
+ {
110
+ message: {
111
+ content: "done",
112
+ tool_calls: [{ id: "c1", function: { name: "lookup", arguments: '{"q":1}' } }],
113
+ },
114
+ },
115
+ ],
116
+ usage: { prompt_tokens: 3, completion_tokens: 4, total_tokens: 7 },
117
+ },
118
+ "databricks-claude-opus-4-8",
119
+ ) as Record<string, unknown>;
120
+
121
+ assert.equal(response.id, "chatcmpl-1");
122
+ assert.equal(response.status, "completed");
123
+ assert.equal(response.model, "databricks-claude-opus-4-8");
124
+ assert.deepEqual(response.output, [
125
+ { type: "message", role: "assistant", content: [{ type: "output_text", text: "done" }] },
126
+ { type: "function_call", call_id: "c1", name: "lookup", arguments: '{"q":1}' },
127
+ ]);
128
+ assert.deepEqual(response.usage, { input_tokens: 3, output_tokens: 4, total_tokens: 7 });
129
+ });
130
+
131
+ it("omits the message item when the turn was tool calls only", () => {
132
+ const response = chatToResponse(
133
+ { choices: [{ message: { content: null, tool_calls: [] } }] },
134
+ "m",
135
+ ) as { output: unknown[] };
136
+ assert.deepEqual(response.output, []);
137
+ });
138
+ });
139
+
140
+ describe("createResponsesStreamTranslator", () => {
141
+ it("opens on the first chunk and closes the text run at finish", () => {
142
+ const translator = createResponsesStreamTranslator("m", "resp-1");
143
+ const first = translator.feed({ choices: [{ delta: { content: "he" } }] });
144
+ assert.deepEqual(eventNames(first), [
145
+ "response.created",
146
+ "response.output_item.added",
147
+ "response.output_text.delta",
148
+ ]);
149
+
150
+ const second = translator.feed({ choices: [{ delta: { content: "llo" } }] });
151
+ assert.deepEqual(eventNames(second), ["response.output_text.delta"]);
152
+
153
+ const done = translator.finish();
154
+ assert.deepEqual(eventNames(done), [
155
+ "response.output_text.done",
156
+ "response.output_item.done",
157
+ "response.completed",
158
+ ]);
159
+ // The buffered text is what the client renders as the final message.
160
+ assert.equal(eventData(done)[0]?.text, "hello");
161
+ });
162
+
163
+ it("assembles argument fragments into one function_call item", () => {
164
+ const translator = createResponsesStreamTranslator("m", "resp-1");
165
+ translator.feed({
166
+ choices: [
167
+ { delta: { tool_calls: [{ index: 0, id: "c1", function: { name: "lookup" } }] } },
168
+ ],
169
+ });
170
+ translator.feed({ choices: [{ delta: { tool_calls: [{ index: 0, function: { arguments: '{"q' } }] } }] });
171
+ translator.feed({ choices: [{ delta: { tool_calls: [{ index: 0, function: { arguments: '":1}' } }] } }] });
172
+
173
+ const done = translator.finish();
174
+ const [args] = eventData(done);
175
+ assert.equal(args?.arguments, '{"q":1}');
176
+ assert.ok(eventNames(done).includes("response.function_call_arguments.done"));
177
+ });
178
+
179
+ it("closes an open text run before opening a tool call so output stays ordered", () => {
180
+ const translator = createResponsesStreamTranslator("m", "resp-1");
181
+ translator.feed({ choices: [{ delta: { content: "thinking" } }] });
182
+ const withTool = translator.feed({
183
+ choices: [{ delta: { tool_calls: [{ index: 0, id: "c1", function: { name: "f" } }] } }],
184
+ });
185
+ assert.deepEqual(eventNames(withTool), [
186
+ "response.output_text.done",
187
+ "response.output_item.done",
188
+ "response.output_item.added",
189
+ ]);
190
+ });
191
+
192
+ it("emits nothing but the lifecycle for an empty chunk", () => {
193
+ const translator = createResponsesStreamTranslator("m", "resp-1");
194
+ assert.deepEqual(eventNames(translator.feed({})), ["response.created"]);
195
+ assert.deepEqual(eventNames(translator.finish()), ["response.completed"]);
196
+ });
197
+ });
198
+
199
+ describe("readResponsesOutput", () => {
200
+ it("prefers the flattened output_text", () => {
201
+ const { text } = readResponsesOutput({
202
+ output_text: " the answer ",
203
+ output: [{ content: [{ text: "ignored" }] }],
204
+ });
205
+ assert.equal(text, "the answer");
206
+ });
207
+
208
+ it("falls back to joining the output items", () => {
209
+ const { text } = readResponsesOutput({
210
+ output: [{ content: [{ text: "one" }, { text: "two" }] }],
211
+ });
212
+ assert.equal(text, "one\ntwo");
213
+ });
214
+
215
+ it("collects url_citation annotations, deduplicated by url", () => {
216
+ const { citations } = readResponsesOutput({
217
+ output: [
218
+ {
219
+ content: [
220
+ {
221
+ text: "answer",
222
+ annotations: [
223
+ { type: "url_citation", url: "https://a.example", title: "A" },
224
+ { type: "url_citation", url: "https://a.example", title: "A again" },
225
+ { type: "url_citation", url: "https://b.example" },
226
+ { type: "file_citation" },
227
+ ],
228
+ },
229
+ ],
230
+ },
231
+ ],
232
+ });
233
+ assert.deepEqual(citations, [
234
+ { url: "https://a.example", title: "A" },
235
+ { url: "https://b.example" },
236
+ ]);
237
+ });
238
+
239
+ it("returns empty results for a payload with no output", () => {
240
+ assert.deepEqual(readResponsesOutput({}), { text: "", citations: [] });
241
+ });
242
+ });
@@ -0,0 +1,14 @@
1
+ // ~~ Generated by projen. To modify, edit .projenrc.js and run "pnpm exec projen".
2
+ {
3
+ "extends": "../tsconfig.json",
4
+ "compilerOptions": {
5
+ "noEmit": true,
6
+ "rootDir": ".."
7
+ },
8
+ "include": [
9
+ "**/*.ts"
10
+ ],
11
+ "exclude": [
12
+ "node_modules"
13
+ ]
14
+ }