@eddyskywalker/dsh-chatgpt-subscription 0.12.3 → 0.12.6
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/lib/index.js +837 -216
- package/lib/types/host/claude/adapter.d.ts +50 -0
- package/lib/types/host/claude/adapter.d.ts.map +1 -1
- package/lib/types/host/claude/mapper.d.ts +7 -0
- package/lib/types/host/claude/mapper.d.ts.map +1 -1
- package/lib/types/host/command-code/adapter.d.ts +24 -0
- package/lib/types/host/command-code/adapter.d.ts.map +1 -1
- package/lib/types/host/command-code/mapper.d.ts +44 -0
- package/lib/types/host/command-code/mapper.d.ts.map +1 -1
- package/lib/types/host/common/stream-error.d.ts +93 -0
- package/lib/types/host/common/stream-error.d.ts.map +1 -0
- package/lib/types/host/kimi-code/adapter.d.ts +64 -2
- package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
- package/lib/types/host/kimi-code/mapper.d.ts +26 -0
- package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
- package/lib/types/host/minimax-code/adapter.d.ts.map +1 -1
- package/lib/types/host/minimax-code/mapper.d.ts +39 -0
- package/lib/types/host/minimax-code/mapper.d.ts.map +1 -1
- package/lib/types/host/ollama/adapter.d.ts.map +1 -1
- package/lib/types/host/ollama/types.d.ts +33 -0
- package/lib/types/host/ollama/types.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -791,7 +791,7 @@ function parseListing(payload) {
|
|
|
791
791
|
function parseListingEntry$1(value) {
|
|
792
792
|
const record = asRecord$10(value);
|
|
793
793
|
if (record === void 0) return [];
|
|
794
|
-
const id = asString$
|
|
794
|
+
const id = asString$18(record.slug) ?? asString$18(record.id);
|
|
795
795
|
if (id === void 0) return [];
|
|
796
796
|
const contextWindow = asNumber$4(record.context_window) ?? asNumber$4(record.contextWindow);
|
|
797
797
|
const modalities = parseModalities(record.input_modalities);
|
|
@@ -799,18 +799,18 @@ function parseListingEntry$1(value) {
|
|
|
799
799
|
const fallback = CODEX_MODEL_CATALOG.find((entry) => entry.id === id);
|
|
800
800
|
return [{
|
|
801
801
|
id,
|
|
802
|
-
name: asString$
|
|
802
|
+
name: asString$18(record.display_name) ?? asString$18(record.displayName) ?? fallback?.name ?? id,
|
|
803
803
|
contextWindow: contextWindow !== void 0 && contextWindow > 0 ? contextWindow : null,
|
|
804
804
|
inputModalities: modalities ?? (fallback ? [...fallback.inputModalities] : ["text"]),
|
|
805
805
|
...efforts !== null ? { reasoningEfforts: efforts } : {},
|
|
806
|
-
defaultReasoningEffort: asString$
|
|
806
|
+
defaultReasoningEffort: asString$18(record.default_reasoning_level) ?? fallback?.defaultReasoningEffort ?? null
|
|
807
807
|
}];
|
|
808
808
|
}
|
|
809
809
|
function parseModalities(value) {
|
|
810
810
|
if (!Array.isArray(value)) return null;
|
|
811
811
|
const out = [];
|
|
812
812
|
for (const item of value) {
|
|
813
|
-
const name = asString$
|
|
813
|
+
const name = asString$18(item);
|
|
814
814
|
if (name === "text" || name === "image") out.push(name);
|
|
815
815
|
}
|
|
816
816
|
return out.length > 0 ? out : null;
|
|
@@ -825,7 +825,7 @@ function parseEfforts(value) {
|
|
|
825
825
|
if (!Array.isArray(value)) return null;
|
|
826
826
|
const out = [];
|
|
827
827
|
for (const item of value) {
|
|
828
|
-
const effort = asString$
|
|
828
|
+
const effort = asString$18(item) ?? asString$18(asRecord$10(item)?.effort);
|
|
829
829
|
if (effort !== void 0 && !out.includes(effort)) out.push(effort);
|
|
830
830
|
}
|
|
831
831
|
return out.length > 0 ? out : null;
|
|
@@ -843,7 +843,7 @@ function accountKeyFor$1(credentials) {
|
|
|
843
843
|
function asRecord$10(value) {
|
|
844
844
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
845
845
|
}
|
|
846
|
-
function asString$
|
|
846
|
+
function asString$18(value) {
|
|
847
847
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
848
848
|
}
|
|
849
849
|
function asNumber$4(value) {
|
|
@@ -1085,6 +1085,22 @@ var WindowsDpapiTokenStore = class extends WindowsDpapiCredentialStore {
|
|
|
1085
1085
|
super(path, parseStoredCredentials);
|
|
1086
1086
|
}
|
|
1087
1087
|
};
|
|
1088
|
+
/**
|
|
1089
|
+
* How long a helper may run before it is killed and the read fails.
|
|
1090
|
+
*
|
|
1091
|
+
* A healthy spawn costs ~200 ms (see the cache note on this class), so the guard
|
|
1092
|
+
* exists only for a child that never exits, and it was set at 10 s - fifty times
|
|
1093
|
+
* the healthy cost. That turned out to be too tight for one real environment: a
|
|
1094
|
+
* cold Windows runner whose freshly-installed dependency tree is being scanned
|
|
1095
|
+
* on first spawn, where the helper legitimately took longer than 10 s and the
|
|
1096
|
+
* kill turned a working credential read into `DPAPI helper timed out`.
|
|
1097
|
+
*
|
|
1098
|
+
* The guard is kept, and only its headroom widened: 30 s is still bounded, still
|
|
1099
|
+
* far above anything a warm machine needs, and a hung helper now blocks one
|
|
1100
|
+
* credential read for 30 s rather than 10 - a worse wait in a case that is already
|
|
1101
|
+
* a failure, in exchange for not failing a machine that is merely cold.
|
|
1102
|
+
*/
|
|
1103
|
+
const POWERSHELL_HELPER_TIMEOUT_MS = 3e4;
|
|
1088
1104
|
function runPowerShell(script, path, stdin) {
|
|
1089
1105
|
return new Promise((resolve, reject) => {
|
|
1090
1106
|
const child = spawn("powershell.exe", [
|
|
@@ -1110,7 +1126,7 @@ function runPowerShell(script, path, stdin) {
|
|
|
1110
1126
|
const timer = setTimeout(() => {
|
|
1111
1127
|
child.kill();
|
|
1112
1128
|
reject(/* @__PURE__ */ new Error("DPAPI helper timed out"));
|
|
1113
|
-
},
|
|
1129
|
+
}, POWERSHELL_HELPER_TIMEOUT_MS);
|
|
1114
1130
|
child.stdout.setEncoding("utf8");
|
|
1115
1131
|
child.stdout.on("data", (chunk) => {
|
|
1116
1132
|
stdout += chunk;
|
|
@@ -3309,13 +3325,13 @@ function createCodexFetchProvider(options = {}) {
|
|
|
3309
3325
|
//#region src/host/common/llm-compat.ts
|
|
3310
3326
|
/** This package's kind in the harness message-source map. */
|
|
3311
3327
|
const PLUGIN_MESSAGE_SOURCE_KIND = "dsh-chatgpt-subscription";
|
|
3312
|
-
function isRecord$
|
|
3328
|
+
function isRecord$30(value) {
|
|
3313
3329
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3314
3330
|
}
|
|
3315
3331
|
/** Read a message body's blocks, keeping every entry that carries a block tag. */
|
|
3316
3332
|
function readBlocks(raw) {
|
|
3317
3333
|
if (!Array.isArray(raw)) return [];
|
|
3318
|
-
return raw.filter((block) => isRecord$
|
|
3334
|
+
return raw.filter((block) => isRecord$30(block) && typeof block.type === "string");
|
|
3319
3335
|
}
|
|
3320
3336
|
/**
|
|
3321
3337
|
* Normalize one harness message list into {@link Message}.
|
|
@@ -3330,10 +3346,10 @@ function readBlocks(raw) {
|
|
|
3330
3346
|
function normalizeMessages(messages) {
|
|
3331
3347
|
const normalized = [];
|
|
3332
3348
|
for (const raw of messages ?? []) {
|
|
3333
|
-
if (!isRecord$
|
|
3349
|
+
if (!isRecord$30(raw)) continue;
|
|
3334
3350
|
const content = readBlocks(raw.content);
|
|
3335
3351
|
if (raw.role === "tool") {
|
|
3336
|
-
const source = isRecord$
|
|
3352
|
+
const source = isRecord$30(raw.source) ? raw.source : void 0;
|
|
3337
3353
|
const callId = String(raw.toolCallId ?? source?.callId ?? "");
|
|
3338
3354
|
normalized.push({
|
|
3339
3355
|
id: raw.id,
|
|
@@ -3355,7 +3371,7 @@ function normalizeMessages(messages) {
|
|
|
3355
3371
|
id: raw.id,
|
|
3356
3372
|
role: typeof raw.role === "string" ? raw.role : "user",
|
|
3357
3373
|
content,
|
|
3358
|
-
...isRecord$
|
|
3374
|
+
...isRecord$30(raw.source) ? { source: raw.source } : {}
|
|
3359
3375
|
});
|
|
3360
3376
|
}
|
|
3361
3377
|
return normalized;
|
|
@@ -7055,7 +7071,7 @@ function field(value, name) {
|
|
|
7055
7071
|
const candidate = value[name];
|
|
7056
7072
|
return typeof candidate === "string" && candidate !== "" ? candidate : null;
|
|
7057
7073
|
}
|
|
7058
|
-
function isRecord$
|
|
7074
|
+
function isRecord$29(value) {
|
|
7059
7075
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7060
7076
|
}
|
|
7061
7077
|
function readPreferencesUpdate(value, current) {
|
|
@@ -7089,7 +7105,7 @@ function readPreferencesUpdate(value, current) {
|
|
|
7089
7105
|
patch.searchProvider = value.searchProvider;
|
|
7090
7106
|
}
|
|
7091
7107
|
if ("contextWindowOverrides" in value) {
|
|
7092
|
-
if (!isRecord$
|
|
7108
|
+
if (!isRecord$29(value.contextWindowOverrides)) throw new PreferenceError("contextWindowOverrides must be an object.");
|
|
7093
7109
|
const overrides = {};
|
|
7094
7110
|
for (const [model, contextWindow] of Object.entries(value.contextWindowOverrides)) {
|
|
7095
7111
|
if (!isCodexModelId(model)) throw new PreferenceError("Unknown Codex model for a context window override.");
|
|
@@ -8589,7 +8605,7 @@ const schemaFields = /* @__PURE__ */ new Set([
|
|
|
8589
8605
|
"required",
|
|
8590
8606
|
"propertyOrdering"
|
|
8591
8607
|
]);
|
|
8592
|
-
function isRecord$
|
|
8608
|
+
function isRecord$28(value) {
|
|
8593
8609
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8594
8610
|
}
|
|
8595
8611
|
function mergeSchemas(left, right) {
|
|
@@ -8597,7 +8613,7 @@ function mergeSchemas(left, right) {
|
|
|
8597
8613
|
...left,
|
|
8598
8614
|
...right
|
|
8599
8615
|
};
|
|
8600
|
-
if (isRecord$
|
|
8616
|
+
if (isRecord$28(left.properties) && isRecord$28(right.properties)) merged.properties = {
|
|
8601
8617
|
...left.properties,
|
|
8602
8618
|
...right.properties
|
|
8603
8619
|
};
|
|
@@ -8633,9 +8649,9 @@ const mergedTypeKeys = /* @__PURE__ */ new Set([
|
|
|
8633
8649
|
* model with strictly less than the schema it started from.
|
|
8634
8650
|
*/
|
|
8635
8651
|
function describeBranch(branch) {
|
|
8636
|
-
const type = typeof branch.type === "string" ? branch.type : isRecord$
|
|
8652
|
+
const type = typeof branch.type === "string" ? branch.type : isRecord$28(branch.properties) ? "object" : isRecord$28(branch.items) ? "array" : "value";
|
|
8637
8653
|
const details = [];
|
|
8638
|
-
if (isRecord$
|
|
8654
|
+
if (isRecord$28(branch.properties)) {
|
|
8639
8655
|
const names = Object.keys(branch.properties);
|
|
8640
8656
|
if (names.length > 0) details.push(`{${names.join(",")}}`);
|
|
8641
8657
|
}
|
|
@@ -8649,7 +8665,7 @@ function describeBranch(branch) {
|
|
|
8649
8665
|
}
|
|
8650
8666
|
/** How well one branch can stand in for a whole union; a named object shape wins. */
|
|
8651
8667
|
function branchRank(branch) {
|
|
8652
|
-
if (isRecord$
|
|
8668
|
+
if (isRecord$28(branch.properties)) return 3;
|
|
8653
8669
|
if (branch.type === "object") return 2;
|
|
8654
8670
|
if (branch.type === "array") return 1;
|
|
8655
8671
|
return 0;
|
|
@@ -8678,7 +8694,7 @@ function unionShape(branches) {
|
|
|
8678
8694
|
shape: branches[0],
|
|
8679
8695
|
folded: false
|
|
8680
8696
|
};
|
|
8681
|
-
if (new Set(branches.map((branch) => branch.type)).size === 1 && branches.every((branch) => !isRecord$
|
|
8697
|
+
if (new Set(branches.map((branch) => branch.type)).size === 1 && branches.every((branch) => !isRecord$28(branch.properties) && !isRecord$28(branch.items))) {
|
|
8682
8698
|
const shape = { type: branches[0].type };
|
|
8683
8699
|
if (branches.every((branch) => Array.isArray(branch.enum))) {
|
|
8684
8700
|
const values = [...new Set(branches.flatMap((branch) => branch.enum))];
|
|
@@ -8715,7 +8731,7 @@ function foldOwnFields(node) {
|
|
|
8715
8731
|
const out = {};
|
|
8716
8732
|
for (const [key, value] of Object.entries(node)) {
|
|
8717
8733
|
if (key === "anyOf" || key === "oneOf" || key === "allOf") continue;
|
|
8718
|
-
if (key === "properties" && isRecord$
|
|
8734
|
+
if (key === "properties" && isRecord$28(value)) {
|
|
8719
8735
|
out.properties = Object.fromEntries(Object.entries(value).map(([name, child]) => [name, foldSchemaUnions(child)]));
|
|
8720
8736
|
continue;
|
|
8721
8737
|
}
|
|
@@ -8744,15 +8760,15 @@ function foldOwnFields(node) {
|
|
|
8744
8760
|
* argument the model sends anyway fails there, naming the actual problem.
|
|
8745
8761
|
*/
|
|
8746
8762
|
function foldSchemaUnions(node) {
|
|
8747
|
-
if (!isRecord$
|
|
8763
|
+
if (!isRecord$28(node)) return node;
|
|
8748
8764
|
let own = foldOwnFields(node);
|
|
8749
8765
|
if (Array.isArray(node.allOf)) for (const branch of node.allOf) {
|
|
8750
8766
|
const folded = foldSchemaUnions(branch);
|
|
8751
|
-
if (isRecord$
|
|
8767
|
+
if (isRecord$28(folded)) own = mergeSchemas(own, folded);
|
|
8752
8768
|
}
|
|
8753
8769
|
const alternatives = Array.isArray(node.anyOf) ? node.anyOf : Array.isArray(node.oneOf) ? node.oneOf : [];
|
|
8754
8770
|
if (alternatives.length === 0) return own;
|
|
8755
|
-
const branches = alternatives.map((branch) => foldSchemaUnions(branch)).filter(isRecord$
|
|
8771
|
+
const branches = alternatives.map((branch) => foldSchemaUnions(branch)).filter(isRecord$28);
|
|
8756
8772
|
if (branches.length === 0) return own;
|
|
8757
8773
|
const shapes = branches.filter((branch) => branch.type !== "null");
|
|
8758
8774
|
const acceptsNull = branches.some((branch) => branch.type === "null");
|
|
@@ -8768,7 +8784,7 @@ function foldSchemaUnions(node) {
|
|
|
8768
8784
|
return merged;
|
|
8769
8785
|
}
|
|
8770
8786
|
function toAntigravityToolSchema(schema, options = {}) {
|
|
8771
|
-
if (!isRecord$
|
|
8787
|
+
if (!isRecord$28(schema)) return schema;
|
|
8772
8788
|
const root = schema;
|
|
8773
8789
|
function resolveReference(reference) {
|
|
8774
8790
|
let target = root;
|
|
@@ -8776,13 +8792,13 @@ function toAntigravityToolSchema(schema, options = {}) {
|
|
|
8776
8792
|
const path = reference === "#" ? [] : reference.slice(2).split("/");
|
|
8777
8793
|
for (const segment of path) {
|
|
8778
8794
|
const key = segment.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
8779
|
-
target = isRecord$
|
|
8795
|
+
target = isRecord$28(target) && Object.hasOwn(target, key) ? target[key] : void 0;
|
|
8780
8796
|
}
|
|
8781
|
-
if (!isRecord$
|
|
8797
|
+
if (!isRecord$28(target)) throw new LlmError(`Antigravity tool schema reference was not found: ${reference}`, "PROVIDER_ERROR");
|
|
8782
8798
|
return target;
|
|
8783
8799
|
}
|
|
8784
8800
|
function convert(node, references) {
|
|
8785
|
-
if (!isRecord$
|
|
8801
|
+
if (!isRecord$28(node)) return {};
|
|
8786
8802
|
let inherited = {};
|
|
8787
8803
|
if (typeof node.$ref === "string") {
|
|
8788
8804
|
if (references.has(node.$ref)) throw new LlmError(`Antigravity tool schema contains a recursive reference: ${node.$ref}`, "PROVIDER_ERROR");
|
|
@@ -8791,8 +8807,8 @@ function toAntigravityToolSchema(schema, options = {}) {
|
|
|
8791
8807
|
if (Array.isArray(node.allOf)) for (const branch of node.allOf) inherited = mergeSchemas(inherited, convert(branch, references));
|
|
8792
8808
|
const out = {};
|
|
8793
8809
|
for (const [key, value] of Object.entries(node)) if (schemaFields.has(key)) out[key] = value;
|
|
8794
|
-
if (isRecord$
|
|
8795
|
-
if (isRecord$
|
|
8810
|
+
if (isRecord$28(node.properties)) out.properties = Object.fromEntries(Object.entries(node.properties).map(([name, child]) => [name, convert(child, references)]));
|
|
8811
|
+
if (isRecord$28(node.items)) out.items = convert(node.items, references);
|
|
8796
8812
|
const alternatives = Array.isArray(node.anyOf) ? node.anyOf : node.oneOf;
|
|
8797
8813
|
if (Array.isArray(alternatives)) out.anyOf = alternatives.map((child) => convert(child, references));
|
|
8798
8814
|
if (Array.isArray(node.type)) {
|
|
@@ -8828,10 +8844,10 @@ let toolCallCounter = 0;
|
|
|
8828
8844
|
function sanitizeText$5(text) {
|
|
8829
8845
|
return text.replace(/\0/g, "");
|
|
8830
8846
|
}
|
|
8831
|
-
function isRecord$
|
|
8847
|
+
function isRecord$27(value) {
|
|
8832
8848
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8833
8849
|
}
|
|
8834
|
-
function asString$
|
|
8850
|
+
function asString$17(value) {
|
|
8835
8851
|
return typeof value === "string" ? value : void 0;
|
|
8836
8852
|
}
|
|
8837
8853
|
function safeJsonParse$5(text) {
|
|
@@ -8848,25 +8864,25 @@ function toolCallIdNeeded(modelId, runtimeModel) {
|
|
|
8848
8864
|
return modelId.startsWith("claude-") || modelId.startsWith("gpt-oss-") || runtimeModel.startsWith("claude-") || runtimeModel.startsWith("gpt-oss-");
|
|
8849
8865
|
}
|
|
8850
8866
|
function parseArguments$1(raw) {
|
|
8851
|
-
if (isRecord$
|
|
8867
|
+
if (isRecord$27(raw)) return raw;
|
|
8852
8868
|
if (raw === void 0 || raw === null || raw === "") return {};
|
|
8853
8869
|
const parsed = typeof raw === "string" ? safeJsonParse$5(raw) : raw;
|
|
8854
|
-
return isRecord$
|
|
8870
|
+
return isRecord$27(parsed) ? parsed : {};
|
|
8855
8871
|
}
|
|
8856
8872
|
const NO_RESOLVED_IMAGES$5 = /* @__PURE__ */ new Map();
|
|
8857
8873
|
function attachmentOf$5(block) {
|
|
8858
8874
|
const attachment = block.attachment;
|
|
8859
|
-
if (!isRecord$
|
|
8875
|
+
if (!isRecord$27(attachment)) return void 0;
|
|
8860
8876
|
return typeof attachment.attachmentId === "string" ? attachment : void 0;
|
|
8861
8877
|
}
|
|
8862
8878
|
function attachmentLabel$6(block) {
|
|
8863
|
-
const attachment = isRecord$
|
|
8864
|
-
return asString$
|
|
8879
|
+
const attachment = isRecord$27(block.attachment) ? block.attachment : void 0;
|
|
8880
|
+
return asString$17(attachment?.name) || asString$17(attachment?.attachmentId);
|
|
8865
8881
|
}
|
|
8866
8882
|
function collectImageRefs$4(content, refs) {
|
|
8867
8883
|
if (!Array.isArray(content)) return;
|
|
8868
8884
|
for (const block of content) {
|
|
8869
|
-
if (!isRecord$
|
|
8885
|
+
if (!isRecord$27(block)) continue;
|
|
8870
8886
|
if (block.type === "image") {
|
|
8871
8887
|
const attachment = attachmentOf$5(block);
|
|
8872
8888
|
if (attachment) refs.set(attachment.attachmentId, attachment);
|
|
@@ -8904,13 +8920,13 @@ function base64Length$4(bytes) {
|
|
|
8904
8920
|
function requestImageBytes$4(block) {
|
|
8905
8921
|
const attachment = attachmentOf$5(block);
|
|
8906
8922
|
if (attachment) return base64Length$4(attachment.bytes);
|
|
8907
|
-
const inline = asString$
|
|
8923
|
+
const inline = asString$17(block.data) || asString$17(block.base64);
|
|
8908
8924
|
return inline ? inline.length : void 0;
|
|
8909
8925
|
}
|
|
8910
8926
|
function collectRequestImageBytes$4(content, lengths) {
|
|
8911
8927
|
if (!Array.isArray(content)) return;
|
|
8912
8928
|
for (const block of content) {
|
|
8913
|
-
if (!isRecord$
|
|
8929
|
+
if (!isRecord$27(block) || block.type !== "image") continue;
|
|
8914
8930
|
const bytes = requestImageBytes$4(block);
|
|
8915
8931
|
if (bytes !== void 0) lengths.push(bytes);
|
|
8916
8932
|
}
|
|
@@ -8945,7 +8961,7 @@ function offloadOldestRequestImages$4(options) {
|
|
|
8945
8961
|
if (remaining.count === 0 || !Array.isArray(message.content)) return message;
|
|
8946
8962
|
let replaced = false;
|
|
8947
8963
|
const content = message.content.map((block) => {
|
|
8948
|
-
if (remaining.count === 0 || !isRecord$
|
|
8964
|
+
if (remaining.count === 0 || !isRecord$27(block) || block.type !== "image") return block;
|
|
8949
8965
|
if (requestImageBytes$4(block) === void 0) return block;
|
|
8950
8966
|
remaining.count -= 1;
|
|
8951
8967
|
replaced = true;
|
|
@@ -9008,10 +9024,10 @@ function unavailableImageText$6(block) {
|
|
|
9008
9024
|
return `[image unavailable: ${label ? `${label} could not be read` : "the image could not be read"}; ask the user to attach it again if the image is needed]`;
|
|
9009
9025
|
}
|
|
9010
9026
|
function imageBlockToPart(block, images) {
|
|
9011
|
-
let data = asString$
|
|
9012
|
-
const source = isRecord$
|
|
9013
|
-
if (!data && source) data = asString$
|
|
9014
|
-
let mimeType = asString$
|
|
9027
|
+
let data = asString$17(block.data) || asString$17(block.base64);
|
|
9028
|
+
const source = isRecord$27(block.source) ? block.source : void 0;
|
|
9029
|
+
if (!data && source) data = asString$17(source.data) || asString$17(source.base64);
|
|
9030
|
+
let mimeType = asString$17(block.mimeType) || asString$17(block.mediaType) || (source ? asString$17(source.mimeType) || asString$17(source.mediaType) : void 0) || "image/png";
|
|
9015
9031
|
if (data?.startsWith("data:")) {
|
|
9016
9032
|
const match = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
9017
9033
|
if (match) {
|
|
@@ -9034,8 +9050,8 @@ function contentToUserParts(content, images) {
|
|
|
9034
9050
|
if (typeof content === "string") return [{ text: sanitizeText$5(content) }];
|
|
9035
9051
|
if (!Array.isArray(content)) return [];
|
|
9036
9052
|
const parts = [];
|
|
9037
|
-
for (const block of content) if (isRecord$
|
|
9038
|
-
else if (isRecord$
|
|
9053
|
+
for (const block of content) if (isRecord$27(block) && block.type === "text" && typeof block.text === "string") parts.push({ text: sanitizeText$5(block.text) });
|
|
9054
|
+
else if (isRecord$27(block) && block.type === "image") {
|
|
9039
9055
|
const img = imageBlockToPart(block, images);
|
|
9040
9056
|
parts.push(img ?? { text: unavailableImageText$6(block) });
|
|
9041
9057
|
}
|
|
@@ -9050,7 +9066,7 @@ function toolResultImageParts(blocks, images) {
|
|
|
9050
9066
|
if (!Array.isArray(blocks)) return [];
|
|
9051
9067
|
const parts = [];
|
|
9052
9068
|
for (const block of blocks) {
|
|
9053
|
-
if (!isRecord$
|
|
9069
|
+
if (!isRecord$27(block)) continue;
|
|
9054
9070
|
if (block.type === "image") {
|
|
9055
9071
|
parts.push(imageBlockToPart(block, images) ?? { text: unavailableImageText$6(block) });
|
|
9056
9072
|
continue;
|
|
@@ -9062,7 +9078,7 @@ function toolResultImageParts(blocks, images) {
|
|
|
9062
9078
|
function toolResultText$5(blocks) {
|
|
9063
9079
|
if (!Array.isArray(blocks)) return "";
|
|
9064
9080
|
return blocks.map((block) => {
|
|
9065
|
-
if (!isRecord$
|
|
9081
|
+
if (!isRecord$27(block)) return "";
|
|
9066
9082
|
if (block.type === "text" && typeof block.text === "string") return sanitizeText$5(block.text);
|
|
9067
9083
|
if (block.type === "tool-result") return toolResultText$5(block.content);
|
|
9068
9084
|
if (block.type === "image") {
|
|
@@ -9076,16 +9092,16 @@ function replayBlockFor$1(message, index) {
|
|
|
9076
9092
|
const source = message.source;
|
|
9077
9093
|
if (!source || source.kind !== "model" || source.provider !== "antigravity") return void 0;
|
|
9078
9094
|
const state = source.replayState;
|
|
9079
|
-
if (!isRecord$
|
|
9095
|
+
if (!isRecord$27(state)) return void 0;
|
|
9080
9096
|
if (Array.isArray(state.blocks)) return state.blocks[index];
|
|
9081
|
-
const resp = isRecord$
|
|
9097
|
+
const resp = isRecord$27(state.response) ? state.response : void 0;
|
|
9082
9098
|
if (resp) {
|
|
9083
9099
|
if (Array.isArray(resp.outputItems)) return resp.outputItems[index];
|
|
9084
9100
|
if (Array.isArray(resp.blocks)) return resp.blocks[index];
|
|
9085
9101
|
}
|
|
9086
9102
|
}
|
|
9087
9103
|
function thoughtSignature(part) {
|
|
9088
|
-
return asString$
|
|
9104
|
+
return asString$17(part?.thoughtSignature) || asString$17(part?.thought_signature) || asString$17(part?.thinkingSignature) || asString$17(part?.textSignature);
|
|
9089
9105
|
}
|
|
9090
9106
|
function replayPart(part) {
|
|
9091
9107
|
const copy = { ...part };
|
|
@@ -9138,11 +9154,11 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
9138
9154
|
if (!Array.isArray(message.content)) return parts;
|
|
9139
9155
|
for (let index = 0; index < message.content.length; index++) {
|
|
9140
9156
|
const block = message.content[index];
|
|
9141
|
-
if (!isRecord$
|
|
9157
|
+
if (!isRecord$27(block)) continue;
|
|
9142
9158
|
if (block.type === "reasoning" && runtimeModel.startsWith("claude-") && (message.source?.kind !== "model" || message.source.provider !== "antigravity" || !("model" in message.source) || message.source.model !== model.id)) continue;
|
|
9143
9159
|
const replay = replayBlockFor$1(message, index);
|
|
9144
|
-
const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$
|
|
9145
|
-
if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$
|
|
9160
|
+
const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$27) : [];
|
|
9161
|
+
if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$17(part.text) || "").join("") === sanitizeText$5(String(block.text || ""))) {
|
|
9146
9162
|
parts.push(...originalParts.map(replayPart));
|
|
9147
9163
|
continue;
|
|
9148
9164
|
}
|
|
@@ -9162,8 +9178,8 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
9162
9178
|
} else if (block.type === "tool-call") {
|
|
9163
9179
|
const toolId = String(block.id || "");
|
|
9164
9180
|
const toolName = String(block.name || "");
|
|
9165
|
-
const originalCall = originalParts.find((part) => isRecord$
|
|
9166
|
-
const wireId = asString$
|
|
9181
|
+
const originalCall = originalParts.find((part) => isRecord$27(part.functionCall));
|
|
9182
|
+
const wireId = asString$17((isRecord$27(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
|
|
9167
9183
|
toolCalls.set(toolId, {
|
|
9168
9184
|
name: toolName,
|
|
9169
9185
|
id: wireId
|
|
@@ -9215,7 +9231,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
|
|
|
9215
9231
|
continue;
|
|
9216
9232
|
}
|
|
9217
9233
|
const content = Array.isArray(message.content) ? message.content : [];
|
|
9218
|
-
const userParts = contentToUserParts(content.filter((b) => !isRecord$
|
|
9234
|
+
const userParts = contentToUserParts(content.filter((b) => !isRecord$27(b) || b.type !== "tool-result"), images);
|
|
9219
9235
|
if (role === "system") {
|
|
9220
9236
|
if (userParts.length) contents.push({
|
|
9221
9237
|
role: GEMINI_ROLE.user,
|
|
@@ -9227,7 +9243,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
|
|
|
9227
9243
|
role: GEMINI_ROLE.user,
|
|
9228
9244
|
parts: userParts
|
|
9229
9245
|
});
|
|
9230
|
-
for (const b of content) if (isRecord$
|
|
9246
|
+
for (const b of content) if (isRecord$27(b) && b.type === "tool-result") pushToolResult(contents, b, toolCalls, model, runtimeModel, images);
|
|
9231
9247
|
}
|
|
9232
9248
|
return contents;
|
|
9233
9249
|
}
|
|
@@ -9362,7 +9378,7 @@ const USAGE_FIELDS = [
|
|
|
9362
9378
|
"totalTokenCount"
|
|
9363
9379
|
];
|
|
9364
9380
|
function collectUsage(value, state) {
|
|
9365
|
-
if (!isRecord$
|
|
9381
|
+
if (!isRecord$27(value)) return;
|
|
9366
9382
|
for (const key of USAGE_FIELDS) {
|
|
9367
9383
|
const count = value[key];
|
|
9368
9384
|
if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0) continue;
|
|
@@ -9392,17 +9408,17 @@ function processStreamLine$2(line, state) {
|
|
|
9392
9408
|
}
|
|
9393
9409
|
if (!json) return [];
|
|
9394
9410
|
const chunk = safeJsonParse$5(json);
|
|
9395
|
-
if (!isRecord$
|
|
9396
|
-
const responseData = isRecord$
|
|
9397
|
-
const error = isRecord$
|
|
9398
|
-
if (error !== void 0) throw new LlmError$1(`Antigravity stream error: ${asString$
|
|
9411
|
+
if (!isRecord$27(chunk)) return [];
|
|
9412
|
+
const responseData = isRecord$27(chunk.response) ? chunk.response : chunk;
|
|
9413
|
+
const error = isRecord$27(chunk.error) ? chunk.error : isRecord$27(responseData.error) ? responseData.error : void 0;
|
|
9414
|
+
if (error !== void 0) throw new LlmError$1(`Antigravity stream error: ${asString$17(error.message) ?? "unknown error"}`, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
9399
9415
|
const candidates = Array.isArray(responseData.candidates) ? responseData.candidates : [];
|
|
9400
|
-
const candidate = isRecord$
|
|
9401
|
-
const content = isRecord$
|
|
9416
|
+
const candidate = isRecord$27(candidates[0]) ? candidates[0] : void 0;
|
|
9417
|
+
const content = isRecord$27(candidate?.content) ? candidate.content : void 0;
|
|
9402
9418
|
const parts = Array.isArray(content?.parts) ? content.parts : [];
|
|
9403
9419
|
const out = [];
|
|
9404
9420
|
for (const part of parts) {
|
|
9405
|
-
if (!isRecord$
|
|
9421
|
+
if (!isRecord$27(part)) continue;
|
|
9406
9422
|
if (typeof part.text === "string" && part.text !== "") {
|
|
9407
9423
|
const isThinking = Boolean(part.thought);
|
|
9408
9424
|
const blockType = isThinking ? "reasoning" : "text";
|
|
@@ -9434,7 +9450,7 @@ function processStreamLine$2(line, state) {
|
|
|
9434
9450
|
index: state.currentBlock.index,
|
|
9435
9451
|
text: delta
|
|
9436
9452
|
});
|
|
9437
|
-
} else if (!isRecord$
|
|
9453
|
+
} else if (!isRecord$27(part.functionCall) && thoughtSignature(part)) {
|
|
9438
9454
|
if (state.replayBlocks.length === 0) {
|
|
9439
9455
|
const type = part.thought ? "reasoning" : "text";
|
|
9440
9456
|
state.blocks.push({
|
|
@@ -9458,12 +9474,12 @@ function processStreamLine$2(line, state) {
|
|
|
9458
9474
|
}
|
|
9459
9475
|
state.replayBlocks[state.replayBlocks.length - 1].parts.push(replayPart(part));
|
|
9460
9476
|
}
|
|
9461
|
-
if (isRecord$
|
|
9477
|
+
if (isRecord$27(part.functionCall)) {
|
|
9462
9478
|
out.push(...closeCurrentBlock(state));
|
|
9463
9479
|
const fc = part.functionCall;
|
|
9464
|
-
const toolName = asString$
|
|
9465
|
-
const toolId = asString$
|
|
9466
|
-
const argsText = JSON.stringify(isRecord$
|
|
9480
|
+
const toolName = asString$17(fc.name) || "";
|
|
9481
|
+
const toolId = asString$17(fc.id) || sanitizeToolCallId("", toolName);
|
|
9482
|
+
const argsText = JSON.stringify(isRecord$27(fc.args) ? fc.args : {});
|
|
9467
9483
|
const index = state.blocks.length;
|
|
9468
9484
|
const block = {
|
|
9469
9485
|
type: "tool-call",
|
|
@@ -9500,7 +9516,7 @@ function processStreamLine$2(line, state) {
|
|
|
9500
9516
|
}
|
|
9501
9517
|
collectUsage(chunk.usageMetadata, state);
|
|
9502
9518
|
if (responseData !== chunk) collectUsage(responseData.usageMetadata, state);
|
|
9503
|
-
const finishReason = asString$
|
|
9519
|
+
const finishReason = asString$17(candidate?.finishReason) || asString$17(responseData.finishReason);
|
|
9504
9520
|
if (finishReason) {
|
|
9505
9521
|
state.finishReason = finishReason;
|
|
9506
9522
|
out.push(...closeCurrentBlock(state));
|
|
@@ -11859,13 +11875,13 @@ function commandCodeHeaders(apiKey, extra = {}) {
|
|
|
11859
11875
|
function timeoutSignal$3(signal, ms) {
|
|
11860
11876
|
return signal ? AbortSignal.any([signal, AbortSignal.timeout(ms)]) : AbortSignal.timeout(ms);
|
|
11861
11877
|
}
|
|
11862
|
-
function isRecord$
|
|
11878
|
+
function isRecord$26(value) {
|
|
11863
11879
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11864
11880
|
}
|
|
11865
11881
|
function asRecord$9(value) {
|
|
11866
|
-
return isRecord$
|
|
11882
|
+
return isRecord$26(value) ? value : void 0;
|
|
11867
11883
|
}
|
|
11868
|
-
function asString$
|
|
11884
|
+
function asString$16(value) {
|
|
11869
11885
|
if (typeof value === "string" && value.trim() !== "") return value;
|
|
11870
11886
|
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
11871
11887
|
}
|
|
@@ -11878,7 +11894,7 @@ function asNumber$3(value) {
|
|
|
11878
11894
|
}
|
|
11879
11895
|
function firstString$1(record, keys) {
|
|
11880
11896
|
for (const key of keys) {
|
|
11881
|
-
const value = asString$
|
|
11897
|
+
const value = asString$16(record[key]);
|
|
11882
11898
|
if (value !== void 0) return value;
|
|
11883
11899
|
}
|
|
11884
11900
|
}
|
|
@@ -11907,7 +11923,7 @@ function deepValue(value, keys, depth = 0) {
|
|
|
11907
11923
|
}
|
|
11908
11924
|
return;
|
|
11909
11925
|
}
|
|
11910
|
-
if (!isRecord$
|
|
11926
|
+
if (!isRecord$26(value)) return void 0;
|
|
11911
11927
|
for (const key of keys) if (value[key] !== void 0 && value[key] !== null) return value[key];
|
|
11912
11928
|
for (const nested of Object.values(value)) {
|
|
11913
11929
|
const hit = deepValue(nested, keys, depth + 1);
|
|
@@ -11921,7 +11937,7 @@ function collectRecords(value, keys, depth = 0, out = []) {
|
|
|
11921
11937
|
for (const entry of value) collectRecords(entry, keys, depth + 1, out);
|
|
11922
11938
|
return out;
|
|
11923
11939
|
}
|
|
11924
|
-
if (!isRecord$
|
|
11940
|
+
if (!isRecord$26(value)) return out;
|
|
11925
11941
|
if (keys.some((key) => value[key] !== void 0)) out.push(value);
|
|
11926
11942
|
for (const nested of Object.values(value)) collectRecords(nested, keys, depth + 1, out);
|
|
11927
11943
|
return out;
|
|
@@ -12125,7 +12141,7 @@ function parseCreditBalances(payload, consumed = []) {
|
|
|
12125
12141
|
/** Resolve the plan id the subscription or credits payload reports, when either does. */
|
|
12126
12142
|
function parsePlanId(payloads) {
|
|
12127
12143
|
for (const payload of payloads) {
|
|
12128
|
-
const id = asString$
|
|
12144
|
+
const id = asString$16(deepValue(payload, [
|
|
12129
12145
|
"planId",
|
|
12130
12146
|
"plan_id",
|
|
12131
12147
|
"priceId",
|
|
@@ -12144,7 +12160,7 @@ function parsePlanId(payloads) {
|
|
|
12144
12160
|
*/
|
|
12145
12161
|
function parseSubscriptionStatus(payload) {
|
|
12146
12162
|
const root = asRecord$9(payload) ?? {};
|
|
12147
|
-
return asString$
|
|
12163
|
+
return asString$16(deepValue(asRecord$9(root.data) ?? root, ["status"])) ?? null;
|
|
12148
12164
|
}
|
|
12149
12165
|
/** End of the current billing period, in Unix milliseconds. */
|
|
12150
12166
|
function parseSubscriptionPeriodEnd(payload) {
|
|
@@ -12696,10 +12712,10 @@ function buildModelOptions$2(catalog, enabledModelIds, overrides) {
|
|
|
12696
12712
|
*
|
|
12697
12713
|
* https://commandcode.ai/blog/command-code-provider-api
|
|
12698
12714
|
*/
|
|
12699
|
-
function isRecord$
|
|
12715
|
+
function isRecord$25(value) {
|
|
12700
12716
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12701
12717
|
}
|
|
12702
|
-
function asString$
|
|
12718
|
+
function asString$15(value) {
|
|
12703
12719
|
return typeof value === "string" ? value : void 0;
|
|
12704
12720
|
}
|
|
12705
12721
|
function safeJsonParse$4(text) {
|
|
@@ -12736,17 +12752,17 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$4 = /* @__PURE__ */ new Set([
|
|
|
12736
12752
|
]);
|
|
12737
12753
|
function attachmentOf$4(block) {
|
|
12738
12754
|
const attachment = block.attachment;
|
|
12739
|
-
if (!isRecord$
|
|
12755
|
+
if (!isRecord$25(attachment)) return void 0;
|
|
12740
12756
|
return typeof attachment.attachmentId === "string" ? attachment : void 0;
|
|
12741
12757
|
}
|
|
12742
12758
|
function attachmentLabel$5(block) {
|
|
12743
|
-
const attachment = isRecord$
|
|
12744
|
-
return asString$
|
|
12759
|
+
const attachment = isRecord$25(block.attachment) ? block.attachment : void 0;
|
|
12760
|
+
return asString$15(attachment?.name) || asString$15(attachment?.attachmentId);
|
|
12745
12761
|
}
|
|
12746
12762
|
function collectImageRefs$3(content, refs) {
|
|
12747
12763
|
if (!Array.isArray(content)) return;
|
|
12748
12764
|
for (const block of content) {
|
|
12749
|
-
if (!isRecord$
|
|
12765
|
+
if (!isRecord$25(block)) continue;
|
|
12750
12766
|
if (block.type === "image") {
|
|
12751
12767
|
const attachment = attachmentOf$4(block);
|
|
12752
12768
|
if (attachment) refs.set(attachment.attachmentId, attachment);
|
|
@@ -12761,13 +12777,13 @@ function base64Length$3(bytes) {
|
|
|
12761
12777
|
function requestImageBytes$3(block) {
|
|
12762
12778
|
const attachment = attachmentOf$4(block);
|
|
12763
12779
|
if (attachment) return base64Length$3(attachment.bytes);
|
|
12764
|
-
const inline = asString$
|
|
12780
|
+
const inline = asString$15(block.data) || asString$15(block.base64);
|
|
12765
12781
|
return inline ? inline.length : void 0;
|
|
12766
12782
|
}
|
|
12767
12783
|
function collectRequestImageBytes$3(content, lengths) {
|
|
12768
12784
|
if (!Array.isArray(content)) return;
|
|
12769
12785
|
for (const block of content) {
|
|
12770
|
-
if (!isRecord$
|
|
12786
|
+
if (!isRecord$25(block) || block.type !== "image") continue;
|
|
12771
12787
|
const bytes = requestImageBytes$3(block);
|
|
12772
12788
|
if (bytes !== void 0) lengths.push(bytes);
|
|
12773
12789
|
}
|
|
@@ -12794,7 +12810,7 @@ function offloadOldestRequestImages$3(options) {
|
|
|
12794
12810
|
if (remaining.count === 0 || !Array.isArray(message.content)) return message;
|
|
12795
12811
|
let replaced = false;
|
|
12796
12812
|
const content = message.content.map((block) => {
|
|
12797
|
-
if (remaining.count === 0 || !isRecord$
|
|
12813
|
+
if (remaining.count === 0 || !isRecord$25(block) || block.type !== "image") return block;
|
|
12798
12814
|
if (requestImageBytes$3(block) === void 0) return block;
|
|
12799
12815
|
remaining.count -= 1;
|
|
12800
12816
|
replaced = true;
|
|
@@ -12847,10 +12863,10 @@ function unavailableImageText$5(block) {
|
|
|
12847
12863
|
return `[image unavailable: ${label ? `${label} could not be read` : "the image could not be read"}; ask the user to attach it again if the image is needed]`;
|
|
12848
12864
|
}
|
|
12849
12865
|
function imageBlockToInline$3(block, images) {
|
|
12850
|
-
let data = asString$
|
|
12851
|
-
const source = isRecord$
|
|
12852
|
-
if (!data && source) data = asString$
|
|
12853
|
-
let mediaType = asString$
|
|
12866
|
+
let data = asString$15(block.data) || asString$15(block.base64);
|
|
12867
|
+
const source = isRecord$25(block.source) ? block.source : void 0;
|
|
12868
|
+
if (!data && source) data = asString$15(source.data) || asString$15(source.base64);
|
|
12869
|
+
let mediaType = asString$15(block.mimeType) || asString$15(block.mediaType) || (source ? asString$15(source.mimeType) || asString$15(source.mediaType) : void 0) || "image/png";
|
|
12854
12870
|
if (data?.startsWith("data:")) {
|
|
12855
12871
|
const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
12856
12872
|
if (matched) {
|
|
@@ -12874,7 +12890,7 @@ function textOf$5(content) {
|
|
|
12874
12890
|
if (!Array.isArray(content)) return "";
|
|
12875
12891
|
const parts = [];
|
|
12876
12892
|
for (const block of content) {
|
|
12877
|
-
if (!isRecord$
|
|
12893
|
+
if (!isRecord$25(block)) continue;
|
|
12878
12894
|
if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$4(block.text));
|
|
12879
12895
|
else if (block.type === "tool-result") parts.push(textOf$5(block.content));
|
|
12880
12896
|
}
|
|
@@ -12883,7 +12899,7 @@ function textOf$5(content) {
|
|
|
12883
12899
|
function toolResultText$4(blocks) {
|
|
12884
12900
|
if (!Array.isArray(blocks)) return "";
|
|
12885
12901
|
return blocks.map((block) => {
|
|
12886
|
-
if (!isRecord$
|
|
12902
|
+
if (!isRecord$25(block)) return "";
|
|
12887
12903
|
if (block.type === "text" && typeof block.text === "string") return sanitizeText$4(block.text);
|
|
12888
12904
|
if (block.type === "tool-result") return toolResultText$4(block.content);
|
|
12889
12905
|
if (block.type === "image") return `[image: ${attachmentLabel$5(block) ?? "attached image"}]`;
|
|
@@ -12901,7 +12917,7 @@ function toolResultBlocks$2(blocks, images) {
|
|
|
12901
12917
|
const out = [];
|
|
12902
12918
|
let hasImage = false;
|
|
12903
12919
|
for (const block of blocks) {
|
|
12904
|
-
if (!isRecord$
|
|
12920
|
+
if (!isRecord$25(block)) continue;
|
|
12905
12921
|
if (block.type === "text" && typeof block.text === "string") {
|
|
12906
12922
|
out.push({
|
|
12907
12923
|
type: "text",
|
|
@@ -12950,7 +12966,7 @@ function toolResultImageBlocks$2(blocks, images) {
|
|
|
12950
12966
|
if (!Array.isArray(blocks)) return [];
|
|
12951
12967
|
const out = [];
|
|
12952
12968
|
for (const block of blocks) {
|
|
12953
|
-
if (!isRecord$
|
|
12969
|
+
if (!isRecord$25(block)) continue;
|
|
12954
12970
|
if (block.type === "image") {
|
|
12955
12971
|
const inline = imageBlockToInline$3(block, images);
|
|
12956
12972
|
if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
|
|
@@ -12994,7 +13010,7 @@ function nonSystemMessages$4(options) {
|
|
|
12994
13010
|
}
|
|
12995
13011
|
/** Drop the JSON-Schema keywords provider gateways reject or ignore. */
|
|
12996
13012
|
function stripMetaSchema$2(schema) {
|
|
12997
|
-
if (!isRecord$
|
|
13013
|
+
if (!isRecord$25(schema)) return {
|
|
12998
13014
|
type: "object",
|
|
12999
13015
|
properties: {}
|
|
13000
13016
|
};
|
|
@@ -13011,7 +13027,7 @@ function openAIUserContent$2(message, images) {
|
|
|
13011
13027
|
const parts = [];
|
|
13012
13028
|
let hasImage = false;
|
|
13013
13029
|
for (const block of message.content) {
|
|
13014
|
-
if (!isRecord$
|
|
13030
|
+
if (!isRecord$25(block)) continue;
|
|
13015
13031
|
if (block.type === "text" && typeof block.text === "string") {
|
|
13016
13032
|
const text = sanitizeText$4(block.text);
|
|
13017
13033
|
if (text !== "") parts.push({
|
|
@@ -13039,7 +13055,7 @@ function openAIAssistantContent$2(message) {
|
|
|
13039
13055
|
const textParts = [];
|
|
13040
13056
|
const toolCalls = [];
|
|
13041
13057
|
for (const block of message.content) {
|
|
13042
|
-
if (!isRecord$
|
|
13058
|
+
if (!isRecord$25(block)) continue;
|
|
13043
13059
|
if (block.type === "text" && typeof block.text === "string") textParts.push(sanitizeText$4(block.text));
|
|
13044
13060
|
else if (block.type === "tool-call" && typeof block.name === "string") toolCalls.push({
|
|
13045
13061
|
id: typeof block.id === "string" && block.id !== "" ? block.id : `call_${toolCalls.length}`,
|
|
@@ -13071,7 +13087,7 @@ function buildOpenAIRequest$1(options, images = NO_RESOLVED_IMAGES$4) {
|
|
|
13071
13087
|
while (index < conversation.length && isToolResultMessage$4(conversation[index])) {
|
|
13072
13088
|
const current = conversation[index];
|
|
13073
13089
|
const block = current.content[0];
|
|
13074
|
-
const callId = isRecord$
|
|
13090
|
+
const callId = isRecord$25(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
|
|
13075
13091
|
messages.push({
|
|
13076
13092
|
role: "tool",
|
|
13077
13093
|
tool_call_id: callId,
|
|
@@ -13132,7 +13148,7 @@ function anthropicUserContent$2(message, images) {
|
|
|
13132
13148
|
if (!Array.isArray(message.content)) return [];
|
|
13133
13149
|
const blocks = [];
|
|
13134
13150
|
for (const block of message.content) {
|
|
13135
|
-
if (!isRecord$
|
|
13151
|
+
if (!isRecord$25(block)) continue;
|
|
13136
13152
|
if (block.type === "text" && typeof block.text === "string") {
|
|
13137
13153
|
const text = sanitizeText$4(block.text);
|
|
13138
13154
|
if (text !== "") blocks.push({
|
|
@@ -13169,7 +13185,7 @@ function anthropicUserContent$2(message, images) {
|
|
|
13169
13185
|
function anthropicAssistantContent$2(message) {
|
|
13170
13186
|
const blocks = [];
|
|
13171
13187
|
for (const block of message.content) {
|
|
13172
|
-
if (!isRecord$
|
|
13188
|
+
if (!isRecord$25(block)) continue;
|
|
13173
13189
|
if (block.type === "text" && typeof block.text === "string") {
|
|
13174
13190
|
const text = sanitizeText$4(block.text);
|
|
13175
13191
|
if (text !== "") blocks.push({
|
|
@@ -13182,7 +13198,7 @@ function anthropicAssistantContent$2(message) {
|
|
|
13182
13198
|
type: "tool_use",
|
|
13183
13199
|
id: typeof block.id === "string" && block.id !== "" ? block.id : `toolu_${blocks.length}`,
|
|
13184
13200
|
name: block.name,
|
|
13185
|
-
input: isRecord$
|
|
13201
|
+
input: isRecord$25(parsed) ? parsed : {}
|
|
13186
13202
|
});
|
|
13187
13203
|
}
|
|
13188
13204
|
}
|
|
@@ -13276,7 +13292,7 @@ function responsesUserContent(message, images) {
|
|
|
13276
13292
|
if (!Array.isArray(message.content)) return [];
|
|
13277
13293
|
const parts = [];
|
|
13278
13294
|
for (const block of message.content) {
|
|
13279
|
-
if (!isRecord$
|
|
13295
|
+
if (!isRecord$25(block)) continue;
|
|
13280
13296
|
if (block.type === "text" && typeof block.text === "string") {
|
|
13281
13297
|
const text = sanitizeText$4(block.text);
|
|
13282
13298
|
if (text !== "") parts.push({
|
|
@@ -13301,7 +13317,7 @@ function responsesToolResultImageBlocks(blocks, images) {
|
|
|
13301
13317
|
if (!Array.isArray(blocks)) return [];
|
|
13302
13318
|
const out = [];
|
|
13303
13319
|
for (const block of blocks) {
|
|
13304
|
-
if (!isRecord$
|
|
13320
|
+
if (!isRecord$25(block)) continue;
|
|
13305
13321
|
if (block.type === "image") {
|
|
13306
13322
|
const inline = imageBlockToInline$3(block, images);
|
|
13307
13323
|
if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
|
|
@@ -13328,8 +13344,8 @@ function buildResponsesRequest(options, images = NO_RESOLVED_IMAGES$4) {
|
|
|
13328
13344
|
const imageBlocks = [];
|
|
13329
13345
|
while (index < conversation.length && isToolResultMessage$4(conversation[index])) {
|
|
13330
13346
|
const current = conversation[index];
|
|
13331
|
-
const toolResult = Array.isArray(current.content) ? current.content.find((b) => isRecord$
|
|
13332
|
-
const callId = (isRecord$
|
|
13347
|
+
const toolResult = Array.isArray(current.content) ? current.content.find((b) => isRecord$25(b) && b.type === "tool-result") : void 0;
|
|
13348
|
+
const callId = (isRecord$25(toolResult) && typeof toolResult.toolCallId === "string" ? toolResult.toolCallId : "") || (typeof current.source?.callId === "string" ? current.source.callId : "");
|
|
13333
13349
|
input.push({
|
|
13334
13350
|
type: "function_call_output",
|
|
13335
13351
|
call_id: callId,
|
|
@@ -13352,7 +13368,7 @@ function buildResponsesRequest(options, images = NO_RESOLVED_IMAGES$4) {
|
|
|
13352
13368
|
content
|
|
13353
13369
|
});
|
|
13354
13370
|
for (const call of toolCalls) {
|
|
13355
|
-
const fn = isRecord$
|
|
13371
|
+
const fn = isRecord$25(call.function) ? call.function : void 0;
|
|
13356
13372
|
input.push({
|
|
13357
13373
|
type: "function_call",
|
|
13358
13374
|
call_id: call.id,
|
|
@@ -13475,25 +13491,33 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
13475
13491
|
}
|
|
13476
13492
|
if (payload === "") return [];
|
|
13477
13493
|
const chunk = safeJsonParse$4(payload);
|
|
13478
|
-
if (!isRecord$
|
|
13494
|
+
if (!isRecord$25(chunk)) return [];
|
|
13479
13495
|
const out = [];
|
|
13480
|
-
if (isRecord$
|
|
13481
|
-
|
|
13496
|
+
if (isRecord$25(chunk.error)) {
|
|
13497
|
+
const message = asString$15(chunk.error.message) ?? "unknown error";
|
|
13498
|
+
state.streamError = {
|
|
13499
|
+
vocabulary: "openai",
|
|
13500
|
+
error: chunk.error,
|
|
13501
|
+
message
|
|
13502
|
+
};
|
|
13503
|
+
throw new LlmError$1(`Command Code stream error: ${message}`, isContextOverflow(chunk.error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
13504
|
+
}
|
|
13505
|
+
const usage = isRecord$25(chunk.usage) ? chunk.usage : void 0;
|
|
13482
13506
|
if (usage) {
|
|
13483
13507
|
state.sawUsage = true;
|
|
13484
13508
|
const prompt = numberOr$5(usage.prompt_tokens, 0);
|
|
13485
|
-
const details = isRecord$
|
|
13509
|
+
const details = isRecord$25(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
|
|
13486
13510
|
const cached = details ? numberOr$5(details.cached_tokens, 0) : 0;
|
|
13487
13511
|
state.inputTokens = Math.max(0, prompt - cached);
|
|
13488
13512
|
state.cacheReadTokens = cached;
|
|
13489
13513
|
state.outputTokens = numberOr$5(usage.completion_tokens, state.outputTokens);
|
|
13490
|
-
if (isRecord$
|
|
13514
|
+
if (isRecord$25(usage.completion_tokens_details)) state.reasoningTokens = numberOr$5(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
|
|
13491
13515
|
}
|
|
13492
13516
|
const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
|
|
13493
|
-
const choice = isRecord$
|
|
13494
|
-
const delta = isRecord$
|
|
13517
|
+
const choice = isRecord$25(choices[0]) ? choices[0] : void 0;
|
|
13518
|
+
const delta = isRecord$25(choice?.delta) ? choice.delta : void 0;
|
|
13495
13519
|
if (delta) {
|
|
13496
|
-
const reasoning = asString$
|
|
13520
|
+
const reasoning = asString$15(delta.reasoning_content) ?? asString$15(delta.reasoning);
|
|
13497
13521
|
if (reasoning !== void 0 && reasoning !== "") {
|
|
13498
13522
|
out.push(...closeToolCalls$4(state));
|
|
13499
13523
|
if (state.current === null || state.current.type !== "reasoning") out.push(...openTextBlock$3(state, "reasoning"));
|
|
@@ -13505,7 +13529,7 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
13505
13529
|
text: sanitizeText$4(reasoning)
|
|
13506
13530
|
});
|
|
13507
13531
|
}
|
|
13508
|
-
const content = asString$
|
|
13532
|
+
const content = asString$15(delta.content);
|
|
13509
13533
|
if (content !== void 0 && content !== "") {
|
|
13510
13534
|
out.push(...closeToolCalls$4(state));
|
|
13511
13535
|
if (state.current === null || state.current.type !== "text") out.push(...openTextBlock$3(state, "text"));
|
|
@@ -13519,11 +13543,11 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
13519
13543
|
}
|
|
13520
13544
|
const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
|
|
13521
13545
|
for (const entry of toolDeltas) {
|
|
13522
|
-
if (!isRecord$
|
|
13546
|
+
if (!isRecord$25(entry)) continue;
|
|
13523
13547
|
out.push(...applyOpenAIToolDelta$1(entry, state));
|
|
13524
13548
|
}
|
|
13525
13549
|
}
|
|
13526
|
-
const finish = asString$
|
|
13550
|
+
const finish = asString$15(choice?.finish_reason);
|
|
13527
13551
|
if (finish !== void 0 && finish !== "") {
|
|
13528
13552
|
state.finishReason = finish;
|
|
13529
13553
|
out.push(...closeCurrent$3(state));
|
|
@@ -13533,15 +13557,15 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
13533
13557
|
}
|
|
13534
13558
|
function applyOpenAIToolDelta$1(entry, state) {
|
|
13535
13559
|
const wireIndex = typeof entry.index === "number" ? entry.index : 0;
|
|
13536
|
-
const fn = isRecord$
|
|
13560
|
+
const fn = isRecord$25(entry.function) ? entry.function : {};
|
|
13537
13561
|
const out = [];
|
|
13538
13562
|
let call = state.toolCalls.get(wireIndex);
|
|
13539
13563
|
if (call === void 0) {
|
|
13540
13564
|
out.push(...closeCurrent$3(state));
|
|
13541
13565
|
call = {
|
|
13542
13566
|
blockIndex: state.blocks.length,
|
|
13543
|
-
id: asString$
|
|
13544
|
-
name: asString$
|
|
13567
|
+
id: asString$15(entry.id) ?? `call_${wireIndex}`,
|
|
13568
|
+
name: asString$15(fn.name) ?? "",
|
|
13545
13569
|
arguments: "",
|
|
13546
13570
|
started: false
|
|
13547
13571
|
};
|
|
@@ -13554,13 +13578,13 @@ function applyOpenAIToolDelta$1(entry, state) {
|
|
|
13554
13578
|
state.toolCalls.set(wireIndex, call);
|
|
13555
13579
|
} else {
|
|
13556
13580
|
if (call.id === `call_${wireIndex}`) {
|
|
13557
|
-
const id = asString$
|
|
13581
|
+
const id = asString$15(entry.id);
|
|
13558
13582
|
if (id !== void 0) call.id = id;
|
|
13559
13583
|
}
|
|
13560
|
-
const name = asString$
|
|
13584
|
+
const name = asString$15(fn.name);
|
|
13561
13585
|
if (name !== void 0 && name !== "") call.name = name;
|
|
13562
13586
|
}
|
|
13563
|
-
const argsDelta = asString$
|
|
13587
|
+
const argsDelta = asString$15(fn.arguments) ?? "";
|
|
13564
13588
|
if (argsDelta !== "") call.arguments += argsDelta;
|
|
13565
13589
|
if (!call.started) {
|
|
13566
13590
|
call.started = true;
|
|
@@ -13591,12 +13615,12 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
13591
13615
|
const payload = trimmed.slice(5).trim();
|
|
13592
13616
|
if (payload === "" || payload === "[DONE]") return [];
|
|
13593
13617
|
const event = safeJsonParse$4(payload);
|
|
13594
|
-
if (!isRecord$
|
|
13595
|
-
const type = asString$
|
|
13618
|
+
if (!isRecord$25(event)) return [];
|
|
13619
|
+
const type = asString$15(event.type);
|
|
13596
13620
|
const out = [];
|
|
13597
13621
|
if (type === "message_start") {
|
|
13598
|
-
const message = isRecord$
|
|
13599
|
-
const usage = message && isRecord$
|
|
13622
|
+
const message = isRecord$25(event.message) ? event.message : void 0;
|
|
13623
|
+
const usage = message && isRecord$25(message.usage) ? message.usage : void 0;
|
|
13600
13624
|
if (usage) {
|
|
13601
13625
|
state.sawUsage = true;
|
|
13602
13626
|
state.inputTokens = numberOr$5(usage.input_tokens, 0);
|
|
@@ -13604,21 +13628,21 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
13604
13628
|
state.cacheWriteTokens = numberOr$5(usage.cache_creation_input_tokens, 0);
|
|
13605
13629
|
state.outputTokens = numberOr$5(usage.output_tokens, 0);
|
|
13606
13630
|
}
|
|
13607
|
-
const stop = message ? asString$
|
|
13631
|
+
const stop = message ? asString$15(message.stop_reason) : void 0;
|
|
13608
13632
|
if (stop !== void 0 && stop !== null) state.finishReason = stop;
|
|
13609
13633
|
return out;
|
|
13610
13634
|
}
|
|
13611
13635
|
if (type === "content_block_start") {
|
|
13612
13636
|
const contentIndex = numberOr$5(event.index, 0);
|
|
13613
|
-
const block = isRecord$
|
|
13614
|
-
const blockType = asString$
|
|
13637
|
+
const block = isRecord$25(event.content_block) ? event.content_block : {};
|
|
13638
|
+
const blockType = asString$15(block.type);
|
|
13615
13639
|
out.push(...closeCurrent$3(state));
|
|
13616
13640
|
if (blockType === "tool_use") {
|
|
13617
13641
|
const index = state.blocks.length;
|
|
13618
13642
|
const pending = {
|
|
13619
13643
|
blockIndex: index,
|
|
13620
|
-
id: asString$
|
|
13621
|
-
name: asString$
|
|
13644
|
+
id: asString$15(block.id) ?? `toolu_${contentIndex}`,
|
|
13645
|
+
name: asString$15(block.name) ?? "",
|
|
13622
13646
|
arguments: "",
|
|
13623
13647
|
started: true
|
|
13624
13648
|
};
|
|
@@ -13660,11 +13684,11 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
13660
13684
|
}
|
|
13661
13685
|
if (type === "content_block_delta") {
|
|
13662
13686
|
const contentIndex = numberOr$5(event.index, 0);
|
|
13663
|
-
const delta = isRecord$
|
|
13664
|
-
const deltaType = asString$
|
|
13687
|
+
const delta = isRecord$25(event.delta) ? event.delta : {};
|
|
13688
|
+
const deltaType = asString$15(delta.type);
|
|
13665
13689
|
if (deltaType === "input_json_delta") {
|
|
13666
13690
|
const pending = state.toolCalls.get(contentIndex);
|
|
13667
|
-
const partial = asString$
|
|
13691
|
+
const partial = asString$15(delta.partial_json) ?? "";
|
|
13668
13692
|
if (pending !== void 0) {
|
|
13669
13693
|
pending.arguments += partial;
|
|
13670
13694
|
out.push({
|
|
@@ -13677,7 +13701,7 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
13677
13701
|
}
|
|
13678
13702
|
return out;
|
|
13679
13703
|
}
|
|
13680
|
-
const text = deltaType === "thinking_delta" ? asString$
|
|
13704
|
+
const text = deltaType === "thinking_delta" ? asString$15(delta.thinking) : asString$15(delta.text);
|
|
13681
13705
|
if (text !== void 0 && text !== "") {
|
|
13682
13706
|
const index = state.contentIndexes.get(contentIndex) ?? state.current?.index;
|
|
13683
13707
|
const kind = deltaType === "thinking_delta" ? "reasoning" : "text";
|
|
@@ -13733,10 +13757,10 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
13733
13757
|
return out;
|
|
13734
13758
|
}
|
|
13735
13759
|
if (type === "message_delta") {
|
|
13736
|
-
const delta = isRecord$
|
|
13737
|
-
const stop = delta ? asString$
|
|
13760
|
+
const delta = isRecord$25(event.delta) ? event.delta : void 0;
|
|
13761
|
+
const stop = delta ? asString$15(delta.stop_reason) : void 0;
|
|
13738
13762
|
if (stop !== void 0 && stop !== "") state.finishReason = stop;
|
|
13739
|
-
const usage = isRecord$
|
|
13763
|
+
const usage = isRecord$25(event.usage) ? event.usage : void 0;
|
|
13740
13764
|
if (usage) {
|
|
13741
13765
|
state.sawUsage = true;
|
|
13742
13766
|
state.outputTokens = numberOr$5(usage.output_tokens, state.outputTokens);
|
|
@@ -13748,8 +13772,14 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
13748
13772
|
return closeStream$4(state);
|
|
13749
13773
|
}
|
|
13750
13774
|
if (type === "error") {
|
|
13751
|
-
const error = isRecord$
|
|
13752
|
-
|
|
13775
|
+
const error = isRecord$25(event.error) ? event.error : {};
|
|
13776
|
+
const message = asString$15(error.message) ?? "unknown error";
|
|
13777
|
+
state.streamError = {
|
|
13778
|
+
vocabulary: "anthropic",
|
|
13779
|
+
error,
|
|
13780
|
+
message
|
|
13781
|
+
};
|
|
13782
|
+
throw new LlmError$1(`Command Code stream error: ${message}`, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
13753
13783
|
}
|
|
13754
13784
|
return out;
|
|
13755
13785
|
}
|
|
@@ -13788,7 +13818,7 @@ function processResponsesStreamLine(line, state) {
|
|
|
13788
13818
|
} catch {
|
|
13789
13819
|
return [];
|
|
13790
13820
|
}
|
|
13791
|
-
if (!isRecord$
|
|
13821
|
+
if (!isRecord$25(parsed)) return [];
|
|
13792
13822
|
const type = typeof parsed.type === "string" ? parsed.type : "";
|
|
13793
13823
|
if (type === "response.output_text.delta") {
|
|
13794
13824
|
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
@@ -13815,7 +13845,7 @@ function processResponsesStreamLine(line, state) {
|
|
|
13815
13845
|
}];
|
|
13816
13846
|
}
|
|
13817
13847
|
if (type === "response.output_item.added") {
|
|
13818
|
-
const item = isRecord$
|
|
13848
|
+
const item = isRecord$25(parsed.item) ? parsed.item : null;
|
|
13819
13849
|
if (item === null || item.type !== "function_call") return [];
|
|
13820
13850
|
return startResponsesToolCall(state, parsed, item);
|
|
13821
13851
|
}
|
|
@@ -13839,19 +13869,24 @@ function processResponsesStreamLine(line, state) {
|
|
|
13839
13869
|
return [];
|
|
13840
13870
|
}
|
|
13841
13871
|
if (type === "response.completed" || type === "response.incomplete") {
|
|
13842
|
-
const response = isRecord$
|
|
13872
|
+
const response = isRecord$25(parsed.response) ? parsed.response : null;
|
|
13843
13873
|
if (response !== null) {
|
|
13844
13874
|
if (response.status === "failed") {
|
|
13845
13875
|
state.done = true;
|
|
13846
|
-
const errorObj = isRecord$
|
|
13876
|
+
const errorObj = isRecord$25(response.error) ? response.error : null;
|
|
13847
13877
|
const detail = errorObj && typeof errorObj.message === "string" ? errorObj.message : typeof response.error === "string" ? response.error : "";
|
|
13878
|
+
state.streamError = {
|
|
13879
|
+
vocabulary: "responses",
|
|
13880
|
+
error: errorObj,
|
|
13881
|
+
message: detail
|
|
13882
|
+
};
|
|
13848
13883
|
throw new LlmError$1(detail === "" ? "Command Code responses stream failed" : `Command Code responses stream failed: ${detail}`, "PROVIDER_ERROR");
|
|
13849
13884
|
}
|
|
13850
13885
|
readResponsesUsage(response, state);
|
|
13851
13886
|
}
|
|
13852
13887
|
state.done = true;
|
|
13853
13888
|
if (type === "response.incomplete") {
|
|
13854
|
-
const details = response && isRecord$
|
|
13889
|
+
const details = response && isRecord$25(response.incomplete_details) ? response.incomplete_details : null;
|
|
13855
13890
|
const reason = details && typeof details.reason === "string" ? details.reason : "";
|
|
13856
13891
|
state.finishReason = reason === "max_output_tokens" || reason === "length" || reason === "max_tokens" ? "length" : reason || "length";
|
|
13857
13892
|
} else state.finishReason = "stop";
|
|
@@ -13859,8 +13894,13 @@ function processResponsesStreamLine(line, state) {
|
|
|
13859
13894
|
}
|
|
13860
13895
|
if (type === "response.failed" || type === "error") {
|
|
13861
13896
|
state.done = true;
|
|
13862
|
-
const errorObj = isRecord$
|
|
13863
|
-
const detail = (typeof parsed.message === "string" ? parsed.message : "") || (errorObj && typeof errorObj.message === "string" ? errorObj.message : "") || (isRecord$
|
|
13897
|
+
const errorObj = isRecord$25(parsed.error) ? parsed.error : isRecord$25(parsed.response) && isRecord$25(parsed.response.error) ? parsed.response.error : null;
|
|
13898
|
+
const detail = (typeof parsed.message === "string" ? parsed.message : "") || (errorObj && typeof errorObj.message === "string" ? errorObj.message : "") || (isRecord$25(parsed.response) && typeof parsed.response.error === "string" ? parsed.response.error : typeof parsed.error === "string" ? parsed.error : "");
|
|
13899
|
+
state.streamError = {
|
|
13900
|
+
vocabulary: "responses",
|
|
13901
|
+
error: errorObj,
|
|
13902
|
+
message: detail
|
|
13903
|
+
};
|
|
13864
13904
|
throw new LlmError$1(detail === "" ? "Command Code responses stream failed" : `Command Code responses stream failed: ${detail}`, isContextOverflow(errorObj ?? detail) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
13865
13905
|
}
|
|
13866
13906
|
return [];
|
|
@@ -13943,15 +13983,15 @@ function responsesToolCall(state, key) {
|
|
|
13943
13983
|
for (const call of state.toolCalls.values()) if (call.id === toToolCallId(key)) return call;
|
|
13944
13984
|
}
|
|
13945
13985
|
function readResponsesUsage(response, state) {
|
|
13946
|
-
const usage = isRecord$
|
|
13986
|
+
const usage = isRecord$25(response.usage) ? response.usage : null;
|
|
13947
13987
|
if (usage === null) return;
|
|
13948
|
-
const cached = isRecord$
|
|
13949
|
-
const written = isRecord$
|
|
13988
|
+
const cached = isRecord$25(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cached_tokens) : 0;
|
|
13989
|
+
const written = isRecord$25(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cache_write_tokens) : 0;
|
|
13950
13990
|
state.inputTokens = Math.max(0, numberOrZero(usage.input_tokens) - cached - written);
|
|
13951
13991
|
state.cacheReadTokens = cached;
|
|
13952
13992
|
state.cacheWriteTokens = written;
|
|
13953
13993
|
state.outputTokens = numberOrZero(usage.output_tokens);
|
|
13954
|
-
const outputDetails = isRecord$
|
|
13994
|
+
const outputDetails = isRecord$25(usage.output_tokens_details) ? usage.output_tokens_details : null;
|
|
13955
13995
|
if (outputDetails !== null) state.reasoningTokens = numberOrZero(outputDetails.reasoning_tokens);
|
|
13956
13996
|
state.sawUsage = true;
|
|
13957
13997
|
}
|
|
@@ -13978,6 +14018,136 @@ function assertStreamComplete$4(state) {
|
|
|
13978
14018
|
if (!state.done && state.finishReason === null) throw new LlmError$1("Command Code stream ended before its terminal event", "PROVIDER_ERROR");
|
|
13979
14019
|
}
|
|
13980
14020
|
//#endregion
|
|
14021
|
+
//#region src/host/common/stream-error.ts
|
|
14022
|
+
/**
|
|
14023
|
+
* A failure the provider reported INSIDE a 200 stream.
|
|
14024
|
+
*
|
|
14025
|
+
* A service can answer 200 and then report the failure in the stream, in the
|
|
14026
|
+
* same `{ error: { type, message } }` envelope a non-2xx body carries. A mapper
|
|
14027
|
+
* has to type that event with one code, and the code that is right in general is
|
|
14028
|
+
* PROVIDER_ERROR - it cannot know whether output has started - which is outside
|
|
14029
|
+
* every retry set. So a transient failure delivered this way ends the turn on
|
|
14030
|
+
* the first try while the identical failure delivered as a status is retried.
|
|
14031
|
+
*
|
|
14032
|
+
* The reclassification itself is per line, because only the adapter knows
|
|
14033
|
+
* whether anything has reached the caller yet, and because every line owns rules
|
|
14034
|
+
* its own HTTP path already owns. What is shared is the question each line asks
|
|
14035
|
+
* its own classifier: what status WOULD this failure have carried?
|
|
14036
|
+
*/
|
|
14037
|
+
/**
|
|
14038
|
+
* The status an in-band `error` event stands for, or null for a type this
|
|
14039
|
+
* vocabulary does not name.
|
|
14040
|
+
*
|
|
14041
|
+
* The Anthropic-compatible shims (MiniMax Code, Kimi Code, and Command Code's
|
|
14042
|
+
* messages stream) speak one vocabulary, and each of these types already has a
|
|
14043
|
+
* status: 529 is Anthropic's documented overload, 429 the rate limit, and a 5xx
|
|
14044
|
+
* the server-side failure. Naming the STATUS rather than the verdict is what lets
|
|
14045
|
+
* each line hand the answer to its own classifier, so a rule that line already
|
|
14046
|
+
* owns - a 429 that names an exhausted plan, a credential refusal reported as
|
|
14047
|
+
* 403 - keeps owning it here.
|
|
14048
|
+
*
|
|
14049
|
+
* Null for everything else: a request the provider rejected, a context
|
|
14050
|
+
* overflow, a credential refusal, a type from the future. Null is what keeps
|
|
14051
|
+
* the mapper's own verdict, and that is the safe direction to fail in - a
|
|
14052
|
+
* fallback to some made-up status would file an unknown type as a retryable
|
|
14053
|
+
* server error, which is worse than not retrying at all.
|
|
14054
|
+
*/
|
|
14055
|
+
function inBandAnthropicStatus(error) {
|
|
14056
|
+
const type = readErrorType(error);
|
|
14057
|
+
if (type === null) return null;
|
|
14058
|
+
return ANTHROPIC_IN_BAND_STATUS[type] ?? null;
|
|
14059
|
+
}
|
|
14060
|
+
/** The status each transient Anthropic-compatible in-band type stands for. */
|
|
14061
|
+
const ANTHROPIC_IN_BAND_STATUS = {
|
|
14062
|
+
overloaded_error: 529,
|
|
14063
|
+
rate_limit_error: 429,
|
|
14064
|
+
api_error: 500
|
|
14065
|
+
};
|
|
14066
|
+
/**
|
|
14067
|
+
* The DSH code an in-band Responses-vocabulary failure becomes, or null when it
|
|
14068
|
+
* names nothing transient.
|
|
14069
|
+
*
|
|
14070
|
+
* The Responses stream reports failure as `response.failed` or `error`, whose
|
|
14071
|
+
* message is free text and whose structured evidence is split across TWO fields:
|
|
14072
|
+
* this plugin's own routes document `{"error":{"message":"Upstream model
|
|
14073
|
+
* provider is temporarily unavailable. Please try again in a moment.","type":
|
|
14074
|
+
* "server_error"}}` - `type`, not `code` - so reading only `code` would miss
|
|
14075
|
+
* the exact body this exists for, and its message names nothing the heuristic
|
|
14076
|
+
* would catch. Both fields are read, and the message is read too, because a
|
|
14077
|
+
* deployment that says "overloaded" in prose is the whole signal there.
|
|
14078
|
+
*
|
|
14079
|
+
* Anything not recognized keeps the mapper's verdict.
|
|
14080
|
+
*/
|
|
14081
|
+
function inBandResponsesCode(error, message) {
|
|
14082
|
+
const fields = isRecord$24(error) ? error : {};
|
|
14083
|
+
const rawCode = (asString$14(fields.code) ?? asString$14(fields.type) ?? "").toLowerCase();
|
|
14084
|
+
const text = message.toLowerCase();
|
|
14085
|
+
if (text.includes("rate limit") || rawCode === "rate_limit" || rawCode === "rate_limit_exceeded") return "RATE_LIMIT";
|
|
14086
|
+
if (text.includes("overload") || text.includes("server error") || rawCode === "server_error" || rawCode === "service_unavailable" || rawCode === "internal_error") return "SERVER";
|
|
14087
|
+
return null;
|
|
14088
|
+
}
|
|
14089
|
+
/**
|
|
14090
|
+
* The error one in-band stream failure becomes, or `thrown` itself when the
|
|
14091
|
+
* line's own verdict stands.
|
|
14092
|
+
*
|
|
14093
|
+
* Call this only while nothing has reached the caller: the whole reason a fresh
|
|
14094
|
+
* request is still free is what makes the retry safe (see module note 1 in the
|
|
14095
|
+
* Claude adapter, which this generalizes). After the first chunk the mapper's
|
|
14096
|
+
* verdict stands and this must not be called at all.
|
|
14097
|
+
*
|
|
14098
|
+
* Only the CODE changes. The message stays the mapper's, which names the wire
|
|
14099
|
+
* type the user saw, and no `status` is attached: the response really was a
|
|
14100
|
+
* 200, and a synthetic one would misreport what the provider said.
|
|
14101
|
+
*
|
|
14102
|
+
* @param thrown - the mapper's own verdict, passed through when it stands.
|
|
14103
|
+
* @param rawError - the event's wire `error` object, from the stream state.
|
|
14104
|
+
* @param classify - this line's own failure classifier, so every rule its HTTP
|
|
14105
|
+
* path owns still owns the verdict reached here.
|
|
14106
|
+
* @param statusFor - the vocabulary's status table; Responses lines pass
|
|
14107
|
+
* {@link inBandResponsesCode} through {@link reclassifyInBandResponsesError}.
|
|
14108
|
+
*/
|
|
14109
|
+
function reclassifyInBandError(thrown, rawError, classify, statusFor = inBandAnthropicStatus) {
|
|
14110
|
+
const status = statusFor(rawError);
|
|
14111
|
+
if (status === null) return thrown;
|
|
14112
|
+
const failure = classify(status, JSON.stringify({ error: rawError }));
|
|
14113
|
+
if (!failure.retryable) return thrown;
|
|
14114
|
+
return new LlmError(thrown.message, failure.code, { cause: thrown });
|
|
14115
|
+
}
|
|
14116
|
+
/**
|
|
14117
|
+
* {@link reclassifyInBandError} for a line whose classifier reads a status, fed
|
|
14118
|
+
* by the Responses vocabulary instead of the Anthropic one.
|
|
14119
|
+
*
|
|
14120
|
+
* The transient verdict found here is a QUESTION, not the answer: a
|
|
14121
|
+
* `rate_limit` code says only that the failure is worth retrying, and whether
|
|
14122
|
+
* it actually is - a 429 naming a spent balance is this route's PROVIDER_ERROR,
|
|
14123
|
+
* not a RATE_LIMIT - is a rule the line's own classifier owns. So the answer is
|
|
14124
|
+
* asked of `classify` at the status the verdict stands for, exactly as the
|
|
14125
|
+
* Anthropic sibling does, and the CODE that comes back is the one the HTTP path
|
|
14126
|
+
* would have produced for the same body. That agreement is the whole point: the
|
|
14127
|
+
* in-band delivery must not be the one delivery with its own opinion.
|
|
14128
|
+
*/
|
|
14129
|
+
function reclassifyInBandResponsesError(thrown, rawError, message, classify) {
|
|
14130
|
+
const code = inBandResponsesCode(rawError, message);
|
|
14131
|
+
if (code === null) return thrown;
|
|
14132
|
+
const failure = classify(code === "RATE_LIMIT" ? 429 : 500, JSON.stringify({
|
|
14133
|
+
error: rawError,
|
|
14134
|
+
message
|
|
14135
|
+
}));
|
|
14136
|
+
if (!failure.retryable) return thrown;
|
|
14137
|
+
return new LlmError(thrown.message, failure.code, { cause: thrown });
|
|
14138
|
+
}
|
|
14139
|
+
/** The wire `error` object of an in-band event, read defensively. */
|
|
14140
|
+
function readErrorType(error) {
|
|
14141
|
+
if (!isRecord$24(error)) return null;
|
|
14142
|
+
return typeof error.type === "string" ? error.type : null;
|
|
14143
|
+
}
|
|
14144
|
+
function asString$14(value) {
|
|
14145
|
+
return typeof value === "string" ? value : void 0;
|
|
14146
|
+
}
|
|
14147
|
+
function isRecord$24(value) {
|
|
14148
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14149
|
+
}
|
|
14150
|
+
//#endregion
|
|
13981
14151
|
//#region src/host/common/capabilities.ts
|
|
13982
14152
|
/** Error thrown by requireCapability when a capability contract fails. */
|
|
13983
14153
|
var CapabilityError = class extends Error {
|
|
@@ -14253,6 +14423,35 @@ function isCommandCodeCredentialInvalid(status, detail) {
|
|
|
14253
14423
|
}
|
|
14254
14424
|
return false;
|
|
14255
14425
|
}
|
|
14426
|
+
/**
|
|
14427
|
+
* The verdict one failed response becomes on this route.
|
|
14428
|
+
*
|
|
14429
|
+
* An in-band `error` event is a status the provider chose not to send as a
|
|
14430
|
+
* status, so the chain that answers a non-2xx body has to answer it too rather
|
|
14431
|
+
* than a second, looser one: every rule this route already owns - a model the
|
|
14432
|
+
* plan does not include, a rejected key, a spent quota - keeps owning the
|
|
14433
|
+
* answer, and the codes below are the ONLY place the HTTP path reads them from.
|
|
14434
|
+
*
|
|
14435
|
+
* `retryable` is membership of this route's own policy rather than a second
|
|
14436
|
+
* judgement, because a code is worth repeating exactly when RETRY_POLICY repeats
|
|
14437
|
+
* it; a verdict the policy would not act on must not be filed as transient.
|
|
14438
|
+
*
|
|
14439
|
+
* @param status - the response status, or the status an in-band type stands for.
|
|
14440
|
+
* @param detail - the response body, or the serialized in-band error envelope.
|
|
14441
|
+
*/
|
|
14442
|
+
function classifyCommandCodeFailure(status, detail) {
|
|
14443
|
+
let code;
|
|
14444
|
+
if (status === 422) code = "PROVIDER_ERROR";
|
|
14445
|
+
else if (isCommandCodeModelAccessDenied(status, detail)) code = "PROVIDER_ERROR";
|
|
14446
|
+
else if (isCommandCodeCredentialInvalid(status, detail) || status === 401) code = "INVALID_CREDENTIAL";
|
|
14447
|
+
else if (status === 429) code = "RATE_LIMIT";
|
|
14448
|
+
else if (status >= 500) code = "SERVER";
|
|
14449
|
+
else code = isHttpContextOverflow(status, detail) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR";
|
|
14450
|
+
return {
|
|
14451
|
+
code,
|
|
14452
|
+
retryable: RETRY_POLICY$5.mode === "normal" && RETRY_POLICY$5.retryableCodes.includes(code)
|
|
14453
|
+
};
|
|
14454
|
+
}
|
|
14256
14455
|
/** Cooldown one rate-limited key takes when the provider states no delay. */
|
|
14257
14456
|
const POOL_COOLDOWN_MS$4 = 15 * 6e4;
|
|
14258
14457
|
var CommandCodeAdapter = class extends LlmAdapter {
|
|
@@ -14447,49 +14646,105 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
14447
14646
|
}
|
|
14448
14647
|
if (response === void 0 || !response.ok) {
|
|
14449
14648
|
const status = response?.status ?? 500;
|
|
14649
|
+
const { code } = classifyCommandCodeFailure(status, detail);
|
|
14450
14650
|
if (status === 422) {
|
|
14451
|
-
if (detail.includes("cmd_zdr_no_providers")) throw new LlmError(`${PROVIDER_NAME$5} rejected request under Zero Data Retention: no ZDR-capable upstream is available for this model (${detail || "cmd_zdr_no_providers"}).`,
|
|
14452
|
-
throw new LlmError(`${PROVIDER_NAME$5} validation error (422): ${detail || "Unprocessable Entity"}`,
|
|
14651
|
+
if (detail.includes("cmd_zdr_no_providers")) throw new LlmError(`${PROVIDER_NAME$5} rejected request under Zero Data Retention: no ZDR-capable upstream is available for this model (${detail || "cmd_zdr_no_providers"}).`, code, { status: 422 });
|
|
14652
|
+
throw new LlmError(`${PROVIDER_NAME$5} validation error (422): ${detail || "Unprocessable Entity"}`, code, { status: 422 });
|
|
14453
14653
|
}
|
|
14454
|
-
if (isCommandCodeModelAccessDenied(status, detail)) throw new LlmError(`${PROVIDER_NAME$5} access denied for model ${options.model}: this model is not included in the plan or requires higher entitlement (${status}).${detail ? ` ${detail}` : ""}`,
|
|
14455
|
-
if (isCommandCodeCredentialInvalid(status, detail) || status === 401) throw new LlmError(`${PROVIDER_NAME$5} rejected the stored API key (${status}). Sign in again from Settings > Command Code.${detail ? ` ${detail}` : ""}`,
|
|
14654
|
+
if (isCommandCodeModelAccessDenied(status, detail)) throw new LlmError(`${PROVIDER_NAME$5} access denied for model ${options.model}: this model is not included in the plan or requires higher entitlement (${status}).${detail ? ` ${detail}` : ""}`, code, { status });
|
|
14655
|
+
if (isCommandCodeCredentialInvalid(status, detail) || status === 401) throw new LlmError(`${PROVIDER_NAME$5} rejected the stored API key (${status}). Sign in again from Settings > Command Code.${detail ? ` ${detail}` : ""}`, code, { status });
|
|
14456
14656
|
if (status === 429) {
|
|
14457
14657
|
const after = response === void 0 ? void 0 : retryAfterMs$1(response.headers);
|
|
14458
|
-
throw new LlmError(`${PROVIDER_NAME$5} rate limit or plan quota reached (429). Check the quota card in Settings > Command Code.${detail ? ` ${detail}` : ""}`,
|
|
14658
|
+
throw new LlmError(`${PROVIDER_NAME$5} rate limit or plan quota reached (429). Check the quota card in Settings > Command Code.${detail ? ` ${detail}` : ""}`, code, {
|
|
14459
14659
|
status: 429,
|
|
14460
14660
|
...after === void 0 ? {} : { providerRetryAfterMs: after }
|
|
14461
14661
|
});
|
|
14462
14662
|
}
|
|
14463
|
-
if (status >= 500) throw new LlmError(`${PROVIDER_NAME$5} upstream server error (${status}): ${detail || "No response"}`,
|
|
14464
|
-
throw new LlmError(`${PROVIDER_NAME$5} API error (${status}): ${detail || "No response"}`,
|
|
14663
|
+
if (status >= 500) throw new LlmError(`${PROVIDER_NAME$5} upstream server error (${status}): ${detail || "No response"}`, code, { status });
|
|
14664
|
+
throw new LlmError(`${PROVIDER_NAME$5} API error (${status}): ${detail || "No response"}`, code, { status });
|
|
14465
14665
|
}
|
|
14466
14666
|
if (response.body === null) throw new LlmError("Command Code returned an empty response body", "PROVIDER_ERROR");
|
|
14467
14667
|
const reader = response.body.getReader();
|
|
14468
14668
|
const decoder = new TextDecoder();
|
|
14469
14669
|
const state = createStreamState$5(wire);
|
|
14470
14670
|
let buffer = "";
|
|
14671
|
+
/**
|
|
14672
|
+
* Set the moment ANY chunk reaches the caller, and never cleared.
|
|
14673
|
+
*
|
|
14674
|
+
* Deliberately broader than `a text delta or a tool call`: a retry would repeat
|
|
14675
|
+
* a block-start the caller has already seen just as surely, and could re-issue
|
|
14676
|
+
* a tool call the agent has already run, so the conservative reading is the
|
|
14677
|
+
* one that cannot be wrong. It is what keeps the in-band reclassification
|
|
14678
|
+
* below pre-output only, and before that point a fresh request is still free.
|
|
14679
|
+
*/
|
|
14680
|
+
let outputStarted = false;
|
|
14471
14681
|
try {
|
|
14472
|
-
|
|
14473
|
-
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
|
|
14477
|
-
|
|
14478
|
-
|
|
14479
|
-
for (const
|
|
14480
|
-
|
|
14682
|
+
try {
|
|
14683
|
+
while (true) {
|
|
14684
|
+
const { done, value } = await reader.read();
|
|
14685
|
+
if (done) break;
|
|
14686
|
+
buffer += decoder.decode(value, { stream: true });
|
|
14687
|
+
const lines = buffer.split("\n");
|
|
14688
|
+
buffer = lines.pop() ?? "";
|
|
14689
|
+
for (const line of lines) {
|
|
14690
|
+
for (const chunk of processLine$1(line, state, wire)) {
|
|
14691
|
+
outputStarted = true;
|
|
14692
|
+
yield chunk;
|
|
14693
|
+
}
|
|
14694
|
+
if (state.finished) return;
|
|
14695
|
+
}
|
|
14696
|
+
}
|
|
14697
|
+
buffer += decoder.decode();
|
|
14698
|
+
if (buffer.trim() !== "") for (const line of buffer.split("\n")) for (const chunk of processLine$1(line, state, wire)) {
|
|
14699
|
+
outputStarted = true;
|
|
14700
|
+
yield chunk;
|
|
14701
|
+
}
|
|
14702
|
+
if (state.finished) return;
|
|
14703
|
+
assertStreamComplete$4(state);
|
|
14704
|
+
for (const chunk of closeStream$4(state)) {
|
|
14705
|
+
outputStarted = true;
|
|
14706
|
+
yield chunk;
|
|
14707
|
+
}
|
|
14708
|
+
} catch (error) {
|
|
14709
|
+
const inBand = state.streamError;
|
|
14710
|
+
if (error instanceof LlmError && !outputStarted && inBand !== void 0 && error.code === "PROVIDER_ERROR") {
|
|
14711
|
+
const reclassified = reclassifyInBandStreamError(error, inBand);
|
|
14712
|
+
if (reclassified.code === "RATE_LIMIT" && pool !== null && accountId !== void 0) {
|
|
14713
|
+
const after = retryAfterMs$1(response.headers);
|
|
14714
|
+
await pool.markCooldown(accountId, after ?? POOL_COOLDOWN_MS$4, `${PROVIDER_NAME$5} in-stream 429`).catch(() => void 0);
|
|
14715
|
+
}
|
|
14716
|
+
throw reclassified;
|
|
14481
14717
|
}
|
|
14718
|
+
throw error;
|
|
14482
14719
|
}
|
|
14483
|
-
buffer += decoder.decode();
|
|
14484
|
-
if (buffer.trim() !== "") for (const line of buffer.split("\n")) for (const chunk of processLine$1(line, state, wire)) yield chunk;
|
|
14485
|
-
if (state.finished) return;
|
|
14486
|
-
assertStreamComplete$4(state);
|
|
14487
|
-
for (const chunk of closeStream$4(state)) yield chunk;
|
|
14488
14720
|
} finally {
|
|
14489
14721
|
reader.cancel().catch(() => void 0);
|
|
14490
14722
|
}
|
|
14491
14723
|
}
|
|
14492
14724
|
};
|
|
14725
|
+
/**
|
|
14726
|
+
* The error one recorded in-band failure becomes, or the mapper's own verdict.
|
|
14727
|
+
*
|
|
14728
|
+
* Two rules, because this line speaks three in-band vocabularies and they do
|
|
14729
|
+
* not carry the same evidence. The messages wire names a transient failure with
|
|
14730
|
+
* a `type` that STANDS FOR A STATUS - an `overloaded_error` is the 529 it would
|
|
14731
|
+
* have sent - so its envelope is answered by the status table. The
|
|
14732
|
+
* chat-completions and Responses wires have no such type: their evidence is a
|
|
14733
|
+
* `code`, a `type` in the looser `server_error` sense, or plain prose, and the
|
|
14734
|
+
* status-reading helper is what turns that into the question this line's own
|
|
14735
|
+
* classifier answers.
|
|
14736
|
+
*
|
|
14737
|
+
* The switch is exhaustive on purpose. A fourth vocabulary must be a compile
|
|
14738
|
+
* error here rather than a silent fall into the rule above, which is the one
|
|
14739
|
+
* shape of this bug that cannot be caught by a test.
|
|
14740
|
+
*/
|
|
14741
|
+
function reclassifyInBandStreamError(thrown, inBand) {
|
|
14742
|
+
switch (inBand.vocabulary) {
|
|
14743
|
+
case "anthropic": return reclassifyInBandError(thrown, inBand.error, classifyCommandCodeFailure);
|
|
14744
|
+
case "openai":
|
|
14745
|
+
case "responses": return reclassifyInBandResponsesError(thrown, inBand.error, inBand.message, classifyCommandCodeFailure);
|
|
14746
|
+
}
|
|
14747
|
+
}
|
|
14493
14748
|
/** Path suffix the chosen route answers on. */
|
|
14494
14749
|
function endpointPathFor(wire) {
|
|
14495
14750
|
if (wire === "anthropic") return "/messages";
|
|
@@ -15541,6 +15796,24 @@ const DEFAULT_CONTEXT_WINDOW$4 = 128e3;
|
|
|
15541
15796
|
* ceiling rather than a claim about what the model can do.
|
|
15542
15797
|
*/
|
|
15543
15798
|
const DEFAULT_MAX_OUTPUT_TOKENS = 8192;
|
|
15799
|
+
/**
|
|
15800
|
+
* Raise a cap that is too small for this model's forced thinking.
|
|
15801
|
+
*
|
|
15802
|
+
* Left alone: a model whose thinking CAN be disabled - its caller may have asked
|
|
15803
|
+
* for thinking off on purpose, and raising the cap would not enable it while the
|
|
15804
|
+
* number read back would be misleading - and an absent cap, which
|
|
15805
|
+
* `DEFAULT_MAX_OUTPUT_TOKENS` already owns at a size nothing is short of.
|
|
15806
|
+
*
|
|
15807
|
+
* @param modelId - the routed model id.
|
|
15808
|
+
* @param requested - the caller's cap, undefined when it stated none.
|
|
15809
|
+
* @returns the cap to request, raised only when that is the difference between an
|
|
15810
|
+
* empty truncated answer and a usable one.
|
|
15811
|
+
*/
|
|
15812
|
+
function floorForcedThinkingTokens$1(modelId, requested) {
|
|
15813
|
+
if (requested === void 0) return void 0;
|
|
15814
|
+
if (thinkingModeForModel(modelId) !== "levels") return requested;
|
|
15815
|
+
return Math.max(requested, 512);
|
|
15816
|
+
}
|
|
15544
15817
|
/** How long a catalog sync may take before the cached list is used instead. */
|
|
15545
15818
|
const CATALOG_TIMEOUT_MS = 15e3;
|
|
15546
15819
|
/**
|
|
@@ -16586,6 +16859,23 @@ var OllamaAdapter = class extends LlmAdapter {
|
|
|
16586
16859
|
let lastStatus;
|
|
16587
16860
|
let lastDetail = "";
|
|
16588
16861
|
let accountId;
|
|
16862
|
+
/**
|
|
16863
|
+
* Set the moment ANY chunk reaches the caller, and never cleared.
|
|
16864
|
+
*
|
|
16865
|
+
* Deliberately broader than "some text arrived": a block start or a tool
|
|
16866
|
+
* call the caller has already seen is exactly as visible as the text, so the
|
|
16867
|
+
* conservative reading is the one that cannot be wrong. It also survives the
|
|
16868
|
+
* pool rotation below, because output an account produced before failing is
|
|
16869
|
+
* still output.
|
|
16870
|
+
*/
|
|
16871
|
+
let outputStarted = false;
|
|
16872
|
+
/**
|
|
16873
|
+
* The code a transient in-band failure becomes, or null for this attempt.
|
|
16874
|
+
*
|
|
16875
|
+
* Assigned per failure rather than accumulated, so a later attempt that
|
|
16876
|
+
* failed for a reason of its own is never judged by an earlier one's wording.
|
|
16877
|
+
*/
|
|
16878
|
+
let lastInBandCode = null;
|
|
16589
16879
|
for (;;) {
|
|
16590
16880
|
let credentials;
|
|
16591
16881
|
if (pool === null) {
|
|
@@ -16613,6 +16903,7 @@ var OllamaAdapter = class extends LlmAdapter {
|
|
|
16613
16903
|
if (event.type === "error") {
|
|
16614
16904
|
lastStatus = openedStatus;
|
|
16615
16905
|
lastDetail = event.message;
|
|
16906
|
+
lastInBandCode = outputStarted || !(openedStatus !== void 0 && openedStatus >= 200 && openedStatus < 300) ? null : inBandTransientCode(event.message);
|
|
16616
16907
|
failed = true;
|
|
16617
16908
|
break;
|
|
16618
16909
|
}
|
|
@@ -16621,12 +16912,18 @@ var OllamaAdapter = class extends LlmAdapter {
|
|
|
16621
16912
|
continue;
|
|
16622
16913
|
}
|
|
16623
16914
|
if (event.type === "text" || event.type === "thinking" || event.type === "tool_call") {
|
|
16624
|
-
for (const chunk of applyEvent(state, event))
|
|
16915
|
+
for (const chunk of applyEvent(state, event)) {
|
|
16916
|
+
outputStarted = true;
|
|
16917
|
+
yield chunk;
|
|
16918
|
+
}
|
|
16625
16919
|
continue;
|
|
16626
16920
|
}
|
|
16627
16921
|
}
|
|
16628
16922
|
if (!failed) {
|
|
16629
|
-
for (const chunk of closeStream$3(state))
|
|
16923
|
+
for (const chunk of closeStream$3(state)) {
|
|
16924
|
+
outputStarted = true;
|
|
16925
|
+
yield chunk;
|
|
16926
|
+
}
|
|
16630
16927
|
if (pool !== null && accountId !== void 0 && spent !== null) await pool.recordUsage(accountId, spent.inputTokens, spent.outputTokens);
|
|
16631
16928
|
return;
|
|
16632
16929
|
}
|
|
@@ -16646,9 +16943,76 @@ var OllamaAdapter = class extends LlmAdapter {
|
|
|
16646
16943
|
const status = lastStatus;
|
|
16647
16944
|
if (status === 401 || status === 403) throw new LlmError(`${PROVIDER_NAME$4} rejected the API key (${status}). Replace it from Settings > ${PROVIDER_NAME$4}.${lastDetail ? ` ${lastDetail}` : ""}`, "INVALID_CREDENTIAL", { status });
|
|
16648
16945
|
if (status === 429) throw new LlmError(`${PROVIDER_NAME$4} rate limit or plan quota reached (429). Add another key, or wait for the cooldown shown in Settings > ${PROVIDER_NAME$4}.${lastDetail ? ` ${lastDetail}` : ""}`, "RATE_LIMIT", { status: 429 });
|
|
16649
|
-
throw new LlmError(`${PROVIDER_NAME$4} request failed${status === void 0 ? "" : ` (${status})`}.${lastDetail}`, status !== void 0 && status >= 500 ? "SERVER" : "INVALID_REQUEST", status === void 0 ? {} : { status });
|
|
16946
|
+
throw new LlmError(`${PROVIDER_NAME$4} request failed${status === void 0 ? "" : ` (${status})`}.${lastDetail}`, lastInBandCode ?? (status !== void 0 && status >= 500 ? "SERVER" : "INVALID_REQUEST"), status === void 0 ? {} : { status });
|
|
16650
16947
|
}
|
|
16651
16948
|
};
|
|
16949
|
+
/**
|
|
16950
|
+
* The DSH code an in-band Ollama failure becomes, or null when the message names
|
|
16951
|
+
* nothing transient.
|
|
16952
|
+
*
|
|
16953
|
+
* Ollama reports a failure inside a 200 as `{"error": "<message>"}` - one string,
|
|
16954
|
+
* no type - so the shared helper's Anthropic table cannot apply and there is no
|
|
16955
|
+
* status to name either. The wording is the whole signal, which is the same
|
|
16956
|
+
* message heuristic the Codex line already reads on `response.failed` in
|
|
16957
|
+
* `responses-client.ts` (generalized for the Responses vocabulary by
|
|
16958
|
+
* `inBandResponsesCode` in `common/stream-error.ts`); it is kept local here
|
|
16959
|
+
* because these are Ollama's own phrasings, not a vocabulary lines share.
|
|
16960
|
+
*
|
|
16961
|
+
* Every phrase below names a condition Ollama reports that clears on its own: a
|
|
16962
|
+
* model still being pulled into memory, a runner that would not start, a server
|
|
16963
|
+
* with no slot for this request, an overloaded or throttled front door. That is
|
|
16964
|
+
* what makes a retry worth taking - the request did not change, so a later one
|
|
16965
|
+
* is genuinely a different bet.
|
|
16966
|
+
*
|
|
16967
|
+
* Deliberately narrow, because the cost of guessing is paid by the user in
|
|
16968
|
+
* backoff. A refusal the wording does not name is usually the service objecting
|
|
16969
|
+
* to the caller's message, and retrying repeats it verbatim: three identical
|
|
16970
|
+
* requests ending in the same verdict, with the real fault unreported. Falling
|
|
16971
|
+
* back to some invented status instead would be worse on both counts, filing an
|
|
16972
|
+
* unrecognized refusal as a retryable server error and inviting the pool chain
|
|
16973
|
+
* to cool an account down for something nothing observed.
|
|
16974
|
+
*/
|
|
16975
|
+
function inBandTransientCode(message) {
|
|
16976
|
+
const text = message.toLowerCase();
|
|
16977
|
+
if (IN_BAND_RATE_LIMIT.some((phrase) => text.includes(phrase))) return "RATE_LIMIT";
|
|
16978
|
+
if (IN_BAND_SERVER.some((phrase) => text.includes(phrase))) return "SERVER";
|
|
16979
|
+
return null;
|
|
16980
|
+
}
|
|
16981
|
+
/**
|
|
16982
|
+
* Throttling wording, read first because it is the narrower of the two verdicts.
|
|
16983
|
+
*
|
|
16984
|
+
* The same conditions this line already types RATE_LIMIT for when they arrive as
|
|
16985
|
+
* a 429; a gateway that reports one inside the stream is describing the same
|
|
16986
|
+
* state, and the harness backoff that 429 earns is what the turn should get.
|
|
16987
|
+
*/
|
|
16988
|
+
const IN_BAND_RATE_LIMIT = [
|
|
16989
|
+
"rate limit",
|
|
16990
|
+
"rate-limit",
|
|
16991
|
+
"rate_limit",
|
|
16992
|
+
"too many requests",
|
|
16993
|
+
"quota"
|
|
16994
|
+
];
|
|
16995
|
+
/**
|
|
16996
|
+
* Server-side conditions, in no particular order.
|
|
16997
|
+
*
|
|
16998
|
+
* The model-loading and runner wording covers the two failures Ollama raises while
|
|
16999
|
+
* it is still getting ready to serve - the request was well formed and the
|
|
17000
|
+
* service was not ready for it - and the rest is what its front door says when it
|
|
17001
|
+
* is saturated.
|
|
17002
|
+
*/
|
|
17003
|
+
const IN_BAND_SERVER = [
|
|
17004
|
+
"overload",
|
|
17005
|
+
"server busy",
|
|
17006
|
+
"model is loading",
|
|
17007
|
+
"loading model",
|
|
17008
|
+
"couldn't load",
|
|
17009
|
+
"could not load",
|
|
17010
|
+
"unable to load",
|
|
17011
|
+
"failed to load",
|
|
17012
|
+
"runner",
|
|
17013
|
+
"service unavailable",
|
|
17014
|
+
"internal server error"
|
|
17015
|
+
];
|
|
16652
17016
|
function isAbort$3(error, signal) {
|
|
16653
17017
|
return signal?.aborted === true || error instanceof Error && error.name === "AbortError";
|
|
16654
17018
|
}
|
|
@@ -16812,7 +17176,8 @@ async function toOllamaRequest(options, attachments, signal) {
|
|
|
16812
17176
|
model: options.model,
|
|
16813
17177
|
messages
|
|
16814
17178
|
};
|
|
16815
|
-
|
|
17179
|
+
const flooredMax = floorForcedThinkingTokens$1(options.model, options.maxTokens);
|
|
17180
|
+
if (flooredMax !== void 0) request.maxOutputTokens = flooredMax;
|
|
16816
17181
|
if (options.temperature !== void 0) request.temperature = options.temperature;
|
|
16817
17182
|
const think = thinkForModel(options.model, options.reasoningEffort);
|
|
16818
17183
|
if (think !== void 0) request.think = think;
|
|
@@ -21104,7 +21469,15 @@ function processOpenAIStreamLine(line, state) {
|
|
|
21104
21469
|
if (!isRecord$17(chunk)) return [];
|
|
21105
21470
|
const out = [];
|
|
21106
21471
|
const errorPayload = isRecord$17(chunk.error) ? chunk.error : void 0;
|
|
21107
|
-
if (errorPayload !== void 0)
|
|
21472
|
+
if (errorPayload !== void 0) {
|
|
21473
|
+
const message = asString$9(errorPayload.message) ?? "unknown error";
|
|
21474
|
+
state.streamError = {
|
|
21475
|
+
vocabulary: "openai",
|
|
21476
|
+
error: errorPayload,
|
|
21477
|
+
message
|
|
21478
|
+
};
|
|
21479
|
+
throw new LlmError$1(`Kimi Code stream error: ${message}`, isContextOverflow(errorPayload) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
21480
|
+
}
|
|
21108
21481
|
const usage = isRecord$17(chunk.usage) ? chunk.usage : void 0;
|
|
21109
21482
|
if (usage) {
|
|
21110
21483
|
state.sawUsage = true;
|
|
@@ -21373,7 +21746,13 @@ function processAnthropicStreamLine(line, state) {
|
|
|
21373
21746
|
}
|
|
21374
21747
|
if (type === "error") {
|
|
21375
21748
|
const error = isRecord$17(event.error) ? event.error : {};
|
|
21376
|
-
|
|
21749
|
+
const message = asString$9(error.message) ?? "unknown error";
|
|
21750
|
+
state.streamError = {
|
|
21751
|
+
vocabulary: "anthropic",
|
|
21752
|
+
error,
|
|
21753
|
+
message
|
|
21754
|
+
};
|
|
21755
|
+
throw new LlmError$1(`Kimi Code stream error: ${message}`, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
21377
21756
|
}
|
|
21378
21757
|
return out;
|
|
21379
21758
|
}
|
|
@@ -21610,8 +21989,10 @@ function assertStreamComplete$3(state) {
|
|
|
21610
21989
|
* - `INVALID_CREDENTIAL` — a rejected access token fails identically on every
|
|
21611
21990
|
* attempt;
|
|
21612
21991
|
* - `PROVIDER_ERROR` — a 400, a 401 that is really a plan-entitlement refusal,
|
|
21613
|
-
* or a 403 quota limit. Retrying a quota that resets in hours
|
|
21614
|
-
* requests and delays the message the user needs to
|
|
21992
|
+
* or a 403 quota limit. Retrying a quota that resets in hours against the
|
|
21993
|
+
* SAME account only burns requests and delays the message the user needs to
|
|
21994
|
+
* see, so none of it is retried; a 403 limit still rotates to another account
|
|
21995
|
+
* when the pool holds one, which is a routing decision rather than a retry;
|
|
21615
21996
|
* - `ABORTED` — the caller already cancelled.
|
|
21616
21997
|
*
|
|
21617
21998
|
* The DSH normal defaults would apply anyway; stating the values here pins them
|
|
@@ -21695,17 +22076,20 @@ function classifyKimiFailure(status, bodyText) {
|
|
|
21695
22076
|
if (isHttpContextOverflow(status, bodyText)) return {
|
|
21696
22077
|
code: CONTEXT_OVERFLOW_CODE,
|
|
21697
22078
|
retryable: false,
|
|
22079
|
+
accountScoped: false,
|
|
21698
22080
|
message: `${PROVIDER_NAME$3} context window exceeded: ${detail}`
|
|
21699
22081
|
};
|
|
21700
22082
|
if (status === 402) return {
|
|
21701
22083
|
code: "SERVER",
|
|
21702
22084
|
retryable: true,
|
|
22085
|
+
accountScoped: false,
|
|
21703
22086
|
message: `${PROVIDER_NAME$3} could not verify the subscription tier (402). Retrying; if it persists, confirm the membership is active.${detail ? ` ${detail}` : ""}`
|
|
21704
22087
|
};
|
|
21705
22088
|
if (status === 401 || status === 403) {
|
|
21706
22089
|
if (matchesAny$1(detail, ENTITLEMENT_PATTERNS)) return {
|
|
21707
22090
|
code: "PROVIDER_ERROR",
|
|
21708
22091
|
retryable: false,
|
|
22092
|
+
accountScoped: false,
|
|
21709
22093
|
message: `${PROVIDER_NAME$3} refused this request for the current plan: ${detail || "the requested model or context is not included"}. Switch to a model the plan includes, lower the context-window override, or upgrade the subscription.`
|
|
21710
22094
|
};
|
|
21711
22095
|
if (status === 403) {
|
|
@@ -21713,12 +22097,14 @@ function classifyKimiFailure(status, bodyText) {
|
|
|
21713
22097
|
return {
|
|
21714
22098
|
code: "PROVIDER_ERROR",
|
|
21715
22099
|
retryable: false,
|
|
22100
|
+
accountScoped: true,
|
|
21716
22101
|
message: `${PROVIDER_NAME$3} blocked the request on an account limit (403): ${detail || (limitReached ? "the account limit was reached" : "the account refused the request")}. The quota refreshes on its own schedule — check the Kimi Code card in Settings for the reset time.`
|
|
21717
22102
|
};
|
|
21718
22103
|
}
|
|
21719
22104
|
return {
|
|
21720
22105
|
code: "INVALID_CREDENTIAL",
|
|
21721
22106
|
retryable: false,
|
|
22107
|
+
accountScoped: false,
|
|
21722
22108
|
message: `${PROVIDER_NAME$3} rejected the stored credential (401). Sign in again from Settings > Kimi Code.${detail ? ` ${detail}` : ""}`
|
|
21723
22109
|
};
|
|
21724
22110
|
}
|
|
@@ -21726,32 +22112,81 @@ function classifyKimiFailure(status, bodyText) {
|
|
|
21726
22112
|
if (matchesAny$1(detail, QUOTA_EXHAUSTED_PATTERNS$1)) return {
|
|
21727
22113
|
code: "PROVIDER_ERROR",
|
|
21728
22114
|
retryable: false,
|
|
22115
|
+
accountScoped: true,
|
|
21729
22116
|
message: `${PROVIDER_NAME$3} reports the account quota is exhausted: ${detail || "no remaining quota"}. Top up or wait for the window to reset.`
|
|
21730
22117
|
};
|
|
21731
22118
|
return {
|
|
21732
22119
|
code: "RATE_LIMIT",
|
|
21733
22120
|
retryable: true,
|
|
22121
|
+
accountScoped: false,
|
|
21734
22122
|
message: `${PROVIDER_NAME$3} is rate limited or overloaded (429): ${detail || "too many requests"}. Retrying with backoff.`
|
|
21735
22123
|
};
|
|
21736
22124
|
}
|
|
21737
22125
|
if (status >= 500) return {
|
|
21738
22126
|
code: "SERVER",
|
|
21739
22127
|
retryable: true,
|
|
22128
|
+
accountScoped: false,
|
|
21740
22129
|
message: `${PROVIDER_NAME$3} upstream server error (${status}): ${detail || "the model provider is temporarily unavailable"}. Retrying with backoff.`
|
|
21741
22130
|
};
|
|
21742
22131
|
if (status === 400) return {
|
|
21743
22132
|
code: "PROVIDER_ERROR",
|
|
21744
22133
|
retryable: false,
|
|
22134
|
+
accountScoped: false,
|
|
21745
22135
|
message: `${PROVIDER_NAME$3} rejected the request (400): ${detail || "the request was not accepted"}`
|
|
21746
22136
|
};
|
|
21747
22137
|
return {
|
|
21748
22138
|
code: "PROVIDER_ERROR",
|
|
21749
22139
|
retryable: false,
|
|
22140
|
+
accountScoped: false,
|
|
21750
22141
|
message: `${PROVIDER_NAME$3} API error (${status}): ${detail || "No response"}`
|
|
21751
22142
|
};
|
|
21752
22143
|
}
|
|
22144
|
+
/** Numeric reset the service may ship as a field rather than in prose. */
|
|
22145
|
+
const RESET_FIELD_PATTERN = /"?reset[A-Za-z_]*"?\s*[:=]\s*"?(\d{9,16})"?/i;
|
|
22146
|
+
/** ISO instant quoted in prose, trusted only when it names its own zone. */
|
|
22147
|
+
const RESET_INSTANT_PATTERN = /\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(?::\d{2})?(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})/;
|
|
22148
|
+
/** The window a billing-cycle refusal names; nothing shorter describes it. */
|
|
22149
|
+
const BILLING_CYCLE_PATTERN = /usage limit for this billing cycle/i;
|
|
22150
|
+
/**
|
|
22151
|
+
* How long one account stays out of rotation after it reports a spent limit.
|
|
22152
|
+
*
|
|
22153
|
+
* The reset instant is read from the body whenever the service states one — as a
|
|
22154
|
+
* numeric field, or as an instant carrying its own zone — and the length of the
|
|
22155
|
+
* window the service names is used otherwise. The zone is required for that
|
|
22156
|
+
* instant because an unqualified one is ambiguous, and a cooldown computed from
|
|
22157
|
+
* the wrong zone is either hours too long or already over; where the body is
|
|
22158
|
+
* ambiguous the window length is the honest answer.
|
|
22159
|
+
*
|
|
22160
|
+
* Both ends of the range are load-bearing. A reset instant barely in the future
|
|
22161
|
+
* would otherwise read as no cooldown at all and put the account straight back
|
|
22162
|
+
* into rotation to be refused again; and a reset instant already in the past
|
|
22163
|
+
* (a stale cache, a clock skew) falls back to the window length above rather
|
|
22164
|
+
* than to no cooldown at all.
|
|
22165
|
+
*/
|
|
22166
|
+
function accountLimitCooldownMs(bodyText, now = Date.now()) {
|
|
22167
|
+
const field = bodyText.match(RESET_FIELD_PATTERN);
|
|
22168
|
+
const instant = bodyText.match(RESET_INSTANT_PATTERN);
|
|
22169
|
+
const resetsAt = field !== null ? parseTimestamp(Number(field[1])) : instant !== null ? Date.parse(instant[0].replace(" ", "T")) : null;
|
|
22170
|
+
if (resetsAt !== null && Number.isFinite(resetsAt) && resetsAt > now) return Math.min(Math.max(resetsAt - now, POOL_COOLDOWN_MS$2), MAX_ACCOUNT_LIMIT_COOLDOWN_MS);
|
|
22171
|
+
return BILLING_CYCLE_PATTERN.test(bodyText) ? BILLING_CYCLE_COOLDOWN_MS : ACCOUNT_LIMIT_COOLDOWN_MS;
|
|
22172
|
+
}
|
|
21753
22173
|
/** Cooldown one rate-limited account takes when the provider states no delay. */
|
|
21754
22174
|
const POOL_COOLDOWN_MS$2 = 15 * 6e4;
|
|
22175
|
+
/**
|
|
22176
|
+
* Fallback cooldown for an account whose usage window is spent.
|
|
22177
|
+
*
|
|
22178
|
+
* The service states the reset time only sometimes, so the fallback is the
|
|
22179
|
+
* window's own length. The 15 minutes a 429 gets would put the account back
|
|
22180
|
+
* into rotation four times inside the very window that just refused it.
|
|
22181
|
+
*/
|
|
22182
|
+
const ACCOUNT_LIMIT_COOLDOWN_MS = 300 * 6e4;
|
|
22183
|
+
/**
|
|
22184
|
+
* A billing cycle is not a window: a 5-hour cooldown would spend a request every
|
|
22185
|
+
* five hours to learn an answer that changes at most once a month.
|
|
22186
|
+
*/
|
|
22187
|
+
const BILLING_CYCLE_COOLDOWN_MS = 720 * 60 * 6e4;
|
|
22188
|
+
/** Ceiling, so a malformed reset time cannot park an account for years. */
|
|
22189
|
+
const MAX_ACCOUNT_LIMIT_COOLDOWN_MS = BILLING_CYCLE_COOLDOWN_MS;
|
|
21755
22190
|
var KimiCodeAdapter = class extends LlmAdapter {
|
|
21756
22191
|
store;
|
|
21757
22192
|
modelSettings;
|
|
@@ -21936,11 +22371,15 @@ var KimiCodeAdapter = class extends LlmAdapter {
|
|
|
21936
22371
|
if (pool !== null && accountId !== void 0) {
|
|
21937
22372
|
const planScoped = response.status === 429 && matchesAny$1(detail, ENTITLEMENT_PATTERNS);
|
|
21938
22373
|
if (response.status === 429 && !planScoped) {
|
|
21939
|
-
|
|
22374
|
+
const cooldownMs = failure.accountScoped ? accountLimitCooldownMs(detail) : after ?? POOL_COOLDOWN_MS$2;
|
|
22375
|
+
await pool.markCooldown(accountId, cooldownMs, `${PROVIDER_NAME$3} 429`).catch(() => void 0);
|
|
21940
22376
|
if (await pool.hasAnotherAvailableAccount(tried)) continue;
|
|
21941
22377
|
} else if (failure.code === "INVALID_CREDENTIAL") {
|
|
21942
22378
|
await pool.markAuthFailed(accountId, failure.message).catch(() => void 0);
|
|
21943
22379
|
if (await pool.hasAnotherAvailableAccount(tried)) continue;
|
|
22380
|
+
} else if (failure.accountScoped) {
|
|
22381
|
+
await pool.markCooldown(accountId, accountLimitCooldownMs(detail), `${PROVIDER_NAME$3} 403`).catch(() => void 0);
|
|
22382
|
+
if (await pool.hasAnotherAvailableAccount(tried)) continue;
|
|
21944
22383
|
}
|
|
21945
22384
|
}
|
|
21946
22385
|
throw new LlmError(failure.message, failure.code, {
|
|
@@ -21954,27 +22393,98 @@ var KimiCodeAdapter = class extends LlmAdapter {
|
|
|
21954
22393
|
const state = createStreamState$3(wire, requestOptions.sessionId);
|
|
21955
22394
|
markSessionActive(requestOptions.sessionId);
|
|
21956
22395
|
let buffer = "";
|
|
22396
|
+
/**
|
|
22397
|
+
* Set the moment ANY chunk reaches the caller, and never cleared.
|
|
22398
|
+
*
|
|
22399
|
+
* Deliberately broader than "text arrived": a block-start the caller has
|
|
22400
|
+
* already seen repeats just as badly as text it has already read, so the
|
|
22401
|
+
* conservative reading is the one that cannot be wrong. It is what keeps the
|
|
22402
|
+
* in-band reclassification below pre-output only.
|
|
22403
|
+
*/
|
|
22404
|
+
let outputStarted = false;
|
|
21957
22405
|
try {
|
|
21958
|
-
|
|
21959
|
-
|
|
21960
|
-
|
|
21961
|
-
|
|
21962
|
-
|
|
21963
|
-
|
|
21964
|
-
|
|
21965
|
-
for (const
|
|
21966
|
-
|
|
22406
|
+
try {
|
|
22407
|
+
while (true) {
|
|
22408
|
+
const { done, value } = await reader.read();
|
|
22409
|
+
if (done) break;
|
|
22410
|
+
buffer += decoder.decode(value, { stream: true });
|
|
22411
|
+
const lines = buffer.split("\n");
|
|
22412
|
+
buffer = lines.pop() ?? "";
|
|
22413
|
+
for (const line of lines) {
|
|
22414
|
+
for (const chunk of processLine(line, state, wire)) {
|
|
22415
|
+
outputStarted = true;
|
|
22416
|
+
yield chunk;
|
|
22417
|
+
}
|
|
22418
|
+
if (state.finished) return;
|
|
22419
|
+
}
|
|
22420
|
+
}
|
|
22421
|
+
buffer += decoder.decode();
|
|
22422
|
+
if (buffer.trim() !== "") for (const line of buffer.split("\n")) for (const chunk of processLine(line, state, wire)) {
|
|
22423
|
+
outputStarted = true;
|
|
22424
|
+
yield chunk;
|
|
22425
|
+
}
|
|
22426
|
+
if (state.finished) return;
|
|
22427
|
+
assertStreamComplete$3(state);
|
|
22428
|
+
for (const chunk of closeStream$2(state, servedByAccountId)) {
|
|
22429
|
+
outputStarted = true;
|
|
22430
|
+
yield chunk;
|
|
21967
22431
|
}
|
|
22432
|
+
} catch (error) {
|
|
22433
|
+
const inBand = state.streamError;
|
|
22434
|
+
if (error instanceof LlmError && !outputStarted && error.code === "PROVIDER_ERROR" && inBand !== void 0) throw await this.inBandStreamFailure(error, inBand, servedByAccountId);
|
|
22435
|
+
throw error;
|
|
21968
22436
|
}
|
|
21969
|
-
buffer += decoder.decode();
|
|
21970
|
-
if (buffer.trim() !== "") for (const line of buffer.split("\n")) for (const chunk of processLine(line, state, wire)) yield chunk;
|
|
21971
|
-
if (state.finished) return;
|
|
21972
|
-
assertStreamComplete$3(state);
|
|
21973
|
-
for (const chunk of closeStream$2(state, servedByAccountId)) yield chunk;
|
|
21974
22437
|
} finally {
|
|
21975
22438
|
reader.cancel().catch(() => void 0);
|
|
21976
22439
|
}
|
|
21977
22440
|
}
|
|
22441
|
+
/**
|
|
22442
|
+
* What one in-band failure becomes once the pool has been told what the
|
|
22443
|
+
* verdict means for it.
|
|
22444
|
+
*
|
|
22445
|
+
* Reclassification and the pool reaction are separate because they answer
|
|
22446
|
+
* different questions about the same classification: the code decides whether
|
|
22447
|
+
* the harness retries, `accountScoped` decides whether a retry could land
|
|
22448
|
+
* somewhere that can answer. The mapper can supply only the first, which is
|
|
22449
|
+
* why the wire object is recorded there and read here.
|
|
22450
|
+
*
|
|
22451
|
+
* The body is the one a non-2xx response would have carried, so every pattern
|
|
22452
|
+
* below reads exactly what the HTTP branch reads and a limit cannot mean one
|
|
22453
|
+
* thing as a status and another as an event. The request itself is NOT
|
|
22454
|
+
* re-issued: its body is already open and part-read, and the harness retry
|
|
22455
|
+
* policy owns the repeat.
|
|
22456
|
+
*/
|
|
22457
|
+
async inBandStreamFailure(thrown, inBand, accountId) {
|
|
22458
|
+
const bodyText = JSON.stringify({ error: inBand.error });
|
|
22459
|
+
const reclassified = inBand.vocabulary === "anthropic" ? reclassifyInBandError(thrown, inBand.error, classifyKimiFailure) : reclassifyInBandResponsesError(thrown, inBand.error, inBand.message, classifyKimiFailure);
|
|
22460
|
+
const pool = this.accountPool;
|
|
22461
|
+
if (pool === null || accountId === void 0) return reclassified;
|
|
22462
|
+
if (inBand.vocabulary === "anthropic") {
|
|
22463
|
+
const status = inBandAnthropicStatus(inBand.error);
|
|
22464
|
+
if (status === null) return reclassified;
|
|
22465
|
+
const failure = classifyKimiFailure(status, bodyText);
|
|
22466
|
+
const planScoped = status === 429 && matchesAny$1(bodyText, ENTITLEMENT_PATTERNS);
|
|
22467
|
+
if (status === 429 && !planScoped) await this.coolInBandRateLimit(pool, accountId, failure.accountScoped, bodyText);
|
|
22468
|
+
else if (failure.code === "INVALID_CREDENTIAL") await pool.markAuthFailed(accountId, failure.message).catch(() => void 0);
|
|
22469
|
+
else if (failure.accountScoped) await pool.markCooldown(accountId, accountLimitCooldownMs(bodyText), `${PROVIDER_NAME$3} in-stream 403`).catch(() => void 0);
|
|
22470
|
+
return reclassified;
|
|
22471
|
+
}
|
|
22472
|
+
if (reclassified.code === "RATE_LIMIT" && !matchesAny$1(bodyText, ENTITLEMENT_PATTERNS)) await this.coolInBandRateLimit(pool, accountId, classifyKimiFailure(429, bodyText).accountScoped, bodyText);
|
|
22473
|
+
return reclassified;
|
|
22474
|
+
}
|
|
22475
|
+
/**
|
|
22476
|
+
* Cool the account whose own rate limit the stream reported.
|
|
22477
|
+
*
|
|
22478
|
+
* The window this route already defaults to, never a Retry-After: there is no
|
|
22479
|
+
* 429 response to read one from, and a delay stated on the 200 belongs to a
|
|
22480
|
+
* different message. An account-scoped verdict takes its own window instead,
|
|
22481
|
+
* because a spent balance is not back-pressure and 15 minutes would put the
|
|
22482
|
+
* account back into rotation four times inside the window that refused it.
|
|
22483
|
+
*/
|
|
22484
|
+
async coolInBandRateLimit(pool, accountId, accountScoped, bodyText) {
|
|
22485
|
+
const cooldownMs = accountScoped ? accountLimitCooldownMs(bodyText) : POOL_COOLDOWN_MS$2;
|
|
22486
|
+
await pool.markCooldown(accountId, cooldownMs, `${PROVIDER_NAME$3} in-stream 429`).catch(() => void 0);
|
|
22487
|
+
}
|
|
21978
22488
|
};
|
|
21979
22489
|
function processLine(line, state, wire) {
|
|
21980
22490
|
return wire === "anthropic" ? processAnthropicStreamLine(line, state) : processOpenAIStreamLine(line, state);
|
|
@@ -23937,6 +24447,26 @@ function outputConfigFor(modelId, requestedEffort) {
|
|
|
23937
24447
|
const effort = effortForModel(modelId, requestedEffort ?? null);
|
|
23938
24448
|
return effort === "default" ? void 0 : { effort };
|
|
23939
24449
|
}
|
|
24450
|
+
/**
|
|
24451
|
+
* Raise a cap that is too small for this line's forced thinking.
|
|
24452
|
+
*
|
|
24453
|
+
* Left alone: a model that can disable thinking (its caller may have asked for
|
|
24454
|
+
* thinking off on purpose, and raising the cap would not enable it but a caller
|
|
24455
|
+
* reading the number back would be misled), and an absent cap (the caller stated
|
|
24456
|
+
* none, so \`maxOutputTokensFor\` owns the ceiling).
|
|
24457
|
+
*
|
|
24458
|
+
* @param modelId - the routed model id.
|
|
24459
|
+
* @param requested - the caller's cap, undefined when it stated none.
|
|
24460
|
+
* @returns the cap to request, raised only when that is the difference between an
|
|
24461
|
+
* empty truncated answer and a usable one.
|
|
24462
|
+
*/
|
|
24463
|
+
function floorForcedThinkingTokens(modelId, requested) {
|
|
24464
|
+
if (requested === void 0) return void 0;
|
|
24465
|
+
const model = catalogEntry(modelId);
|
|
24466
|
+
const thinking = model?.thinking;
|
|
24467
|
+
if (thinking !== "always-on" && thinking !== "forced-effort") return requested;
|
|
24468
|
+
return Math.min(Math.max(requested, 512), Math.max(requested, model?.maxTokens ?? requested));
|
|
24469
|
+
}
|
|
23940
24470
|
/** Output cap one request asks for, tracked against the model's declared ceiling. */
|
|
23941
24471
|
function maxOutputTokensFor$1(modelId, contextWindow) {
|
|
23942
24472
|
const model = catalogEntry(modelId);
|
|
@@ -24455,6 +24985,7 @@ function processMinimaxStreamLine(line, state) {
|
|
|
24455
24985
|
}
|
|
24456
24986
|
if (type === "error") {
|
|
24457
24987
|
const error = isRecord$16(event.error) ? event.error : {};
|
|
24988
|
+
state.streamError = error;
|
|
24458
24989
|
throw new LlmError$1("MiniMax Code(编程订阅) stream error: " + (asString$8(error.message) ?? "unknown error"), isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
24459
24990
|
}
|
|
24460
24991
|
return out;
|
|
@@ -27115,7 +27646,7 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
27115
27646
|
}
|
|
27116
27647
|
let authOwner = computeMinimaxAuthOwner(credentials, accountId);
|
|
27117
27648
|
const withUploads = await uploadOversizedMedia(requestOptions, images, videos, credentials, accountId, this.options.fetchFn ?? fetch, signal);
|
|
27118
|
-
const effectiveMax = clampOutputToContext(requestOptions.maxTokens ?? maxOutputTokensFor$1(options.model, contextWindow), contextWindow, estimatedInputTokens(requestOptions));
|
|
27649
|
+
const effectiveMax = clampOutputToContext(floorForcedThinkingTokens(options.model, requestOptions.maxTokens) ?? maxOutputTokensFor$1(options.model, contextWindow), contextWindow, estimatedInputTokens(requestOptions));
|
|
27119
27650
|
const buildBodyForOwner = (owner) => {
|
|
27120
27651
|
return assertRequestBodyFits(buildMinimaxRequest({
|
|
27121
27652
|
...withUploads,
|
|
@@ -27175,23 +27706,46 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
27175
27706
|
provider: PROVIDER_ID$2
|
|
27176
27707
|
});
|
|
27177
27708
|
let buffer = "";
|
|
27709
|
+
/**
|
|
27710
|
+
* Set the moment ANY chunk reaches the caller, and never cleared.
|
|
27711
|
+
*
|
|
27712
|
+
* Deliberately broader than "a content delta or a tool block": a retry would
|
|
27713
|
+
* duplicate a block-start the caller has already seen just as surely, so the
|
|
27714
|
+
* conservative reading is the one that cannot be wrong. It is what keeps the
|
|
27715
|
+
* in-band reclassification below pre-output only.
|
|
27716
|
+
*/
|
|
27717
|
+
let outputStarted = false;
|
|
27178
27718
|
try {
|
|
27179
|
-
|
|
27180
|
-
|
|
27181
|
-
|
|
27182
|
-
|
|
27183
|
-
|
|
27184
|
-
|
|
27185
|
-
|
|
27186
|
-
for (const
|
|
27187
|
-
|
|
27719
|
+
try {
|
|
27720
|
+
while (true) {
|
|
27721
|
+
const { done, value } = await reader.read();
|
|
27722
|
+
if (done) break;
|
|
27723
|
+
buffer += decoder.decode(value, { stream: true });
|
|
27724
|
+
const lines = buffer.split("\n");
|
|
27725
|
+
buffer = lines.pop() ?? "";
|
|
27726
|
+
for (const line of lines) {
|
|
27727
|
+
for (const chunk of processMinimaxStreamLine(line, state)) {
|
|
27728
|
+
outputStarted = true;
|
|
27729
|
+
yield chunk;
|
|
27730
|
+
}
|
|
27731
|
+
if (state.finished) return;
|
|
27732
|
+
}
|
|
27733
|
+
}
|
|
27734
|
+
buffer += decoder.decode();
|
|
27735
|
+
if (buffer.trim() !== "") for (const line of buffer.split("\n")) for (const chunk of processMinimaxStreamLine(line, state)) {
|
|
27736
|
+
outputStarted = true;
|
|
27737
|
+
yield chunk;
|
|
27738
|
+
}
|
|
27739
|
+
if (state.finished) return;
|
|
27740
|
+
assertStreamComplete(state);
|
|
27741
|
+
for (const chunk of closeMinimaxStream(state)) {
|
|
27742
|
+
outputStarted = true;
|
|
27743
|
+
yield chunk;
|
|
27188
27744
|
}
|
|
27745
|
+
} catch (error) {
|
|
27746
|
+
if (error instanceof LlmError && !outputStarted && error.code === "PROVIDER_ERROR" && state.streamError !== void 0) throw reclassifyInBandError(error, state.streamError, classifyMinimaxFailure);
|
|
27747
|
+
throw error;
|
|
27189
27748
|
}
|
|
27190
|
-
buffer += decoder.decode();
|
|
27191
|
-
if (buffer.trim() !== "") for (const line of buffer.split("\n")) for (const chunk of processMinimaxStreamLine(line, state)) yield chunk;
|
|
27192
|
-
if (state.finished) return;
|
|
27193
|
-
assertStreamComplete(state);
|
|
27194
|
-
for (const chunk of closeMinimaxStream(state)) yield chunk;
|
|
27195
27749
|
} finally {
|
|
27196
27750
|
reader.cancel().catch(() => void 0);
|
|
27197
27751
|
}
|
|
@@ -36581,6 +37135,7 @@ function processStreamLine(line, state) {
|
|
|
36581
37135
|
const error = isRecord$5(event.error) ? event.error : {};
|
|
36582
37136
|
const message = asString$2(error.message) ?? "unknown error";
|
|
36583
37137
|
const kind = asString$2(error.type);
|
|
37138
|
+
state.streamError = error;
|
|
36584
37139
|
throw new LlmError$1("Claude stream error" + (kind === void 0 ? "" : " (" + kind + ")") + ": " + message, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
36585
37140
|
}
|
|
36586
37141
|
return out;
|
|
@@ -37754,6 +38309,13 @@ function cancelLogin() {
|
|
|
37754
38309
|
* - `request` -> PROVIDER_ERROR;
|
|
37755
38310
|
* - `network` -> TRANSPORT.
|
|
37756
38311
|
*
|
|
38312
|
+
* An in-band `error` event inside a 200 stream carries the same envelope and is
|
|
38313
|
+
* classified the same way while nothing has reached the caller; after the first
|
|
38314
|
+
* chunk it is surfaced as PROVIDER_ERROR, for the reason in note 1
|
|
38315
|
+
* ({@link inBandStreamVerdict}). A reclassified in-band failure is weighed by
|
|
38316
|
+
* {@link shouldRotateAccount} exactly as a non-2xx one is, so an account-scoped
|
|
38317
|
+
* limit reported inside the stream still takes that account out of rotation.
|
|
38318
|
+
*
|
|
37757
38319
|
* A reported-client-version rejection is a REQUEST problem even though it
|
|
37758
38320
|
* arrives as a 400 that mentions the client: it must NOT sign the user out, and
|
|
37759
38321
|
* it has a real remedy (raise the reported version), so it is handled
|
|
@@ -38153,8 +38715,19 @@ var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
|
|
|
38153
38715
|
* a later reordering of this method cannot silently drop it.
|
|
38154
38716
|
*/
|
|
38155
38717
|
let outputStarted = false;
|
|
38718
|
+
/**
|
|
38719
|
+
* The account the response now being streamed was issued with.
|
|
38720
|
+
*
|
|
38721
|
+
* Hoisted out of the loop because the in-stream failure path needs it: a
|
|
38722
|
+
* rate limit reported inside a 200 stream belongs to the account that was
|
|
38723
|
+
* asked, and that account is what the failure takes out of rotation — the
|
|
38724
|
+
* harness is about to repeat this request, and repeating it against the same
|
|
38725
|
+
* exhausted account fails identically.
|
|
38726
|
+
*/
|
|
38727
|
+
let usedAccountId;
|
|
38156
38728
|
while (true) {
|
|
38157
38729
|
const { credentials, accountId } = await this.resolveCredential(pool, tried, fetchFn, signal);
|
|
38730
|
+
usedAccountId = accountId;
|
|
38158
38731
|
response = await this.attemptRequest(credentials, requestOptions, images, toolNames, thinking, settings, signal, fetchFn);
|
|
38159
38732
|
if (response.ok) break;
|
|
38160
38733
|
const detail = (await response.text().catch(() => "")).slice(0, 2e3);
|
|
@@ -38200,7 +38773,12 @@ var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
|
|
|
38200
38773
|
yield chunk;
|
|
38201
38774
|
}
|
|
38202
38775
|
} catch (error) {
|
|
38203
|
-
if (error instanceof LlmError)
|
|
38776
|
+
if (error instanceof LlmError) {
|
|
38777
|
+
if (outputStarted || error.code !== "PROVIDER_ERROR" || state.streamError === void 0) throw error;
|
|
38778
|
+
const verdict = inBandStreamVerdict(error, state.streamError, response.headers);
|
|
38779
|
+
if (verdict.failure !== null && shouldRotateAccount(verdict.failure, outputStarted) && usedAccountId !== void 0) await pool?.markCooldown(usedAccountId, cooldownMsFor(verdict.failure), "Claude(订阅) in-stream 429").catch(() => void 0);
|
|
38780
|
+
throw verdict.error;
|
|
38781
|
+
}
|
|
38204
38782
|
if (signal.aborted) throw new LlmError("Claude request aborted", "ABORTED", { cause: error });
|
|
38205
38783
|
throw new LlmError("Claude stream failed: " + (error instanceof Error ? error.message : String(error)), outputStarted ? "PROVIDER_ERROR" : "TRANSPORT", { cause: error });
|
|
38206
38784
|
}
|
|
@@ -38290,6 +38868,49 @@ function codeForFailure(failure) {
|
|
|
38290
38868
|
return "PROVIDER_ERROR";
|
|
38291
38869
|
}
|
|
38292
38870
|
/**
|
|
38871
|
+
* The DSH error an in-band `error` event becomes when it arrived BEFORE any
|
|
38872
|
+
* chunk reached the caller.
|
|
38873
|
+
*
|
|
38874
|
+
* Anthropic can answer 200 and then report the failure inside the stream, in
|
|
38875
|
+
* the same `{ error: { type, message } }` envelope a non-2xx body carries. The
|
|
38876
|
+
* mapper types every such event PROVIDER_ERROR, because it cannot know whether
|
|
38877
|
+
* output has started — and PROVIDER_ERROR is outside the retry set, so an
|
|
38878
|
+
* `overloaded_error` delivered this way ended the turn on the first try while
|
|
38879
|
+
* the identical overload delivered as a 529 is retried. Before any output a
|
|
38880
|
+
* fresh request is still free (module note 1), so the envelope is classified
|
|
38881
|
+
* exactly as a response body would be, and a transient verdict (overloaded,
|
|
38882
|
+
* server, rate limit) takes its retryable code.
|
|
38883
|
+
*
|
|
38884
|
+
* Everything else keeps the mapper's verdict: a request problem, a context
|
|
38885
|
+
* overflow, a credential refusal, and a type this line does not recognize. The
|
|
38886
|
+
* last matters: classifyFailure falls back to the status line for an unknown
|
|
38887
|
+
* type, and no status here describes the failure — the response itself was a
|
|
38888
|
+
* 200 — so the status passed is 0 and never consulted for a recognized type.
|
|
38889
|
+
*
|
|
38890
|
+
* The message stays the mapper's, which names the wire type the user saw.
|
|
38891
|
+
*
|
|
38892
|
+
* The classified failure rides along beside the error so the caller can weigh it
|
|
38893
|
+
* with {@link shouldRotateAccount} instead of re-deriving what it says. It is
|
|
38894
|
+
* null whenever the mapper's verdict stands, so a caller never has to guess
|
|
38895
|
+
* whether `accountScoped` is meaningful.
|
|
38896
|
+
*
|
|
38897
|
+
* @param thrown - the mapper's PROVIDER_ERROR (or context-overflow) verdict.
|
|
38898
|
+
* @param streamError - the event's wire `error` object, from the stream state.
|
|
38899
|
+
* @param headers - the 200 response's headers, read for the rate-limit verdict.
|
|
38900
|
+
*/
|
|
38901
|
+
function inBandStreamVerdict(thrown, streamError, headers) {
|
|
38902
|
+
const failure = classifyFailure(0, JSON.stringify({ error: streamError }), headers);
|
|
38903
|
+
if (failure.type === null || !failure.retryable) return {
|
|
38904
|
+
error: thrown,
|
|
38905
|
+
failure: null
|
|
38906
|
+
};
|
|
38907
|
+
const retryAfter = failure.retryAfterMs !== null && failure.retryAfterMs > 0 ? failure.retryAfterMs : void 0;
|
|
38908
|
+
return {
|
|
38909
|
+
error: new LlmError(thrown.message, codeForFailure(failure), retryAfter === void 0 ? {} : { providerRetryAfterMs: retryAfter }),
|
|
38910
|
+
failure
|
|
38911
|
+
};
|
|
38912
|
+
}
|
|
38913
|
+
/**
|
|
38293
38914
|
* Turn one classified failure into the DSH error the caller sees.
|
|
38294
38915
|
*
|
|
38295
38916
|
* The facts the harness needs ride along: the HTTP status, and the delay the
|