@jeffreycao/copilot-api 1.12.9 → 1.13.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 +72 -29
- package/README.zh-CN.md +72 -29
- package/dist/{auth-15xzL-eW.js → auth-BDHOrS4c.js} +14 -4
- package/dist/auth-BDHOrS4c.js.map +1 -0
- package/dist/auth-BjDQCtUW.js +2 -0
- package/dist/{config-B71_S_hQ.js → config-DODTXsGz.js} +7 -7
- package/dist/config-DODTXsGz.js.map +1 -0
- package/dist/{debug-TyT2u9dt.js → debug-CjJqlHl_.js} +2 -2
- package/dist/{debug-TyT2u9dt.js.map → debug-CjJqlHl_.js.map} +1 -1
- package/dist/main.js +3 -5
- package/dist/main.js.map +1 -1
- package/dist/{server-34rnRg4k.js → server-s_0_JChu.js} +591 -167
- package/dist/server-s_0_JChu.js.map +1 -0
- package/dist/{start-8y_02ZHG.js → start-DxOR_R2Y.js} +68 -57
- package/dist/start-DxOR_R2Y.js.map +1 -0
- package/dist/{token-fpw8tAQS.js → token-DigcCxDR.js} +8 -1933
- package/dist/token-DigcCxDR.js.map +1 -0
- package/package.json +1 -1
- package/pages/index.html +93 -13
- package/dist/auth-15xzL-eW.js.map +0 -1
- package/dist/check-usage-Bu9w7RbA.js +0 -43
- package/dist/check-usage-Bu9w7RbA.js.map +0 -1
- package/dist/config-B71_S_hQ.js.map +0 -1
- package/dist/server-34rnRg4k.js.map +0 -1
- package/dist/start-8y_02ZHG.js.map +0 -1
- package/dist/token-fpw8tAQS.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { C as
|
|
1
|
+
import { S as setModelMappings, a as getExtraPromptForModel, c as getModelResponsesApiCompactThreshold$1, d as getReasoningEffortForModel, f as getSmallModel, g as isResponsesApiWebSocketEnabled, h as isResponsesApiWebSearchEnabled, i as getConfig, l as getProviderConfig, m as isResponsesApiContextManagementEnabled, n as getAnthropicApiKey, o as getMessageApiWebSearchModel, p as isMessagesApiEnabled, r as getClaudeTokenMultiplier, s as getModelMappings, u as getRawProviderConfig, v as listEnabledProviders, w as PATHS, x as resolveMappedModel } from "./config-DODTXsGz.js";
|
|
2
|
+
import { B as forwardError, C as prepareInteractionHeaders, D as compactMessageSections, E as compactAutoContinuePromptStarts, F as resolveTraceId$1, I as createPooledWebSocketStream, L as createWebSocketUrl, M as forwardCodexResponses, N as generateTraceId, P as requestContext, R as state, S as prepareForCompact, _ as getCopilotUsage, b as copilotHeaders, d as generateRequestIdFromPayload, f as getRootSessionId, g as sleep, h as parseUserIdMetadata, k as compactSystemPromptStarts, m as isNullish, p as getUUID, r as setupCodexToken, w as prepareMessageProxyHeaders, x as copilotWebSocketHeaders, y as copilotBaseUrl, z as HTTPError } from "./token-DigcCxDR.js";
|
|
3
3
|
import { a as isDeferredToolName, c as parseMcpToolSearchSentinel, d as shouldEnableResponsesToolSearch, i as isBridgeToolSearchName, l as resolveBridgeToolSearchName, o as listDeferredToolNames, r as formatToolSearchBridgeArguments, s as normalizeToolSearchBridgeArguments, t as BRIDGE_TOOL_SEARCH_NAME, u as selectDeferredToolsByNames } from "./tool-search-OX6iPJ9D.js";
|
|
4
4
|
import consola from "consola";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
@@ -485,6 +485,7 @@ var SqliteDbStore = class {
|
|
|
485
485
|
//#region src/lib/token-usage/store.ts
|
|
486
486
|
const DB_PATH_ENV = "COPILOT_API_SQLITE_DB_PATH";
|
|
487
487
|
const DEFAULT_DB_FILENAME = "copilot-api.sqlite";
|
|
488
|
+
const COST_NANOS_PER_UNIT$1 = 1e9;
|
|
488
489
|
let writeQueue = Promise.resolve();
|
|
489
490
|
function getDbPath() {
|
|
490
491
|
return process.env[DB_PATH_ENV] ?? path.join(PATHS.APP_DIR, DEFAULT_DB_FILENAME);
|
|
@@ -518,11 +519,19 @@ function initializeTokenUsageDb(db) {
|
|
|
518
519
|
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
519
520
|
cache_read_input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
520
521
|
cache_creation_input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
521
|
-
total_tokens INTEGER NOT NULL DEFAULT 0
|
|
522
|
+
total_tokens INTEGER NOT NULL DEFAULT 0,
|
|
523
|
+
total_nano_aiu INTEGER,
|
|
524
|
+
cost_currency TEXT,
|
|
525
|
+
total_cost_nanos INTEGER,
|
|
526
|
+
cost_source TEXT
|
|
522
527
|
)
|
|
523
528
|
`);
|
|
524
529
|
ensureColumn(db, "user_id", "TEXT NOT NULL DEFAULT ''");
|
|
525
530
|
ensureColumn(db, "total_tokens", "INTEGER NOT NULL DEFAULT 0");
|
|
531
|
+
ensureColumn(db, "total_nano_aiu", "INTEGER");
|
|
532
|
+
ensureColumn(db, "cost_currency", "TEXT");
|
|
533
|
+
ensureColumn(db, "total_cost_nanos", "INTEGER");
|
|
534
|
+
ensureColumn(db, "cost_source", "TEXT");
|
|
526
535
|
db.exec(`
|
|
527
536
|
CREATE INDEX IF NOT EXISTS idx_token_usage_events_created_at_ms
|
|
528
537
|
ON token_usage_events(created_at_ms)
|
|
@@ -555,7 +564,7 @@ function normalizeOptionalToken(value) {
|
|
|
555
564
|
return value === null || value === void 0 ? void 0 : normalizeToken(value);
|
|
556
565
|
}
|
|
557
566
|
function hasAnyToken(tokens) {
|
|
558
|
-
return normalizeToken(tokens.input_tokens) > 0 || normalizeToken(tokens.output_tokens) > 0 || normalizeToken(tokens.cache_read_input_tokens) > 0 || normalizeToken(tokens.cache_creation_input_tokens) > 0 || normalizeToken(tokens.total_tokens) > 0;
|
|
567
|
+
return normalizeToken(tokens.input_tokens) > 0 || normalizeToken(tokens.output_tokens) > 0 || normalizeToken(tokens.cache_read_input_tokens) > 0 || normalizeToken(tokens.cache_creation_input_tokens) > 0 || normalizeToken(tokens.total_tokens) > 0 || normalizeToken(tokens.total_nano_aiu) > 0;
|
|
559
568
|
}
|
|
560
569
|
function resolveTotalTokens(input) {
|
|
561
570
|
const explicitTotal = normalizeOptionalToken(input.total_tokens);
|
|
@@ -578,9 +587,13 @@ async function writeTokenUsageEvent(event) {
|
|
|
578
587
|
output_tokens,
|
|
579
588
|
cache_read_input_tokens,
|
|
580
589
|
cache_creation_input_tokens,
|
|
581
|
-
total_tokens
|
|
582
|
-
|
|
583
|
-
|
|
590
|
+
total_tokens,
|
|
591
|
+
total_nano_aiu,
|
|
592
|
+
cost_currency,
|
|
593
|
+
total_cost_nanos,
|
|
594
|
+
cost_source
|
|
595
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
596
|
+
`).run(event.created_at_ms, event.created_at_utc, event.trace_id, event.session_id, event.user_id, event.source, event.endpoint, event.provider_name, event.model, event.input_tokens, event.output_tokens, event.cache_read_input_tokens, event.cache_creation_input_tokens, event.total_tokens, event.total_nano_aiu, event.cost_currency, event.total_cost_nanos, event.cost_source);
|
|
584
597
|
}
|
|
585
598
|
function enqueueTokenUsageWrite(event) {
|
|
586
599
|
if (!isTokenUsageStorageEnabled()) return;
|
|
@@ -651,20 +664,34 @@ function createEmptyTotals() {
|
|
|
651
664
|
return {
|
|
652
665
|
cache_creation_input_tokens: 0,
|
|
653
666
|
cache_read_input_tokens: 0,
|
|
667
|
+
costs: [],
|
|
654
668
|
input_tokens: 0,
|
|
655
669
|
output_tokens: 0,
|
|
656
670
|
request_count: 0,
|
|
671
|
+
total_nano_aiu: null,
|
|
657
672
|
total_tokens: 0
|
|
658
673
|
};
|
|
659
674
|
}
|
|
660
675
|
function addTotals(target, next) {
|
|
661
676
|
target.cache_creation_input_tokens += next.cache_creation_input_tokens;
|
|
662
677
|
target.cache_read_input_tokens += next.cache_read_input_tokens;
|
|
678
|
+
target.costs = mergeCosts(target.costs, next.costs);
|
|
663
679
|
target.input_tokens += next.input_tokens;
|
|
664
680
|
target.output_tokens += next.output_tokens;
|
|
665
681
|
target.request_count += next.request_count;
|
|
682
|
+
target.total_nano_aiu = addNullableNumbers(target.total_nano_aiu, next.total_nano_aiu);
|
|
666
683
|
target.total_tokens += next.total_tokens;
|
|
667
684
|
}
|
|
685
|
+
function addNullableNumbers(current, next) {
|
|
686
|
+
if (current === null) return next;
|
|
687
|
+
if (next === null) return current;
|
|
688
|
+
return current + next;
|
|
689
|
+
}
|
|
690
|
+
function mergeCosts(current, next) {
|
|
691
|
+
const byCurrency = /* @__PURE__ */ new Map();
|
|
692
|
+
for (const cost of [...current, ...next]) byCurrency.set(cost.currency, (byCurrency.get(cost.currency) ?? 0) + cost.total_cost_nanos);
|
|
693
|
+
return [...byCurrency.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([currency, totalCostNanos]) => createCost(currency, totalCostNanos));
|
|
694
|
+
}
|
|
668
695
|
function createEmptySummary(period) {
|
|
669
696
|
const range = getPeriodRange(period);
|
|
670
697
|
return {
|
|
@@ -729,19 +756,47 @@ function numberFromRow(row, key) {
|
|
|
729
756
|
const value = row?.[key];
|
|
730
757
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
731
758
|
}
|
|
732
|
-
function
|
|
759
|
+
function nullableNumberFromRow(row, key) {
|
|
760
|
+
const value = row?.[key];
|
|
761
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
762
|
+
}
|
|
763
|
+
function createCost(currency, totalCostNanos) {
|
|
764
|
+
return {
|
|
765
|
+
amount: totalCostNanos / COST_NANOS_PER_UNIT$1,
|
|
766
|
+
currency,
|
|
767
|
+
total_cost_nanos: totalCostNanos
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
function costFromRow(row) {
|
|
771
|
+
const currency = row.cost_currency;
|
|
772
|
+
const totalCostNanos = row.total_cost_nanos;
|
|
773
|
+
if (typeof currency !== "string" || !currency || typeof totalCostNanos !== "number" || !Number.isFinite(totalCostNanos)) return null;
|
|
774
|
+
return createCost(currency, totalCostNanos);
|
|
775
|
+
}
|
|
776
|
+
function eventCostFromRow(row) {
|
|
777
|
+
const cost = costFromRow(row);
|
|
778
|
+
const source = row.cost_source;
|
|
779
|
+
if (!cost || typeof source !== "string" || !source) return null;
|
|
780
|
+
return {
|
|
781
|
+
...cost,
|
|
782
|
+
source
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
function totalsFromRow(row, costs = []) {
|
|
733
786
|
return {
|
|
734
787
|
cache_creation_input_tokens: numberFromRow(row, "cache_creation_input_tokens"),
|
|
735
788
|
cache_read_input_tokens: numberFromRow(row, "cache_read_input_tokens"),
|
|
789
|
+
costs,
|
|
736
790
|
input_tokens: numberFromRow(row, "input_tokens"),
|
|
737
791
|
output_tokens: numberFromRow(row, "output_tokens"),
|
|
738
792
|
request_count: numberFromRow(row, "request_count"),
|
|
793
|
+
total_nano_aiu: nullableNumberFromRow(row, "total_nano_aiu"),
|
|
739
794
|
total_tokens: numberFromRow(row, "total_tokens")
|
|
740
795
|
};
|
|
741
796
|
}
|
|
742
|
-
function modelSummaryFromRow(row) {
|
|
797
|
+
function modelSummaryFromRow(row, costs = []) {
|
|
743
798
|
return {
|
|
744
|
-
...totalsFromRow(row),
|
|
799
|
+
...totalsFromRow(row, costs),
|
|
745
800
|
model: typeof row.model === "string" ? row.model : "unknown"
|
|
746
801
|
};
|
|
747
802
|
}
|
|
@@ -757,6 +812,7 @@ function usageEventFromRow(row) {
|
|
|
757
812
|
return {
|
|
758
813
|
cache_creation_input_tokens: numberFromRow(row, "cache_creation_input_tokens"),
|
|
759
814
|
cache_read_input_tokens: numberFromRow(row, "cache_read_input_tokens"),
|
|
815
|
+
cost: eventCostFromRow(row),
|
|
760
816
|
created_at_ms: numberFromRow(row, "created_at_ms"),
|
|
761
817
|
created_at_utc: stringFromRow(row, "created_at_utc"),
|
|
762
818
|
endpoint: stringFromRow(row, "endpoint"),
|
|
@@ -767,6 +823,7 @@ function usageEventFromRow(row) {
|
|
|
767
823
|
provider_name: nullableStringFromRow(row, "provider_name"),
|
|
768
824
|
session_id: stringFromRow(row, "session_id"),
|
|
769
825
|
source: stringFromRow(row, "source"),
|
|
826
|
+
total_nano_aiu: nullableNumberFromRow(row, "total_nano_aiu"),
|
|
770
827
|
total_tokens: numberFromRow(row, "total_tokens"),
|
|
771
828
|
trace_id: stringFromRow(row, "trace_id"),
|
|
772
829
|
user_id: stringFromRow(row, "user_id")
|
|
@@ -780,6 +837,7 @@ function getTotalsRow(db, range) {
|
|
|
780
837
|
COALESCE(SUM(output_tokens), 0) AS output_tokens,
|
|
781
838
|
COALESCE(SUM(cache_read_input_tokens), 0) AS cache_read_input_tokens,
|
|
782
839
|
COALESCE(SUM(cache_creation_input_tokens), 0) AS cache_creation_input_tokens,
|
|
840
|
+
SUM(total_nano_aiu) AS total_nano_aiu,
|
|
783
841
|
COALESCE(SUM(total_tokens), 0) AS total_tokens
|
|
784
842
|
FROM token_usage_events
|
|
785
843
|
WHERE created_at_ms >= ? AND created_at_ms < ?
|
|
@@ -794,6 +852,7 @@ function getModelRows(db, range) {
|
|
|
794
852
|
COALESCE(SUM(output_tokens), 0) AS output_tokens,
|
|
795
853
|
COALESCE(SUM(cache_read_input_tokens), 0) AS cache_read_input_tokens,
|
|
796
854
|
COALESCE(SUM(cache_creation_input_tokens), 0) AS cache_creation_input_tokens,
|
|
855
|
+
SUM(total_nano_aiu) AS total_nano_aiu,
|
|
797
856
|
COALESCE(SUM(total_tokens), 0) AS total_tokens
|
|
798
857
|
FROM token_usage_events
|
|
799
858
|
WHERE created_at_ms >= ? AND created_at_ms < ?
|
|
@@ -803,8 +862,56 @@ function getModelRows(db, range) {
|
|
|
803
862
|
model ASC
|
|
804
863
|
`).all(range.startMs, range.endMs);
|
|
805
864
|
}
|
|
806
|
-
function
|
|
807
|
-
|
|
865
|
+
function getCostRows(db, range) {
|
|
866
|
+
return db.prepare(`
|
|
867
|
+
SELECT
|
|
868
|
+
cost_currency,
|
|
869
|
+
COALESCE(SUM(total_cost_nanos), 0) AS total_cost_nanos
|
|
870
|
+
FROM token_usage_events
|
|
871
|
+
WHERE
|
|
872
|
+
created_at_ms >= ?
|
|
873
|
+
AND created_at_ms < ?
|
|
874
|
+
AND cost_currency IS NOT NULL
|
|
875
|
+
AND total_cost_nanos IS NOT NULL
|
|
876
|
+
GROUP BY cost_currency
|
|
877
|
+
ORDER BY cost_currency ASC
|
|
878
|
+
`).all(range.startMs, range.endMs).flatMap((row) => {
|
|
879
|
+
const cost = costFromRow(row);
|
|
880
|
+
return cost ? [cost] : [];
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
function getModelCostMap(db, range) {
|
|
884
|
+
const rows = db.prepare(`
|
|
885
|
+
SELECT
|
|
886
|
+
model,
|
|
887
|
+
cost_currency,
|
|
888
|
+
COALESCE(SUM(total_cost_nanos), 0) AS total_cost_nanos
|
|
889
|
+
FROM token_usage_events
|
|
890
|
+
WHERE
|
|
891
|
+
created_at_ms >= ?
|
|
892
|
+
AND created_at_ms < ?
|
|
893
|
+
AND cost_currency IS NOT NULL
|
|
894
|
+
AND total_cost_nanos IS NOT NULL
|
|
895
|
+
GROUP BY model, cost_currency
|
|
896
|
+
ORDER BY model ASC, cost_currency ASC
|
|
897
|
+
`).all(range.startMs, range.endMs);
|
|
898
|
+
const costMap = /* @__PURE__ */ new Map();
|
|
899
|
+
for (const row of rows) {
|
|
900
|
+
const model = stringFromRow(row, "model") || "unknown";
|
|
901
|
+
const cost = costFromRow(row);
|
|
902
|
+
if (!cost) continue;
|
|
903
|
+
costMap.set(model, [...costMap.get(model) ?? [], cost]);
|
|
904
|
+
}
|
|
905
|
+
return costMap;
|
|
906
|
+
}
|
|
907
|
+
function getModelSummaries(db, range) {
|
|
908
|
+
const costMap = getModelCostMap(db, range);
|
|
909
|
+
return getModelRows(db, range).map((row) => {
|
|
910
|
+
const model = stringFromRow(row, "model") || "unknown";
|
|
911
|
+
return modelSummaryFromRow(row, costMap.get(model) ?? []);
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
function createDailyBucket(interval, byModel) {
|
|
808
915
|
const totals = createEmptyTotals();
|
|
809
916
|
for (const model of byModel) addTotals(totals, model);
|
|
810
917
|
return {
|
|
@@ -822,10 +929,10 @@ async function getTokenUsageSummary(period) {
|
|
|
822
929
|
const db = await getDb();
|
|
823
930
|
const totalsRow = getTotalsRow(db, range);
|
|
824
931
|
return {
|
|
825
|
-
byModel:
|
|
932
|
+
byModel: getModelSummaries(db, range),
|
|
826
933
|
period,
|
|
827
934
|
range: rangePayload(range),
|
|
828
|
-
totals: totalsFromRow(totalsRow)
|
|
935
|
+
totals: totalsFromRow(totalsRow, getCostRows(db, range))
|
|
829
936
|
};
|
|
830
937
|
}
|
|
831
938
|
async function getTokenUsageDailySummary(period) {
|
|
@@ -835,11 +942,11 @@ async function getTokenUsageDailySummary(period) {
|
|
|
835
942
|
const db = await getDb();
|
|
836
943
|
const intervals = createDailyIntervals(range);
|
|
837
944
|
return {
|
|
838
|
-
byModel:
|
|
839
|
-
days: intervals.map((interval) => createDailyBucket(interval,
|
|
945
|
+
byModel: getModelSummaries(db, range),
|
|
946
|
+
days: intervals.map((interval) => createDailyBucket(interval, getModelSummaries(db, interval))),
|
|
840
947
|
period,
|
|
841
948
|
range: rangePayload(range),
|
|
842
|
-
totals: totalsFromRow(getTotalsRow(db, range))
|
|
949
|
+
totals: totalsFromRow(getTotalsRow(db, range), getCostRows(db, range))
|
|
843
950
|
};
|
|
844
951
|
}
|
|
845
952
|
async function getTokenUsageEventsPage(input) {
|
|
@@ -871,7 +978,11 @@ async function getTokenUsageEventsPage(input) {
|
|
|
871
978
|
output_tokens,
|
|
872
979
|
cache_read_input_tokens,
|
|
873
980
|
cache_creation_input_tokens,
|
|
874
|
-
|
|
981
|
+
total_nano_aiu,
|
|
982
|
+
total_tokens,
|
|
983
|
+
cost_currency,
|
|
984
|
+
total_cost_nanos,
|
|
985
|
+
cost_source
|
|
875
986
|
FROM token_usage_events
|
|
876
987
|
WHERE created_at_ms >= ? AND created_at_ms < ?
|
|
877
988
|
ORDER BY created_at_ms DESC, id DESC
|
|
@@ -904,6 +1015,174 @@ async function closeUsageStore() {
|
|
|
904
1015
|
}
|
|
905
1016
|
registerProcessCleanup(closeUsageStore);
|
|
906
1017
|
//#endregion
|
|
1018
|
+
//#region src/lib/token-usage/pricing.ts
|
|
1019
|
+
const COST_NANOS_PER_UNIT = 1e9;
|
|
1020
|
+
const COST_NANOS_PER_TOKEN_AT_ONE_PER_MILLION = 1e3;
|
|
1021
|
+
const COPILOT_NANO_AIU_TO_COST_NANOS = COST_NANOS_PER_UNIT / 1e11;
|
|
1022
|
+
const BUILTIN_PROVIDER_CURRENCIES = {
|
|
1023
|
+
codex: "USD",
|
|
1024
|
+
dashscope: "CNY",
|
|
1025
|
+
deepseek: "CNY"
|
|
1026
|
+
};
|
|
1027
|
+
const BUILTIN_PROVIDER_PRICING = {
|
|
1028
|
+
codex: {
|
|
1029
|
+
"gpt-5.3-codex": {
|
|
1030
|
+
cachedInput: .175,
|
|
1031
|
+
input: 1.75,
|
|
1032
|
+
output: 14
|
|
1033
|
+
},
|
|
1034
|
+
"gpt-5.4": {
|
|
1035
|
+
cachedInput: .25,
|
|
1036
|
+
input: 2.5,
|
|
1037
|
+
output: 15
|
|
1038
|
+
},
|
|
1039
|
+
"gpt-5.4-mini": {
|
|
1040
|
+
cachedInput: .075,
|
|
1041
|
+
input: .75,
|
|
1042
|
+
output: 4.5
|
|
1043
|
+
},
|
|
1044
|
+
"gpt-5.5": {
|
|
1045
|
+
cachedInput: .5,
|
|
1046
|
+
input: 5,
|
|
1047
|
+
output: 30
|
|
1048
|
+
}
|
|
1049
|
+
},
|
|
1050
|
+
dashscope: {
|
|
1051
|
+
"glm-5.1": { tiers: [{
|
|
1052
|
+
cachedInput: 1.2,
|
|
1053
|
+
cacheCreationInput: 7.5,
|
|
1054
|
+
explicitCachedInput: .6,
|
|
1055
|
+
input: 6,
|
|
1056
|
+
maxInputTokens: 32e3,
|
|
1057
|
+
output: 24
|
|
1058
|
+
}, {
|
|
1059
|
+
cachedInput: 1.6,
|
|
1060
|
+
cacheCreationInput: 10,
|
|
1061
|
+
explicitCachedInput: .8,
|
|
1062
|
+
input: 8,
|
|
1063
|
+
maxInputTokens: 2e5,
|
|
1064
|
+
output: 28
|
|
1065
|
+
}] },
|
|
1066
|
+
"glm-5.2": {
|
|
1067
|
+
cachedInput: 2,
|
|
1068
|
+
cacheCreationInput: 10,
|
|
1069
|
+
explicitCachedInput: .8,
|
|
1070
|
+
input: 8,
|
|
1071
|
+
output: 28
|
|
1072
|
+
},
|
|
1073
|
+
"qwen3.7-max": {
|
|
1074
|
+
cachedInput: 2.4,
|
|
1075
|
+
cacheCreationInput: 15,
|
|
1076
|
+
explicitCachedInput: 1.2,
|
|
1077
|
+
input: 12,
|
|
1078
|
+
output: 36
|
|
1079
|
+
},
|
|
1080
|
+
"qwen3.7-plus": { tiers: [{
|
|
1081
|
+
cachedInput: .4,
|
|
1082
|
+
cacheCreationInput: 2.5,
|
|
1083
|
+
explicitCachedInput: .2,
|
|
1084
|
+
input: 2,
|
|
1085
|
+
maxInputTokens: 256e3,
|
|
1086
|
+
output: 8
|
|
1087
|
+
}, {
|
|
1088
|
+
cachedInput: 1.2,
|
|
1089
|
+
cacheCreationInput: 7.5,
|
|
1090
|
+
explicitCachedInput: .6,
|
|
1091
|
+
input: 6,
|
|
1092
|
+
maxInputTokens: 1e6,
|
|
1093
|
+
output: 24
|
|
1094
|
+
}] }
|
|
1095
|
+
},
|
|
1096
|
+
deepseek: {
|
|
1097
|
+
"deepseek-v4-flash": {
|
|
1098
|
+
cachedInput: .02,
|
|
1099
|
+
input: 1,
|
|
1100
|
+
output: 2
|
|
1101
|
+
},
|
|
1102
|
+
"deepseek-v4-pro": {
|
|
1103
|
+
cachedInput: .025,
|
|
1104
|
+
input: 3,
|
|
1105
|
+
output: 6
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
function resolveTokenUsageCost(input) {
|
|
1110
|
+
if (input.source === "copilot") return resolveCopilotCost(input);
|
|
1111
|
+
const providerName = input.providerName?.trim();
|
|
1112
|
+
if (!providerName) return null;
|
|
1113
|
+
const resolvedPricing = resolveProviderPricing(providerName, input.model, input.pricing);
|
|
1114
|
+
if (!resolvedPricing) return null;
|
|
1115
|
+
const pricing = resolvePricingTier(resolvedPricing.pricing, getInputTokenTotal(input));
|
|
1116
|
+
const currency = resolveProviderCurrency(providerName, input.pricingCurrency);
|
|
1117
|
+
if (!currency) return null;
|
|
1118
|
+
const inputPrice = normalizePrice(pricing.input);
|
|
1119
|
+
const outputPrice = normalizePrice(pricing.output);
|
|
1120
|
+
const cacheReadPrice = resolveCacheReadPrice(pricing, input);
|
|
1121
|
+
const cacheCreationPrice = resolveCacheCreationPrice(pricing);
|
|
1122
|
+
const totalCostNanos = costNanosForTokens(input.input_tokens, inputPrice) + costNanosForTokens(input.output_tokens, outputPrice) + costNanosForTokens(input.cache_read_input_tokens, cacheReadPrice) + costNanosForTokens(input.cache_creation_input_tokens, cacheCreationPrice);
|
|
1123
|
+
if (totalCostNanos <= 0) return null;
|
|
1124
|
+
return {
|
|
1125
|
+
currency,
|
|
1126
|
+
source: resolvedPricing.source,
|
|
1127
|
+
total_cost_nanos: totalCostNanos
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
function resolveCopilotCost(input) {
|
|
1131
|
+
const totalNanoAiu = normalizeToken(input.total_nano_aiu);
|
|
1132
|
+
if (totalNanoAiu <= 0) return null;
|
|
1133
|
+
const totalCostNanos = Math.round(totalNanoAiu * COPILOT_NANO_AIU_TO_COST_NANOS);
|
|
1134
|
+
if (totalCostNanos <= 0) return null;
|
|
1135
|
+
return {
|
|
1136
|
+
currency: "USD",
|
|
1137
|
+
source: "copilot_aiu",
|
|
1138
|
+
total_cost_nanos: totalCostNanos
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
function resolveProviderPricing(providerName, model, configuredPricing) {
|
|
1142
|
+
if (configuredPricing) return {
|
|
1143
|
+
pricing: configuredPricing,
|
|
1144
|
+
source: "config"
|
|
1145
|
+
};
|
|
1146
|
+
const builtinPricing = BUILTIN_PROVIDER_PRICING[providerName.toLowerCase()]?.[model.toLowerCase()];
|
|
1147
|
+
if (!builtinPricing) return null;
|
|
1148
|
+
return {
|
|
1149
|
+
pricing: builtinPricing,
|
|
1150
|
+
source: "builtin"
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
function resolvePricingTier(pricing, inputTokenTotal) {
|
|
1154
|
+
const tiers = pricing.tiers?.filter((tier) => typeof tier === "object" && tier !== null).toSorted((a, b) => normalizeTierMax(a) - normalizeTierMax(b));
|
|
1155
|
+
const selectedTier = tiers?.find((tier) => inputTokenTotal <= normalizeTierMax(tier)) ?? tiers?.at(-1);
|
|
1156
|
+
return {
|
|
1157
|
+
...pricing,
|
|
1158
|
+
...selectedTier
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
function normalizeTierMax(tier) {
|
|
1162
|
+
const maxInputTokens = tier.maxInputTokens;
|
|
1163
|
+
return typeof maxInputTokens === "number" && Number.isFinite(maxInputTokens) && maxInputTokens > 0 ? maxInputTokens : Number.POSITIVE_INFINITY;
|
|
1164
|
+
}
|
|
1165
|
+
function getInputTokenTotal(input) {
|
|
1166
|
+
return normalizeToken(input.input_tokens) + normalizeToken(input.cache_read_input_tokens) + normalizeToken(input.cache_creation_input_tokens);
|
|
1167
|
+
}
|
|
1168
|
+
function normalizePrice(value) {
|
|
1169
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
1170
|
+
}
|
|
1171
|
+
function resolveProviderCurrency(providerName, configuredCurrency) {
|
|
1172
|
+
return configuredCurrency?.trim().toUpperCase() || BUILTIN_PROVIDER_CURRENCIES[providerName.toLowerCase()] || null;
|
|
1173
|
+
}
|
|
1174
|
+
function resolveCacheCreationPrice(pricing) {
|
|
1175
|
+
return normalizePrice(pricing.cacheCreationInput);
|
|
1176
|
+
}
|
|
1177
|
+
function resolveCacheReadPrice(pricing, input) {
|
|
1178
|
+
if (input.cache_creation_input_tokens !== void 0 && input.cache_creation_input_tokens !== null) return normalizePrice(pricing.explicitCachedInput);
|
|
1179
|
+
return normalizePrice(pricing.cachedInput);
|
|
1180
|
+
}
|
|
1181
|
+
function costNanosForTokens(tokens, pricePerMillionTokens) {
|
|
1182
|
+
if (pricePerMillionTokens === null) return 0;
|
|
1183
|
+
return Math.round(normalizeToken(tokens) * pricePerMillionTokens * COST_NANOS_PER_TOKEN_AT_ONE_PER_MILLION);
|
|
1184
|
+
}
|
|
1185
|
+
//#endregion
|
|
907
1186
|
//#region src/lib/token-usage/index.ts
|
|
908
1187
|
const tokenUsageEventBus = new EventBus();
|
|
909
1188
|
function resolveTraceId(traceId) {
|
|
@@ -919,9 +1198,12 @@ function resolveUserId(input) {
|
|
|
919
1198
|
function toPersistedEvent(input) {
|
|
920
1199
|
if (!hasAnyToken(input)) return null;
|
|
921
1200
|
const now = /* @__PURE__ */ new Date();
|
|
1201
|
+
const cost = resolveTokenUsageCost(input);
|
|
922
1202
|
return {
|
|
923
1203
|
cache_creation_input_tokens: normalizeToken(input.cache_creation_input_tokens),
|
|
924
1204
|
cache_read_input_tokens: normalizeToken(input.cache_read_input_tokens),
|
|
1205
|
+
cost_currency: cost?.currency ?? null,
|
|
1206
|
+
cost_source: cost?.source ?? null,
|
|
925
1207
|
created_at_ms: now.getTime(),
|
|
926
1208
|
created_at_utc: now.toISOString(),
|
|
927
1209
|
endpoint: input.endpoint,
|
|
@@ -931,6 +1213,8 @@ function toPersistedEvent(input) {
|
|
|
931
1213
|
provider_name: input.providerName?.trim() || null,
|
|
932
1214
|
session_id: resolveTokenUsageSessionId(input.sessionId, input.fallbackSessionId),
|
|
933
1215
|
source: input.source,
|
|
1216
|
+
total_nano_aiu: input.total_nano_aiu === void 0 || input.total_nano_aiu === null ? null : normalizeToken(input.total_nano_aiu),
|
|
1217
|
+
total_cost_nanos: cost?.total_cost_nanos ?? null,
|
|
934
1218
|
total_tokens: resolveTotalTokens(input),
|
|
935
1219
|
trace_id: resolveTraceId(input.traceId),
|
|
936
1220
|
user_id: resolveUserId(input)
|
|
@@ -963,12 +1247,21 @@ function createProviderTokenUsageRecorder(options) {
|
|
|
963
1247
|
});
|
|
964
1248
|
}
|
|
965
1249
|
function normalizeOpenAIUsage(usage) {
|
|
966
|
-
|
|
967
|
-
|
|
1250
|
+
if (usage && (Object.hasOwn(usage, "prompt_cache_hit_tokens") || Object.hasOwn(usage, "prompt_cache_miss_tokens"))) return {
|
|
1251
|
+
cache_read_input_tokens: normalizeToken(usage.prompt_cache_hit_tokens),
|
|
1252
|
+
input_tokens: normalizeToken(usage.prompt_cache_miss_tokens),
|
|
1253
|
+
output_tokens: normalizeToken(usage.completion_tokens),
|
|
1254
|
+
total_tokens: normalizeOptionalToken(usage.total_tokens)
|
|
1255
|
+
};
|
|
1256
|
+
const promptDetails = usage?.prompt_tokens_details;
|
|
1257
|
+
const hasCacheCreationTokens = Boolean(promptDetails && Object.hasOwn(promptDetails, "cache_creation_input_tokens"));
|
|
1258
|
+
const hasCachedTokens = Boolean(promptDetails && Object.hasOwn(promptDetails, "cached_tokens"));
|
|
1259
|
+
const cachedTokens = normalizeToken(promptDetails?.cached_tokens);
|
|
1260
|
+
const cacheCreationTokens = normalizeToken(promptDetails?.cache_creation_input_tokens);
|
|
968
1261
|
const promptTokens = normalizeToken(usage?.prompt_tokens);
|
|
969
1262
|
return {
|
|
970
|
-
cache_creation_input_tokens: cacheCreationTokens,
|
|
971
|
-
cache_read_input_tokens: cachedTokens,
|
|
1263
|
+
...hasCacheCreationTokens && { cache_creation_input_tokens: cacheCreationTokens },
|
|
1264
|
+
...hasCachedTokens && { cache_read_input_tokens: cachedTokens },
|
|
972
1265
|
input_tokens: Math.max(0, promptTokens - cachedTokens - cacheCreationTokens),
|
|
973
1266
|
output_tokens: normalizeToken(usage?.completion_tokens),
|
|
974
1267
|
total_tokens: normalizeOptionalToken(usage?.total_tokens)
|
|
@@ -1104,7 +1397,7 @@ async function forwardProviderModels(providerConfig, requestHeaders) {
|
|
|
1104
1397
|
}
|
|
1105
1398
|
//#endregion
|
|
1106
1399
|
//#region src/routes/provider/chat-completions/handler.ts
|
|
1107
|
-
const logger$
|
|
1400
|
+
const logger$9 = createHandlerLogger("provider-chat-completions-handler");
|
|
1108
1401
|
async function handleProviderChatCompletionsForProvider(c, options) {
|
|
1109
1402
|
const { payload, provider } = options;
|
|
1110
1403
|
const providerConfig = await resolveProviderConfig(provider);
|
|
@@ -1116,19 +1409,19 @@ async function handleProviderChatCompletionsForProvider(c, options) {
|
|
|
1116
1409
|
applyProviderModelDefaults(payload, modelConfig);
|
|
1117
1410
|
applyMissingExtraBody$1(payload, { extraBody: modelConfig?.extraBody });
|
|
1118
1411
|
applyProviderStreamOptions(payload);
|
|
1119
|
-
debugJson(logger$
|
|
1412
|
+
debugJson(logger$9, "provider.chat_completions.request", {
|
|
1120
1413
|
payload,
|
|
1121
1414
|
provider
|
|
1122
1415
|
});
|
|
1123
1416
|
const upstreamResponse = await forwardProviderChatCompletions(providerConfig, payload, c.req.raw.headers);
|
|
1124
1417
|
if (!upstreamResponse.ok) {
|
|
1125
|
-
logger$
|
|
1418
|
+
logger$9.error("Failed to create provider chat completions", {
|
|
1126
1419
|
provider,
|
|
1127
1420
|
statusCode: upstreamResponse.status
|
|
1128
1421
|
});
|
|
1129
1422
|
throw new HTTPError(`Failed to create ${provider} chat completions`, upstreamResponse);
|
|
1130
1423
|
}
|
|
1131
|
-
const recordUsage = createProviderChatCompletionsUsageRecorder(payload, provider);
|
|
1424
|
+
const recordUsage = createProviderChatCompletionsUsageRecorder(payload, provider, modelConfig, providerConfig.pricingCurrency);
|
|
1132
1425
|
const contentType = upstreamResponse.headers.get("content-type") ?? "";
|
|
1133
1426
|
if (Boolean(payload.stream) && contentType.includes("text/event-stream")) return streamProviderChatCompletions(c, upstreamResponse, {
|
|
1134
1427
|
provider,
|
|
@@ -1136,7 +1429,7 @@ async function handleProviderChatCompletionsForProvider(c, options) {
|
|
|
1136
1429
|
});
|
|
1137
1430
|
const responseBody = await upstreamResponse.clone().json();
|
|
1138
1431
|
recordUsage(normalizeOpenAIUsage(responseBody.usage));
|
|
1139
|
-
debugJson(logger$
|
|
1432
|
+
debugJson(logger$9, "provider.chat_completions.response", responseBody);
|
|
1140
1433
|
return createProviderProxyResponse(upstreamResponse);
|
|
1141
1434
|
}
|
|
1142
1435
|
const applyProviderModelDefaults = (payload, modelConfig) => {
|
|
@@ -1154,18 +1447,20 @@ const applyProviderStreamOptions = (payload) => {
|
|
|
1154
1447
|
include_usage: true
|
|
1155
1448
|
};
|
|
1156
1449
|
};
|
|
1157
|
-
const createProviderChatCompletionsUsageRecorder = (payload, provider) => createProviderTokenUsageRecorder({
|
|
1450
|
+
const createProviderChatCompletionsUsageRecorder = (payload, provider, modelConfig, pricingCurrency) => createProviderTokenUsageRecorder({
|
|
1158
1451
|
endpoint: "chat_completions",
|
|
1159
1452
|
model: payload.model,
|
|
1453
|
+
pricing: modelConfig?.pricing,
|
|
1454
|
+
pricingCurrency,
|
|
1160
1455
|
providerName: provider
|
|
1161
1456
|
});
|
|
1162
1457
|
const streamProviderChatCompletions = (c, upstreamResponse, options) => {
|
|
1163
|
-
logger$
|
|
1458
|
+
logger$9.debug("provider.chat_completions.streaming", { provider: options.provider });
|
|
1164
1459
|
return streamSSE(c, async (stream) => {
|
|
1165
1460
|
let usage = {};
|
|
1166
1461
|
try {
|
|
1167
1462
|
for await (const chunk of events(upstreamResponse)) {
|
|
1168
|
-
debugJson(logger$
|
|
1463
|
+
debugJson(logger$9, "provider.chat_completions.stream_chunk", chunk);
|
|
1169
1464
|
if (chunk.data && chunk.data !== "[DONE]") {
|
|
1170
1465
|
const parsedChunk = parseChatCompletionChunkData(chunk.data);
|
|
1171
1466
|
if (parsedChunk?.usage) usage = normalizeOpenAIUsage(parsedChunk.usage);
|
|
@@ -1292,7 +1587,7 @@ const createChatCompletions = async (payload, options) => {
|
|
|
1292
1587
|
};
|
|
1293
1588
|
//#endregion
|
|
1294
1589
|
//#region src/routes/chat-completions/handler.ts
|
|
1295
|
-
const logger$
|
|
1590
|
+
const logger$8 = createHandlerLogger("chat-completions-handler");
|
|
1296
1591
|
async function handleCompletion$1(c) {
|
|
1297
1592
|
let payload = await c.req.json();
|
|
1298
1593
|
const requestedModel = payload.model;
|
|
@@ -1307,7 +1602,7 @@ async function handleCompletion$1(c) {
|
|
|
1307
1602
|
});
|
|
1308
1603
|
}
|
|
1309
1604
|
await checkRateLimit(state);
|
|
1310
|
-
debugJson(logger$
|
|
1605
|
+
debugJson(logger$8, "Request payload:", payload);
|
|
1311
1606
|
const selectedModel = state.models?.data.find((model) => model.id === payload.model);
|
|
1312
1607
|
if (state.manualApprove) await awaitApproval();
|
|
1313
1608
|
if (isNullish(payload.max_tokens) && isNullish(payload.max_completion_tokens)) {
|
|
@@ -1315,16 +1610,16 @@ async function handleCompletion$1(c) {
|
|
|
1315
1610
|
...payload,
|
|
1316
1611
|
max_tokens: selectedModel?.capabilities.limits.max_output_tokens
|
|
1317
1612
|
};
|
|
1318
|
-
debugJson(logger$
|
|
1613
|
+
debugJson(logger$8, "Set max_tokens to:", payload.max_tokens);
|
|
1319
1614
|
}
|
|
1320
1615
|
if (payload.model.includes("gpt")) {
|
|
1321
1616
|
if (isNullish(payload.max_completion_tokens)) payload.max_completion_tokens = payload.max_tokens;
|
|
1322
1617
|
delete payload.max_tokens;
|
|
1323
1618
|
}
|
|
1324
1619
|
const requestId = generateRequestIdFromPayload(payload);
|
|
1325
|
-
logger$
|
|
1620
|
+
logger$8.debug("Generated request ID:", requestId);
|
|
1326
1621
|
const sessionId = getUUID(requestId);
|
|
1327
|
-
logger$
|
|
1622
|
+
logger$8.debug("Extracted session ID:", sessionId);
|
|
1328
1623
|
const recordUsage = createCopilotTokenUsageRecorder({
|
|
1329
1624
|
endpoint: "chat_completions",
|
|
1330
1625
|
fallbackSessionId: sessionId,
|
|
@@ -1335,17 +1630,23 @@ async function handleCompletion$1(c) {
|
|
|
1335
1630
|
sessionId
|
|
1336
1631
|
});
|
|
1337
1632
|
if (isNonStreaming$1(response)) {
|
|
1338
|
-
debugJson(logger$
|
|
1339
|
-
recordUsage(
|
|
1633
|
+
debugJson(logger$8, "Non-streaming response:", response);
|
|
1634
|
+
recordUsage({
|
|
1635
|
+
...normalizeOpenAIUsage(response.usage),
|
|
1636
|
+
total_nano_aiu: normalizeOptionalToken(response.copilot_usage?.total_nano_aiu)
|
|
1637
|
+
});
|
|
1340
1638
|
return c.json(response);
|
|
1341
1639
|
}
|
|
1342
|
-
logger$
|
|
1640
|
+
logger$8.debug("Streaming response");
|
|
1343
1641
|
return streamSSE(c, async (stream) => {
|
|
1344
1642
|
let usage = {};
|
|
1345
1643
|
for await (const chunk of response) {
|
|
1346
|
-
debugJson(logger$
|
|
1644
|
+
debugJson(logger$8, "Streaming chunk:", chunk);
|
|
1347
1645
|
const parsedChunk = parseChatCompletionChunk(chunk);
|
|
1348
|
-
if (parsedChunk?.usage) usage =
|
|
1646
|
+
if (parsedChunk?.usage || parsedChunk?.copilot_usage) usage = {
|
|
1647
|
+
...normalizeOpenAIUsage(parsedChunk.usage),
|
|
1648
|
+
total_nano_aiu: normalizeOptionalToken(parsedChunk.copilot_usage?.total_nano_aiu)
|
|
1649
|
+
};
|
|
1349
1650
|
await stream.writeSSE(chunk);
|
|
1350
1651
|
}
|
|
1351
1652
|
recordUsage(usage);
|
|
@@ -2448,7 +2749,7 @@ const prepareMessagesApiPayload = (payload, selectedModel) => {
|
|
|
2448
2749
|
};
|
|
2449
2750
|
//#endregion
|
|
2450
2751
|
//#region src/routes/provider/messages/count-tokens-handler.ts
|
|
2451
|
-
const logger$
|
|
2752
|
+
const logger$7 = createHandlerLogger("provider-count-tokens-handler");
|
|
2452
2753
|
async function handleProviderCountTokens(c) {
|
|
2453
2754
|
const provider = c.req.param("provider");
|
|
2454
2755
|
return await handleProviderCountTokensForProvider(c, {
|
|
@@ -2471,7 +2772,7 @@ async function handleProviderCountTokensForProvider(c, options) {
|
|
|
2471
2772
|
toolContentSupportType: modelConfig?.toolContentSupportType ?? []
|
|
2472
2773
|
} : void 0), createFallbackModel(modelId));
|
|
2473
2774
|
const finalTokenCount = tokenCount.input + tokenCount.output;
|
|
2474
|
-
logger$
|
|
2775
|
+
logger$7.debug("provider.count_tokens.success", {
|
|
2475
2776
|
provider,
|
|
2476
2777
|
model: anthropicPayload.model,
|
|
2477
2778
|
input_tokens: finalTokenCount
|
|
@@ -3608,9 +3909,9 @@ const mapResponsesUsage = (response) => {
|
|
|
3608
3909
|
...response.usage?.input_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: response.usage.input_tokens_details.cached_tokens }
|
|
3609
3910
|
};
|
|
3610
3911
|
};
|
|
3611
|
-
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
3612
|
-
const isResponseOutputText = (block) => isRecord(block) && "type" in block && block.type === "output_text";
|
|
3613
|
-
const isResponseOutputRefusal = (block) => isRecord(block) && "type" in block && block.type === "refusal";
|
|
3912
|
+
const isRecord$1 = (value) => typeof value === "object" && value !== null;
|
|
3913
|
+
const isResponseOutputText = (block) => isRecord$1(block) && "type" in block && block.type === "output_text";
|
|
3914
|
+
const isResponseOutputRefusal = (block) => isRecord$1(block) && "type" in block && block.type === "refusal";
|
|
3614
3915
|
const convertToolResultContent = (content) => {
|
|
3615
3916
|
if (typeof content === "string") return content;
|
|
3616
3917
|
if (Array.isArray(content)) {
|
|
@@ -4512,39 +4813,47 @@ const createWebSearchResponsesStreamCollection = () => ({
|
|
|
4512
4813
|
textPartsByKey: /* @__PURE__ */ new Map()
|
|
4513
4814
|
});
|
|
4514
4815
|
const collectWebSearchResponsesStreamEvent = (event, state) => {
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4816
|
+
switch (event.type) {
|
|
4817
|
+
case "response.created":
|
|
4818
|
+
state.createdResponse = getResponsesResult(event.response);
|
|
4819
|
+
break;
|
|
4820
|
+
case "response.completed":
|
|
4821
|
+
case "response.failed":
|
|
4822
|
+
case "response.incomplete":
|
|
4823
|
+
if (isResponsesTerminalEvent(event)) {
|
|
4824
|
+
event.response.copilot_usage ??= event.copilot_usage;
|
|
4825
|
+
state.terminalResponse = event.response;
|
|
4826
|
+
}
|
|
4827
|
+
break;
|
|
4828
|
+
case "response.output_item.added":
|
|
4829
|
+
case "response.output_item.done": {
|
|
4830
|
+
const outputIndex = getNumber(event.output_index);
|
|
4831
|
+
const item = getRecord(event.item);
|
|
4832
|
+
if (outputIndex !== void 0 && item) state.outputItemsByIndex.set(outputIndex, item);
|
|
4833
|
+
break;
|
|
4834
|
+
}
|
|
4835
|
+
case "response.output_text.delta": {
|
|
4836
|
+
const part = getOrCreateOutputTextPart(event, state);
|
|
4837
|
+
const delta = getString(event.delta);
|
|
4838
|
+
if (part && delta) part.text += delta;
|
|
4839
|
+
break;
|
|
4840
|
+
}
|
|
4841
|
+
case "response.output_text.done": {
|
|
4842
|
+
const part = getOrCreateOutputTextPart(event, state);
|
|
4843
|
+
const text = getString(event.text);
|
|
4844
|
+
if (part && text !== void 0) part.text = text;
|
|
4845
|
+
break;
|
|
4846
|
+
}
|
|
4847
|
+
case "response.output_text.annotation.added": {
|
|
4848
|
+
const part = getOrCreateOutputTextPart(event, state);
|
|
4849
|
+
const annotation = event.annotation;
|
|
4850
|
+
if (part && annotation !== void 0) part.annotations.push(annotation);
|
|
4851
|
+
break;
|
|
4852
|
+
}
|
|
4853
|
+
case "response.content_part.done":
|
|
4854
|
+
collectDoneContentPart(event, state);
|
|
4855
|
+
break;
|
|
4546
4856
|
}
|
|
4547
|
-
if (event.type === "response.content_part.done") collectDoneContentPart(event, state);
|
|
4548
4857
|
};
|
|
4549
4858
|
const buildWebSearchResponsesStreamResult = (state) => {
|
|
4550
4859
|
const response = state.terminalResponse ?? state.createdResponse;
|
|
@@ -4692,7 +5001,10 @@ const handleWebSearchViaResponses = async (c, payload, options) => {
|
|
|
4692
5001
|
}) : upstreamResult;
|
|
4693
5002
|
const { extract, response } = reconstructWebSearchResponse(payload, result, { requestId: options.requestId });
|
|
4694
5003
|
debugJson(logger, `Web search via responses: ${extract.queries.length} quer(y/ies), ${extract.sources.length} source(s)`, result);
|
|
4695
|
-
createUsageRecorder(payload, options.sessionId, webSearchModel)(
|
|
5004
|
+
createUsageRecorder(payload, options.sessionId, webSearchModel)({
|
|
5005
|
+
...normalizeResponsesUsage(result.usage),
|
|
5006
|
+
total_nano_aiu: normalizeOptionalToken(result.copilot_usage?.total_nano_aiu)
|
|
5007
|
+
});
|
|
4696
5008
|
if (!wantsStream) return c.json(response);
|
|
4697
5009
|
return streamSSE(c, async (stream) => {
|
|
4698
5010
|
for (const event of buildSyntheticStreamEvents(response)) await stream.writeSSE({
|
|
@@ -4857,7 +5169,7 @@ function getModels() {
|
|
|
4857
5169
|
}
|
|
4858
5170
|
//#endregion
|
|
4859
5171
|
//#region src/routes/provider/messages/handler.ts
|
|
4860
|
-
const logger$
|
|
5172
|
+
const logger$6 = createHandlerLogger("provider-messages-handler");
|
|
4861
5173
|
const OPENAI_COMPATIBLE_CONTEXT_CACHE_MARKER_LIMIT = 4;
|
|
4862
5174
|
const OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL = { type: "ephemeral" };
|
|
4863
5175
|
const OPENAI_COMPATIBLE_CONTEXT_CACHE_ROLES = new Set([
|
|
@@ -4882,7 +5194,7 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
4882
5194
|
} }, 404);
|
|
4883
5195
|
try {
|
|
4884
5196
|
const modelConfig = providerConfig.models?.[payload.model];
|
|
4885
|
-
debugJson(logger$
|
|
5197
|
+
debugJson(logger$6, "provider.messages.request", {
|
|
4886
5198
|
payload,
|
|
4887
5199
|
provider
|
|
4888
5200
|
});
|
|
@@ -4891,6 +5203,7 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
4891
5203
|
if (providerConfig.type === "openai-responses") {
|
|
4892
5204
|
if (hasWebSearchServerTool(payload)) {
|
|
4893
5205
|
if (isWebSearchOnlyRequest(payload)) return await handleOpenAIResponsesProviderWebSearchMessages(c, {
|
|
5206
|
+
modelConfig,
|
|
4894
5207
|
payload,
|
|
4895
5208
|
provider,
|
|
4896
5209
|
providerConfig
|
|
@@ -4914,29 +5227,33 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
4914
5227
|
});
|
|
4915
5228
|
}
|
|
4916
5229
|
applyMissingExtraBody(payload, { extraBody: modelConfig?.extraBody });
|
|
4917
|
-
debugJson(logger$
|
|
5230
|
+
debugJson(logger$6, "Translated provider.messages.request", {
|
|
4918
5231
|
payload,
|
|
4919
5232
|
provider
|
|
4920
5233
|
});
|
|
4921
5234
|
const upstreamResponse = await forwardProviderMessages(providerConfig, payload, c.req.raw.headers);
|
|
4922
5235
|
if (!upstreamResponse.ok) {
|
|
4923
|
-
logger$
|
|
5236
|
+
logger$6.error("Failed to create responses", upstreamResponse);
|
|
4924
5237
|
throw new HTTPError("Failed to create responses", upstreamResponse);
|
|
4925
5238
|
}
|
|
4926
5239
|
const contentType = upstreamResponse.headers.get("content-type") ?? "";
|
|
4927
5240
|
if (Boolean(payload.stream) && contentType.includes("text/event-stream")) return streamProviderMessages({
|
|
4928
5241
|
c,
|
|
5242
|
+
modelConfig,
|
|
4929
5243
|
payload,
|
|
5244
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
4930
5245
|
provider,
|
|
4931
5246
|
upstreamResponse
|
|
4932
5247
|
});
|
|
4933
5248
|
return respondProviderMessagesJson(c, {
|
|
4934
5249
|
body: await upstreamResponse.json(),
|
|
5250
|
+
modelConfig,
|
|
4935
5251
|
payload,
|
|
5252
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
4936
5253
|
provider
|
|
4937
5254
|
});
|
|
4938
5255
|
} catch (error) {
|
|
4939
|
-
logger$
|
|
5256
|
+
logger$6.error("provider.messages.error", {
|
|
4940
5257
|
provider,
|
|
4941
5258
|
error
|
|
4942
5259
|
});
|
|
@@ -4944,13 +5261,13 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
4944
5261
|
}
|
|
4945
5262
|
}
|
|
4946
5263
|
const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
|
|
4947
|
-
const { payload, provider, providerConfig } = options;
|
|
5264
|
+
const { modelConfig, payload, provider, providerConfig } = options;
|
|
4948
5265
|
const selectedModel = providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0;
|
|
4949
5266
|
const responsesPayload = prepareWebSearchResponsesPayload(payload);
|
|
4950
5267
|
responsesPayload.stream = true;
|
|
4951
5268
|
applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens);
|
|
4952
5269
|
compactInputByLatestCompaction(responsesPayload);
|
|
4953
|
-
debugJson(logger$
|
|
5270
|
+
debugJson(logger$6, "provider.messages.responses.web_search.request", {
|
|
4954
5271
|
payload: responsesPayload,
|
|
4955
5272
|
provider
|
|
4956
5273
|
});
|
|
@@ -4961,20 +5278,24 @@ const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
|
|
|
4961
5278
|
errorMessagePrefix: `${provider} web search responses stream`,
|
|
4962
5279
|
parseEvent: (data) => parseResponsesProviderStreamChunk(data, providerConfig),
|
|
4963
5280
|
upstreamResponse,
|
|
4964
|
-
logger: logger$
|
|
5281
|
+
logger: logger$6
|
|
4965
5282
|
}),
|
|
5283
|
+
modelConfig,
|
|
4966
5284
|
payload,
|
|
5285
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
4967
5286
|
provider
|
|
4968
5287
|
});
|
|
4969
5288
|
return respondWebSearchProviderMessagesJson(c, {
|
|
4970
5289
|
body: upstreamResponse,
|
|
5290
|
+
modelConfig,
|
|
4971
5291
|
payload,
|
|
5292
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
4972
5293
|
provider
|
|
4973
5294
|
});
|
|
4974
5295
|
}
|
|
4975
5296
|
const upstreamResponse = await forwardProviderResponses(providerConfig, responsesPayload, c.req.raw.headers);
|
|
4976
5297
|
if (!upstreamResponse.ok) {
|
|
4977
|
-
logger$
|
|
5298
|
+
logger$6.error("Failed to create provider web search responses", {
|
|
4978
5299
|
provider,
|
|
4979
5300
|
upstreamResponse
|
|
4980
5301
|
});
|
|
@@ -4985,24 +5306,28 @@ const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
|
|
|
4985
5306
|
errorMessagePrefix: `${provider} web search responses stream`,
|
|
4986
5307
|
parseEvent: (data) => parseResponsesProviderStreamChunk(data, providerConfig),
|
|
4987
5308
|
upstreamResponse: events(upstreamResponse),
|
|
4988
|
-
logger: logger$
|
|
5309
|
+
logger: logger$6
|
|
4989
5310
|
}),
|
|
5311
|
+
modelConfig,
|
|
4990
5312
|
payload,
|
|
5313
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
4991
5314
|
provider
|
|
4992
5315
|
});
|
|
4993
5316
|
return respondWebSearchProviderMessagesJson(c, {
|
|
4994
5317
|
body: await upstreamResponse.json(),
|
|
5318
|
+
modelConfig,
|
|
4995
5319
|
payload,
|
|
5320
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
4996
5321
|
provider
|
|
4997
5322
|
});
|
|
4998
5323
|
};
|
|
4999
5324
|
const handleOpenAIResponsesProviderMessages = async (c, options) => {
|
|
5000
|
-
const { payload, provider, providerConfig } = options;
|
|
5325
|
+
const { modelConfig, payload, provider, providerConfig } = options;
|
|
5001
5326
|
const selectedModel = providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0;
|
|
5002
5327
|
const responsesPayload = translateAnthropicMessagesToResponsesPayload(payload);
|
|
5003
5328
|
applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens);
|
|
5004
5329
|
compactInputByLatestCompaction(responsesPayload);
|
|
5005
|
-
debugJson(logger$
|
|
5330
|
+
debugJson(logger$6, "provider.messages.responses.request", {
|
|
5006
5331
|
payload: responsesPayload,
|
|
5007
5332
|
provider
|
|
5008
5333
|
});
|
|
@@ -5010,33 +5335,41 @@ const handleOpenAIResponsesProviderMessages = async (c, options) => {
|
|
|
5010
5335
|
const upstreamResponse = await forwardCodexResponses(responsesPayload, c.req.raw.headers, providerConfig.baseUrl);
|
|
5011
5336
|
if (responsesPayload.stream && isResponsesStream$1(upstreamResponse)) return streamResponsesProviderMessages({
|
|
5012
5337
|
c,
|
|
5338
|
+
modelConfig,
|
|
5013
5339
|
payload,
|
|
5340
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
5014
5341
|
provider,
|
|
5015
5342
|
providerConfig,
|
|
5016
5343
|
upstreamResponse
|
|
5017
5344
|
});
|
|
5018
5345
|
return respondResponsesProviderMessagesJson(c, {
|
|
5019
5346
|
body: upstreamResponse,
|
|
5347
|
+
modelConfig,
|
|
5020
5348
|
payload,
|
|
5349
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
5021
5350
|
provider,
|
|
5022
5351
|
providerConfig
|
|
5023
5352
|
});
|
|
5024
5353
|
}
|
|
5025
5354
|
const upstreamResponse = await forwardProviderResponses(providerConfig, responsesPayload, c.req.raw.headers);
|
|
5026
5355
|
if (!upstreamResponse.ok) {
|
|
5027
|
-
logger$
|
|
5356
|
+
logger$6.error("Failed to create provider responses", upstreamResponse);
|
|
5028
5357
|
throw new HTTPError("Failed to create provider responses", upstreamResponse);
|
|
5029
5358
|
}
|
|
5030
5359
|
if (responsesPayload.stream) return streamResponsesProviderMessages({
|
|
5031
5360
|
c,
|
|
5361
|
+
modelConfig,
|
|
5032
5362
|
payload,
|
|
5363
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
5033
5364
|
provider,
|
|
5034
5365
|
providerConfig,
|
|
5035
5366
|
upstreamResponse: events(upstreamResponse)
|
|
5036
5367
|
});
|
|
5037
5368
|
return respondResponsesProviderMessagesJson(c, {
|
|
5038
5369
|
body: await upstreamResponse.json(),
|
|
5370
|
+
modelConfig,
|
|
5039
5371
|
payload,
|
|
5372
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
5040
5373
|
provider,
|
|
5041
5374
|
providerConfig
|
|
5042
5375
|
});
|
|
@@ -5071,25 +5404,29 @@ const applyOpenAICompatibleExtraBodyThinkingBudget = (payload, options) => {
|
|
|
5071
5404
|
const handleOpenAICompatibleProviderMessages = async (c, options) => {
|
|
5072
5405
|
const { modelConfig, payload, provider, providerConfig } = options;
|
|
5073
5406
|
const openAIPayload = createOpenAICompatiblePayload(payload, modelConfig);
|
|
5074
|
-
debugJson(logger$
|
|
5407
|
+
debugJson(logger$6, "provider.messages.openai_compatible.request", {
|
|
5075
5408
|
payload: openAIPayload,
|
|
5076
5409
|
provider
|
|
5077
5410
|
});
|
|
5078
5411
|
const upstreamResponse = await forwardProviderChatCompletions(providerConfig, openAIPayload, c.req.raw.headers);
|
|
5079
5412
|
if (!upstreamResponse.ok) {
|
|
5080
|
-
logger$
|
|
5413
|
+
logger$6.error("Failed to create openai-compatible responses", upstreamResponse);
|
|
5081
5414
|
throw new HTTPError("Failed to create openai-compatible responses", upstreamResponse);
|
|
5082
5415
|
}
|
|
5083
5416
|
const contentType = upstreamResponse.headers.get("content-type") ?? "";
|
|
5084
5417
|
if (Boolean(openAIPayload.stream) && contentType.includes("text/event-stream")) return streamOpenAICompatibleProviderMessages({
|
|
5085
5418
|
c,
|
|
5419
|
+
modelConfig,
|
|
5086
5420
|
payload,
|
|
5421
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
5087
5422
|
provider,
|
|
5088
5423
|
upstreamResponse
|
|
5089
5424
|
});
|
|
5090
5425
|
return respondOpenAICompatibleProviderMessagesJson(c, {
|
|
5091
5426
|
body: await upstreamResponse.json(),
|
|
5427
|
+
modelConfig,
|
|
5092
5428
|
payload,
|
|
5429
|
+
pricingCurrency: providerConfig.pricingCurrency,
|
|
5093
5430
|
provider
|
|
5094
5431
|
});
|
|
5095
5432
|
};
|
|
@@ -5158,13 +5495,13 @@ const applyContextCacheControl = (message) => {
|
|
|
5158
5495
|
const setContextCacheControl = (part) => {
|
|
5159
5496
|
part.cache_control = { ...OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL };
|
|
5160
5497
|
};
|
|
5161
|
-
const streamProviderMessages = ({ c, payload, provider, upstreamResponse }) => {
|
|
5162
|
-
logger$
|
|
5163
|
-
const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
|
|
5498
|
+
const streamProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, upstreamResponse }) => {
|
|
5499
|
+
logger$6.debug("provider.messages.streaming");
|
|
5500
|
+
const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency);
|
|
5164
5501
|
return streamSSE(c, async (stream) => {
|
|
5165
5502
|
let usage = {};
|
|
5166
5503
|
for await (const chunk of events(upstreamResponse)) {
|
|
5167
|
-
logger$
|
|
5504
|
+
logger$6.debug("provider.messages.raw_stream_event:", chunk.data);
|
|
5168
5505
|
const eventName = chunk.event;
|
|
5169
5506
|
if (eventName === "ping") {
|
|
5170
5507
|
await stream.writeSSE({
|
|
@@ -5189,9 +5526,9 @@ const streamProviderMessages = ({ c, payload, provider, upstreamResponse }) => {
|
|
|
5189
5526
|
recordUsage(usage);
|
|
5190
5527
|
});
|
|
5191
5528
|
};
|
|
5192
|
-
const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstreamResponse }) => {
|
|
5193
|
-
logger$
|
|
5194
|
-
const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
|
|
5529
|
+
const streamOpenAICompatibleProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, upstreamResponse }) => {
|
|
5530
|
+
logger$6.debug("provider.messages.openai_compatible.streaming");
|
|
5531
|
+
const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency);
|
|
5195
5532
|
return streamSSE(c, async (stream) => {
|
|
5196
5533
|
let usage = {};
|
|
5197
5534
|
const streamState = {
|
|
@@ -5202,7 +5539,7 @@ const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstream
|
|
|
5202
5539
|
thinkingBlockOpen: false
|
|
5203
5540
|
};
|
|
5204
5541
|
for await (const chunk of events(upstreamResponse)) {
|
|
5205
|
-
logger$
|
|
5542
|
+
logger$6.debug("provider.messages.openai_compatible.raw_stream_event:", chunk.data);
|
|
5206
5543
|
if (chunk.event === "ping") {
|
|
5207
5544
|
await stream.writeSSE({
|
|
5208
5545
|
event: "ping",
|
|
@@ -5220,7 +5557,7 @@ const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstream
|
|
|
5220
5557
|
const events = translateChunkToAnthropicEvents(parsed, streamState);
|
|
5221
5558
|
for (const event of events) {
|
|
5222
5559
|
const eventData = JSON.stringify(event);
|
|
5223
|
-
debugLazy(logger$
|
|
5560
|
+
debugLazy(logger$6, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
|
|
5224
5561
|
await stream.writeSSE({
|
|
5225
5562
|
event: event.type,
|
|
5226
5563
|
data: eventData
|
|
@@ -5229,7 +5566,7 @@ const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstream
|
|
|
5229
5566
|
}
|
|
5230
5567
|
for (const event of flushPendingAnthropicStreamEvents(streamState)) {
|
|
5231
5568
|
const eventData = JSON.stringify(event);
|
|
5232
|
-
debugLazy(logger$
|
|
5569
|
+
debugLazy(logger$6, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
|
|
5233
5570
|
await stream.writeSSE({
|
|
5234
5571
|
event: event.type,
|
|
5235
5572
|
data: eventData
|
|
@@ -5238,14 +5575,14 @@ const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstream
|
|
|
5238
5575
|
recordUsage(usage);
|
|
5239
5576
|
});
|
|
5240
5577
|
};
|
|
5241
|
-
const streamResponsesProviderMessages = ({ c, payload, provider, providerConfig, upstreamResponse }) => {
|
|
5242
|
-
logger$
|
|
5243
|
-
const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
|
|
5578
|
+
const streamResponsesProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, providerConfig, upstreamResponse }) => {
|
|
5579
|
+
logger$6.debug("provider.messages.responses.streaming", { provider });
|
|
5580
|
+
const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency);
|
|
5244
5581
|
return streamSSE(c, async (stream) => {
|
|
5245
5582
|
let usage = {};
|
|
5246
5583
|
const streamState = createResponsesStreamState({ toolSearchName: resolveBridgeToolSearchName(payload.tools) });
|
|
5247
5584
|
for await (const chunk of upstreamResponse) {
|
|
5248
|
-
logger$
|
|
5585
|
+
logger$6.debug("provider.messages.responses.raw_stream_event:", chunk.data);
|
|
5249
5586
|
if (chunk.event === "ping") {
|
|
5250
5587
|
await stream.writeSSE({
|
|
5251
5588
|
event: "ping",
|
|
@@ -5263,7 +5600,7 @@ const streamResponsesProviderMessages = ({ c, payload, provider, providerConfig,
|
|
|
5263
5600
|
const events = translateResponsesStreamEvent(parsed, streamState);
|
|
5264
5601
|
for (const event of events) {
|
|
5265
5602
|
const eventData = JSON.stringify(event);
|
|
5266
|
-
debugLazy(logger$
|
|
5603
|
+
debugLazy(logger$6, () => ["provider.messages.responses.translated_event:", eventData]);
|
|
5267
5604
|
await stream.writeSSE({
|
|
5268
5605
|
event: event.type,
|
|
5269
5606
|
data: eventData
|
|
@@ -5287,7 +5624,7 @@ const parseOpenAICompatibleStreamChunk = (data) => {
|
|
|
5287
5624
|
try {
|
|
5288
5625
|
return JSON.parse(data);
|
|
5289
5626
|
} catch (error) {
|
|
5290
|
-
logger$
|
|
5627
|
+
logger$6.error("provider.messages.openai_compatible.parse_chunk_error", {
|
|
5291
5628
|
data,
|
|
5292
5629
|
error
|
|
5293
5630
|
});
|
|
@@ -5300,7 +5637,7 @@ const parseResponsesProviderStreamChunk = (data, providerConfig) => {
|
|
|
5300
5637
|
if (providerConfig.name === "codex") logCodexRateLimitsEvent(parsed);
|
|
5301
5638
|
return parsed;
|
|
5302
5639
|
} catch (error) {
|
|
5303
|
-
logger$
|
|
5640
|
+
logger$6.error("provider.messages.responses.parse_chunk_error", {
|
|
5304
5641
|
provider: providerConfig.name,
|
|
5305
5642
|
data,
|
|
5306
5643
|
error
|
|
@@ -5325,7 +5662,7 @@ const parseProviderStreamEvent = (data) => {
|
|
|
5325
5662
|
usage: {}
|
|
5326
5663
|
};
|
|
5327
5664
|
} catch (error) {
|
|
5328
|
-
logger$
|
|
5665
|
+
logger$6.error("provider.messages.streaming.adjust_tokens_error", {
|
|
5329
5666
|
error,
|
|
5330
5667
|
originalData: data
|
|
5331
5668
|
});
|
|
@@ -5333,31 +5670,31 @@ const parseProviderStreamEvent = (data) => {
|
|
|
5333
5670
|
}
|
|
5334
5671
|
};
|
|
5335
5672
|
const respondProviderMessagesJson = (c, options) => {
|
|
5336
|
-
const { body, payload, provider } = options;
|
|
5337
|
-
createProviderMessagesUsageRecorder(payload, provider)(normalizeAnthropicUsage(body.usage));
|
|
5338
|
-
debugJson(logger$
|
|
5673
|
+
const { body, modelConfig, payload, pricingCurrency, provider } = options;
|
|
5674
|
+
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeAnthropicUsage(body.usage));
|
|
5675
|
+
debugJson(logger$6, "provider.messages.no_stream result:", body);
|
|
5339
5676
|
return c.json(body);
|
|
5340
5677
|
};
|
|
5341
5678
|
const respondOpenAICompatibleProviderMessagesJson = (c, options) => {
|
|
5342
|
-
const { body, payload, provider } = options;
|
|
5343
|
-
createProviderMessagesUsageRecorder(payload, provider)(normalizeOpenAIUsage(body.usage));
|
|
5679
|
+
const { body, modelConfig, payload, pricingCurrency, provider } = options;
|
|
5680
|
+
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeOpenAIUsage(body.usage));
|
|
5344
5681
|
const anthropicResponse = translateToAnthropic(body);
|
|
5345
|
-
debugJson(logger$
|
|
5682
|
+
debugJson(logger$6, "provider.messages.openai_compatible.no_stream result:", anthropicResponse);
|
|
5346
5683
|
return c.json(anthropicResponse);
|
|
5347
5684
|
};
|
|
5348
5685
|
const respondResponsesProviderMessagesJson = (c, options) => {
|
|
5349
|
-
const { body, payload, provider, providerConfig } = options;
|
|
5350
|
-
createProviderMessagesUsageRecorder(payload, provider)(normalizeResponsesUsage(body.usage));
|
|
5686
|
+
const { body, modelConfig, payload, pricingCurrency, provider, providerConfig } = options;
|
|
5687
|
+
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeResponsesUsage(body.usage));
|
|
5351
5688
|
const anthropicResponse = translateResponsesResultToAnthropic(body, { toolSearchName: resolveBridgeToolSearchName(payload.tools) });
|
|
5352
|
-
debugJson(logger$
|
|
5353
|
-
if (providerConfig.name === "codex") logger$
|
|
5689
|
+
debugJson(logger$6, "provider.messages.responses.no_stream result:", anthropicResponse);
|
|
5690
|
+
if (providerConfig.name === "codex") logger$6.debug("provider.messages.codex.no_stream.result");
|
|
5354
5691
|
return c.json(anthropicResponse);
|
|
5355
5692
|
};
|
|
5356
5693
|
const respondWebSearchProviderMessagesJson = (c, options) => {
|
|
5357
|
-
const { body, payload, provider } = options;
|
|
5358
|
-
createProviderMessagesUsageRecorder(payload, provider)(normalizeResponsesUsage(body.usage));
|
|
5694
|
+
const { body, modelConfig, payload, pricingCurrency, provider } = options;
|
|
5695
|
+
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeResponsesUsage(body.usage));
|
|
5359
5696
|
const { extract, response } = reconstructWebSearchResponse(payload, body, { requestId: body.id || `${provider}:${payload.model}` });
|
|
5360
|
-
logger$
|
|
5697
|
+
logger$6.debug(`provider.messages.responses.web_search: ${extract.queries.length} quer(y/ies), ${extract.sources.length} source(s)`);
|
|
5361
5698
|
if (!payload.stream) return c.json(response);
|
|
5362
5699
|
return streamSSE(c, async (stream) => {
|
|
5363
5700
|
for (const event of buildSyntheticStreamEvents(response)) await stream.writeSSE({
|
|
@@ -5366,9 +5703,11 @@ const respondWebSearchProviderMessagesJson = (c, options) => {
|
|
|
5366
5703
|
});
|
|
5367
5704
|
});
|
|
5368
5705
|
};
|
|
5369
|
-
const createProviderMessagesUsageRecorder = (payload, provider) => createProviderTokenUsageRecorder({
|
|
5706
|
+
const createProviderMessagesUsageRecorder = (payload, provider, modelConfig, pricingCurrency) => createProviderTokenUsageRecorder({
|
|
5370
5707
|
endpoint: "provider_messages",
|
|
5371
5708
|
model: payload.model,
|
|
5709
|
+
pricing: modelConfig?.pricing,
|
|
5710
|
+
pricingCurrency,
|
|
5372
5711
|
providerName: provider,
|
|
5373
5712
|
sessionId: parseUserIdMetadata(payload.metadata?.user_id).sessionId
|
|
5374
5713
|
});
|
|
@@ -5454,7 +5793,10 @@ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
|
|
|
5454
5793
|
});
|
|
5455
5794
|
if (isNonStreaming(response)) {
|
|
5456
5795
|
debugJson(logger, "Non-streaming response from Copilot:", response);
|
|
5457
|
-
recordUsage(
|
|
5796
|
+
recordUsage({
|
|
5797
|
+
...normalizeOpenAIUsage(response.usage),
|
|
5798
|
+
total_nano_aiu: normalizeOptionalToken(response.copilot_usage?.total_nano_aiu)
|
|
5799
|
+
});
|
|
5458
5800
|
const anthropicResponse = translateToAnthropic(response);
|
|
5459
5801
|
debugJson(logger, "Translated Anthropic response:", anthropicResponse);
|
|
5460
5802
|
return c.json(anthropicResponse);
|
|
@@ -5474,7 +5816,10 @@ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
|
|
|
5474
5816
|
if (rawEvent.data === "[DONE]") break;
|
|
5475
5817
|
if (!rawEvent.data) continue;
|
|
5476
5818
|
const chunk = JSON.parse(rawEvent.data);
|
|
5477
|
-
if (chunk.usage) usage =
|
|
5819
|
+
if (chunk.usage || chunk.copilot_usage) usage = {
|
|
5820
|
+
...normalizeOpenAIUsage(chunk.usage),
|
|
5821
|
+
total_nano_aiu: normalizeOptionalToken(chunk.copilot_usage?.total_nano_aiu)
|
|
5822
|
+
};
|
|
5478
5823
|
const events = translateChunkToAnthropicEvents(chunk, streamState);
|
|
5479
5824
|
for (const event of events) {
|
|
5480
5825
|
const eventData = JSON.stringify(event);
|
|
@@ -5533,7 +5878,10 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
|
|
|
5533
5878
|
if (!data) continue;
|
|
5534
5879
|
debugLazy(logger, () => ["Responses raw stream event:", data]);
|
|
5535
5880
|
const responseEvent = JSON.parse(data);
|
|
5536
|
-
if (responseEvent.type === "response.completed" || responseEvent.type === "response.failed" || responseEvent.type === "response.incomplete") usage =
|
|
5881
|
+
if (responseEvent.type === "response.completed" || responseEvent.type === "response.failed" || responseEvent.type === "response.incomplete") usage = {
|
|
5882
|
+
...normalizeResponsesUsage(responseEvent.response.usage),
|
|
5883
|
+
total_nano_aiu: normalizeOptionalToken(responseEvent.copilot_usage?.total_nano_aiu)
|
|
5884
|
+
};
|
|
5537
5885
|
const events = translateResponsesStreamEvent(responseEvent, streamState);
|
|
5538
5886
|
for (const event of events) {
|
|
5539
5887
|
const eventData = JSON.stringify(event);
|
|
@@ -5559,12 +5907,13 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
|
|
|
5559
5907
|
recordUsage(usage);
|
|
5560
5908
|
});
|
|
5561
5909
|
}
|
|
5562
|
-
|
|
5563
|
-
value: response,
|
|
5564
|
-
tailLength: 400
|
|
5565
|
-
});
|
|
5910
|
+
debugJson(logger, "Non-streaming Responses result:", response);
|
|
5566
5911
|
const anthropicResponse = translateResponsesResultToAnthropic(response, { toolSearchName: resolveBridgeToolSearchName(anthropicPayload.tools) });
|
|
5567
|
-
|
|
5912
|
+
const responsesResult = response;
|
|
5913
|
+
recordUsage({
|
|
5914
|
+
...normalizeResponsesUsage(responsesResult.usage),
|
|
5915
|
+
total_nano_aiu: normalizeOptionalToken(responsesResult.copilot_usage?.total_nano_aiu)
|
|
5916
|
+
});
|
|
5568
5917
|
debugJson(logger, "Translated Anthropic response:", anthropicResponse);
|
|
5569
5918
|
return c.json(anthropicResponse);
|
|
5570
5919
|
};
|
|
@@ -5650,7 +5999,7 @@ const parseAnthropicStreamEvent = (data) => {
|
|
|
5650
5999
|
};
|
|
5651
6000
|
//#endregion
|
|
5652
6001
|
//#region src/routes/messages/handler.ts
|
|
5653
|
-
const logger$
|
|
6002
|
+
const logger$5 = createHandlerLogger("messages-handler");
|
|
5654
6003
|
const messagesFlowHandlers = {
|
|
5655
6004
|
handleWithChatCompletions,
|
|
5656
6005
|
handleWithMessagesApi,
|
|
@@ -5662,7 +6011,7 @@ async function handleCompletion(c) {
|
|
|
5662
6011
|
anthropicPayload.model = resolveMappedModel(anthropicPayload.model);
|
|
5663
6012
|
if (anthropicPayload.model !== requestedModel) consola.debug(`Resolved model mapping: ${requestedModel} -> ${anthropicPayload.model}`);
|
|
5664
6013
|
const webSearchResult = await tryHandleWebSearch(c, anthropicPayload, {
|
|
5665
|
-
logger: logger$
|
|
6014
|
+
logger: logger$5,
|
|
5666
6015
|
forwardToProvider: (ctx, payload, provider) => handleProviderMessagesForProvider(ctx, {
|
|
5667
6016
|
payload,
|
|
5668
6017
|
provider
|
|
@@ -5677,19 +6026,19 @@ async function handleCompletion(c) {
|
|
|
5677
6026
|
provider: providerModelAlias.provider
|
|
5678
6027
|
});
|
|
5679
6028
|
}
|
|
5680
|
-
debugJson(logger$
|
|
6029
|
+
debugJson(logger$5, "Anthropic request payload:", anthropicPayload);
|
|
5681
6030
|
normalizeSystemMessages(anthropicPayload);
|
|
5682
6031
|
await checkRateLimit(state);
|
|
5683
6032
|
sanitizeIdeTools(anthropicPayload);
|
|
5684
6033
|
const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
|
|
5685
|
-
if (subagentMarker) debugJson(logger$
|
|
6034
|
+
if (subagentMarker) debugJson(logger$5, "Detected Subagent marker:", subagentMarker);
|
|
5686
6035
|
let sessionId = getRootSessionId(anthropicPayload, c);
|
|
5687
6036
|
const compactType = getCompactType(anthropicPayload);
|
|
5688
6037
|
const anthropicBeta = c.req.header("anthropic-beta");
|
|
5689
|
-
logger$
|
|
6038
|
+
logger$5.debug("Anthropic Beta header:", anthropicBeta);
|
|
5690
6039
|
const noTools = !anthropicPayload.tools || anthropicPayload.tools.length === 0;
|
|
5691
6040
|
if (anthropicBeta && noTools && compactType === 0) anthropicPayload.model = getSmallModel();
|
|
5692
|
-
if (compactType) logger$
|
|
6041
|
+
if (compactType) logger$5.debug("Compact request type:", compactType);
|
|
5693
6042
|
if (!state.tokenBasedBilling) {
|
|
5694
6043
|
const lastMessageCacheControl = getLastMessageContentCacheControl(anthropicPayload.messages.at(-1));
|
|
5695
6044
|
stripToolReferenceTurnBoundary(anthropicPayload);
|
|
@@ -5697,9 +6046,9 @@ async function handleCompletion(c) {
|
|
|
5697
6046
|
applyLastMessageCacheControl(anthropicPayload, lastMessageCacheControl);
|
|
5698
6047
|
}
|
|
5699
6048
|
const requestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
|
|
5700
|
-
logger$
|
|
6049
|
+
logger$5.debug("Generated request ID:", requestId);
|
|
5701
6050
|
if (!sessionId) sessionId = getUUID(requestId);
|
|
5702
|
-
logger$
|
|
6051
|
+
logger$5.debug("Extracted session ID:", sessionId);
|
|
5703
6052
|
if (state.manualApprove) await awaitApproval();
|
|
5704
6053
|
const selectedModel = findEndpointModel(anthropicPayload.model);
|
|
5705
6054
|
anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
|
|
@@ -5710,7 +6059,7 @@ async function handleCompletion(c) {
|
|
|
5710
6059
|
requestId,
|
|
5711
6060
|
sessionId,
|
|
5712
6061
|
compactType,
|
|
5713
|
-
logger: logger$
|
|
6062
|
+
logger: logger$5
|
|
5714
6063
|
});
|
|
5715
6064
|
if (shouldUseResponsesApi(selectedModel, compactType)) return await messagesFlowHandlers.handleWithResponsesApi(c, anthropicPayload, {
|
|
5716
6065
|
subagentMarker,
|
|
@@ -5718,7 +6067,7 @@ async function handleCompletion(c) {
|
|
|
5718
6067
|
requestId,
|
|
5719
6068
|
sessionId,
|
|
5720
6069
|
compactType,
|
|
5721
|
-
logger: logger$
|
|
6070
|
+
logger: logger$5
|
|
5722
6071
|
});
|
|
5723
6072
|
return await messagesFlowHandlers.handleWithChatCompletions(c, anthropicPayload, {
|
|
5724
6073
|
subagentMarker,
|
|
@@ -5726,7 +6075,7 @@ async function handleCompletion(c) {
|
|
|
5726
6075
|
requestId,
|
|
5727
6076
|
sessionId,
|
|
5728
6077
|
compactType,
|
|
5729
|
-
logger: logger$
|
|
6078
|
+
logger: logger$5
|
|
5730
6079
|
});
|
|
5731
6080
|
}
|
|
5732
6081
|
const MESSAGES_ENDPOINT = "/v1/messages";
|
|
@@ -5757,24 +6106,89 @@ messageRoutes.post("/count_tokens", async (c) => {
|
|
|
5757
6106
|
//#endregion
|
|
5758
6107
|
//#region src/routes/models/route.ts
|
|
5759
6108
|
const modelRoutes = new Hono();
|
|
5760
|
-
|
|
6109
|
+
const logger$4 = createHandlerLogger("models-handler");
|
|
6110
|
+
const EPOCH_ISO = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
6111
|
+
function isRecord(value) {
|
|
6112
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6113
|
+
}
|
|
6114
|
+
function normalizeCopilotModel(model) {
|
|
6115
|
+
const contextWindow = model.capabilities?.limits?.max_context_window_tokens ?? 0;
|
|
6116
|
+
const clientId = toClientModelId(model.id);
|
|
6117
|
+
return {
|
|
6118
|
+
claude_model_id: contextWindow >= 1e6 ? `${clientId}[1m]` : clientId,
|
|
6119
|
+
...model,
|
|
6120
|
+
id: clientId,
|
|
6121
|
+
object: "model",
|
|
6122
|
+
type: "model",
|
|
6123
|
+
created: 0,
|
|
6124
|
+
created_at: EPOCH_ISO,
|
|
6125
|
+
owned_by: model.vendor,
|
|
6126
|
+
display_name: model.name
|
|
6127
|
+
};
|
|
6128
|
+
}
|
|
6129
|
+
function getStringField(model, field) {
|
|
6130
|
+
const value = model[field];
|
|
6131
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
6132
|
+
}
|
|
6133
|
+
function normalizeProviderModel(provider, model) {
|
|
6134
|
+
if (!isRecord(model)) return null;
|
|
6135
|
+
const rawId = getStringField(model, "id");
|
|
6136
|
+
if (!rawId) return null;
|
|
6137
|
+
const id = `${provider}/${rawId}`;
|
|
6138
|
+
const name = getStringField(model, "display_name") ?? getStringField(model, "name") ?? rawId;
|
|
6139
|
+
const ownedBy = getStringField(model, "owned_by") ?? getStringField(model, "vendor") ?? provider;
|
|
6140
|
+
return {
|
|
6141
|
+
...model,
|
|
6142
|
+
id,
|
|
6143
|
+
object: getStringField(model, "object") ?? "model",
|
|
6144
|
+
type: getStringField(model, "type") ?? "model",
|
|
6145
|
+
created: typeof model.created === "number" ? model.created : 0,
|
|
6146
|
+
created_at: getStringField(model, "created_at") ?? EPOCH_ISO,
|
|
6147
|
+
owned_by: ownedBy,
|
|
6148
|
+
display_name: name
|
|
6149
|
+
};
|
|
6150
|
+
}
|
|
6151
|
+
async function getProviderModels(provider, requestHeaders) {
|
|
5761
6152
|
try {
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
6153
|
+
const providerConfig = await resolveProviderConfig(provider);
|
|
6154
|
+
if (!providerConfig) return [];
|
|
6155
|
+
if (providerConfig.name === "codex") return getModels().data.map((model) => normalizeProviderModel(providerConfig.name, model)).filter((model) => model !== null);
|
|
6156
|
+
const response = await forwardProviderModels(providerConfig, requestHeaders);
|
|
6157
|
+
if (!response.ok) {
|
|
6158
|
+
logger$4.warn("models.provider.skip_non_ok", {
|
|
6159
|
+
provider,
|
|
6160
|
+
statusCode: response.status
|
|
6161
|
+
});
|
|
6162
|
+
return [];
|
|
6163
|
+
}
|
|
6164
|
+
const body = await response.json();
|
|
6165
|
+
if (!isRecord(body) || !Array.isArray(body.data)) {
|
|
6166
|
+
logger$4.warn("models.provider.skip_invalid_body", { provider });
|
|
6167
|
+
return [];
|
|
6168
|
+
}
|
|
6169
|
+
return body.data.map((model) => normalizeProviderModel(providerConfig.name, model)).filter((model) => model !== null);
|
|
6170
|
+
} catch (error) {
|
|
6171
|
+
logger$4.warn("models.provider.skip_error", {
|
|
6172
|
+
provider,
|
|
6173
|
+
error
|
|
5777
6174
|
});
|
|
6175
|
+
return [];
|
|
6176
|
+
}
|
|
6177
|
+
}
|
|
6178
|
+
async function getAggregatedModels(requestHeaders) {
|
|
6179
|
+
const copilotModels = state.models?.data.map(normalizeCopilotModel) ?? [];
|
|
6180
|
+
const providerModelsByProvider = await Promise.all(listEnabledProviders().map((provider) => getProviderModels(provider, requestHeaders)));
|
|
6181
|
+
const models = [...copilotModels, ...providerModelsByProvider.flat()];
|
|
6182
|
+
const seenModelIds = /* @__PURE__ */ new Set();
|
|
6183
|
+
return models.filter((model) => {
|
|
6184
|
+
if (seenModelIds.has(model.id)) return false;
|
|
6185
|
+
seenModelIds.add(model.id);
|
|
6186
|
+
return true;
|
|
6187
|
+
});
|
|
6188
|
+
}
|
|
6189
|
+
modelRoutes.get("/", async (c) => {
|
|
6190
|
+
try {
|
|
6191
|
+
const models = await getAggregatedModels(c.req.raw.headers);
|
|
5778
6192
|
return c.json({
|
|
5779
6193
|
object: "list",
|
|
5780
6194
|
data: models,
|
|
@@ -5856,9 +6270,10 @@ async function handleProviderResponsesForProvider(c, options) {
|
|
|
5856
6270
|
provider
|
|
5857
6271
|
});
|
|
5858
6272
|
compactInputByLatestCompaction(payload);
|
|
6273
|
+
const modelConfig = providerConfig.models?.[payload.model];
|
|
5859
6274
|
if (providerConfig.name === "codex") {
|
|
5860
6275
|
const upstreamResponse = await forwardCodexResponses(payload, c.req.raw.headers, providerConfig.baseUrl);
|
|
5861
|
-
const recordUsage = createProviderResponsesUsageRecorder(payload, provider);
|
|
6276
|
+
const recordUsage = createProviderResponsesUsageRecorder(payload, provider, modelConfig, providerConfig.pricingCurrency);
|
|
5862
6277
|
if (payload.stream && isResponsesStream(upstreamResponse)) return streamProviderResponses(c, upstreamResponse, {
|
|
5863
6278
|
normalizeCodex: true,
|
|
5864
6279
|
provider,
|
|
@@ -5870,7 +6285,7 @@ async function handleProviderResponsesForProvider(c, options) {
|
|
|
5870
6285
|
}
|
|
5871
6286
|
const upstreamResponse = await forwardProviderResponses(providerConfig, payload, c.req.raw.headers);
|
|
5872
6287
|
if (!upstreamResponse.ok) throw new HTTPError(`Failed to create ${provider} responses`, upstreamResponse);
|
|
5873
|
-
const recordUsage = createProviderResponsesUsageRecorder(payload, provider);
|
|
6288
|
+
const recordUsage = createProviderResponsesUsageRecorder(payload, provider, modelConfig, providerConfig.pricingCurrency);
|
|
5874
6289
|
if (payload.stream) return streamProviderResponses(c, getResponsesEvents(upstreamResponse), {
|
|
5875
6290
|
normalizeCodex: false,
|
|
5876
6291
|
provider,
|
|
@@ -5879,11 +6294,13 @@ async function handleProviderResponsesForProvider(c, options) {
|
|
|
5879
6294
|
recordUsage(normalizeResponsesUsage((await upstreamResponse.clone().json()).usage));
|
|
5880
6295
|
return createProviderProxyResponse(upstreamResponse);
|
|
5881
6296
|
}
|
|
5882
|
-
const createProviderResponsesUsageRecorder = (payload, provider) => {
|
|
6297
|
+
const createProviderResponsesUsageRecorder = (payload, provider, modelConfig, pricingCurrency) => {
|
|
5883
6298
|
const sessionAffinity = requestContext.getStore()?.sessionAffinity?.trim() || null;
|
|
5884
6299
|
return createProviderTokenUsageRecorder({
|
|
5885
6300
|
endpoint: "responses",
|
|
5886
6301
|
model: payload.model,
|
|
6302
|
+
pricing: modelConfig?.pricing,
|
|
6303
|
+
pricingCurrency,
|
|
5887
6304
|
providerName: provider,
|
|
5888
6305
|
sessionId: sessionAffinity ?? ""
|
|
5889
6306
|
});
|
|
@@ -6068,7 +6485,10 @@ const handleResponses = async (c) => {
|
|
|
6068
6485
|
for await (const chunk of response) {
|
|
6069
6486
|
debugJson(logger$1, "Responses stream chunk:", chunk);
|
|
6070
6487
|
const parsedEvent = parseResponsesStreamEvent(chunk);
|
|
6071
|
-
if (parsedEvent?.type === "response.completed" || parsedEvent?.type === "response.failed" || parsedEvent?.type === "response.incomplete") usage =
|
|
6488
|
+
if (parsedEvent?.type === "response.completed" || parsedEvent?.type === "response.failed" || parsedEvent?.type === "response.incomplete") usage = {
|
|
6489
|
+
...normalizeResponsesUsage(parsedEvent.response.usage),
|
|
6490
|
+
total_nano_aiu: normalizeOptionalToken(parsedEvent.copilot_usage?.total_nano_aiu)
|
|
6491
|
+
};
|
|
6072
6492
|
const processedData = fixStreamIds(chunk.data ?? "", chunk.event, idTracker);
|
|
6073
6493
|
await stream.writeSSE({
|
|
6074
6494
|
id: chunk.id,
|
|
@@ -6083,8 +6503,12 @@ const handleResponses = async (c) => {
|
|
|
6083
6503
|
value: response,
|
|
6084
6504
|
tailLength: 400
|
|
6085
6505
|
});
|
|
6086
|
-
|
|
6087
|
-
|
|
6506
|
+
const result = response;
|
|
6507
|
+
recordUsage({
|
|
6508
|
+
...normalizeResponsesUsage(result.usage),
|
|
6509
|
+
total_nano_aiu: normalizeOptionalToken(result.copilot_usage?.total_nano_aiu)
|
|
6510
|
+
});
|
|
6511
|
+
return c.json(result);
|
|
6088
6512
|
};
|
|
6089
6513
|
const isAsyncIterable = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
|
|
6090
6514
|
const isStreamingRequested = (payload) => Boolean(payload.stream);
|
|
@@ -6254,4 +6678,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
|
|
|
6254
6678
|
//#endregion
|
|
6255
6679
|
export { server };
|
|
6256
6680
|
|
|
6257
|
-
//# sourceMappingURL=server-
|
|
6681
|
+
//# sourceMappingURL=server-s_0_JChu.js.map
|