@copilotkit/aimock 1.37.4 → 1.38.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 +22 -0
- package/README.md +27 -9
- package/dist/agui-recorder.cjs +6 -0
- package/dist/agui-recorder.cjs.map +1 -1
- package/dist/agui-recorder.d.cts.map +1 -1
- package/dist/agui-recorder.d.ts.map +1 -1
- package/dist/agui-recorder.js +6 -0
- package/dist/agui-recorder.js.map +1 -1
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/api-key-auth.cjs +166 -0
- package/dist/api-key-auth.cjs.map +1 -0
- package/dist/api-key-auth.d.cts +17 -0
- package/dist/api-key-auth.d.cts.map +1 -0
- package/dist/api-key-auth.d.ts +17 -0
- package/dist/api-key-auth.d.ts.map +1 -0
- package/dist/api-key-auth.js +158 -0
- package/dist/api-key-auth.js.map +1 -0
- package/dist/cli.cjs +4 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/config-loader.cjs +4 -2
- package/dist/config-loader.cjs.map +1 -1
- package/dist/config-loader.d.cts +2 -1
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/config-loader.d.ts +2 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +5 -3
- package/dist/config-loader.js.map +1 -1
- package/dist/fal-audio.cjs +2 -0
- package/dist/fal-audio.cjs.map +1 -1
- package/dist/fal-audio.d.cts.map +1 -1
- package/dist/fal-audio.d.ts.map +1 -1
- package/dist/fal-audio.js +2 -0
- package/dist/fal-audio.js.map +1 -1
- package/dist/fal.cjs +4 -1
- package/dist/fal.cjs.map +1 -1
- package/dist/fal.d.cts.map +1 -1
- package/dist/fal.d.ts.map +1 -1
- package/dist/fal.js +4 -1
- package/dist/fal.js.map +1 -1
- package/dist/fixture-loader.cjs +0 -0
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts +3 -1
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts +3 -1
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +0 -0
- package/dist/fixture-loader.js.map +1 -1
- package/dist/grok-video.cjs +9 -2
- package/dist/grok-video.cjs.map +1 -1
- package/dist/grok-video.js +10 -3
- package/dist/grok-video.js.map +1 -1
- package/dist/helpers.cjs +16 -22
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +16 -21
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/llmock.cjs +14 -3
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +4 -2
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +4 -2
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +15 -5
- package/dist/llmock.js.map +1 -1
- package/dist/openrouter-chat.cjs +333 -0
- package/dist/openrouter-chat.cjs.map +1 -0
- package/dist/openrouter-chat.js +325 -0
- package/dist/openrouter-chat.js.map +1 -0
- package/dist/openrouter-video.cjs +24 -7
- package/dist/openrouter-video.cjs.map +1 -1
- package/dist/openrouter-video.d.cts.map +1 -1
- package/dist/openrouter-video.d.ts.map +1 -1
- package/dist/openrouter-video.js +25 -8
- package/dist/openrouter-video.js.map +1 -1
- package/dist/provider-auth.cjs +20 -0
- package/dist/provider-auth.cjs.map +1 -1
- package/dist/provider-auth.js +20 -1
- package/dist/provider-auth.js.map +1 -1
- package/dist/recorder.cjs +50 -8
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.d.cts.map +1 -1
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +50 -10
- package/dist/recorder.js.map +1 -1
- package/dist/responses.cjs +200 -89
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts +18 -3
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts +18 -3
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +199 -90
- package/dist/responses.js.map +1 -1
- package/dist/server.cjs +156 -66
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +1 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +157 -68
- package/dist/server.js.map +1 -1
- package/dist/sse-writer.cjs +3 -0
- package/dist/sse-writer.cjs.map +1 -1
- package/dist/sse-writer.d.cts +8 -0
- package/dist/sse-writer.d.cts.map +1 -1
- package/dist/sse-writer.d.ts +8 -0
- package/dist/sse-writer.d.ts.map +1 -1
- package/dist/sse-writer.js +3 -0
- package/dist/sse-writer.js.map +1 -1
- package/dist/stream-collapse.cjs +26 -0
- package/dist/stream-collapse.cjs.map +1 -1
- package/dist/stream-collapse.d.cts +7 -0
- package/dist/stream-collapse.d.cts.map +1 -1
- package/dist/stream-collapse.d.ts +7 -0
- package/dist/stream-collapse.d.ts.map +1 -1
- package/dist/stream-collapse.js +26 -0
- package/dist/stream-collapse.js.map +1 -1
- package/dist/transcription.cjs +49 -2
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.d.cts.map +1 -1
- package/dist/transcription.d.ts.map +1 -1
- package/dist/transcription.js +50 -3
- package/dist/transcription.js.map +1 -1
- package/dist/types.d.cts +187 -5
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +187 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/veo-video.cjs +9 -2
- package/dist/veo-video.cjs.map +1 -1
- package/dist/veo-video.js +10 -3
- package/dist/veo-video.js.map +1 -1
- package/dist/ws-realtime.cjs +306 -57
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts +1 -0
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts +1 -0
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +307 -58
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +11 -6
- 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 +12 -7
- package/dist/ws-responses.js.map +1 -1
- package/package.json +1 -1
- package/skills/write-fixtures/SKILL.md +53 -19
package/dist/server.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
2
|
+
const require_api_key_auth = require('./api-key-auth.cjs');
|
|
2
3
|
const require_helpers = require('./helpers.cjs');
|
|
3
4
|
const require_logger = require('./logger.cjs');
|
|
4
5
|
const require_journal = require('./journal.cjs');
|
|
@@ -6,6 +7,7 @@ const require_router = require('./router.cjs');
|
|
|
6
7
|
const require_fixture_loader = require('./fixture-loader.cjs');
|
|
7
8
|
const require_sse_writer = require('./sse-writer.cjs');
|
|
8
9
|
const require_interruption = require('./interruption.cjs');
|
|
10
|
+
const require_openrouter_chat = require('./openrouter-chat.cjs');
|
|
9
11
|
const require_chaos = require('./chaos.cjs');
|
|
10
12
|
const require_recorder = require('./recorder.cjs');
|
|
11
13
|
const require_responses = require('./responses.cjs');
|
|
@@ -311,7 +313,7 @@ async function handleControlAPI(req, res, pathname, fixtures, journal, videoStat
|
|
|
311
313
|
handleNotFound(res, `Unknown control endpoint: ${pathname}`);
|
|
312
314
|
return true;
|
|
313
315
|
}
|
|
314
|
-
async function handleCompletions(req, res, fixtures, journal, defaults, modelFallback, providerKey) {
|
|
316
|
+
async function handleCompletions(req, res, fixtures, journal, defaults, modelFallback, providerKey, openRouter = false) {
|
|
315
317
|
setCorsHeaders(res);
|
|
316
318
|
let raw;
|
|
317
319
|
try {
|
|
@@ -328,7 +330,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
328
330
|
fixture: null
|
|
329
331
|
}
|
|
330
332
|
});
|
|
331
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
333
|
+
require_sse_writer.writeErrorResponse(res, 500, openRouter ? require_openrouter_chat.serializeOpenRouterError(500, `Request body read failed: ${msg}`) : JSON.stringify({ error: {
|
|
332
334
|
message: `Request body read failed: ${msg}`,
|
|
333
335
|
type: "server_error"
|
|
334
336
|
} }));
|
|
@@ -350,7 +352,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
350
352
|
fixture: null
|
|
351
353
|
}
|
|
352
354
|
});
|
|
353
|
-
require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
|
|
355
|
+
require_sse_writer.writeErrorResponse(res, 400, openRouter ? require_openrouter_chat.serializeOpenRouterError(400, `Malformed JSON: ${detail}`) : JSON.stringify({ error: {
|
|
354
356
|
message: `Malformed JSON: ${detail}`,
|
|
355
357
|
type: "invalid_request_error",
|
|
356
358
|
param: null,
|
|
@@ -369,7 +371,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
369
371
|
fixture: null
|
|
370
372
|
}
|
|
371
373
|
});
|
|
372
|
-
require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
|
|
374
|
+
require_sse_writer.writeErrorResponse(res, 400, openRouter ? require_openrouter_chat.serializeOpenRouterError(400, "Missing required parameter: 'messages'") : JSON.stringify({ error: {
|
|
373
375
|
message: "Missing required parameter: 'messages'",
|
|
374
376
|
type: "invalid_request_error",
|
|
375
377
|
param: null,
|
|
@@ -383,9 +385,66 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
383
385
|
body._endpointType = "chat";
|
|
384
386
|
body._context = require_helpers.getContext(req);
|
|
385
387
|
const testId = require_helpers.getTestId(req);
|
|
386
|
-
const
|
|
388
|
+
const matchOptions = require_router.recordMatchOptions(!!(defaults.record && providerKey), defaults.logger);
|
|
389
|
+
let fixture = null;
|
|
390
|
+
let skippedBySequenceOrTurn = 0;
|
|
391
|
+
let preResolvedResponse = null;
|
|
392
|
+
let responseModel = body.model;
|
|
393
|
+
let fixtureCountIncremented = false;
|
|
394
|
+
if (openRouter && Array.isArray(body.models) && body.models.length > 0) {
|
|
395
|
+
const candidates = require_openrouter_chat.buildOpenRouterCandidates(body);
|
|
396
|
+
let matchCounts = journal.getFixtureMatchCountsForTest(testId);
|
|
397
|
+
const allowFallbacks = body.provider?.allow_fallbacks !== false;
|
|
398
|
+
let lastErrorFixture = null;
|
|
399
|
+
let lastErrorResponse = null;
|
|
400
|
+
const resolveCandidate = async (candidate) => {
|
|
401
|
+
const probe = {
|
|
402
|
+
...body,
|
|
403
|
+
model: candidate
|
|
404
|
+
};
|
|
405
|
+
const attempt = require_router.matchFixtureDiagnostic(fixtures, probe, matchCounts, defaults.requestTransform, matchOptions);
|
|
406
|
+
skippedBySequenceOrTurn = Math.max(skippedBySequenceOrTurn, attempt.skippedBySequenceOrTurn);
|
|
407
|
+
if (!attempt.fixture) return null;
|
|
408
|
+
const response = await require_helpers.resolveResponse(attempt.fixture, probe);
|
|
409
|
+
return {
|
|
410
|
+
fixture: attempt.fixture,
|
|
411
|
+
response,
|
|
412
|
+
isError: require_helpers.isErrorResponse(response)
|
|
413
|
+
};
|
|
414
|
+
};
|
|
415
|
+
for (const candidate of candidates) {
|
|
416
|
+
const outcome = await resolveCandidate(candidate);
|
|
417
|
+
if (!outcome) {
|
|
418
|
+
if (!allowFallbacks) break;
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
journal.incrementFixtureMatchCount(outcome.fixture, fixtures, testId);
|
|
422
|
+
fixtureCountIncremented = true;
|
|
423
|
+
matchCounts = journal.getFixtureMatchCountsForTest(testId);
|
|
424
|
+
responseModel = candidate;
|
|
425
|
+
if (outcome.isError) {
|
|
426
|
+
const errorFallsThrough = outcome.response.fallthrough !== false;
|
|
427
|
+
if (allowFallbacks && errorFallsThrough) {
|
|
428
|
+
lastErrorFixture = outcome.fixture;
|
|
429
|
+
lastErrorResponse = outcome.response;
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
fixture = outcome.fixture;
|
|
434
|
+
preResolvedResponse = outcome.response;
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
if (!fixture && lastErrorFixture) {
|
|
438
|
+
fixture = lastErrorFixture;
|
|
439
|
+
preResolvedResponse = lastErrorResponse;
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
const single = require_router.matchFixtureDiagnostic(fixtures, body, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform, matchOptions);
|
|
443
|
+
fixture = single.fixture;
|
|
444
|
+
skippedBySequenceOrTurn = single.skippedBySequenceOrTurn;
|
|
445
|
+
}
|
|
387
446
|
if (fixture) {
|
|
388
|
-
journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
447
|
+
if (!fixtureCountIncremented) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
389
448
|
defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
|
|
390
449
|
} else {
|
|
391
450
|
const lastUserMsg = body.messages.filter((m) => m.role === "user").pop();
|
|
@@ -423,7 +482,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
423
482
|
...require_helpers.strictOverrideField(defaults.strict, req.headers)
|
|
424
483
|
}
|
|
425
484
|
});
|
|
426
|
-
require_sse_writer.writeErrorResponse(res, strictStatus, JSON.stringify({ error: {
|
|
485
|
+
require_sse_writer.writeErrorResponse(res, strictStatus, openRouter ? require_openrouter_chat.serializeOpenRouterError(strictStatus, strictMessage) : JSON.stringify({ error: {
|
|
427
486
|
message: strictMessage,
|
|
428
487
|
type: "invalid_request_error",
|
|
429
488
|
param: null,
|
|
@@ -474,7 +533,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
474
533
|
...require_helpers.strictOverrideField(defaults.strict, req.headers)
|
|
475
534
|
}
|
|
476
535
|
});
|
|
477
|
-
require_sse_writer.writeErrorResponse(res, 404, JSON.stringify({ error: {
|
|
536
|
+
require_sse_writer.writeErrorResponse(res, 404, openRouter ? require_openrouter_chat.serializeOpenRouterError(404, "No fixture matched") : JSON.stringify({ error: {
|
|
478
537
|
message: "No fixture matched",
|
|
479
538
|
type: "invalid_request_error",
|
|
480
539
|
param: null,
|
|
@@ -482,10 +541,23 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
482
541
|
} }));
|
|
483
542
|
return;
|
|
484
543
|
}
|
|
485
|
-
const response = await require_helpers.resolveResponse(fixture, body);
|
|
544
|
+
const response = preResolvedResponse ?? await require_helpers.resolveResponse(fixture, body);
|
|
486
545
|
const latency = fixture.latency ?? defaults.latency;
|
|
487
546
|
const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
|
|
488
|
-
const
|
|
547
|
+
const emitStreamingUsage = body.stream === true && body.stream_options?.include_usage === true || openRouter;
|
|
548
|
+
const streamingPromptText = body.messages.map((m) => typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((p) => p.text ?? "").join("") : "").join("");
|
|
549
|
+
const resolveStreamingUsageTokens = (overrides, completionText) => require_helpers.resolveUsage(overrides, streamingPromptText, completionText);
|
|
550
|
+
const shapeORCompletion = (completion, overrides) => {
|
|
551
|
+
if (!openRouter) return completion;
|
|
552
|
+
return require_openrouter_chat.shapeOpenRouterCompletion(completion, require_openrouter_chat.resolveOpenRouterShaping(overrides, overrides?.model ?? responseModel), overrides?.id !== void 0);
|
|
553
|
+
};
|
|
554
|
+
const shapeORChunks = (chunks, usageChunk, overrides) => {
|
|
555
|
+
if (!openRouter) return;
|
|
556
|
+
const shaping = require_openrouter_chat.resolveOpenRouterShaping(overrides, overrides?.model ?? responseModel);
|
|
557
|
+
require_openrouter_chat.shapeOpenRouterChunks(chunks, shaping, overrides?.id !== void 0);
|
|
558
|
+
if (usageChunk) require_openrouter_chat.shapeOpenRouterChunks([usageChunk], shaping, overrides?.id !== void 0);
|
|
559
|
+
};
|
|
560
|
+
const openRouterProcessing = !!(openRouter && fixture.openRouterProcessing);
|
|
489
561
|
if (require_helpers.isErrorResponse(response)) {
|
|
490
562
|
const status = response.status ?? 500;
|
|
491
563
|
journal.add({
|
|
@@ -498,7 +570,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
498
570
|
fixture
|
|
499
571
|
}
|
|
500
572
|
});
|
|
501
|
-
require_sse_writer.writeErrorResponse(res, status, require_helpers.serializeErrorResponse(response), { retryAfter: response.retryAfter });
|
|
573
|
+
require_sse_writer.writeErrorResponse(res, status, openRouter ? require_openrouter_chat.serializeOpenRouterError(status, response.error.message, response.error.metadata) : require_helpers.serializeErrorResponse(response), { retryAfter: response.retryAfter });
|
|
502
574
|
return;
|
|
503
575
|
}
|
|
504
576
|
if (require_helpers.isAudioResponse(response)) {
|
|
@@ -512,7 +584,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
512
584
|
fixture
|
|
513
585
|
}
|
|
514
586
|
});
|
|
515
|
-
require_sse_writer.writeErrorResponse(res, 422, JSON.stringify({ error: {
|
|
587
|
+
require_sse_writer.writeErrorResponse(res, 422, openRouter ? require_openrouter_chat.serializeOpenRouterError(422, "Audio responses are not supported on the chat completions endpoint. Use Gemini generateContent or a dedicated audio endpoint.") : JSON.stringify({ error: {
|
|
516
588
|
message: "Audio responses are not supported on the chat completions endpoint. Use Gemini generateContent or a dedicated audio endpoint.",
|
|
517
589
|
type: "invalid_request_error"
|
|
518
590
|
} }));
|
|
@@ -522,7 +594,9 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
522
594
|
if (response.webSearches?.length) defaults.logger.warn("webSearches in fixture response are not supported for Chat Completions API — ignoring");
|
|
523
595
|
const overrides = require_helpers.extractOverrides(response);
|
|
524
596
|
const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
|
|
525
|
-
const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning,
|
|
597
|
+
const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, responseModel, effectiveStrict, defaults.logger);
|
|
598
|
+
const streaming = body.stream === true;
|
|
599
|
+
const streamingBlocks = streaming && response.blocks && response.blocks.length > 0 ? require_helpers.resolveFixtureBlocks(response.blocks) : void 0;
|
|
526
600
|
const journalEntry = journal.add({
|
|
527
601
|
method: req.method ?? "POST",
|
|
528
602
|
path: req.url ?? COMPLETIONS_PATH,
|
|
@@ -533,22 +607,15 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
533
607
|
fixture
|
|
534
608
|
}
|
|
535
609
|
});
|
|
536
|
-
if (
|
|
537
|
-
const completion = require_helpers.buildContentWithToolCallsCompletion(response.content ?? "", response.toolCalls ?? [],
|
|
610
|
+
if (!streaming) {
|
|
611
|
+
const completion = require_helpers.buildContentWithToolCallsCompletion(response.content ?? "", response.toolCalls ?? [], responseModel, effReasoning, overrides, body.messages);
|
|
538
612
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
539
|
-
res.end(JSON.stringify(completion));
|
|
613
|
+
res.end(JSON.stringify(shapeORCompletion(completion, overrides)));
|
|
540
614
|
} else {
|
|
541
|
-
const chunks = require_helpers.buildContentWithToolCallsChunks(response.content ?? "", response.toolCalls ?? [],
|
|
542
|
-
const completionText = (response.content ?? "") + (response.toolCalls ?? []).map((tc) => tc.name + tc.arguments).join("");
|
|
543
|
-
const usageChunk =
|
|
544
|
-
|
|
545
|
-
completion_tokens: overrides.usage.completion_tokens ?? 0,
|
|
546
|
-
total_tokens: overrides.usage.total_tokens ?? (overrides.usage.prompt_tokens ?? 0) + (overrides.usage.completion_tokens ?? 0)
|
|
547
|
-
} : {
|
|
548
|
-
prompt_tokens: require_helpers.estimatePromptTokens(body.messages),
|
|
549
|
-
completion_tokens: require_helpers.estimateTokens(completionText),
|
|
550
|
-
total_tokens: require_helpers.estimatePromptTokens(body.messages) + require_helpers.estimateTokens(completionText)
|
|
551
|
-
}, overrides?.systemFingerprint) : void 0;
|
|
615
|
+
const chunks = require_helpers.buildContentWithToolCallsChunks(response.content ?? "", response.toolCalls ?? [], responseModel, chunkSize, effReasoning, overrides, streamingBlocks);
|
|
616
|
+
const completionText = streamingBlocks ? streamingBlocks.map((b) => b.type === "text" ? b.text : b.name + b.arguments).join("") : (response.content ?? "") + (response.toolCalls ?? []).map((tc) => tc.name + tc.arguments).join("");
|
|
617
|
+
const usageChunk = emitStreamingUsage ? require_helpers.buildUsageChunk(chunks[0]?.id ?? "chatcmpl-unknown", overrides?.model ?? responseModel, chunks[0]?.created ?? Math.floor(Date.now() / 1e3), resolveStreamingUsageTokens(overrides, completionText), overrides?.systemFingerprint) : void 0;
|
|
618
|
+
shapeORChunks(chunks, usageChunk, overrides);
|
|
552
619
|
const interruption = require_interruption.createInterruptionSignal(fixture);
|
|
553
620
|
if (!await require_sse_writer.writeSSEStream(res, chunks, {
|
|
554
621
|
latency,
|
|
@@ -557,7 +624,8 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
557
624
|
onChunkSent: interruption?.tick,
|
|
558
625
|
usageChunk,
|
|
559
626
|
recordedTimings: fixture.recordedTimings,
|
|
560
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed
|
|
627
|
+
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
628
|
+
openRouterProcessing
|
|
561
629
|
})) {
|
|
562
630
|
if (!res.writableEnded) res.destroy();
|
|
563
631
|
journalEntry.response.interrupted = true;
|
|
@@ -571,7 +639,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
571
639
|
if (response.webSearches?.length) defaults.logger.warn("webSearches in fixture response are not supported for Chat Completions API — ignoring");
|
|
572
640
|
const overrides = require_helpers.extractOverrides(response);
|
|
573
641
|
const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
|
|
574
|
-
const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning,
|
|
642
|
+
const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, responseModel, effectiveStrict, defaults.logger);
|
|
575
643
|
const journalEntry = journal.add({
|
|
576
644
|
method: req.method ?? "POST",
|
|
577
645
|
path: req.url ?? COMPLETIONS_PATH,
|
|
@@ -583,20 +651,13 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
583
651
|
}
|
|
584
652
|
});
|
|
585
653
|
if (body.stream !== true) {
|
|
586
|
-
const completion = require_helpers.buildTextCompletion(response.content,
|
|
654
|
+
const completion = require_helpers.buildTextCompletion(response.content, responseModel, effReasoning, overrides, body.messages);
|
|
587
655
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
588
|
-
res.end(JSON.stringify(completion));
|
|
656
|
+
res.end(JSON.stringify(shapeORCompletion(completion, overrides)));
|
|
589
657
|
} else {
|
|
590
|
-
const chunks = require_helpers.buildTextChunks(response.content,
|
|
591
|
-
const usageChunk =
|
|
592
|
-
|
|
593
|
-
completion_tokens: overrides.usage.completion_tokens ?? 0,
|
|
594
|
-
total_tokens: overrides.usage.total_tokens ?? (overrides.usage.prompt_tokens ?? 0) + (overrides.usage.completion_tokens ?? 0)
|
|
595
|
-
} : {
|
|
596
|
-
prompt_tokens: require_helpers.estimatePromptTokens(body.messages),
|
|
597
|
-
completion_tokens: require_helpers.estimateTokens(response.content),
|
|
598
|
-
total_tokens: require_helpers.estimatePromptTokens(body.messages) + require_helpers.estimateTokens(response.content)
|
|
599
|
-
}, overrides?.systemFingerprint) : void 0;
|
|
658
|
+
const chunks = require_helpers.buildTextChunks(response.content, responseModel, chunkSize, effReasoning, overrides);
|
|
659
|
+
const usageChunk = emitStreamingUsage ? require_helpers.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;
|
|
660
|
+
shapeORChunks(chunks, usageChunk, overrides);
|
|
600
661
|
const interruption = require_interruption.createInterruptionSignal(fixture);
|
|
601
662
|
if (!await require_sse_writer.writeSSEStream(res, chunks, {
|
|
602
663
|
latency,
|
|
@@ -605,7 +666,8 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
605
666
|
onChunkSent: interruption?.tick,
|
|
606
667
|
usageChunk,
|
|
607
668
|
recordedTimings: fixture.recordedTimings,
|
|
608
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed
|
|
669
|
+
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
670
|
+
openRouterProcessing
|
|
609
671
|
})) {
|
|
610
672
|
if (!res.writableEnded) res.destroy();
|
|
611
673
|
journalEntry.response.interrupted = true;
|
|
@@ -619,7 +681,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
619
681
|
if (response.webSearches?.length) defaults.logger.warn("webSearches in fixture response are not supported for Chat Completions API — ignoring");
|
|
620
682
|
const overrides = require_helpers.extractOverrides(response);
|
|
621
683
|
const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
|
|
622
|
-
const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning,
|
|
684
|
+
const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, responseModel, effectiveStrict, defaults.logger);
|
|
623
685
|
const journalEntry = journal.add({
|
|
624
686
|
method: req.method ?? "POST",
|
|
625
687
|
path: req.url ?? COMPLETIONS_PATH,
|
|
@@ -631,21 +693,14 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
631
693
|
}
|
|
632
694
|
});
|
|
633
695
|
if (body.stream !== true) {
|
|
634
|
-
const completion = require_helpers.buildToolCallCompletion(response.toolCalls,
|
|
696
|
+
const completion = require_helpers.buildToolCallCompletion(response.toolCalls, responseModel, effReasoning, overrides, body.messages);
|
|
635
697
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
636
|
-
res.end(JSON.stringify(completion));
|
|
698
|
+
res.end(JSON.stringify(shapeORCompletion(completion, overrides)));
|
|
637
699
|
} else {
|
|
638
|
-
const chunks = require_helpers.buildToolCallChunks(response.toolCalls,
|
|
700
|
+
const chunks = require_helpers.buildToolCallChunks(response.toolCalls, responseModel, chunkSize, effReasoning, overrides);
|
|
639
701
|
const completionText = response.toolCalls.map((tc) => tc.name + tc.arguments).join("");
|
|
640
|
-
const usageChunk =
|
|
641
|
-
|
|
642
|
-
completion_tokens: overrides.usage.completion_tokens ?? 0,
|
|
643
|
-
total_tokens: overrides.usage.total_tokens ?? (overrides.usage.prompt_tokens ?? 0) + (overrides.usage.completion_tokens ?? 0)
|
|
644
|
-
} : {
|
|
645
|
-
prompt_tokens: require_helpers.estimatePromptTokens(body.messages),
|
|
646
|
-
completion_tokens: require_helpers.estimateTokens(completionText),
|
|
647
|
-
total_tokens: require_helpers.estimatePromptTokens(body.messages) + require_helpers.estimateTokens(completionText)
|
|
648
|
-
}, overrides?.systemFingerprint) : void 0;
|
|
702
|
+
const usageChunk = emitStreamingUsage ? require_helpers.buildUsageChunk(chunks[0]?.id ?? "chatcmpl-unknown", overrides?.model ?? responseModel, chunks[0]?.created ?? Math.floor(Date.now() / 1e3), resolveStreamingUsageTokens(overrides, completionText), overrides?.systemFingerprint) : void 0;
|
|
703
|
+
shapeORChunks(chunks, usageChunk, overrides);
|
|
649
704
|
const interruption = require_interruption.createInterruptionSignal(fixture);
|
|
650
705
|
if (!await require_sse_writer.writeSSEStream(res, chunks, {
|
|
651
706
|
latency,
|
|
@@ -654,7 +709,8 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
654
709
|
onChunkSent: interruption?.tick,
|
|
655
710
|
usageChunk,
|
|
656
711
|
recordedTimings: fixture.recordedTimings,
|
|
657
|
-
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed
|
|
712
|
+
replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
|
|
713
|
+
openRouterProcessing
|
|
658
714
|
})) {
|
|
659
715
|
if (!res.writableEnded) res.destroy();
|
|
660
716
|
journalEntry.response.interrupted = true;
|
|
@@ -674,12 +730,19 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
674
730
|
fixture
|
|
675
731
|
}
|
|
676
732
|
});
|
|
677
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
733
|
+
require_sse_writer.writeErrorResponse(res, 500, openRouter ? require_openrouter_chat.serializeOpenRouterError(500, "Fixture response did not match any known type") : JSON.stringify({ error: {
|
|
678
734
|
message: "Fixture response did not match any known type",
|
|
679
735
|
type: "server_error"
|
|
680
736
|
} }));
|
|
681
737
|
}
|
|
682
738
|
async function createServer(fixtures, options, mounts, serviceFixtures) {
|
|
739
|
+
return createServerWithResolvedAuth(fixtures, options, require_api_key_auth.resolveInboundAuth({
|
|
740
|
+
value: options?.auth,
|
|
741
|
+
label: "options.auth"
|
|
742
|
+
}), mounts, serviceFixtures);
|
|
743
|
+
}
|
|
744
|
+
/** @internal Config startup uses this to avoid parsing a selected auth source twice. */
|
|
745
|
+
async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mounts, serviceFixtures) {
|
|
683
746
|
const host = options?.host ?? "127.0.0.1";
|
|
684
747
|
const port = options?.port ?? 0;
|
|
685
748
|
const logger = new require_logger.Logger(options?.logLevel ?? "silent");
|
|
@@ -793,13 +856,10 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
|
|
|
793
856
|
});
|
|
794
857
|
});
|
|
795
858
|
async function handleHttpRequest(req, res) {
|
|
796
|
-
if (req.method === "OPTIONS") {
|
|
797
|
-
handleOptions(res);
|
|
798
|
-
return;
|
|
799
|
-
}
|
|
800
859
|
const startTime = registry ? process.hrtime.bigint() : 0n;
|
|
801
860
|
const parsedUrl = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
802
861
|
let pathname = parsedUrl.pathname;
|
|
862
|
+
const isOpenRouter = require_openrouter_chat.isOpenRouterPath(pathname);
|
|
803
863
|
if (registry) res.on("finish", () => {
|
|
804
864
|
try {
|
|
805
865
|
const normalizedPath = require_metrics.normalizePathLabel(pathname);
|
|
@@ -819,6 +879,17 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
|
|
|
819
879
|
defaults.logger.warn("metrics instrumentation error", err);
|
|
820
880
|
}
|
|
821
881
|
});
|
|
882
|
+
if (req.method === "OPTIONS" && (!resolvedAuth.policy.enabled || req.headers.origin !== void 0 && req.headers["access-control-request-method"] !== void 0)) {
|
|
883
|
+
handleOptions(res);
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
if (!(req.method === "GET" && (pathname === HEALTH_PATH || pathname === READY_PATH || pathname === "/metrics"))) {
|
|
887
|
+
if (!require_api_key_auth.validateRequestApiKey(req, resolvedAuth.policy).ok) {
|
|
888
|
+
require_api_key_auth.writeApiKeyHttpRejection(res, setCorsHeaders);
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
require_api_key_auth.markAuthenticatedRequest(req, resolvedAuth.policy);
|
|
892
|
+
}
|
|
822
893
|
if (pathname.startsWith(CONTROL_PREFIX)) {
|
|
823
894
|
await handleControlAPI(req, res, pathname, fixtures, journal, videoStates, openRouterVideoJobs, veoVideoJobs, grokVideoJobs, defaults);
|
|
824
895
|
return;
|
|
@@ -1003,6 +1074,18 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
|
|
|
1003
1074
|
}
|
|
1004
1075
|
return;
|
|
1005
1076
|
}
|
|
1077
|
+
if (pathname === "/api/v1/models" && req.method === "GET") {
|
|
1078
|
+
require_openrouter_chat.handleOpenRouterModels(req, res, fixtures, journal, defaults, setCorsHeaders);
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
if (pathname === "/api/v1/key" && req.method === "GET") {
|
|
1082
|
+
require_openrouter_chat.handleOpenRouterKey(req, res, journal, setCorsHeaders);
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
if (pathname === "/api/v1/credits" && req.method === "GET") {
|
|
1086
|
+
require_openrouter_chat.handleOpenRouterCredits(req, res, journal, setCorsHeaders);
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1006
1089
|
let azureDeploymentId;
|
|
1007
1090
|
const azureMatch = pathname.match(AZURE_DEPLOYMENT_RE);
|
|
1008
1091
|
if (azureMatch && req.method === "POST") {
|
|
@@ -1728,17 +1811,17 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
|
|
|
1728
1811
|
handleNotFound(res, "Not found");
|
|
1729
1812
|
return;
|
|
1730
1813
|
}
|
|
1731
|
-
const completionsProvider = azureDeploymentId ? "azure" : "openai";
|
|
1814
|
+
const completionsProvider = azureDeploymentId ? "azure" : isOpenRouter ? "openrouter" : "openai";
|
|
1732
1815
|
try {
|
|
1733
|
-
await handleCompletions(req, res, fixtures, journal, defaults, azureDeploymentId, completionsProvider);
|
|
1816
|
+
await handleCompletions(req, res, fixtures, journal, defaults, azureDeploymentId, completionsProvider, isOpenRouter);
|
|
1734
1817
|
} catch (err) {
|
|
1735
1818
|
const msg = err instanceof Error ? err.message : "Internal error";
|
|
1736
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1819
|
+
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, isOpenRouter ? require_openrouter_chat.serializeOpenRouterError(500, msg) : JSON.stringify({ error: {
|
|
1737
1820
|
message: msg,
|
|
1738
1821
|
type: "server_error"
|
|
1739
1822
|
} }));
|
|
1740
1823
|
else if (!res.writableEnded) try {
|
|
1741
|
-
res.write(`data: ${JSON.stringify({ error: {
|
|
1824
|
+
res.write(`data: ${isOpenRouter ? require_openrouter_chat.serializeOpenRouterError(500, msg) : JSON.stringify({ error: {
|
|
1742
1825
|
message: msg,
|
|
1743
1826
|
type: "server_error"
|
|
1744
1827
|
} })}\n\n`);
|
|
@@ -1759,6 +1842,10 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
|
|
|
1759
1842
|
async function handleUpgradeRequest(req, socket, head) {
|
|
1760
1843
|
const parsedUrl = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
1761
1844
|
let pathname = parsedUrl.pathname;
|
|
1845
|
+
if (!require_api_key_auth.validateRequestApiKey(req, resolvedAuth.policy).ok) {
|
|
1846
|
+
require_api_key_auth.writeApiKeyUpgradeRejection(socket);
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1762
1849
|
if (mounts) {
|
|
1763
1850
|
for (const { path: mountPath, handler } of mounts) if ((pathname === mountPath || pathname.startsWith(mountPath + "/")) && handler.handleUpgrade) {
|
|
1764
1851
|
const subPath = pathname.slice(mountPath.length) || "/";
|
|
@@ -1797,10 +1884,12 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
|
|
|
1797
1884
|
upgradeHeaders: req.headers
|
|
1798
1885
|
});
|
|
1799
1886
|
else if (pathname === REALTIME_PATH) {
|
|
1800
|
-
const
|
|
1887
|
+
const transcriptionIntent = parsedUrl.searchParams.get("intent") === "transcription";
|
|
1888
|
+
const model = transcriptionIntent ? "gpt-transcribe" : parsedUrl.searchParams.get("model") ?? "gpt-realtime-2";
|
|
1801
1889
|
require_ws_realtime.handleWebSocketRealtime(ws, fixtures, journal, {
|
|
1802
1890
|
...defaults,
|
|
1803
1891
|
model,
|
|
1892
|
+
transcriptionIntent,
|
|
1804
1893
|
testId: wsTestId,
|
|
1805
1894
|
upgradeHeaders: req.headers
|
|
1806
1895
|
});
|
|
@@ -1850,4 +1939,5 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
|
|
|
1850
1939
|
|
|
1851
1940
|
//#endregion
|
|
1852
1941
|
exports.createServer = createServer;
|
|
1942
|
+
exports.createServerWithResolvedAuth = createServerWithResolvedAuth;
|
|
1853
1943
|
//# sourceMappingURL=server.cjs.map
|