@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/server.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.cts","names":[],"sources":["../src/server.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;AA8X+B,UAAd,cAAA,CAAc;mBAEhB,CAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;QACJ,EADD,MAAA,CAAK,MACJ;SAEC,EAFD,OAEC;KACG,EAAA,MAAA;UACQ,EAFX,eAEW;aACP,EAFD,aAEC;qBACC,EAFM,qBAEN;cACI,EAFL,cAEK;EAAmB,aAAA,EADvB,eACuB;
|
|
1
|
+
{"version":3,"file":"server.d.cts","names":[],"sources":["../src/server.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;AA8X+B,UAAd,cAAA,CAAc;mBAEhB,CAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;QACJ,EADD,MAAA,CAAK,MACJ;SAEC,EAFD,OAEC;KACG,EAAA,MAAA;UACQ,EAFX,eAEW;aACP,EAFD,aAEC;qBACC,EAFM,qBAEN;cACI,EAFL,cAEK;EAAmB,aAAA,EADvB,eACuB;EA88EvB,iBAAA,EA98EI,mBA88EW;;;;;;;;UAAf,eAAA;UACP;UACA;cACI;;aAED;;iBAMS,YAAA,WACV,qBACA,4BACD;;WAA+B;sBACtB,kBACjB,QAAQ"}
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","names":[],"sources":["../src/server.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;AA8X+B,UAAd,cAAA,CAAc;mBAEhB,CAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;QACJ,EADD,MAAA,CAAK,MACJ;SAEC,EAFD,OAEC;KACG,EAAA,MAAA;UACQ,EAFX,eAEW;aACP,EAFD,aAEC;qBACC,EAFM,qBAEN;cACI,EAFL,cAEK;EAAmB,aAAA,EADvB,eACuB;
|
|
1
|
+
{"version":3,"file":"server.d.ts","names":[],"sources":["../src/server.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;AA8X+B,UAAd,cAAA,CAAc;mBAEhB,CAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;QACJ,EADD,MAAA,CAAK,MACJ;SAEC,EAFD,OAEC;KACG,EAAA,MAAA;UACQ,EAFX,eAEW;aACP,EAFD,aAEC;qBACC,EAFM,qBAEN;cACI,EAFL,cAEK;EAAmB,aAAA,EADvB,eACuB;EA88EvB,iBAAA,EA98EI,mBA88EW;;;;;;;;UAAf,eAAA;UACP;UACA;cACI;;aAED;;iBAMS,YAAA,WACV,qBACA,4BACD;;WAA+B;sBACtB,kBACjB,QAAQ"}
|
package/dist/server.js
CHANGED
|
@@ -4,9 +4,9 @@ import { DEFAULT_TEST_ID } from "./constants.js";
|
|
|
4
4
|
import { build, msg, quote } from "./message-text.js";
|
|
5
5
|
import { markAuthenticatedRequest, resolveInboundAuth, validateRequestApiKey, writeApiKeyHttpRejection, writeApiKeyUpgradeRejection } from "./api-key-auth.js";
|
|
6
6
|
import { parsePolicy, resolvePolicy, resolveRequestDecisions, strictOverrideField } from "./response/policy.js";
|
|
7
|
-
import { RequestBodyTooLargeError, buildContentWithToolCallsChunks, buildContentWithToolCallsCompletion, buildOpenAIContentFilterChunks, buildOpenAIContentFilterCompletion, buildOpenAIReasoningChunks, buildOpenAIReasoningCompletion, buildOpenAIRefusalChunks, buildOpenAIRefusalCompletion, buildTextChunks, buildTextCompletion, buildToolCallChunks, buildToolCallCompletion, buildUsageChunk, createServerFixtureList, describeMatch, extractOverrides, fixtureToolCallErrorCode, flattenHeaders, getContext, getTestId, googleFixtureToolCallErrorDetails, isAudioResponse, isCombinedFixtureResponse, isEmbeddingResponse, isErrorResponse, isExtendedResponsesToolsList, isFixtureToolCallError, isImageResponse, isJSONResponse, isJsonObject, isResponseFactory, isServerOwnedFixtures, isTextResponse, isToolCallResponse, isTranscriptionResponse, isVideoResponse, markMintedRequestId, prepareOpenAIChatMisbehavior, readBody, readBodyBufferBounded, requireEmittedFunctionToolCalls, requireServedFunctionToolCalls, resolveFixtureBlockOutcome, resolveOpenAIChatMisbehaviorUsage, resolveReasoningForModel, resolveRequestId, resolveResponse, resolveTestId, resolveUsage, runWithToolArgumentsScope, serializeErrorResponse, strictNoMatchLogLine, strictNoMatchMessage, validateToolsField, withoutResponsesToolKeys, wouldProxyMiss } from "./helpers.js";
|
|
7
|
+
import { RequestBodyTooLargeError, buildContentWithToolCallsChunks, buildContentWithToolCallsCompletion, buildOpenAIContentFilterChunks, buildOpenAIContentFilterCompletion, buildOpenAIReasoningChunks, buildOpenAIReasoningCompletion, buildOpenAIRefusalChunks, buildOpenAIRefusalCompletion, buildTextChunks, buildTextCompletion, buildToolCallChunks, buildToolCallCompletion, buildUsageChunk, createServerFixtureList, describeMatch, extractOverrides, fixtureToolCallErrorCode, flattenHeaders, getContext, getTestId, googleFixtureToolCallErrorDetails, isAudioResponse, isCombinedFixtureResponse, isEmbeddingResponse, isErrorResponse, isExtendedResponsesToolsList, isFixtureToolCallError, isImageResponse, isJSONResponse, isJsonObject, isRawResponse, isResponseFactory, isServerOwnedFixtures, isTextResponse, isToolCallResponse, isTranscriptionResponse, isVideoResponse, markMintedRequestId, prepareOpenAIChatMisbehavior, readBody, readBodyBufferBounded, rejectGeneratedFiles, requireEmittedFunctionToolCalls, requireServedFunctionToolCalls, resolveFixtureBlockOutcome, resolveOpenAIChatMisbehaviorUsage, resolveReasoningForModel, resolveRequestId, resolveResponse, resolveTestId, resolveUsage, runWithToolArgumentsScope, serializeErrorResponse, strictNoMatchLogLine, strictNoMatchMessage, validateToolsField, withoutResponsesToolKeys, wouldProxyMiss } from "./helpers.js";
|
|
8
8
|
import { normalizeLiveOptions } from "./live-fixture.js";
|
|
9
|
-
import {
|
|
9
|
+
import { sseCodec, writeErrorResponse } from "./sse-writer.js";
|
|
10
10
|
import { CHAOS_FIELDS, CHAOS_FIELD_NAMES, applyChaosAction, awaitChaosLatency, describeUnwritableReason, evaluateChaos, isChaosScope, parseChaosField, resetChaosWarnings, resolveChaosConfig, responseGoneReason } from "./chaos.js";
|
|
11
11
|
import { MISBEHAVIOR_CATALOG, WIRE_SUPPORT, getFixtureMisbehaviorPosition, parseMisbehavior, parseMisbehaviorHeader, planMisbehavior, recordMisbehaviorOutcome, resolveMisbehaviorSeed, resolveMisbehaviorShortCircuit, setFixtureMisbehaviorPosition } from "./misbehavior.js";
|
|
12
12
|
import { FixtureLoadError, INJECTED_STATUS_RANGE, MisbehaviorConfigError, claimOneShotError, clearFixtureQueue, enableHeldFixtureMisbehavior, entryToFixture, isInjectableStatus, isOneShotError, markFixtureResponsesToolsExtended, queueOneShotError, releaseOneShotError, responsesToolsExtendedView, responsesToolsViewSource, validateFixtures } from "./fixture-loader.js";
|
|
@@ -14,12 +14,16 @@ import { matchFixtureDiagnostic, recordMatchOptions } from "./router.js";
|
|
|
14
14
|
import { proxyAndRecord } from "./recorder.js";
|
|
15
15
|
import { Logger } from "./logger.js";
|
|
16
16
|
import { Journal } from "./journal.js";
|
|
17
|
-
import {
|
|
17
|
+
import { CLIENT_ABORTED } from "./response/lifecycle.js";
|
|
18
|
+
import { extendRecordedTimings, misbehaviorPayloadLength } from "./response/timing.js";
|
|
19
|
+
import { deliverJson, deliverStream } from "./response/deliver.js";
|
|
20
|
+
import { proxyInterruption, withHangUpDetection } from "./response/proxy.js";
|
|
18
21
|
import { collect, idsFor } from "./response/catalog/collect.js";
|
|
19
|
-
import { anthropicPage } from "./response/catalog/anthropic-page.js";
|
|
20
|
-
import { geminiPage } from "./response/catalog/gemini-page.js";
|
|
21
22
|
import { coreModelIds, renderAnthropicModel, renderAnthropicModels, renderGeminiModel, renderGeminiModels, renderOllamaTags, renderOpenAIModel, renderOpenAIModels } from "./response/catalog/render.js";
|
|
22
23
|
import { buildOpenRouterCandidates, handleOpenRouterCredits, handleOpenRouterKey, handleOpenRouterModels, isOpenRouterPath, resolveOpenRouterShaping, serializeOpenRouterError, shapeOpenRouterChunks, shapeOpenRouterCompletion } from "./openrouter-chat.js";
|
|
24
|
+
import { serveRawResponse } from "./response/raw.js";
|
|
25
|
+
import { anthropicPage } from "./response/catalog/anthropic-page.js";
|
|
26
|
+
import { geminiPage } from "./response/catalog/gemini-page.js";
|
|
23
27
|
import { handleResponses } from "./responses.js";
|
|
24
28
|
import { handleMessages } from "./messages.js";
|
|
25
29
|
import { handleGemini } from "./gemini.js";
|
|
@@ -211,6 +215,7 @@ function fixtureResponseKind(response) {
|
|
|
211
215
|
if (isCombinedFixtureResponse(response)) return "contentWithToolCalls";
|
|
212
216
|
if (isToolCallResponse(response)) return "toolCalls";
|
|
213
217
|
if (isTextResponse(response)) return "text";
|
|
218
|
+
if (isRawResponse(response)) return "raw";
|
|
214
219
|
return "unknown";
|
|
215
220
|
}
|
|
216
221
|
/**
|
|
@@ -896,7 +901,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
896
901
|
const clientAbort = clientAbortedMidBody(req, res, err);
|
|
897
902
|
const bodyLimitDisconnect = clientFault && (req.destroyed || res.destroyed);
|
|
898
903
|
if (clientAbort || bodyLimitDisconnect) {
|
|
899
|
-
const interruptReason = bodyLimitDisconnect ? "request body exceeded size limit" :
|
|
904
|
+
const interruptReason = bodyLimitDisconnect ? "request body exceeded size limit" : CLIENT_ABORTED;
|
|
900
905
|
defaults.logger.warn(bodyLimitDisconnect ? `${route}: ${msg}` : `${route}: client aborted mid-body (${msg})`);
|
|
901
906
|
journal.add({
|
|
902
907
|
method: req.method ?? "POST",
|
|
@@ -1045,7 +1050,10 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
1045
1050
|
body._endpointType = "chat";
|
|
1046
1051
|
body._context = getContext(req);
|
|
1047
1052
|
const testId = getTestId(req);
|
|
1048
|
-
const matchOptions =
|
|
1053
|
+
const matchOptions = {
|
|
1054
|
+
...recordMatchOptions(!!(defaults.record && providerKey), defaults.logger),
|
|
1055
|
+
wire: "openai-chat"
|
|
1056
|
+
};
|
|
1049
1057
|
let fixture = null;
|
|
1050
1058
|
let skippedBySequenceOrTurn = 0;
|
|
1051
1059
|
let preResolvedResponse = null;
|
|
@@ -1075,10 +1083,11 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
1075
1083
|
skippedBySequenceOrTurn = Math.max(skippedBySequenceOrTurn, attempt.skippedBySequenceOrTurn);
|
|
1076
1084
|
if (!attempt.fixture) return null;
|
|
1077
1085
|
const response = await resolveResponse(attempt.fixture, probe);
|
|
1086
|
+
const isError = isErrorResponse(response) || isRawResponse(response) && (response.raw.status ?? 200) >= 400;
|
|
1078
1087
|
return {
|
|
1079
1088
|
fixture: attempt.fixture,
|
|
1080
1089
|
response,
|
|
1081
|
-
isError
|
|
1090
|
+
isError
|
|
1082
1091
|
};
|
|
1083
1092
|
};
|
|
1084
1093
|
for (const candidate of candidates) {
|
|
@@ -1092,7 +1101,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
1092
1101
|
matchCounts = journal.getFixtureMatchCountsForTest(testId);
|
|
1093
1102
|
responseModel = candidate;
|
|
1094
1103
|
if (outcome.isError) {
|
|
1095
|
-
const errorFallsThrough = outcome.response.fallthrough !== false;
|
|
1104
|
+
const errorFallsThrough = !isErrorResponse(outcome.response) || outcome.response.fallthrough !== false;
|
|
1096
1105
|
if (allowFallbacks && errorFallsThrough) {
|
|
1097
1106
|
lastErrorFixture = outcome.fixture;
|
|
1098
1107
|
lastErrorResponse = outcome.response;
|
|
@@ -1209,22 +1218,9 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
1209
1218
|
});
|
|
1210
1219
|
}
|
|
1211
1220
|
} : void 0;
|
|
1212
|
-
|
|
1213
|
-
const noteClientHangUp = () => {
|
|
1214
|
-
if (!res.writableEnded) clientHungUp = true;
|
|
1215
|
-
};
|
|
1216
|
-
req.socket?.on("end", noteClientHangUp);
|
|
1217
|
-
req.socket?.on("error", noteClientHangUp);
|
|
1218
|
-
let outcome;
|
|
1219
|
-
try {
|
|
1220
|
-
outcome = await proxyAndRecord(req, res, body, providerKey, req.url ?? COMPLETIONS_PATH, fixtures, defaults, raw, hookOptions);
|
|
1221
|
-
} finally {
|
|
1222
|
-
req.socket?.off("end", noteClientHangUp);
|
|
1223
|
-
req.socket?.off("error", noteClientHangUp);
|
|
1224
|
-
}
|
|
1221
|
+
const { outcome, clientHungUp } = await withHangUpDetection(req, res, () => proxyAndRecord(req, res, body, providerKey, req.url ?? COMPLETIONS_PATH, fixtures, defaults, raw, hookOptions));
|
|
1225
1222
|
if (outcome === "handled_by_hook") return;
|
|
1226
1223
|
if (outcome !== "not_configured") {
|
|
1227
|
-
const destroyedMidStream = res.destroyed && !res.writableEnded;
|
|
1228
1224
|
journal.add({
|
|
1229
1225
|
method: req.method ?? "POST",
|
|
1230
1226
|
path: req.url ?? COMPLETIONS_PATH,
|
|
@@ -1234,10 +1230,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
1234
1230
|
status: res.statusCode ?? 200,
|
|
1235
1231
|
fixture: null,
|
|
1236
1232
|
source: "proxy",
|
|
1237
|
-
...
|
|
1238
|
-
interrupted: true,
|
|
1239
|
-
interruptReason: clientHungUp ? "client aborted" : "proxy stream destroyed"
|
|
1240
|
-
} : {}
|
|
1233
|
+
...proxyInterruption(res, clientHungUp)
|
|
1241
1234
|
}
|
|
1242
1235
|
});
|
|
1243
1236
|
recordBypass("proxied");
|
|
@@ -1324,20 +1317,23 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
1324
1317
|
const emitStreamingUsage = body.stream === true && body.stream_options?.include_usage === true || openRouter;
|
|
1325
1318
|
const streamingPromptText = body.messages.map((m) => typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((p) => p.text ?? "").join("") : "").join("");
|
|
1326
1319
|
const resolveStreamingUsageTokens = (overrides, completionText) => appliedUsage ?? resolveUsage(overrides, streamingPromptText, completionText);
|
|
1327
|
-
const
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1320
|
+
const nonStreamingOpts = (payloadLength) => ({
|
|
1321
|
+
surface: "openai-chat",
|
|
1322
|
+
payloadLength,
|
|
1323
|
+
chunkSize,
|
|
1324
|
+
recordedTimings: fixture.recordedTimings,
|
|
1325
|
+
duplicateId: !!appliedPlan?.duplicateId,
|
|
1326
|
+
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed
|
|
1327
|
+
});
|
|
1328
|
+
const streamTiming = (frameCount) => ({
|
|
1329
|
+
latency,
|
|
1330
|
+
streamingProfile: fixture.streamingProfile,
|
|
1331
|
+
recordedTimings: extendRecordedTimings(fixture.recordedTimings, frameCount, !!appliedPlan?.duplicateId),
|
|
1332
|
+
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed
|
|
1333
|
+
});
|
|
1334
|
+
const commitNonStream = async (entry, reply, payloadLength) => {
|
|
1335
|
+
recordOutcome(entry);
|
|
1336
|
+
await deliverJson(res, entry, fixture, () => reply, nonStreamingOpts(payloadLength));
|
|
1341
1337
|
};
|
|
1342
1338
|
const shapeORCompletion = (completion, overrides) => {
|
|
1343
1339
|
if (appliedUsage) completion.usage = appliedUsage;
|
|
@@ -1351,6 +1347,24 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
1351
1347
|
if (usageChunk) shapeOpenRouterChunks([usageChunk], shaping, overrides?.id !== void 0);
|
|
1352
1348
|
};
|
|
1353
1349
|
const openRouterProcessing = !!(openRouter && fixture.openRouterProcessing);
|
|
1350
|
+
if (isRawResponse(response)) {
|
|
1351
|
+
await serveRawResponse({
|
|
1352
|
+
wire: "openai-chat",
|
|
1353
|
+
stream: body.stream === true,
|
|
1354
|
+
req,
|
|
1355
|
+
res,
|
|
1356
|
+
fixture,
|
|
1357
|
+
response,
|
|
1358
|
+
body,
|
|
1359
|
+
journal,
|
|
1360
|
+
defaults,
|
|
1361
|
+
testId,
|
|
1362
|
+
misbehaviorSummary: evaluation.summary,
|
|
1363
|
+
errorWire: "openai",
|
|
1364
|
+
openRouter
|
|
1365
|
+
});
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1354
1368
|
if (isErrorResponse(response)) {
|
|
1355
1369
|
const status = response.status ?? 500;
|
|
1356
1370
|
recordOutcome(journal.add({
|
|
@@ -1395,32 +1409,18 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
1395
1409
|
fixture
|
|
1396
1410
|
}
|
|
1397
1411
|
});
|
|
1398
|
-
|
|
1399
|
-
if (body.stream !== true)
|
|
1400
|
-
|
|
1401
|
-
await awaitNonStreamingTiming((appliedPlan.stop === "refusal" ? appliedPlan.refusal ?? "" : appliedPlan.stop === "content_filter" ? "" : appliedPlan.reasoning ?? "").length);
|
|
1402
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1403
|
-
res.end(JSON.stringify(shapeORCompletion(completion, overrides)));
|
|
1404
|
-
} else {
|
|
1412
|
+
rejectGeneratedFiles(response, wire);
|
|
1413
|
+
if (body.stream !== true) await commitNonStream(entry, shapeORCompletion(appliedPlan.stop === "refusal" ? buildOpenAIRefusalCompletion(appliedPlan.refusal ?? "", responseModel, overrides, body.messages) : appliedPlan.stop === "content_filter" ? buildOpenAIContentFilterCompletion(responseModel, overrides, body.messages) : buildOpenAIReasoningCompletion(appliedPlan.reasoning ?? "", responseModel, openRouter, overrides, body.messages), overrides), misbehaviorPayloadLength(appliedPlan, appliedReasoning));
|
|
1414
|
+
else {
|
|
1405
1415
|
const chunks = appliedPlan.stop === "refusal" ? buildOpenAIRefusalChunks(appliedPlan.refusal ?? "", responseModel, chunkSize, overrides) : appliedPlan.stop === "content_filter" ? buildOpenAIContentFilterChunks(responseModel, overrides) : buildOpenAIReasoningChunks(appliedPlan.reasoning ?? "", responseModel, chunkSize, openRouter, overrides);
|
|
1406
1416
|
const usageChunk = emitStreamingUsage ? buildUsageChunk(chunks[0].id, overrides?.model ?? responseModel, chunks[0].created, resolveStreamingUsageTokens(overrides, ""), overrides?.systemFingerprint) : void 0;
|
|
1407
1417
|
shapeORChunks(chunks, usageChunk, overrides);
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
streamingProfile: fixture.streamingProfile,
|
|
1412
|
-
signal: interruption?.signal,
|
|
1413
|
-
onChunkSent: interruption?.tick,
|
|
1418
|
+
recordOutcome(entry);
|
|
1419
|
+
await deliverStream(res, entry, fixture, sseCodec({
|
|
1420
|
+
done: true,
|
|
1414
1421
|
usageChunk,
|
|
1415
|
-
recordedTimings: resolveRecordedTimings(chunks.length),
|
|
1416
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
1417
1422
|
openRouterProcessing
|
|
1418
|
-
}))
|
|
1419
|
-
if (!res.writableEnded) res.destroy();
|
|
1420
|
-
entry.response.interrupted = true;
|
|
1421
|
-
entry.response.interruptReason = interruption?.reason();
|
|
1422
|
-
}
|
|
1423
|
-
interruption?.cleanup();
|
|
1423
|
+
}), chunks, streamTiming(chunks.length));
|
|
1424
1424
|
}
|
|
1425
1425
|
return;
|
|
1426
1426
|
}
|
|
@@ -1441,37 +1441,26 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
1441
1441
|
fixture
|
|
1442
1442
|
}
|
|
1443
1443
|
});
|
|
1444
|
-
|
|
1444
|
+
rejectGeneratedFiles(response, wire);
|
|
1445
1445
|
const toolCalls = requireEmittedFunctionToolCalls(response, wire);
|
|
1446
1446
|
const completionText = blockOutcome ? blockOutcome.content + blockOutcome.toolCalls.map((tc) => tc.name + tc.arguments).join("") : (response.content ?? "") + toolCalls.map((tc) => tc.name + tc.arguments).join("");
|
|
1447
1447
|
if (!streaming) {
|
|
1448
|
-
await awaitNonStreamingTiming((effReasoning?.length ?? 0) + completionText.length);
|
|
1449
1448
|
const completion = buildContentWithToolCallsCompletion(blockOutcome?.content ?? response.content ?? "", blockOutcome?.toolCalls ?? toolCalls, responseModel, effReasoning, blockOutcome ? {
|
|
1450
1449
|
...overrides,
|
|
1451
1450
|
finishReason: overrides?.finishReason ?? (blockOutcome.hasToolCalls ? "tool_calls" : "stop")
|
|
1452
1451
|
} : overrides, body.messages);
|
|
1453
|
-
|
|
1454
|
-
|
|
1452
|
+
const contentLength = (effReasoning?.length ?? 0) + completionText.length;
|
|
1453
|
+
await commitNonStream(journalEntry, shapeORCompletion(completion, overrides), contentLength);
|
|
1455
1454
|
} else {
|
|
1456
1455
|
const chunks = buildContentWithToolCallsChunks(blockOutcome?.content ?? response.content ?? "", blockOutcome?.toolCalls ?? toolCalls, responseModel, chunkSize, effReasoning, overrides, blockOutcome?.ordered);
|
|
1457
1456
|
const usageChunk = emitStreamingUsage ? buildUsageChunk(chunks[0]?.id ?? "chatcmpl-unknown", overrides?.model ?? responseModel, chunks[0]?.created ?? Math.floor(Date.now() / 1e3), resolveStreamingUsageTokens(overrides, completionText), overrides?.systemFingerprint) : void 0;
|
|
1458
1457
|
shapeORChunks(chunks, usageChunk, overrides);
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
streamingProfile: fixture.streamingProfile,
|
|
1463
|
-
signal: interruption?.signal,
|
|
1464
|
-
onChunkSent: interruption?.tick,
|
|
1458
|
+
recordOutcome(journalEntry);
|
|
1459
|
+
await deliverStream(res, journalEntry, fixture, sseCodec({
|
|
1460
|
+
done: true,
|
|
1465
1461
|
usageChunk,
|
|
1466
|
-
recordedTimings: resolveRecordedTimings(chunks.length),
|
|
1467
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
1468
1462
|
openRouterProcessing
|
|
1469
|
-
}))
|
|
1470
|
-
if (!res.writableEnded) res.destroy();
|
|
1471
|
-
journalEntry.response.interrupted = true;
|
|
1472
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
1473
|
-
}
|
|
1474
|
-
interruption?.cleanup();
|
|
1463
|
+
}), chunks, streamTiming(chunks.length));
|
|
1475
1464
|
}
|
|
1476
1465
|
return;
|
|
1477
1466
|
}
|
|
@@ -1490,32 +1479,21 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
1490
1479
|
fixture
|
|
1491
1480
|
}
|
|
1492
1481
|
});
|
|
1493
|
-
|
|
1482
|
+
rejectGeneratedFiles(response, wire);
|
|
1494
1483
|
if (body.stream !== true) {
|
|
1495
|
-
await awaitNonStreamingTiming((effReasoning?.length ?? 0) + response.content.length);
|
|
1496
1484
|
const completion = buildTextCompletion(response.content, responseModel, effReasoning, overrides, body.messages);
|
|
1497
|
-
|
|
1498
|
-
|
|
1485
|
+
const contentLength = (effReasoning?.length ?? 0) + response.content.length;
|
|
1486
|
+
await commitNonStream(journalEntry, shapeORCompletion(completion, overrides), contentLength);
|
|
1499
1487
|
} else {
|
|
1500
1488
|
const chunks = buildTextChunks(response.content, responseModel, chunkSize, effReasoning, overrides);
|
|
1501
1489
|
const usageChunk = emitStreamingUsage ? buildUsageChunk(chunks[0]?.id ?? "chatcmpl-unknown", overrides?.model ?? responseModel, chunks[0]?.created ?? Math.floor(Date.now() / 1e3), resolveStreamingUsageTokens(overrides, response.content), overrides?.systemFingerprint) : void 0;
|
|
1502
1490
|
shapeORChunks(chunks, usageChunk, overrides);
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
streamingProfile: fixture.streamingProfile,
|
|
1507
|
-
signal: interruption?.signal,
|
|
1508
|
-
onChunkSent: interruption?.tick,
|
|
1491
|
+
recordOutcome(journalEntry);
|
|
1492
|
+
await deliverStream(res, journalEntry, fixture, sseCodec({
|
|
1493
|
+
done: true,
|
|
1509
1494
|
usageChunk,
|
|
1510
|
-
recordedTimings: resolveRecordedTimings(chunks.length),
|
|
1511
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
1512
1495
|
openRouterProcessing
|
|
1513
|
-
}))
|
|
1514
|
-
if (!res.writableEnded) res.destroy();
|
|
1515
|
-
journalEntry.response.interrupted = true;
|
|
1516
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
1517
|
-
}
|
|
1518
|
-
interruption?.cleanup();
|
|
1496
|
+
}), chunks, streamTiming(chunks.length));
|
|
1519
1497
|
}
|
|
1520
1498
|
return;
|
|
1521
1499
|
}
|
|
@@ -1534,35 +1512,24 @@ async function handleCompletions(req, res, fixtures, journal, defaults, getReque
|
|
|
1534
1512
|
fixture
|
|
1535
1513
|
}
|
|
1536
1514
|
});
|
|
1537
|
-
|
|
1515
|
+
rejectGeneratedFiles(response, wire);
|
|
1538
1516
|
const toolCalls = requireServedFunctionToolCalls(response, wire);
|
|
1539
1517
|
if (body.stream !== true) {
|
|
1540
1518
|
const toolCallText = toolCalls.map((tc) => tc.name + tc.arguments).join("");
|
|
1541
|
-
await awaitNonStreamingTiming((effReasoning?.length ?? 0) + toolCallText.length);
|
|
1542
1519
|
const completion = buildToolCallCompletion(toolCalls, responseModel, effReasoning, overrides, body.messages);
|
|
1543
|
-
|
|
1544
|
-
|
|
1520
|
+
const contentLength = (effReasoning?.length ?? 0) + toolCallText.length;
|
|
1521
|
+
await commitNonStream(journalEntry, shapeORCompletion(completion, overrides), contentLength);
|
|
1545
1522
|
} else {
|
|
1546
1523
|
const chunks = buildToolCallChunks(toolCalls, responseModel, chunkSize, effReasoning, overrides);
|
|
1547
1524
|
const completionText = toolCalls.map((tc) => tc.name + tc.arguments).join("");
|
|
1548
1525
|
const usageChunk = emitStreamingUsage ? buildUsageChunk(chunks[0]?.id ?? "chatcmpl-unknown", overrides?.model ?? responseModel, chunks[0]?.created ?? Math.floor(Date.now() / 1e3), resolveStreamingUsageTokens(overrides, completionText), overrides?.systemFingerprint) : void 0;
|
|
1549
1526
|
shapeORChunks(chunks, usageChunk, overrides);
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
streamingProfile: fixture.streamingProfile,
|
|
1554
|
-
signal: interruption?.signal,
|
|
1555
|
-
onChunkSent: interruption?.tick,
|
|
1527
|
+
recordOutcome(journalEntry);
|
|
1528
|
+
await deliverStream(res, journalEntry, fixture, sseCodec({
|
|
1529
|
+
done: true,
|
|
1556
1530
|
usageChunk,
|
|
1557
|
-
recordedTimings: resolveRecordedTimings(chunks.length),
|
|
1558
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
1559
1531
|
openRouterProcessing
|
|
1560
|
-
}))
|
|
1561
|
-
if (!res.writableEnded) res.destroy();
|
|
1562
|
-
journalEntry.response.interrupted = true;
|
|
1563
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
1564
|
-
}
|
|
1565
|
-
interruption?.cleanup();
|
|
1532
|
+
}), chunks, streamTiming(chunks.length));
|
|
1566
1533
|
}
|
|
1567
1534
|
return;
|
|
1568
1535
|
}
|
|
@@ -1822,10 +1789,12 @@ async function startServer(fixtures, options, resolvedAuth, mountList, logger, s
|
|
|
1822
1789
|
return status >= 400 && status < 500 ? "invalid_request_error" : "server_error";
|
|
1823
1790
|
}
|
|
1824
1791
|
/**
|
|
1825
|
-
* Envelope for a fixture
|
|
1826
|
-
*
|
|
1827
|
-
*
|
|
1828
|
-
*
|
|
1792
|
+
* Envelope for a fixture error (see isFixtureToolCallError: invalid JSON
|
|
1793
|
+
* arguments on an object wire, a custom tool call on a non-Responses wire, a
|
|
1794
|
+
* malformed fixture tool call, generated `files` on a wire that cannot carry
|
|
1795
|
+
* them, or a malformed fixture `citations` or `files` value). It is the
|
|
1796
|
+
* provider envelope aimock emits for that route, with the aimock `code` in
|
|
1797
|
+
* it: Google's
|
|
1829
1798
|
* `google.rpc.ErrorInfo` detail on Gemini and Vertex AI, a string
|
|
1830
1799
|
* `error.code` on Gemini Interactions and Anthropic Messages, a `reason`
|
|
1831
1800
|
* member on Bedrock (a `code` member would replace `__type` as the AWS SDK's
|
|
@@ -1955,7 +1924,7 @@ async function startServer(fixtures, options, resolvedAuth, mountList, logger, s
|
|
|
1955
1924
|
const existing = lastJournalEntryFor(req);
|
|
1956
1925
|
const bodyLimitDisconnect = clientFault && (req.destroyed || res.destroyed);
|
|
1957
1926
|
if ((clientAbort || bodyLimitDisconnect) && !res.headersSent) {
|
|
1958
|
-
const interruptReason = bodyLimitDisconnect ? "request body exceeded size limit" :
|
|
1927
|
+
const interruptReason = bodyLimitDisconnect ? "request body exceeded size limit" : CLIENT_ABORTED;
|
|
1959
1928
|
if (existing) {
|
|
1960
1929
|
if (!existing.response.interrupted) {
|
|
1961
1930
|
existing.response.status = 0;
|
|
@@ -2011,7 +1980,7 @@ async function startServer(fixtures, options, resolvedAuth, mountList, logger, s
|
|
|
2011
1980
|
type: errorTypeForStatus(status)
|
|
2012
1981
|
}).body);
|
|
2013
1982
|
} else {
|
|
2014
|
-
const midStreamReason = clientAbort ?
|
|
1983
|
+
const midStreamReason = clientAbort ? CLIENT_ABORTED : "handler crashed mid-stream";
|
|
2015
1984
|
if (existing) {
|
|
2016
1985
|
if (res.writableEnded) {
|
|
2017
1986
|
if (existing.response.error === void 0) existing.response.error = msg;
|