@copilotkit/aimock 1.44.0 → 1.45.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +42 -0
- package/README.md +6 -0
- package/dist/agui-types.d.cts.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 +216 -17
- 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 +214 -18
- 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/openrouter-video.cjs +30 -2
- 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 +30 -2
- 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 +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
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { extractOverrides, flattenHeaders, generateToolCallId, getContext, getTestId,
|
|
1
|
+
import { extractOverrides, flattenHeaders, generateToolCallId, getContext, getTestId, isCombinedFixtureResponse, isErrorResponse, isJsonObject, isTextResponse, isToolCallResponse, prepareOpenAIChatMisbehavior, requireEmittedFunctionToolCalls, resolveFixtureBlockOutcome, resolveOpenAIChatMisbehaviorUsage, resolveResponse, resolveStrictMode, servedToolArgs, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField } 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 } from "./router.js";
|
|
5
6
|
import { proxyAndRecord } from "./recorder.js";
|
|
6
7
|
import { createInterruptionSignal } from "./interruption.js";
|
|
@@ -215,18 +216,12 @@ function buildInteractionsTextResponse(content, model, interactionId, overrides)
|
|
|
215
216
|
};
|
|
216
217
|
}
|
|
217
218
|
function buildFunctionCallStep(tc, logger) {
|
|
218
|
-
|
|
219
|
-
try {
|
|
220
|
-
argsObj = JSON.parse(tc.arguments || "{}");
|
|
221
|
-
} catch {
|
|
222
|
-
logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
|
|
223
|
-
argsObj = {};
|
|
224
|
-
}
|
|
219
|
+
const args = servedToolArgs(tc, "object", logger);
|
|
225
220
|
return {
|
|
226
221
|
type: "function_call",
|
|
227
222
|
id: tc.id || generateToolCallId(),
|
|
228
223
|
name: tc.name,
|
|
229
|
-
arguments:
|
|
224
|
+
arguments: args.value
|
|
230
225
|
};
|
|
231
226
|
}
|
|
232
227
|
function buildInteractionsToolCallResponse(toolCalls, model, interactionId, logger, overrides) {
|
|
@@ -360,13 +355,7 @@ function buildInteractionsToolCallSSEEvents(toolCalls, interactionId, logger, ov
|
|
|
360
355
|
});
|
|
361
356
|
for (let idx = 0; idx < toolCalls.length; idx++) {
|
|
362
357
|
const tc = toolCalls[idx];
|
|
363
|
-
|
|
364
|
-
try {
|
|
365
|
-
argsObj = JSON.parse(tc.arguments || "{}");
|
|
366
|
-
} catch {
|
|
367
|
-
logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
|
|
368
|
-
argsObj = {};
|
|
369
|
-
}
|
|
358
|
+
const args = servedToolArgs(tc, "string", logger);
|
|
370
359
|
events.push({
|
|
371
360
|
event_type: "step.start",
|
|
372
361
|
index: idx,
|
|
@@ -383,7 +372,7 @@ function buildInteractionsToolCallSSEEvents(toolCalls, interactionId, logger, ov
|
|
|
383
372
|
index: idx,
|
|
384
373
|
delta: {
|
|
385
374
|
type: "arguments_delta",
|
|
386
|
-
arguments:
|
|
375
|
+
arguments: args.text
|
|
387
376
|
},
|
|
388
377
|
event_id: nextEventId()
|
|
389
378
|
});
|
|
@@ -439,13 +428,7 @@ function pushTextStepEvents(events, index, content, chunkSize) {
|
|
|
439
428
|
});
|
|
440
429
|
}
|
|
441
430
|
function pushFunctionCallStepEvents(events, index, tc, logger) {
|
|
442
|
-
|
|
443
|
-
try {
|
|
444
|
-
argsObj = JSON.parse(tc.arguments || "{}");
|
|
445
|
-
} catch {
|
|
446
|
-
logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
|
|
447
|
-
argsObj = {};
|
|
448
|
-
}
|
|
431
|
+
const args = servedToolArgs(tc, "string", logger);
|
|
449
432
|
events.push({
|
|
450
433
|
event_type: "step.start",
|
|
451
434
|
index,
|
|
@@ -462,7 +445,7 @@ function pushFunctionCallStepEvents(events, index, tc, logger) {
|
|
|
462
445
|
index,
|
|
463
446
|
delta: {
|
|
464
447
|
type: "arguments_delta",
|
|
465
|
-
arguments:
|
|
448
|
+
arguments: args.text
|
|
466
449
|
},
|
|
467
450
|
event_id: nextEventId()
|
|
468
451
|
});
|
|
@@ -539,6 +522,35 @@ async function writeGeminiInteractionsSSEStream(res, events, optionsOrLatency) {
|
|
|
539
522
|
if (!res.writableEnded) res.end();
|
|
540
523
|
return true;
|
|
541
524
|
}
|
|
525
|
+
function prepareInteractionsMisbehavior(plan, streaming) {
|
|
526
|
+
if (!streaming && plan.summary.fault === "stop-length-mid-tool") {
|
|
527
|
+
const response = plan.response;
|
|
528
|
+
const combined = isCombinedFixtureResponse(response);
|
|
529
|
+
const outcome = combined && response.blocks?.length ? resolveFixtureBlockOutcome(response.blocks) : void 0;
|
|
530
|
+
const toolCalls = (outcome?.toolCalls ?? (combined || isToolCallResponse(response) ? response.toolCalls ?? [] : [])).filter((_, index) => index !== plan.target?.index);
|
|
531
|
+
let callIndex = 0;
|
|
532
|
+
const blocks = outcome?.ordered.filter((block) => block.type === "text" || callIndex++ !== plan.target?.index);
|
|
533
|
+
plan = {
|
|
534
|
+
...plan,
|
|
535
|
+
response: {
|
|
536
|
+
...response,
|
|
537
|
+
toolCalls,
|
|
538
|
+
...blocks ? { blocks } : {}
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
return prepareOpenAIChatMisbehavior(plan);
|
|
543
|
+
}
|
|
544
|
+
function finalizeInteractionsMisbehavior(events, plan) {
|
|
545
|
+
if (plan.kind !== "applied" || plan.summary.fault !== "stop-length-mid-tool") return events;
|
|
546
|
+
return events.map((event) => event.event_type === "interaction.completed" && isJsonObject(event.interaction) ? {
|
|
547
|
+
...event,
|
|
548
|
+
interaction: {
|
|
549
|
+
...event.interaction,
|
|
550
|
+
status: "incomplete"
|
|
551
|
+
}
|
|
552
|
+
} : event);
|
|
553
|
+
}
|
|
542
554
|
async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaults, setCorsHeaders) {
|
|
543
555
|
const { logger } = defaults;
|
|
544
556
|
setCorsHeaders(res);
|
|
@@ -655,29 +667,172 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
|
|
|
655
667
|
writeErrorResponse(res, 404, JSON.stringify(buildInteractionsErrorResponse("No fixture matched", "NOT_FOUND")));
|
|
656
668
|
return;
|
|
657
669
|
}
|
|
658
|
-
|
|
670
|
+
let response = await resolveResponse(fixture, completionReq);
|
|
671
|
+
let misbehavior = planMisbehavior({
|
|
672
|
+
wire: "gemini-interactions",
|
|
673
|
+
fixture,
|
|
674
|
+
response,
|
|
675
|
+
request: completionReq,
|
|
676
|
+
stream: streaming,
|
|
677
|
+
emitsToolCallIds: true,
|
|
678
|
+
defaults,
|
|
679
|
+
rawHeaders: req.headers,
|
|
680
|
+
url: req.url
|
|
681
|
+
});
|
|
682
|
+
if (misbehavior.kind === "error") {
|
|
683
|
+
recordMisbehaviorOutcome({
|
|
684
|
+
entry: journal.add({
|
|
685
|
+
method: req.method ?? "POST",
|
|
686
|
+
path: urlPath,
|
|
687
|
+
headers: flattenHeaders(req.headers),
|
|
688
|
+
body: completionReq,
|
|
689
|
+
response: {
|
|
690
|
+
status: misbehavior.status,
|
|
691
|
+
fixture
|
|
692
|
+
}
|
|
693
|
+
}),
|
|
694
|
+
summary: misbehavior.summary,
|
|
695
|
+
defaults,
|
|
696
|
+
testId
|
|
697
|
+
});
|
|
698
|
+
if (!misbehavior.summary?.evaluations.some((evaluation) => evaluation.outcome === "error")) logger.error(`${req.method ?? "POST"} ${urlPath}: ${misbehavior.message}`);
|
|
699
|
+
writeErrorResponse(res, misbehavior.status, JSON.stringify(buildInteractionsErrorResponse(misbehavior.message, misbehavior.code)));
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
if (misbehavior.kind === "applied") {
|
|
703
|
+
misbehavior = prepareInteractionsMisbehavior(misbehavior, streaming);
|
|
704
|
+
response = misbehavior.response;
|
|
705
|
+
}
|
|
706
|
+
const appliedUsage = misbehavior.kind === "applied" ? resolveOpenAIChatMisbehaviorUsage(misbehavior, completionReq) : void 0;
|
|
659
707
|
const latency = fixture.latency ?? defaults.latency;
|
|
660
708
|
const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
|
|
661
709
|
const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
|
|
662
710
|
if (isErrorResponse(response)) {
|
|
663
711
|
const status = response.status ?? 500;
|
|
664
|
-
|
|
712
|
+
recordMisbehaviorOutcome({
|
|
713
|
+
entry: journal.add({
|
|
714
|
+
method: req.method ?? "POST",
|
|
715
|
+
path: urlPath,
|
|
716
|
+
headers: flattenHeaders(req.headers),
|
|
717
|
+
body: completionReq,
|
|
718
|
+
response: {
|
|
719
|
+
status,
|
|
720
|
+
fixture
|
|
721
|
+
}
|
|
722
|
+
}),
|
|
723
|
+
summary: misbehavior.summary,
|
|
724
|
+
defaults,
|
|
725
|
+
testId
|
|
726
|
+
});
|
|
727
|
+
writeErrorResponse(res, status, JSON.stringify(buildInteractionsErrorResponse(response.error.message, response.error.type ?? "ERROR")), { retryAfter: response.retryAfter });
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
if (misbehavior.kind === "applied" && misbehavior.summary.fault === "reasoning-only") {
|
|
731
|
+
const journalEntry = journal.add({
|
|
665
732
|
method: req.method ?? "POST",
|
|
666
733
|
path: urlPath,
|
|
667
734
|
headers: flattenHeaders(req.headers),
|
|
668
735
|
body: completionReq,
|
|
669
736
|
response: {
|
|
670
|
-
status,
|
|
737
|
+
status: 200,
|
|
671
738
|
fixture
|
|
672
739
|
}
|
|
673
740
|
});
|
|
674
|
-
|
|
741
|
+
recordMisbehaviorOutcome({
|
|
742
|
+
entry: journalEntry,
|
|
743
|
+
summary: misbehavior.summary,
|
|
744
|
+
defaults,
|
|
745
|
+
testId
|
|
746
|
+
});
|
|
747
|
+
const interactionId = nextInteractionId();
|
|
748
|
+
const usage = {
|
|
749
|
+
...interactionsUsage({ usage: appliedUsage }),
|
|
750
|
+
total_output_tokens: 0,
|
|
751
|
+
total_thought_tokens: appliedUsage?.completion_tokens ?? 0
|
|
752
|
+
};
|
|
753
|
+
if (!streaming) {
|
|
754
|
+
const overrides = isTextResponse(response) || isToolCallResponse(response) || isCombinedFixtureResponse(response) ? extractOverrides(response) : void 0;
|
|
755
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
756
|
+
res.end(JSON.stringify({
|
|
757
|
+
id: interactionId,
|
|
758
|
+
model: overrides?.model ?? model,
|
|
759
|
+
status: "incomplete",
|
|
760
|
+
steps: [{
|
|
761
|
+
type: "thought",
|
|
762
|
+
signature: "",
|
|
763
|
+
summary: [{
|
|
764
|
+
type: "text",
|
|
765
|
+
text: misbehavior.reasoning ?? ""
|
|
766
|
+
}]
|
|
767
|
+
}],
|
|
768
|
+
usage
|
|
769
|
+
}));
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
const events = [
|
|
773
|
+
{
|
|
774
|
+
event_type: "interaction.created",
|
|
775
|
+
interaction: {
|
|
776
|
+
id: interactionId,
|
|
777
|
+
status: "in_progress"
|
|
778
|
+
},
|
|
779
|
+
event_id: nextEventId()
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
event_type: "step.start",
|
|
783
|
+
index: 0,
|
|
784
|
+
step: { type: "thought" },
|
|
785
|
+
event_id: nextEventId()
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
event_type: "step.delta",
|
|
789
|
+
index: 0,
|
|
790
|
+
delta: {
|
|
791
|
+
type: "thought_summary",
|
|
792
|
+
content: {
|
|
793
|
+
type: "text",
|
|
794
|
+
text: misbehavior.reasoning ?? ""
|
|
795
|
+
}
|
|
796
|
+
},
|
|
797
|
+
event_id: nextEventId()
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
event_type: "step.stop",
|
|
801
|
+
index: 0,
|
|
802
|
+
event_id: nextEventId()
|
|
803
|
+
},
|
|
804
|
+
{
|
|
805
|
+
event_type: "interaction.completed",
|
|
806
|
+
interaction: {
|
|
807
|
+
id: interactionId,
|
|
808
|
+
status: "incomplete",
|
|
809
|
+
usage
|
|
810
|
+
},
|
|
811
|
+
event_id: nextEventId()
|
|
812
|
+
}
|
|
813
|
+
];
|
|
814
|
+
const interruption = createInterruptionSignal(fixture);
|
|
815
|
+
if (!await writeGeminiInteractionsSSEStream(res, events, {
|
|
816
|
+
latency,
|
|
817
|
+
streamingProfile: fixture.streamingProfile,
|
|
818
|
+
recordedTimings: fixture.recordedTimings,
|
|
819
|
+
replaySpeed,
|
|
820
|
+
signal: interruption?.signal,
|
|
821
|
+
onChunkSent: interruption?.tick
|
|
822
|
+
})) {
|
|
823
|
+
if (!res.writableEnded) res.destroy();
|
|
824
|
+
journalEntry.response.interrupted = true;
|
|
825
|
+
journalEntry.response.interruptReason = interruption?.reason();
|
|
826
|
+
}
|
|
827
|
+
interruption?.cleanup();
|
|
675
828
|
return;
|
|
676
829
|
}
|
|
677
|
-
|
|
678
|
-
if (isContentWithToolCallsResponse(response)) {
|
|
830
|
+
if (isCombinedFixtureResponse(response)) {
|
|
679
831
|
if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Gemini Interactions API — ignoring");
|
|
680
|
-
const overrides =
|
|
832
|
+
const overrides = {
|
|
833
|
+
...extractOverrides(response),
|
|
834
|
+
...appliedUsage ? { usage: appliedUsage } : {}
|
|
835
|
+
};
|
|
681
836
|
const journalEntry = journal.add({
|
|
682
837
|
method: req.method ?? "POST",
|
|
683
838
|
path: urlPath,
|
|
@@ -688,14 +843,25 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
|
|
|
688
843
|
fixture
|
|
689
844
|
}
|
|
690
845
|
});
|
|
846
|
+
recordMisbehaviorOutcome({
|
|
847
|
+
entry: journalEntry,
|
|
848
|
+
summary: misbehavior.summary,
|
|
849
|
+
defaults,
|
|
850
|
+
testId
|
|
851
|
+
});
|
|
852
|
+
const functionToolCalls = requireEmittedFunctionToolCalls(response, "Gemini Interactions");
|
|
853
|
+
const interactionId = nextInteractionId();
|
|
691
854
|
if (!streaming) {
|
|
692
|
-
const body = buildInteractionsContentWithToolCallsResponse(response.content ?? "",
|
|
855
|
+
const body = buildInteractionsContentWithToolCallsResponse(response.content ?? "", functionToolCalls, model, interactionId, logger, overrides, response.blocks);
|
|
693
856
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
694
|
-
res.end(JSON.stringify(
|
|
857
|
+
res.end(JSON.stringify(misbehavior.kind === "applied" && misbehavior.summary.fault === "stop-length-mid-tool" ? {
|
|
858
|
+
...body,
|
|
859
|
+
status: "incomplete"
|
|
860
|
+
} : body));
|
|
695
861
|
} else {
|
|
696
|
-
const events = buildInteractionsContentWithToolCallsSSEEvents(response.content ?? "",
|
|
862
|
+
const events = buildInteractionsContentWithToolCallsSSEEvents(response.content ?? "", functionToolCalls, interactionId, chunkSize, logger, overrides, response.blocks);
|
|
697
863
|
const interruption = createInterruptionSignal(fixture);
|
|
698
|
-
if (!await writeGeminiInteractionsSSEStream(res, events, {
|
|
864
|
+
if (!await writeGeminiInteractionsSSEStream(res, finalizeInteractionsMisbehavior(events, misbehavior), {
|
|
699
865
|
latency,
|
|
700
866
|
streamingProfile: fixture.streamingProfile,
|
|
701
867
|
recordedTimings: fixture.recordedTimings,
|
|
@@ -713,7 +879,10 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
|
|
|
713
879
|
}
|
|
714
880
|
if (isTextResponse(response)) {
|
|
715
881
|
if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Gemini Interactions API — ignoring");
|
|
716
|
-
const overrides =
|
|
882
|
+
const overrides = {
|
|
883
|
+
...extractOverrides(response),
|
|
884
|
+
...appliedUsage ? { usage: appliedUsage } : {}
|
|
885
|
+
};
|
|
717
886
|
const journalEntry = journal.add({
|
|
718
887
|
method: req.method ?? "POST",
|
|
719
888
|
path: urlPath,
|
|
@@ -724,14 +893,24 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
|
|
|
724
893
|
fixture
|
|
725
894
|
}
|
|
726
895
|
});
|
|
896
|
+
recordMisbehaviorOutcome({
|
|
897
|
+
entry: journalEntry,
|
|
898
|
+
summary: misbehavior.summary,
|
|
899
|
+
defaults,
|
|
900
|
+
testId
|
|
901
|
+
});
|
|
902
|
+
const interactionId = nextInteractionId();
|
|
727
903
|
if (!streaming) {
|
|
728
904
|
const body = buildInteractionsTextResponse(response.content, model, interactionId, overrides);
|
|
729
905
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
730
|
-
res.end(JSON.stringify(
|
|
906
|
+
res.end(JSON.stringify(misbehavior.kind === "applied" && misbehavior.summary.fault === "stop-length-mid-tool" ? {
|
|
907
|
+
...body,
|
|
908
|
+
status: "incomplete"
|
|
909
|
+
} : body));
|
|
731
910
|
} else {
|
|
732
911
|
const events = buildInteractionsTextSSEEvents(response.content, interactionId, chunkSize, overrides);
|
|
733
912
|
const interruption = createInterruptionSignal(fixture);
|
|
734
|
-
if (!await writeGeminiInteractionsSSEStream(res, events, {
|
|
913
|
+
if (!await writeGeminiInteractionsSSEStream(res, finalizeInteractionsMisbehavior(events, misbehavior), {
|
|
735
914
|
latency,
|
|
736
915
|
streamingProfile: fixture.streamingProfile,
|
|
737
916
|
recordedTimings: fixture.recordedTimings,
|
|
@@ -749,7 +928,10 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
|
|
|
749
928
|
}
|
|
750
929
|
if (isToolCallResponse(response)) {
|
|
751
930
|
if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Gemini Interactions API — ignoring");
|
|
752
|
-
const overrides =
|
|
931
|
+
const overrides = {
|
|
932
|
+
...extractOverrides(response),
|
|
933
|
+
...appliedUsage ? { usage: appliedUsage } : {}
|
|
934
|
+
};
|
|
753
935
|
const journalEntry = journal.add({
|
|
754
936
|
method: req.method ?? "POST",
|
|
755
937
|
path: urlPath,
|
|
@@ -760,14 +942,25 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
|
|
|
760
942
|
fixture
|
|
761
943
|
}
|
|
762
944
|
});
|
|
945
|
+
recordMisbehaviorOutcome({
|
|
946
|
+
entry: journalEntry,
|
|
947
|
+
summary: misbehavior.summary,
|
|
948
|
+
defaults,
|
|
949
|
+
testId
|
|
950
|
+
});
|
|
951
|
+
const functionToolCalls = requireEmittedFunctionToolCalls(response, "Gemini Interactions");
|
|
952
|
+
const interactionId = nextInteractionId();
|
|
763
953
|
if (!streaming) {
|
|
764
|
-
const body = buildInteractionsToolCallResponse(
|
|
954
|
+
const body = buildInteractionsToolCallResponse(functionToolCalls, model, interactionId, logger, overrides);
|
|
765
955
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
766
|
-
res.end(JSON.stringify(
|
|
956
|
+
res.end(JSON.stringify(misbehavior.kind === "applied" && misbehavior.summary.fault === "stop-length-mid-tool" ? {
|
|
957
|
+
...body,
|
|
958
|
+
status: "incomplete"
|
|
959
|
+
} : body));
|
|
767
960
|
} else {
|
|
768
|
-
const events = buildInteractionsToolCallSSEEvents(
|
|
961
|
+
const events = buildInteractionsToolCallSSEEvents(functionToolCalls, interactionId, logger, overrides);
|
|
769
962
|
const interruption = createInterruptionSignal(fixture);
|
|
770
|
-
if (!await writeGeminiInteractionsSSEStream(res, events, {
|
|
963
|
+
if (!await writeGeminiInteractionsSSEStream(res, finalizeInteractionsMisbehavior(events, misbehavior), {
|
|
771
964
|
latency,
|
|
772
965
|
streamingProfile: fixture.streamingProfile,
|
|
773
966
|
recordedTimings: fixture.recordedTimings,
|
|
@@ -783,15 +976,20 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
|
|
|
783
976
|
}
|
|
784
977
|
return;
|
|
785
978
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
979
|
+
recordMisbehaviorOutcome({
|
|
980
|
+
entry: journal.add({
|
|
981
|
+
method: req.method ?? "POST",
|
|
982
|
+
path: urlPath,
|
|
983
|
+
headers: flattenHeaders(req.headers),
|
|
984
|
+
body: completionReq,
|
|
985
|
+
response: {
|
|
986
|
+
status: 500,
|
|
987
|
+
fixture
|
|
988
|
+
}
|
|
989
|
+
}),
|
|
990
|
+
summary: misbehavior.summary,
|
|
991
|
+
defaults,
|
|
992
|
+
testId
|
|
795
993
|
});
|
|
796
994
|
writeErrorResponse(res, 500, JSON.stringify(buildInteractionsErrorResponse("Fixture response did not match any known type", "INTERNAL")));
|
|
797
995
|
}
|