@dbx-tools/cli-model-proxy 0.3.25 → 0.3.27
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 +4 -2
- package/package.json +4 -4
- package/src/server.ts +30 -7
package/README.md
CHANGED
|
@@ -134,8 +134,10 @@ Use this when tests or local developer tools need a managed proxy lifecycle.
|
|
|
134
134
|
Responses-only models (Codex) which are translated and posted to
|
|
135
135
|
`/serving-endpoints/responses`.
|
|
136
136
|
- Responses → `/serving-endpoints/responses` (OpenAI-family) or
|
|
137
|
-
`/serving-endpoints/open-responses` (Claude/Gemini/…)
|
|
138
|
-
|
|
137
|
+
`/serving-endpoints/open-responses` (Claude/Gemini/…). For Open
|
|
138
|
+
Responses the proxy strips non-`function` tools and rewrites prior-turn
|
|
139
|
+
`output_*` content parts to `input_*` (Claude/Gemini reject
|
|
140
|
+
`output_text` in `input`).
|
|
139
141
|
5. JSON or SSE response bodies are piped back (with a chat↔Responses
|
|
140
142
|
translation only when a chat client hit a Responses-only model).
|
|
141
143
|
|
package/package.json
CHANGED
|
@@ -18,16 +18,16 @@
|
|
|
18
18
|
"@databricks/sdk-experimental": "^0.17.0",
|
|
19
19
|
"commander": "^15.0.0",
|
|
20
20
|
"tsx": "^4.23.0",
|
|
21
|
-
"@dbx-tools/model": "0.3.
|
|
22
|
-
"@dbx-tools/shared-
|
|
23
|
-
"@dbx-tools/shared-
|
|
21
|
+
"@dbx-tools/model": "0.3.27",
|
|
22
|
+
"@dbx-tools/shared-core": "0.3.27",
|
|
23
|
+
"@dbx-tools/shared-model": "0.3.27"
|
|
24
24
|
},
|
|
25
25
|
"main": "index.ts",
|
|
26
26
|
"license": "UNLICENSED",
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
|
-
"version": "0.3.
|
|
30
|
+
"version": "0.3.27",
|
|
31
31
|
"types": "index.ts",
|
|
32
32
|
"type": "module",
|
|
33
33
|
"exports": {
|
package/src/server.ts
CHANGED
|
@@ -38,7 +38,8 @@ import { classify, openaiChat, openaiResponses } from "@dbx-tools/shared-model";
|
|
|
38
38
|
import type { DatabricksBackend } from "./backend";
|
|
39
39
|
import { DEFAULT_BIND_HOST, DEFAULT_PORT } from "./defaults";
|
|
40
40
|
|
|
41
|
-
const { chatToResponsesRequest, responseToChatCompletion } =
|
|
41
|
+
const { chatToResponsesRequest, responseToChatCompletion, sanitizeOpenResponsesRequest } =
|
|
42
|
+
openaiResponses;
|
|
42
43
|
|
|
43
44
|
const logger = log.logger("model-proxy/server");
|
|
44
45
|
|
|
@@ -300,18 +301,23 @@ async function proxyChatViaResponses(
|
|
|
300
301
|
headers["content-type"] = "application/json";
|
|
301
302
|
headers.accept = "application/json";
|
|
302
303
|
|
|
304
|
+
const upstreamUrl = backend.responsesUrl(modelId);
|
|
305
|
+
const forward = upstreamUrl.includes("/open-responses")
|
|
306
|
+
? sanitizeOpenResponsesRequest(responses)
|
|
307
|
+
: responses;
|
|
308
|
+
|
|
303
309
|
logger.info("proxy", {
|
|
304
310
|
requested,
|
|
305
311
|
resolved: modelId,
|
|
306
312
|
matched,
|
|
307
|
-
upstream:
|
|
313
|
+
upstream: upstreamUrl,
|
|
308
314
|
stream: false,
|
|
309
315
|
});
|
|
310
316
|
|
|
311
|
-
const upstream = await fetch(
|
|
317
|
+
const upstream = await fetch(upstreamUrl, {
|
|
312
318
|
method: "POST",
|
|
313
319
|
headers,
|
|
314
|
-
body: JSON.stringify(
|
|
320
|
+
body: JSON.stringify(forward),
|
|
315
321
|
});
|
|
316
322
|
|
|
317
323
|
if (!upstream.ok) {
|
|
@@ -329,6 +335,12 @@ async function proxyChatViaResponses(
|
|
|
329
335
|
* `POST /v1/responses`: forward the Responses body to Databricks' native
|
|
330
336
|
* Responses / Open Responses surface (model stays in the body; URL is
|
|
331
337
|
* workspace-level). Streaming and non-streaming both pass through as-is.
|
|
338
|
+
*
|
|
339
|
+
* Open Responses (Claude/Gemini/…) only accepts `function` tools and
|
|
340
|
+
* `input_*` content part types, so Codex's built-in `web_search` /
|
|
341
|
+
* `local_shell` / … and prior-turn `output_text` parts are rewritten/
|
|
342
|
+
* stripped there. The OpenAI `/responses` path keeps them - GPT supports
|
|
343
|
+
* those shapes.
|
|
332
344
|
*/
|
|
333
345
|
async function handleResponses(
|
|
334
346
|
backend: DatabricksBackend,
|
|
@@ -345,24 +357,35 @@ async function handleResponses(
|
|
|
345
357
|
const resolved = await backend.resolve(requested);
|
|
346
358
|
body.model = resolved.modelId;
|
|
347
359
|
|
|
348
|
-
const
|
|
360
|
+
const upstreamUrl = backend.responsesUrl(resolved.modelId);
|
|
361
|
+
// Cross-provider Open Responses rejects non-function tools and `output_*`
|
|
362
|
+
// content parts in `input`; OpenAI `/responses` keeps Codex's native shapes.
|
|
363
|
+
const forward = upstreamUrl.includes("/open-responses")
|
|
364
|
+
? sanitizeOpenResponsesRequest(body)
|
|
365
|
+
: body;
|
|
366
|
+
|
|
367
|
+
const wantsStream = forward.stream === true;
|
|
349
368
|
const headers = await backend.authHeaders();
|
|
350
369
|
headers["content-type"] = "application/json";
|
|
351
370
|
headers.accept = wantsStream ? "text/event-stream" : "application/json";
|
|
352
371
|
|
|
353
|
-
const
|
|
372
|
+
const stripped =
|
|
373
|
+
Array.isArray(body.tools) &&
|
|
374
|
+
(!Array.isArray(forward.tools) || forward.tools.length !== body.tools.length);
|
|
375
|
+
|
|
354
376
|
logger.info("responses", {
|
|
355
377
|
requested,
|
|
356
378
|
resolved: resolved.modelId,
|
|
357
379
|
matched: resolved.matched,
|
|
358
380
|
upstream: upstreamUrl,
|
|
359
381
|
stream: wantsStream,
|
|
382
|
+
...(stripped ? { strippedNonFunctionTools: true } : {}),
|
|
360
383
|
});
|
|
361
384
|
|
|
362
385
|
const upstream = await fetch(upstreamUrl, {
|
|
363
386
|
method: "POST",
|
|
364
387
|
headers,
|
|
365
|
-
body: JSON.stringify(
|
|
388
|
+
body: JSON.stringify(forward),
|
|
366
389
|
});
|
|
367
390
|
|
|
368
391
|
res.writeHead(upstream.status, {
|