@copilotkit/aimock 1.43.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 +46 -0
- package/README.md +14 -2
- package/dist/agui-handler.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 +344 -43
- 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 +345 -44
- 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 +9 -5
- package/dist/chaos.cjs.map +1 -1
- package/dist/chaos.d.cts.map +1 -1
- package/dist/chaos.d.ts.map +1 -1
- package/dist/chaos.js +10 -7
- package/dist/chaos.js.map +1 -1
- package/dist/cli.cjs +238 -9
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +242 -13
- package/dist/cli.js.map +1 -1
- package/dist/cohere.cjs +159 -72
- 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 +160 -73
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.cjs +63 -5
- 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 +63 -5
- package/dist/config-loader.js.map +1 -1
- package/dist/constants.cjs +8 -0
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +6 -2
- package/dist/constants.d.ts +6 -2
- package/dist/constants.js +8 -1
- package/dist/constants.js.map +1 -1
- package/dist/echo-text.cjs +65 -0
- package/dist/echo-text.cjs.map +1 -0
- package/dist/echo-text.d.cts +22 -0
- package/dist/echo-text.d.cts.map +1 -0
- package/dist/echo-text.d.ts +22 -0
- package/dist/echo-text.d.ts.map +1 -0
- package/dist/echo-text.js +65 -0
- package/dist/echo-text.js.map +1 -0
- package/dist/embeddings.cjs +18 -1
- package/dist/embeddings.cjs.map +1 -1
- package/dist/embeddings.d.cts +1 -1
- package/dist/embeddings.d.cts.map +1 -1
- package/dist/embeddings.d.ts +1 -1
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/embeddings.js +18 -1
- package/dist/embeddings.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/files.cjs +9 -11
- package/dist/files.cjs.map +1 -1
- package/dist/files.d.cts.map +1 -1
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +10 -13
- package/dist/files.js.map +1 -1
- package/dist/fine-tuning.cjs +1 -19
- package/dist/fine-tuning.cjs.map +1 -1
- package/dist/fine-tuning.d.cts.map +1 -1
- package/dist/fine-tuning.d.ts.map +1 -1
- package/dist/fine-tuning.js +2 -20
- package/dist/fine-tuning.js.map +1 -1
- package/dist/fixture-loader-services.cjs +116 -0
- package/dist/fixture-loader-services.cjs.map +1 -0
- package/dist/fixture-loader-services.d.cts +48 -0
- package/dist/fixture-loader-services.d.cts.map +1 -0
- package/dist/fixture-loader-services.d.ts +48 -0
- package/dist/fixture-loader-services.d.ts.map +1 -0
- package/dist/fixture-loader-services.js +114 -0
- package/dist/fixture-loader-services.js.map +1 -0
- package/dist/fixture-loader.cjs +552 -29
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts +140 -2
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts +140 -2
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +542 -31
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini-embeddings.cjs +42 -2
- package/dist/gemini-embeddings.cjs.map +1 -1
- package/dist/gemini-embeddings.js +43 -3
- package/dist/gemini-embeddings.js.map +1 -1
- package/dist/gemini-interactions.cjs +288 -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 +289 -53
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +234 -38
- 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 +235 -39
- package/dist/gemini.js.map +1 -1
- package/dist/helpers.cjs +1157 -12
- 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 +1113 -14
- package/dist/helpers.js.map +1 -1
- package/dist/images.cjs +3 -2
- package/dist/images.cjs.map +1 -1
- package/dist/images.js +3 -2
- package/dist/images.js.map +1 -1
- package/dist/index.cjs +39 -1
- package/dist/index.d.cts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.js +11 -4
- package/dist/jest.cjs +43 -14
- package/dist/jest.cjs.map +1 -1
- package/dist/jest.d.cts +47 -5
- package/dist/jest.d.cts.map +1 -1
- package/dist/jest.d.ts +47 -5
- package/dist/jest.d.ts.map +1 -1
- package/dist/jest.js +45 -16
- package/dist/jest.js.map +1 -1
- package/dist/journal.cjs +155 -13
- package/dist/journal.cjs.map +1 -1
- package/dist/journal.d.cts +54 -4
- package/dist/journal.d.cts.map +1 -1
- package/dist/journal.d.ts +54 -4
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +155 -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 +204 -39
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +51 -1
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +51 -1
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +206 -41
- package/dist/llmock.js.map +1 -1
- package/dist/mcp-fakes-mount.cjs +217 -0
- package/dist/mcp-fakes-mount.cjs.map +1 -0
- package/dist/mcp-fakes-mount.js +211 -0
- package/dist/mcp-fakes-mount.js.map +1 -0
- 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 +1942 -0
- package/dist/mcp-fakes.cjs.map +1 -0
- package/dist/mcp-fakes.d.cts +504 -0
- package/dist/mcp-fakes.d.cts.map +1 -0
- package/dist/mcp-fakes.d.ts +504 -0
- package/dist/mcp-fakes.d.ts.map +1 -0
- package/dist/mcp-fakes.js +1937 -0
- package/dist/mcp-fakes.js.map +1 -0
- package/dist/mcp-handler.cjs +534 -27
- 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 +530 -28
- package/dist/mcp-handler.js.map +1 -1
- package/dist/mcp-mock.cjs +326 -47
- package/dist/mcp-mock.cjs.map +1 -1
- package/dist/mcp-mock.d.cts +97 -1
- package/dist/mcp-mock.d.cts.map +1 -1
- package/dist/mcp-mock.d.ts +97 -1
- package/dist/mcp-mock.d.ts.map +1 -1
- package/dist/mcp-mock.js +327 -48
- 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/mcp-stub.cjs +5 -1
- package/dist/mcp-stub.d.cts +3 -1
- package/dist/mcp-stub.d.ts +3 -1
- package/dist/mcp-stub.js +3 -1
- package/dist/mcp-types.d.cts +6 -0
- package/dist/mcp-types.d.ts +6 -0
- package/dist/message-text.cjs +192 -0
- package/dist/message-text.cjs.map +1 -0
- package/dist/message-text.d.cts +31 -0
- package/dist/message-text.d.cts.map +1 -0
- package/dist/message-text.d.ts +31 -0
- package/dist/message-text.d.ts.map +1 -0
- package/dist/message-text.js +184 -0
- package/dist/message-text.js.map +1 -0
- package/dist/messages.cjs +400 -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 +401 -58
- package/dist/messages.js.map +1 -1
- package/dist/metrics.cjs +46 -66
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.d.cts +14 -6
- package/dist/metrics.d.cts.map +1 -1
- package/dist/metrics.d.ts +14 -6
- package/dist/metrics.d.ts.map +1 -1
- package/dist/metrics.js +32 -40
- package/dist/metrics.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 +315 -113
- 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 +316 -114
- package/dist/ollama.js.map +1 -1
- package/dist/openapi.cjs +3405 -0
- package/dist/openapi.cjs.map +1 -0
- package/dist/openapi.d.cts +30 -0
- package/dist/openapi.d.cts.map +1 -0
- package/dist/openapi.d.ts +30 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +3404 -0
- package/dist/openapi.js.map +1 -0
- package/dist/openrouter-video.cjs +4 -4
- package/dist/openrouter-video.cjs.map +1 -1
- package/dist/openrouter-video.d.cts.map +1 -1
- package/dist/openrouter-video.d.ts.map +1 -1
- package/dist/openrouter-video.js +4 -4
- package/dist/openrouter-video.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 +115 -6
- 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 +116 -8
- package/dist/recorder.js.map +1 -1
- package/dist/responses.cjs +701 -166
- 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 +699 -169
- package/dist/responses.js.map +1 -1
- package/dist/route-registry.cjs +951 -0
- package/dist/route-registry.cjs.map +1 -0
- package/dist/route-registry.d.cts +33 -0
- package/dist/route-registry.d.cts.map +1 -0
- package/dist/route-registry.d.ts +33 -0
- package/dist/route-registry.d.ts.map +1 -0
- package/dist/route-registry.js +866 -0
- package/dist/route-registry.js.map +1 -0
- 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 +1159 -264
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +4 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts +4 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1067 -172
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +4 -2
- package/dist/speech.cjs.map +1 -1
- package/dist/speech.js +4 -2
- package/dist/speech.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/suite.cjs +1 -1
- package/dist/suite.js +1 -1
- package/dist/transcription.cjs +2 -2
- 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 +2 -2
- package/dist/transcription.js.map +1 -1
- package/dist/types.cjs +18 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +516 -5
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +516 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/validate-cli.cjs +123 -33
- package/dist/validate-cli.cjs.map +1 -1
- package/dist/validate-cli.js +125 -35
- package/dist/validate-cli.js.map +1 -1
- package/dist/vector-stores.cjs +1180 -0
- package/dist/vector-stores.cjs.map +1 -0
- package/dist/vector-stores.d.cts +106 -0
- package/dist/vector-stores.d.cts.map +1 -0
- package/dist/vector-stores.d.ts +106 -0
- package/dist/vector-stores.d.ts.map +1 -0
- package/dist/vector-stores.js +1164 -0
- package/dist/vector-stores.js.map +1 -0
- package/dist/vector-types.d.cts.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/video.cjs +19 -0
- package/dist/video.cjs.map +1 -1
- package/dist/video.d.cts.map +1 -1
- package/dist/video.d.ts.map +1 -1
- package/dist/video.js +19 -0
- package/dist/video.js.map +1 -1
- package/dist/vitest.cjs +77 -16
- package/dist/vitest.cjs.map +1 -1
- package/dist/vitest.d.cts +38 -5
- package/dist/vitest.d.cts.map +1 -1
- package/dist/vitest.d.ts +38 -5
- package/dist/vitest.d.ts.map +1 -1
- package/dist/vitest.js +78 -17
- 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 +121 -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 +123 -18
- package/dist/ws-responses.js.map +1 -1
- package/package.json +13 -2
- package/skills/write-fixtures/SKILL.md +179 -21
package/dist/gemini.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { extractOverrides, flattenHeaders, formatToMime, getContext, getTestId, isAudioResponse,
|
|
1
|
+
import { extractOverrides, flattenHeaders, formatToMime, getContext, getTestId, isAudioResponse, isCombinedFixtureResponse, isErrorResponse, isJsonObject, isTextResponse, isToolCallResponse, requireEmittedFunctionToolCalls, requireServedFunctionToolCalls, resolveFixtureBlockOutcome, resolveReasoningForModel, resolveResponse, resolveStrictMode, resolveUsage, servedToolArgs, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField, validateToolsField } from "./helpers.js";
|
|
2
2
|
import { calculateDelay, delay, 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";
|
|
@@ -29,7 +30,14 @@ function validateGeminiBody(req) {
|
|
|
29
30
|
const parts = req.systemInstruction.parts;
|
|
30
31
|
if (parts !== void 0 && parts !== null && !Array.isArray(parts)) return "systemInstruction.parts must be an array";
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
const toolsError = validateToolsField(req.tools);
|
|
34
|
+
if (toolsError) return toolsError;
|
|
35
|
+
if (Array.isArray(req.tools)) for (const [toolIndex, tool] of req.tools.entries()) {
|
|
36
|
+
if (!Array.isArray(tool.functionDeclarations)) continue;
|
|
37
|
+
const declarationIndex = tool.functionDeclarations.findIndex((declaration) => declaration === null);
|
|
38
|
+
if (declarationIndex !== -1) return `tools[${toolIndex}].functionDeclarations[${declarationIndex}] must not be null`;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
33
41
|
}
|
|
34
42
|
function geminiToCompletionRequest(req, model, stream) {
|
|
35
43
|
const messages = [];
|
|
@@ -108,7 +116,7 @@ function geminiToCompletionRequest(req, model, stream) {
|
|
|
108
116
|
function: {
|
|
109
117
|
name: d.name,
|
|
110
118
|
description: d.description,
|
|
111
|
-
parameters: d.parameters
|
|
119
|
+
parameters: d.parameters ?? d.parametersJsonSchema
|
|
112
120
|
}
|
|
113
121
|
}));
|
|
114
122
|
}
|
|
@@ -192,16 +200,10 @@ function buildGeminiTextStreamChunks(content, chunkSize, reasoning, overrides) {
|
|
|
192
200
|
return chunks;
|
|
193
201
|
}
|
|
194
202
|
function parseToolCallPart(tc, logger) {
|
|
195
|
-
|
|
196
|
-
try {
|
|
197
|
-
argsObj = JSON.parse(tc.arguments || "{}");
|
|
198
|
-
} catch {
|
|
199
|
-
logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
|
|
200
|
-
argsObj = {};
|
|
201
|
-
}
|
|
203
|
+
const args = servedToolArgs(tc, "object", logger);
|
|
202
204
|
const functionCall = {
|
|
203
205
|
name: tc.name,
|
|
204
|
-
args:
|
|
206
|
+
args: args.value
|
|
205
207
|
};
|
|
206
208
|
if (tc.id) functionCall.id = tc.id;
|
|
207
209
|
return { functionCall };
|
|
@@ -418,24 +420,24 @@ function resolveAudioInlineData(audio) {
|
|
|
418
420
|
data: audio.audio.b64Json
|
|
419
421
|
};
|
|
420
422
|
}
|
|
421
|
-
function buildGeminiAudioParts(audio, logger, effReasoning) {
|
|
423
|
+
function buildGeminiAudioParts(audio, toolCalls, logger, effReasoning) {
|
|
422
424
|
const parts = [{ inlineData: resolveAudioInlineData(audio) }];
|
|
423
425
|
if (effReasoning) parts.push({
|
|
424
426
|
text: effReasoning,
|
|
425
427
|
thought: true
|
|
426
428
|
});
|
|
427
429
|
if (audio.content) parts.push({ text: audio.content });
|
|
428
|
-
if (
|
|
430
|
+
if (toolCalls.length) parts.push(...toolCalls.map((tc) => parseToolCallPart(tc, logger)));
|
|
429
431
|
return parts;
|
|
430
432
|
}
|
|
431
|
-
function buildGeminiAudioResponse(audio, logger, effReasoning) {
|
|
433
|
+
function buildGeminiAudioResponse(audio, toolCalls, logger, effReasoning) {
|
|
432
434
|
return {
|
|
433
435
|
candidates: [{
|
|
434
436
|
content: {
|
|
435
437
|
role: "model",
|
|
436
|
-
parts: buildGeminiAudioParts(audio, logger, effReasoning)
|
|
438
|
+
parts: buildGeminiAudioParts(audio, toolCalls, logger, effReasoning)
|
|
437
439
|
},
|
|
438
|
-
finishReason:
|
|
440
|
+
finishReason: toolCalls.length ? "FUNCTION_CALL" : "STOP",
|
|
439
441
|
index: 0
|
|
440
442
|
}],
|
|
441
443
|
usageMetadata: {
|
|
@@ -445,14 +447,14 @@ function buildGeminiAudioResponse(audio, logger, effReasoning) {
|
|
|
445
447
|
}
|
|
446
448
|
};
|
|
447
449
|
}
|
|
448
|
-
function buildGeminiAudioStreamChunks(audio, logger, effReasoning) {
|
|
450
|
+
function buildGeminiAudioStreamChunks(audio, toolCalls, logger, effReasoning) {
|
|
449
451
|
return [{
|
|
450
452
|
candidates: [{
|
|
451
453
|
content: {
|
|
452
454
|
role: "model",
|
|
453
|
-
parts: buildGeminiAudioParts(audio, logger, effReasoning)
|
|
455
|
+
parts: buildGeminiAudioParts(audio, toolCalls, logger, effReasoning)
|
|
454
456
|
},
|
|
455
|
-
finishReason:
|
|
457
|
+
finishReason: toolCalls.length ? "FUNCTION_CALL" : "STOP",
|
|
456
458
|
index: 0
|
|
457
459
|
}],
|
|
458
460
|
usageMetadata: {
|
|
@@ -487,8 +489,90 @@ async function writeGeminiSSEStream(res, chunks, optionsOrLatency) {
|
|
|
487
489
|
if (!res.writableEnded) res.end();
|
|
488
490
|
return true;
|
|
489
491
|
}
|
|
492
|
+
/** Prepare native fault output once; the journal describes these exact parts. */
|
|
493
|
+
function prepareGeminiMisbehavior(plan, request, streaming, chunkSize, logger, strict) {
|
|
494
|
+
const response = plan.response;
|
|
495
|
+
const combined = isCombinedFixtureResponse(response);
|
|
496
|
+
if (!(combined || isToolCallResponse(response) || isTextResponse(response))) throw new Error("Applied Gemini misbehavior requires a chat response");
|
|
497
|
+
const outcome = combined && response.blocks?.length ? resolveFixtureBlockOutcome(response.blocks) : void 0;
|
|
498
|
+
const content = outcome?.content ?? ("content" in response ? response.content ?? "" : "");
|
|
499
|
+
const calls = outcome?.toolCalls ?? ("toolCalls" in response ? response.toolCalls ?? [] : []);
|
|
500
|
+
const overrides = extractOverrides(response);
|
|
501
|
+
delete overrides.usage;
|
|
502
|
+
const fault = plan.summary.fault;
|
|
503
|
+
const candidate = {
|
|
504
|
+
content: {
|
|
505
|
+
role: "model",
|
|
506
|
+
parts: []
|
|
507
|
+
},
|
|
508
|
+
index: 0
|
|
509
|
+
};
|
|
510
|
+
let chunks;
|
|
511
|
+
if (fault === "tool-args-invalid-json") {
|
|
512
|
+
const target = calls[plan.target?.index ?? 0];
|
|
513
|
+
if (!target) throw new Error("Gemini malformed-call plan requires its selected tool call");
|
|
514
|
+
chunks = [{ candidates: [{
|
|
515
|
+
index: 0,
|
|
516
|
+
finishReason: "MALFORMED_FUNCTION_CALL",
|
|
517
|
+
finishMessage: `Malformed function call: ${target.name}(${target.arguments})`
|
|
518
|
+
}] }];
|
|
519
|
+
} else if (fault === "tool-unknown-name" && !request.tools?.length) {
|
|
520
|
+
candidate.finishReason = "UNEXPECTED_TOOL_CALL";
|
|
521
|
+
chunks = [{ candidates: [candidate] }];
|
|
522
|
+
} else if (fault === "stop-length-mid-tool") {
|
|
523
|
+
candidate.content.parts = content ? [{ text: content }] : [];
|
|
524
|
+
candidate.finishReason = "MAX_TOKENS";
|
|
525
|
+
chunks = [{ candidates: [candidate] }];
|
|
526
|
+
} else if (fault === "empty-response") {
|
|
527
|
+
candidate.content.parts = [{ text: "" }];
|
|
528
|
+
candidate.finishReason = "STOP";
|
|
529
|
+
chunks = [{ candidates: [candidate] }];
|
|
530
|
+
} else if (fault === "content-filter") {
|
|
531
|
+
candidate.finishReason = "SAFETY";
|
|
532
|
+
candidate.safetyRatings = [{
|
|
533
|
+
category: "HARM_CATEGORY_DANGEROUS_CONTENT",
|
|
534
|
+
probability: "HIGH",
|
|
535
|
+
blocked: true
|
|
536
|
+
}];
|
|
537
|
+
chunks = [{ candidates: [candidate] }];
|
|
538
|
+
} else if (fault === "reasoning-only") {
|
|
539
|
+
candidate.content.parts = [{
|
|
540
|
+
text: plan.reasoning ?? "",
|
|
541
|
+
thought: true
|
|
542
|
+
}];
|
|
543
|
+
candidate.finishReason = "MAX_TOKENS";
|
|
544
|
+
chunks = [{ candidates: [candidate] }];
|
|
545
|
+
} else {
|
|
546
|
+
const reasoning = resolveReasoningForModel(response.reasoning, request.model, strict, logger);
|
|
547
|
+
if (fault === "tool-unknown-name") overrides.finishReason = "stop";
|
|
548
|
+
if (combined) chunks = streaming ? buildGeminiContentWithToolCallsStreamChunks(content, calls, chunkSize, logger, reasoning, overrides, response.blocks) : [buildGeminiContentWithToolCallsResponse(content, calls, logger, reasoning, overrides, response.blocks)];
|
|
549
|
+
else if (isToolCallResponse(response)) chunks = streaming ? buildGeminiToolCallStreamChunks(calls, chunkSize, logger, reasoning, overrides) : [buildGeminiToolCallResponse(calls, logger, reasoning, overrides)];
|
|
550
|
+
else chunks = streaming ? buildGeminiTextStreamChunks(content, chunkSize, reasoning, overrides) : [buildGeminiTextResponse(content, reasoning, overrides)];
|
|
551
|
+
}
|
|
552
|
+
const parts = chunks.flatMap((chunk) => chunk.candidates.flatMap((item) => item.content?.parts ?? []));
|
|
553
|
+
const servedToolCalls = parts.flatMap((part) => part.functionCall ? [{
|
|
554
|
+
name: part.functionCall.name,
|
|
555
|
+
arguments: JSON.stringify(part.functionCall.args),
|
|
556
|
+
...part.functionCall.id ? { id: part.functionCall.id } : {}
|
|
557
|
+
}] : []);
|
|
558
|
+
const usage = resolveUsage(void 0, request.messages.map((message) => typeof message.content === "string" ? message.content : (message.content ?? []).map((part) => part.text ?? "").join("")).join(""), parts.map((part) => part.text ?? (part.functionCall ? part.functionCall.name + JSON.stringify(part.functionCall.args) : "")).join(""));
|
|
559
|
+
for (const chunk of chunks) delete chunk.usageMetadata;
|
|
560
|
+
chunks[chunks.length - 1].usageMetadata = {
|
|
561
|
+
promptTokenCount: usage.prompt_tokens,
|
|
562
|
+
candidatesTokenCount: usage.completion_tokens,
|
|
563
|
+
totalTokenCount: usage.total_tokens
|
|
564
|
+
};
|
|
565
|
+
return {
|
|
566
|
+
chunks,
|
|
567
|
+
summary: {
|
|
568
|
+
...plan.summary,
|
|
569
|
+
servedToolCalls
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
}
|
|
490
573
|
async function handleGemini(req, res, raw, model, streaming, fixtures, journal, defaults, setCorsHeaders, providerKey = "gemini") {
|
|
491
574
|
const { logger } = defaults;
|
|
575
|
+
const wire = providerKey === "vertexai" ? "Vertex AI" : "Gemini";
|
|
492
576
|
setCorsHeaders(res);
|
|
493
577
|
let geminiReq;
|
|
494
578
|
try {
|
|
@@ -623,21 +707,101 @@ async function handleGemini(req, res, raw, model, streaming, fixtures, journal,
|
|
|
623
707
|
return;
|
|
624
708
|
}
|
|
625
709
|
const response = await resolveResponse(fixture, completionReq);
|
|
710
|
+
const misbehavior = planMisbehavior({
|
|
711
|
+
wire: "gemini",
|
|
712
|
+
toolCallIdMode: "authored-nonempty",
|
|
713
|
+
fixture,
|
|
714
|
+
response,
|
|
715
|
+
request: completionReq,
|
|
716
|
+
stream: streaming,
|
|
717
|
+
defaults,
|
|
718
|
+
rawHeaders: req.headers,
|
|
719
|
+
url: req.url
|
|
720
|
+
});
|
|
721
|
+
if (misbehavior.kind === "error") {
|
|
722
|
+
recordMisbehaviorOutcome({
|
|
723
|
+
entry: journal.add({
|
|
724
|
+
method: req.method ?? "POST",
|
|
725
|
+
path,
|
|
726
|
+
headers: flattenHeaders(req.headers),
|
|
727
|
+
body: completionReq,
|
|
728
|
+
response: {
|
|
729
|
+
status: misbehavior.status,
|
|
730
|
+
fixture,
|
|
731
|
+
error: misbehavior.message
|
|
732
|
+
}
|
|
733
|
+
}),
|
|
734
|
+
summary: misbehavior.summary,
|
|
735
|
+
defaults,
|
|
736
|
+
testId
|
|
737
|
+
});
|
|
738
|
+
if (misbehavior.summary?.evaluations.length === 0) logger.error(`${req.method ?? "POST"} ${path}: ${misbehavior.message}`);
|
|
739
|
+
writeErrorResponse(res, misbehavior.status, JSON.stringify({ error: {
|
|
740
|
+
code: misbehavior.status,
|
|
741
|
+
message: misbehavior.message,
|
|
742
|
+
status: misbehavior.status === 400 ? "INVALID_ARGUMENT" : "UNIMPLEMENTED"
|
|
743
|
+
} }));
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
626
746
|
const latency = fixture.latency ?? defaults.latency;
|
|
627
747
|
const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
|
|
628
748
|
const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
|
|
629
|
-
if (
|
|
630
|
-
const
|
|
631
|
-
journal.add({
|
|
749
|
+
if (misbehavior.kind === "applied") {
|
|
750
|
+
const prepared = prepareGeminiMisbehavior(misbehavior, completionReq, streaming, chunkSize, logger, resolveStrictMode(defaults.strict, req.headers));
|
|
751
|
+
const entry = journal.add({
|
|
632
752
|
method: req.method ?? "POST",
|
|
633
753
|
path,
|
|
634
754
|
headers: flattenHeaders(req.headers),
|
|
635
755
|
body: completionReq,
|
|
636
756
|
response: {
|
|
637
|
-
status,
|
|
757
|
+
status: 200,
|
|
638
758
|
fixture
|
|
639
759
|
}
|
|
640
760
|
});
|
|
761
|
+
recordMisbehaviorOutcome({
|
|
762
|
+
entry,
|
|
763
|
+
summary: prepared.summary,
|
|
764
|
+
defaults,
|
|
765
|
+
testId
|
|
766
|
+
});
|
|
767
|
+
if (!streaming) {
|
|
768
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
769
|
+
res.end(JSON.stringify(prepared.chunks[0]));
|
|
770
|
+
} else {
|
|
771
|
+
const interruption = createInterruptionSignal(fixture);
|
|
772
|
+
if (!await writeGeminiSSEStream(res, prepared.chunks, {
|
|
773
|
+
latency,
|
|
774
|
+
streamingProfile: fixture.streamingProfile,
|
|
775
|
+
recordedTimings: fixture.recordedTimings,
|
|
776
|
+
replaySpeed,
|
|
777
|
+
signal: interruption?.signal,
|
|
778
|
+
onChunkSent: interruption?.tick
|
|
779
|
+
})) {
|
|
780
|
+
if (!res.writableEnded) res.destroy();
|
|
781
|
+
entry.response.interrupted = true;
|
|
782
|
+
entry.response.interruptReason = interruption?.reason();
|
|
783
|
+
}
|
|
784
|
+
interruption?.cleanup();
|
|
785
|
+
}
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
if (isErrorResponse(response)) {
|
|
789
|
+
const status = response.status ?? 500;
|
|
790
|
+
recordMisbehaviorOutcome({
|
|
791
|
+
entry: journal.add({
|
|
792
|
+
method: req.method ?? "POST",
|
|
793
|
+
path,
|
|
794
|
+
headers: flattenHeaders(req.headers),
|
|
795
|
+
body: completionReq,
|
|
796
|
+
response: {
|
|
797
|
+
status,
|
|
798
|
+
fixture
|
|
799
|
+
}
|
|
800
|
+
}),
|
|
801
|
+
summary: misbehavior.summary,
|
|
802
|
+
defaults,
|
|
803
|
+
testId
|
|
804
|
+
});
|
|
641
805
|
const geminiError = { error: {
|
|
642
806
|
code: status,
|
|
643
807
|
message: response.error.message,
|
|
@@ -659,12 +823,19 @@ async function handleGemini(req, res, raw, model, streaming, fixtures, journal,
|
|
|
659
823
|
fixture
|
|
660
824
|
}
|
|
661
825
|
});
|
|
826
|
+
recordMisbehaviorOutcome({
|
|
827
|
+
entry: journalEntry,
|
|
828
|
+
summary: misbehavior.summary,
|
|
829
|
+
defaults,
|
|
830
|
+
testId
|
|
831
|
+
});
|
|
832
|
+
const audioToolCalls = Array.isArray(response.toolCalls) ? requireServedFunctionToolCalls(response, wire) : [];
|
|
662
833
|
if (!streaming) {
|
|
663
|
-
const body = buildGeminiAudioResponse(response, logger, effReasoning);
|
|
834
|
+
const body = buildGeminiAudioResponse(response, audioToolCalls, logger, effReasoning);
|
|
664
835
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
665
836
|
res.end(JSON.stringify(body));
|
|
666
837
|
} else {
|
|
667
|
-
const chunks = buildGeminiAudioStreamChunks(response, logger, effReasoning);
|
|
838
|
+
const chunks = buildGeminiAudioStreamChunks(response, audioToolCalls, logger, effReasoning);
|
|
668
839
|
const interruption = createInterruptionSignal(fixture);
|
|
669
840
|
if (!await writeGeminiSSEStream(res, chunks, {
|
|
670
841
|
latency,
|
|
@@ -682,7 +853,7 @@ async function handleGemini(req, res, raw, model, streaming, fixtures, journal,
|
|
|
682
853
|
}
|
|
683
854
|
return;
|
|
684
855
|
}
|
|
685
|
-
if (
|
|
856
|
+
if (isCombinedFixtureResponse(response)) {
|
|
686
857
|
if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Gemini API — ignoring");
|
|
687
858
|
const overrides = extractOverrides(response);
|
|
688
859
|
const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);
|
|
@@ -697,12 +868,19 @@ async function handleGemini(req, res, raw, model, streaming, fixtures, journal,
|
|
|
697
868
|
fixture
|
|
698
869
|
}
|
|
699
870
|
});
|
|
871
|
+
recordMisbehaviorOutcome({
|
|
872
|
+
entry: journalEntry,
|
|
873
|
+
summary: misbehavior.summary,
|
|
874
|
+
defaults,
|
|
875
|
+
testId
|
|
876
|
+
});
|
|
877
|
+
const functionToolCalls = requireEmittedFunctionToolCalls(response, wire);
|
|
700
878
|
if (!streaming) {
|
|
701
|
-
const body = buildGeminiContentWithToolCallsResponse(response.content ?? "",
|
|
879
|
+
const body = buildGeminiContentWithToolCallsResponse(response.content ?? "", functionToolCalls, logger, effReasoning, overrides, response.blocks);
|
|
702
880
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
703
881
|
res.end(JSON.stringify(body));
|
|
704
882
|
} else {
|
|
705
|
-
const chunks = buildGeminiContentWithToolCallsStreamChunks(response.content ?? "",
|
|
883
|
+
const chunks = buildGeminiContentWithToolCallsStreamChunks(response.content ?? "", functionToolCalls, chunkSize, logger, effReasoning, overrides, response.blocks);
|
|
706
884
|
const interruption = createInterruptionSignal(fixture);
|
|
707
885
|
if (!await writeGeminiSSEStream(res, chunks, {
|
|
708
886
|
latency,
|
|
@@ -735,6 +913,12 @@ async function handleGemini(req, res, raw, model, streaming, fixtures, journal,
|
|
|
735
913
|
fixture
|
|
736
914
|
}
|
|
737
915
|
});
|
|
916
|
+
recordMisbehaviorOutcome({
|
|
917
|
+
entry: journalEntry,
|
|
918
|
+
summary: misbehavior.summary,
|
|
919
|
+
defaults,
|
|
920
|
+
testId
|
|
921
|
+
});
|
|
738
922
|
if (!streaming) {
|
|
739
923
|
const body = buildGeminiTextResponse(response.content, effReasoning, overrides);
|
|
740
924
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
@@ -773,12 +957,19 @@ async function handleGemini(req, res, raw, model, streaming, fixtures, journal,
|
|
|
773
957
|
fixture
|
|
774
958
|
}
|
|
775
959
|
});
|
|
960
|
+
recordMisbehaviorOutcome({
|
|
961
|
+
entry: journalEntry,
|
|
962
|
+
summary: misbehavior.summary,
|
|
963
|
+
defaults,
|
|
964
|
+
testId
|
|
965
|
+
});
|
|
966
|
+
const functionToolCalls = requireEmittedFunctionToolCalls(response, wire);
|
|
776
967
|
if (!streaming) {
|
|
777
|
-
const body = buildGeminiToolCallResponse(
|
|
968
|
+
const body = buildGeminiToolCallResponse(functionToolCalls, logger, effReasoning, overrides);
|
|
778
969
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
779
970
|
res.end(JSON.stringify(body));
|
|
780
971
|
} else {
|
|
781
|
-
const chunks = buildGeminiToolCallStreamChunks(
|
|
972
|
+
const chunks = buildGeminiToolCallStreamChunks(functionToolCalls, chunkSize, logger, effReasoning, overrides);
|
|
782
973
|
const interruption = createInterruptionSignal(fixture);
|
|
783
974
|
if (!await writeGeminiSSEStream(res, chunks, {
|
|
784
975
|
latency,
|
|
@@ -796,15 +987,20 @@ async function handleGemini(req, res, raw, model, streaming, fixtures, journal,
|
|
|
796
987
|
}
|
|
797
988
|
return;
|
|
798
989
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
990
|
+
recordMisbehaviorOutcome({
|
|
991
|
+
entry: journal.add({
|
|
992
|
+
method: req.method ?? "POST",
|
|
993
|
+
path,
|
|
994
|
+
headers: flattenHeaders(req.headers),
|
|
995
|
+
body: completionReq,
|
|
996
|
+
response: {
|
|
997
|
+
status: 500,
|
|
998
|
+
fixture
|
|
999
|
+
}
|
|
1000
|
+
}),
|
|
1001
|
+
summary: misbehavior.summary,
|
|
1002
|
+
defaults,
|
|
1003
|
+
testId
|
|
808
1004
|
});
|
|
809
1005
|
writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
810
1006
|
message: "Fixture response did not match any known type",
|