@eddyskywalker/dsh-chatgpt-subscription 0.11.4 → 0.11.7
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/CHANGELOG.md +19 -0
- package/README.md +6 -0
- package/lib/client.js +96 -56
- package/lib/client.js.map +1 -1
- package/lib/index.js +360 -120
- package/lib/types/client/antigravity/styles.d.ts.map +1 -1
- package/lib/types/client/claude/styles.d.ts.map +1 -1
- package/lib/types/client/common/plugin-style.d.ts +23 -0
- package/lib/types/client/common/plugin-style.d.ts.map +1 -0
- package/lib/types/client/common/styles.d.ts.map +1 -1
- package/lib/types/client/kimi-code/styles.d.ts.map +1 -1
- package/lib/types/client/mermaid/styles.d.ts.map +1 -1
- package/lib/types/client/minimax-code/styles.d.ts.map +1 -1
- package/lib/types/client/styles.d.ts +5 -0
- package/lib/types/client/styles.d.ts.map +1 -1
- package/lib/types/client/workbuddy/styles.d.ts.map +1 -1
- package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
- package/lib/types/host/antigravity/mapper.d.ts.map +1 -1
- package/lib/types/host/claude/adapter.d.ts.map +1 -1
- package/lib/types/host/claude/mapper.d.ts.map +1 -1
- package/lib/types/host/command-code/adapter.d.ts.map +1 -1
- package/lib/types/host/command-code/mapper.d.ts.map +1 -1
- package/lib/types/host/common/context-budget-fetch.d.ts +7 -0
- package/lib/types/host/common/context-budget-fetch.d.ts.map +1 -0
- package/lib/types/host/common/context-overflow.d.ts +7 -0
- package/lib/types/host/common/context-overflow.d.ts.map +1 -0
- package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
- 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.map +1 -1
- package/lib/types/host/ollama/client.d.ts +29 -0
- package/lib/types/host/ollama/client.d.ts.map +1 -1
- package/lib/types/host/ollama/routes.d.ts.map +1 -1
- package/lib/types/host/responses-client.d.ts.map +1 -1
- package/lib/types/host/workbuddy/adapter.d.ts.map +1 -1
- package/lib/types/host/workbuddy/mapper.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -5629,6 +5629,32 @@ function withWritable(value) {
|
|
|
5629
5629
|
};
|
|
5630
5630
|
}
|
|
5631
5631
|
//#endregion
|
|
5632
|
+
//#region src/host/common/context-overflow.ts
|
|
5633
|
+
/** Stable code understood by Harness overflow recovery, including older hosts. */
|
|
5634
|
+
const CONTEXT_OVERFLOW_CODE = "CONTEXT_WINDOW_EXCEEDED";
|
|
5635
|
+
/** Inspect provider error fields only; never classify request bodies or successful output. */
|
|
5636
|
+
function isContextOverflow(error) {
|
|
5637
|
+
if (typeof error === "string") {
|
|
5638
|
+
try {
|
|
5639
|
+
const parsed = JSON.parse(error);
|
|
5640
|
+
if (typeof parsed === "object" && parsed !== null) return isContextOverflow(parsed);
|
|
5641
|
+
} catch {}
|
|
5642
|
+
return /\bcontext[_ -](?:length|window)[_ -](?:exceeded|overflow|limit[_ -]exceeded)\b/i.test(error) || /\b(?:maximum|max)(?: allowed| supported)? context (?:length|window)\b/i.test(error) && /\b(?:exceed(?:s|ed)?|requested|resulted in|reduce|too (?:long|large))\b/i.test(error) || /\b(?:prompt|input|request) (?:is )?too (?:long|large) for (?:the |this )?(?:model(?:'s)? )?context\b/i.test(error) || /\b(?:prompt|input) (?:is )?too long:\s*[\d,]+ tokens?\s*>\s*[\d,]+\s*(?:tokens?\s*)?maximum\b/i.test(error) || /\brequest exceeded model token limit\b/i.test(error) || /\b(?:input|prompt|request|messages?)\b.{0,40}\bexceed(?:s|ed)?\b.{0,40}\b(?:model(?:'s)? )?context (?:length|window)\b/i.test(error);
|
|
5643
|
+
}
|
|
5644
|
+
if (typeof error !== "object" || error === null || Array.isArray(error)) return false;
|
|
5645
|
+
const fields = error;
|
|
5646
|
+
return [
|
|
5647
|
+
fields.code,
|
|
5648
|
+
fields.type,
|
|
5649
|
+
fields.message,
|
|
5650
|
+
fields.error
|
|
5651
|
+
].some((value) => typeof value === "string" ? isContextOverflow(value) : value !== error && value !== void 0 && isContextOverflow(value));
|
|
5652
|
+
}
|
|
5653
|
+
/** Only request-rejection statuses can be reclassified as context overflow. */
|
|
5654
|
+
function isHttpContextOverflow(status, error) {
|
|
5655
|
+
return (status === 400 || status === 413 || status === 422) && isContextOverflow(error);
|
|
5656
|
+
}
|
|
5657
|
+
//#endregion
|
|
5632
5658
|
//#region src/host/common/brand-compat.ts
|
|
5633
5659
|
const toToolCallId = (id) => {
|
|
5634
5660
|
const mod = LlmModule;
|
|
@@ -6578,7 +6604,7 @@ async function* parseResponsesStream(response, signal, hiddenSandboxControls = /
|
|
|
6578
6604
|
const message = string(error?.message) ?? "Codex generation failed.";
|
|
6579
6605
|
const rawCode = string(error?.code)?.toLowerCase();
|
|
6580
6606
|
const isOverload = message.toLowerCase().includes("overload") || message.toLowerCase().includes("server error") || rawCode === "server_error" || rawCode === "service_unavailable" || rawCode === "internal_error";
|
|
6581
|
-
throw new LlmError(message, message.toLowerCase().includes("rate limit") || rawCode === "rate_limit" ? "RATE_LIMIT" : isOverload ? "SERVER_ERROR" : string(error?.code)?.toUpperCase() ?? "PROVIDER_ERROR");
|
|
6607
|
+
throw new LlmError(message, message.toLowerCase().includes("rate limit") || rawCode === "rate_limit" ? "RATE_LIMIT" : isOverload ? "SERVER_ERROR" : isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : string(error?.code)?.toUpperCase() ?? "PROVIDER_ERROR");
|
|
6582
6608
|
}
|
|
6583
6609
|
};
|
|
6584
6610
|
try {
|
|
@@ -6746,6 +6772,7 @@ async function responseError(response) {
|
|
|
6746
6772
|
...requestId ? { requestId: ProviderRequestId(requestId) } : {},
|
|
6747
6773
|
...response.status === 429 ? { providerRetryAfterMs: retryAfterMs$1(response.headers) } : {}
|
|
6748
6774
|
};
|
|
6775
|
+
if (isHttpContextOverflow(response.status, detail)) return new LlmError(`Codex context window exceeded: ${detail}`, CONTEXT_OVERFLOW_CODE, options);
|
|
6749
6776
|
if (response.status === 401) return new LlmError("ChatGPT sign-in has expired. Sign in again.", "AUTH", options);
|
|
6750
6777
|
if (response.status === 404) return new LlmError(`Codex model or resource not found (${response.status})${detail ? `: ${detail}` : "."}`, "NOT_FOUND", options);
|
|
6751
6778
|
if (response.status === 429) return new LlmError("Codex rate limit reached.", "RATE_LIMIT", options);
|
|
@@ -9142,6 +9169,8 @@ function processStreamLine$2(line, state) {
|
|
|
9142
9169
|
const chunk = safeJsonParse$5(json);
|
|
9143
9170
|
if (!isRecord$21(chunk)) return [];
|
|
9144
9171
|
const responseData = isRecord$21(chunk.response) ? chunk.response : chunk;
|
|
9172
|
+
const error = isRecord$21(chunk.error) ? chunk.error : isRecord$21(responseData.error) ? responseData.error : void 0;
|
|
9173
|
+
if (error !== void 0) throw new LlmError$1(`Antigravity stream error: ${asString$14(error.message) ?? "unknown error"}`, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
9145
9174
|
const candidates = Array.isArray(responseData.candidates) ? responseData.candidates : [];
|
|
9146
9175
|
const candidate = isRecord$21(candidates[0]) ? candidates[0] : void 0;
|
|
9147
9176
|
const content = isRecord$21(candidate?.content) ? candidate.content : void 0;
|
|
@@ -9663,7 +9692,7 @@ var AntigravityAdapter = class extends LlmAdapter {
|
|
|
9663
9692
|
const status = response?.status ?? 500;
|
|
9664
9693
|
const errText = await response?.text().catch(() => "");
|
|
9665
9694
|
if (status === 429) throw new LlmError(`Antigravity 账号配额已耗尽或请求受限 (429 RESOURCE_EXHAUSTED)。请在插件设置页查看配额剩余百分比及重置倒计时。原始响应: ${errText || "No response"}`, "RATE_LIMIT", { status: 429 });
|
|
9666
|
-
throw new LlmError(`Antigravity API error (${status}): ${errText || "No response"}`, "PROVIDER_ERROR", { status });
|
|
9695
|
+
throw new LlmError(`Antigravity API error (${status}): ${errText || "No response"}`, isHttpContextOverflow(status, errText) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR", { status });
|
|
9667
9696
|
}
|
|
9668
9697
|
if (!response.body) throw new LlmError("Antigravity returned empty response body", "PROVIDER_ERROR");
|
|
9669
9698
|
const reader = response.body.getReader();
|
|
@@ -9950,6 +9979,103 @@ function registerAntigravityRoutes(ctx, store, modelSettings, preferences, fetch
|
|
|
9950
9979
|
});
|
|
9951
9980
|
}
|
|
9952
9981
|
//#endregion
|
|
9982
|
+
//#region src/host/common/context-budget-fetch.ts
|
|
9983
|
+
/**
|
|
9984
|
+
* Recover a rejected input+output budget without dropping model-visible history.
|
|
9985
|
+
* Only explicit wire output controls and provider-confirmed counts qualify.
|
|
9986
|
+
* HTTP success/SSE, auth, quota, and byte-limit failures retain their old paths.
|
|
9987
|
+
*/
|
|
9988
|
+
function fetchWithContextBudgetRecovery(fetchFn) {
|
|
9989
|
+
return async (input, init) => {
|
|
9990
|
+
const response = await fetchFn(input, init);
|
|
9991
|
+
if (response.status !== 400 && response.status !== 422) return response;
|
|
9992
|
+
if (typeof init?.body !== "string") return response;
|
|
9993
|
+
let body;
|
|
9994
|
+
try {
|
|
9995
|
+
const parsed = JSON.parse(init.body);
|
|
9996
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return response;
|
|
9997
|
+
body = parsed;
|
|
9998
|
+
} catch {
|
|
9999
|
+
return response;
|
|
10000
|
+
}
|
|
10001
|
+
const keys = [
|
|
10002
|
+
"max_tokens",
|
|
10003
|
+
"max_completion_tokens",
|
|
10004
|
+
"max_output_tokens"
|
|
10005
|
+
].filter((key) => key in body);
|
|
10006
|
+
if (keys.length !== 1) return response;
|
|
10007
|
+
const key = keys[0];
|
|
10008
|
+
const requested = body[key];
|
|
10009
|
+
if (typeof requested !== "number" || !Number.isSafeInteger(requested) || requested <= 0) return response;
|
|
10010
|
+
const reduced = reducedOutputBudget(await boundedDiagnostic(response), requested);
|
|
10011
|
+
if (reduced === void 0) return response;
|
|
10012
|
+
const thinking = body.thinking;
|
|
10013
|
+
if (typeof thinking === "object" && thinking !== null) {
|
|
10014
|
+
const budget = thinking.budget_tokens;
|
|
10015
|
+
if (typeof budget === "number" && reduced <= budget) return response;
|
|
10016
|
+
}
|
|
10017
|
+
init.signal?.throwIfAborted();
|
|
10018
|
+
await response.body?.cancel().catch(() => void 0);
|
|
10019
|
+
return fetchFn(input, {
|
|
10020
|
+
...init,
|
|
10021
|
+
body: JSON.stringify({
|
|
10022
|
+
...body,
|
|
10023
|
+
[key]: reduced
|
|
10024
|
+
})
|
|
10025
|
+
});
|
|
10026
|
+
};
|
|
10027
|
+
}
|
|
10028
|
+
/** Read a bounded clone so a non-recoverable refusal remains readable by its owner. */
|
|
10029
|
+
async function boundedDiagnostic(response) {
|
|
10030
|
+
const reader = response.clone().body?.getReader();
|
|
10031
|
+
if (reader === void 0) return "";
|
|
10032
|
+
const decoder = new TextDecoder();
|
|
10033
|
+
let size = 0;
|
|
10034
|
+
let text = "";
|
|
10035
|
+
try {
|
|
10036
|
+
for (;;) {
|
|
10037
|
+
const { done, value } = await reader.read();
|
|
10038
|
+
if (done) return text + decoder.decode();
|
|
10039
|
+
size += value.byteLength;
|
|
10040
|
+
if (size > 16384) return "";
|
|
10041
|
+
text += decoder.decode(value, { stream: true });
|
|
10042
|
+
}
|
|
10043
|
+
} catch {
|
|
10044
|
+
return "";
|
|
10045
|
+
} finally {
|
|
10046
|
+
reader.cancel().catch(() => void 0);
|
|
10047
|
+
}
|
|
10048
|
+
}
|
|
10049
|
+
function diagnosticMessage(value, depth = 0) {
|
|
10050
|
+
if (depth > 4) return void 0;
|
|
10051
|
+
if (typeof value === "string") return value;
|
|
10052
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
10053
|
+
const fields = value;
|
|
10054
|
+
return diagnosticMessage(fields.error, depth + 1) ?? diagnosticMessage(fields.message, depth + 1);
|
|
10055
|
+
}
|
|
10056
|
+
/** Never infer capacity from a model name or from an echoed request. */
|
|
10057
|
+
function reducedOutputBudget(detail, requested) {
|
|
10058
|
+
let message;
|
|
10059
|
+
try {
|
|
10060
|
+
message = diagnosticMessage(JSON.parse(detail));
|
|
10061
|
+
} catch {
|
|
10062
|
+
message = detail;
|
|
10063
|
+
}
|
|
10064
|
+
if (message === void 0) return void 0;
|
|
10065
|
+
const match = /maximum context length is ([\d,]+) tokens[\s\S]*?requested ([\d,]+) tokens[\s\S]*?\(([\d,]+) in the messages, ([\d,]+) in the completion\)/i.exec(message);
|
|
10066
|
+
if (match === null) return void 0;
|
|
10067
|
+
const [window, total, prompt, completion] = match.slice(1).map((value) => Number(value.replaceAll(",", "")));
|
|
10068
|
+
if (![
|
|
10069
|
+
window,
|
|
10070
|
+
total,
|
|
10071
|
+
prompt,
|
|
10072
|
+
completion
|
|
10073
|
+
].every((value) => Number.isSafeInteger(value) && value > 0)) return void 0;
|
|
10074
|
+
if (completion !== requested || prompt + completion !== total || total <= window) return void 0;
|
|
10075
|
+
const available = window - prompt - 1024;
|
|
10076
|
+
return available >= 1024 && available < requested ? available : void 0;
|
|
10077
|
+
}
|
|
10078
|
+
//#endregion
|
|
9953
10079
|
//#region src/host/command-code/model-catalog.ts
|
|
9954
10080
|
/** Every model the Command Code registry describes, in registry order. */
|
|
9955
10081
|
const COMMAND_CODE_MODELS = [
|
|
@@ -13126,6 +13252,7 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
13126
13252
|
const chunk = safeJsonParse$4(payload);
|
|
13127
13253
|
if (!isRecord$19(chunk)) return [];
|
|
13128
13254
|
const out = [];
|
|
13255
|
+
if (isRecord$19(chunk.error)) throw new LlmError$1(`Command Code stream error: ${asString$12(chunk.error.message) ?? "unknown error"}`, isContextOverflow(chunk.error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
13129
13256
|
const usage = isRecord$19(chunk.usage) ? chunk.usage : void 0;
|
|
13130
13257
|
if (usage) {
|
|
13131
13258
|
state.sawUsage = true;
|
|
@@ -13395,7 +13522,10 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
13395
13522
|
state.done = true;
|
|
13396
13523
|
return closeStream$4(state);
|
|
13397
13524
|
}
|
|
13398
|
-
if (type === "error")
|
|
13525
|
+
if (type === "error") {
|
|
13526
|
+
const error = isRecord$19(event.error) ? event.error : {};
|
|
13527
|
+
throw new LlmError$1(`Command Code stream error: ${asString$12(error.message) ?? "unknown error"}`, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
13528
|
+
}
|
|
13399
13529
|
return out;
|
|
13400
13530
|
}
|
|
13401
13531
|
function tokenUsage$4(state) {
|
|
@@ -13506,7 +13636,7 @@ function processResponsesStreamLine(line, state) {
|
|
|
13506
13636
|
state.done = true;
|
|
13507
13637
|
const errorObj = isRecord$19(parsed.error) ? parsed.error : isRecord$19(parsed.response) && isRecord$19(parsed.response.error) ? parsed.response.error : null;
|
|
13508
13638
|
const detail = (typeof parsed.message === "string" ? parsed.message : "") || (errorObj && typeof errorObj.message === "string" ? errorObj.message : "") || (isRecord$19(parsed.response) && typeof parsed.response.error === "string" ? parsed.response.error : typeof parsed.error === "string" ? parsed.error : "");
|
|
13509
|
-
throw new LlmError$1(detail === "" ? "Command Code responses stream failed" : `Command Code responses stream failed: ${detail}`, "PROVIDER_ERROR");
|
|
13639
|
+
throw new LlmError$1(detail === "" ? "Command Code responses stream failed" : `Command Code responses stream failed: ${detail}`, isContextOverflow(errorObj ?? detail) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
13510
13640
|
}
|
|
13511
13641
|
return [];
|
|
13512
13642
|
}
|
|
@@ -14059,7 +14189,7 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
14059
14189
|
"anthropic-version": "2023-06-01"
|
|
14060
14190
|
} : baseHeaders;
|
|
14061
14191
|
try {
|
|
14062
|
-
response = await fetchFn(endpoint, {
|
|
14192
|
+
response = await fetchWithContextBudgetRecovery(fetchFn)(endpoint, {
|
|
14063
14193
|
method: "POST",
|
|
14064
14194
|
headers,
|
|
14065
14195
|
body,
|
|
@@ -14106,7 +14236,7 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
14106
14236
|
});
|
|
14107
14237
|
}
|
|
14108
14238
|
if (status >= 500) throw new LlmError(`${PROVIDER_NAME$5} upstream server error (${status}): ${detail || "No response"}`, "SERVER", { status });
|
|
14109
|
-
throw new LlmError(`${PROVIDER_NAME$5} API error (${status}): ${detail || "No response"}`, "PROVIDER_ERROR", { status });
|
|
14239
|
+
throw new LlmError(`${PROVIDER_NAME$5} API error (${status}): ${detail || "No response"}`, isHttpContextOverflow(status, detail) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR", { status });
|
|
14110
14240
|
}
|
|
14111
14241
|
if (response.body === null) throw new LlmError("Command Code returned an empty response body", "PROVIDER_ERROR");
|
|
14112
14242
|
const reader = response.body.getReader();
|
|
@@ -15860,16 +15990,57 @@ function accumulateToolCall(raw, pending, openaiShape) {
|
|
|
15860
15990
|
* making the line unusable.
|
|
15861
15991
|
*/
|
|
15862
15992
|
async function loadCatalog$1(fetchFn, credentials) {
|
|
15863
|
-
|
|
15864
|
-
|
|
15865
|
-
|
|
15866
|
-
|
|
15867
|
-
|
|
15868
|
-
|
|
15869
|
-
|
|
15870
|
-
|
|
15993
|
+
return (await fetchCatalog(fetchFn, credentials)).models;
|
|
15994
|
+
}
|
|
15995
|
+
/**
|
|
15996
|
+
* The same read as {@link loadCatalog}, keeping the reason it failed.
|
|
15997
|
+
*
|
|
15998
|
+
* Never throws, for the reason its wrapper has always given. What it adds is that
|
|
15999
|
+
* "failed" stops being one opaque state, so the settings card can name the
|
|
16000
|
+
* cause instead of asking the user to guess.
|
|
16001
|
+
*/
|
|
16002
|
+
async function fetchCatalog(fetchFn, credentials) {
|
|
16003
|
+
let response;
|
|
16004
|
+
try {
|
|
16005
|
+
response = await fetchFn(`${CLOUD_BASE_URL}${NATIVE_TAGS_PATH}`, {
|
|
16006
|
+
method: "GET",
|
|
16007
|
+
headers: headersFor(credentials, "application/json"),
|
|
16008
|
+
signal: AbortSignal.timeout(CATALOG_TIMEOUT_MS)
|
|
16009
|
+
});
|
|
16010
|
+
} catch {
|
|
16011
|
+
return {
|
|
16012
|
+
models: [],
|
|
16013
|
+
failure: "unreachable"
|
|
16014
|
+
};
|
|
16015
|
+
}
|
|
16016
|
+
if (!response.ok) return response.status === 401 || response.status === 403 ? {
|
|
16017
|
+
models: [],
|
|
16018
|
+
failure: "auth",
|
|
16019
|
+
status: response.status
|
|
16020
|
+
} : {
|
|
16021
|
+
models: [],
|
|
16022
|
+
failure: "upstream",
|
|
16023
|
+
status: response.status
|
|
16024
|
+
};
|
|
16025
|
+
let data;
|
|
16026
|
+
try {
|
|
16027
|
+
data = await response.json();
|
|
16028
|
+
} catch {
|
|
16029
|
+
return {
|
|
16030
|
+
models: [],
|
|
16031
|
+
failure: "malformed"
|
|
16032
|
+
};
|
|
16033
|
+
}
|
|
16034
|
+
if (typeof data !== "object" || data === null) return {
|
|
16035
|
+
models: [],
|
|
16036
|
+
failure: "malformed"
|
|
16037
|
+
};
|
|
15871
16038
|
const record = data;
|
|
15872
|
-
|
|
16039
|
+
if (!Array.isArray(record.models)) return {
|
|
16040
|
+
models: [],
|
|
16041
|
+
failure: "malformed"
|
|
16042
|
+
};
|
|
16043
|
+
const models = record.models;
|
|
15873
16044
|
const result = [];
|
|
15874
16045
|
for (const entry of models) {
|
|
15875
16046
|
if (typeof entry !== "object" || entry === null) continue;
|
|
@@ -15884,7 +16055,7 @@ async function loadCatalog$1(fetchFn, credentials) {
|
|
|
15884
16055
|
fetchedAt: Date.now()
|
|
15885
16056
|
});
|
|
15886
16057
|
}
|
|
15887
|
-
return result;
|
|
16058
|
+
return { models: result };
|
|
15888
16059
|
}
|
|
15889
16060
|
//#endregion
|
|
15890
16061
|
//#region src/host/ollama/mapper.ts
|
|
@@ -16482,6 +16653,8 @@ function textOf$4(content) {
|
|
|
16482
16653
|
//#endregion
|
|
16483
16654
|
//#region src/host/ollama/routes.ts
|
|
16484
16655
|
const ROUTE_PREFIX$3 = "/ollama/api";
|
|
16656
|
+
/** Where a user creates the keys this line stores. */
|
|
16657
|
+
const OLLAMA_KEYS_URL = "https://ollama.com/settings/keys";
|
|
16485
16658
|
function sendJson$5(response, status, body) {
|
|
16486
16659
|
const payload = JSON.stringify(body);
|
|
16487
16660
|
response.writeHead(status, { "content-type": "application/json; charset=utf-8" });
|
|
@@ -16507,6 +16680,22 @@ async function readRequestJson$5(request) {
|
|
|
16507
16680
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error("Request body must be a JSON object.");
|
|
16508
16681
|
return parsed;
|
|
16509
16682
|
}
|
|
16683
|
+
/**
|
|
16684
|
+
* The sentence the card shows for a catalog read that produced nothing.
|
|
16685
|
+
*
|
|
16686
|
+
* Every one of these used to collapse into "Could not read the model list from
|
|
16687
|
+
* Ollama", which told a user nothing they could act on — the complaint in issue
|
|
16688
|
+
* #36. The four causes have four different remedies, so they are named apart.
|
|
16689
|
+
*/
|
|
16690
|
+
function catalogFailureMessage(result) {
|
|
16691
|
+
switch (result.failure) {
|
|
16692
|
+
case "auth": return `Ollama rejected the stored API key (HTTP ${result.status ?? 401}). Create or re-paste a key at ${OLLAMA_KEYS_URL}.`;
|
|
16693
|
+
case "upstream": return `Ollama answered HTTP ${result.status ?? "?"} for ${CLOUD_BASE_URL}/api/tags.`;
|
|
16694
|
+
case "unreachable": return "Could not reach Ollama Cloud. Check the network or proxy, then sync again.";
|
|
16695
|
+
case "malformed": return "Ollama answered with something that is not a /api/tags document (a proxy or filter may be rewriting the reply).";
|
|
16696
|
+
default: return "Could not read the model list from Ollama.";
|
|
16697
|
+
}
|
|
16698
|
+
}
|
|
16510
16699
|
/** Whether one account can serve a request right now. */
|
|
16511
16700
|
function isUsable(account, now) {
|
|
16512
16701
|
if (account.authStatus !== void 0 && account.authStatus !== "ok") return false;
|
|
@@ -16557,123 +16746,144 @@ function registerOllamaRoutes(ctx, options) {
|
|
|
16557
16746
|
handler: async (request, response) => {
|
|
16558
16747
|
const path = new URL(request.url || "/", "http://dsh.local").pathname.replace(/^\/ollama\/api\/?/, "");
|
|
16559
16748
|
const method = request.method ?? "GET";
|
|
16560
|
-
|
|
16561
|
-
|
|
16562
|
-
value: await getOllamaWebStatus(options)
|
|
16563
|
-
});
|
|
16564
|
-
if (path === "accounts") {
|
|
16565
|
-
if (method === "GET") return sendJson$5(response, 200, {
|
|
16749
|
+
try {
|
|
16750
|
+
if (path === "" || path === "status") return sendJson$5(response, 200, {
|
|
16566
16751
|
ok: true,
|
|
16567
16752
|
value: await getOllamaWebStatus(options)
|
|
16568
16753
|
});
|
|
16569
|
-
if (
|
|
16570
|
-
|
|
16571
|
-
|
|
16572
|
-
|
|
16573
|
-
|
|
16574
|
-
|
|
16575
|
-
|
|
16576
|
-
body = await readRequestJson$5(request);
|
|
16577
|
-
} catch (error) {
|
|
16578
|
-
return sendJson$5(response, 400, {
|
|
16754
|
+
if (path === "accounts") {
|
|
16755
|
+
if (method === "GET") return sendJson$5(response, 200, {
|
|
16756
|
+
ok: true,
|
|
16757
|
+
value: await getOllamaWebStatus(options)
|
|
16758
|
+
});
|
|
16759
|
+
if (method !== "POST") return sendMethodNotAllowed$4(response);
|
|
16760
|
+
if (!isSameOriginMutation(request)) return sendJson$5(response, 403, {
|
|
16579
16761
|
ok: false,
|
|
16580
|
-
error:
|
|
16762
|
+
error: "Cross-origin request rejected."
|
|
16581
16763
|
});
|
|
16582
|
-
|
|
16583
|
-
|
|
16584
|
-
|
|
16585
|
-
|
|
16586
|
-
|
|
16587
|
-
const apiKey = typeof body.apiKey === "string" ? body.apiKey.trim() : "";
|
|
16588
|
-
if (apiKey === "") return sendJson$5(response, 400, {
|
|
16764
|
+
let body;
|
|
16765
|
+
try {
|
|
16766
|
+
body = await readRequestJson$5(request);
|
|
16767
|
+
} catch (error) {
|
|
16768
|
+
return sendJson$5(response, 400, {
|
|
16589
16769
|
ok: false,
|
|
16590
|
-
error:
|
|
16770
|
+
error: error instanceof Error ? error.message : String(error)
|
|
16591
16771
|
});
|
|
16592
|
-
|
|
16593
|
-
|
|
16594
|
-
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
|
|
16772
|
+
}
|
|
16773
|
+
const action = typeof body.action === "string" ? body.action : "";
|
|
16774
|
+
const accountId = typeof body.accountId === "string" ? body.accountId : void 0;
|
|
16775
|
+
try {
|
|
16776
|
+
if (action === "add") {
|
|
16777
|
+
const apiKey = typeof body.apiKey === "string" ? body.apiKey.trim() : "";
|
|
16778
|
+
if (apiKey === "") return sendJson$5(response, 400, {
|
|
16779
|
+
ok: false,
|
|
16780
|
+
error: "API key is required."
|
|
16781
|
+
});
|
|
16782
|
+
const alias = typeof body.alias === "string" && body.alias.trim() !== "" ? body.alias.trim() : void 0;
|
|
16783
|
+
const credentials = {
|
|
16784
|
+
apiKey,
|
|
16785
|
+
addedAt: Date.now()
|
|
16786
|
+
};
|
|
16787
|
+
if (alias !== void 0) credentials.alias = alias;
|
|
16788
|
+
return sendJson$5(response, 200, {
|
|
16789
|
+
ok: true,
|
|
16790
|
+
value: { id: (await accountPool.addAccount(credentials, alias)).id }
|
|
16791
|
+
});
|
|
16792
|
+
}
|
|
16793
|
+
if (accountId === void 0) return sendJson$5(response, 400, {
|
|
16794
|
+
ok: false,
|
|
16795
|
+
error: "accountId is required."
|
|
16796
|
+
});
|
|
16797
|
+
if (action === "set-primary") await accountPool.setPrimary(accountId);
|
|
16798
|
+
else if (action === "set-alias" && typeof body.alias === "string") await accountPool.setAlias(accountId, body.alias);
|
|
16799
|
+
else if (action === "delete") await accountPool.deleteAccount(accountId);
|
|
16800
|
+
else if (action === "clear-cooldown") await accountPool.clearCooldown(accountId);
|
|
16801
|
+
else if (action === "strategy" && (body.strategy === "sequential" || body.strategy === "round-robin" || body.strategy === "sticky")) await accountPool.setStrategy(body.strategy);
|
|
16802
|
+
else return sendJson$5(response, 400, {
|
|
16803
|
+
ok: false,
|
|
16804
|
+
error: "Unsupported account action."
|
|
16805
|
+
});
|
|
16806
|
+
} catch (error) {
|
|
16807
|
+
return sendJson$5(response, 400, {
|
|
16808
|
+
ok: false,
|
|
16809
|
+
error: error instanceof Error ? error.message : String(error)
|
|
16810
|
+
});
|
|
16811
|
+
}
|
|
16812
|
+
return sendJson$5(response, 200, {
|
|
16813
|
+
ok: true,
|
|
16814
|
+
value: await getOllamaWebStatus(options)
|
|
16815
|
+
});
|
|
16816
|
+
}
|
|
16817
|
+
if (path === "models") {
|
|
16818
|
+
if (method === "GET") {
|
|
16819
|
+
const settings = await modelSettings.read();
|
|
16598
16820
|
return sendJson$5(response, 200, {
|
|
16599
16821
|
ok: true,
|
|
16600
|
-
value: {
|
|
16822
|
+
value: {
|
|
16823
|
+
models: settings.catalogModels,
|
|
16824
|
+
enabled: settings.enabled,
|
|
16825
|
+
enabledModelIds: settings.enabledModelIds
|
|
16826
|
+
}
|
|
16601
16827
|
});
|
|
16602
16828
|
}
|
|
16603
|
-
if (
|
|
16829
|
+
if (method !== "POST") return sendMethodNotAllowed$4(response);
|
|
16830
|
+
if (!isSameOriginMutation(request)) return sendJson$5(response, 403, {
|
|
16604
16831
|
ok: false,
|
|
16605
|
-
error: "
|
|
16832
|
+
error: "Cross-origin request rejected."
|
|
16606
16833
|
});
|
|
16607
|
-
|
|
16608
|
-
|
|
16609
|
-
|
|
16610
|
-
|
|
16611
|
-
|
|
16612
|
-
|
|
16834
|
+
const body = await readRequestJson$5(request).catch(() => ({}));
|
|
16835
|
+
if (typeof body.enabled === "boolean") await modelSettings.update({ enabled: body.enabled });
|
|
16836
|
+
if (Array.isArray(body.enabledModelIds)) await modelSettings.update({ enabledModelIds: body.enabledModelIds.filter((id) => typeof id === "string") });
|
|
16837
|
+
return sendJson$5(response, 200, {
|
|
16838
|
+
ok: true,
|
|
16839
|
+
value: await modelSettings.read()
|
|
16840
|
+
});
|
|
16841
|
+
}
|
|
16842
|
+
if (path === "catalog/refresh") {
|
|
16843
|
+
if (method !== "POST") return sendMethodNotAllowed$4(response);
|
|
16844
|
+
if (!isSameOriginMutation(request)) return sendJson$5(response, 403, {
|
|
16613
16845
|
ok: false,
|
|
16614
|
-
error: "
|
|
16846
|
+
error: "Cross-origin request rejected."
|
|
16615
16847
|
});
|
|
16616
|
-
|
|
16617
|
-
|
|
16848
|
+
let credentials = null;
|
|
16849
|
+
let poolBusy = false;
|
|
16850
|
+
try {
|
|
16851
|
+
credentials = (await accountPool.getEffectiveCredential(void 0, fetchFn)).credentials;
|
|
16852
|
+
} catch {
|
|
16853
|
+
poolBusy = await accountPool.read().then((data) => data.accounts.length > 0 && data.accounts.every((account) => isUsable(account, Date.now()) === false)).catch(() => false);
|
|
16854
|
+
credentials = null;
|
|
16855
|
+
}
|
|
16856
|
+
if (credentials === null) return sendJson$5(response, 400, {
|
|
16618
16857
|
ok: false,
|
|
16619
|
-
error:
|
|
16858
|
+
error: poolBusy ? "Every stored Ollama key is cooling down right now. Wait for the cooldown, then sync again." : "Add an API key before syncing models."
|
|
16620
16859
|
});
|
|
16621
|
-
|
|
16622
|
-
|
|
16623
|
-
|
|
16624
|
-
|
|
16625
|
-
|
|
16626
|
-
|
|
16627
|
-
|
|
16628
|
-
|
|
16629
|
-
|
|
16860
|
+
const result = await fetchCatalog(fetchFn, credentials);
|
|
16861
|
+
if (result.models.length === 0) return sendJson$5(response, 502, {
|
|
16862
|
+
ok: false,
|
|
16863
|
+
error: catalogFailureMessage(result)
|
|
16864
|
+
});
|
|
16865
|
+
try {
|
|
16866
|
+
await modelSettings.storeCatalog(result.models);
|
|
16867
|
+
} catch (error) {
|
|
16868
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
16869
|
+
return sendJson$5(response, 500, {
|
|
16870
|
+
ok: false,
|
|
16871
|
+
error: `Read ${result.models.length} models from Ollama but could not save them locally: ${detail}`
|
|
16872
|
+
});
|
|
16873
|
+
}
|
|
16630
16874
|
return sendJson$5(response, 200, {
|
|
16631
16875
|
ok: true,
|
|
16632
|
-
value: {
|
|
16633
|
-
models: settings.catalogModels,
|
|
16634
|
-
enabled: settings.enabled,
|
|
16635
|
-
enabledModelIds: settings.enabledModelIds
|
|
16636
|
-
}
|
|
16876
|
+
value: { models: result.models }
|
|
16637
16877
|
});
|
|
16638
16878
|
}
|
|
16639
|
-
|
|
16640
|
-
if (!isSameOriginMutation(request)) return sendJson$5(response, 403, {
|
|
16641
|
-
ok: false,
|
|
16642
|
-
error: "Cross-origin request rejected."
|
|
16643
|
-
});
|
|
16644
|
-
const body = await readRequestJson$5(request).catch(() => ({}));
|
|
16645
|
-
if (typeof body.enabled === "boolean") await modelSettings.update({ enabled: body.enabled });
|
|
16646
|
-
if (Array.isArray(body.enabledModelIds)) await modelSettings.update({ enabledModelIds: body.enabledModelIds.filter((id) => typeof id === "string") });
|
|
16647
|
-
return sendJson$5(response, 200, {
|
|
16648
|
-
ok: true,
|
|
16649
|
-
value: await modelSettings.read()
|
|
16650
|
-
});
|
|
16651
|
-
}
|
|
16652
|
-
if (path === "catalog/refresh") {
|
|
16653
|
-
if (method !== "POST") return sendMethodNotAllowed$4(response);
|
|
16654
|
-
if (!isSameOriginMutation(request)) return sendJson$5(response, 403, {
|
|
16879
|
+
return sendJson$5(response, 404, {
|
|
16655
16880
|
ok: false,
|
|
16656
|
-
error: "
|
|
16657
|
-
});
|
|
16658
|
-
let credentials = null;
|
|
16659
|
-
try {
|
|
16660
|
-
credentials = (await accountPool.getEffectiveCredential(void 0, fetchFn)).credentials;
|
|
16661
|
-
} catch {
|
|
16662
|
-
credentials = null;
|
|
16663
|
-
}
|
|
16664
|
-
if (credentials === null) return sendJson$5(response, 400, {
|
|
16665
|
-
ok: false,
|
|
16666
|
-
error: "Add an API key before syncing models."
|
|
16881
|
+
error: "not-found"
|
|
16667
16882
|
});
|
|
16668
|
-
|
|
16669
|
-
|
|
16883
|
+
} catch (error) {
|
|
16884
|
+
return sendJson$5(response, 500, {
|
|
16670
16885
|
ok: false,
|
|
16671
|
-
error:
|
|
16672
|
-
});
|
|
16673
|
-
await modelSettings.storeCatalog(models);
|
|
16674
|
-
return sendJson$5(response, 200, {
|
|
16675
|
-
ok: true,
|
|
16676
|
-
value: { models }
|
|
16886
|
+
error: error instanceof Error ? error.message : String(error)
|
|
16677
16887
|
});
|
|
16678
16888
|
}
|
|
16679
16889
|
}
|
|
@@ -19810,7 +20020,20 @@ function estimatedInputTokens(options) {
|
|
|
19810
20020
|
characters += JSON.stringify(tool.parameters).length;
|
|
19811
20021
|
} catch {}
|
|
19812
20022
|
}
|
|
19813
|
-
|
|
20023
|
+
const contentCharacters = (content) => {
|
|
20024
|
+
if (!Array.isArray(content)) return typeof content === "string" ? content.length : 0;
|
|
20025
|
+
return content.reduce((total, block) => {
|
|
20026
|
+
if (!isRecord$16(block)) return total;
|
|
20027
|
+
if ((block.type === "text" || block.type === "reasoning") && typeof block.text === "string") return total + block.text.length;
|
|
20028
|
+
if (block.type === "tool-result") return total + contentCharacters(block.content);
|
|
20029
|
+
if (block.type === "tool-call") {
|
|
20030
|
+
const args = toolCallArguments$3(block.arguments);
|
|
20031
|
+
return total + String(block.name ?? "").length + args.length;
|
|
20032
|
+
}
|
|
20033
|
+
return total;
|
|
20034
|
+
}, 0);
|
|
20035
|
+
};
|
|
20036
|
+
for (const message of options.messages) characters += contentCharacters(message.content);
|
|
19814
20037
|
if (characters === 0) return void 0;
|
|
19815
20038
|
return Math.ceil(characters / 4);
|
|
19816
20039
|
}
|
|
@@ -20244,7 +20467,7 @@ function processOpenAIStreamLine(line, state) {
|
|
|
20244
20467
|
if (!isRecord$16(chunk)) return [];
|
|
20245
20468
|
const out = [];
|
|
20246
20469
|
const errorPayload = isRecord$16(chunk.error) ? chunk.error : void 0;
|
|
20247
|
-
if (errorPayload !== void 0) throw new LlmError$1(`Kimi Code stream error: ${asString$9(errorPayload.message) ?? "unknown error"}`, "PROVIDER_ERROR");
|
|
20470
|
+
if (errorPayload !== void 0) throw new LlmError$1(`Kimi Code stream error: ${asString$9(errorPayload.message) ?? "unknown error"}`, isContextOverflow(errorPayload) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
20248
20471
|
const usage = isRecord$16(chunk.usage) ? chunk.usage : void 0;
|
|
20249
20472
|
if (usage) {
|
|
20250
20473
|
state.sawUsage = true;
|
|
@@ -20511,7 +20734,10 @@ function processAnthropicStreamLine(line, state) {
|
|
|
20511
20734
|
state.done = true;
|
|
20512
20735
|
return closeStream$2(state);
|
|
20513
20736
|
}
|
|
20514
|
-
if (type === "error")
|
|
20737
|
+
if (type === "error") {
|
|
20738
|
+
const error = isRecord$16(event.error) ? event.error : {};
|
|
20739
|
+
throw new LlmError$1(`Kimi Code stream error: ${asString$9(error.message) ?? "unknown error"}`, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
20740
|
+
}
|
|
20515
20741
|
return out;
|
|
20516
20742
|
}
|
|
20517
20743
|
/**
|
|
@@ -20744,6 +20970,11 @@ function summarizeFailureBody$1(raw) {
|
|
|
20744
20970
|
*/
|
|
20745
20971
|
function classifyKimiFailure(status, bodyText) {
|
|
20746
20972
|
const detail = summarizeFailureBody$1(bodyText);
|
|
20973
|
+
if (isHttpContextOverflow(status, bodyText)) return {
|
|
20974
|
+
code: CONTEXT_OVERFLOW_CODE,
|
|
20975
|
+
retryable: false,
|
|
20976
|
+
message: `${PROVIDER_NAME$3} context window exceeded: ${detail}`
|
|
20977
|
+
};
|
|
20747
20978
|
if (status === 402) return {
|
|
20748
20979
|
code: "SERVER",
|
|
20749
20980
|
retryable: true,
|
|
@@ -20961,7 +21192,7 @@ var KimiCodeAdapter = class extends LlmAdapter {
|
|
|
20961
21192
|
const endpoint = wire === "anthropic" ? `${base}/v1/messages?beta=true` : `${base}/v1/chat/completions`;
|
|
20962
21193
|
const headers = await modelRequestHeaders$1(apiCredentials.accessToken, wire);
|
|
20963
21194
|
try {
|
|
20964
|
-
response = await fetchFn(endpoint, {
|
|
21195
|
+
response = await fetchWithContextBudgetRecovery(fetchFn)(endpoint, {
|
|
20965
21196
|
method: "POST",
|
|
20966
21197
|
headers,
|
|
20967
21198
|
body,
|
|
@@ -23379,7 +23610,10 @@ function processMinimaxStreamLine(line, state) {
|
|
|
23379
23610
|
state.done = true;
|
|
23380
23611
|
return closeMinimaxStream(state);
|
|
23381
23612
|
}
|
|
23382
|
-
if (type === "error")
|
|
23613
|
+
if (type === "error") {
|
|
23614
|
+
const error = isRecord$15(event.error) ? event.error : {};
|
|
23615
|
+
throw new LlmError$1("MiniMax Code(编程订阅) stream error: " + (asString$8(error.message) ?? "unknown error"), isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
23616
|
+
}
|
|
23383
23617
|
return out;
|
|
23384
23618
|
}
|
|
23385
23619
|
//#endregion
|
|
@@ -25407,6 +25641,11 @@ function matchesAny(text, patterns) {
|
|
|
25407
25641
|
*/
|
|
25408
25642
|
function classifyMinimaxFailure(status, bodyText) {
|
|
25409
25643
|
const detail = summarizeFailureBody(bodyText);
|
|
25644
|
+
if (isHttpContextOverflow(status, bodyText)) return {
|
|
25645
|
+
code: CONTEXT_OVERFLOW_CODE,
|
|
25646
|
+
retryable: false,
|
|
25647
|
+
message: `${PROVIDER_NAME$2} context window exceeded: ${detail}`
|
|
25648
|
+
};
|
|
25410
25649
|
if (status === 401 || status === 403) return {
|
|
25411
25650
|
code: "INVALID_CREDENTIAL",
|
|
25412
25651
|
retryable: false,
|
|
@@ -25670,7 +25909,7 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
25670
25909
|
let response;
|
|
25671
25910
|
for (let attempt = 0;; attempt += 1) {
|
|
25672
25911
|
try {
|
|
25673
|
-
response = await fetchFn(messagesUrl(credentials.region), {
|
|
25912
|
+
response = await fetchWithContextBudgetRecovery(fetchFn)(messagesUrl(credentials.region), {
|
|
25674
25913
|
method: "POST",
|
|
25675
25914
|
headers: modelRequestHeaders(credentials.accessToken),
|
|
25676
25915
|
body,
|
|
@@ -30052,7 +30291,7 @@ function processStreamLine$1(line, state) {
|
|
|
30052
30291
|
if (!isRecord$8(chunk)) return [];
|
|
30053
30292
|
const out = [];
|
|
30054
30293
|
const errorPayload = isRecord$8(chunk.error) ? chunk.error : void 0;
|
|
30055
|
-
if (errorPayload !== void 0) throw new LlmError$1(`WorkBuddy stream error: ${asString$4(errorPayload.message) ?? "unknown error"}`, "PROVIDER_ERROR");
|
|
30294
|
+
if (errorPayload !== void 0) throw new LlmError$1(`WorkBuddy stream error: ${asString$4(errorPayload.message) ?? "unknown error"}`, isContextOverflow(errorPayload) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
30056
30295
|
const usage = isRecord$8(chunk.usage) ? chunk.usage : void 0;
|
|
30057
30296
|
if (usage) {
|
|
30058
30297
|
state.sawUsage = true;
|
|
@@ -30410,7 +30649,7 @@ var WorkBuddyAdapter = class extends LlmAdapter {
|
|
|
30410
30649
|
credentials = effective.credentials;
|
|
30411
30650
|
}
|
|
30412
30651
|
try {
|
|
30413
|
-
response = await fetchFn(`${credentials.backend}${CHAT_PATH}`, {
|
|
30652
|
+
response = await fetchWithContextBudgetRecovery(fetchFn)(`${credentials.backend}${CHAT_PATH}`, {
|
|
30414
30653
|
method: "POST",
|
|
30415
30654
|
headers: workBuddyHeaders(credentials, { accept: "text/event-stream" }),
|
|
30416
30655
|
body,
|
|
@@ -30485,7 +30724,7 @@ function classifyFailure$1(status, detail, headers) {
|
|
|
30485
30724
|
if (code === 11135 || code === 11133) return new LlmError(`${PROVIDER_NAME$1} rejected the request parameters (${code}). An image may be unsupported by this model or unreadable.${detail ? ` ${detail}` : ""}`, "PROVIDER_ERROR", { status });
|
|
30486
30725
|
if (code === 11128) return new LlmError(`${PROVIDER_NAME$1} rejected the message history: the conversation must open with a system prompt.${detail ? ` ${detail}` : ""}`, "PROVIDER_ERROR", { status });
|
|
30487
30726
|
if (status >= 500 || code === 11134) return new LlmError(`${PROVIDER_NAME$1} upstream server error (${status}): ${detail || "No response"}`, "SERVER", { status });
|
|
30488
|
-
return new LlmError(`${PROVIDER_NAME$1} API error (${status}): ${detail || "No response"}`, "PROVIDER_ERROR", { status });
|
|
30727
|
+
return new LlmError(`${PROVIDER_NAME$1} API error (${status}): ${detail || "No response"}`, isHttpContextOverflow(status, detail) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR", { status });
|
|
30489
30728
|
}
|
|
30490
30729
|
/** Read the subscription's own numeric error code out of a response body. */
|
|
30491
30730
|
function readErrorCode(detail) {
|
|
@@ -35029,7 +35268,7 @@ function processStreamLine(line, state) {
|
|
|
35029
35268
|
const error = isRecord$5(event.error) ? event.error : {};
|
|
35030
35269
|
const message = asString$2(error.message) ?? "unknown error";
|
|
35031
35270
|
const kind = asString$2(error.type);
|
|
35032
|
-
throw new LlmError$1("Claude stream error" + (kind === void 0 ? "" : " (" + kind + ")") + ": " + message, "PROVIDER_ERROR");
|
|
35271
|
+
throw new LlmError$1("Claude stream error" + (kind === void 0 ? "" : " (" + kind + ")") + ": " + message, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
35033
35272
|
}
|
|
35034
35273
|
return out;
|
|
35035
35274
|
}
|
|
@@ -36558,7 +36797,7 @@ var ClaudeAdapter = class ClaudeAdapter extends LlmAdapter {
|
|
|
36558
36797
|
cacheTtl
|
|
36559
36798
|
});
|
|
36560
36799
|
try {
|
|
36561
|
-
return await fetchFn("https://api.anthropic.com/v1/messages?beta=true", {
|
|
36800
|
+
return await fetchWithContextBudgetRecovery(fetchFn)("https://api.anthropic.com/v1/messages?beta=true", {
|
|
36562
36801
|
method: "POST",
|
|
36563
36802
|
headers: buildClaudeHeaders(credentials.accessToken, {
|
|
36564
36803
|
model: requestOptions.model,
|
|
@@ -36754,6 +36993,7 @@ function toLlmError(failure) {
|
|
|
36754
36993
|
};
|
|
36755
36994
|
const detail = failure.message === "" ? "" : " " + failure.message;
|
|
36756
36995
|
if (failure.clientVersionTooOld) return new LlmError("Claude(订阅) refused this request because the client version it was told is below the server's floor (claude_code_version_too_old). Raise it with the DSH_CLAUDE_CLI_VERSION environment variable (or a setClaudeCliVersion pin), then retry — the stored sign-in is still valid." + detail, "PROVIDER_ERROR", options);
|
|
36996
|
+
if (failure.kind === "request" && isHttpContextOverflow(failure.status, failure.message)) return new LlmError("Claude(订阅) context window exceeded." + detail, CONTEXT_OVERFLOW_CODE, options);
|
|
36757
36997
|
switch (failure.kind) {
|
|
36758
36998
|
case "credential": return new LlmError("Claude(订阅) rejected the stored credential. Sign in again from Settings > Claude." + detail, "INVALID_CREDENTIAL", options);
|
|
36759
36999
|
case "rate_limit_account":
|