@copilotkit/aimock 1.46.0 → 1.47.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 +12 -1
- package/README.md +4 -1
- package/dist/aws-event-stream.cjs +20 -23
- package/dist/aws-event-stream.cjs.map +1 -1
- package/dist/aws-event-stream.d.cts +0 -1
- package/dist/aws-event-stream.d.ts +0 -1
- package/dist/aws-event-stream.js +20 -24
- package/dist/aws-event-stream.js.map +1 -1
- package/dist/bedrock-converse.cjs +79 -82
- 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 +80 -83
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +112 -121
- 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 +113 -122
- package/dist/bedrock.js.map +1 -1
- package/dist/cohere.cjs +58 -106
- 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 +60 -108
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/fixture-loader.cjs +103 -2
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +104 -4
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini-interactions.cjs +63 -121
- 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 +65 -123
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +242 -155
- 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 +244 -157
- package/dist/gemini.js.map +1 -1
- package/dist/helpers.cjs +400 -7
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +51 -1
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts +51 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +391 -8
- package/dist/helpers.js.map +1 -1
- package/dist/index.cjs +4 -2
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/mcp-fakes.d.cts.map +1 -1
- package/dist/messages.cjs +159 -141
- 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 +161 -143
- package/dist/messages.js.map +1 -1
- package/dist/misbehavior.cjs +62 -3
- package/dist/misbehavior.cjs.map +1 -1
- package/dist/misbehavior.d.cts.map +1 -1
- package/dist/misbehavior.d.ts.map +1 -1
- package/dist/misbehavior.js +63 -4
- package/dist/misbehavior.js.map +1 -1
- package/dist/ndjson-writer.cjs +21 -23
- package/dist/ndjson-writer.cjs.map +1 -1
- package/dist/ndjson-writer.d.cts +0 -1
- package/dist/ndjson-writer.d.cts.map +1 -1
- package/dist/ndjson-writer.d.ts +0 -1
- package/dist/ndjson-writer.d.ts.map +1 -1
- package/dist/ndjson-writer.js +21 -24
- package/dist/ndjson-writer.js.map +1 -1
- package/dist/ollama.cjs +153 -147
- 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 +155 -149
- package/dist/ollama.js.map +1 -1
- package/dist/openrouter-chat.cjs +1 -1
- package/dist/openrouter-chat.js +1 -1
- package/dist/raw-validation.cjs +177 -0
- package/dist/raw-validation.cjs.map +1 -0
- package/dist/raw-validation.js +176 -0
- package/dist/raw-validation.js.map +1 -0
- package/dist/response/deliver.cjs +144 -0
- package/dist/response/deliver.cjs.map +1 -0
- package/dist/response/deliver.js +143 -0
- package/dist/response/deliver.js.map +1 -0
- package/dist/response/frame-loop.cjs +102 -0
- package/dist/response/frame-loop.cjs.map +1 -0
- package/dist/response/frame-loop.js +100 -0
- package/dist/response/frame-loop.js.map +1 -0
- package/dist/response/lifecycle.cjs +223 -0
- package/dist/response/lifecycle.cjs.map +1 -0
- package/dist/response/lifecycle.js +211 -0
- package/dist/response/lifecycle.js.map +1 -0
- package/dist/response/proxy.cjs +71 -0
- package/dist/response/proxy.cjs.map +1 -0
- package/dist/response/proxy.js +70 -0
- package/dist/response/proxy.js.map +1 -0
- package/dist/response/raw.cjs +228 -0
- package/dist/response/raw.cjs.map +1 -0
- package/dist/response/raw.js +227 -0
- package/dist/response/raw.js.map +1 -0
- package/dist/response/timing.cjs +157 -0
- package/dist/response/timing.cjs.map +1 -0
- package/dist/response/timing.js +150 -0
- package/dist/response/timing.js.map +1 -0
- package/dist/responses.cjs +269 -148
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +270 -149
- package/dist/responses.js.map +1 -1
- package/dist/router.cjs +20 -4
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts +7 -1
- package/dist/router.d.cts.map +1 -1
- package/dist/router.d.ts +7 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +21 -5
- package/dist/router.js.map +1 -1
- package/dist/server.cjs +89 -120
- 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 +91 -122
- package/dist/server.js.map +1 -1
- package/dist/sse-writer.cjs +49 -30
- package/dist/sse-writer.cjs.map +1 -1
- package/dist/sse-writer.d.cts +0 -1
- package/dist/sse-writer.d.cts.map +1 -1
- package/dist/sse-writer.d.ts +0 -1
- package/dist/sse-writer.d.ts.map +1 -1
- package/dist/sse-writer.js +49 -31
- package/dist/sse-writer.js.map +1 -1
- package/dist/transcription.cjs +19 -33
- 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 +20 -34
- package/dist/transcription.js.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +173 -10
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +173 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/ws-framing.cjs +12 -6
- package/dist/ws-framing.cjs.map +1 -1
- package/dist/ws-framing.d.cts +2 -0
- package/dist/ws-framing.d.cts.map +1 -1
- package/dist/ws-framing.d.ts +2 -0
- package/dist/ws-framing.d.ts.map +1 -1
- package/dist/ws-framing.js +12 -6
- package/dist/ws-framing.js.map +1 -1
- package/dist/ws-gemini-live.cjs +120 -93
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.js +120 -93
- package/dist/ws-gemini-live.js.map +1 -1
- package/dist/ws-realtime.cjs +80 -70
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +80 -70
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +72 -53
- package/dist/ws-responses.cjs.map +1 -1
- package/dist/ws-responses.d.cts.map +1 -1
- package/dist/ws-responses.d.ts.map +1 -1
- package/dist/ws-responses.js +73 -54
- package/dist/ws-responses.js.map +1 -1
- package/package.json +1 -1
- package/skills/write-fixtures/SKILL.md +34 -2
package/dist/bedrock.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { renderError } from "./response/errors.js";
|
|
2
2
|
import { resolveRequestDecisions, strictOverrideField } from "./response/policy.js";
|
|
3
|
-
import { extractOverrides, flattenHeaders, generateMessageId, generateToolUseId, getContext, getTestId, isCombinedFixtureResponse, isErrorResponse, isJsonObject, isTextResponse, isToolCallResponse, requireEmittedFunctionToolCalls, resolveFixtureBlockOutcome, resolveReasoningForModel, resolveResponse, servedToolArgs, strictNoMatchLogLine, strictNoMatchMessage, validateChatMessages, validateToolsField } from "./helpers.js";
|
|
3
|
+
import { extractOverrides, flattenHeaders, generateMessageId, generateToolUseId, getContext, getTestId, isCombinedFixtureResponse, isErrorResponse, isJsonObject, isRawResponse, isTextResponse, isToolCallResponse, requireEmittedFunctionToolCalls, resolveFixtureBlockOutcome, resolveReasoningForModel, resolveResponse, servedToolArgs, strictNoMatchLogLine, strictNoMatchMessage, validateChatMessages, validateToolsField } from "./helpers.js";
|
|
4
4
|
import { writeErrorResponse } from "./sse-writer.js";
|
|
5
5
|
import { applyChaosAsync } from "./chaos.js";
|
|
6
6
|
import { planMisbehavior, recordMisbehaviorOutcome } from "./misbehavior.js";
|
|
7
7
|
import { matchFixtureDiagnostic, recordMatchOptions } from "./router.js";
|
|
8
8
|
import { render, resolve } from "./response/usage/codecs/anthropic.js";
|
|
9
9
|
import { proxyAndRecord } from "./recorder.js";
|
|
10
|
-
import {
|
|
10
|
+
import { misbehaviorPayloadLength, servedPayloadLength } from "./response/timing.js";
|
|
11
|
+
import { deliverJson, deliverStream } from "./response/deliver.js";
|
|
12
|
+
import { proxyInterruption, withHangUpDetection } from "./response/proxy.js";
|
|
13
|
+
import { encodeEventStreamMessage, eventStreamCodec } from "./aws-event-stream.js";
|
|
14
|
+
import { serveRawResponse } from "./response/raw.js";
|
|
11
15
|
import { mapAnthropicFinish } from "./response/finish.js";
|
|
12
16
|
import { prepareClaudeMisbehavior } from "./messages.js";
|
|
13
|
-
import { writeEventStream } from "./aws-event-stream.js";
|
|
14
17
|
|
|
15
18
|
//#region src/bedrock.ts
|
|
16
19
|
function bedrockStopReason(overrideFinishReason, defaultReason) {
|
|
@@ -266,7 +269,10 @@ async function handleBedrock(req, res, raw, modelId, fixtures, journal, defaults
|
|
|
266
269
|
completionReq._endpointType = "chat";
|
|
267
270
|
completionReq._context = getContext(req);
|
|
268
271
|
const testId = getTestId(req);
|
|
269
|
-
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform,
|
|
272
|
+
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform, {
|
|
273
|
+
...recordMatchOptions(!!defaults.record, defaults.logger),
|
|
274
|
+
wire: "bedrock-invoke"
|
|
275
|
+
});
|
|
270
276
|
if (fixture) logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
|
|
271
277
|
else logger.debug(`No fixture matched for request`);
|
|
272
278
|
if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
@@ -299,7 +305,7 @@ async function handleBedrock(req, res, raw, modelId, fixtures, journal, defaults
|
|
|
299
305
|
return;
|
|
300
306
|
}
|
|
301
307
|
if (defaults.record) {
|
|
302
|
-
const outcome = await proxyAndRecord(req, res, completionReq, "bedrock", urlPath, fixtures, defaults, raw);
|
|
308
|
+
const { outcome, clientHungUp } = await withHangUpDetection(req, res, () => proxyAndRecord(req, res, completionReq, "bedrock", urlPath, fixtures, defaults, raw));
|
|
303
309
|
if (outcome === "handled_by_hook") return;
|
|
304
310
|
if (outcome !== "not_configured") {
|
|
305
311
|
journal.add({
|
|
@@ -310,7 +316,8 @@ async function handleBedrock(req, res, raw, modelId, fixtures, journal, defaults
|
|
|
310
316
|
response: {
|
|
311
317
|
status: res.statusCode ?? 200,
|
|
312
318
|
fixture: null,
|
|
313
|
-
source: "proxy"
|
|
319
|
+
source: "proxy",
|
|
320
|
+
...proxyInterruption(res, clientHungUp)
|
|
314
321
|
}
|
|
315
322
|
});
|
|
316
323
|
return;
|
|
@@ -376,32 +383,60 @@ async function handleBedrock(req, res, raw, modelId, fixtures, journal, defaults
|
|
|
376
383
|
writeErrorResponse(res, misbehavior.status, renderedError.body);
|
|
377
384
|
return;
|
|
378
385
|
}
|
|
386
|
+
const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
|
|
387
|
+
const jsonOpts = (payloadLength, duplicateId = false) => ({
|
|
388
|
+
surface: "other",
|
|
389
|
+
payloadLength,
|
|
390
|
+
chunkSize,
|
|
391
|
+
recordedTimings: fixture.recordedTimings,
|
|
392
|
+
duplicateId,
|
|
393
|
+
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed
|
|
394
|
+
});
|
|
379
395
|
if (misbehavior.kind === "applied") {
|
|
380
396
|
const prepared = prepareClaudeMisbehavior(misbehavior, {
|
|
381
397
|
request: completionReq,
|
|
382
398
|
stream: false,
|
|
383
|
-
chunkSize
|
|
399
|
+
chunkSize,
|
|
384
400
|
logger,
|
|
385
|
-
strict: resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression
|
|
401
|
+
strict: resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression,
|
|
402
|
+
citations: false
|
|
386
403
|
});
|
|
387
404
|
if (prepared.stream) throw new TypeError("InvokeModel requires non-stream Claude output");
|
|
405
|
+
const entry = journal.add({
|
|
406
|
+
method: req.method ?? "POST",
|
|
407
|
+
path: urlPath,
|
|
408
|
+
headers: flattenHeaders(req.headers),
|
|
409
|
+
body: completionReq,
|
|
410
|
+
response: {
|
|
411
|
+
status: 200,
|
|
412
|
+
fixture
|
|
413
|
+
}
|
|
414
|
+
});
|
|
388
415
|
recordMisbehaviorOutcome({
|
|
389
|
-
entry
|
|
390
|
-
method: req.method ?? "POST",
|
|
391
|
-
path: urlPath,
|
|
392
|
-
headers: flattenHeaders(req.headers),
|
|
393
|
-
body: completionReq,
|
|
394
|
-
response: {
|
|
395
|
-
status: 200,
|
|
396
|
-
fixture
|
|
397
|
-
}
|
|
398
|
-
}),
|
|
416
|
+
entry,
|
|
399
417
|
summary: prepared.plan.summary,
|
|
400
418
|
defaults,
|
|
401
419
|
testId
|
|
402
420
|
});
|
|
403
|
-
|
|
404
|
-
res
|
|
421
|
+
const preparedBody = prepared.body;
|
|
422
|
+
await deliverJson(res, entry, fixture, () => preparedBody, jsonOpts(misbehaviorPayloadLength(misbehavior, misbehavior.reasoning === void 0 ? prepared.reasoning : void 0), !!misbehavior.duplicateId));
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
if (isRawResponse(response)) {
|
|
426
|
+
await serveRawResponse({
|
|
427
|
+
wire: "bedrock-invoke",
|
|
428
|
+
stream: false,
|
|
429
|
+
req,
|
|
430
|
+
res,
|
|
431
|
+
fixture,
|
|
432
|
+
response,
|
|
433
|
+
body: completionReq,
|
|
434
|
+
journal,
|
|
435
|
+
defaults,
|
|
436
|
+
testId,
|
|
437
|
+
misbehaviorSummary: misbehavior.summary,
|
|
438
|
+
errorWire: "bedrock"
|
|
439
|
+
});
|
|
405
440
|
return;
|
|
406
441
|
}
|
|
407
442
|
if (isErrorResponse(response)) {
|
|
@@ -423,7 +458,7 @@ async function handleBedrock(req, res, raw, modelId, fixtures, journal, defaults
|
|
|
423
458
|
if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock API — ignoring");
|
|
424
459
|
const overrides = extractOverrides(response);
|
|
425
460
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression, logger);
|
|
426
|
-
addResponseEntry({
|
|
461
|
+
const journalEntry = addResponseEntry({
|
|
427
462
|
method: req.method ?? "POST",
|
|
428
463
|
path: urlPath,
|
|
429
464
|
headers: flattenHeaders(req.headers),
|
|
@@ -434,28 +469,27 @@ async function handleBedrock(req, res, raw, modelId, fixtures, journal, defaults
|
|
|
434
469
|
}
|
|
435
470
|
});
|
|
436
471
|
const functionToolCalls = requireEmittedFunctionToolCalls(response, "Bedrock InvokeModel");
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
res
|
|
440
|
-
res.end(JSON.stringify(blocksBody));
|
|
472
|
+
const blocks = response.blocks;
|
|
473
|
+
if (blocks && blocks.length > 0) {
|
|
474
|
+
await deliverJson(res, journalEntry, fixture, () => buildBedrockBlocksResponse(blocks, completionReq.model, logger, effReasoning, overrides), jsonOpts(servedPayloadLength(response, effReasoning)));
|
|
441
475
|
return;
|
|
442
476
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
477
|
+
await deliverJson(res, journalEntry, fixture, () => {
|
|
478
|
+
const textBody = buildBedrockTextResponse(response.content ?? "", completionReq.model, effReasoning, overrides);
|
|
479
|
+
const toolBody = buildBedrockToolCallResponse(functionToolCalls, completionReq.model, logger, void 0, overrides);
|
|
480
|
+
return {
|
|
481
|
+
...textBody,
|
|
482
|
+
content: [...textBody.content, ...toolBody.content],
|
|
483
|
+
stop_reason: bedrockStopReason(overrides?.finishReason, "tool_use")
|
|
484
|
+
};
|
|
485
|
+
}, jsonOpts(servedPayloadLength(response, effReasoning)));
|
|
452
486
|
return;
|
|
453
487
|
}
|
|
454
488
|
if (isTextResponse(response)) {
|
|
455
489
|
if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock API — ignoring");
|
|
456
490
|
const overrides = extractOverrides(response);
|
|
457
491
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression, logger);
|
|
458
|
-
addResponseEntry({
|
|
492
|
+
await deliverJson(res, addResponseEntry({
|
|
459
493
|
method: req.method ?? "POST",
|
|
460
494
|
path: urlPath,
|
|
461
495
|
headers: flattenHeaders(req.headers),
|
|
@@ -464,17 +498,14 @@ async function handleBedrock(req, res, raw, modelId, fixtures, journal, defaults
|
|
|
464
498
|
status: 200,
|
|
465
499
|
fixture
|
|
466
500
|
}
|
|
467
|
-
});
|
|
468
|
-
const body = buildBedrockTextResponse(response.content, completionReq.model, effReasoning, overrides);
|
|
469
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
470
|
-
res.end(JSON.stringify(body));
|
|
501
|
+
}), fixture, () => buildBedrockTextResponse(response.content, completionReq.model, effReasoning, overrides), jsonOpts(servedPayloadLength(response, effReasoning)));
|
|
471
502
|
return;
|
|
472
503
|
}
|
|
473
504
|
if (isToolCallResponse(response)) {
|
|
474
505
|
if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock API — ignoring");
|
|
475
506
|
const overrides = extractOverrides(response);
|
|
476
507
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression, logger);
|
|
477
|
-
addResponseEntry({
|
|
508
|
+
const journalEntry = addResponseEntry({
|
|
478
509
|
method: req.method ?? "POST",
|
|
479
510
|
path: urlPath,
|
|
480
511
|
headers: flattenHeaders(req.headers),
|
|
@@ -484,9 +515,8 @@ async function handleBedrock(req, res, raw, modelId, fixtures, journal, defaults
|
|
|
484
515
|
fixture
|
|
485
516
|
}
|
|
486
517
|
});
|
|
487
|
-
const
|
|
488
|
-
res
|
|
489
|
-
res.end(JSON.stringify(body));
|
|
518
|
+
const functionToolCalls = requireEmittedFunctionToolCalls(response, "Bedrock InvokeModel");
|
|
519
|
+
await deliverJson(res, journalEntry, fixture, () => buildBedrockToolCallResponse(functionToolCalls, completionReq.model, logger, effReasoning, overrides), jsonOpts(servedPayloadLength(response, effReasoning)));
|
|
490
520
|
return;
|
|
491
521
|
}
|
|
492
522
|
addResponseEntry({
|
|
@@ -506,12 +536,7 @@ async function handleBedrock(req, res, raw, modelId, fixtures, journal, defaults
|
|
|
506
536
|
}
|
|
507
537
|
const BEDROCK_INVOKE_STREAM_EVENT_TYPE = "chunk";
|
|
508
538
|
/** Serialize Claude events as InvokeModel PayloadPart, leaving generic AWS framing unchanged. */
|
|
509
|
-
|
|
510
|
-
return writeEventStream(res, events.map((event) => ({
|
|
511
|
-
eventType: event.eventType,
|
|
512
|
-
payload: { bytes: Buffer.from(JSON.stringify(event.payload), "utf8").toString("base64") }
|
|
513
|
-
})), options);
|
|
514
|
-
}
|
|
539
|
+
const bedrockInvokeCodec = eventStreamCodec((event) => encodeEventStreamMessage(event.eventType, { bytes: Buffer.from(JSON.stringify(event.payload), "utf8").toString("base64") }));
|
|
515
540
|
function buildBedrockInvokeMessageStart(model, overrides) {
|
|
516
541
|
return {
|
|
517
542
|
eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
|
|
@@ -1010,7 +1035,10 @@ async function handleBedrockStream(req, res, raw, modelId, fixtures, journal, de
|
|
|
1010
1035
|
completionReq._endpointType = "chat";
|
|
1011
1036
|
completionReq._context = getContext(req);
|
|
1012
1037
|
const testId = getTestId(req);
|
|
1013
|
-
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform,
|
|
1038
|
+
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform, {
|
|
1039
|
+
...recordMatchOptions(!!defaults.record, defaults.logger),
|
|
1040
|
+
wire: "bedrock-invoke"
|
|
1041
|
+
});
|
|
1014
1042
|
if (fixture) logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
|
|
1015
1043
|
else logger.debug(`No fixture matched for request`);
|
|
1016
1044
|
if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
@@ -1043,7 +1071,7 @@ async function handleBedrockStream(req, res, raw, modelId, fixtures, journal, de
|
|
|
1043
1071
|
return;
|
|
1044
1072
|
}
|
|
1045
1073
|
if (defaults.record) {
|
|
1046
|
-
const outcome = await proxyAndRecord(req, res, completionReq, "bedrock", urlPath, fixtures, defaults, raw);
|
|
1074
|
+
const { outcome, clientHungUp } = await withHangUpDetection(req, res, () => proxyAndRecord(req, res, completionReq, "bedrock", urlPath, fixtures, defaults, raw));
|
|
1047
1075
|
if (outcome === "handled_by_hook") return;
|
|
1048
1076
|
if (outcome !== "not_configured") {
|
|
1049
1077
|
journal.add({
|
|
@@ -1054,7 +1082,8 @@ async function handleBedrockStream(req, res, raw, modelId, fixtures, journal, de
|
|
|
1054
1082
|
response: {
|
|
1055
1083
|
status: res.statusCode ?? 200,
|
|
1056
1084
|
fixture: null,
|
|
1057
|
-
source: "proxy"
|
|
1085
|
+
source: "proxy",
|
|
1086
|
+
...proxyInterruption(res, clientHungUp)
|
|
1058
1087
|
}
|
|
1059
1088
|
});
|
|
1060
1089
|
return;
|
|
@@ -1120,15 +1149,21 @@ async function handleBedrockStream(req, res, raw, modelId, fixtures, journal, de
|
|
|
1120
1149
|
writeErrorResponse(res, misbehavior.status, renderedError.body);
|
|
1121
1150
|
return;
|
|
1122
1151
|
}
|
|
1123
|
-
const latency = fixture.latency ?? defaults.latency;
|
|
1124
1152
|
const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
|
|
1153
|
+
const streamTiming = {
|
|
1154
|
+
latency: fixture.latency ?? defaults.latency,
|
|
1155
|
+
streamingProfile: fixture.streamingProfile,
|
|
1156
|
+
recordedTimings: fixture.recordedTimings,
|
|
1157
|
+
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed
|
|
1158
|
+
};
|
|
1125
1159
|
if (misbehavior.kind === "applied") {
|
|
1126
1160
|
const prepared = prepareClaudeMisbehavior(misbehavior, {
|
|
1127
1161
|
request: completionReq,
|
|
1128
1162
|
stream: true,
|
|
1129
1163
|
chunkSize,
|
|
1130
1164
|
logger,
|
|
1131
|
-
strict: resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression
|
|
1165
|
+
strict: resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression,
|
|
1166
|
+
citations: false
|
|
1132
1167
|
});
|
|
1133
1168
|
if (!prepared.stream) throw new TypeError("InvokeModel stream requires Claude events");
|
|
1134
1169
|
const entry = journal.add({
|
|
@@ -1147,27 +1182,27 @@ async function handleBedrockStream(req, res, raw, modelId, fixtures, journal, de
|
|
|
1147
1182
|
defaults,
|
|
1148
1183
|
testId
|
|
1149
1184
|
});
|
|
1150
|
-
|
|
1185
|
+
await deliverStream(res, entry, fixture, bedrockInvokeCodec, prepared.events.map((event) => ({
|
|
1151
1186
|
eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
|
|
1152
1187
|
payload: event
|
|
1153
|
-
}));
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
}
|
|
1188
|
+
})), streamTiming);
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
if (isRawResponse(response)) {
|
|
1192
|
+
await serveRawResponse({
|
|
1193
|
+
wire: "bedrock-invoke",
|
|
1194
|
+
stream: true,
|
|
1195
|
+
req,
|
|
1196
|
+
res,
|
|
1197
|
+
fixture,
|
|
1198
|
+
response,
|
|
1199
|
+
body: completionReq,
|
|
1200
|
+
journal,
|
|
1201
|
+
defaults,
|
|
1202
|
+
testId,
|
|
1203
|
+
misbehaviorSummary: misbehavior.summary,
|
|
1204
|
+
errorWire: "bedrock"
|
|
1205
|
+
});
|
|
1171
1206
|
return;
|
|
1172
1207
|
}
|
|
1173
1208
|
if (isErrorResponse(response)) {
|
|
@@ -1200,28 +1235,14 @@ async function handleBedrockStream(req, res, raw, modelId, fixtures, journal, de
|
|
|
1200
1235
|
}
|
|
1201
1236
|
});
|
|
1202
1237
|
const functionToolCalls = requireEmittedFunctionToolCalls(response, "Bedrock InvokeModel");
|
|
1203
|
-
|
|
1204
|
-
const interruption = createInterruptionSignal(fixture);
|
|
1205
|
-
if (!await writeBedrockInvokeStream(res, events, {
|
|
1206
|
-
latency,
|
|
1207
|
-
streamingProfile: fixture.streamingProfile,
|
|
1208
|
-
recordedTimings: fixture.recordedTimings,
|
|
1209
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
1210
|
-
signal: interruption?.signal,
|
|
1211
|
-
onChunkSent: interruption?.tick
|
|
1212
|
-
})) {
|
|
1213
|
-
if (!res.writableEnded) res.destroy();
|
|
1214
|
-
journalEntry.response.interrupted = true;
|
|
1215
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
1216
|
-
}
|
|
1217
|
-
interruption?.cleanup();
|
|
1238
|
+
await deliverStream(res, journalEntry, fixture, bedrockInvokeCodec, buildBedrockStreamContentWithToolCallsEvents(response.content ?? "", functionToolCalls, completionReq.model, chunkSize, logger, effReasoning, overrides, response.blocks), streamTiming);
|
|
1218
1239
|
return;
|
|
1219
1240
|
}
|
|
1220
1241
|
if (isTextResponse(response)) {
|
|
1221
1242
|
if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock API — ignoring");
|
|
1222
1243
|
const overrides = extractOverrides(response);
|
|
1223
1244
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression, logger);
|
|
1224
|
-
|
|
1245
|
+
await deliverStream(res, addResponseEntry({
|
|
1225
1246
|
method: req.method ?? "POST",
|
|
1226
1247
|
path: urlPath,
|
|
1227
1248
|
headers: flattenHeaders(req.headers),
|
|
@@ -1230,29 +1251,14 @@ async function handleBedrockStream(req, res, raw, modelId, fixtures, journal, de
|
|
|
1230
1251
|
status: 200,
|
|
1231
1252
|
fixture
|
|
1232
1253
|
}
|
|
1233
|
-
});
|
|
1234
|
-
const events = buildBedrockStreamTextEvents(response.content, completionReq.model, chunkSize, effReasoning, overrides);
|
|
1235
|
-
const interruption = createInterruptionSignal(fixture);
|
|
1236
|
-
if (!await writeBedrockInvokeStream(res, events, {
|
|
1237
|
-
latency,
|
|
1238
|
-
streamingProfile: fixture.streamingProfile,
|
|
1239
|
-
recordedTimings: fixture.recordedTimings,
|
|
1240
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
1241
|
-
signal: interruption?.signal,
|
|
1242
|
-
onChunkSent: interruption?.tick
|
|
1243
|
-
})) {
|
|
1244
|
-
if (!res.writableEnded) res.destroy();
|
|
1245
|
-
journalEntry.response.interrupted = true;
|
|
1246
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
1247
|
-
}
|
|
1248
|
-
interruption?.cleanup();
|
|
1254
|
+
}), fixture, bedrockInvokeCodec, buildBedrockStreamTextEvents(response.content, completionReq.model, chunkSize, effReasoning, overrides), streamTiming);
|
|
1249
1255
|
return;
|
|
1250
1256
|
}
|
|
1251
1257
|
if (isToolCallResponse(response)) {
|
|
1252
1258
|
if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock API — ignoring");
|
|
1253
1259
|
const overrides = extractOverrides(response);
|
|
1254
1260
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression, logger);
|
|
1255
|
-
|
|
1261
|
+
await deliverStream(res, addResponseEntry({
|
|
1256
1262
|
method: req.method ?? "POST",
|
|
1257
1263
|
path: urlPath,
|
|
1258
1264
|
headers: flattenHeaders(req.headers),
|
|
@@ -1261,22 +1267,7 @@ async function handleBedrockStream(req, res, raw, modelId, fixtures, journal, de
|
|
|
1261
1267
|
status: 200,
|
|
1262
1268
|
fixture
|
|
1263
1269
|
}
|
|
1264
|
-
});
|
|
1265
|
-
const events = buildBedrockStreamToolCallEvents(requireEmittedFunctionToolCalls(response, "Bedrock InvokeModel"), completionReq.model, chunkSize, logger, effReasoning, overrides);
|
|
1266
|
-
const interruption = createInterruptionSignal(fixture);
|
|
1267
|
-
if (!await writeBedrockInvokeStream(res, events, {
|
|
1268
|
-
latency,
|
|
1269
|
-
streamingProfile: fixture.streamingProfile,
|
|
1270
|
-
recordedTimings: fixture.recordedTimings,
|
|
1271
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
1272
|
-
signal: interruption?.signal,
|
|
1273
|
-
onChunkSent: interruption?.tick
|
|
1274
|
-
})) {
|
|
1275
|
-
if (!res.writableEnded) res.destroy();
|
|
1276
|
-
journalEntry.response.interrupted = true;
|
|
1277
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
1278
|
-
}
|
|
1279
|
-
interruption?.cleanup();
|
|
1270
|
+
}), fixture, bedrockInvokeCodec, buildBedrockStreamToolCallEvents(requireEmittedFunctionToolCalls(response, "Bedrock InvokeModel"), completionReq.model, chunkSize, logger, effReasoning, overrides), streamTiming);
|
|
1280
1271
|
return;
|
|
1281
1272
|
}
|
|
1282
1273
|
addResponseEntry({
|