@dbx-tools/cli-model-proxy 0.3.27 → 0.3.29
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 -3
- package/package.json +4 -4
- package/src/server.ts +12 -9
package/README.md
CHANGED
|
@@ -135,9 +135,10 @@ Use this when tests or local developer tools need a managed proxy lifecycle.
|
|
|
135
135
|
`/serving-endpoints/responses`.
|
|
136
136
|
- Responses → `/serving-endpoints/responses` (OpenAI-family) or
|
|
137
137
|
`/serving-endpoints/open-responses` (Claude/Gemini/…). For Open
|
|
138
|
-
Responses the proxy strips non-`function` tools
|
|
139
|
-
`output_*` content parts to `input_
|
|
140
|
-
`
|
|
138
|
+
Responses the proxy strips non-`function` tools, rewrites prior-turn
|
|
139
|
+
`output_*` content parts to `input_*`, and drops Claude
|
|
140
|
+
`thinking` / `redacted_thinking` / `reasoning` blocks (replay of those
|
|
141
|
+
signed blobs fails with "Invalid `data` in `redacted_thinking`").
|
|
141
142
|
5. JSON or SSE response bodies are piped back (with a chat↔Responses
|
|
142
143
|
translation only when a chat client hit a Responses-only model).
|
|
143
144
|
|
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/
|
|
22
|
-
"@dbx-tools/shared-
|
|
23
|
-
"@dbx-tools/
|
|
21
|
+
"@dbx-tools/shared-core": "0.3.29",
|
|
22
|
+
"@dbx-tools/shared-model": "0.3.29",
|
|
23
|
+
"@dbx-tools/model": "0.3.29"
|
|
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.29",
|
|
31
31
|
"types": "index.ts",
|
|
32
32
|
"type": "module",
|
|
33
33
|
"exports": {
|
package/src/server.ts
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
34
|
import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http";
|
|
35
|
-
import { error, log } from "@dbx-tools/shared-core";
|
|
35
|
+
import { error, json, log } from "@dbx-tools/shared-core";
|
|
36
36
|
import { classify, openaiChat, openaiResponses } from "@dbx-tools/shared-model";
|
|
37
37
|
|
|
38
38
|
import type { DatabricksBackend } from "./backend";
|
|
@@ -222,7 +222,7 @@ async function handleProxy(
|
|
|
222
222
|
req: IncomingMessage,
|
|
223
223
|
res: ServerResponse,
|
|
224
224
|
): Promise<void> {
|
|
225
|
-
const body =
|
|
225
|
+
const body = await readJsonBody(req);
|
|
226
226
|
const requested = typeof body.model === "string" ? body.model : undefined;
|
|
227
227
|
if (!requested) {
|
|
228
228
|
sendJson(res, 400, errorBody("missing 'model' in request body", "invalid_request_error"));
|
|
@@ -337,8 +337,9 @@ async function proxyChatViaResponses(
|
|
|
337
337
|
* workspace-level). Streaming and non-streaming both pass through as-is.
|
|
338
338
|
*
|
|
339
339
|
* Open Responses (Claude/Gemini/…) only accepts `function` tools and
|
|
340
|
-
* `input_*` content part types,
|
|
341
|
-
*
|
|
340
|
+
* `input_*` content part types, and rejects replayed Claude thinking
|
|
341
|
+
* blocks — so Codex's built-in tools, prior-turn `output_text`, and
|
|
342
|
+
* `redacted_thinking` / `thinking` / `reasoning` parts are rewritten or
|
|
342
343
|
* stripped there. The OpenAI `/responses` path keeps them - GPT supports
|
|
343
344
|
* those shapes.
|
|
344
345
|
*/
|
|
@@ -347,7 +348,7 @@ async function handleResponses(
|
|
|
347
348
|
req: IncomingMessage,
|
|
348
349
|
res: ServerResponse,
|
|
349
350
|
): Promise<void> {
|
|
350
|
-
const body =
|
|
351
|
+
const body = await readJsonBody(req);
|
|
351
352
|
const requested = typeof body.model === "string" ? body.model : undefined;
|
|
352
353
|
if (!requested) {
|
|
353
354
|
sendJson(res, 400, errorBody("missing 'model' in request body", "invalid_request_error"));
|
|
@@ -423,14 +424,16 @@ function isAuthorized(req: IncomingMessage, apiKey: string): boolean {
|
|
|
423
424
|
return header.replace(/^Bearer\s+/i, "").trim() === apiKey;
|
|
424
425
|
}
|
|
425
426
|
|
|
426
|
-
/**
|
|
427
|
-
|
|
427
|
+
/**
|
|
428
|
+
* Drain a request body and parse it as a JSON object. An empty, malformed, or
|
|
429
|
+
* non-object body yields `{}`, which the callers reject as a missing `model`.
|
|
430
|
+
*/
|
|
431
|
+
async function readJsonBody(req: IncomingMessage): Promise<Record<string, unknown>> {
|
|
428
432
|
const chunks: Buffer[] = [];
|
|
429
433
|
for await (const chunk of req) {
|
|
430
434
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk as Uint8Array));
|
|
431
435
|
}
|
|
432
|
-
|
|
433
|
-
return raw ? JSON.parse(raw) : {};
|
|
436
|
+
return json.parseRecord(Buffer.concat(chunks).toString("utf8")) ?? {};
|
|
434
437
|
}
|
|
435
438
|
|
|
436
439
|
/** Serialize and send a JSON response. */
|