@jeffreycao/copilot-api 1.12.9 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -28
- package/README.zh-CN.md +71 -28
- package/dist/auth-BwQ7Vhzt.js +2 -0
- package/dist/{auth-15xzL-eW.js → auth-DcYySZhC.js} +14 -4
- package/dist/auth-DcYySZhC.js.map +1 -0
- package/dist/{config-B71_S_hQ.js → config-CQxppJtD.js} +5 -1
- package/dist/config-CQxppJtD.js.map +1 -0
- package/dist/{debug-TyT2u9dt.js → debug-IUKehQot.js} +2 -2
- package/dist/{debug-TyT2u9dt.js.map → debug-IUKehQot.js.map} +1 -1
- package/dist/main.js +3 -5
- package/dist/main.js.map +1 -1
- package/dist/{server-34rnRg4k.js → server-7U9OZLf0.js} +450 -92
- package/dist/server-7U9OZLf0.js.map +1 -0
- package/dist/{start-8y_02ZHG.js → start-Dq2b9vPm.js} +68 -57
- package/dist/start-Dq2b9vPm.js.map +1 -0
- package/dist/{token-fpw8tAQS.js → token-CFArcYwb.js} +8 -6
- package/dist/token-CFArcYwb.js.map +1 -0
- package/package.json +1 -1
- package/pages/index.html +68 -14
- 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 { C as setModelMappings, S as resolveMappedModel, T as PATHS, _ as isResponsesApiWebSocketEnabled, a as getExtraPromptForModel, c as getModelResponsesApiCompactThreshold$1, d as getReasoningEffortForModel, f as getSmallModel, g as isResponsesApiWebSearchEnabled, h as isResponsesApiContextManagementEnabled, i as getConfig, l as getProviderConfig, m as isMessagesApiEnabled, n as getAnthropicApiKey, o as getMessageApiWebSearchModel, r as getClaudeTokenMultiplier, s as getModelMappings, u as getRawProviderConfig } from "./config-
|
|
2
|
-
import { C as
|
|
1
|
+
import { C as setModelMappings, S as resolveMappedModel, T as PATHS, _ as isResponsesApiWebSocketEnabled, a as getExtraPromptForModel, c as getModelResponsesApiCompactThreshold$1, d as getReasoningEffortForModel, f as getSmallModel, g as isResponsesApiWebSearchEnabled, h as isResponsesApiContextManagementEnabled, i as getConfig, l as getProviderConfig, m as isMessagesApiEnabled, n as getAnthropicApiKey, o as getMessageApiWebSearchModel, r as getClaudeTokenMultiplier, s as getModelMappings, u as getRawProviderConfig } from "./config-CQxppJtD.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-CFArcYwb.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)
|
|
@@ -1128,7 +1421,7 @@ async function handleProviderChatCompletionsForProvider(c, options) {
|
|
|
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,
|
|
@@ -1154,9 +1447,11 @@ 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) => {
|
|
@@ -1336,7 +1631,10 @@ async function handleCompletion$1(c) {
|
|
|
1336
1631
|
});
|
|
1337
1632
|
if (isNonStreaming$1(response)) {
|
|
1338
1633
|
debugJson(logger$7, "Non-streaming response:", response);
|
|
1339
|
-
recordUsage(
|
|
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
1640
|
logger$7.debug("Streaming response");
|
|
@@ -1345,7 +1643,10 @@ async function handleCompletion$1(c) {
|
|
|
1345
1643
|
for await (const chunk of response) {
|
|
1346
1644
|
debugJson(logger$7, "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);
|
|
@@ -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({
|
|
@@ -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
|
|
@@ -4926,13 +5239,17 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
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) {
|
|
@@ -4944,7 +5261,7 @@ 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;
|
|
@@ -4963,12 +5280,16 @@ const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
|
|
|
4963
5280
|
upstreamResponse,
|
|
4964
5281
|
logger: logger$5
|
|
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
|
}
|
|
@@ -4987,17 +5308,21 @@ const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
|
|
|
4987
5308
|
upstreamResponse: events(upstreamResponse),
|
|
4988
5309
|
logger: logger$5
|
|
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);
|
|
@@ -5010,14 +5335,18 @@ 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
|
});
|
|
@@ -5029,14 +5358,18 @@ const handleOpenAIResponsesProviderMessages = async (c, options) => {
|
|
|
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
|
});
|
|
@@ -5083,13 +5416,17 @@ const handleOpenAICompatibleProviderMessages = async (c, options) => {
|
|
|
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,9 +5495,9 @@ 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 }) => {
|
|
5498
|
+
const streamProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, upstreamResponse }) => {
|
|
5162
5499
|
logger$5.debug("provider.messages.streaming");
|
|
5163
|
-
const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
|
|
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)) {
|
|
@@ -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 }) => {
|
|
5529
|
+
const streamOpenAICompatibleProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, upstreamResponse }) => {
|
|
5193
5530
|
logger$5.debug("provider.messages.openai_compatible.streaming");
|
|
5194
|
-
const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
|
|
5531
|
+
const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency);
|
|
5195
5532
|
return streamSSE(c, async (stream) => {
|
|
5196
5533
|
let usage = {};
|
|
5197
5534
|
const streamState = {
|
|
@@ -5238,9 +5575,9 @@ const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstream
|
|
|
5238
5575
|
recordUsage(usage);
|
|
5239
5576
|
});
|
|
5240
5577
|
};
|
|
5241
|
-
const streamResponsesProviderMessages = ({ c, payload, provider, providerConfig, upstreamResponse }) => {
|
|
5578
|
+
const streamResponsesProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, providerConfig, upstreamResponse }) => {
|
|
5242
5579
|
logger$5.debug("provider.messages.responses.streaming", { provider });
|
|
5243
|
-
const recordUsage = createProviderMessagesUsageRecorder(payload, 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) });
|
|
@@ -5333,29 +5670,29 @@ 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));
|
|
5673
|
+
const { body, modelConfig, payload, pricingCurrency, provider } = options;
|
|
5674
|
+
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeAnthropicUsage(body.usage));
|
|
5338
5675
|
debugJson(logger$5, "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
5682
|
debugJson(logger$5, "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
5689
|
debugJson(logger$5, "provider.messages.responses.no_stream result:", anthropicResponse);
|
|
5353
5690
|
if (providerConfig.name === "codex") logger$5.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
5697
|
logger$5.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);
|
|
@@ -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
|
};
|
|
@@ -5759,7 +6108,6 @@ messageRoutes.post("/count_tokens", async (c) => {
|
|
|
5759
6108
|
const modelRoutes = new Hono();
|
|
5760
6109
|
modelRoutes.get("/", async (c) => {
|
|
5761
6110
|
try {
|
|
5762
|
-
if (!state.models) await cacheModels();
|
|
5763
6111
|
const models = state.models?.data.map((model) => {
|
|
5764
6112
|
const contextWindow = model.capabilities?.limits?.max_context_window_tokens ?? 0;
|
|
5765
6113
|
const clientId = toClientModelId(model.id);
|
|
@@ -5856,9 +6204,10 @@ async function handleProviderResponsesForProvider(c, options) {
|
|
|
5856
6204
|
provider
|
|
5857
6205
|
});
|
|
5858
6206
|
compactInputByLatestCompaction(payload);
|
|
6207
|
+
const modelConfig = providerConfig.models?.[payload.model];
|
|
5859
6208
|
if (providerConfig.name === "codex") {
|
|
5860
6209
|
const upstreamResponse = await forwardCodexResponses(payload, c.req.raw.headers, providerConfig.baseUrl);
|
|
5861
|
-
const recordUsage = createProviderResponsesUsageRecorder(payload, provider);
|
|
6210
|
+
const recordUsage = createProviderResponsesUsageRecorder(payload, provider, modelConfig, providerConfig.pricingCurrency);
|
|
5862
6211
|
if (payload.stream && isResponsesStream(upstreamResponse)) return streamProviderResponses(c, upstreamResponse, {
|
|
5863
6212
|
normalizeCodex: true,
|
|
5864
6213
|
provider,
|
|
@@ -5870,7 +6219,7 @@ async function handleProviderResponsesForProvider(c, options) {
|
|
|
5870
6219
|
}
|
|
5871
6220
|
const upstreamResponse = await forwardProviderResponses(providerConfig, payload, c.req.raw.headers);
|
|
5872
6221
|
if (!upstreamResponse.ok) throw new HTTPError(`Failed to create ${provider} responses`, upstreamResponse);
|
|
5873
|
-
const recordUsage = createProviderResponsesUsageRecorder(payload, provider);
|
|
6222
|
+
const recordUsage = createProviderResponsesUsageRecorder(payload, provider, modelConfig, providerConfig.pricingCurrency);
|
|
5874
6223
|
if (payload.stream) return streamProviderResponses(c, getResponsesEvents(upstreamResponse), {
|
|
5875
6224
|
normalizeCodex: false,
|
|
5876
6225
|
provider,
|
|
@@ -5879,11 +6228,13 @@ async function handleProviderResponsesForProvider(c, options) {
|
|
|
5879
6228
|
recordUsage(normalizeResponsesUsage((await upstreamResponse.clone().json()).usage));
|
|
5880
6229
|
return createProviderProxyResponse(upstreamResponse);
|
|
5881
6230
|
}
|
|
5882
|
-
const createProviderResponsesUsageRecorder = (payload, provider) => {
|
|
6231
|
+
const createProviderResponsesUsageRecorder = (payload, provider, modelConfig, pricingCurrency) => {
|
|
5883
6232
|
const sessionAffinity = requestContext.getStore()?.sessionAffinity?.trim() || null;
|
|
5884
6233
|
return createProviderTokenUsageRecorder({
|
|
5885
6234
|
endpoint: "responses",
|
|
5886
6235
|
model: payload.model,
|
|
6236
|
+
pricing: modelConfig?.pricing,
|
|
6237
|
+
pricingCurrency,
|
|
5887
6238
|
providerName: provider,
|
|
5888
6239
|
sessionId: sessionAffinity ?? ""
|
|
5889
6240
|
});
|
|
@@ -6068,7 +6419,10 @@ const handleResponses = async (c) => {
|
|
|
6068
6419
|
for await (const chunk of response) {
|
|
6069
6420
|
debugJson(logger$1, "Responses stream chunk:", chunk);
|
|
6070
6421
|
const parsedEvent = parseResponsesStreamEvent(chunk);
|
|
6071
|
-
if (parsedEvent?.type === "response.completed" || parsedEvent?.type === "response.failed" || parsedEvent?.type === "response.incomplete") usage =
|
|
6422
|
+
if (parsedEvent?.type === "response.completed" || parsedEvent?.type === "response.failed" || parsedEvent?.type === "response.incomplete") usage = {
|
|
6423
|
+
...normalizeResponsesUsage(parsedEvent.response.usage),
|
|
6424
|
+
total_nano_aiu: normalizeOptionalToken(parsedEvent.copilot_usage?.total_nano_aiu)
|
|
6425
|
+
};
|
|
6072
6426
|
const processedData = fixStreamIds(chunk.data ?? "", chunk.event, idTracker);
|
|
6073
6427
|
await stream.writeSSE({
|
|
6074
6428
|
id: chunk.id,
|
|
@@ -6083,8 +6437,12 @@ const handleResponses = async (c) => {
|
|
|
6083
6437
|
value: response,
|
|
6084
6438
|
tailLength: 400
|
|
6085
6439
|
});
|
|
6086
|
-
|
|
6087
|
-
|
|
6440
|
+
const result = response;
|
|
6441
|
+
recordUsage({
|
|
6442
|
+
...normalizeResponsesUsage(result.usage),
|
|
6443
|
+
total_nano_aiu: normalizeOptionalToken(result.copilot_usage?.total_nano_aiu)
|
|
6444
|
+
});
|
|
6445
|
+
return c.json(result);
|
|
6088
6446
|
};
|
|
6089
6447
|
const isAsyncIterable = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
|
|
6090
6448
|
const isStreamingRequested = (payload) => Boolean(payload.stream);
|
|
@@ -6254,4 +6612,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
|
|
|
6254
6612
|
//#endregion
|
|
6255
6613
|
export { server };
|
|
6256
6614
|
|
|
6257
|
-
//# sourceMappingURL=server-
|
|
6615
|
+
//# sourceMappingURL=server-7U9OZLf0.js.map
|