@jeffreycao/copilot-api 1.9.15 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -82
- package/README.zh-CN.md +101 -84
- package/dist/{auth-DEUCqXMV.js → auth-D7YCTWpx.js} +3 -3
- package/dist/{auth-DEUCqXMV.js.map → auth-D7YCTWpx.js.map} +1 -1
- package/dist/{check-usage-OcW_3tEg.js → check-usage-Dgg0nNEw.js} +3 -3
- package/dist/{check-usage-OcW_3tEg.js.map → check-usage-Dgg0nNEw.js.map} +1 -1
- package/dist/main.js +3 -3
- package/dist/{config-DrfmMOO-.js → proxy-De0Po8kG.js} +62 -3
- package/dist/proxy-De0Po8kG.js.map +1 -0
- package/dist/{server-DkUKa2I6.js → server-DpVPS3zt.js} +517 -109
- package/dist/server-DpVPS3zt.js.map +1 -0
- package/dist/{start-DFJynp4A.js → start-DDII-0ML.js} +5 -52
- package/dist/start-DDII-0ML.js.map +1 -0
- package/dist/{token-BOwQe3TO.js → token-BQlDdqtI.js} +2 -2
- package/dist/{token-BOwQe3TO.js.map → token-BQlDdqtI.js.map} +1 -1
- package/dist/{utils-Cj-ToKA6.js → utils-C5ej0z8n.js} +47 -7
- package/dist/utils-C5ej0z8n.js.map +1 -0
- package/package.json +1 -1
- package/pages/index.html +432 -10
- package/dist/config-DrfmMOO-.js.map +0 -1
- package/dist/server-DkUKa2I6.js.map +0 -1
- package/dist/start-DFJynp4A.js.map +0 -1
- package/dist/utils-Cj-ToKA6.js.map +0 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { t as PATHS } from "./paths-DC-mqCY3.js";
|
|
2
|
-
import {
|
|
3
|
-
import { a as
|
|
2
|
+
import { D as generateTraceId, E as prepareMessageProxyHeaders, I as state, M as compactMessageSections, O as requestContext, P as compactSystemPromptStarts, T as prepareInteractionHeaders, _ as copilotWebSocketHeaders, c as getUUID, d as sleep, f as getCopilotUsage, g as copilotHeaders, h as copilotBaseUrl, j as compactAutoContinuePromptStarts, k as resolveTraceId$1, l as isNullish, m as forwardError, n as cacheModels, o as generateRequestIdFromPayload, p as HTTPError, s as getRootSessionId, u as parseUserIdMetadata, w as prepareForCompact } from "./utils-C5ej0z8n.js";
|
|
3
|
+
import { a as getConfig, c as getReasoningEffortForModel, d as isResponsesApiContextManagementModel, f as isResponsesApiWebSearchEnabled, i as getClaudeTokenMultiplier, l as getSmallModel, o as getExtraPromptForModel, p as isResponsesApiWebSocketEnabled, r as getAnthropicApiKey, s as getProviderConfig, t as getProxyEnvDispatcher, u as isMessagesApiEnabled } from "./proxy-De0Po8kG.js";
|
|
4
4
|
import consola from "consola";
|
|
5
5
|
import fs from "node:fs/promises";
|
|
6
6
|
import path from "node:path";
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
7
8
|
import { Hono } from "hono";
|
|
8
9
|
import { cors } from "hono/cors";
|
|
9
10
|
import { logger } from "hono/logger";
|
|
@@ -11,6 +12,7 @@ import fs$1, { readFileSync } from "node:fs";
|
|
|
11
12
|
import { streamSSE } from "hono/streaming";
|
|
12
13
|
import util from "node:util";
|
|
13
14
|
import { events } from "fetch-event-stream";
|
|
15
|
+
import { WebSocket } from "undici";
|
|
14
16
|
//#region src/lib/request-auth.ts
|
|
15
17
|
function normalizeApiKeys(apiKeys) {
|
|
16
18
|
if (!Array.isArray(apiKeys)) {
|
|
@@ -502,19 +504,14 @@ async function flushTokenUsageEvents() {
|
|
|
502
504
|
}
|
|
503
505
|
function getPeriodRange(period, now = /* @__PURE__ */ new Date()) {
|
|
504
506
|
const start = new Date(now);
|
|
507
|
+
start.setHours(0, 0, 0, 0);
|
|
505
508
|
switch (period) {
|
|
506
|
-
case "day":
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
case "week": {
|
|
510
|
-
const daysSinceMonday = (start.getDay() + 6) % 7;
|
|
511
|
-
start.setDate(start.getDate() - daysSinceMonday);
|
|
512
|
-
start.setHours(0, 0, 0, 0);
|
|
509
|
+
case "day": break;
|
|
510
|
+
case "week":
|
|
511
|
+
start.setDate(start.getDate() - 6);
|
|
513
512
|
break;
|
|
514
|
-
}
|
|
515
513
|
case "month":
|
|
516
|
-
start.setDate(
|
|
517
|
-
start.setHours(0, 0, 0, 0);
|
|
514
|
+
start.setDate(start.getDate() - 29);
|
|
518
515
|
break;
|
|
519
516
|
default: break;
|
|
520
517
|
}
|
|
@@ -527,7 +524,7 @@ function getPeriodRange(period, now = /* @__PURE__ */ new Date()) {
|
|
|
527
524
|
end.setDate(end.getDate() + 7);
|
|
528
525
|
break;
|
|
529
526
|
case "month":
|
|
530
|
-
end.
|
|
527
|
+
end.setDate(end.getDate() + 30);
|
|
531
528
|
break;
|
|
532
529
|
default: break;
|
|
533
530
|
}
|
|
@@ -536,6 +533,26 @@ function getPeriodRange(period, now = /* @__PURE__ */ new Date()) {
|
|
|
536
533
|
startMs: start.getTime()
|
|
537
534
|
};
|
|
538
535
|
}
|
|
536
|
+
function formatLocalDate(date) {
|
|
537
|
+
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
538
|
+
}
|
|
539
|
+
function createDailyIntervals(range) {
|
|
540
|
+
const intervals = [];
|
|
541
|
+
const cursor = new Date(range.startMs);
|
|
542
|
+
while (cursor.getTime() < range.endMs) {
|
|
543
|
+
const startMs = cursor.getTime();
|
|
544
|
+
const next = new Date(cursor);
|
|
545
|
+
next.setDate(next.getDate() + 1);
|
|
546
|
+
const endMs = Math.min(next.getTime(), range.endMs);
|
|
547
|
+
intervals.push({
|
|
548
|
+
date: formatLocalDate(cursor),
|
|
549
|
+
endMs,
|
|
550
|
+
startMs
|
|
551
|
+
});
|
|
552
|
+
cursor.setTime(endMs);
|
|
553
|
+
}
|
|
554
|
+
return intervals;
|
|
555
|
+
}
|
|
539
556
|
function createEmptyTotals() {
|
|
540
557
|
return {
|
|
541
558
|
cache_creation_input_tokens: 0,
|
|
@@ -546,6 +563,14 @@ function createEmptyTotals() {
|
|
|
546
563
|
total_tokens: 0
|
|
547
564
|
};
|
|
548
565
|
}
|
|
566
|
+
function addTotals(target, next) {
|
|
567
|
+
target.cache_creation_input_tokens += next.cache_creation_input_tokens;
|
|
568
|
+
target.cache_read_input_tokens += next.cache_read_input_tokens;
|
|
569
|
+
target.input_tokens += next.input_tokens;
|
|
570
|
+
target.output_tokens += next.output_tokens;
|
|
571
|
+
target.request_count += next.request_count;
|
|
572
|
+
target.total_tokens += next.total_tokens;
|
|
573
|
+
}
|
|
549
574
|
function createEmptySummary(period) {
|
|
550
575
|
const range = getPeriodRange(period);
|
|
551
576
|
return {
|
|
@@ -560,6 +585,27 @@ function createEmptySummary(period) {
|
|
|
560
585
|
totals: createEmptyTotals()
|
|
561
586
|
};
|
|
562
587
|
}
|
|
588
|
+
function createEmptyDailySummary(period) {
|
|
589
|
+
const range = getPeriodRange(period);
|
|
590
|
+
return {
|
|
591
|
+
byModel: [],
|
|
592
|
+
days: createDailyIntervals(range).map((interval) => ({
|
|
593
|
+
byModel: [],
|
|
594
|
+
date: interval.date,
|
|
595
|
+
end_ms: interval.endMs,
|
|
596
|
+
start_ms: interval.startMs,
|
|
597
|
+
totals: createEmptyTotals()
|
|
598
|
+
})),
|
|
599
|
+
period,
|
|
600
|
+
range: {
|
|
601
|
+
end_ms: range.endMs,
|
|
602
|
+
end_utc: new Date(range.endMs).toISOString(),
|
|
603
|
+
start_ms: range.startMs,
|
|
604
|
+
start_utc: new Date(range.startMs).toISOString()
|
|
605
|
+
},
|
|
606
|
+
totals: createEmptyTotals()
|
|
607
|
+
};
|
|
608
|
+
}
|
|
563
609
|
function createEmptyEventsPage(input) {
|
|
564
610
|
const range = getPeriodRange(input.period);
|
|
565
611
|
return {
|
|
@@ -577,6 +623,14 @@ function createEmptyEventsPage(input) {
|
|
|
577
623
|
total_pages: 1
|
|
578
624
|
};
|
|
579
625
|
}
|
|
626
|
+
function rangePayload(range) {
|
|
627
|
+
return {
|
|
628
|
+
end_ms: range.endMs,
|
|
629
|
+
end_utc: new Date(range.endMs).toISOString(),
|
|
630
|
+
start_ms: range.startMs,
|
|
631
|
+
start_utc: new Date(range.startMs).toISOString()
|
|
632
|
+
};
|
|
633
|
+
}
|
|
580
634
|
function numberFromRow(row, key) {
|
|
581
635
|
const value = row?.[key];
|
|
582
636
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
@@ -591,6 +645,12 @@ function totalsFromRow(row) {
|
|
|
591
645
|
total_tokens: numberFromRow(row, "total_tokens")
|
|
592
646
|
};
|
|
593
647
|
}
|
|
648
|
+
function modelSummaryFromRow(row) {
|
|
649
|
+
return {
|
|
650
|
+
...totalsFromRow(row),
|
|
651
|
+
model: typeof row.model === "string" ? row.model : "unknown"
|
|
652
|
+
};
|
|
653
|
+
}
|
|
594
654
|
function stringFromRow(row, key) {
|
|
595
655
|
const value = row[key];
|
|
596
656
|
return typeof value === "string" ? value : "";
|
|
@@ -618,12 +678,8 @@ function usageEventFromRow(row) {
|
|
|
618
678
|
user_id: stringFromRow(row, "user_id")
|
|
619
679
|
};
|
|
620
680
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
await flushTokenUsageEvents();
|
|
624
|
-
const range = getPeriodRange(period);
|
|
625
|
-
const db = await getDb();
|
|
626
|
-
const totalsRow = db.prepare(`
|
|
681
|
+
function getTotalsRow(db, range) {
|
|
682
|
+
return db.prepare(`
|
|
627
683
|
SELECT
|
|
628
684
|
COUNT(*) AS request_count,
|
|
629
685
|
COALESCE(SUM(input_tokens), 0) AS input_tokens,
|
|
@@ -634,8 +690,9 @@ async function getTokenUsageSummary(period) {
|
|
|
634
690
|
FROM token_usage_events
|
|
635
691
|
WHERE created_at_ms >= ? AND created_at_ms < ?
|
|
636
692
|
`).get(range.startMs, range.endMs);
|
|
637
|
-
|
|
638
|
-
|
|
693
|
+
}
|
|
694
|
+
function getModelRows(db, range) {
|
|
695
|
+
return db.prepare(`
|
|
639
696
|
SELECT
|
|
640
697
|
model,
|
|
641
698
|
COUNT(*) AS request_count,
|
|
@@ -650,20 +707,47 @@ async function getTokenUsageSummary(period) {
|
|
|
650
707
|
ORDER BY
|
|
651
708
|
total_tokens DESC,
|
|
652
709
|
model ASC
|
|
653
|
-
`).all(range.startMs, range.endMs)
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
710
|
+
`).all(range.startMs, range.endMs);
|
|
711
|
+
}
|
|
712
|
+
function createDailyBucket(interval, rows) {
|
|
713
|
+
const byModel = rows.map((row) => modelSummaryFromRow(row));
|
|
714
|
+
const totals = createEmptyTotals();
|
|
715
|
+
for (const model of byModel) addTotals(totals, model);
|
|
716
|
+
return {
|
|
717
|
+
byModel,
|
|
718
|
+
date: interval.date,
|
|
719
|
+
end_ms: interval.endMs,
|
|
720
|
+
start_ms: interval.startMs,
|
|
721
|
+
totals
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
async function getTokenUsageSummary(period) {
|
|
725
|
+
if (!isTokenUsageStorageEnabled()) return createEmptySummary(period);
|
|
726
|
+
await flushTokenUsageEvents();
|
|
727
|
+
const range = getPeriodRange(period);
|
|
728
|
+
const db = await getDb();
|
|
729
|
+
const totalsRow = getTotalsRow(db, range);
|
|
730
|
+
return {
|
|
731
|
+
byModel: getModelRows(db, range).map((row) => modelSummaryFromRow(row)),
|
|
657
732
|
period,
|
|
658
|
-
range:
|
|
659
|
-
end_ms: range.endMs,
|
|
660
|
-
end_utc: new Date(range.endMs).toISOString(),
|
|
661
|
-
start_ms: range.startMs,
|
|
662
|
-
start_utc: new Date(range.startMs).toISOString()
|
|
663
|
-
},
|
|
733
|
+
range: rangePayload(range),
|
|
664
734
|
totals: totalsFromRow(totalsRow)
|
|
665
735
|
};
|
|
666
736
|
}
|
|
737
|
+
async function getTokenUsageDailySummary(period) {
|
|
738
|
+
if (!isTokenUsageStorageEnabled()) return createEmptyDailySummary(period);
|
|
739
|
+
await flushTokenUsageEvents();
|
|
740
|
+
const range = getPeriodRange(period);
|
|
741
|
+
const db = await getDb();
|
|
742
|
+
const intervals = createDailyIntervals(range);
|
|
743
|
+
return {
|
|
744
|
+
byModel: getModelRows(db, range).map((row) => modelSummaryFromRow(row)),
|
|
745
|
+
days: intervals.map((interval) => createDailyBucket(interval, getModelRows(db, interval))),
|
|
746
|
+
period,
|
|
747
|
+
range: rangePayload(range),
|
|
748
|
+
totals: totalsFromRow(getTotalsRow(db, range))
|
|
749
|
+
};
|
|
750
|
+
}
|
|
667
751
|
async function getTokenUsageEventsPage(input) {
|
|
668
752
|
if (!isTokenUsageStorageEnabled()) return createEmptyEventsPage(input);
|
|
669
753
|
await flushTokenUsageEvents();
|
|
@@ -831,10 +915,14 @@ const copilotRateLimitHeaders = {
|
|
|
831
915
|
session: "x-usage-ratelimit-session",
|
|
832
916
|
weekly: "x-usage-ratelimit-weekly"
|
|
833
917
|
};
|
|
918
|
+
const copilotQuotaSnapshotKeys = {
|
|
919
|
+
session: "5Hour-Session-RateLimits",
|
|
920
|
+
weekly: "Weekly-Session-RateLimits"
|
|
921
|
+
};
|
|
834
922
|
const hasGetMethod = (headers) => {
|
|
835
923
|
return "get" in headers && typeof headers.get === "function";
|
|
836
924
|
};
|
|
837
|
-
const getHeaderValue = (headers, headerName) => {
|
|
925
|
+
const getHeaderValue$1 = (headers, headerName) => {
|
|
838
926
|
if (hasGetMethod(headers)) return headers.get(headerName);
|
|
839
927
|
const normalizedHeaderName = headerName.toLowerCase();
|
|
840
928
|
return Object.entries(headers).find(([key]) => key.toLowerCase() === normalizedHeaderName)?.[1] ?? null;
|
|
@@ -851,7 +939,7 @@ const parseCopilotRateLimitHeader = (headerValue) => {
|
|
|
851
939
|
};
|
|
852
940
|
const getCopilotRateLimitUsage = (headers, type) => {
|
|
853
941
|
const headerName = copilotRateLimitHeaders[type];
|
|
854
|
-
const headerValue = getHeaderValue(headers, headerName);
|
|
942
|
+
const headerValue = getHeaderValue$1(headers, headerName);
|
|
855
943
|
if (!headerValue) return null;
|
|
856
944
|
const parsed = parseCopilotRateLimitHeader(headerValue);
|
|
857
945
|
if (!parsed) return null;
|
|
@@ -860,15 +948,39 @@ const getCopilotRateLimitUsage = (headers, type) => {
|
|
|
860
948
|
...parsed
|
|
861
949
|
};
|
|
862
950
|
};
|
|
951
|
+
const getCopilotRateLimitUsageFromSnapshots = (snapshots, type) => {
|
|
952
|
+
const snapshot = snapshots?.[copilotQuotaSnapshotKeys[type]];
|
|
953
|
+
if (!isCopilotQuotaSnapshot(snapshot)) return null;
|
|
954
|
+
return {
|
|
955
|
+
remaining: String(snapshot.percent_remaining),
|
|
956
|
+
resetAt: snapshot.reset_date,
|
|
957
|
+
type
|
|
958
|
+
};
|
|
959
|
+
};
|
|
863
960
|
const logCopilotRateLimits = (headers) => {
|
|
864
961
|
for (const type of copilotRateLimitTypes) {
|
|
865
962
|
const usage = getCopilotRateLimitUsage(headers, type);
|
|
866
963
|
if (!usage) continue;
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
964
|
+
logCopilotRateLimitUsage(usage);
|
|
965
|
+
}
|
|
966
|
+
};
|
|
967
|
+
const logCopilotQuotaSnapshots = (snapshots) => {
|
|
968
|
+
for (const type of copilotRateLimitTypes) {
|
|
969
|
+
const usage = getCopilotRateLimitUsageFromSnapshots(snapshots, type);
|
|
970
|
+
if (!usage) continue;
|
|
971
|
+
logCopilotRateLimitUsage(usage);
|
|
870
972
|
}
|
|
871
973
|
};
|
|
974
|
+
const logCopilotRateLimitUsage = (usage) => {
|
|
975
|
+
const d = new Date(usage.resetAt);
|
|
976
|
+
const dateStr = Number.isNaN(d.getTime()) ? usage.resetAt : d.toLocaleString();
|
|
977
|
+
consola.info(`Copilot ${usage.type} quota remaining: ${usage.remaining}, resets at: ${dateStr}`);
|
|
978
|
+
};
|
|
979
|
+
const isCopilotQuotaSnapshot = (value) => {
|
|
980
|
+
if (!value || typeof value !== "object") return false;
|
|
981
|
+
const record = value;
|
|
982
|
+
return typeof record.entitlement === "string" && typeof record.percent_remaining === "number" && typeof record.overage_permitted === "boolean" && typeof record.overage_count === "number" && typeof record.reset_date === "string";
|
|
983
|
+
};
|
|
872
984
|
//#endregion
|
|
873
985
|
//#region src/services/copilot/create-chat-completions.ts
|
|
874
986
|
const createChatCompletions = async (payload, options) => {
|
|
@@ -2426,9 +2538,76 @@ const adjustInputTokens = (providerConfig, usage) => {
|
|
|
2426
2538
|
usage.input_tokens = Math.max(0, (usage.input_tokens ?? 0) - (usage.cache_read_input_tokens ?? 0) - (usage.cache_creation_input_tokens ?? 0));
|
|
2427
2539
|
debugJson(logger$4, "provider.messages.adjusted_usage:", usage);
|
|
2428
2540
|
};
|
|
2541
|
+
const responsesUtilsDependencies = {
|
|
2542
|
+
isResponsesApiContextManagementModel,
|
|
2543
|
+
isResponsesApiWebSocketEnabled
|
|
2544
|
+
};
|
|
2545
|
+
const getResponsesRequestOptions = (payload) => {
|
|
2546
|
+
return {
|
|
2547
|
+
vision: hasVisionInput(payload),
|
|
2548
|
+
initiator: hasAgentInitiator(payload) ? "agent" : "user"
|
|
2549
|
+
};
|
|
2550
|
+
};
|
|
2551
|
+
const getResponsesTransportForModel = (selectedModel, options = {}) => {
|
|
2552
|
+
const supportedEndpoints = selectedModel?.supported_endpoints ?? [];
|
|
2553
|
+
const useWebSocket = responsesUtilsDependencies.isResponsesApiWebSocketEnabled();
|
|
2554
|
+
if (options.compactType !== 1 && useWebSocket && supportedEndpoints.includes("ws:/responses")) return "websocket";
|
|
2555
|
+
if (supportedEndpoints.includes("/responses")) return "http";
|
|
2556
|
+
return null;
|
|
2557
|
+
};
|
|
2558
|
+
const hasAgentInitiator = (payload) => {
|
|
2559
|
+
const lastItem = getPayloadItems(payload).at(-1);
|
|
2560
|
+
if (!lastItem) return false;
|
|
2561
|
+
if (!("role" in lastItem) || !lastItem.role) return true;
|
|
2562
|
+
return (typeof lastItem.role === "string" ? lastItem.role.toLowerCase() : "") === "assistant";
|
|
2563
|
+
};
|
|
2564
|
+
const hasVisionInput = (payload) => {
|
|
2565
|
+
return getPayloadItems(payload).some((item) => containsVisionContent(item));
|
|
2566
|
+
};
|
|
2567
|
+
const resolveResponsesCompactThreshold = (maxPromptTokens) => {
|
|
2568
|
+
if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * .9);
|
|
2569
|
+
return 5e4;
|
|
2570
|
+
};
|
|
2571
|
+
const createCompactionContextManagement = (compactThreshold) => [{
|
|
2572
|
+
type: "compaction",
|
|
2573
|
+
compact_threshold: compactThreshold
|
|
2574
|
+
}];
|
|
2575
|
+
const applyResponsesApiContextManagement = (payload, maxPromptTokens) => {
|
|
2576
|
+
if (payload.context_management !== void 0) return;
|
|
2577
|
+
if (!responsesUtilsDependencies.isResponsesApiContextManagementModel(payload.model)) return;
|
|
2578
|
+
payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
|
|
2579
|
+
};
|
|
2580
|
+
const compactInputByLatestCompaction = (payload) => {
|
|
2581
|
+
if (!Array.isArray(payload.input) || payload.input.length === 0) return;
|
|
2582
|
+
const latestCompactionMessageIndex = getLatestCompactionMessageIndex(payload.input);
|
|
2583
|
+
if (latestCompactionMessageIndex === void 0) return;
|
|
2584
|
+
payload.input = payload.input.slice(latestCompactionMessageIndex);
|
|
2585
|
+
};
|
|
2586
|
+
const getLatestCompactionMessageIndex = (input) => {
|
|
2587
|
+
for (let index = input.length - 1; index >= 0; index -= 1) if (isCompactionInputItem(input[index])) return index;
|
|
2588
|
+
};
|
|
2589
|
+
const isCompactionInputItem = (value) => {
|
|
2590
|
+
return "type" in value && typeof value.type === "string" && value.type === "compaction";
|
|
2591
|
+
};
|
|
2592
|
+
const getPayloadItems = (payload) => {
|
|
2593
|
+
const result = [];
|
|
2594
|
+
const { input } = payload;
|
|
2595
|
+
if (Array.isArray(input)) result.push(...input);
|
|
2596
|
+
return result;
|
|
2597
|
+
};
|
|
2598
|
+
const containsVisionContent = (value) => {
|
|
2599
|
+
if (!value) return false;
|
|
2600
|
+
if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
|
|
2601
|
+
if (typeof value !== "object") return false;
|
|
2602
|
+
const record = value;
|
|
2603
|
+
if ((typeof record.type === "string" ? record.type.toLowerCase() : void 0) === "input_image") return true;
|
|
2604
|
+
if (Array.isArray(record.content)) return record.content.some((entry) => containsVisionContent(entry));
|
|
2605
|
+
return false;
|
|
2606
|
+
};
|
|
2429
2607
|
//#endregion
|
|
2430
2608
|
//#region src/services/copilot/create-responses.ts
|
|
2431
|
-
const
|
|
2609
|
+
const RESPONSES_WEBSOCKET_IDLE_TIMEOUT_MS = 6e4;
|
|
2610
|
+
const createResponses = async (payload, { vision, initiator, subagentMarker, requestId, sessionId, compactType, transport = "http" }) => {
|
|
2432
2611
|
if (!state.copilotToken) throw new Error("Copilot token not found");
|
|
2433
2612
|
const headers = {
|
|
2434
2613
|
...copilotHeaders(state, requestId, vision),
|
|
@@ -2438,6 +2617,17 @@ const createResponses = async (payload, { vision, initiator, subagentMarker, req
|
|
|
2438
2617
|
prepareForCompact(headers, compactType);
|
|
2439
2618
|
payload.service_tier = void 0;
|
|
2440
2619
|
consola.log(`<-- model: ${payload.model}`);
|
|
2620
|
+
if ((compactType === 1 ? "http" : transport) === "websocket") {
|
|
2621
|
+
const stream = createPooledResponsesWebSocketStream(prepareResponsesWebSocketRequest(payload, headers, {
|
|
2622
|
+
requestId,
|
|
2623
|
+
subagentMarker
|
|
2624
|
+
}));
|
|
2625
|
+
if (payload.stream) return stream;
|
|
2626
|
+
return await consumeResponsesWebSocketStream(stream);
|
|
2627
|
+
}
|
|
2628
|
+
return await createHttpResponses(payload, headers);
|
|
2629
|
+
};
|
|
2630
|
+
const createHttpResponses = async (payload, headers) => {
|
|
2441
2631
|
const response = await fetch(`${copilotBaseUrl(state)}/responses`, {
|
|
2442
2632
|
method: "POST",
|
|
2443
2633
|
headers,
|
|
@@ -2451,6 +2641,264 @@ const createResponses = async (payload, { vision, initiator, subagentMarker, req
|
|
|
2451
2641
|
if (payload.stream) return events(response);
|
|
2452
2642
|
return await response.json();
|
|
2453
2643
|
};
|
|
2644
|
+
const prepareResponsesWebSocketRequest = (payload, preparedHeaders, options) => {
|
|
2645
|
+
const initiator = getResponsesWebSocketInitiator(preparedHeaders);
|
|
2646
|
+
return {
|
|
2647
|
+
headers: copilotWebSocketHeaders(preparedHeaders),
|
|
2648
|
+
poolKey: buildResponsesWebSocketPoolKey(payload, options),
|
|
2649
|
+
payload: buildResponsesWebSocketPayload(payload, initiator)
|
|
2650
|
+
};
|
|
2651
|
+
};
|
|
2652
|
+
const buildResponsesWebSocketPoolKey = (payload, { requestId, subagentMarker }) => {
|
|
2653
|
+
const tokenFingerprint = state.copilotToken ? createHash("sha256").update(state.copilotToken).digest("hex").slice(0, 16) : "missing-token";
|
|
2654
|
+
const subagentKey = subagentMarker ? [
|
|
2655
|
+
subagentMarker.session_id,
|
|
2656
|
+
subagentMarker.agent_id,
|
|
2657
|
+
subagentMarker.agent_type
|
|
2658
|
+
].join(":") : "main";
|
|
2659
|
+
return [
|
|
2660
|
+
tokenFingerprint,
|
|
2661
|
+
payload.model,
|
|
2662
|
+
requestId,
|
|
2663
|
+
subagentKey
|
|
2664
|
+
].map(encodePoolKeyPart).join("|");
|
|
2665
|
+
};
|
|
2666
|
+
const getResponsesWebSocketInitiator = (preparedHeaders) => {
|
|
2667
|
+
return getHeaderValue(preparedHeaders, "x-initiator")?.toLowerCase() === "agent" ? "agent" : "user";
|
|
2668
|
+
};
|
|
2669
|
+
const createPooledResponsesWebSocketStream = (request) => runResponsesWebSocketPoolRequest(request);
|
|
2670
|
+
const buildResponsesWebSocketPayload = (payload, initiator) => {
|
|
2671
|
+
const websocketPayload = {
|
|
2672
|
+
...payload,
|
|
2673
|
+
type: "response.create",
|
|
2674
|
+
initiator
|
|
2675
|
+
};
|
|
2676
|
+
delete websocketPayload.stream;
|
|
2677
|
+
delete websocketPayload["background"];
|
|
2678
|
+
delete websocketPayload.service_tier;
|
|
2679
|
+
return websocketPayload;
|
|
2680
|
+
};
|
|
2681
|
+
const buildResponsesWebSocketUrl = (baseUrl) => {
|
|
2682
|
+
const url = new URL(`${baseUrl.replace(/\/+$/u, "")}/responses`);
|
|
2683
|
+
if (url.protocol === "https:") url.protocol = "wss:";
|
|
2684
|
+
else if (url.protocol === "http:") url.protocol = "ws:";
|
|
2685
|
+
return url.toString();
|
|
2686
|
+
};
|
|
2687
|
+
const responsesWebSocketPool = /* @__PURE__ */ new Map();
|
|
2688
|
+
const runResponsesWebSocketPoolRequest = async function* (request) {
|
|
2689
|
+
const entry = getResponsesWebSocketPoolEntry(request);
|
|
2690
|
+
const release = await acquireResponsesWebSocketPoolEntry(request.poolKey, entry);
|
|
2691
|
+
try {
|
|
2692
|
+
const websocket = await entry.websocketPromise;
|
|
2693
|
+
websocket.send(JSON.stringify(request.payload));
|
|
2694
|
+
for await (const data of createWebSocketMessageStream(websocket)) {
|
|
2695
|
+
const chunk = createResponsesWebSocketStreamChunk(data);
|
|
2696
|
+
yield chunk;
|
|
2697
|
+
if (isTerminalResponsesStreamChunk(chunk)) return;
|
|
2698
|
+
}
|
|
2699
|
+
removeResponsesWebSocketPoolEntry(request.poolKey, entry);
|
|
2700
|
+
throw new Error("Responses websocket ended without a terminal response");
|
|
2701
|
+
} catch (error) {
|
|
2702
|
+
removeResponsesWebSocketPoolEntry(request.poolKey, entry);
|
|
2703
|
+
throw toError(error);
|
|
2704
|
+
} finally {
|
|
2705
|
+
release();
|
|
2706
|
+
}
|
|
2707
|
+
};
|
|
2708
|
+
const getResponsesWebSocketPoolEntry = (request) => {
|
|
2709
|
+
const existing = responsesWebSocketPool.get(request.poolKey);
|
|
2710
|
+
if (existing && !existing.closed) {
|
|
2711
|
+
clearResponsesWebSocketIdleTimer(existing);
|
|
2712
|
+
return existing;
|
|
2713
|
+
}
|
|
2714
|
+
const entry = createResponsesWebSocketPoolEntry(request);
|
|
2715
|
+
responsesWebSocketPool.set(request.poolKey, entry);
|
|
2716
|
+
return entry;
|
|
2717
|
+
};
|
|
2718
|
+
const createResponsesWebSocketPoolEntry = (request) => {
|
|
2719
|
+
const entry = {
|
|
2720
|
+
closed: false,
|
|
2721
|
+
idleTimer: null,
|
|
2722
|
+
lock: Promise.resolve(),
|
|
2723
|
+
websocketPromise: openResponsesWebSocket({
|
|
2724
|
+
headers: request.headers,
|
|
2725
|
+
url: buildResponsesWebSocketUrl(copilotBaseUrl(state))
|
|
2726
|
+
})
|
|
2727
|
+
};
|
|
2728
|
+
entry.websocketPromise.then((websocket) => {
|
|
2729
|
+
websocket.addEventListener("close", () => {
|
|
2730
|
+
removeResponsesWebSocketPoolEntry(request.poolKey, entry);
|
|
2731
|
+
});
|
|
2732
|
+
websocket.addEventListener("error", () => {
|
|
2733
|
+
removeResponsesWebSocketPoolEntry(request.poolKey, entry);
|
|
2734
|
+
});
|
|
2735
|
+
}).catch(() => {
|
|
2736
|
+
removeResponsesWebSocketPoolEntry(request.poolKey, entry);
|
|
2737
|
+
});
|
|
2738
|
+
return entry;
|
|
2739
|
+
};
|
|
2740
|
+
const acquireResponsesWebSocketPoolEntry = async (poolKey, entry) => {
|
|
2741
|
+
clearResponsesWebSocketIdleTimer(entry);
|
|
2742
|
+
let releaseCurrent;
|
|
2743
|
+
const previousLock = entry.lock;
|
|
2744
|
+
entry.lock = new Promise((resolve) => {
|
|
2745
|
+
releaseCurrent = resolve;
|
|
2746
|
+
});
|
|
2747
|
+
await previousLock;
|
|
2748
|
+
clearResponsesWebSocketIdleTimer(entry);
|
|
2749
|
+
let released = false;
|
|
2750
|
+
return () => {
|
|
2751
|
+
if (released) return;
|
|
2752
|
+
released = true;
|
|
2753
|
+
releaseCurrent();
|
|
2754
|
+
if (!entry.closed) scheduleResponsesWebSocketIdleClose(poolKey, entry);
|
|
2755
|
+
};
|
|
2756
|
+
};
|
|
2757
|
+
const scheduleResponsesWebSocketIdleClose = (poolKey, entry) => {
|
|
2758
|
+
clearResponsesWebSocketIdleTimer(entry);
|
|
2759
|
+
entry.idleTimer = setTimeout(() => {
|
|
2760
|
+
removeResponsesWebSocketPoolEntry(poolKey, entry);
|
|
2761
|
+
}, RESPONSES_WEBSOCKET_IDLE_TIMEOUT_MS);
|
|
2762
|
+
unrefTimer(entry.idleTimer);
|
|
2763
|
+
};
|
|
2764
|
+
const clearResponsesWebSocketIdleTimer = (entry) => {
|
|
2765
|
+
if (entry.idleTimer) {
|
|
2766
|
+
clearTimeout(entry.idleTimer);
|
|
2767
|
+
entry.idleTimer = null;
|
|
2768
|
+
}
|
|
2769
|
+
};
|
|
2770
|
+
const removeResponsesWebSocketPoolEntry = (poolKey, entry) => {
|
|
2771
|
+
if (responsesWebSocketPool.get(poolKey) !== entry) return;
|
|
2772
|
+
responsesWebSocketPool.delete(poolKey);
|
|
2773
|
+
entry.closed = true;
|
|
2774
|
+
clearResponsesWebSocketIdleTimer(entry);
|
|
2775
|
+
entry.websocketPromise.then(closeResponsesWebSocket).catch(() => {});
|
|
2776
|
+
};
|
|
2777
|
+
const unrefTimer = (timer) => {
|
|
2778
|
+
if (typeof timer === "object" && "unref" in timer && typeof timer.unref === "function") timer.unref();
|
|
2779
|
+
};
|
|
2780
|
+
const openResponsesWebSocket = async ({ headers, url }) => await new Promise((resolve, reject) => {
|
|
2781
|
+
const dispatcher = getProxyEnvDispatcher();
|
|
2782
|
+
const websocket = new WebSocket(url, dispatcher ? {
|
|
2783
|
+
dispatcher,
|
|
2784
|
+
headers
|
|
2785
|
+
} : { headers });
|
|
2786
|
+
const cleanup = () => {
|
|
2787
|
+
websocket.removeEventListener("open", onOpen);
|
|
2788
|
+
websocket.removeEventListener("error", onError);
|
|
2789
|
+
};
|
|
2790
|
+
const onOpen = () => {
|
|
2791
|
+
cleanup();
|
|
2792
|
+
resolve(websocket);
|
|
2793
|
+
};
|
|
2794
|
+
const onError = () => {
|
|
2795
|
+
cleanup();
|
|
2796
|
+
reject(/* @__PURE__ */ new Error("Failed to create responses websocket"));
|
|
2797
|
+
};
|
|
2798
|
+
websocket.addEventListener("open", onOpen);
|
|
2799
|
+
websocket.addEventListener("error", onError);
|
|
2800
|
+
});
|
|
2801
|
+
const createWebSocketMessageStream = async function* (websocket) {
|
|
2802
|
+
const queue = [];
|
|
2803
|
+
let closed = false;
|
|
2804
|
+
let error = null;
|
|
2805
|
+
let notify = null;
|
|
2806
|
+
const wake = () => {
|
|
2807
|
+
notify?.();
|
|
2808
|
+
notify = null;
|
|
2809
|
+
};
|
|
2810
|
+
const onMessage = (event) => {
|
|
2811
|
+
queue.push(normalizeWebSocketMessageData(event.data));
|
|
2812
|
+
wake();
|
|
2813
|
+
};
|
|
2814
|
+
const onClose = () => {
|
|
2815
|
+
closed = true;
|
|
2816
|
+
wake();
|
|
2817
|
+
};
|
|
2818
|
+
const onError = () => {
|
|
2819
|
+
error = /* @__PURE__ */ new Error("Responses websocket stream error");
|
|
2820
|
+
wake();
|
|
2821
|
+
};
|
|
2822
|
+
websocket.addEventListener("message", onMessage);
|
|
2823
|
+
websocket.addEventListener("close", onClose);
|
|
2824
|
+
websocket.addEventListener("error", onError);
|
|
2825
|
+
try {
|
|
2826
|
+
while (true) {
|
|
2827
|
+
const item = queue.shift();
|
|
2828
|
+
if (item) {
|
|
2829
|
+
yield await item;
|
|
2830
|
+
continue;
|
|
2831
|
+
}
|
|
2832
|
+
if (error) throw toError(error);
|
|
2833
|
+
if (closed) break;
|
|
2834
|
+
await new Promise((resolve) => {
|
|
2835
|
+
notify = resolve;
|
|
2836
|
+
});
|
|
2837
|
+
}
|
|
2838
|
+
} finally {
|
|
2839
|
+
websocket.removeEventListener("message", onMessage);
|
|
2840
|
+
websocket.removeEventListener("close", onClose);
|
|
2841
|
+
websocket.removeEventListener("error", onError);
|
|
2842
|
+
}
|
|
2843
|
+
};
|
|
2844
|
+
const normalizeWebSocketMessageData = async (data) => {
|
|
2845
|
+
if (typeof data === "string") return data;
|
|
2846
|
+
if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);
|
|
2847
|
+
if (ArrayBuffer.isView(data)) {
|
|
2848
|
+
const view = data;
|
|
2849
|
+
return new TextDecoder().decode(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
|
|
2850
|
+
}
|
|
2851
|
+
if (isTextReadable(data)) return await data.text();
|
|
2852
|
+
return String(data);
|
|
2853
|
+
};
|
|
2854
|
+
const isTextReadable = (value) => {
|
|
2855
|
+
if (!value || typeof value !== "object" || !("text" in value)) return false;
|
|
2856
|
+
return typeof value.text === "function";
|
|
2857
|
+
};
|
|
2858
|
+
const toError = (value) => {
|
|
2859
|
+
if (value instanceof Error) return value;
|
|
2860
|
+
return new Error(String(value));
|
|
2861
|
+
};
|
|
2862
|
+
const getHeaderValue = (headers, headerName) => {
|
|
2863
|
+
const normalizedHeaderName = headerName.toLowerCase();
|
|
2864
|
+
return Object.entries(headers).find(([key]) => key.toLowerCase() === normalizedHeaderName)?.[1];
|
|
2865
|
+
};
|
|
2866
|
+
const encodePoolKeyPart = (value) => encodeURIComponent(value);
|
|
2867
|
+
const createResponsesWebSocketStreamChunk = (data) => {
|
|
2868
|
+
if (data === "[DONE]") return { data };
|
|
2869
|
+
try {
|
|
2870
|
+
const parsed = JSON.parse(data);
|
|
2871
|
+
if (parsed.type === "response.completed") logCopilotQuotaSnapshots(parsed.copilot_quota_snapshots);
|
|
2872
|
+
return {
|
|
2873
|
+
data: JSON.stringify(parsed),
|
|
2874
|
+
event: typeof parsed.type === "string" ? parsed.type : void 0,
|
|
2875
|
+
id: typeof parsed.id === "string" ? parsed.id : void 0
|
|
2876
|
+
};
|
|
2877
|
+
} catch {
|
|
2878
|
+
return { data };
|
|
2879
|
+
}
|
|
2880
|
+
};
|
|
2881
|
+
const isTerminalResponsesStreamChunk = (chunk) => {
|
|
2882
|
+
if (!chunk.data || chunk.data === "[DONE]") return false;
|
|
2883
|
+
try {
|
|
2884
|
+
const parsed = JSON.parse(chunk.data);
|
|
2885
|
+
return parsed.type === "response.completed" || parsed.type === "response.failed" || parsed.type === "response.incomplete" || parsed.type === "error";
|
|
2886
|
+
} catch {
|
|
2887
|
+
return false;
|
|
2888
|
+
}
|
|
2889
|
+
};
|
|
2890
|
+
const consumeResponsesWebSocketStream = async (stream) => {
|
|
2891
|
+
for await (const chunk of stream) {
|
|
2892
|
+
if (!chunk.data || chunk.data === "[DONE]") continue;
|
|
2893
|
+
const event = JSON.parse(chunk.data);
|
|
2894
|
+
if (event.type === "error") throw new Error(event.message);
|
|
2895
|
+
if (event.type === "response.completed" || event.type === "response.failed" || event.type === "response.incomplete") return event.response;
|
|
2896
|
+
}
|
|
2897
|
+
throw new Error("Responses websocket ended without a terminal response");
|
|
2898
|
+
};
|
|
2899
|
+
const closeResponsesWebSocket = (websocket) => {
|
|
2900
|
+
if (websocket.readyState === WebSocket.CONNECTING || websocket.readyState === WebSocket.OPEN) websocket.close();
|
|
2901
|
+
};
|
|
2454
2902
|
//#endregion
|
|
2455
2903
|
//#region src/routes/messages/responses-translation.ts
|
|
2456
2904
|
const MESSAGE_TYPE = "message";
|
|
@@ -3307,63 +3755,6 @@ const extractFunctionCallDetails = (rawEvent) => {
|
|
|
3307
3755
|
};
|
|
3308
3756
|
};
|
|
3309
3757
|
//#endregion
|
|
3310
|
-
//#region src/routes/responses/utils.ts
|
|
3311
|
-
const getResponsesRequestOptions = (payload) => {
|
|
3312
|
-
return {
|
|
3313
|
-
vision: hasVisionInput(payload),
|
|
3314
|
-
initiator: hasAgentInitiator(payload) ? "agent" : "user"
|
|
3315
|
-
};
|
|
3316
|
-
};
|
|
3317
|
-
const hasAgentInitiator = (payload) => {
|
|
3318
|
-
const lastItem = getPayloadItems(payload).at(-1);
|
|
3319
|
-
if (!lastItem) return false;
|
|
3320
|
-
if (!("role" in lastItem) || !lastItem.role) return true;
|
|
3321
|
-
return (typeof lastItem.role === "string" ? lastItem.role.toLowerCase() : "") === "assistant";
|
|
3322
|
-
};
|
|
3323
|
-
const hasVisionInput = (payload) => {
|
|
3324
|
-
return getPayloadItems(payload).some((item) => containsVisionContent(item));
|
|
3325
|
-
};
|
|
3326
|
-
const resolveResponsesCompactThreshold = (maxPromptTokens) => {
|
|
3327
|
-
if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * .9);
|
|
3328
|
-
return 5e4;
|
|
3329
|
-
};
|
|
3330
|
-
const createCompactionContextManagement = (compactThreshold) => [{
|
|
3331
|
-
type: "compaction",
|
|
3332
|
-
compact_threshold: compactThreshold
|
|
3333
|
-
}];
|
|
3334
|
-
const applyResponsesApiContextManagement = (payload, maxPromptTokens) => {
|
|
3335
|
-
if (payload.context_management !== void 0) return;
|
|
3336
|
-
if (!isResponsesApiContextManagementModel(payload.model)) return;
|
|
3337
|
-
payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
|
|
3338
|
-
};
|
|
3339
|
-
const compactInputByLatestCompaction = (payload) => {
|
|
3340
|
-
if (!Array.isArray(payload.input) || payload.input.length === 0) return;
|
|
3341
|
-
const latestCompactionMessageIndex = getLatestCompactionMessageIndex(payload.input);
|
|
3342
|
-
if (latestCompactionMessageIndex === void 0) return;
|
|
3343
|
-
payload.input = payload.input.slice(latestCompactionMessageIndex);
|
|
3344
|
-
};
|
|
3345
|
-
const getLatestCompactionMessageIndex = (input) => {
|
|
3346
|
-
for (let index = input.length - 1; index >= 0; index -= 1) if (isCompactionInputItem(input[index])) return index;
|
|
3347
|
-
};
|
|
3348
|
-
const isCompactionInputItem = (value) => {
|
|
3349
|
-
return "type" in value && typeof value.type === "string" && value.type === "compaction";
|
|
3350
|
-
};
|
|
3351
|
-
const getPayloadItems = (payload) => {
|
|
3352
|
-
const result = [];
|
|
3353
|
-
const { input } = payload;
|
|
3354
|
-
if (Array.isArray(input)) result.push(...input);
|
|
3355
|
-
return result;
|
|
3356
|
-
};
|
|
3357
|
-
const containsVisionContent = (value) => {
|
|
3358
|
-
if (!value) return false;
|
|
3359
|
-
if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
|
|
3360
|
-
if (typeof value !== "object") return false;
|
|
3361
|
-
const record = value;
|
|
3362
|
-
if ((typeof record.type === "string" ? record.type.toLowerCase() : void 0) === "input_image") return true;
|
|
3363
|
-
if (Array.isArray(record.content)) return record.content.some((entry) => containsVisionContent(entry));
|
|
3364
|
-
return false;
|
|
3365
|
-
};
|
|
3366
|
-
//#endregion
|
|
3367
3758
|
//#region src/services/copilot/create-messages.ts
|
|
3368
3759
|
const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
|
|
3369
3760
|
const allowedAnthropicBetas = new Set([
|
|
@@ -3657,6 +4048,11 @@ const prepareMessagesApiPayload = (payload, selectedModel) => {
|
|
|
3657
4048
|
const COPILOT_CONTEXT_CACHE_SYSTEM_MARKER_LIMIT = 2;
|
|
3658
4049
|
const COPILOT_CONTEXT_CACHE_NON_SYSTEM_MARKER_LIMIT = 2;
|
|
3659
4050
|
const COPILOT_CONTEXT_CACHE_CONTROL = { type: "ephemeral" };
|
|
4051
|
+
const messagesApiFlowDependencies = {
|
|
4052
|
+
createChatCompletions,
|
|
4053
|
+
createMessages,
|
|
4054
|
+
createResponses
|
|
4055
|
+
};
|
|
3660
4056
|
const handleWithChatCompletions = async (c, anthropicPayload, options) => {
|
|
3661
4057
|
const { logger, subagentMarker, requestId, sessionId, compactType } = options;
|
|
3662
4058
|
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
@@ -3668,7 +4064,7 @@ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
|
|
|
3668
4064
|
payload: anthropicPayload
|
|
3669
4065
|
});
|
|
3670
4066
|
debugJson(logger, "Translated OpenAI request payload:", openAIPayload);
|
|
3671
|
-
const response = await createChatCompletions(openAIPayload, {
|
|
4067
|
+
const response = await messagesApiFlowDependencies.createChatCompletions(openAIPayload, {
|
|
3672
4068
|
subagentMarker,
|
|
3673
4069
|
requestId,
|
|
3674
4070
|
sessionId,
|
|
@@ -3731,9 +4127,11 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
|
|
|
3731
4127
|
compactInputByLatestCompaction(responsesPayload);
|
|
3732
4128
|
debugJson(logger, "Translated Responses payload:", responsesPayload);
|
|
3733
4129
|
const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
|
|
3734
|
-
const
|
|
4130
|
+
const transport = getResponsesTransportForModel(selectedModel, { compactType: requestOptions.compactType }) ?? "http";
|
|
4131
|
+
const response = await messagesApiFlowDependencies.createResponses(responsesPayload, {
|
|
3735
4132
|
vision,
|
|
3736
4133
|
initiator,
|
|
4134
|
+
transport,
|
|
3737
4135
|
...requestOptions
|
|
3738
4136
|
});
|
|
3739
4137
|
if (responsesPayload.stream && isAsyncIterable$1(response)) {
|
|
@@ -3798,7 +4196,7 @@ const handleWithMessagesApi = async (c, anthropicPayload, options) => {
|
|
|
3798
4196
|
payload: anthropicPayload
|
|
3799
4197
|
});
|
|
3800
4198
|
debugJson(logger, "Translated Messages payload:", anthropicPayload);
|
|
3801
|
-
const response = await createMessages(anthropicPayload, anthropicBetaHeader, {
|
|
4199
|
+
const response = await messagesApiFlowDependencies.createMessages(anthropicPayload, anthropicBetaHeader, {
|
|
3802
4200
|
subagentMarker,
|
|
3803
4201
|
requestId,
|
|
3804
4202
|
sessionId,
|
|
@@ -3961,7 +4359,7 @@ async function handleCompletion(c) {
|
|
|
3961
4359
|
compactType,
|
|
3962
4360
|
logger: logger$3
|
|
3963
4361
|
});
|
|
3964
|
-
if (shouldUseResponsesApi(selectedModel)) return await messagesFlowHandlers.handleWithResponsesApi(c, anthropicPayload, {
|
|
4362
|
+
if (shouldUseResponsesApi(selectedModel, compactType)) return await messagesFlowHandlers.handleWithResponsesApi(c, anthropicPayload, {
|
|
3965
4363
|
subagentMarker,
|
|
3966
4364
|
selectedModel,
|
|
3967
4365
|
requestId,
|
|
@@ -3977,10 +4375,9 @@ async function handleCompletion(c) {
|
|
|
3977
4375
|
logger: logger$3
|
|
3978
4376
|
});
|
|
3979
4377
|
}
|
|
3980
|
-
const RESPONSES_ENDPOINT$1 = "/responses";
|
|
3981
4378
|
const MESSAGES_ENDPOINT = "/v1/messages";
|
|
3982
|
-
const shouldUseResponsesApi = (selectedModel) => {
|
|
3983
|
-
return selectedModel
|
|
4379
|
+
const shouldUseResponsesApi = (selectedModel, compactType) => {
|
|
4380
|
+
return Boolean(getResponsesTransportForModel(selectedModel, { compactType }));
|
|
3984
4381
|
};
|
|
3985
4382
|
const shouldUseMessagesApi = (selectedModel) => {
|
|
3986
4383
|
if (!isMessagesApiEnabled()) return false;
|
|
@@ -4113,9 +4510,14 @@ const handleItemId = (parsed, tracker) => {
|
|
|
4113
4510
|
//#endregion
|
|
4114
4511
|
//#region src/routes/responses/handler.ts
|
|
4115
4512
|
const logger$1 = createHandlerLogger("responses-handler");
|
|
4116
|
-
const
|
|
4513
|
+
const responsesHandlerDependencies = {
|
|
4514
|
+
checkRateLimit,
|
|
4515
|
+
createResponses,
|
|
4516
|
+
getConfig,
|
|
4517
|
+
isResponsesApiWebSearchEnabled
|
|
4518
|
+
};
|
|
4117
4519
|
const handleResponses = async (c) => {
|
|
4118
|
-
await checkRateLimit(state);
|
|
4520
|
+
await responsesHandlerDependencies.checkRateLimit(state);
|
|
4119
4521
|
const payload = await c.req.json();
|
|
4120
4522
|
debugJson(logger$1, "Responses request payload:", payload);
|
|
4121
4523
|
const requestId = generateRequestIdFromPayload({ messages: payload.input });
|
|
@@ -4129,10 +4531,11 @@ const handleResponses = async (c) => {
|
|
|
4129
4531
|
});
|
|
4130
4532
|
useFunctionApplyPatch(payload);
|
|
4131
4533
|
removeUnsupportedTools(payload);
|
|
4132
|
-
if (!isResponsesApiWebSearchEnabled()) removeWebSearchTool(payload);
|
|
4534
|
+
if (!responsesHandlerDependencies.isResponsesApiWebSearchEnabled()) removeWebSearchTool(payload);
|
|
4133
4535
|
compactInputByLatestCompaction(payload);
|
|
4134
4536
|
const selectedModel = state.models?.data.find((model) => model.id === payload.model);
|
|
4135
|
-
|
|
4537
|
+
const responsesTransport = getResponsesTransportForModel(selectedModel);
|
|
4538
|
+
if (!responsesTransport) return c.json({ error: {
|
|
4136
4539
|
message: "This model does not support the responses endpoint. Please choose a different model.",
|
|
4137
4540
|
type: "invalid_request_error"
|
|
4138
4541
|
} }, 400);
|
|
@@ -4140,11 +4543,12 @@ const handleResponses = async (c) => {
|
|
|
4140
4543
|
debugJson(logger$1, "Translated Responses payload:", payload);
|
|
4141
4544
|
const { vision, initiator } = getResponsesRequestOptions(payload);
|
|
4142
4545
|
if (state.manualApprove) await awaitApproval();
|
|
4143
|
-
const response = await createResponses(payload, {
|
|
4546
|
+
const response = await responsesHandlerDependencies.createResponses(payload, {
|
|
4144
4547
|
vision,
|
|
4145
4548
|
initiator,
|
|
4146
4549
|
requestId,
|
|
4147
|
-
sessionId
|
|
4550
|
+
sessionId,
|
|
4551
|
+
transport: responsesTransport
|
|
4148
4552
|
});
|
|
4149
4553
|
if (isStreamingRequested(payload) && isAsyncIterable(response)) {
|
|
4150
4554
|
logger$1.debug("Forwarding native Responses stream");
|
|
@@ -4184,7 +4588,7 @@ const parseResponsesStreamEvent = (chunk) => {
|
|
|
4184
4588
|
}
|
|
4185
4589
|
};
|
|
4186
4590
|
const useFunctionApplyPatch = (payload) => {
|
|
4187
|
-
if (getConfig().useFunctionApplyPatch ?? true) {
|
|
4591
|
+
if (responsesHandlerDependencies.getConfig().useFunctionApplyPatch ?? true) {
|
|
4188
4592
|
logger$1.debug("Using function tool apply_patch for responses");
|
|
4189
4593
|
if (Array.isArray(payload.tools)) {
|
|
4190
4594
|
const toolsArr = payload.tools;
|
|
@@ -4258,6 +4662,10 @@ tokenUsageRoute.get("/", async (c) => {
|
|
|
4258
4662
|
const summary = await getTokenUsageSummary(parsePeriod(c.req.query("period")));
|
|
4259
4663
|
return c.json(summary);
|
|
4260
4664
|
});
|
|
4665
|
+
tokenUsageRoute.get("/daily", async (c) => {
|
|
4666
|
+
const summary = await getTokenUsageDailySummary(parsePeriod(c.req.query("period")));
|
|
4667
|
+
return c.json(summary);
|
|
4668
|
+
});
|
|
4261
4669
|
tokenUsageRoute.get("/events", async (c) => {
|
|
4262
4670
|
const period = parsePeriod(c.req.query("period"));
|
|
4263
4671
|
const eventsPage = await getTokenUsageEventsPage({
|
|
@@ -4327,4 +4735,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
|
|
|
4327
4735
|
//#endregion
|
|
4328
4736
|
export { server };
|
|
4329
4737
|
|
|
4330
|
-
//# sourceMappingURL=server-
|
|
4738
|
+
//# sourceMappingURL=server-DpVPS3zt.js.map
|