@copilotkit/aimock 1.44.0 → 1.45.0
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +31 -0
- package/README.md +6 -0
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/aimock-cli.cjs +31 -5
- package/dist/aimock-cli.cjs.map +1 -1
- package/dist/aimock-cli.d.cts.map +1 -1
- package/dist/aimock-cli.d.ts.map +1 -1
- package/dist/aimock-cli.js +31 -5
- package/dist/aimock-cli.js.map +1 -1
- package/dist/bedrock-converse.cjs +312 -39
- 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 +313 -40
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +195 -42
- 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 +196 -43
- package/dist/bedrock.js.map +1 -1
- package/dist/chaos.cjs +1 -0
- package/dist/chaos.js +1 -1
- package/dist/cli.cjs +152 -5
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +155 -8
- package/dist/cli.js.map +1 -1
- package/dist/cohere.cjs +132 -71
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.d.cts.map +1 -1
- package/dist/cohere.d.ts.map +1 -1
- package/dist/cohere.js +133 -72
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.cjs +62 -4
- package/dist/config-loader.cjs.map +1 -1
- package/dist/config-loader.d.cts +37 -4
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/config-loader.d.ts +37 -4
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +62 -4
- package/dist/config-loader.js.map +1 -1
- package/dist/fakes-plugin.cjs +131 -0
- package/dist/fakes-plugin.cjs.map +1 -0
- package/dist/fakes-plugin.d.cts +23 -0
- package/dist/fakes-plugin.d.cts.map +1 -0
- package/dist/fakes-plugin.d.ts +23 -0
- package/dist/fakes-plugin.d.ts.map +1 -0
- package/dist/fakes-plugin.js +127 -0
- package/dist/fakes-plugin.js.map +1 -0
- package/dist/fixture-loader-services.cjs +1 -1
- package/dist/fixture-loader-services.cjs.map +1 -1
- package/dist/fixture-loader-services.js +1 -1
- package/dist/fixture-loader-services.js.map +1 -1
- package/dist/fixture-loader.cjs +389 -27
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts +47 -3
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts +47 -3
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +384 -29
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini-interactions.cjs +250 -52
- package/dist/gemini-interactions.cjs.map +1 -1
- package/dist/gemini-interactions.d.cts.map +1 -1
- package/dist/gemini-interactions.d.ts.map +1 -1
- package/dist/gemini-interactions.js +251 -53
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +226 -37
- 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 +227 -38
- package/dist/gemini.js.map +1 -1
- package/dist/helpers.cjs +881 -7
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +85 -4
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts +85 -4
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +839 -8
- package/dist/helpers.js.map +1 -1
- package/dist/index.cjs +9 -0
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +4 -3
- package/dist/jest.cjs +31 -7
- package/dist/jest.cjs.map +1 -1
- package/dist/jest.d.cts +43 -3
- package/dist/jest.d.cts.map +1 -1
- package/dist/jest.d.ts +43 -3
- package/dist/jest.d.ts.map +1 -1
- package/dist/jest.js +33 -9
- package/dist/jest.js.map +1 -1
- package/dist/journal.cjs +135 -13
- package/dist/journal.cjs.map +1 -1
- package/dist/journal.d.cts +38 -4
- package/dist/journal.d.cts.map +1 -1
- package/dist/journal.d.ts +38 -4
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +135 -13
- package/dist/journal.js.map +1 -1
- package/dist/live-sanitize.cjs +4 -32
- package/dist/live-sanitize.cjs.map +1 -1
- package/dist/live-sanitize.js +4 -32
- package/dist/live-sanitize.js.map +1 -1
- package/dist/llmock.cjs +123 -30
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +16 -1
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +16 -1
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +125 -32
- package/dist/llmock.js.map +1 -1
- package/dist/mcp-fakes-mount.cjs +1 -0
- package/dist/mcp-fakes-mount.cjs.map +1 -1
- package/dist/mcp-fakes-mount.js +1 -0
- package/dist/mcp-fakes-mount.js.map +1 -1
- package/dist/mcp-fakes-report.cjs +111 -0
- package/dist/mcp-fakes-report.cjs.map +1 -0
- package/dist/mcp-fakes-report.d.cts +40 -0
- package/dist/mcp-fakes-report.d.cts.map +1 -0
- package/dist/mcp-fakes-report.d.ts +40 -0
- package/dist/mcp-fakes-report.d.ts.map +1 -0
- package/dist/mcp-fakes-report.js +107 -0
- package/dist/mcp-fakes-report.js.map +1 -0
- package/dist/mcp-fakes.cjs +331 -8
- package/dist/mcp-fakes.cjs.map +1 -1
- package/dist/mcp-fakes.d.cts +406 -3
- package/dist/mcp-fakes.d.cts.map +1 -1
- package/dist/mcp-fakes.d.ts +406 -3
- package/dist/mcp-fakes.d.ts.map +1 -1
- package/dist/mcp-fakes.js +331 -8
- package/dist/mcp-fakes.js.map +1 -1
- package/dist/mcp-handler.cjs +209 -16
- package/dist/mcp-handler.cjs.map +1 -1
- package/dist/mcp-handler.d.cts +49 -0
- package/dist/mcp-handler.d.cts.map +1 -0
- package/dist/mcp-handler.d.ts +49 -0
- package/dist/mcp-handler.d.ts.map +1 -0
- package/dist/mcp-handler.js +207 -17
- package/dist/mcp-handler.js.map +1 -1
- package/dist/mcp-mock.cjs +112 -1
- package/dist/mcp-mock.cjs.map +1 -1
- package/dist/mcp-mock.d.cts +33 -2
- package/dist/mcp-mock.d.cts.map +1 -1
- package/dist/mcp-mock.d.ts +33 -2
- package/dist/mcp-mock.d.ts.map +1 -1
- package/dist/mcp-mock.js +112 -1
- package/dist/mcp-mock.js.map +1 -1
- package/dist/mcp-recorder.cjs +1224 -0
- package/dist/mcp-recorder.cjs.map +1 -0
- package/dist/mcp-recorder.d.cts +108 -0
- package/dist/mcp-recorder.d.cts.map +1 -0
- package/dist/mcp-recorder.d.ts +108 -0
- package/dist/mcp-recorder.d.ts.map +1 -0
- package/dist/mcp-recorder.js +1215 -0
- package/dist/mcp-recorder.js.map +1 -0
- package/dist/messages.cjs +362 -56
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.d.cts.map +1 -1
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +363 -58
- package/dist/messages.js.map +1 -1
- package/dist/misbehavior.cjs +1523 -0
- package/dist/misbehavior.cjs.map +1 -0
- package/dist/misbehavior.d.cts +43 -0
- package/dist/misbehavior.d.cts.map +1 -0
- package/dist/misbehavior.d.ts +43 -0
- package/dist/misbehavior.d.ts.map +1 -0
- package/dist/misbehavior.js +1511 -0
- package/dist/misbehavior.js.map +1 -0
- package/dist/ollama.cjs +310 -112
- 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 +311 -113
- package/dist/ollama.js.map +1 -1
- package/dist/record-sanitize.cjs +231 -0
- package/dist/record-sanitize.cjs.map +1 -0
- package/dist/record-sanitize.js +224 -0
- package/dist/record-sanitize.js.map +1 -0
- package/dist/recorder.cjs +106 -5
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.d.cts +2 -1
- package/dist/recorder.d.cts.map +1 -1
- package/dist/recorder.d.ts +2 -1
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +107 -7
- package/dist/recorder.js.map +1 -1
- package/dist/responses.cjs +667 -171
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts +5 -13
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts +5 -13
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +665 -174
- package/dist/responses.js.map +1 -1
- package/dist/router.cjs +24 -2
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts.map +1 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +25 -4
- package/dist/router.js.map +1 -1
- package/dist/server.cjs +572 -76
- 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 +574 -78
- package/dist/server.js.map +1 -1
- package/dist/stream-collapse.cjs +236 -34
- package/dist/stream-collapse.cjs.map +1 -1
- package/dist/stream-collapse.d.cts +39 -4
- package/dist/stream-collapse.d.cts.map +1 -1
- package/dist/stream-collapse.d.ts +39 -4
- package/dist/stream-collapse.d.ts.map +1 -1
- package/dist/stream-collapse.js +235 -35
- package/dist/stream-collapse.js.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +315 -4
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +315 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/validate-cli.cjs +36 -4
- package/dist/validate-cli.cjs.map +1 -1
- package/dist/validate-cli.js +37 -5
- package/dist/validate-cli.js.map +1 -1
- package/dist/vector-types.d.ts.map +1 -1
- package/dist/version.cjs +45 -0
- package/dist/version.cjs.map +1 -0
- package/dist/version.js +44 -0
- package/dist/version.js.map +1 -0
- package/dist/vitest.cjs +66 -10
- package/dist/vitest.cjs.map +1 -1
- package/dist/vitest.d.cts +35 -4
- package/dist/vitest.d.cts.map +1 -1
- package/dist/vitest.d.ts +35 -4
- package/dist/vitest.d.ts.map +1 -1
- package/dist/vitest.js +67 -11
- package/dist/vitest.js.map +1 -1
- package/dist/watcher.cjs +6 -2
- package/dist/watcher.cjs.map +1 -1
- package/dist/watcher.js +6 -2
- package/dist/watcher.js.map +1 -1
- package/dist/ws-gemini-live.cjs +210 -101
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.d.cts +9 -3
- package/dist/ws-gemini-live.d.cts.map +1 -1
- package/dist/ws-gemini-live.d.ts +9 -3
- package/dist/ws-gemini-live.d.ts.map +1 -1
- package/dist/ws-gemini-live.js +211 -102
- package/dist/ws-gemini-live.js.map +1 -1
- package/dist/ws-realtime.cjs +175 -62
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts +8 -3
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts +8 -3
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +176 -63
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +109 -16
- package/dist/ws-responses.cjs.map +1 -1
- package/dist/ws-responses.d.cts +8 -12
- package/dist/ws-responses.d.cts.map +1 -1
- package/dist/ws-responses.d.ts +8 -12
- package/dist/ws-responses.d.ts.map +1 -1
- package/dist/ws-responses.js +111 -18
- package/dist/ws-responses.js.map +1 -1
- package/package.json +10 -2
- package/skills/write-fixtures/SKILL.md +179 -21
package/dist/ollama.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { flattenHeaders, generateDeterministicEmbedding, getContext, getTestId,
|
|
1
|
+
import { InvalidToolArgumentsError, estimatePromptTokens, estimateTokens, flattenHeaders, generateDeterministicEmbedding, getContext, getTestId, isCombinedFixtureResponse, isEmbeddingResponse, isErrorResponse, isJsonObject, isTextResponse, isToolCallResponse, normalizeEmbeddingInput, requireEmittedFunctionToolCalls, resolveFixtureBlockOutcome, resolveFixtureBlocks, resolveReasoningForModel, resolveResponse, resolveStrictMode, serializeErrorResponse, servedToolArgs, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField, toolArgsForWire, validateChatMessages, validateToolsField } from "./helpers.js";
|
|
2
2
|
import { writeErrorResponse } from "./sse-writer.js";
|
|
3
3
|
import { applyChaosAsync } from "./chaos.js";
|
|
4
|
+
import { planMisbehavior, recordMisbehaviorOutcome } from "./misbehavior.js";
|
|
4
5
|
import { matchFixtureDiagnostic, recordMatchOptions } from "./router.js";
|
|
5
6
|
import { proxyAndRecord } from "./recorder.js";
|
|
6
7
|
import { createInterruptionSignal } from "./interruption.js";
|
|
@@ -122,20 +123,8 @@ function buildOllamaChatTextResponse(content, model, reasoning) {
|
|
|
122
123
|
...DURATION_FIELDS
|
|
123
124
|
};
|
|
124
125
|
}
|
|
125
|
-
function buildOllamaChatToolCallChunks(toolCalls, model, chunkSize,
|
|
126
|
-
const ollamaToolCalls = toolCalls.map(
|
|
127
|
-
let argsObj;
|
|
128
|
-
try {
|
|
129
|
-
argsObj = JSON.parse(tc.arguments || "{}");
|
|
130
|
-
} catch {
|
|
131
|
-
logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
|
|
132
|
-
argsObj = {};
|
|
133
|
-
}
|
|
134
|
-
return { function: {
|
|
135
|
-
name: tc.name,
|
|
136
|
-
arguments: argsObj
|
|
137
|
-
} };
|
|
138
|
-
});
|
|
126
|
+
function buildOllamaChatToolCallChunks(toolCalls, model, chunkSize, reasoning) {
|
|
127
|
+
const ollamaToolCalls = toolCalls.map(toOllamaToolCall);
|
|
139
128
|
const chunks = [];
|
|
140
129
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
141
130
|
if (reasoning) for (let i = 0; i < reasoning.length; i += chunkSize) {
|
|
@@ -173,20 +162,8 @@ function buildOllamaChatToolCallChunks(toolCalls, model, chunkSize, logger, reas
|
|
|
173
162
|
});
|
|
174
163
|
return chunks;
|
|
175
164
|
}
|
|
176
|
-
function buildOllamaChatToolCallResponse(toolCalls, model,
|
|
177
|
-
const ollamaToolCalls = toolCalls.map(
|
|
178
|
-
let argsObj;
|
|
179
|
-
try {
|
|
180
|
-
argsObj = JSON.parse(tc.arguments || "{}");
|
|
181
|
-
} catch {
|
|
182
|
-
logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
|
|
183
|
-
argsObj = {};
|
|
184
|
-
}
|
|
185
|
-
return { function: {
|
|
186
|
-
name: tc.name,
|
|
187
|
-
arguments: argsObj
|
|
188
|
-
} };
|
|
189
|
-
});
|
|
165
|
+
function buildOllamaChatToolCallResponse(toolCalls, model, reasoning) {
|
|
166
|
+
const ollamaToolCalls = toolCalls.map(toOllamaToolCall);
|
|
190
167
|
return {
|
|
191
168
|
model,
|
|
192
169
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -200,20 +177,13 @@ function buildOllamaChatToolCallResponse(toolCalls, model, logger, reasoning) {
|
|
|
200
177
|
...DURATION_FIELDS
|
|
201
178
|
};
|
|
202
179
|
}
|
|
203
|
-
function toOllamaToolCall(tc
|
|
204
|
-
let argsObj;
|
|
205
|
-
try {
|
|
206
|
-
argsObj = JSON.parse(tc.arguments || "{}");
|
|
207
|
-
} catch {
|
|
208
|
-
logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
|
|
209
|
-
argsObj = {};
|
|
210
|
-
}
|
|
180
|
+
function toOllamaToolCall(tc) {
|
|
211
181
|
return { function: {
|
|
212
182
|
name: tc.name,
|
|
213
|
-
arguments:
|
|
183
|
+
arguments: servedToolArgs(tc, "object").value
|
|
214
184
|
} };
|
|
215
185
|
}
|
|
216
|
-
function buildOllamaChatContentWithToolCallsChunks(content, toolCalls, model, chunkSize,
|
|
186
|
+
function buildOllamaChatContentWithToolCallsChunks(content, toolCalls, model, chunkSize, reasoning, blocks) {
|
|
217
187
|
const chunks = [];
|
|
218
188
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
219
189
|
if (blocks && blocks.length > 0) {
|
|
@@ -249,7 +219,7 @@ function buildOllamaChatContentWithToolCallsChunks(content, toolCalls, model, ch
|
|
|
249
219
|
message: {
|
|
250
220
|
role: "assistant",
|
|
251
221
|
content: "",
|
|
252
|
-
tool_calls: [toOllamaToolCall(block
|
|
222
|
+
tool_calls: [toOllamaToolCall(block)]
|
|
253
223
|
},
|
|
254
224
|
done: false
|
|
255
225
|
});
|
|
@@ -290,19 +260,7 @@ function buildOllamaChatContentWithToolCallsChunks(content, toolCalls, model, ch
|
|
|
290
260
|
done: false
|
|
291
261
|
});
|
|
292
262
|
}
|
|
293
|
-
const ollamaToolCalls = toolCalls.map(
|
|
294
|
-
let argsObj;
|
|
295
|
-
try {
|
|
296
|
-
argsObj = JSON.parse(tc.arguments || "{}");
|
|
297
|
-
} catch {
|
|
298
|
-
logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
|
|
299
|
-
argsObj = {};
|
|
300
|
-
}
|
|
301
|
-
return { function: {
|
|
302
|
-
name: tc.name,
|
|
303
|
-
arguments: argsObj
|
|
304
|
-
} };
|
|
305
|
-
});
|
|
263
|
+
const ollamaToolCalls = toolCalls.map(toOllamaToolCall);
|
|
306
264
|
chunks.push({
|
|
307
265
|
model,
|
|
308
266
|
created_at: createdAt,
|
|
@@ -325,7 +283,7 @@ function buildOllamaChatContentWithToolCallsChunks(content, toolCalls, model, ch
|
|
|
325
283
|
});
|
|
326
284
|
return chunks;
|
|
327
285
|
}
|
|
328
|
-
function buildOllamaChatContentWithToolCallsResponse(content, toolCalls, model,
|
|
286
|
+
function buildOllamaChatContentWithToolCallsResponse(content, toolCalls, model, reasoning, blocks) {
|
|
329
287
|
if (blocks && blocks.length > 0) {
|
|
330
288
|
const ordered = resolveFixtureBlocks(blocks);
|
|
331
289
|
content = ordered.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
@@ -334,19 +292,7 @@ function buildOllamaChatContentWithToolCallsResponse(content, toolCalls, model,
|
|
|
334
292
|
arguments: b.arguments
|
|
335
293
|
}));
|
|
336
294
|
}
|
|
337
|
-
const ollamaToolCalls = toolCalls.map(
|
|
338
|
-
let argsObj;
|
|
339
|
-
try {
|
|
340
|
-
argsObj = JSON.parse(tc.arguments || "{}");
|
|
341
|
-
} catch {
|
|
342
|
-
logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
|
|
343
|
-
argsObj = {};
|
|
344
|
-
}
|
|
345
|
-
return { function: {
|
|
346
|
-
name: tc.name,
|
|
347
|
-
arguments: argsObj
|
|
348
|
-
} };
|
|
349
|
-
});
|
|
295
|
+
const ollamaToolCalls = toolCalls.map(toOllamaToolCall);
|
|
350
296
|
return {
|
|
351
297
|
model,
|
|
352
298
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -360,6 +306,105 @@ function buildOllamaChatContentWithToolCallsResponse(content, toolCalls, model,
|
|
|
360
306
|
...DURATION_FIELDS
|
|
361
307
|
};
|
|
362
308
|
}
|
|
309
|
+
/** Prepare fault output and its observations together before sending any bytes. */
|
|
310
|
+
function prepareOllamaMisbehavior(plan, request, stream, chunkSize, effectiveStrict, logger) {
|
|
311
|
+
const response = plan.response;
|
|
312
|
+
const combined = isCombinedFixtureResponse(response);
|
|
313
|
+
const outcome = combined && response.blocks?.length ? resolveFixtureBlockOutcome(response.blocks) : void 0;
|
|
314
|
+
const calls = outcome?.toolCalls ?? (combined || isToolCallResponse(response) ? response.toolCalls ?? [] : []);
|
|
315
|
+
const content = outcome?.content ?? ("content" in response ? response.content ?? "" : "");
|
|
316
|
+
const model = request.model;
|
|
317
|
+
if (plan.summary.fault === "tool-args-invalid-json") {
|
|
318
|
+
const target = calls[plan.target?.index ?? 0];
|
|
319
|
+
if (!target || toolArgsForWire(target).kind !== "verbatim") throw new Error("Ollama invalid-JSON fault requires an invalid prepared target");
|
|
320
|
+
const diagnostic = new InvalidToolArgumentsError(target).parseDiagnostic;
|
|
321
|
+
const error = `error parsing tool call: raw='${target.arguments}', err=${diagnostic}`;
|
|
322
|
+
let priorContent = content;
|
|
323
|
+
if (outcome) {
|
|
324
|
+
priorContent = "";
|
|
325
|
+
let index = 0;
|
|
326
|
+
for (const block of outcome.ordered) if (block.type === "text") priorContent += block.text;
|
|
327
|
+
else if (index++ === plan.target?.index) break;
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
chunks: stream ? [...buildOllamaChatTextChunks(priorContent, model, chunkSize).slice(0, -1), { error }] : [{ error }],
|
|
331
|
+
status: stream ? 200 : 500,
|
|
332
|
+
summary: {
|
|
333
|
+
...plan.summary,
|
|
334
|
+
servedToolCalls: []
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
const servedToolCalls = calls.map((call) => {
|
|
339
|
+
const parsed = toolArgsForWire(call);
|
|
340
|
+
if (parsed.kind === "verbatim") throw new InvalidToolArgumentsError(call);
|
|
341
|
+
return {
|
|
342
|
+
name: call.name,
|
|
343
|
+
arguments: parsed.text
|
|
344
|
+
};
|
|
345
|
+
});
|
|
346
|
+
let chunks;
|
|
347
|
+
let reasoning = "";
|
|
348
|
+
if (plan.summary.fault === "reasoning-only") {
|
|
349
|
+
reasoning = plan.reasoning ?? "";
|
|
350
|
+
const base = {
|
|
351
|
+
model,
|
|
352
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
353
|
+
};
|
|
354
|
+
if (stream) {
|
|
355
|
+
chunks = [];
|
|
356
|
+
for (let i = 0; i < reasoning.length; i += chunkSize) chunks.push({
|
|
357
|
+
...base,
|
|
358
|
+
message: {
|
|
359
|
+
role: "assistant",
|
|
360
|
+
content: "",
|
|
361
|
+
thinking: reasoning.slice(i, i + chunkSize)
|
|
362
|
+
},
|
|
363
|
+
done: false
|
|
364
|
+
});
|
|
365
|
+
chunks.push({
|
|
366
|
+
...base,
|
|
367
|
+
message: {
|
|
368
|
+
role: "assistant",
|
|
369
|
+
content: ""
|
|
370
|
+
},
|
|
371
|
+
done: true,
|
|
372
|
+
...DURATION_FIELDS,
|
|
373
|
+
done_reason: "length"
|
|
374
|
+
});
|
|
375
|
+
} else chunks = [{
|
|
376
|
+
...base,
|
|
377
|
+
message: {
|
|
378
|
+
role: "assistant",
|
|
379
|
+
content: "",
|
|
380
|
+
thinking: reasoning
|
|
381
|
+
},
|
|
382
|
+
done: true,
|
|
383
|
+
...DURATION_FIELDS,
|
|
384
|
+
done_reason: "length"
|
|
385
|
+
}];
|
|
386
|
+
} else {
|
|
387
|
+
reasoning = resolveReasoningForModel("reasoning" in response ? response.reasoning : void 0, model, effectiveStrict, logger) ?? "";
|
|
388
|
+
if (combined) chunks = stream ? buildOllamaChatContentWithToolCallsChunks(content, calls, model, chunkSize, reasoning, response.blocks) : [buildOllamaChatContentWithToolCallsResponse(content, calls, model, reasoning, response.blocks)];
|
|
389
|
+
else if (isToolCallResponse(response)) chunks = stream ? buildOllamaChatToolCallChunks(calls, model, chunkSize, reasoning) : [buildOllamaChatToolCallResponse(calls, model, reasoning)];
|
|
390
|
+
else chunks = stream ? buildOllamaChatTextChunks(content, model, chunkSize, reasoning) : [buildOllamaChatTextResponse(content, model, reasoning)];
|
|
391
|
+
}
|
|
392
|
+
const completion = content + reasoning + servedToolCalls.map((call) => call.name + call.arguments).join("");
|
|
393
|
+
const terminal = chunks.length - 1;
|
|
394
|
+
chunks[terminal] = {
|
|
395
|
+
...chunks[terminal],
|
|
396
|
+
prompt_eval_count: estimatePromptTokens(request.messages),
|
|
397
|
+
eval_count: estimateTokens(completion)
|
|
398
|
+
};
|
|
399
|
+
return {
|
|
400
|
+
chunks,
|
|
401
|
+
status: 200,
|
|
402
|
+
summary: {
|
|
403
|
+
...plan.summary,
|
|
404
|
+
servedToolCalls
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
}
|
|
363
408
|
function buildOllamaGenerateTextChunks(content, model, chunkSize, reasoning) {
|
|
364
409
|
const chunks = [];
|
|
365
410
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -540,25 +585,100 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
540
585
|
return;
|
|
541
586
|
}
|
|
542
587
|
const response = await resolveResponse(fixture, completionReq);
|
|
588
|
+
const misbehavior = planMisbehavior({
|
|
589
|
+
wire: "ollama",
|
|
590
|
+
fixture,
|
|
591
|
+
response,
|
|
592
|
+
request: completionReq,
|
|
593
|
+
stream: ollamaReq.stream !== false,
|
|
594
|
+
defaults,
|
|
595
|
+
rawHeaders: req.headers,
|
|
596
|
+
url: req.url
|
|
597
|
+
});
|
|
598
|
+
if (misbehavior.kind === "error") {
|
|
599
|
+
recordMisbehaviorOutcome({
|
|
600
|
+
entry: journal.add({
|
|
601
|
+
method: req.method ?? "POST",
|
|
602
|
+
path: urlPath,
|
|
603
|
+
headers: flattenHeaders(req.headers),
|
|
604
|
+
body: completionReq,
|
|
605
|
+
response: {
|
|
606
|
+
status: misbehavior.status,
|
|
607
|
+
fixture
|
|
608
|
+
}
|
|
609
|
+
}),
|
|
610
|
+
summary: misbehavior.summary,
|
|
611
|
+
defaults,
|
|
612
|
+
testId
|
|
613
|
+
});
|
|
614
|
+
const message = `${misbehavior.code}: ${misbehavior.message}`;
|
|
615
|
+
if (!misbehavior.summary?.evaluations.length) defaults.logger.error(message);
|
|
616
|
+
writeErrorResponse(res, misbehavior.status, JSON.stringify({ error: message }));
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
543
619
|
const latency = fixture.latency ?? defaults.latency;
|
|
544
620
|
const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
|
|
545
621
|
const streaming = ollamaReq.stream !== false;
|
|
546
|
-
if (
|
|
547
|
-
const
|
|
548
|
-
journal.add({
|
|
622
|
+
if (misbehavior.kind === "applied") {
|
|
623
|
+
const prepared = prepareOllamaMisbehavior(misbehavior, completionReq, streaming, chunkSize, resolveStrictMode(defaults.strict, req.headers), logger);
|
|
624
|
+
const journalEntry = journal.add({
|
|
549
625
|
method: req.method ?? "POST",
|
|
550
626
|
path: urlPath,
|
|
551
627
|
headers: flattenHeaders(req.headers),
|
|
552
628
|
body: completionReq,
|
|
553
629
|
response: {
|
|
554
|
-
status,
|
|
630
|
+
status: prepared.status,
|
|
555
631
|
fixture
|
|
556
632
|
}
|
|
557
633
|
});
|
|
634
|
+
recordMisbehaviorOutcome({
|
|
635
|
+
entry: journalEntry,
|
|
636
|
+
summary: prepared.summary,
|
|
637
|
+
defaults,
|
|
638
|
+
testId
|
|
639
|
+
});
|
|
640
|
+
if (!streaming) {
|
|
641
|
+
res.writeHead(prepared.status, { "Content-Type": "application/json" });
|
|
642
|
+
res.end(JSON.stringify(prepared.chunks[0]));
|
|
643
|
+
} else {
|
|
644
|
+
const interruption = createInterruptionSignal(fixture);
|
|
645
|
+
if (!await writeNDJSONStream(res, prepared.chunks, {
|
|
646
|
+
latency,
|
|
647
|
+
streamingProfile: fixture.streamingProfile,
|
|
648
|
+
recordedTimings: fixture.recordedTimings,
|
|
649
|
+
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
650
|
+
signal: interruption?.signal,
|
|
651
|
+
onChunkSent: interruption?.tick
|
|
652
|
+
})) {
|
|
653
|
+
if (!res.writableEnded) res.destroy();
|
|
654
|
+
journalEntry.response.interrupted = true;
|
|
655
|
+
journalEntry.response.interruptReason = interruption?.reason();
|
|
656
|
+
}
|
|
657
|
+
interruption?.cleanup();
|
|
658
|
+
}
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
if (isErrorResponse(response)) {
|
|
662
|
+
const status = response.status ?? 500;
|
|
663
|
+
recordMisbehaviorOutcome({
|
|
664
|
+
entry: journal.add({
|
|
665
|
+
method: req.method ?? "POST",
|
|
666
|
+
path: urlPath,
|
|
667
|
+
headers: flattenHeaders(req.headers),
|
|
668
|
+
body: completionReq,
|
|
669
|
+
response: {
|
|
670
|
+
status,
|
|
671
|
+
fixture
|
|
672
|
+
}
|
|
673
|
+
}),
|
|
674
|
+
summary: misbehavior.summary,
|
|
675
|
+
defaults,
|
|
676
|
+
testId
|
|
677
|
+
});
|
|
558
678
|
writeErrorResponse(res, status, serializeErrorResponse(response), { retryAfter: response.retryAfter });
|
|
559
679
|
return;
|
|
560
680
|
}
|
|
561
|
-
if (
|
|
681
|
+
if (isCombinedFixtureResponse(response)) {
|
|
562
682
|
if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Ollama API -- ignoring");
|
|
563
683
|
const journalEntry = journal.add({
|
|
564
684
|
method: req.method ?? "POST",
|
|
@@ -570,14 +690,21 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
570
690
|
fixture
|
|
571
691
|
}
|
|
572
692
|
});
|
|
693
|
+
recordMisbehaviorOutcome({
|
|
694
|
+
entry: journalEntry,
|
|
695
|
+
summary: misbehavior.summary,
|
|
696
|
+
defaults,
|
|
697
|
+
testId
|
|
698
|
+
});
|
|
699
|
+
const functionToolCalls = requireEmittedFunctionToolCalls(response, "Ollama");
|
|
573
700
|
const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);
|
|
574
701
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, logger);
|
|
575
702
|
if (!streaming) {
|
|
576
|
-
const body = buildOllamaChatContentWithToolCallsResponse(response.content ?? "",
|
|
703
|
+
const body = buildOllamaChatContentWithToolCallsResponse(response.content ?? "", functionToolCalls, completionReq.model, effReasoning, response.blocks);
|
|
577
704
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
578
705
|
res.end(JSON.stringify(body));
|
|
579
706
|
} else {
|
|
580
|
-
const chunks = buildOllamaChatContentWithToolCallsChunks(response.content ?? "",
|
|
707
|
+
const chunks = buildOllamaChatContentWithToolCallsChunks(response.content ?? "", functionToolCalls, completionReq.model, chunkSize, effReasoning, response.blocks);
|
|
581
708
|
const interruption = createInterruptionSignal(fixture);
|
|
582
709
|
if (!await writeNDJSONStream(res, chunks, {
|
|
583
710
|
latency,
|
|
@@ -607,6 +734,12 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
607
734
|
fixture
|
|
608
735
|
}
|
|
609
736
|
});
|
|
737
|
+
recordMisbehaviorOutcome({
|
|
738
|
+
entry: journalEntry,
|
|
739
|
+
summary: misbehavior.summary,
|
|
740
|
+
defaults,
|
|
741
|
+
testId
|
|
742
|
+
});
|
|
610
743
|
const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);
|
|
611
744
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, logger);
|
|
612
745
|
if (!streaming) {
|
|
@@ -644,14 +777,21 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
644
777
|
fixture
|
|
645
778
|
}
|
|
646
779
|
});
|
|
780
|
+
recordMisbehaviorOutcome({
|
|
781
|
+
entry: journalEntry,
|
|
782
|
+
summary: misbehavior.summary,
|
|
783
|
+
defaults,
|
|
784
|
+
testId
|
|
785
|
+
});
|
|
786
|
+
const functionToolCalls = requireEmittedFunctionToolCalls(response, "Ollama");
|
|
647
787
|
const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);
|
|
648
788
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, logger);
|
|
649
789
|
if (!streaming) {
|
|
650
|
-
const body = buildOllamaChatToolCallResponse(
|
|
790
|
+
const body = buildOllamaChatToolCallResponse(functionToolCalls, completionReq.model, effReasoning);
|
|
651
791
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
652
792
|
res.end(JSON.stringify(body));
|
|
653
793
|
} else {
|
|
654
|
-
const chunks = buildOllamaChatToolCallChunks(
|
|
794
|
+
const chunks = buildOllamaChatToolCallChunks(functionToolCalls, completionReq.model, chunkSize, effReasoning);
|
|
655
795
|
const interruption = createInterruptionSignal(fixture);
|
|
656
796
|
if (!await writeNDJSONStream(res, chunks, {
|
|
657
797
|
latency,
|
|
@@ -669,15 +809,20 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
669
809
|
}
|
|
670
810
|
return;
|
|
671
811
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
812
|
+
recordMisbehaviorOutcome({
|
|
813
|
+
entry: journal.add({
|
|
814
|
+
method: req.method ?? "POST",
|
|
815
|
+
path: urlPath,
|
|
816
|
+
headers: flattenHeaders(req.headers),
|
|
817
|
+
body: completionReq,
|
|
818
|
+
response: {
|
|
819
|
+
status: 500,
|
|
820
|
+
fixture
|
|
821
|
+
}
|
|
822
|
+
}),
|
|
823
|
+
summary: misbehavior.summary,
|
|
824
|
+
defaults,
|
|
825
|
+
testId
|
|
681
826
|
});
|
|
682
827
|
writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
683
828
|
message: "Fixture response did not match any known type",
|
|
@@ -815,20 +960,57 @@ async function handleOllamaGenerate(req, res, raw, fixtures, journal, defaults,
|
|
|
815
960
|
return;
|
|
816
961
|
}
|
|
817
962
|
const response = await resolveResponse(fixture, completionReq);
|
|
963
|
+
const misbehavior = planMisbehavior({
|
|
964
|
+
wire: "ollama",
|
|
965
|
+
faultRenderingAvailable: false,
|
|
966
|
+
fixture,
|
|
967
|
+
response,
|
|
968
|
+
request: completionReq,
|
|
969
|
+
stream: generateReq.stream !== false,
|
|
970
|
+
defaults,
|
|
971
|
+
rawHeaders: req.headers,
|
|
972
|
+
url: req.url
|
|
973
|
+
});
|
|
974
|
+
if (misbehavior.kind === "error") {
|
|
975
|
+
recordMisbehaviorOutcome({
|
|
976
|
+
entry: journal.add({
|
|
977
|
+
method: req.method ?? "POST",
|
|
978
|
+
path: urlPath,
|
|
979
|
+
headers: flattenHeaders(req.headers),
|
|
980
|
+
body: completionReq,
|
|
981
|
+
response: {
|
|
982
|
+
status: misbehavior.status,
|
|
983
|
+
fixture
|
|
984
|
+
}
|
|
985
|
+
}),
|
|
986
|
+
summary: misbehavior.summary,
|
|
987
|
+
defaults,
|
|
988
|
+
testId
|
|
989
|
+
});
|
|
990
|
+
const message = `${misbehavior.code}: ${misbehavior.message}`;
|
|
991
|
+
if (!misbehavior.summary?.evaluations.length) defaults.logger.error(message);
|
|
992
|
+
writeErrorResponse(res, misbehavior.status, JSON.stringify({ error: message }));
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
818
995
|
const latency = fixture.latency ?? defaults.latency;
|
|
819
996
|
const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
|
|
820
997
|
const streaming = generateReq.stream !== false;
|
|
821
998
|
if (isErrorResponse(response)) {
|
|
822
999
|
const status = response.status ?? 500;
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1000
|
+
recordMisbehaviorOutcome({
|
|
1001
|
+
entry: journal.add({
|
|
1002
|
+
method: req.method ?? "POST",
|
|
1003
|
+
path: urlPath,
|
|
1004
|
+
headers: flattenHeaders(req.headers),
|
|
1005
|
+
body: completionReq,
|
|
1006
|
+
response: {
|
|
1007
|
+
status,
|
|
1008
|
+
fixture
|
|
1009
|
+
}
|
|
1010
|
+
}),
|
|
1011
|
+
summary: misbehavior.summary,
|
|
1012
|
+
defaults,
|
|
1013
|
+
testId
|
|
832
1014
|
});
|
|
833
1015
|
writeErrorResponse(res, status, serializeErrorResponse(response), { retryAfter: response.retryAfter });
|
|
834
1016
|
return;
|
|
@@ -844,6 +1026,12 @@ async function handleOllamaGenerate(req, res, raw, fixtures, journal, defaults,
|
|
|
844
1026
|
fixture
|
|
845
1027
|
}
|
|
846
1028
|
});
|
|
1029
|
+
recordMisbehaviorOutcome({
|
|
1030
|
+
entry: journalEntry,
|
|
1031
|
+
summary: misbehavior.summary,
|
|
1032
|
+
defaults,
|
|
1033
|
+
testId
|
|
1034
|
+
});
|
|
847
1035
|
const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);
|
|
848
1036
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, defaults.logger);
|
|
849
1037
|
if (!streaming) {
|
|
@@ -869,16 +1057,21 @@ async function handleOllamaGenerate(req, res, raw, fixtures, journal, defaults,
|
|
|
869
1057
|
}
|
|
870
1058
|
return;
|
|
871
1059
|
}
|
|
872
|
-
if (isToolCallResponse(response) ||
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
1060
|
+
if (isToolCallResponse(response) || isCombinedFixtureResponse(response)) {
|
|
1061
|
+
recordMisbehaviorOutcome({
|
|
1062
|
+
entry: journal.add({
|
|
1063
|
+
method: req.method ?? "POST",
|
|
1064
|
+
path: urlPath,
|
|
1065
|
+
headers: flattenHeaders(req.headers),
|
|
1066
|
+
body: completionReq,
|
|
1067
|
+
response: {
|
|
1068
|
+
status: 400,
|
|
1069
|
+
fixture
|
|
1070
|
+
}
|
|
1071
|
+
}),
|
|
1072
|
+
summary: misbehavior.summary,
|
|
1073
|
+
defaults,
|
|
1074
|
+
testId
|
|
882
1075
|
});
|
|
883
1076
|
writeErrorResponse(res, 400, JSON.stringify({ error: {
|
|
884
1077
|
message: "Tool call fixtures are not supported on /api/generate — use /api/chat instead",
|
|
@@ -886,15 +1079,20 @@ async function handleOllamaGenerate(req, res, raw, fixtures, journal, defaults,
|
|
|
886
1079
|
} }));
|
|
887
1080
|
return;
|
|
888
1081
|
}
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
1082
|
+
recordMisbehaviorOutcome({
|
|
1083
|
+
entry: journal.add({
|
|
1084
|
+
method: req.method ?? "POST",
|
|
1085
|
+
path: urlPath,
|
|
1086
|
+
headers: flattenHeaders(req.headers),
|
|
1087
|
+
body: completionReq,
|
|
1088
|
+
response: {
|
|
1089
|
+
status: 500,
|
|
1090
|
+
fixture
|
|
1091
|
+
}
|
|
1092
|
+
}),
|
|
1093
|
+
summary: misbehavior.summary,
|
|
1094
|
+
defaults,
|
|
1095
|
+
testId
|
|
898
1096
|
});
|
|
899
1097
|
writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
900
1098
|
message: "Fixture response did not match any known type",
|