@copilotkit/aimock 1.15.0 → 1.15.1
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/CHANGELOG.md +26 -16
- package/dist/bedrock-converse.cjs +133 -25
- package/dist/bedrock-converse.cjs.map +1 -1
- package/dist/bedrock-converse.d.cts.map +1 -1
- package/dist/bedrock-converse.d.ts.map +1 -1
- package/dist/bedrock-converse.js +135 -27
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +262 -48
- package/dist/bedrock.cjs.map +1 -1
- package/dist/bedrock.d.cts.map +1 -1
- package/dist/bedrock.d.ts.map +1 -1
- package/dist/bedrock.js +263 -50
- package/dist/bedrock.js.map +1 -1
- package/dist/chaos.cjs +9 -35
- package/dist/chaos.cjs.map +1 -1
- package/dist/chaos.d.cts +2 -17
- package/dist/chaos.d.cts.map +1 -1
- package/dist/chaos.d.ts +2 -17
- package/dist/chaos.d.ts.map +1 -1
- package/dist/chaos.js +10 -35
- package/dist/chaos.js.map +1 -1
- package/dist/cohere.cjs +289 -33
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.d.cts +9 -0
- package/dist/cohere.d.cts.map +1 -1
- package/dist/cohere.d.ts +9 -0
- package/dist/cohere.d.ts.map +1 -1
- package/dist/cohere.js +290 -34
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/embeddings.cjs +22 -4
- package/dist/embeddings.cjs.map +1 -1
- package/dist/embeddings.d.cts +2 -2
- package/dist/embeddings.d.cts.map +1 -1
- package/dist/embeddings.d.ts +2 -2
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/embeddings.js +22 -4
- package/dist/embeddings.js.map +1 -1
- package/dist/gemini.cjs +48 -45
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.d.cts.map +1 -1
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +48 -45
- package/dist/gemini.js.map +1 -1
- package/dist/helpers.cjs +9 -0
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +9 -0
- package/dist/helpers.js.map +1 -1
- package/dist/images.cjs +21 -3
- package/dist/images.cjs.map +1 -1
- package/dist/images.js +21 -3
- package/dist/images.js.map +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/jest.cjs +10 -3
- package/dist/jest.cjs.map +1 -1
- package/dist/jest.js +10 -3
- package/dist/jest.js.map +1 -1
- package/dist/journal.cjs +1 -1
- package/dist/journal.cjs.map +1 -1
- package/dist/journal.d.cts.map +1 -1
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +1 -1
- package/dist/journal.js.map +1 -1
- package/dist/messages.cjs +5 -4
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.js +5 -4
- package/dist/messages.js.map +1 -1
- package/dist/ollama.cjs +129 -8
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.d.cts.map +1 -1
- package/dist/ollama.d.ts.map +1 -1
- package/dist/ollama.js +130 -9
- package/dist/ollama.js.map +1 -1
- package/dist/recorder.cjs +234 -69
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.d.cts +5 -50
- package/dist/recorder.d.cts.map +1 -1
- package/dist/recorder.d.ts +5 -50
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +234 -69
- package/dist/recorder.js.map +1 -1
- package/dist/responses.cjs +12 -3
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts +2 -1
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts +2 -1
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +12 -4
- package/dist/responses.js.map +1 -1
- package/dist/router.cjs +13 -6
- package/dist/router.cjs.map +1 -1
- package/dist/router.js +13 -6
- package/dist/router.js.map +1 -1
- package/dist/server.cjs +150 -94
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +152 -96
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +21 -3
- package/dist/speech.cjs.map +1 -1
- package/dist/speech.js +21 -3
- package/dist/speech.js.map +1 -1
- package/dist/transcription.cjs +10 -6
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.d.cts.map +1 -1
- package/dist/transcription.d.ts.map +1 -1
- package/dist/transcription.js +10 -6
- package/dist/transcription.js.map +1 -1
- package/dist/types.d.cts +1 -16
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +1 -16
- package/dist/types.d.ts.map +1 -1
- package/dist/video.cjs +66 -10
- package/dist/video.cjs.map +1 -1
- package/dist/video.d.cts +16 -3
- package/dist/video.d.cts.map +1 -1
- package/dist/video.d.ts +16 -3
- package/dist/video.d.ts.map +1 -1
- package/dist/video.js +66 -11
- package/dist/video.js.map +1 -1
- package/dist/vitest.cjs +10 -3
- package/dist/vitest.cjs.map +1 -1
- package/dist/vitest.js +10 -3
- package/dist/vitest.js.map +1 -1
- package/package.json +1 -1
package/dist/recorder.cjs
CHANGED
|
@@ -34,14 +34,17 @@ const STRIP_HEADERS = new Set([
|
|
|
34
34
|
* Proxy an unmatched request to the real upstream provider, record the
|
|
35
35
|
* response as a fixture on disk and in memory, then relay the response
|
|
36
36
|
* back to the original client.
|
|
37
|
+
*
|
|
38
|
+
* Returns `true` if the request was proxied (provider configured),
|
|
39
|
+
* `false` if no upstream URL is configured for the given provider key.
|
|
37
40
|
*/
|
|
38
|
-
async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures, defaults, rawBody
|
|
41
|
+
async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures, defaults, rawBody) {
|
|
39
42
|
const record = defaults.record;
|
|
40
|
-
if (!record) return
|
|
43
|
+
if (!record) return false;
|
|
41
44
|
const upstreamUrl = record.providers[providerKey];
|
|
42
45
|
if (!upstreamUrl) {
|
|
43
46
|
defaults.logger.warn(`No upstream URL configured for provider "${providerKey}" — cannot proxy`);
|
|
44
|
-
return
|
|
47
|
+
return false;
|
|
45
48
|
}
|
|
46
49
|
const fixturePath = record.fixturePath ?? "./fixtures/recorded";
|
|
47
50
|
let target;
|
|
@@ -53,7 +56,7 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
|
|
|
53
56
|
message: `Invalid upstream URL: ${upstreamUrl}`,
|
|
54
57
|
type: "proxy_error"
|
|
55
58
|
} }));
|
|
56
|
-
return
|
|
59
|
+
return true;
|
|
57
60
|
}
|
|
58
61
|
defaults.logger.warn(`NO FIXTURE MATCH — proxying to ${upstreamUrl}${pathname}`);
|
|
59
62
|
const forwardHeaders = {};
|
|
@@ -64,6 +67,7 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
|
|
|
64
67
|
let upstreamBody;
|
|
65
68
|
let rawBuffer;
|
|
66
69
|
let streamedToClient = false;
|
|
70
|
+
let clientDisconnected = false;
|
|
67
71
|
try {
|
|
68
72
|
const result = await makeUpstreamRequest(target, forwardHeaders, requestBody, res);
|
|
69
73
|
upstreamStatus = result.status;
|
|
@@ -71,15 +75,18 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
|
|
|
71
75
|
upstreamBody = result.body;
|
|
72
76
|
rawBuffer = result.rawBuffer;
|
|
73
77
|
streamedToClient = result.streamedToClient;
|
|
78
|
+
clientDisconnected = result.clientDisconnected;
|
|
74
79
|
} catch (err) {
|
|
75
80
|
const msg = err instanceof Error ? err.message : "Unknown proxy error";
|
|
76
81
|
defaults.logger.error(`Proxy request failed: ${msg}`);
|
|
77
|
-
res.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
if (!res.headersSent) {
|
|
83
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
84
|
+
res.end(JSON.stringify({ error: {
|
|
85
|
+
message: `Proxy to upstream failed: ${msg}`,
|
|
86
|
+
type: "proxy_error"
|
|
87
|
+
} }));
|
|
88
|
+
} else res.end();
|
|
89
|
+
return true;
|
|
83
90
|
}
|
|
84
91
|
const contentType = upstreamHeaders["content-type"];
|
|
85
92
|
const ctString = Array.isArray(contentType) ? contentType.join(", ") : contentType ?? "";
|
|
@@ -97,10 +104,20 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
|
|
|
97
104
|
if (collapsed.truncated) defaults.logger.warn("Bedrock EventStream: CRC mismatch — response may be truncated");
|
|
98
105
|
if (collapsed.droppedChunks && collapsed.droppedChunks > 0) defaults.logger.warn(`${collapsed.droppedChunks} chunk(s) dropped during stream collapse`);
|
|
99
106
|
if (collapsed.content === "" && (!collapsed.toolCalls || collapsed.toolCalls.length === 0)) defaults.logger.warn("Stream collapse produced empty content — fixture may be incomplete");
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
107
|
+
const reasoningSpread = collapsed.reasoning ? { reasoning: collapsed.reasoning } : {};
|
|
108
|
+
if (collapsed.toolCalls && collapsed.toolCalls.length > 0) if (collapsed.content) fixtureResponse = {
|
|
109
|
+
content: collapsed.content,
|
|
110
|
+
toolCalls: collapsed.toolCalls,
|
|
111
|
+
...reasoningSpread
|
|
112
|
+
};
|
|
113
|
+
else fixtureResponse = {
|
|
114
|
+
toolCalls: collapsed.toolCalls,
|
|
115
|
+
...reasoningSpread
|
|
116
|
+
};
|
|
117
|
+
else fixtureResponse = {
|
|
118
|
+
content: collapsed.content ?? "",
|
|
119
|
+
...reasoningSpread
|
|
120
|
+
};
|
|
104
121
|
} else {
|
|
105
122
|
let parsedResponse = null;
|
|
106
123
|
try {
|
|
@@ -111,9 +128,15 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
|
|
|
111
128
|
let encodingFormat;
|
|
112
129
|
try {
|
|
113
130
|
encodingFormat = rawBody ? JSON.parse(rawBody).encoding_format : void 0;
|
|
114
|
-
} catch {
|
|
131
|
+
} catch (err) {
|
|
132
|
+
defaults.logger.debug(`Could not parse encoding_format from raw body: ${err instanceof Error ? err.message : "unknown error"}`);
|
|
133
|
+
}
|
|
115
134
|
fixtureResponse = buildFixtureResponse(parsedResponse, upstreamStatus, encodingFormat);
|
|
116
135
|
}
|
|
136
|
+
if (clientDisconnected) {
|
|
137
|
+
defaults.logger.warn("Client disconnected mid-stream — skipping fixture save to avoid truncated data");
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
117
140
|
const fixtureMatch = buildFixtureMatch(defaults.requestTransform ? defaults.requestTransform(request) : request);
|
|
118
141
|
const fixture = {
|
|
119
142
|
match: fixtureMatch,
|
|
@@ -138,29 +161,22 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
|
|
|
138
161
|
} catch (err) {
|
|
139
162
|
const msg = err instanceof Error ? err.message : "Unknown filesystem error";
|
|
140
163
|
defaults.logger.error(`Failed to save fixture to disk: ${msg}`);
|
|
141
|
-
res.setHeader("X-LLMock-Record-Error", msg);
|
|
164
|
+
if (!res.headersSent) res.setHeader("X-LLMock-Record-Error", msg);
|
|
165
|
+
else defaults.logger.warn(`Cannot set X-LLMock-Record-Error header — headers already sent`);
|
|
142
166
|
}
|
|
143
167
|
if (writtenToDisk) {
|
|
144
168
|
if (!isEmptyMatch) fixtures.push(fixture);
|
|
145
169
|
defaults.logger.warn(`Response recorded → ${filepath}`);
|
|
146
170
|
} else defaults.logger.warn(`Response relayed but NOT saved to disk — see error above`);
|
|
147
171
|
} else defaults.logger.info(`Proxied ${providerKey} request (proxy-only mode)`);
|
|
148
|
-
if (streamedToClient) {
|
|
149
|
-
if (options?.beforeWriteResponse && options.onHookBypassed) options.onHookBypassed("sse_streamed");
|
|
150
|
-
} else {
|
|
151
|
-
if (options?.beforeWriteResponse) {
|
|
152
|
-
if (await options.beforeWriteResponse({
|
|
153
|
-
status: upstreamStatus,
|
|
154
|
-
contentType: ctString,
|
|
155
|
-
body: rawBuffer
|
|
156
|
-
})) return "handled_by_hook";
|
|
157
|
-
}
|
|
172
|
+
if (!streamedToClient) {
|
|
158
173
|
const relayHeaders = {};
|
|
159
174
|
if (ctString) relayHeaders["Content-Type"] = ctString;
|
|
160
175
|
res.writeHead(upstreamStatus, relayHeaders);
|
|
161
|
-
|
|
176
|
+
const isAudioRelay = ctString.toLowerCase().startsWith("audio/");
|
|
177
|
+
res.end(isBinaryStream || isAudioRelay ? rawBuffer : upstreamBody);
|
|
162
178
|
}
|
|
163
|
-
return
|
|
179
|
+
return true;
|
|
164
180
|
}
|
|
165
181
|
function makeUpstreamRequest(target, headers, body, clientRes) {
|
|
166
182
|
return new Promise((resolve, reject) => {
|
|
@@ -182,28 +198,34 @@ function makeUpstreamRequest(target, headers, body, clientRes) {
|
|
|
182
198
|
const ctStr = Array.isArray(ct) ? ct.join(", ") : ct ?? "";
|
|
183
199
|
const isSSE = ctStr.toLowerCase().includes("text/event-stream");
|
|
184
200
|
let streamedToClient = false;
|
|
201
|
+
let clientDisconnected = false;
|
|
185
202
|
if (isSSE && clientRes && !clientRes.headersSent) {
|
|
186
203
|
const relayHeaders = {};
|
|
187
204
|
if (ctStr) relayHeaders["Content-Type"] = ctStr;
|
|
188
205
|
clientRes.writeHead(res.statusCode ?? 200, relayHeaders);
|
|
189
206
|
if (typeof clientRes.flushHeaders === "function") clientRes.flushHeaders();
|
|
190
207
|
streamedToClient = true;
|
|
208
|
+
clientRes.on("close", () => {
|
|
209
|
+
clientDisconnected = true;
|
|
210
|
+
req.destroy();
|
|
211
|
+
});
|
|
191
212
|
}
|
|
192
213
|
const chunks = [];
|
|
193
214
|
res.on("data", (chunk) => {
|
|
194
215
|
chunks.push(chunk);
|
|
195
|
-
if (streamedToClient) clientRes.write(chunk);
|
|
216
|
+
if (streamedToClient && clientRes && !clientDisconnected && !clientRes.destroyed && !clientRes.writableEnded) clientRes.write(chunk);
|
|
196
217
|
});
|
|
197
218
|
res.on("error", reject);
|
|
198
219
|
res.on("end", () => {
|
|
199
220
|
const rawBuffer = Buffer.concat(chunks);
|
|
200
|
-
if (streamedToClient) clientRes.end();
|
|
221
|
+
if (streamedToClient && clientRes && !clientDisconnected && !clientRes.destroyed && !clientRes.writableEnded) clientRes.end();
|
|
201
222
|
resolve({
|
|
202
223
|
status: res.statusCode ?? 500,
|
|
203
224
|
headers: res.headers,
|
|
204
225
|
body: rawBuffer.toString(),
|
|
205
226
|
rawBuffer,
|
|
206
|
-
streamedToClient
|
|
227
|
+
streamedToClient,
|
|
228
|
+
clientDisconnected
|
|
207
229
|
});
|
|
208
230
|
});
|
|
209
231
|
});
|
|
@@ -228,7 +250,7 @@ function buildFixtureResponse(parsed, status, encodingFormat) {
|
|
|
228
250
|
status
|
|
229
251
|
};
|
|
230
252
|
const obj = parsed;
|
|
231
|
-
if (obj.error) {
|
|
253
|
+
if (typeof obj.error === "object" && obj.error !== null && typeof obj.error.message === "string") {
|
|
232
254
|
const err = obj.error;
|
|
233
255
|
return {
|
|
234
256
|
error: {
|
|
@@ -242,11 +264,12 @@ function buildFixtureResponse(parsed, status, encodingFormat) {
|
|
|
242
264
|
if (Array.isArray(obj.data) && obj.data.length > 0) {
|
|
243
265
|
const first = obj.data[0];
|
|
244
266
|
if (Array.isArray(first.embedding)) return { embedding: first.embedding };
|
|
245
|
-
if (typeof first.embedding === "string" && encodingFormat === "base64")
|
|
267
|
+
if (typeof first.embedding === "string" && encodingFormat === "base64") {
|
|
246
268
|
const buf = Buffer.from(first.embedding, "base64");
|
|
247
|
-
const
|
|
269
|
+
const aligned = new Uint8Array(buf).buffer;
|
|
270
|
+
const floats = new Float32Array(aligned, 0, buf.byteLength / 4);
|
|
248
271
|
return { embedding: Array.from(floats) };
|
|
249
|
-
}
|
|
272
|
+
}
|
|
250
273
|
if (first.url || first.b64_json) {
|
|
251
274
|
const images = obj.data.map((item) => ({
|
|
252
275
|
...item.url ? { url: String(item.url) } : {},
|
|
@@ -272,7 +295,7 @@ function buildFixtureResponse(parsed, status, encodingFormat) {
|
|
|
272
295
|
...Array.isArray(obj.words) ? { words: obj.words } : {},
|
|
273
296
|
...Array.isArray(obj.segments) ? { segments: obj.segments } : {}
|
|
274
297
|
} };
|
|
275
|
-
if (typeof obj.id === "string" && typeof obj.status === "string" && (obj.status === "completed" || obj.status === "in_progress" || obj.status === "failed")) {
|
|
298
|
+
if (typeof obj.id === "string" && typeof obj.status === "string" && (obj.status === "completed" || obj.status === "in_progress" || obj.status === "failed") && !("choices" in obj) && !("content" in obj) && !("candidates" in obj) && !("message" in obj) && !("data" in obj) && !("object" in obj)) {
|
|
276
299
|
if (obj.status === "completed" && obj.url) return { video: {
|
|
277
300
|
id: String(obj.id),
|
|
278
301
|
status: "completed",
|
|
@@ -287,40 +310,109 @@ function buildFixtureResponse(parsed, status, encodingFormat) {
|
|
|
287
310
|
if (Array.isArray(obj.choices) && obj.choices.length > 0) {
|
|
288
311
|
const message = obj.choices[0].message;
|
|
289
312
|
if (message) {
|
|
290
|
-
|
|
291
|
-
|
|
313
|
+
const hasToolCalls = Array.isArray(message.tool_calls) && message.tool_calls.length > 0;
|
|
314
|
+
const hasContent = typeof message.content === "string" && message.content.length > 0;
|
|
315
|
+
const openaiReasoning = typeof message.reasoning_content === "string" && message.reasoning_content.length > 0 ? message.reasoning_content : void 0;
|
|
316
|
+
if (hasToolCalls) {
|
|
317
|
+
const toolCalls = message.tool_calls.map((tc) => {
|
|
318
|
+
const fn = tc.function;
|
|
319
|
+
return {
|
|
320
|
+
name: String(fn.name),
|
|
321
|
+
arguments: String(fn.arguments),
|
|
322
|
+
...tc.id ? { id: String(tc.id) } : {}
|
|
323
|
+
};
|
|
324
|
+
});
|
|
325
|
+
if (hasContent) return {
|
|
326
|
+
content: message.content,
|
|
327
|
+
toolCalls,
|
|
328
|
+
...openaiReasoning ? { reasoning: openaiReasoning } : {}
|
|
329
|
+
};
|
|
292
330
|
return {
|
|
293
|
-
|
|
294
|
-
|
|
331
|
+
toolCalls,
|
|
332
|
+
...openaiReasoning ? { reasoning: openaiReasoning } : {}
|
|
295
333
|
};
|
|
296
|
-
}
|
|
297
|
-
if (
|
|
334
|
+
}
|
|
335
|
+
if (hasContent) return {
|
|
336
|
+
content: message.content,
|
|
337
|
+
...openaiReasoning ? { reasoning: openaiReasoning } : {}
|
|
338
|
+
};
|
|
339
|
+
return {
|
|
340
|
+
content: "",
|
|
341
|
+
...openaiReasoning ? { reasoning: openaiReasoning } : {}
|
|
342
|
+
};
|
|
298
343
|
}
|
|
299
344
|
}
|
|
300
345
|
if (Array.isArray(obj.content) && obj.content.length > 0) {
|
|
301
346
|
const blocks = obj.content;
|
|
302
347
|
const toolUseBlocks = blocks.filter((b) => b.type === "tool_use");
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const
|
|
308
|
-
|
|
348
|
+
const textBlocks = blocks.filter((b) => b.type === "text" && typeof b.text === "string");
|
|
349
|
+
const thinkingBlocks = blocks.filter((b) => b.type === "thinking");
|
|
350
|
+
const hasToolCalls = toolUseBlocks.length > 0;
|
|
351
|
+
const joinedText = textBlocks.map((b) => String(b.text ?? "")).join("");
|
|
352
|
+
const hasContent = joinedText.length > 0;
|
|
353
|
+
const anthropicReasoning = thinkingBlocks.length > 0 ? thinkingBlocks.map((b) => String(b.thinking ?? "")).join("") : void 0;
|
|
354
|
+
if (hasToolCalls) {
|
|
355
|
+
const toolCalls = toolUseBlocks.map((b) => ({
|
|
356
|
+
name: String(b.name),
|
|
357
|
+
arguments: typeof b.input === "string" ? b.input : JSON.stringify(b.input),
|
|
358
|
+
...b.id ? { id: String(b.id) } : {}
|
|
359
|
+
}));
|
|
360
|
+
if (hasContent) return {
|
|
361
|
+
content: joinedText,
|
|
362
|
+
toolCalls,
|
|
363
|
+
...anthropicReasoning ? { reasoning: anthropicReasoning } : {}
|
|
364
|
+
};
|
|
365
|
+
return {
|
|
366
|
+
toolCalls,
|
|
367
|
+
...anthropicReasoning ? { reasoning: anthropicReasoning } : {}
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
if (hasContent) return {
|
|
371
|
+
content: joinedText,
|
|
372
|
+
...anthropicReasoning ? { reasoning: anthropicReasoning } : {}
|
|
373
|
+
};
|
|
374
|
+
if (anthropicReasoning) return {
|
|
375
|
+
content: "",
|
|
376
|
+
reasoning: anthropicReasoning
|
|
377
|
+
};
|
|
309
378
|
}
|
|
310
379
|
if (Array.isArray(obj.candidates) && obj.candidates.length > 0) {
|
|
311
380
|
const content = obj.candidates[0].content;
|
|
312
381
|
if (content && Array.isArray(content.parts)) {
|
|
313
382
|
const parts = content.parts;
|
|
314
383
|
const fnCallParts = parts.filter((p) => p.functionCall);
|
|
315
|
-
|
|
316
|
-
|
|
384
|
+
const textParts = parts.filter((p) => typeof p.text === "string" && !p.thought);
|
|
385
|
+
const thoughtParts = parts.filter((p) => p.thought === true && typeof p.text === "string");
|
|
386
|
+
const hasToolCalls = fnCallParts.length > 0;
|
|
387
|
+
const joinedText = textParts.map((p) => String(p.text ?? "")).join("");
|
|
388
|
+
const hasContent = joinedText.length > 0;
|
|
389
|
+
const geminiReasoning = thoughtParts.length > 0 ? thoughtParts.map((p) => String(p.text ?? "")).join("") : void 0;
|
|
390
|
+
if (hasToolCalls) {
|
|
391
|
+
const toolCalls = fnCallParts.map((p) => {
|
|
392
|
+
const fc = p.functionCall;
|
|
393
|
+
return {
|
|
394
|
+
name: String(fc.name),
|
|
395
|
+
arguments: typeof fc.args === "string" ? fc.args : JSON.stringify(fc.args)
|
|
396
|
+
};
|
|
397
|
+
});
|
|
398
|
+
if (hasContent) return {
|
|
399
|
+
content: joinedText,
|
|
400
|
+
toolCalls,
|
|
401
|
+
...geminiReasoning ? { reasoning: geminiReasoning } : {}
|
|
402
|
+
};
|
|
317
403
|
return {
|
|
318
|
-
|
|
319
|
-
|
|
404
|
+
toolCalls,
|
|
405
|
+
...geminiReasoning ? { reasoning: geminiReasoning } : {}
|
|
320
406
|
};
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
|
|
407
|
+
}
|
|
408
|
+
if (hasContent) return {
|
|
409
|
+
content: joinedText,
|
|
410
|
+
...geminiReasoning ? { reasoning: geminiReasoning } : {}
|
|
411
|
+
};
|
|
412
|
+
return {
|
|
413
|
+
content: "",
|
|
414
|
+
...geminiReasoning ? { reasoning: geminiReasoning } : {}
|
|
415
|
+
};
|
|
324
416
|
}
|
|
325
417
|
}
|
|
326
418
|
if (obj.output && typeof obj.output === "object") {
|
|
@@ -328,32 +420,105 @@ function buildFixtureResponse(parsed, status, encodingFormat) {
|
|
|
328
420
|
if (msg && Array.isArray(msg.content)) {
|
|
329
421
|
const blocks = msg.content;
|
|
330
422
|
const toolUseBlocks = blocks.filter((b) => b.toolUse);
|
|
331
|
-
|
|
332
|
-
|
|
423
|
+
const textBlocks = blocks.filter((b) => typeof b.text === "string");
|
|
424
|
+
const reasoningBlocks = blocks.filter((b) => b.reasoningContent);
|
|
425
|
+
const hasToolCalls = toolUseBlocks.length > 0;
|
|
426
|
+
const joinedText = textBlocks.map((b) => String(b.text ?? "")).join("");
|
|
427
|
+
const hasContent = joinedText.length > 0;
|
|
428
|
+
const bedrockReasoning = reasoningBlocks.length > 0 ? reasoningBlocks.map((b) => {
|
|
429
|
+
const rt = b.reasoningContent?.reasoningText;
|
|
430
|
+
return String(rt?.text ?? "");
|
|
431
|
+
}).join("") : void 0;
|
|
432
|
+
if (hasToolCalls) {
|
|
433
|
+
const toolCalls = toolUseBlocks.map((b) => {
|
|
434
|
+
const tu = b.toolUse;
|
|
435
|
+
return {
|
|
436
|
+
name: String(tu.name ?? ""),
|
|
437
|
+
arguments: typeof tu.input === "string" ? tu.input : JSON.stringify(tu.input),
|
|
438
|
+
...tu.toolUseId ? { id: String(tu.toolUseId) } : {}
|
|
439
|
+
};
|
|
440
|
+
});
|
|
441
|
+
if (hasContent) return {
|
|
442
|
+
content: joinedText,
|
|
443
|
+
toolCalls,
|
|
444
|
+
...bedrockReasoning ? { reasoning: bedrockReasoning } : {}
|
|
445
|
+
};
|
|
333
446
|
return {
|
|
334
|
-
|
|
335
|
-
|
|
447
|
+
toolCalls,
|
|
448
|
+
...bedrockReasoning ? { reasoning: bedrockReasoning } : {}
|
|
336
449
|
};
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
|
|
450
|
+
}
|
|
451
|
+
if (hasContent) return {
|
|
452
|
+
content: joinedText,
|
|
453
|
+
...bedrockReasoning ? { reasoning: bedrockReasoning } : {}
|
|
454
|
+
};
|
|
455
|
+
return {
|
|
456
|
+
content: "",
|
|
457
|
+
...bedrockReasoning ? { reasoning: bedrockReasoning } : {}
|
|
458
|
+
};
|
|
340
459
|
}
|
|
341
460
|
}
|
|
461
|
+
if (typeof obj.finish_reason === "string" && obj.message && typeof obj.message === "object" && Array.isArray(obj.message.content)) {
|
|
462
|
+
const msg = obj.message;
|
|
463
|
+
const contentBlocks = msg.content;
|
|
464
|
+
const textBlock = contentBlocks.find((b) => b.type === "text" && typeof b.text === "string");
|
|
465
|
+
const hasContent = textBlock && typeof textBlock.text === "string" && textBlock.text.length > 0;
|
|
466
|
+
const toolCallBlocks = contentBlocks.filter((b) => b.type === "tool_call");
|
|
467
|
+
const msgToolCalls = Array.isArray(msg.tool_calls) ? msg.tool_calls : [];
|
|
468
|
+
if (toolCallBlocks.length > 0) {
|
|
469
|
+
const toolCalls = toolCallBlocks.map((b) => ({
|
|
470
|
+
name: String(b.name ?? b.function?.name ?? ""),
|
|
471
|
+
arguments: typeof b.parameters === "string" ? b.parameters : typeof b.parameters === "object" ? JSON.stringify(b.parameters) : typeof b.function?.arguments === "string" ? String(b.function.arguments) : JSON.stringify(b.function?.arguments),
|
|
472
|
+
...b.id ? { id: String(b.id) } : {}
|
|
473
|
+
}));
|
|
474
|
+
if (hasContent) return {
|
|
475
|
+
content: textBlock.text,
|
|
476
|
+
toolCalls
|
|
477
|
+
};
|
|
478
|
+
return { toolCalls };
|
|
479
|
+
}
|
|
480
|
+
if (msgToolCalls.length > 0) {
|
|
481
|
+
const toolCalls = msgToolCalls.map((tc) => {
|
|
482
|
+
const fn = tc.function;
|
|
483
|
+
return {
|
|
484
|
+
name: String(tc.name ?? fn?.name ?? ""),
|
|
485
|
+
arguments: typeof tc.parameters === "string" ? tc.parameters : typeof tc.parameters === "object" ? JSON.stringify(tc.parameters) : typeof fn?.arguments === "string" ? String(fn.arguments) : JSON.stringify(fn?.arguments),
|
|
486
|
+
...tc.id ? { id: String(tc.id) } : {}
|
|
487
|
+
};
|
|
488
|
+
});
|
|
489
|
+
if (hasContent) return {
|
|
490
|
+
content: textBlock.text,
|
|
491
|
+
toolCalls
|
|
492
|
+
};
|
|
493
|
+
return { toolCalls };
|
|
494
|
+
}
|
|
495
|
+
if (hasContent) return { content: textBlock.text };
|
|
496
|
+
}
|
|
342
497
|
if (obj.message && typeof obj.message === "object") {
|
|
343
498
|
const msg = obj.message;
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
499
|
+
const hasOllamaToolCalls = Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0;
|
|
500
|
+
const hasOllamaContent = typeof msg.content === "string" && msg.content.length > 0;
|
|
501
|
+
if (hasOllamaToolCalls) {
|
|
502
|
+
const toolCalls = msg.tool_calls.filter((tc) => tc.function != null).map((tc) => {
|
|
503
|
+
const fn = tc.function;
|
|
504
|
+
return {
|
|
505
|
+
name: String(fn.name ?? ""),
|
|
506
|
+
arguments: typeof fn.arguments === "string" ? fn.arguments : JSON.stringify(fn.arguments)
|
|
507
|
+
};
|
|
508
|
+
});
|
|
509
|
+
if (hasOllamaContent) return {
|
|
510
|
+
content: msg.content,
|
|
511
|
+
toolCalls
|
|
349
512
|
};
|
|
350
|
-
|
|
351
|
-
|
|
513
|
+
return { toolCalls };
|
|
514
|
+
}
|
|
515
|
+
if (hasOllamaContent) return { content: msg.content };
|
|
352
516
|
if (Array.isArray(msg.content) && msg.content.length > 0) {
|
|
353
517
|
const first = msg.content[0];
|
|
354
518
|
if (typeof first.text === "string") return { content: first.text };
|
|
355
519
|
}
|
|
356
520
|
}
|
|
521
|
+
if (typeof obj.response === "string" && "done" in obj) return { content: obj.response };
|
|
357
522
|
return {
|
|
358
523
|
error: {
|
|
359
524
|
message: "Could not detect response format from upstream",
|