@openhoo/hoopilot 0.7.3 → 0.7.5
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 +1 -1
- package/dist/cli.js +152 -36
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +215 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +215 -55
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -399,22 +399,31 @@ function normalizeCopilotUsage(body) {
|
|
|
399
399
|
}
|
|
400
400
|
function normalizeQuotaDetail(detail) {
|
|
401
401
|
const entitlement = numberOrUndefined(detail.entitlement);
|
|
402
|
+
const overageCount = numberOrUndefined(detail.overage_count);
|
|
402
403
|
const remaining = numberOrUndefined(detail.remaining) ?? numberOrUndefined(detail.quota_remaining);
|
|
403
404
|
return removeUndefinedQuota({
|
|
404
405
|
entitlement,
|
|
405
|
-
|
|
406
|
+
hasQuota: typeof detail.has_quota === "boolean" ? detail.has_quota : void 0,
|
|
407
|
+
overageCount,
|
|
408
|
+
overageEntitlement: numberOrUndefined(detail.overage_entitlement),
|
|
406
409
|
overagePermitted: typeof detail.overage_permitted === "boolean" ? detail.overage_permitted : void 0,
|
|
407
410
|
percentRemaining: numberOrUndefined(detail.percent_remaining),
|
|
411
|
+
quotaId: stringOrUndefined(detail.quota_id),
|
|
412
|
+
quotaResetAt: stringOrUndefined(detail.quota_reset_at),
|
|
408
413
|
remaining,
|
|
414
|
+
timestampUtc: stringOrUndefined(detail.timestamp_utc),
|
|
415
|
+
tokenBasedBilling: typeof detail.token_based_billing === "boolean" ? detail.token_based_billing : void 0,
|
|
409
416
|
unlimited: typeof detail.unlimited === "boolean" ? detail.unlimited : void 0,
|
|
410
|
-
used: usedFrom(entitlement, remaining)
|
|
417
|
+
used: usedFrom(entitlement, remaining, overageCount)
|
|
411
418
|
});
|
|
412
419
|
}
|
|
413
|
-
function usedFrom(entitlement, remaining) {
|
|
420
|
+
function usedFrom(entitlement, remaining, overageCount) {
|
|
414
421
|
if (entitlement === void 0 || remaining === void 0) {
|
|
415
422
|
return void 0;
|
|
416
423
|
}
|
|
417
|
-
|
|
424
|
+
const base = entitlement - remaining;
|
|
425
|
+
const overage = remaining === 0 ? overageCount ?? 0 : 0;
|
|
426
|
+
return Math.max(0, base + overage);
|
|
418
427
|
}
|
|
419
428
|
function numberOrUndefined(value) {
|
|
420
429
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
@@ -677,6 +686,12 @@ function isLogLevel(value) {
|
|
|
677
686
|
|
|
678
687
|
// src/openai.ts
|
|
679
688
|
var DEFAULT_MODEL = "gpt-4.1";
|
|
689
|
+
var OpenAICompatibilityError = class extends Error {
|
|
690
|
+
constructor(message) {
|
|
691
|
+
super(message);
|
|
692
|
+
this.name = "OpenAICompatibilityError";
|
|
693
|
+
}
|
|
694
|
+
};
|
|
680
695
|
function responsesRequestToChatCompletion(request) {
|
|
681
696
|
const messages = [];
|
|
682
697
|
const instructions = contentToText(request.instructions);
|
|
@@ -710,13 +725,22 @@ function normalizeChatCompletionRequest(request) {
|
|
|
710
725
|
});
|
|
711
726
|
}
|
|
712
727
|
function completionsRequestToChatCompletion(request) {
|
|
728
|
+
assertSupportedLegacyCompletionRequest(request);
|
|
713
729
|
return removeUndefined({
|
|
730
|
+
frequency_penalty: request.frequency_penalty,
|
|
731
|
+
logit_bias: request.logit_bias,
|
|
714
732
|
max_tokens: request.max_tokens,
|
|
715
|
-
messages: [{ content:
|
|
733
|
+
messages: [{ content: legacyPromptToText(request.prompt), role: "user" }],
|
|
716
734
|
model: normalizeRequestedModel(request.model),
|
|
735
|
+
n: request.n,
|
|
736
|
+
presence_penalty: request.presence_penalty,
|
|
737
|
+
seed: request.seed,
|
|
738
|
+
stop: request.stop,
|
|
717
739
|
stream: request.stream === true,
|
|
740
|
+
stream_options: request.stream_options,
|
|
718
741
|
temperature: request.temperature,
|
|
719
|
-
top_p: request.top_p
|
|
742
|
+
top_p: request.top_p,
|
|
743
|
+
user: request.user
|
|
720
744
|
});
|
|
721
745
|
}
|
|
722
746
|
function normalizeRequestedModel(model) {
|
|
@@ -752,21 +776,21 @@ function chatCompletionToResponse(completion, responseId) {
|
|
|
752
776
|
});
|
|
753
777
|
}
|
|
754
778
|
function chatCompletionToCompletion(completion) {
|
|
755
|
-
const choice = firstChoice(completion);
|
|
756
|
-
const message = asRecord(choice.message);
|
|
757
779
|
return removeUndefined({
|
|
758
|
-
choices:
|
|
759
|
-
|
|
780
|
+
choices: completionChoices(completion).map((choice, index) => {
|
|
781
|
+
const message = asRecord(choice.message);
|
|
782
|
+
return {
|
|
760
783
|
finish_reason: choice.finish_reason ?? "stop",
|
|
761
|
-
index:
|
|
762
|
-
logprobs: null,
|
|
763
|
-
text: contentToText(message.content)
|
|
764
|
-
}
|
|
765
|
-
|
|
784
|
+
index: typeof choice.index === "number" ? choice.index : index,
|
|
785
|
+
logprobs: choice.logprobs ?? null,
|
|
786
|
+
text: contentToText(choice.text) || contentToText(message.content)
|
|
787
|
+
};
|
|
788
|
+
}),
|
|
766
789
|
created: completion.created ?? epochSeconds(),
|
|
767
790
|
id: completion.id ?? `cmpl_${randomId()}`,
|
|
768
791
|
model: completion.model ?? DEFAULT_MODEL,
|
|
769
792
|
object: "text_completion",
|
|
793
|
+
system_fingerprint: completion.system_fingerprint,
|
|
770
794
|
usage: completion.usage
|
|
771
795
|
});
|
|
772
796
|
}
|
|
@@ -1030,7 +1054,8 @@ function inputToMessages(input) {
|
|
|
1030
1054
|
const messages = [];
|
|
1031
1055
|
for (const item of input) {
|
|
1032
1056
|
const record = asRecord(item);
|
|
1033
|
-
|
|
1057
|
+
const type = contentToText(record.type);
|
|
1058
|
+
if (type === "function_call_output") {
|
|
1034
1059
|
messages.push({
|
|
1035
1060
|
content: contentToText(record.output),
|
|
1036
1061
|
role: "tool",
|
|
@@ -1038,7 +1063,7 @@ function inputToMessages(input) {
|
|
|
1038
1063
|
});
|
|
1039
1064
|
continue;
|
|
1040
1065
|
}
|
|
1041
|
-
if (
|
|
1066
|
+
if (type === "function_call") {
|
|
1042
1067
|
messages.push({
|
|
1043
1068
|
role: "assistant",
|
|
1044
1069
|
tool_calls: [
|
|
@@ -1054,7 +1079,10 @@ function inputToMessages(input) {
|
|
|
1054
1079
|
});
|
|
1055
1080
|
continue;
|
|
1056
1081
|
}
|
|
1057
|
-
|
|
1082
|
+
if (type && type !== "message") {
|
|
1083
|
+
unsupportedResponsesFeature(`input item type "${type}"`);
|
|
1084
|
+
}
|
|
1085
|
+
const role = responsesRoleToChatRole(contentToText(record.role));
|
|
1058
1086
|
const content = chatMessageContent(record.content);
|
|
1059
1087
|
if (role && content !== void 0) {
|
|
1060
1088
|
messages.push({ content, role });
|
|
@@ -1067,7 +1095,10 @@ function chatMessageContent(content) {
|
|
|
1067
1095
|
return content;
|
|
1068
1096
|
}
|
|
1069
1097
|
if (!Array.isArray(content)) {
|
|
1070
|
-
|
|
1098
|
+
if (content === void 0 || content === null) {
|
|
1099
|
+
return void 0;
|
|
1100
|
+
}
|
|
1101
|
+
unsupportedResponsesFeature("non-array message content objects");
|
|
1071
1102
|
}
|
|
1072
1103
|
const parts = [];
|
|
1073
1104
|
for (const part of content) {
|
|
@@ -1075,13 +1106,31 @@ function chatMessageContent(content) {
|
|
|
1075
1106
|
const type = contentToText(record.type);
|
|
1076
1107
|
if (type === "input_text" || type === "output_text" || type === "text") {
|
|
1077
1108
|
parts.push({ text: contentToText(record.text), type: "text" });
|
|
1109
|
+
continue;
|
|
1078
1110
|
}
|
|
1079
1111
|
if (type === "input_image") {
|
|
1112
|
+
if (contentToText(record.file_id)) {
|
|
1113
|
+
unsupportedResponsesFeature("input_image file_id parts");
|
|
1114
|
+
}
|
|
1080
1115
|
const imageUrl = contentToText(record.image_url);
|
|
1081
|
-
if (imageUrl) {
|
|
1082
|
-
|
|
1116
|
+
if (!imageUrl) {
|
|
1117
|
+
unsupportedResponsesFeature("input_image parts without image_url");
|
|
1118
|
+
}
|
|
1119
|
+
const image = { url: imageUrl };
|
|
1120
|
+
const detail = contentToText(record.detail);
|
|
1121
|
+
if (detail) {
|
|
1122
|
+
image.detail = detail;
|
|
1083
1123
|
}
|
|
1124
|
+
parts.push({ image_url: image, type: "image_url" });
|
|
1125
|
+
continue;
|
|
1126
|
+
}
|
|
1127
|
+
if (type === "input_file") {
|
|
1128
|
+
unsupportedResponsesFeature("input_file parts");
|
|
1129
|
+
}
|
|
1130
|
+
if (type === "input_audio") {
|
|
1131
|
+
unsupportedResponsesFeature("input_audio parts");
|
|
1084
1132
|
}
|
|
1133
|
+
unsupportedResponsesFeature(`content part type "${type || "unknown"}"`);
|
|
1085
1134
|
}
|
|
1086
1135
|
if (parts.length === 0) {
|
|
1087
1136
|
return void 0;
|
|
@@ -1091,11 +1140,38 @@ function chatMessageContent(content) {
|
|
|
1091
1140
|
}
|
|
1092
1141
|
return parts;
|
|
1093
1142
|
}
|
|
1094
|
-
function
|
|
1095
|
-
if (
|
|
1096
|
-
return prompt
|
|
1143
|
+
function legacyPromptToText(prompt) {
|
|
1144
|
+
if (typeof prompt === "string") {
|
|
1145
|
+
return prompt;
|
|
1146
|
+
}
|
|
1147
|
+
if (Array.isArray(prompt) && prompt.length === 1 && typeof prompt[0] === "string") {
|
|
1148
|
+
return prompt[0];
|
|
1149
|
+
}
|
|
1150
|
+
throw new OpenAICompatibilityError(
|
|
1151
|
+
"Hoopilot legacy completions compatibility supports exactly one string prompt per request."
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
function assertSupportedLegacyCompletionRequest(request) {
|
|
1155
|
+
if (request.echo === true) {
|
|
1156
|
+
throw new OpenAICompatibilityError(
|
|
1157
|
+
"Hoopilot legacy completions compatibility does not support echo=true."
|
|
1158
|
+
);
|
|
1159
|
+
}
|
|
1160
|
+
if (typeof request.best_of === "number" && request.best_of > 1) {
|
|
1161
|
+
throw new OpenAICompatibilityError(
|
|
1162
|
+
"Hoopilot legacy completions compatibility does not support best_of greater than 1."
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
if (typeof request.logprobs === "number" && request.logprobs > 0) {
|
|
1166
|
+
throw new OpenAICompatibilityError(
|
|
1167
|
+
"Hoopilot legacy completions compatibility does not support legacy logprobs."
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
if (contentToText(request.suffix)) {
|
|
1171
|
+
throw new OpenAICompatibilityError(
|
|
1172
|
+
"Hoopilot legacy completions compatibility does not support suffix."
|
|
1173
|
+
);
|
|
1097
1174
|
}
|
|
1098
|
-
return contentToText(prompt);
|
|
1099
1175
|
}
|
|
1100
1176
|
function contentToText(content) {
|
|
1101
1177
|
if (typeof content === "string") {
|
|
@@ -1119,25 +1195,35 @@ function contentToText(content) {
|
|
|
1119
1195
|
}
|
|
1120
1196
|
return "";
|
|
1121
1197
|
}
|
|
1122
|
-
function
|
|
1123
|
-
if (role
|
|
1198
|
+
function responsesRoleToChatRole(role) {
|
|
1199
|
+
if (!role) {
|
|
1200
|
+
return "user";
|
|
1201
|
+
}
|
|
1202
|
+
if (role === "assistant" || role === "developer" || role === "system" || role === "tool" || role === "user") {
|
|
1124
1203
|
return role === "developer" ? "system" : role;
|
|
1125
1204
|
}
|
|
1126
|
-
|
|
1205
|
+
unsupportedResponsesFeature(`message role "${role}"`);
|
|
1127
1206
|
}
|
|
1128
1207
|
function chatTools(tools) {
|
|
1129
1208
|
if (!Array.isArray(tools)) {
|
|
1130
1209
|
return void 0;
|
|
1131
1210
|
}
|
|
1132
|
-
const converted = tools.map((tool) =>
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1211
|
+
const converted = tools.map((tool) => {
|
|
1212
|
+
const record = asRecord(tool);
|
|
1213
|
+
const type = contentToText(record.type);
|
|
1214
|
+
if (type !== "function") {
|
|
1215
|
+
unsupportedResponsesFeature(`tool type "${type || "unknown"}"`);
|
|
1216
|
+
}
|
|
1217
|
+
return {
|
|
1218
|
+
function: removeUndefined({
|
|
1219
|
+
description: record.description,
|
|
1220
|
+
name: record.name,
|
|
1221
|
+
parameters: record.parameters,
|
|
1222
|
+
strict: record.strict
|
|
1223
|
+
}),
|
|
1224
|
+
type: "function"
|
|
1225
|
+
};
|
|
1226
|
+
});
|
|
1141
1227
|
return converted.length > 0 ? converted : void 0;
|
|
1142
1228
|
}
|
|
1143
1229
|
function chatToolChoice(toolChoice) {
|
|
@@ -1145,10 +1231,16 @@ function chatToolChoice(toolChoice) {
|
|
|
1145
1231
|
return toolChoice;
|
|
1146
1232
|
}
|
|
1147
1233
|
const record = asRecord(toolChoice);
|
|
1148
|
-
|
|
1234
|
+
const type = contentToText(record.type);
|
|
1235
|
+
if (type === "function" && typeof record.name === "string") {
|
|
1149
1236
|
return { function: { name: record.name }, type: "function" };
|
|
1150
1237
|
}
|
|
1151
|
-
|
|
1238
|
+
unsupportedResponsesFeature(`tool_choice type "${type || "unknown"}"`);
|
|
1239
|
+
}
|
|
1240
|
+
function unsupportedResponsesFeature(feature) {
|
|
1241
|
+
throw new OpenAICompatibilityError(
|
|
1242
|
+
`Hoopilot Responses-to-chat compatibility does not support ${feature}.`
|
|
1243
|
+
);
|
|
1152
1244
|
}
|
|
1153
1245
|
function outputItemsFromMessage(message) {
|
|
1154
1246
|
const output = [];
|
|
@@ -1263,8 +1355,11 @@ function firstNumber(...values) {
|
|
|
1263
1355
|
return void 0;
|
|
1264
1356
|
}
|
|
1265
1357
|
function firstChoice(completion) {
|
|
1358
|
+
return completionChoices(completion)[0] ?? {};
|
|
1359
|
+
}
|
|
1360
|
+
function completionChoices(completion) {
|
|
1266
1361
|
const choices = Array.isArray(completion.choices) ? completion.choices : [];
|
|
1267
|
-
return asRecord(
|
|
1362
|
+
return choices.map((choice) => asRecord(choice));
|
|
1268
1363
|
}
|
|
1269
1364
|
function processCompletionSseBlock(block, enqueue, markTerminal) {
|
|
1270
1365
|
let event = "message";
|
|
@@ -1296,25 +1391,28 @@ function processCompletionSseBlock(block, enqueue, markTerminal) {
|
|
|
1296
1391
|
enqueue({ error });
|
|
1297
1392
|
return;
|
|
1298
1393
|
}
|
|
1299
|
-
const
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1394
|
+
const choices = completionChoices(parsed).map((choice, index) => {
|
|
1395
|
+
const delta = asRecord(choice.delta);
|
|
1396
|
+
const text = contentToText(delta.content);
|
|
1397
|
+
const finishReason = choice.finish_reason ?? null;
|
|
1398
|
+
if (!text && finishReason === null) {
|
|
1399
|
+
return void 0;
|
|
1400
|
+
}
|
|
1401
|
+
return {
|
|
1402
|
+
finish_reason: finishReason,
|
|
1403
|
+
index: typeof choice.index === "number" ? choice.index : index,
|
|
1404
|
+
logprobs: choice.logprobs ?? null,
|
|
1405
|
+
text
|
|
1406
|
+
};
|
|
1407
|
+
}).filter((choice) => choice !== void 0);
|
|
1303
1408
|
const usage = asRecord(parsed.usage);
|
|
1304
1409
|
const hasUsage = Object.keys(usage).length > 0;
|
|
1305
|
-
if (
|
|
1410
|
+
if (choices.length === 0 && !hasUsage) {
|
|
1306
1411
|
return;
|
|
1307
1412
|
}
|
|
1308
1413
|
enqueue(
|
|
1309
1414
|
removeUndefined({
|
|
1310
|
-
choices
|
|
1311
|
-
{
|
|
1312
|
-
finish_reason: finishReason,
|
|
1313
|
-
index: typeof choice.index === "number" ? choice.index : 0,
|
|
1314
|
-
logprobs: null,
|
|
1315
|
-
text
|
|
1316
|
-
}
|
|
1317
|
-
] : [],
|
|
1415
|
+
choices,
|
|
1318
1416
|
created: typeof parsed.created === "number" ? parsed.created : epochSeconds(),
|
|
1319
1417
|
id: contentToText(parsed.id) || `cmpl_${randomId()}`,
|
|
1320
1418
|
model: contentToText(parsed.model) || DEFAULT_MODEL,
|
|
@@ -1623,11 +1721,43 @@ var MetricsRegistry = class {
|
|
|
1623
1721
|
gauge("remaining", "Remaining quota for the Copilot category.", (q) => q.remaining);
|
|
1624
1722
|
gauge("entitlement", "Quota entitlement for the Copilot category.", (q) => q.entitlement);
|
|
1625
1723
|
gauge("used", "Used quota (entitlement minus remaining) for the category.", (q) => q.used);
|
|
1724
|
+
gauge("overage_count", "Overage count for the Copilot category.", (q) => q.overageCount);
|
|
1725
|
+
gauge(
|
|
1726
|
+
"overage_entitlement",
|
|
1727
|
+
"Overage entitlement for the Copilot category.",
|
|
1728
|
+
(q) => q.overageEntitlement
|
|
1729
|
+
);
|
|
1626
1730
|
gauge(
|
|
1627
1731
|
"percent_remaining",
|
|
1628
1732
|
"Percent of quota remaining for the Copilot category.",
|
|
1629
1733
|
(q) => q.percentRemaining
|
|
1630
1734
|
);
|
|
1735
|
+
booleanGauge(
|
|
1736
|
+
"unlimited",
|
|
1737
|
+
"Whether the Copilot quota category is unlimited.",
|
|
1738
|
+
(q) => q.unlimited
|
|
1739
|
+
);
|
|
1740
|
+
booleanGauge(
|
|
1741
|
+
"overage_permitted",
|
|
1742
|
+
"Whether overage is permitted for the Copilot category.",
|
|
1743
|
+
(q) => q.overagePermitted
|
|
1744
|
+
);
|
|
1745
|
+
booleanGauge("has_quota", "Whether the Copilot quota category has a quota.", (q) => q.hasQuota);
|
|
1746
|
+
booleanGauge(
|
|
1747
|
+
"token_based_billing",
|
|
1748
|
+
"Whether the Copilot quota category uses token-based billing.",
|
|
1749
|
+
(q) => q.tokenBasedBilling
|
|
1750
|
+
);
|
|
1751
|
+
dateGauge(
|
|
1752
|
+
"category_reset_timestamp_seconds",
|
|
1753
|
+
"Unix epoch of the Copilot category-specific quota reset.",
|
|
1754
|
+
(q) => q.quotaResetAt
|
|
1755
|
+
);
|
|
1756
|
+
dateGauge(
|
|
1757
|
+
"category_snapshot_timestamp_seconds",
|
|
1758
|
+
"Unix epoch of the Copilot category quota snapshot.",
|
|
1759
|
+
(q) => q.timestampUtc
|
|
1760
|
+
);
|
|
1631
1761
|
const resetMs = usage.quotaResetDate ? Date.parse(usage.quotaResetDate) : Number.NaN;
|
|
1632
1762
|
if (Number.isFinite(resetMs)) {
|
|
1633
1763
|
lines.push(
|
|
@@ -1646,6 +1776,30 @@ var MetricsRegistry = class {
|
|
|
1646
1776
|
})} 1`
|
|
1647
1777
|
);
|
|
1648
1778
|
}
|
|
1779
|
+
function booleanGauge(suffix, help, pick) {
|
|
1780
|
+
const present = categories.filter(([, quota]) => pick(quota) !== void 0);
|
|
1781
|
+
if (present.length === 0) {
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
lines.push(`# HELP hoopilot_copilot_quota_${suffix} ${help}`);
|
|
1785
|
+
lines.push(`# TYPE hoopilot_copilot_quota_${suffix} gauge`);
|
|
1786
|
+
for (const [category, quota] of present) {
|
|
1787
|
+
lines.push(
|
|
1788
|
+
`hoopilot_copilot_quota_${suffix}${labels({ category })} ${pick(quota) ? 1 : 0}`
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
function dateGauge(suffix, help, pick) {
|
|
1793
|
+
const present = categories.map(([category, quota]) => [category, Date.parse(pick(quota) ?? "")]).filter(([, timestamp]) => Number.isFinite(timestamp));
|
|
1794
|
+
if (present.length === 0) {
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1797
|
+
lines.push(`# HELP hoopilot_copilot_quota_${suffix} ${help}`);
|
|
1798
|
+
lines.push(`# TYPE hoopilot_copilot_quota_${suffix} gauge`);
|
|
1799
|
+
for (const [category, timestamp] of present) {
|
|
1800
|
+
lines.push(`hoopilot_copilot_quota_${suffix}${labels({ category })} ${timestamp / 1e3}`);
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1649
1803
|
}
|
|
1650
1804
|
};
|
|
1651
1805
|
function observeResponseUsage(response, fallbackModel, onUsage, signal) {
|
|
@@ -1886,6 +2040,12 @@ function createHoopilotHandler(options = {}) {
|
|
|
1886
2040
|
"request body was invalid json"
|
|
1887
2041
|
);
|
|
1888
2042
|
return finish(jsonError(400, "invalid_request_error", message));
|
|
2043
|
+
} else if (error instanceof OpenAICompatibilityError) {
|
|
2044
|
+
requestLogger.warn(
|
|
2045
|
+
{ err: errorDetails(error), event: "http.request.failed" },
|
|
2046
|
+
"request body used unsupported OpenAI compatibility fields"
|
|
2047
|
+
);
|
|
2048
|
+
return finish(jsonError(400, "invalid_request_error", message));
|
|
1889
2049
|
} else if (error instanceof RequestBodyTooLargeError) {
|
|
1890
2050
|
requestLogger.warn(
|
|
1891
2051
|
{ err: errorDetails(error), event: "http.request.failed" },
|
|
@@ -2337,8 +2497,8 @@ function metricsResponse(metrics) {
|
|
|
2337
2497
|
});
|
|
2338
2498
|
}
|
|
2339
2499
|
async function handleUsage(metrics, readUsage, signal) {
|
|
2340
|
-
const proxy = metrics.snapshot();
|
|
2341
2500
|
const { copilot, error } = await readUsage(signal);
|
|
2501
|
+
const proxy = metrics.snapshot();
|
|
2342
2502
|
const body = { copilot: copilot ?? null, object: "usage", proxy };
|
|
2343
2503
|
if (error) {
|
|
2344
2504
|
body.copilot_error = error;
|
|
@@ -2363,10 +2523,10 @@ function createUsageReader(client, metrics, now = Date.now, ttlMs = USAGE_CACHE_
|
|
|
2363
2523
|
metrics.recordCopilotQuota(value);
|
|
2364
2524
|
return { copilot: value };
|
|
2365
2525
|
} catch (error) {
|
|
2366
|
-
metrics.recordUpstream(usagePath, false);
|
|
2367
2526
|
if (error instanceof CopilotAuthError) {
|
|
2368
2527
|
return { error: error.message };
|
|
2369
2528
|
}
|
|
2529
|
+
metrics.recordUpstream(usagePath, false);
|
|
2370
2530
|
return { error: errorMessage(error) };
|
|
2371
2531
|
}
|
|
2372
2532
|
};
|