@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/ollama.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { renderError } from "./response/errors.js";
|
|
2
2
|
import { resolveRequestDecisions, strictOverrideField } from "./response/policy.js";
|
|
3
|
-
import { InvalidToolArgumentsError, MAX_EMBEDDING_DIMENSIONS, flattenHeaders, generateDeterministicEmbedding, getContext, getTestId, isCombinedFixtureResponse, isEmbeddingResponse, isErrorResponse, isJSONResponse, isJsonObject, isTextResponse, isToolCallResponse, normalizeEmbeddingInput, requireEmittedFunctionToolCalls, resolveFixtureBlockOutcome, resolveFixtureBlocks, resolveReasoningForModel, resolveResponse, servedToolArgs, strictNoMatchLogLine, strictNoMatchMessage, toolArgsForWire, validateChatMessages, validateEmbeddingDimensions, validateToolsField } from "./helpers.js";
|
|
3
|
+
import { InvalidToolArgumentsError, MAX_EMBEDDING_DIMENSIONS, flattenHeaders, generateDeterministicEmbedding, getContext, getTestId, isCombinedFixtureResponse, isEmbeddingResponse, isErrorResponse, isJSONResponse, isJsonObject, isRawResponse, isTextResponse, isToolCallResponse, normalizeEmbeddingInput, requireEmittedFunctionToolCalls, resolveFixtureBlockOutcome, resolveFixtureBlocks, resolveReasoningForModel, resolveResponse, servedToolArgs, strictNoMatchLogLine, strictNoMatchMessage, toolArgsForWire, validateChatMessages, validateEmbeddingDimensions, 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 { setEmbeddingRequest } from "./embedding-request.js";
|
|
8
8
|
import { matchFixtureDiagnostic, recordMatchOptions } from "./router.js";
|
|
9
9
|
import { proxyAndRecord } from "./recorder.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { misbehaviorPayloadLength, nonStreamingTimingEnabled, servedPayloadLength } from "./response/timing.js";
|
|
11
|
+
import { deliverJson, deliverStream } from "./response/deliver.js";
|
|
12
|
+
import { proxyInterruption, withHangUpDetection } from "./response/proxy.js";
|
|
13
|
+
import { ndjsonCodec } from "./ndjson-writer.js";
|
|
14
|
+
import { serveRawResponse } from "./response/raw.js";
|
|
12
15
|
import { render } from "./response/usage/codecs/ollama.js";
|
|
13
16
|
|
|
14
17
|
//#region src/ollama.ts
|
|
@@ -330,8 +333,10 @@ function prepareOllamaMisbehavior(plan, request, stream, chunkSize, effectiveStr
|
|
|
330
333
|
for (const block of outcome.ordered) if (block.type === "text") priorContent += block.text;
|
|
331
334
|
else if (index++ === plan.target?.index) break;
|
|
332
335
|
}
|
|
336
|
+
const chunks = stream ? [...buildOllamaChatTextChunks(priorContent, model, chunkSize).slice(0, -1), { error }] : [{ error }];
|
|
333
337
|
return {
|
|
334
|
-
|
|
338
|
+
build: () => chunks,
|
|
339
|
+
reasoning: void 0,
|
|
335
340
|
status: stream ? 200 : 500,
|
|
336
341
|
summary: {
|
|
337
342
|
...plan.summary,
|
|
@@ -347,64 +352,64 @@ function prepareOllamaMisbehavior(plan, request, stream, chunkSize, effectiveStr
|
|
|
347
352
|
arguments: parsed.text
|
|
348
353
|
};
|
|
349
354
|
});
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
355
|
+
const reasoning = plan.summary.fault === "reasoning-only" ? plan.reasoning ?? "" : resolveReasoningForModel("reasoning" in response ? response.reasoning : void 0, model, effectiveStrict, logger) ?? "";
|
|
356
|
+
const completion = content + reasoning + servedToolCalls.map((call) => call.name + call.arguments).join("");
|
|
357
|
+
const build = () => {
|
|
358
|
+
let chunks;
|
|
359
|
+
if (plan.summary.fault === "reasoning-only") {
|
|
360
|
+
const base = {
|
|
361
|
+
model,
|
|
362
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
363
|
+
};
|
|
364
|
+
if (stream) {
|
|
365
|
+
chunks = [];
|
|
366
|
+
for (let i = 0; i < reasoning.length; i += chunkSize) chunks.push({
|
|
367
|
+
...base,
|
|
368
|
+
message: {
|
|
369
|
+
role: "assistant",
|
|
370
|
+
content: "",
|
|
371
|
+
thinking: reasoning.slice(i, i + chunkSize)
|
|
372
|
+
},
|
|
373
|
+
done: false
|
|
374
|
+
});
|
|
375
|
+
chunks.push({
|
|
376
|
+
...base,
|
|
377
|
+
message: {
|
|
378
|
+
role: "assistant",
|
|
379
|
+
content: ""
|
|
380
|
+
},
|
|
381
|
+
done: true,
|
|
382
|
+
...DURATION_FIELDS,
|
|
383
|
+
done_reason: "length"
|
|
384
|
+
});
|
|
385
|
+
} else chunks = [{
|
|
361
386
|
...base,
|
|
362
387
|
message: {
|
|
363
388
|
role: "assistant",
|
|
364
389
|
content: "",
|
|
365
|
-
thinking: reasoning
|
|
366
|
-
},
|
|
367
|
-
done: false
|
|
368
|
-
});
|
|
369
|
-
chunks.push({
|
|
370
|
-
...base,
|
|
371
|
-
message: {
|
|
372
|
-
role: "assistant",
|
|
373
|
-
content: ""
|
|
390
|
+
thinking: reasoning
|
|
374
391
|
},
|
|
375
392
|
done: true,
|
|
376
393
|
...DURATION_FIELDS,
|
|
377
394
|
done_reason: "length"
|
|
378
|
-
}
|
|
379
|
-
} else chunks = [
|
|
380
|
-
...base,
|
|
381
|
-
message: {
|
|
382
|
-
role: "assistant",
|
|
383
|
-
content: "",
|
|
384
|
-
thinking: reasoning
|
|
385
|
-
},
|
|
386
|
-
done: true,
|
|
387
|
-
...DURATION_FIELDS,
|
|
388
|
-
done_reason: "length"
|
|
389
|
-
}];
|
|
390
|
-
} else {
|
|
391
|
-
reasoning = resolveReasoningForModel("reasoning" in response ? response.reasoning : void 0, model, effectiveStrict, logger) ?? "";
|
|
392
|
-
if (combined) chunks = stream ? buildOllamaChatContentWithToolCallsChunks(content, calls, model, chunkSize, reasoning, response.blocks) : [buildOllamaChatContentWithToolCallsResponse(content, calls, model, reasoning, response.blocks)];
|
|
395
|
+
}];
|
|
396
|
+
} else if (combined) chunks = stream ? buildOllamaChatContentWithToolCallsChunks(content, calls, model, chunkSize, reasoning, response.blocks) : [buildOllamaChatContentWithToolCallsResponse(content, calls, model, reasoning, response.blocks)];
|
|
393
397
|
else if (isToolCallResponse(response)) chunks = stream ? buildOllamaChatToolCallChunks(calls, model, chunkSize, reasoning) : [buildOllamaChatToolCallResponse(calls, model, reasoning)];
|
|
394
398
|
else chunks = stream ? buildOllamaChatTextChunks(content, model, chunkSize, reasoning) : [buildOllamaChatTextResponse(content, model, reasoning)];
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
399
|
+
const terminal = chunks.length - 1;
|
|
400
|
+
chunks[terminal] = {
|
|
401
|
+
...chunks[terminal],
|
|
402
|
+
...render({
|
|
403
|
+
kind: "applied-chat-estimate",
|
|
404
|
+
messages: request.messages,
|
|
405
|
+
completion
|
|
406
|
+
})
|
|
407
|
+
};
|
|
408
|
+
return chunks;
|
|
405
409
|
};
|
|
406
410
|
return {
|
|
407
|
-
|
|
411
|
+
build,
|
|
412
|
+
reasoning,
|
|
408
413
|
status: 200,
|
|
409
414
|
summary: {
|
|
410
415
|
...plan.summary,
|
|
@@ -523,7 +528,10 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
523
528
|
completionReq._endpointType = "chat";
|
|
524
529
|
completionReq._context = getContext(req);
|
|
525
530
|
const testId = getTestId(req);
|
|
526
|
-
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform,
|
|
531
|
+
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform, {
|
|
532
|
+
...recordMatchOptions(!!defaults.record, defaults.logger),
|
|
533
|
+
wire: "ollama"
|
|
534
|
+
});
|
|
527
535
|
if (fixture) {
|
|
528
536
|
journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
529
537
|
logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
|
|
@@ -557,7 +565,7 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
557
565
|
return;
|
|
558
566
|
}
|
|
559
567
|
if (defaults.record) {
|
|
560
|
-
const outcome = await proxyAndRecord(req, res, completionReq, "ollama", urlPath, fixtures, defaults, raw);
|
|
568
|
+
const { outcome, clientHungUp } = await withHangUpDetection(req, res, () => proxyAndRecord(req, res, completionReq, "ollama", urlPath, fixtures, defaults, raw));
|
|
561
569
|
if (outcome === "handled_by_hook") return;
|
|
562
570
|
if (outcome !== "not_configured") {
|
|
563
571
|
journal.add({
|
|
@@ -568,7 +576,8 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
568
576
|
response: {
|
|
569
577
|
status: res.statusCode ?? 200,
|
|
570
578
|
fixture: null,
|
|
571
|
-
source: "proxy"
|
|
579
|
+
source: "proxy",
|
|
580
|
+
...proxyInterruption(res, clientHungUp)
|
|
572
581
|
}
|
|
573
582
|
});
|
|
574
583
|
return;
|
|
@@ -626,11 +635,44 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
626
635
|
}).body);
|
|
627
636
|
return;
|
|
628
637
|
}
|
|
638
|
+
if (isRawResponse(response)) {
|
|
639
|
+
await serveRawResponse({
|
|
640
|
+
wire: "ollama",
|
|
641
|
+
stream: ollamaReq.stream !== false,
|
|
642
|
+
req,
|
|
643
|
+
res,
|
|
644
|
+
fixture,
|
|
645
|
+
response,
|
|
646
|
+
body: completionReq,
|
|
647
|
+
journal,
|
|
648
|
+
defaults,
|
|
649
|
+
testId,
|
|
650
|
+
misbehaviorSummary: misbehavior.summary,
|
|
651
|
+
errorWire: "ollama"
|
|
652
|
+
});
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
629
655
|
const latency = fixture.latency ?? defaults.latency;
|
|
630
656
|
const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
|
|
657
|
+
const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
|
|
658
|
+
const streamTiming = {
|
|
659
|
+
latency,
|
|
660
|
+
streamingProfile: fixture.streamingProfile,
|
|
661
|
+
recordedTimings: fixture.recordedTimings,
|
|
662
|
+
replaySpeed
|
|
663
|
+
};
|
|
664
|
+
const jsonOpts = (payloadLength, duplicateId = false) => ({
|
|
665
|
+
surface: "other",
|
|
666
|
+
payloadLength,
|
|
667
|
+
chunkSize,
|
|
668
|
+
recordedTimings: fixture.recordedTimings,
|
|
669
|
+
duplicateId,
|
|
670
|
+
replaySpeed
|
|
671
|
+
});
|
|
631
672
|
const streaming = ollamaReq.stream !== false;
|
|
632
673
|
if (misbehavior.kind === "applied") {
|
|
633
674
|
const prepared = prepareOllamaMisbehavior(misbehavior, completionReq, streaming, chunkSize, resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression, logger);
|
|
675
|
+
const chunks = !streaming && prepared.status === 200 && nonStreamingTimingEnabled(fixture, "other") ? void 0 : prepared.build();
|
|
634
676
|
const journalEntry = journal.add({
|
|
635
677
|
method: req.method ?? "POST",
|
|
636
678
|
path: urlPath,
|
|
@@ -647,24 +689,16 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
647
689
|
defaults,
|
|
648
690
|
testId
|
|
649
691
|
});
|
|
650
|
-
if (!streaming) {
|
|
692
|
+
if (!streaming && prepared.status !== 200) {
|
|
651
693
|
res.writeHead(prepared.status, { "Content-Type": "application/json" });
|
|
652
|
-
res.end(JSON.stringify(prepared.
|
|
653
|
-
} else {
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
signal: interruption?.signal,
|
|
661
|
-
onChunkSent: interruption?.tick
|
|
662
|
-
})) {
|
|
663
|
-
if (!res.writableEnded) res.destroy();
|
|
664
|
-
journalEntry.response.interrupted = true;
|
|
665
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
666
|
-
}
|
|
667
|
-
interruption?.cleanup();
|
|
694
|
+
res.end(JSON.stringify((chunks ?? prepared.build())[0]));
|
|
695
|
+
} else if (!streaming) await deliverJson(res, journalEntry, fixture, () => (chunks ?? prepared.build())[0], {
|
|
696
|
+
...jsonOpts(misbehaviorPayloadLength(misbehavior, misbehavior.reasoning === void 0 ? prepared.reasoning : void 0), !!misbehavior.duplicateId),
|
|
697
|
+
status: prepared.status
|
|
698
|
+
});
|
|
699
|
+
else {
|
|
700
|
+
const frames = chunks ?? prepared.build();
|
|
701
|
+
await deliverStream(res, journalEntry, fixture, ndjsonCodec(), frames, streamTiming);
|
|
668
702
|
}
|
|
669
703
|
return;
|
|
670
704
|
}
|
|
@@ -709,26 +743,10 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
709
743
|
const functionToolCalls = requireEmittedFunctionToolCalls(response, "Ollama");
|
|
710
744
|
const effectiveStrict = resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression;
|
|
711
745
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, logger);
|
|
712
|
-
if (!streaming)
|
|
713
|
-
|
|
714
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
715
|
-
res.end(JSON.stringify(body));
|
|
716
|
-
} else {
|
|
746
|
+
if (!streaming) await deliverJson(res, journalEntry, fixture, () => buildOllamaChatContentWithToolCallsResponse(response.content ?? "", functionToolCalls, completionReq.model, effReasoning, response.blocks), jsonOpts(servedPayloadLength(response, effReasoning)));
|
|
747
|
+
else {
|
|
717
748
|
const chunks = buildOllamaChatContentWithToolCallsChunks(response.content ?? "", functionToolCalls, completionReq.model, chunkSize, effReasoning, response.blocks);
|
|
718
|
-
|
|
719
|
-
if (!await writeNDJSONStream(res, chunks, {
|
|
720
|
-
latency,
|
|
721
|
-
streamingProfile: fixture.streamingProfile,
|
|
722
|
-
recordedTimings: fixture.recordedTimings,
|
|
723
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
724
|
-
signal: interruption?.signal,
|
|
725
|
-
onChunkSent: interruption?.tick
|
|
726
|
-
})) {
|
|
727
|
-
if (!res.writableEnded) res.destroy();
|
|
728
|
-
journalEntry.response.interrupted = true;
|
|
729
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
730
|
-
}
|
|
731
|
-
interruption?.cleanup();
|
|
749
|
+
await deliverStream(res, journalEntry, fixture, ndjsonCodec(), chunks, streamTiming);
|
|
732
750
|
}
|
|
733
751
|
return;
|
|
734
752
|
}
|
|
@@ -752,26 +770,10 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
752
770
|
});
|
|
753
771
|
const effectiveStrict = resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression;
|
|
754
772
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, logger);
|
|
755
|
-
if (!streaming)
|
|
756
|
-
|
|
757
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
758
|
-
res.end(JSON.stringify(body));
|
|
759
|
-
} else {
|
|
773
|
+
if (!streaming) await deliverJson(res, journalEntry, fixture, () => buildOllamaChatTextResponse(response.content, completionReq.model, effReasoning), jsonOpts(servedPayloadLength(response, effReasoning)));
|
|
774
|
+
else {
|
|
760
775
|
const chunks = buildOllamaChatTextChunks(response.content, completionReq.model, chunkSize, effReasoning);
|
|
761
|
-
|
|
762
|
-
if (!await writeNDJSONStream(res, chunks, {
|
|
763
|
-
latency,
|
|
764
|
-
streamingProfile: fixture.streamingProfile,
|
|
765
|
-
recordedTimings: fixture.recordedTimings,
|
|
766
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
767
|
-
signal: interruption?.signal,
|
|
768
|
-
onChunkSent: interruption?.tick
|
|
769
|
-
})) {
|
|
770
|
-
if (!res.writableEnded) res.destroy();
|
|
771
|
-
journalEntry.response.interrupted = true;
|
|
772
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
773
|
-
}
|
|
774
|
-
interruption?.cleanup();
|
|
776
|
+
await deliverStream(res, journalEntry, fixture, ndjsonCodec(), chunks, streamTiming);
|
|
775
777
|
}
|
|
776
778
|
return;
|
|
777
779
|
}
|
|
@@ -796,26 +798,10 @@ async function handleOllama(req, res, raw, fixtures, journal, defaults, setCorsH
|
|
|
796
798
|
const functionToolCalls = requireEmittedFunctionToolCalls(response, "Ollama");
|
|
797
799
|
const effectiveStrict = resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression;
|
|
798
800
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, logger);
|
|
799
|
-
if (!streaming)
|
|
800
|
-
|
|
801
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
802
|
-
res.end(JSON.stringify(body));
|
|
803
|
-
} else {
|
|
801
|
+
if (!streaming) await deliverJson(res, journalEntry, fixture, () => buildOllamaChatToolCallResponse(functionToolCalls, completionReq.model, effReasoning), jsonOpts(servedPayloadLength(response, effReasoning)));
|
|
802
|
+
else {
|
|
804
803
|
const chunks = buildOllamaChatToolCallChunks(functionToolCalls, completionReq.model, chunkSize, effReasoning);
|
|
805
|
-
|
|
806
|
-
if (!await writeNDJSONStream(res, chunks, {
|
|
807
|
-
latency,
|
|
808
|
-
streamingProfile: fixture.streamingProfile,
|
|
809
|
-
recordedTimings: fixture.recordedTimings,
|
|
810
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
811
|
-
signal: interruption?.signal,
|
|
812
|
-
onChunkSent: interruption?.tick
|
|
813
|
-
})) {
|
|
814
|
-
if (!res.writableEnded) res.destroy();
|
|
815
|
-
journalEntry.response.interrupted = true;
|
|
816
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
817
|
-
}
|
|
818
|
-
interruption?.cleanup();
|
|
804
|
+
await deliverStream(res, journalEntry, fixture, ndjsonCodec(), chunks, streamTiming);
|
|
819
805
|
}
|
|
820
806
|
return;
|
|
821
807
|
}
|
|
@@ -901,7 +887,10 @@ async function handleOllamaGenerate(req, res, raw, fixtures, journal, defaults,
|
|
|
901
887
|
completionReq._endpointType = "chat";
|
|
902
888
|
completionReq._context = getContext(req);
|
|
903
889
|
const testId = getTestId(req);
|
|
904
|
-
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform,
|
|
890
|
+
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform, {
|
|
891
|
+
...recordMatchOptions(!!defaults.record, defaults.logger),
|
|
892
|
+
wire: "ollama-generate"
|
|
893
|
+
});
|
|
905
894
|
if (fixture) {
|
|
906
895
|
journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
907
896
|
defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
|
|
@@ -935,7 +924,7 @@ async function handleOllamaGenerate(req, res, raw, fixtures, journal, defaults,
|
|
|
935
924
|
return;
|
|
936
925
|
}
|
|
937
926
|
if (defaults.record) {
|
|
938
|
-
const outcome = await proxyAndRecord(req, res, completionReq, "ollama", urlPath, fixtures, defaults, raw);
|
|
927
|
+
const { outcome, clientHungUp } = await withHangUpDetection(req, res, () => proxyAndRecord(req, res, completionReq, "ollama", urlPath, fixtures, defaults, raw));
|
|
939
928
|
if (outcome === "handled_by_hook") return;
|
|
940
929
|
if (outcome !== "not_configured") {
|
|
941
930
|
journal.add({
|
|
@@ -946,7 +935,8 @@ async function handleOllamaGenerate(req, res, raw, fixtures, journal, defaults,
|
|
|
946
935
|
response: {
|
|
947
936
|
status: res.statusCode ?? 200,
|
|
948
937
|
fixture: null,
|
|
949
|
-
source: "proxy"
|
|
938
|
+
source: "proxy",
|
|
939
|
+
...proxyInterruption(res, clientHungUp)
|
|
950
940
|
}
|
|
951
941
|
});
|
|
952
942
|
return;
|
|
@@ -1005,8 +995,40 @@ async function handleOllamaGenerate(req, res, raw, fixtures, journal, defaults,
|
|
|
1005
995
|
}).body);
|
|
1006
996
|
return;
|
|
1007
997
|
}
|
|
998
|
+
if (isRawResponse(response)) {
|
|
999
|
+
await serveRawResponse({
|
|
1000
|
+
wire: "ollama-generate",
|
|
1001
|
+
stream: generateReq.stream !== false,
|
|
1002
|
+
req,
|
|
1003
|
+
res,
|
|
1004
|
+
fixture,
|
|
1005
|
+
response,
|
|
1006
|
+
body: completionReq,
|
|
1007
|
+
journal,
|
|
1008
|
+
defaults,
|
|
1009
|
+
testId,
|
|
1010
|
+
misbehaviorSummary: misbehavior.summary,
|
|
1011
|
+
errorWire: "ollama"
|
|
1012
|
+
});
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1008
1015
|
const latency = fixture.latency ?? defaults.latency;
|
|
1009
1016
|
const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
|
|
1017
|
+
const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
|
|
1018
|
+
const streamTiming = {
|
|
1019
|
+
latency,
|
|
1020
|
+
streamingProfile: fixture.streamingProfile,
|
|
1021
|
+
recordedTimings: fixture.recordedTimings,
|
|
1022
|
+
replaySpeed
|
|
1023
|
+
};
|
|
1024
|
+
const jsonOpts = (payloadLength, duplicateId = false) => ({
|
|
1025
|
+
surface: "other",
|
|
1026
|
+
payloadLength,
|
|
1027
|
+
chunkSize,
|
|
1028
|
+
recordedTimings: fixture.recordedTimings,
|
|
1029
|
+
duplicateId,
|
|
1030
|
+
replaySpeed
|
|
1031
|
+
});
|
|
1010
1032
|
const streaming = generateReq.stream !== false;
|
|
1011
1033
|
if (isErrorResponse(response)) {
|
|
1012
1034
|
const status = response.status ?? 500;
|
|
@@ -1047,26 +1069,10 @@ async function handleOllamaGenerate(req, res, raw, fixtures, journal, defaults,
|
|
|
1047
1069
|
});
|
|
1048
1070
|
const effectiveStrict = resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression;
|
|
1049
1071
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, defaults.logger);
|
|
1050
|
-
if (!streaming) {
|
|
1051
|
-
|
|
1052
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1053
|
-
res.end(JSON.stringify(body));
|
|
1054
|
-
} else {
|
|
1072
|
+
if (!streaming) await deliverJson(res, journalEntry, fixture, () => buildOllamaGenerateTextResponse(response.content, completionReq.model, effReasoning), jsonOpts(servedPayloadLength({ content: response.content }, effReasoning)));
|
|
1073
|
+
else {
|
|
1055
1074
|
const chunks = buildOllamaGenerateTextChunks(response.content, completionReq.model, chunkSize, effReasoning);
|
|
1056
|
-
|
|
1057
|
-
if (!await writeNDJSONStream(res, chunks, {
|
|
1058
|
-
latency,
|
|
1059
|
-
streamingProfile: fixture.streamingProfile,
|
|
1060
|
-
recordedTimings: fixture.recordedTimings,
|
|
1061
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
1062
|
-
signal: interruption?.signal,
|
|
1063
|
-
onChunkSent: interruption?.tick
|
|
1064
|
-
})) {
|
|
1065
|
-
if (!res.writableEnded) res.destroy();
|
|
1066
|
-
journalEntry.response.interrupted = true;
|
|
1067
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
1068
|
-
}
|
|
1069
|
-
interruption?.cleanup();
|
|
1075
|
+
await deliverStream(res, journalEntry, fixture, ndjsonCodec(), chunks, streamTiming);
|
|
1070
1076
|
}
|
|
1071
1077
|
return;
|
|
1072
1078
|
}
|