@dbx-tools/shared-model 0.9.4 → 0.9.6

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.
@@ -1,210 +0,0 @@
1
- /**
2
- * OpenAI Responses API <-> Chat Completions translation.
3
- *
4
- * Some clients speak only the Responses API (`POST /v1/responses`) - the Codex
5
- * CLI is the motivating one. Databricks now also exposes native Responses
6
- * surfaces (`/serving-endpoints/responses` and `/serving-endpoints/open-responses`),
7
- * while most endpoints still speak Chat Completions at `/invocations`. This
8
- * module bridges the two, in both directions:
9
- *
10
- * - {@link responsesToChat} lowers a Responses request body to a chat
11
- * completions body (instructions -> system message, typed `input` items ->
12
- * `messages`, `tools`/`tool_choice` carried through, function-call outputs
13
- * folded back into the transcript).
14
- * - {@link chatToResponsesRequest} raises a chat-completions request into a
15
- * Responses request (the inverse of {@link responsesToChat}), for routing a
16
- * chat client at a Responses-only model like Codex.
17
- * - {@link chatToResponse} lifts a non-streaming chat completion back into a
18
- * Responses `response` object.
19
- * - {@link responseToChatCompletion} lifts a native Responses `response`
20
- * back into a chat-completions body (the inverse of {@link chatToResponse}).
21
- * - {@link createResponsesStreamTranslator} lifts a streaming chat completion
22
- * (an OpenAI SSE `chat.completion.chunk` stream) into the Responses SSE
23
- * event stream those clients consume (`response.created`,
24
- * `response.output_text.delta`, function-call argument deltas,
25
- * `response.completed`).
26
- * - {@link readResponsesOutput} reads the other direction: pull the answer
27
- * text and citations out of a `response` object returned by an endpoint
28
- * that speaks Responses natively (the Databricks native web-search tool).
29
- * - {@link sanitizeResponsesTools} keeps only `function` tools on a Responses
30
- * request body (for `/open-responses` / Anthropic, which reject Codex
31
- * built-ins like `web_search`).
32
- * - {@link sanitizeOpenResponsesInput} rewrites `output_*` content part types
33
- * in `input` to `input_*`, and drops Claude thinking / reasoning blocks
34
- * that Open Responses rejects on replay (`redacted_thinking`, …).
35
- * - {@link repairTrailingAssistantInput} drops a trailing assistant turn that
36
- * Anthropic reads as a prefill request, the Responses-side counterpart to
37
- * `@dbx-tools/appkit-mastra`'s `repairAssistantPrefill`.
38
- *
39
- * Only the surface real clients exercise is translated; unknown fields are
40
- * ignored rather than rejected, so a newer client degrades instead of breaking.
41
- *
42
- * Browser-safe: pure functions over plain JSON, no transport and no Node
43
- * built-ins, so the same translation runs in a proxy, a server route, or a test.
44
- *
45
- * @module
46
- */
47
- /**
48
- * Lower a Responses request body to a chat-completions body. Returns the chat
49
- * body plus whether the caller asked for streaming (the server needs it to pick
50
- * the upstream `accept` header and the translation path).
51
- */
52
- export declare function responsesToChat(body: Record<string, unknown>): {
53
- chat: Record<string, unknown>;
54
- stream: boolean;
55
- };
56
- /**
57
- * Raise a chat-completions request into a Responses request body. Inverse of
58
- * {@link responsesToChat}: used when a chat client hits a Responses-only
59
- * Databricks model (e.g. Codex) so the proxy can POST to
60
- * `/serving-endpoints/responses` without the client knowing.
61
- */
62
- export declare function chatToResponsesRequest(body: Record<string, unknown>): {
63
- responses: Record<string, unknown>;
64
- stream: boolean;
65
- };
66
- /** Lift a non-streaming chat completion JSON into a Responses `response` object. */
67
- export declare function chatToResponse(chat: Record<string, unknown>, model: string): unknown;
68
- /**
69
- * Lift a native Responses `response` object into a chat-completions body.
70
- * Inverse of {@link chatToResponse}: used after a Responses-only upstream call
71
- * when the client spoke Chat Completions.
72
- */
73
- export declare function responseToChatCompletion(response: Record<string, unknown>, model: string): Record<string, unknown>;
74
- /**
75
- * Incremental chat-chunk -> Responses-SSE translator. `feed` and `finish` both
76
- * return the SSE bytes to forward, or `""` when a chunk produced no event.
77
- */
78
- export interface ResponsesStreamTranslator {
79
- /** Translate one upstream `chat.completion.chunk` object. */
80
- feed(chunk: Record<string, unknown>): string;
81
- /** Close any open items and emit `response.completed`. Call once, at end of stream. */
82
- finish(): string;
83
- }
84
- /**
85
- * Translate an upstream chat-completions SSE stream into the Responses SSE
86
- * event stream a Responses client consumes.
87
- *
88
- * Upstream chunks are `chat.completion.chunk` objects whose `choices[0].delta`
89
- * carries incremental `content` (assistant text) and/or `tool_calls` (function
90
- * calls, streamed by `index` with partial `arguments`). We emit the Responses
91
- * lifecycle around them:
92
- *
93
- * response.created
94
- * -> per text run: output_item.added → output_text.delta* → output_item.done
95
- * -> per tool call: output_item.added → function_call_arguments.delta*
96
- * → function_call_arguments.done → output_item.done
97
- * response.completed (with the assembled final `response` object)
98
- *
99
- * The translator is intentionally tolerant: malformed/keepalive lines yield
100
- * nothing.
101
- */
102
- export declare function createResponsesStreamTranslator(model: string, responseId: string): ResponsesStreamTranslator;
103
- /** A source the model cited, as carried by a Responses content-part annotation. */
104
- export interface ResponsesCitation {
105
- url: string;
106
- title?: string;
107
- }
108
- /** What {@link readResponsesOutput} pulls out of a `response` object. */
109
- export interface ResponsesOutput {
110
- /** The assistant's answer, with the output items concatenated. */
111
- text: string;
112
- /** Cited sources in first-seen order, deduplicated by URL. */
113
- citations: ResponsesCitation[];
114
- }
115
- /**
116
- * Read the answer text and cited sources out of a Responses `response` payload.
117
- *
118
- * This is the inverse of {@link chatToResponse}: it consumes what an endpoint
119
- * speaking Responses natively returns, rather than producing it. The Databricks
120
- * native web-search tool answers this way, with each source attached as a
121
- * `url_citation` annotation on the content part that used it.
122
- *
123
- * Prefers the flattened `output_text` when the payload carries it, and falls
124
- * back to walking `output[].content[].text`. Every field is optional upstream,
125
- * so a payload missing any of it yields empty results rather than throwing.
126
- */
127
- export declare function readResponsesOutput(payload: Record<string, unknown>): ResponsesOutput;
128
- /**
129
- * Strip tool types the upstream model doesn't support from a Responses request
130
- * body, returning a shallow copy safe to forward (the input is not mutated).
131
- *
132
- * Clients like the Codex CLI include built-in Responses tools (`web_search`,
133
- * `local_shell`, `custom`, ...) alongside their `function` tools. Databricks'
134
- * Open Responses surface for Anthropic/Claude (and other non-OpenAI providers)
135
- * only accepts `function` tools and hard-errors otherwise:
136
- * "Anthropic does not support tool type 'web_search'. Only 'function' is supported."
137
- * Call this before forwarding to `/serving-endpoints/open-responses`. The OpenAI
138
- * `/serving-endpoints/responses` path should keep built-ins (GPT supports them).
139
- * If filtering empties the list, `tools` / `tool_choice` / `parallel_tool_calls`
140
- * are dropped so we never send an empty `tools: []`.
141
- */
142
- export declare function sanitizeResponsesTools(body: Record<string, unknown>): Record<string, unknown>;
143
- /**
144
- * Content-part / input-item types Claude extended thinking uses on the wire.
145
- *
146
- * Shared so both wire surfaces strip the same set: the Responses path here
147
- * ({@link sanitizeOpenResponsesInput}) and the Chat Completions path in
148
- * `@dbx-tools/appkit-mastra`'s serving sanitize. Anthropic signs these blocks,
149
- * so a replay that mutates one is rejected outright - both paths must agree on
150
- * what counts as a reasoning block.
151
- */
152
- export declare const REASONING_TYPES: ReadonlySet<string>;
153
- /**
154
- * Rewrite Responses `input` so Open Responses will accept it.
155
- *
156
- * Two OpenAI / Codex shapes that Databricks Open Responses (Claude, Gemini, …)
157
- * reject:
158
- *
159
- * 1. Prior assistant turns with `output_text` / `output_*` content parts —
160
- * Open Responses only allows `input_text`, `input_image`, `input_file`,
161
- * `input_audio`. Map every `output_<kind>` part to `input_<kind>`.
162
- * 2. Replayed extended-thinking blocks (`thinking`, `redacted_thinking`,
163
- * `reasoning` content parts, and top-level `reasoning` input items). Claude
164
- * signs those; any client round-trip that mutates them (or a cross-provider
165
- * replay) fails with e.g.
166
- * "messages.N.content.M: Invalid `data` in `redacted_thinking` block"
167
- * Strip them — the UI/client already showed the thinking; replay does not
168
- * need the signed blob. Same policy as appkit-mastra's serving sanitize.
169
- *
170
- * Returns a shallow copy when anything changes; otherwise the input body.
171
- */
172
- export declare function sanitizeOpenResponsesInput(body: Record<string, unknown>): Record<string, unknown>;
173
- /**
174
- * Drop trailing assistant turns so the transcript ends on something Anthropic
175
- * will continue from.
176
- *
177
- * Databricks Open Responses rejects a body whose last item is an assistant
178
- * message with `"This model does not support assistant message prefill. The
179
- * conversation must end with a user message."` (the upstream Bedrock route
180
- * disallows prefill). Two ways a real client hits it:
181
- *
182
- * 1. The client replays its own last answer. The Codex CLI does this when a turn
183
- * ends without a tool call and the next request carries the full transcript.
184
- * 2. {@link sanitizeOpenResponsesInput} CREATES the shape: a turn that ended in a
185
- * `reasoning` item is stripped for replay compatibility, promoting the
186
- * assistant message before it to last. Running this repair after that strip
187
- * is what keeps one fix from causing the other failure.
188
- *
189
- * Dropping is correct rather than lossy: a trailing assistant turn carries text
190
- * the model itself just produced, so it is context the provider does not need
191
- * repeated in order to continue. Appending a synthetic `"Continue."` user turn
192
- * also satisfies the provider, but it puts words in the user's mouth that show
193
- * up in the model's context, so this takes the honest option.
194
- *
195
- * A trailing `function_call` is left ALONE. It is also an assistant-side item,
196
- * but Anthropic rejects an unanswered `tool_use` on a different rule
197
- * (`tool_use` ids without `tool_result`), and dropping it would silently discard
198
- * a tool call the client is about to answer. That is the client's bug to fix,
199
- * not something to paper over here.
200
- *
201
- * Returns a shallow copy when anything changes; otherwise the input body.
202
- */
203
- export declare function repairTrailingAssistantInput(body: Record<string, unknown>): Record<string, unknown>;
204
- /**
205
- * Full Open Responses request sanitizer: strip non-`function` tools, rewrite
206
- * `output_*` content parts, drop thinking / reasoning blocks, and drop a
207
- * trailing assistant turn the provider would read as a prefill. Safe no-op
208
- * when nothing needs changing.
209
- */
210
- export declare function sanitizeOpenResponsesRequest(body: Record<string, unknown>): Record<string, unknown>;