@eddyskywalker/dsh-chatgpt-subscription 0.10.21 → 0.11.2
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 +9 -0
- package/lib/client.js +53 -8
- package/lib/client.js.map +1 -1
- package/lib/index.js +2501 -305
- package/lib/types/client/command-code/CommandCodeSection.d.ts.map +1 -1
- package/lib/types/client/command-code/locales.d.ts +14 -2
- package/lib/types/client/command-code/locales.d.ts.map +1 -1
- package/lib/types/host/antigravity/mapper.d.ts.map +1 -1
- package/lib/types/host/antigravity/types.d.ts.map +1 -1
- package/lib/types/host/codex-account-pool.d.ts +2 -8
- package/lib/types/host/codex-account-pool.d.ts.map +1 -1
- package/lib/types/host/command-code/adapter.d.ts +19 -0
- package/lib/types/host/command-code/adapter.d.ts.map +1 -1
- package/lib/types/host/command-code/client.d.ts +4 -2
- package/lib/types/host/command-code/client.d.ts.map +1 -1
- package/lib/types/host/command-code/mapper.d.ts +11 -0
- package/lib/types/host/command-code/mapper.d.ts.map +1 -1
- package/lib/types/host/command-code/routes.d.ts +2 -0
- package/lib/types/host/command-code/routes.d.ts.map +1 -1
- package/lib/types/host/command-code/token-store.d.ts +7 -0
- package/lib/types/host/command-code/token-store.d.ts.map +1 -1
- package/lib/types/host/command-code/types.d.ts +15 -0
- package/lib/types/host/command-code/types.d.ts.map +1 -1
- package/lib/types/host/common/capabilities.d.ts +100 -0
- package/lib/types/host/common/capabilities.d.ts.map +1 -0
- package/lib/types/host/common/concurrency-gate.d.ts +46 -0
- package/lib/types/host/common/concurrency-gate.d.ts.map +1 -0
- package/lib/types/host/common/model-request-control.d.ts +21 -0
- package/lib/types/host/common/model-request-control.d.ts.map +1 -0
- package/lib/types/host/common/request-diagnostics.d.ts +79 -0
- package/lib/types/host/common/request-diagnostics.d.ts.map +1 -0
- package/lib/types/host/minimax-code/adapter.d.ts.map +1 -1
- package/lib/types/host/minimax-code/mapper.d.ts +32 -1
- package/lib/types/host/minimax-code/mapper.d.ts.map +1 -1
- package/lib/types/host/minimax-code/model-catalog.d.ts +7 -2
- package/lib/types/host/minimax-code/model-catalog.d.ts.map +1 -1
- package/lib/types/host/minimax-code/types.d.ts +12 -0
- package/lib/types/host/minimax-code/types.d.ts.map +1 -1
- package/lib/types/host/ollama/adapter.d.ts +18 -4
- package/lib/types/host/ollama/adapter.d.ts.map +1 -1
- package/lib/types/host/ollama/client.d.ts +14 -0
- package/lib/types/host/ollama/client.d.ts.map +1 -1
- package/lib/types/host/ollama/mapper.d.ts +5 -0
- package/lib/types/host/ollama/mapper.d.ts.map +1 -1
- package/lib/types/host/ollama/types.d.ts +23 -0
- package/lib/types/host/ollama/types.d.ts.map +1 -1
- package/lib/types/host/responses-client.d.ts +27 -10
- package/lib/types/host/responses-client.d.ts.map +1 -1
- package/lib/types/host/wire-auth.d.ts +19 -5
- package/lib/types/host/wire-auth.d.ts.map +1 -1
- package/lib/types/host/workbuddy/mapper.d.ts +1 -0
- package/lib/types/host/workbuddy/mapper.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/command-code-contracts.d.ts +15 -2
- package/lib/types/shared/command-code-contracts.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { HarnessError, LlmAdapter, LlmError, LlmError as LlmError$1, ProviderReq
|
|
|
5
5
|
import fs, { chmod, lstat, mkdir, open, readFile, rename, stat, unlink } from "node:fs/promises";
|
|
6
6
|
import path, { basename, dirname, join, relative, resolve } from "node:path";
|
|
7
7
|
import os, { homedir } from "node:os";
|
|
8
|
-
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
8
|
+
import { createHash, createHmac, randomBytes, randomUUID } from "node:crypto";
|
|
9
9
|
import { isDeepStrictEqual } from "node:util";
|
|
10
10
|
import { execSync, spawn } from "node:child_process";
|
|
11
11
|
import fs$1, { appendFileSync, constants, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, utimesSync, writeFileSync } from "node:fs";
|
|
@@ -612,10 +612,16 @@ async function rehydrateCatalogCache(name, parseModels, accept, currentFetchedAt
|
|
|
612
612
|
/**
|
|
613
613
|
* Turn-state header the Codex backend hands back on a responses response.
|
|
614
614
|
*
|
|
615
|
-
* The official CLI reads it and echoes it on the next request
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
*
|
|
615
|
+
* The official CLI reads it and echoes it on the SAME TURN's next request — a
|
|
616
|
+
* retry, an incremental append or a continuation — and the backend uses it to
|
|
617
|
+
* resume instead of re-ingesting the whole history.
|
|
618
|
+
*
|
|
619
|
+
* Its scope is exactly one turn. The official client builds a fresh per-turn
|
|
620
|
+
* session and documents that reusing one across turns violates the
|
|
621
|
+
* client/server contract and can cause routing bugs; the token is also
|
|
622
|
+
* account-scoped and is discarded when auth ownership changes. It is opaque,
|
|
623
|
+
* short-lived, and threaded through rather than computed (see
|
|
624
|
+
* `responses-client.ts`).
|
|
619
625
|
*/
|
|
620
626
|
const CODEX_TURN_STATE_HEADER = "x-codex-turn-state";
|
|
621
627
|
function codexHeaders(credentials, sessionId, options = {}) {
|
|
@@ -630,6 +636,16 @@ function codexHeaders(credentials, sessionId, options = {}) {
|
|
|
630
636
|
...options.turnState ? { [CODEX_TURN_STATE_HEADER]: options.turnState } : {}
|
|
631
637
|
};
|
|
632
638
|
}
|
|
639
|
+
/**
|
|
640
|
+
* Opaque local identity of whoever signs a request.
|
|
641
|
+
*
|
|
642
|
+
* Turn state is account-scoped, so the client has to detect when the signer
|
|
643
|
+
* changed without ever putting that fact on the wire. The digest is computed
|
|
644
|
+
* and compared locally: it is not a header, not a credential, and never logged.
|
|
645
|
+
*/
|
|
646
|
+
function authOwnerKey(credentials) {
|
|
647
|
+
return createHash("sha256").update(credentials.accountId ?? "").update("\0").update(credentials.accessToken).digest("hex").slice(0, 32);
|
|
648
|
+
}
|
|
633
649
|
function stableSessionId(value) {
|
|
634
650
|
const source = value === void 0 || value === "" ? randomUUID() : value;
|
|
635
651
|
return `dsh-${createHash("sha256").update(source).digest("hex").slice(0, 32)}`;
|
|
@@ -775,7 +791,7 @@ function parseListing(payload) {
|
|
|
775
791
|
function parseListingEntry$1(value) {
|
|
776
792
|
const record = asRecord$10(value);
|
|
777
793
|
if (record === void 0) return [];
|
|
778
|
-
const id = asString$
|
|
794
|
+
const id = asString$15(record.slug) ?? asString$15(record.id);
|
|
779
795
|
if (id === void 0) return [];
|
|
780
796
|
const contextWindow = asNumber$4(record.context_window) ?? asNumber$4(record.contextWindow);
|
|
781
797
|
const modalities = parseModalities(record.input_modalities);
|
|
@@ -783,18 +799,18 @@ function parseListingEntry$1(value) {
|
|
|
783
799
|
const fallback = CODEX_MODEL_CATALOG.find((entry) => entry.id === id);
|
|
784
800
|
return [{
|
|
785
801
|
id,
|
|
786
|
-
name: asString$
|
|
802
|
+
name: asString$15(record.display_name) ?? asString$15(record.displayName) ?? fallback?.name ?? id,
|
|
787
803
|
contextWindow: contextWindow !== void 0 && contextWindow > 0 ? contextWindow : null,
|
|
788
804
|
inputModalities: modalities ?? (fallback ? [...fallback.inputModalities] : ["text"]),
|
|
789
805
|
...efforts !== null ? { reasoningEfforts: efforts } : {},
|
|
790
|
-
defaultReasoningEffort: asString$
|
|
806
|
+
defaultReasoningEffort: asString$15(record.default_reasoning_level) ?? fallback?.defaultReasoningEffort ?? null
|
|
791
807
|
}];
|
|
792
808
|
}
|
|
793
809
|
function parseModalities(value) {
|
|
794
810
|
if (!Array.isArray(value)) return null;
|
|
795
811
|
const out = [];
|
|
796
812
|
for (const item of value) {
|
|
797
|
-
const name = asString$
|
|
813
|
+
const name = asString$15(item);
|
|
798
814
|
if (name === "text" || name === "image") out.push(name);
|
|
799
815
|
}
|
|
800
816
|
return out.length > 0 ? out : null;
|
|
@@ -809,7 +825,7 @@ function parseEfforts(value) {
|
|
|
809
825
|
if (!Array.isArray(value)) return null;
|
|
810
826
|
const out = [];
|
|
811
827
|
for (const item of value) {
|
|
812
|
-
const effort = asString$
|
|
828
|
+
const effort = asString$15(item) ?? asString$15(asRecord$10(item)?.effort);
|
|
813
829
|
if (effort !== void 0 && !out.includes(effort)) out.push(effort);
|
|
814
830
|
}
|
|
815
831
|
return out.length > 0 ? out : null;
|
|
@@ -827,7 +843,7 @@ function accountKeyFor$1(credentials) {
|
|
|
827
843
|
function asRecord$10(value) {
|
|
828
844
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
829
845
|
}
|
|
830
|
-
function asString$
|
|
846
|
+
function asString$15(value) {
|
|
831
847
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
832
848
|
}
|
|
833
849
|
function asNumber$4(value) {
|
|
@@ -2072,6 +2088,104 @@ function createPlatformTokenStore(platform = process.platform) {
|
|
|
2072
2088
|
throw new Error(`Unsupported platform ${platform}; dsh-chatgpt-subscription supports Windows, macOS, and Linux.`);
|
|
2073
2089
|
}
|
|
2074
2090
|
//#endregion
|
|
2091
|
+
//#region src/host/common/concurrency-gate.ts
|
|
2092
|
+
var ConcurrencyGate = class {
|
|
2093
|
+
held = /* @__PURE__ */ new Map();
|
|
2094
|
+
queues = /* @__PURE__ */ new Map();
|
|
2095
|
+
limits = /* @__PURE__ */ new Map();
|
|
2096
|
+
/**
|
|
2097
|
+
* Record the concurrency limit for one account.
|
|
2098
|
+
*
|
|
2099
|
+
* A non-positive or non-finite limit clears the cap, which is the same as
|
|
2100
|
+
* never having set one: requests then pass through unbounded rather than
|
|
2101
|
+
* being blocked by a value nobody verified.
|
|
2102
|
+
*/
|
|
2103
|
+
setLimit(accountId, limit) {
|
|
2104
|
+
if (!Number.isFinite(limit) || limit <= 0) {
|
|
2105
|
+
this.limits.delete(accountId);
|
|
2106
|
+
this.drain(accountId);
|
|
2107
|
+
return;
|
|
2108
|
+
}
|
|
2109
|
+
this.limits.set(accountId, Math.max(1, Math.floor(limit)));
|
|
2110
|
+
this.drain(accountId);
|
|
2111
|
+
}
|
|
2112
|
+
/** Limit currently in force for one account, or undefined when uncapped. */
|
|
2113
|
+
limitFor(accountId) {
|
|
2114
|
+
return this.limits.get(accountId);
|
|
2115
|
+
}
|
|
2116
|
+
/** Requests currently in flight for one account. */
|
|
2117
|
+
inFlight(accountId) {
|
|
2118
|
+
return this.held.get(accountId) ?? 0;
|
|
2119
|
+
}
|
|
2120
|
+
/**
|
|
2121
|
+
* Take one slot, waiting for it when the account is at its limit.
|
|
2122
|
+
*
|
|
2123
|
+
* The returned function releases the slot and is safe to call more than once:
|
|
2124
|
+
* a double release on an aborted request must not hand a stranger a slot that
|
|
2125
|
+
* this holder never had.
|
|
2126
|
+
*/
|
|
2127
|
+
async acquire(accountId, signal) {
|
|
2128
|
+
if (signal?.aborted === true) throw signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
2129
|
+
const limit = this.limits.get(accountId);
|
|
2130
|
+
const current = this.held.get(accountId) ?? 0;
|
|
2131
|
+
if (limit === void 0 || current < limit) return this.take(accountId);
|
|
2132
|
+
await new Promise((resolve, reject) => {
|
|
2133
|
+
const queue = this.queues.get(accountId) ?? [];
|
|
2134
|
+
const waiter = { resolve: () => {
|
|
2135
|
+
remove();
|
|
2136
|
+
resolve();
|
|
2137
|
+
} };
|
|
2138
|
+
const onAbort = () => {
|
|
2139
|
+
remove();
|
|
2140
|
+
reject(signal?.reason ?? new DOMException("Aborted", "AbortError"));
|
|
2141
|
+
};
|
|
2142
|
+
const remove = () => {
|
|
2143
|
+
const index = queue.indexOf(waiter);
|
|
2144
|
+
if (index !== -1) queue.splice(index, 1);
|
|
2145
|
+
if (queue.length === 0) this.queues.delete(accountId);
|
|
2146
|
+
signal?.removeEventListener("abort", onAbort);
|
|
2147
|
+
};
|
|
2148
|
+
queue.push(waiter);
|
|
2149
|
+
this.queues.set(accountId, queue);
|
|
2150
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2151
|
+
});
|
|
2152
|
+
const release = this.releaseFn(accountId);
|
|
2153
|
+
if (signal?.aborted) {
|
|
2154
|
+
release();
|
|
2155
|
+
throw signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
2156
|
+
}
|
|
2157
|
+
return release;
|
|
2158
|
+
}
|
|
2159
|
+
take(accountId) {
|
|
2160
|
+
this.held.set(accountId, (this.held.get(accountId) ?? 0) + 1);
|
|
2161
|
+
return this.releaseFn(accountId);
|
|
2162
|
+
}
|
|
2163
|
+
releaseFn(accountId) {
|
|
2164
|
+
let released = false;
|
|
2165
|
+
return () => {
|
|
2166
|
+
if (released) return;
|
|
2167
|
+
released = true;
|
|
2168
|
+
const next = (this.held.get(accountId) ?? 1) - 1;
|
|
2169
|
+
if (next <= 0) this.held.delete(accountId);
|
|
2170
|
+
else this.held.set(accountId, next);
|
|
2171
|
+
this.drain(accountId);
|
|
2172
|
+
};
|
|
2173
|
+
}
|
|
2174
|
+
/** Hand slots to as many waiters as the current limit allows. */
|
|
2175
|
+
drain(accountId) {
|
|
2176
|
+
const queue = this.queues.get(accountId);
|
|
2177
|
+
if (queue === void 0 || queue.length === 0) return;
|
|
2178
|
+
const limit = this.limits.get(accountId);
|
|
2179
|
+
const room = limit === void 0 ? queue.length : limit - (this.held.get(accountId) ?? 0);
|
|
2180
|
+
for (let index = 0; index < room && queue.length > 0; index++) {
|
|
2181
|
+
const waiter = queue.shift();
|
|
2182
|
+
this.held.set(accountId, (this.held.get(accountId) ?? 0) + 1);
|
|
2183
|
+
waiter.resolve();
|
|
2184
|
+
}
|
|
2185
|
+
if (queue.length === 0) this.queues.delete(accountId);
|
|
2186
|
+
}
|
|
2187
|
+
};
|
|
2188
|
+
//#endregion
|
|
2075
2189
|
//#region src/host/callback-server.ts
|
|
2076
2190
|
/** One-shot localhost OAuth callback listener. */
|
|
2077
2191
|
var OAuthCallbackServer = class {
|
|
@@ -2750,6 +2864,17 @@ function parseCodexPoolData(value) {
|
|
|
2750
2864
|
* hooks the core cannot know — how to refresh one account's tokens and which
|
|
2751
2865
|
* accounts a cached quota window already rules out.
|
|
2752
2866
|
*/
|
|
2867
|
+
/**
|
|
2868
|
+
* Per-account in-flight requests, shared by every ChatGPT request this host
|
|
2869
|
+
* makes. A fan-out of subagents is what reaches a plan's concurrency bound, so
|
|
2870
|
+
* the bound is enforced here rather than discovered by cooling every account at
|
|
2871
|
+
* once. Limits are learned from upstream evidence (see
|
|
2872
|
+
* {@link CodexAccountPool.noteConcurrencySignal}), never assumed.
|
|
2873
|
+
*/
|
|
2874
|
+
const concurrency = new ConcurrencyGate();
|
|
2875
|
+
function chatGPTConcurrency() {
|
|
2876
|
+
return concurrency;
|
|
2877
|
+
}
|
|
2753
2878
|
var CodexAccountPool = class extends AccountPoolCore {
|
|
2754
2879
|
refresherRef;
|
|
2755
2880
|
store;
|
|
@@ -3156,13 +3281,13 @@ function createCodexFetchProvider(options = {}) {
|
|
|
3156
3281
|
//#region src/host/common/llm-compat.ts
|
|
3157
3282
|
/** This package's kind in the harness message-source map. */
|
|
3158
3283
|
const PLUGIN_MESSAGE_SOURCE_KIND = "dsh-chatgpt-subscription";
|
|
3159
|
-
function isRecord$
|
|
3284
|
+
function isRecord$24(value) {
|
|
3160
3285
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3161
3286
|
}
|
|
3162
3287
|
/** Read a message body's blocks, keeping every entry that carries a block tag. */
|
|
3163
3288
|
function readBlocks(raw) {
|
|
3164
3289
|
if (!Array.isArray(raw)) return [];
|
|
3165
|
-
return raw.filter((block) => isRecord$
|
|
3290
|
+
return raw.filter((block) => isRecord$24(block) && typeof block.type === "string");
|
|
3166
3291
|
}
|
|
3167
3292
|
/**
|
|
3168
3293
|
* Normalize one harness message list into {@link Message}.
|
|
@@ -3177,10 +3302,10 @@ function readBlocks(raw) {
|
|
|
3177
3302
|
function normalizeMessages(messages) {
|
|
3178
3303
|
const normalized = [];
|
|
3179
3304
|
for (const raw of messages ?? []) {
|
|
3180
|
-
if (!isRecord$
|
|
3305
|
+
if (!isRecord$24(raw)) continue;
|
|
3181
3306
|
const content = readBlocks(raw.content);
|
|
3182
3307
|
if (raw.role === "tool") {
|
|
3183
|
-
const source = isRecord$
|
|
3308
|
+
const source = isRecord$24(raw.source) ? raw.source : void 0;
|
|
3184
3309
|
const callId = String(raw.toolCallId ?? source?.callId ?? "");
|
|
3185
3310
|
normalized.push({
|
|
3186
3311
|
id: raw.id,
|
|
@@ -3202,7 +3327,7 @@ function normalizeMessages(messages) {
|
|
|
3202
3327
|
id: raw.id,
|
|
3203
3328
|
role: typeof raw.role === "string" ? raw.role : "user",
|
|
3204
3329
|
content,
|
|
3205
|
-
...isRecord$
|
|
3330
|
+
...isRecord$24(raw.source) ? { source: raw.source } : {}
|
|
3206
3331
|
});
|
|
3207
3332
|
}
|
|
3208
3333
|
return normalized;
|
|
@@ -3744,6 +3869,666 @@ var ProxyManager = class {
|
|
|
3744
3869
|
}
|
|
3745
3870
|
};
|
|
3746
3871
|
//#endregion
|
|
3872
|
+
//#region src/host/common/model-request-control.ts
|
|
3873
|
+
const CONTROLLED_PROVIDERS = [
|
|
3874
|
+
"codex-chatgpt",
|
|
3875
|
+
"claude",
|
|
3876
|
+
"antigravity",
|
|
3877
|
+
"kimi-code",
|
|
3878
|
+
"minimax-code",
|
|
3879
|
+
"command-code",
|
|
3880
|
+
"workbuddy",
|
|
3881
|
+
"ollama"
|
|
3882
|
+
];
|
|
3883
|
+
/** Explicit deployment configuration. Invalid values fail closed at startup. */
|
|
3884
|
+
function readModelRequestLimits(env = process.env) {
|
|
3885
|
+
const raw = env.DSH_PROVIDER_CONCURRENCY;
|
|
3886
|
+
if (!raw) return {};
|
|
3887
|
+
let value;
|
|
3888
|
+
try {
|
|
3889
|
+
value = JSON.parse(raw);
|
|
3890
|
+
} catch {
|
|
3891
|
+
throw new Error("DSH_PROVIDER_CONCURRENCY must be a JSON object");
|
|
3892
|
+
}
|
|
3893
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("DSH_PROVIDER_CONCURRENCY must be a JSON object");
|
|
3894
|
+
const input = value;
|
|
3895
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
3896
|
+
"default",
|
|
3897
|
+
"queueTimeoutMs",
|
|
3898
|
+
...CONTROLLED_PROVIDERS
|
|
3899
|
+
]);
|
|
3900
|
+
for (const key of Object.keys(input)) if (!allowed.has(key)) throw new Error("Unknown DSH_PROVIDER_CONCURRENCY field");
|
|
3901
|
+
const number = (key, max) => {
|
|
3902
|
+
const n = input[key];
|
|
3903
|
+
if (n === void 0) return void 0;
|
|
3904
|
+
if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 0 || n > max) throw new Error("Invalid DSH_PROVIDER_CONCURRENCY numeric value");
|
|
3905
|
+
return n;
|
|
3906
|
+
};
|
|
3907
|
+
const providers = {};
|
|
3908
|
+
for (const provider of CONTROLLED_PROVIDERS) {
|
|
3909
|
+
const limit = number(provider, 1e4);
|
|
3910
|
+
if (limit !== void 0) providers[provider] = limit;
|
|
3911
|
+
}
|
|
3912
|
+
return {
|
|
3913
|
+
default: number("default", 1e4),
|
|
3914
|
+
queueTimeoutMs: number("queueTimeoutMs", 36e5),
|
|
3915
|
+
providers
|
|
3916
|
+
};
|
|
3917
|
+
}
|
|
3918
|
+
/** Only generation POSTs are limited; token refresh/catalog/quota must never wait behind them. */
|
|
3919
|
+
function isModelRequest(input, init) {
|
|
3920
|
+
if ((init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase() !== "POST") return false;
|
|
3921
|
+
let path;
|
|
3922
|
+
try {
|
|
3923
|
+
path = new URL(input instanceof Request ? input.url : String(input)).pathname;
|
|
3924
|
+
} catch {
|
|
3925
|
+
return false;
|
|
3926
|
+
}
|
|
3927
|
+
return [
|
|
3928
|
+
"/responses",
|
|
3929
|
+
"/messages",
|
|
3930
|
+
"/chat/completions",
|
|
3931
|
+
"/api/chat"
|
|
3932
|
+
].some((suffix) => path.endsWith(suffix)) || /:(?:streamGenerateContent|generateContent)$/.test(path);
|
|
3933
|
+
}
|
|
3934
|
+
/** Hold a slot until EOF, cancel, abort or failure, never merely until response headers. */
|
|
3935
|
+
function createControlledModelFetch(baseFetch, options) {
|
|
3936
|
+
const gate = options.gate ?? new ConcurrencyGate();
|
|
3937
|
+
const limit = options.limits.providers?.[options.provider] ?? options.limits.default ?? 0;
|
|
3938
|
+
if (!Number.isSafeInteger(limit) || limit < 0) throw new Error("Invalid provider concurrency limit");
|
|
3939
|
+
if (limit === 0) return baseFetch;
|
|
3940
|
+
return async (input, init) => {
|
|
3941
|
+
if (!isModelRequest(input, init)) return baseFetch(input, init);
|
|
3942
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
|
|
3943
|
+
const credential = headers.get("authorization") ?? headers.get("x-api-key") ?? "";
|
|
3944
|
+
const key = options.provider + ":" + createHash("sha256").update(credential).digest("hex");
|
|
3945
|
+
gate.setLimit(key, limit);
|
|
3946
|
+
const signal = init?.signal ?? (input instanceof Request ? input.signal : void 0);
|
|
3947
|
+
const queued = new AbortController();
|
|
3948
|
+
const abortQueue = () => queued.abort(signal?.reason ?? new DOMException("Aborted", "AbortError"));
|
|
3949
|
+
signal?.addEventListener("abort", abortQueue, { once: true });
|
|
3950
|
+
if (signal?.aborted) abortQueue();
|
|
3951
|
+
const timeout = options.limits.queueTimeoutMs ?? 12e4;
|
|
3952
|
+
const timer = timeout > 0 ? setTimeout(() => queued.abort(new DOMException("Provider concurrency queue timed out", "TimeoutError")), timeout) : void 0;
|
|
3953
|
+
let release;
|
|
3954
|
+
try {
|
|
3955
|
+
release = await gate.acquire(key, queued.signal);
|
|
3956
|
+
} finally {
|
|
3957
|
+
if (timer) clearTimeout(timer);
|
|
3958
|
+
signal?.removeEventListener("abort", abortQueue);
|
|
3959
|
+
if (gate.inFlight(key) === 0) gate.setLimit(key, 0);
|
|
3960
|
+
}
|
|
3961
|
+
let done = false;
|
|
3962
|
+
let reader;
|
|
3963
|
+
let controller;
|
|
3964
|
+
const finish = () => {
|
|
3965
|
+
if (done) return;
|
|
3966
|
+
done = true;
|
|
3967
|
+
signal?.removeEventListener("abort", abort);
|
|
3968
|
+
release();
|
|
3969
|
+
if (gate.inFlight(key) === 0) gate.setLimit(key, 0);
|
|
3970
|
+
};
|
|
3971
|
+
const abort = () => {
|
|
3972
|
+
const reason = signal?.reason ?? new DOMException("Aborted", "AbortError");
|
|
3973
|
+
finish();
|
|
3974
|
+
if (reader) reader.cancel(reason).catch(() => void 0).finally(() => {
|
|
3975
|
+
try {
|
|
3976
|
+
reader?.releaseLock();
|
|
3977
|
+
} catch {}
|
|
3978
|
+
});
|
|
3979
|
+
try {
|
|
3980
|
+
controller?.error(reason);
|
|
3981
|
+
} catch {}
|
|
3982
|
+
};
|
|
3983
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
3984
|
+
try {
|
|
3985
|
+
if (signal?.aborted) {
|
|
3986
|
+
abort();
|
|
3987
|
+
throw signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
3988
|
+
}
|
|
3989
|
+
const response = await baseFetch(input, init);
|
|
3990
|
+
if (done) {
|
|
3991
|
+
response.body?.cancel().catch(() => void 0);
|
|
3992
|
+
throw signal?.reason ?? new DOMException("Aborted", "AbortError");
|
|
3993
|
+
}
|
|
3994
|
+
if (!response.body) {
|
|
3995
|
+
finish();
|
|
3996
|
+
return response;
|
|
3997
|
+
}
|
|
3998
|
+
reader = response.body.getReader();
|
|
3999
|
+
const body = new ReadableStream({
|
|
4000
|
+
start(c) {
|
|
4001
|
+
controller = c;
|
|
4002
|
+
},
|
|
4003
|
+
async pull(c) {
|
|
4004
|
+
try {
|
|
4005
|
+
const chunk = await reader.read();
|
|
4006
|
+
if (done) return;
|
|
4007
|
+
if (chunk.done) {
|
|
4008
|
+
finish();
|
|
4009
|
+
reader.releaseLock();
|
|
4010
|
+
c.close();
|
|
4011
|
+
} else c.enqueue(chunk.value);
|
|
4012
|
+
} catch (error) {
|
|
4013
|
+
finish();
|
|
4014
|
+
try {
|
|
4015
|
+
reader.releaseLock();
|
|
4016
|
+
} catch {}
|
|
4017
|
+
c.error(error);
|
|
4018
|
+
}
|
|
4019
|
+
},
|
|
4020
|
+
async cancel(reason) {
|
|
4021
|
+
finish();
|
|
4022
|
+
try {
|
|
4023
|
+
await reader.cancel(reason);
|
|
4024
|
+
} finally {
|
|
4025
|
+
reader.releaseLock();
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
}, { highWaterMark: 0 });
|
|
4029
|
+
const wrapped = new Response(body, {
|
|
4030
|
+
status: response.status,
|
|
4031
|
+
statusText: response.statusText,
|
|
4032
|
+
headers: response.headers
|
|
4033
|
+
});
|
|
4034
|
+
for (const name of [
|
|
4035
|
+
"url",
|
|
4036
|
+
"redirected",
|
|
4037
|
+
"type"
|
|
4038
|
+
]) Object.defineProperty(wrapped, name, { value: response[name] });
|
|
4039
|
+
return wrapped;
|
|
4040
|
+
} catch (error) {
|
|
4041
|
+
finish();
|
|
4042
|
+
throw error;
|
|
4043
|
+
}
|
|
4044
|
+
};
|
|
4045
|
+
}
|
|
4046
|
+
//#endregion
|
|
4047
|
+
//#region src/host/common/request-diagnostics.ts
|
|
4048
|
+
/**
|
|
4049
|
+
* Reusable request diagnostics wrapper for model provider calls.
|
|
4050
|
+
*
|
|
4051
|
+
* Implements W5 usage, latency, and transport diagnostics:
|
|
4052
|
+
* - First-byte chunk latency (firstByteMs) and total duration
|
|
4053
|
+
* - Request payload bytes (null when unknown stream, not 0)
|
|
4054
|
+
* - Safe runtime-validated enum-only endpoint and provider classification
|
|
4055
|
+
* - Ephemeral keyed-HMAC fingerprints scoped per provider+endpoint
|
|
4056
|
+
* - Disjoint token usage mapping with missing vs zero differentiation and endpoint-awareness
|
|
4057
|
+
* - Complete SSE line and NDJSON streaming parser merging start/delta usage
|
|
4058
|
+
* - Stream proxy with backpressure preservation (highWaterMark: 0) and early cancel/abort
|
|
4059
|
+
* - Isolated failure boundary (diagnostics sink failures never break generation)
|
|
4060
|
+
*
|
|
4061
|
+
* @module dsh-chatgpt-subscription/request-diagnostics
|
|
4062
|
+
*/
|
|
4063
|
+
const DIAGNOSTIC_PROVIDERS = [
|
|
4064
|
+
"codex-chatgpt",
|
|
4065
|
+
"claude-subscription",
|
|
4066
|
+
"antigravity",
|
|
4067
|
+
"kimi-code",
|
|
4068
|
+
"minimax-code",
|
|
4069
|
+
"command-code",
|
|
4070
|
+
"workbuddy-subscription",
|
|
4071
|
+
"ollama",
|
|
4072
|
+
"claude",
|
|
4073
|
+
"workbuddy",
|
|
4074
|
+
"codex"
|
|
4075
|
+
];
|
|
4076
|
+
const KNOWN_WIRE_ENDPOINTS = [
|
|
4077
|
+
"messages",
|
|
4078
|
+
"responses",
|
|
4079
|
+
"chat_completions",
|
|
4080
|
+
"generate_content",
|
|
4081
|
+
"stream_generate_content",
|
|
4082
|
+
"ollama_chat",
|
|
4083
|
+
"ollama_generate",
|
|
4084
|
+
"workbuddy_chat",
|
|
4085
|
+
"unknown"
|
|
4086
|
+
];
|
|
4087
|
+
function isValidProvider(provider) {
|
|
4088
|
+
return typeof provider === "string" && DIAGNOSTIC_PROVIDERS.includes(provider);
|
|
4089
|
+
}
|
|
4090
|
+
function isValidEndpoint(endpoint) {
|
|
4091
|
+
return typeof endpoint === "string" && KNOWN_WIRE_ENDPOINTS.includes(endpoint);
|
|
4092
|
+
}
|
|
4093
|
+
const EPHEMERAL_HMAC_KEY = randomBytes(32);
|
|
4094
|
+
function computeHmacPrefix(data) {
|
|
4095
|
+
return createHmac("sha256", EPHEMERAL_HMAC_KEY).update(data).digest("hex").slice(0, 16);
|
|
4096
|
+
}
|
|
4097
|
+
const MAX_SESSION_CACHE_SIZE = 500;
|
|
4098
|
+
const sessionCache = /* @__PURE__ */ new Map();
|
|
4099
|
+
function updateSessionFingerprints(scopedSessionKey, current) {
|
|
4100
|
+
const prev = sessionCache.get(scopedSessionKey);
|
|
4101
|
+
const comparison = {
|
|
4102
|
+
...current,
|
|
4103
|
+
authChanged: current.authFingerprint !== void 0 && prev?.authFingerprint !== void 0 ? current.authFingerprint !== prev.authFingerprint : void 0,
|
|
4104
|
+
modelChanged: current.modelFingerprint !== void 0 && prev?.modelFingerprint !== void 0 ? current.modelFingerprint !== prev.modelFingerprint : void 0,
|
|
4105
|
+
toolChanged: current.toolFingerprint !== void 0 && prev?.toolFingerprint !== void 0 ? current.toolFingerprint !== prev.toolFingerprint : void 0,
|
|
4106
|
+
prefixChanged: current.prefixFingerprint !== void 0 && prev?.prefixFingerprint !== void 0 ? current.prefixFingerprint !== prev.prefixFingerprint : void 0
|
|
4107
|
+
};
|
|
4108
|
+
if (sessionCache.has(scopedSessionKey)) sessionCache.delete(scopedSessionKey);
|
|
4109
|
+
else if (sessionCache.size >= MAX_SESSION_CACHE_SIZE) {
|
|
4110
|
+
const oldestKey = sessionCache.keys().next().value;
|
|
4111
|
+
if (oldestKey) sessionCache.delete(oldestKey);
|
|
4112
|
+
}
|
|
4113
|
+
sessionCache.set(scopedSessionKey, {
|
|
4114
|
+
authFingerprint: current.authFingerprint ?? prev?.authFingerprint,
|
|
4115
|
+
modelFingerprint: current.modelFingerprint ?? prev?.modelFingerprint,
|
|
4116
|
+
toolFingerprint: current.toolFingerprint ?? prev?.toolFingerprint,
|
|
4117
|
+
prefixFingerprint: current.prefixFingerprint ?? prev?.prefixFingerprint
|
|
4118
|
+
});
|
|
4119
|
+
return comparison;
|
|
4120
|
+
}
|
|
4121
|
+
function isDiagnosticsEnabled(options) {
|
|
4122
|
+
if (options?.enabled !== void 0) return Boolean(options.enabled);
|
|
4123
|
+
return process.env.DSH_PROVIDER_DIAGNOSTICS === "1";
|
|
4124
|
+
}
|
|
4125
|
+
function classifyHttpStatus(statusCode) {
|
|
4126
|
+
if (statusCode === null) return "error";
|
|
4127
|
+
if (statusCode >= 200 && statusCode < 300) return "2xx";
|
|
4128
|
+
if (statusCode >= 300 && statusCode < 400) return "3xx";
|
|
4129
|
+
if (statusCode >= 400 && statusCode < 500) return "4xx";
|
|
4130
|
+
if (statusCode >= 500 && statusCode < 600) return "5xx";
|
|
4131
|
+
return "error";
|
|
4132
|
+
}
|
|
4133
|
+
function isDefaultModelPath(pathname) {
|
|
4134
|
+
const path = pathname.toLowerCase();
|
|
4135
|
+
if (path.endsWith("/messages")) return "messages";
|
|
4136
|
+
if (path.endsWith("/responses")) return "responses";
|
|
4137
|
+
if (path.endsWith("/chat/completions") || path.endsWith("/chatcompletion_v2") || path.endsWith("/conversation") || path.endsWith("/latents/chat")) return "chat_completions";
|
|
4138
|
+
if (path.includes(":streamgeneratecontent")) return "stream_generate_content";
|
|
4139
|
+
if (path.includes(":generatecontent")) return "generate_content";
|
|
4140
|
+
if (path.endsWith("/api/chat")) return "ollama_chat";
|
|
4141
|
+
if (path.endsWith("/api/generate")) return "ollama_generate";
|
|
4142
|
+
return null;
|
|
4143
|
+
}
|
|
4144
|
+
function getUrlAndPathname(input) {
|
|
4145
|
+
let fullUrl = "";
|
|
4146
|
+
if (typeof input === "string") fullUrl = input;
|
|
4147
|
+
else if (input instanceof URL) fullUrl = input.toString();
|
|
4148
|
+
else if (typeof input === "object" && input !== null && "url" in input) fullUrl = String(input.url);
|
|
4149
|
+
try {
|
|
4150
|
+
const parsed = new URL(fullUrl, "http://127.0.0.1");
|
|
4151
|
+
return {
|
|
4152
|
+
fullUrl,
|
|
4153
|
+
pathname: parsed.pathname
|
|
4154
|
+
};
|
|
4155
|
+
} catch {
|
|
4156
|
+
return {
|
|
4157
|
+
fullUrl,
|
|
4158
|
+
pathname: ""
|
|
4159
|
+
};
|
|
4160
|
+
}
|
|
4161
|
+
}
|
|
4162
|
+
function getHeaderValue(headers, name) {
|
|
4163
|
+
if (!headers) return void 0;
|
|
4164
|
+
const target = name.toLowerCase();
|
|
4165
|
+
if (headers instanceof Headers) return headers.get(target) ?? void 0;
|
|
4166
|
+
if (Array.isArray(headers)) {
|
|
4167
|
+
for (const [key, val] of headers) if (key.toLowerCase() === target) return val;
|
|
4168
|
+
return;
|
|
4169
|
+
}
|
|
4170
|
+
if (typeof headers === "object") {
|
|
4171
|
+
for (const [key, val] of Object.entries(headers)) if (key.toLowerCase() === target) return typeof val === "string" ? val : void 0;
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4174
|
+
function measureRequestBytes(body, input, init) {
|
|
4175
|
+
if (body === null || body === void 0) {
|
|
4176
|
+
if (input instanceof Request && input.body) {
|
|
4177
|
+
const cl = input.headers.get("content-length");
|
|
4178
|
+
if (cl) {
|
|
4179
|
+
const parsed = parseInt(cl, 10);
|
|
4180
|
+
if (!Number.isNaN(parsed) && parsed >= 0) return parsed;
|
|
4181
|
+
}
|
|
4182
|
+
return null;
|
|
4183
|
+
}
|
|
4184
|
+
const cl = getHeaderValue(init?.headers, "content-length");
|
|
4185
|
+
if (cl) {
|
|
4186
|
+
const parsed = parseInt(cl, 10);
|
|
4187
|
+
if (!Number.isNaN(parsed) && parsed >= 0) return parsed;
|
|
4188
|
+
}
|
|
4189
|
+
return 0;
|
|
4190
|
+
}
|
|
4191
|
+
if (typeof body === "string") return Buffer.byteLength(body, "utf-8");
|
|
4192
|
+
if (body instanceof ArrayBuffer) return body.byteLength;
|
|
4193
|
+
if (ArrayBuffer.isView(body)) return body.byteLength;
|
|
4194
|
+
if (typeof Blob !== "undefined" && body instanceof Blob) return body.size;
|
|
4195
|
+
return null;
|
|
4196
|
+
}
|
|
4197
|
+
const MAX_JSON_PARSE_BYTES = 512 * 1024;
|
|
4198
|
+
function extractBodyFingerprints(body) {
|
|
4199
|
+
if (typeof body !== "string" || body.length > MAX_JSON_PARSE_BYTES) return {};
|
|
4200
|
+
const trimmed = body.trim();
|
|
4201
|
+
if (!trimmed.startsWith("{")) return {};
|
|
4202
|
+
try {
|
|
4203
|
+
const parsed = JSON.parse(trimmed);
|
|
4204
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
4205
|
+
let modelFingerprint;
|
|
4206
|
+
if (typeof parsed.model === "string" && parsed.model) modelFingerprint = computeHmacPrefix(parsed.model);
|
|
4207
|
+
let toolFingerprint;
|
|
4208
|
+
if (Array.isArray(parsed.tools)) toolFingerprint = computeHmacPrefix(JSON.stringify(parsed.tools));
|
|
4209
|
+
let prefixFingerprint;
|
|
4210
|
+
let prefixCandidate = "";
|
|
4211
|
+
if (typeof parsed.instructions === "string" && parsed.instructions) prefixCandidate = parsed.instructions;
|
|
4212
|
+
else if (typeof parsed.system === "string" && parsed.system) prefixCandidate = parsed.system;
|
|
4213
|
+
else if (Array.isArray(parsed.system) && parsed.system.length > 0) prefixCandidate = JSON.stringify(parsed.system);
|
|
4214
|
+
else if (Array.isArray(parsed.messages) && parsed.messages.length > 0) {
|
|
4215
|
+
const first = parsed.messages[0];
|
|
4216
|
+
if (first && typeof first === "object") {
|
|
4217
|
+
const f = first;
|
|
4218
|
+
if (f.role === "system" || f.role === "developer") prefixCandidate = typeof f.content === "string" ? f.content : JSON.stringify(f.content);
|
|
4219
|
+
else prefixCandidate = JSON.stringify(f);
|
|
4220
|
+
}
|
|
4221
|
+
}
|
|
4222
|
+
if (prefixCandidate) prefixFingerprint = computeHmacPrefix(prefixCandidate);
|
|
4223
|
+
return {
|
|
4224
|
+
modelFingerprint,
|
|
4225
|
+
toolFingerprint,
|
|
4226
|
+
prefixFingerprint
|
|
4227
|
+
};
|
|
4228
|
+
} catch {
|
|
4229
|
+
return {};
|
|
4230
|
+
}
|
|
4231
|
+
}
|
|
4232
|
+
function parseFiniteNonNegativeNumber(val) {
|
|
4233
|
+
if (typeof val === "number") {
|
|
4234
|
+
if (Number.isFinite(val) && val >= 0) return Math.floor(val);
|
|
4235
|
+
return;
|
|
4236
|
+
}
|
|
4237
|
+
if (typeof val === "string" && val.trim() !== "") {
|
|
4238
|
+
const num = Number(val);
|
|
4239
|
+
if (Number.isFinite(num) && num >= 0) return Math.floor(num);
|
|
4240
|
+
}
|
|
4241
|
+
}
|
|
4242
|
+
function parseUsageObject(raw, endpoint) {
|
|
4243
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
4244
|
+
const r = raw;
|
|
4245
|
+
const totalInput = parseFiniteNonNegativeNumber(r.prompt_tokens) ?? parseFiniteNonNegativeNumber(r.input_tokens);
|
|
4246
|
+
const outputTokens = parseFiniteNonNegativeNumber(r.completion_tokens) ?? parseFiniteNonNegativeNumber(r.output_tokens);
|
|
4247
|
+
const totalTokens = parseFiniteNonNegativeNumber(r.total_tokens);
|
|
4248
|
+
const inputDetails = typeof r.prompt_tokens_details === "object" && r.prompt_tokens_details !== null ? r.prompt_tokens_details : typeof r.input_tokens_details === "object" && r.input_tokens_details !== null ? r.input_tokens_details : null;
|
|
4249
|
+
const outputDetails = typeof r.completion_tokens_details === "object" && r.completion_tokens_details !== null ? r.completion_tokens_details : typeof r.output_tokens_details === "object" && r.output_tokens_details !== null ? r.output_tokens_details : null;
|
|
4250
|
+
const cacheRead = parseFiniteNonNegativeNumber(inputDetails?.cached_tokens) ?? parseFiniteNonNegativeNumber(r.cache_read_input_tokens) ?? parseFiniteNonNegativeNumber(r.cache_read_tokens);
|
|
4251
|
+
const cacheWrite = parseFiniteNonNegativeNumber(inputDetails?.cache_write_tokens) ?? parseFiniteNonNegativeNumber(r.cache_creation_input_tokens) ?? parseFiniteNonNegativeNumber(r.cache_write_tokens);
|
|
4252
|
+
const reasoning = parseFiniteNonNegativeNumber(outputDetails?.reasoning_tokens) ?? parseFiniteNonNegativeNumber(r.reasoning_tokens);
|
|
4253
|
+
if (totalInput === void 0 && outputTokens === void 0 && totalTokens === void 0 && cacheRead === void 0 && cacheWrite === void 0) return;
|
|
4254
|
+
let disjointInput;
|
|
4255
|
+
if (totalInput !== void 0) if (endpoint === "messages") disjointInput = totalInput;
|
|
4256
|
+
else disjointInput = Math.max(0, totalInput - (cacheRead ?? 0) - (cacheWrite ?? 0));
|
|
4257
|
+
return {
|
|
4258
|
+
...disjointInput !== void 0 ? { inputTokens: disjointInput } : {},
|
|
4259
|
+
...outputTokens !== void 0 ? { outputTokens } : {},
|
|
4260
|
+
...cacheRead !== void 0 ? { cacheReadTokens: cacheRead } : {},
|
|
4261
|
+
...cacheWrite !== void 0 ? { cacheWriteTokens: cacheWrite } : {},
|
|
4262
|
+
...reasoning !== void 0 ? { reasoningTokens: reasoning } : {},
|
|
4263
|
+
...totalTokens !== void 0 ? { totalTokens } : {}
|
|
4264
|
+
};
|
|
4265
|
+
}
|
|
4266
|
+
function mergeUsage(target, source) {
|
|
4267
|
+
if (!target) return source ? { ...source } : void 0;
|
|
4268
|
+
if (!source) return target ? { ...target } : void 0;
|
|
4269
|
+
return {
|
|
4270
|
+
inputTokens: source.inputTokens ?? target.inputTokens,
|
|
4271
|
+
outputTokens: source.outputTokens ?? target.outputTokens,
|
|
4272
|
+
cacheReadTokens: source.cacheReadTokens ?? target.cacheReadTokens,
|
|
4273
|
+
cacheWriteTokens: source.cacheWriteTokens ?? target.cacheWriteTokens,
|
|
4274
|
+
reasoningTokens: source.reasoningTokens ?? target.reasoningTokens,
|
|
4275
|
+
totalTokens: source.totalTokens ?? target.totalTokens
|
|
4276
|
+
};
|
|
4277
|
+
}
|
|
4278
|
+
const MAX_LINE_BUFFER_BYTES = 64 * 1024;
|
|
4279
|
+
var StreamingUsageParser = class {
|
|
4280
|
+
endpoint;
|
|
4281
|
+
lineBuffer = "";
|
|
4282
|
+
accumulatedUsage;
|
|
4283
|
+
constructor(endpoint) {
|
|
4284
|
+
this.endpoint = endpoint;
|
|
4285
|
+
}
|
|
4286
|
+
droppingLine = false;
|
|
4287
|
+
feed(chunkText) {
|
|
4288
|
+
let start = 0;
|
|
4289
|
+
while (start < chunkText.length) {
|
|
4290
|
+
const newline = chunkText.indexOf("\n", start);
|
|
4291
|
+
const end = newline === -1 ? chunkText.length : newline;
|
|
4292
|
+
if (!this.droppingLine) if (this.lineBuffer.length + end - start > MAX_LINE_BUFFER_BYTES) {
|
|
4293
|
+
this.lineBuffer = "";
|
|
4294
|
+
this.droppingLine = true;
|
|
4295
|
+
} else this.lineBuffer += chunkText.slice(start, end);
|
|
4296
|
+
if (newline === -1) break;
|
|
4297
|
+
if (!this.droppingLine) this.processLine(this.lineBuffer.trim());
|
|
4298
|
+
this.lineBuffer = "";
|
|
4299
|
+
this.droppingLine = false;
|
|
4300
|
+
start = newline + 1;
|
|
4301
|
+
}
|
|
4302
|
+
}
|
|
4303
|
+
flush() {
|
|
4304
|
+
const trailing = this.lineBuffer.trim();
|
|
4305
|
+
if (trailing) {
|
|
4306
|
+
this.processLine(trailing);
|
|
4307
|
+
this.lineBuffer = "";
|
|
4308
|
+
}
|
|
4309
|
+
return this.accumulatedUsage;
|
|
4310
|
+
}
|
|
4311
|
+
processLine(line) {
|
|
4312
|
+
let payload = line;
|
|
4313
|
+
if (payload.startsWith("data:")) payload = payload.slice(5).trim();
|
|
4314
|
+
if (!payload || payload === "[DONE]") return;
|
|
4315
|
+
if (!payload.startsWith("{")) return;
|
|
4316
|
+
try {
|
|
4317
|
+
const parsed = JSON.parse(payload);
|
|
4318
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return;
|
|
4319
|
+
if (parsed.type === "message_start" && parsed.message && typeof parsed.message === "object") {
|
|
4320
|
+
const msg = parsed.message;
|
|
4321
|
+
if (msg.usage) {
|
|
4322
|
+
const parsedUsage = parseUsageObject(msg.usage, this.endpoint);
|
|
4323
|
+
this.accumulatedUsage = mergeUsage(this.accumulatedUsage, parsedUsage);
|
|
4324
|
+
return;
|
|
4325
|
+
}
|
|
4326
|
+
}
|
|
4327
|
+
if (parsed.type === "message_delta" && parsed.usage) {
|
|
4328
|
+
const parsedUsage = parseUsageObject(parsed.usage, this.endpoint);
|
|
4329
|
+
this.accumulatedUsage = mergeUsage(this.accumulatedUsage, parsedUsage);
|
|
4330
|
+
return;
|
|
4331
|
+
}
|
|
4332
|
+
if (parsed.done === true) {
|
|
4333
|
+
const promptEval = parseFiniteNonNegativeNumber(parsed.prompt_eval_count);
|
|
4334
|
+
const evalCount = parseFiniteNonNegativeNumber(parsed.eval_count);
|
|
4335
|
+
if (promptEval !== void 0 || evalCount !== void 0) {
|
|
4336
|
+
const ollamaUsage = {
|
|
4337
|
+
...promptEval !== void 0 ? { inputTokens: promptEval } : {},
|
|
4338
|
+
...evalCount !== void 0 ? { outputTokens: evalCount } : {},
|
|
4339
|
+
...promptEval !== void 0 && evalCount !== void 0 ? { totalTokens: promptEval + evalCount } : {}
|
|
4340
|
+
};
|
|
4341
|
+
this.accumulatedUsage = mergeUsage(this.accumulatedUsage, ollamaUsage);
|
|
4342
|
+
return;
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4345
|
+
const rawUsage = parsed.usage ?? (parsed.response && typeof parsed.response === "object" ? parsed.response.usage : void 0) ?? (parsed.message && typeof parsed.message === "object" ? parsed.message.usage : void 0);
|
|
4346
|
+
if (rawUsage && typeof rawUsage === "object") {
|
|
4347
|
+
const parsedUsage = parseUsageObject(rawUsage, this.endpoint);
|
|
4348
|
+
this.accumulatedUsage = mergeUsage(this.accumulatedUsage, parsedUsage);
|
|
4349
|
+
}
|
|
4350
|
+
} catch {}
|
|
4351
|
+
}
|
|
4352
|
+
};
|
|
4353
|
+
/**
|
|
4354
|
+
* Creates a diagnostic wrapper around fetch for model requests.
|
|
4355
|
+
*/
|
|
4356
|
+
function createDiagnosticFetch(baseFetch, options) {
|
|
4357
|
+
return async function diagnosticFetch(input, init) {
|
|
4358
|
+
if (!isDiagnosticsEnabled(options)) return baseFetch(input, init);
|
|
4359
|
+
if ((init?.method ?? (input instanceof Request ? input.method : typeof input === "object" && input !== null && "method" in input ? String(input.method) : "GET")).toUpperCase() !== "POST") return baseFetch(input, init);
|
|
4360
|
+
const { fullUrl, pathname } = getUrlAndPathname(input);
|
|
4361
|
+
const rawEndpoint = options?.endpoint ?? (options?.classifyEndpoint ? options.classifyEndpoint(fullUrl, pathname) : isDefaultModelPath(pathname));
|
|
4362
|
+
if (!rawEndpoint || !isValidEndpoint(rawEndpoint)) return baseFetch(input, init);
|
|
4363
|
+
const endpoint = rawEndpoint;
|
|
4364
|
+
const candidateProvider = options?.provider ?? "codex-chatgpt";
|
|
4365
|
+
if (!isValidProvider(candidateProvider)) return baseFetch(input, init);
|
|
4366
|
+
const provider = candidateProvider;
|
|
4367
|
+
const requestBytes = measureRequestBytes(init?.body, input, init);
|
|
4368
|
+
const startTime = performance.now();
|
|
4369
|
+
const authHeader = getHeaderValue(init?.headers, "authorization") ?? getHeaderValue(init?.headers, "x-api-key") ?? (input instanceof Request ? input.headers.get("authorization") ?? input.headers.get("x-api-key") ?? void 0 : void 0);
|
|
4370
|
+
const authFingerprint = authHeader ? computeHmacPrefix(authHeader) : void 0;
|
|
4371
|
+
const sessionRaw = options?.correlation?.sessionId ?? getHeaderValue(init?.headers, "x-session-id") ?? getHeaderValue(init?.headers, "session_id") ?? (input instanceof Request ? input.headers.get("x-session-id") ?? input.headers.get("session_id") ?? void 0 : void 0);
|
|
4372
|
+
const scopedSessionKey = sessionRaw ? computeHmacPrefix(provider + ":" + endpoint + ":" + sessionRaw) : void 0;
|
|
4373
|
+
let retries;
|
|
4374
|
+
if (typeof options?.correlation?.retryCount === "number") retries = options.correlation.retryCount;
|
|
4375
|
+
else {
|
|
4376
|
+
const retryHeader = getHeaderValue(init?.headers, "x-retry-count") ?? getHeaderValue(init?.headers, "retry-count") ?? (input instanceof Request ? input.headers.get("x-retry-count") ?? input.headers.get("retry-count") ?? void 0 : void 0);
|
|
4377
|
+
if (retryHeader) {
|
|
4378
|
+
const parsed = parseInt(retryHeader, 10);
|
|
4379
|
+
if (!Number.isNaN(parsed)) retries = parsed;
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
const currentFingerprints = {
|
|
4383
|
+
authFingerprint,
|
|
4384
|
+
...extractBodyFingerprints(init?.body ?? (input instanceof Request ? void 0 : void 0))
|
|
4385
|
+
};
|
|
4386
|
+
let fingerprints;
|
|
4387
|
+
if (scopedSessionKey) fingerprints = updateSessionFingerprints(scopedSessionKey, currentFingerprints);
|
|
4388
|
+
else if (currentFingerprints.authFingerprint || currentFingerprints.modelFingerprint || currentFingerprints.toolFingerprint || currentFingerprints.prefixFingerprint) fingerprints = { ...currentFingerprints };
|
|
4389
|
+
const signal = init?.signal ?? (input instanceof Request ? input.signal : void 0);
|
|
4390
|
+
let firstByteMs = null;
|
|
4391
|
+
let emitted = false;
|
|
4392
|
+
const usageParser = new StreamingUsageParser(endpoint);
|
|
4393
|
+
const decoder = new TextDecoder("utf-8", { fatal: false });
|
|
4394
|
+
function emitRecord(outcome, statusCode) {
|
|
4395
|
+
if (emitted) return;
|
|
4396
|
+
emitted = true;
|
|
4397
|
+
const durationMs = Math.max(0, Math.round(performance.now() - startTime));
|
|
4398
|
+
const usage = outcome === "completed" ? usageParser.flush() : void 0;
|
|
4399
|
+
const record = {
|
|
4400
|
+
provider,
|
|
4401
|
+
endpoint,
|
|
4402
|
+
requestBytes,
|
|
4403
|
+
firstByteMs,
|
|
4404
|
+
ttftMs: null,
|
|
4405
|
+
durationMs,
|
|
4406
|
+
statusCode,
|
|
4407
|
+
statusClass: classifyHttpStatus(statusCode),
|
|
4408
|
+
outcome,
|
|
4409
|
+
...usage !== void 0 ? { usage } : {},
|
|
4410
|
+
...retries !== void 0 ? { retries } : {},
|
|
4411
|
+
...fingerprints !== void 0 ? { fingerprints } : {}
|
|
4412
|
+
};
|
|
4413
|
+
try {
|
|
4414
|
+
const res = options?.onRecord?.(record);
|
|
4415
|
+
if (res && typeof res.catch === "function") res.catch(() => {});
|
|
4416
|
+
} catch {}
|
|
4417
|
+
}
|
|
4418
|
+
let response;
|
|
4419
|
+
try {
|
|
4420
|
+
response = await baseFetch(input, init);
|
|
4421
|
+
} catch (error) {
|
|
4422
|
+
emitRecord(Boolean(signal?.aborted) || error instanceof Error && error.name === "AbortError" ? "canceled" : "error", null);
|
|
4423
|
+
throw error;
|
|
4424
|
+
}
|
|
4425
|
+
if (signal?.aborted) {
|
|
4426
|
+
const reason = signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
4427
|
+
emitRecord("canceled", response.status);
|
|
4428
|
+
if (response.body) try {
|
|
4429
|
+
const r = response.body.getReader();
|
|
4430
|
+
await r.cancel(reason);
|
|
4431
|
+
r.releaseLock();
|
|
4432
|
+
} catch {}
|
|
4433
|
+
throw reason;
|
|
4434
|
+
}
|
|
4435
|
+
if (response.body === null || response.status === 204 || response.status === 304) {
|
|
4436
|
+
emitRecord(response.ok ? "completed" : "error", response.status);
|
|
4437
|
+
return response;
|
|
4438
|
+
}
|
|
4439
|
+
const reader = response.body.getReader();
|
|
4440
|
+
let streamClosed = false;
|
|
4441
|
+
let controllerRef;
|
|
4442
|
+
const cleanup = () => {
|
|
4443
|
+
streamClosed = true;
|
|
4444
|
+
if (signal) try {
|
|
4445
|
+
signal.removeEventListener("abort", abortListener);
|
|
4446
|
+
} catch {}
|
|
4447
|
+
};
|
|
4448
|
+
const abortListener = () => {
|
|
4449
|
+
if (streamClosed) return;
|
|
4450
|
+
cleanup();
|
|
4451
|
+
const reason = signal?.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
4452
|
+
emitRecord("canceled", response.status);
|
|
4453
|
+
try {
|
|
4454
|
+
controllerRef?.error(reason);
|
|
4455
|
+
} catch {}
|
|
4456
|
+
reader.cancel(reason).catch(() => {}).finally(() => {
|
|
4457
|
+
try {
|
|
4458
|
+
reader.releaseLock();
|
|
4459
|
+
} catch {}
|
|
4460
|
+
});
|
|
4461
|
+
};
|
|
4462
|
+
if (signal) signal.addEventListener("abort", abortListener, { once: true });
|
|
4463
|
+
const wrappedBody = new ReadableStream({
|
|
4464
|
+
start(controller) {
|
|
4465
|
+
controllerRef = controller;
|
|
4466
|
+
},
|
|
4467
|
+
async pull(controller) {
|
|
4468
|
+
try {
|
|
4469
|
+
const { done, value } = await reader.read();
|
|
4470
|
+
if (done) {
|
|
4471
|
+
cleanup();
|
|
4472
|
+
try {
|
|
4473
|
+
reader.releaseLock();
|
|
4474
|
+
} catch {}
|
|
4475
|
+
emitRecord("completed", response.status);
|
|
4476
|
+
controller.close();
|
|
4477
|
+
return;
|
|
4478
|
+
}
|
|
4479
|
+
if (value && value.byteLength > 0) {
|
|
4480
|
+
if (firstByteMs === null) firstByteMs = Math.max(0, Math.round(performance.now() - startTime));
|
|
4481
|
+
const text = decoder.decode(value, { stream: true });
|
|
4482
|
+
if (text) usageParser.feed(text);
|
|
4483
|
+
}
|
|
4484
|
+
controller.enqueue(value);
|
|
4485
|
+
} catch (err) {
|
|
4486
|
+
cleanup();
|
|
4487
|
+
try {
|
|
4488
|
+
reader.releaseLock();
|
|
4489
|
+
} catch {}
|
|
4490
|
+
emitRecord(Boolean(signal?.aborted) || err instanceof Error && err.name === "AbortError" ? "canceled" : "error", response.status);
|
|
4491
|
+
controller.error(err);
|
|
4492
|
+
}
|
|
4493
|
+
},
|
|
4494
|
+
async cancel(reason) {
|
|
4495
|
+
cleanup();
|
|
4496
|
+
emitRecord("canceled", response.status);
|
|
4497
|
+
try {
|
|
4498
|
+
await reader.cancel(reason);
|
|
4499
|
+
} finally {
|
|
4500
|
+
try {
|
|
4501
|
+
reader.releaseLock();
|
|
4502
|
+
} catch {}
|
|
4503
|
+
}
|
|
4504
|
+
}
|
|
4505
|
+
}, { highWaterMark: 0 });
|
|
4506
|
+
const wrappedResponse = new Response(wrappedBody, {
|
|
4507
|
+
status: response.status,
|
|
4508
|
+
statusText: response.statusText,
|
|
4509
|
+
headers: response.headers
|
|
4510
|
+
});
|
|
4511
|
+
try {
|
|
4512
|
+
Object.defineProperty(wrappedResponse, "url", {
|
|
4513
|
+
value: response.url,
|
|
4514
|
+
writable: false,
|
|
4515
|
+
configurable: true
|
|
4516
|
+
});
|
|
4517
|
+
Object.defineProperty(wrappedResponse, "redirected", {
|
|
4518
|
+
value: response.redirected,
|
|
4519
|
+
writable: false,
|
|
4520
|
+
configurable: true
|
|
4521
|
+
});
|
|
4522
|
+
Object.defineProperty(wrappedResponse, "type", {
|
|
4523
|
+
value: response.type,
|
|
4524
|
+
writable: false,
|
|
4525
|
+
configurable: true
|
|
4526
|
+
});
|
|
4527
|
+
} catch {}
|
|
4528
|
+
return wrappedResponse;
|
|
4529
|
+
};
|
|
4530
|
+
}
|
|
4531
|
+
//#endregion
|
|
3747
4532
|
//#region src/host/antigravity/types.ts
|
|
3748
4533
|
const PROVIDER_NAME$6 = "Antigravity";
|
|
3749
4534
|
const PROVIDER_ID$6 = "antigravity";
|
|
@@ -3794,6 +4579,32 @@ const ROUTING = {
|
|
|
3794
4579
|
defaultRequestId: "gemini-3.8-flash-tiered",
|
|
3795
4580
|
fallbackCandidates: ["gemini-3.7-flash-tiered", "gemini-3.6-flash-low"]
|
|
3796
4581
|
},
|
|
4582
|
+
"claude-opus-5-5": {
|
|
4583
|
+
off: "claude-opus-5-5-low",
|
|
4584
|
+
routing: {
|
|
4585
|
+
off: "claude-opus-5-5-low",
|
|
4586
|
+
none: "claude-opus-5-5-low",
|
|
4587
|
+
minimal: "claude-opus-5-5-low",
|
|
4588
|
+
low: "claude-opus-5-5-low",
|
|
4589
|
+
medium: "claude-opus-5-5-medium",
|
|
4590
|
+
high: "claude-opus-5-5-high",
|
|
4591
|
+
xhigh: "claude-opus-5-5-high"
|
|
4592
|
+
},
|
|
4593
|
+
defaultRequestId: "claude-opus-5-5-medium"
|
|
4594
|
+
},
|
|
4595
|
+
"claude-sonnet-5-5": {
|
|
4596
|
+
off: "claude-sonnet-5-5-low",
|
|
4597
|
+
routing: {
|
|
4598
|
+
off: "claude-sonnet-5-5-low",
|
|
4599
|
+
none: "claude-sonnet-5-5-low",
|
|
4600
|
+
minimal: "claude-sonnet-5-5-low",
|
|
4601
|
+
low: "claude-sonnet-5-5-low",
|
|
4602
|
+
medium: "claude-sonnet-5-5-medium",
|
|
4603
|
+
high: "claude-sonnet-5-5-high",
|
|
4604
|
+
xhigh: "claude-sonnet-5-5-high"
|
|
4605
|
+
},
|
|
4606
|
+
defaultRequestId: "claude-sonnet-5-5-medium"
|
|
4607
|
+
},
|
|
3797
4608
|
"claude-opus-4-6": {
|
|
3798
4609
|
off: "claude-opus-4-6-thinking",
|
|
3799
4610
|
routing: {
|
|
@@ -3938,6 +4749,14 @@ const RUNTIME_MAX_OUTPUT_TOKENS = {
|
|
|
3938
4749
|
"gemini-3.1-pro-low": 65535,
|
|
3939
4750
|
"gemini-3.1-pro-high": 65535,
|
|
3940
4751
|
"gemini-pro-agent": 65535,
|
|
4752
|
+
"claude-opus-5-5": 64e3,
|
|
4753
|
+
"claude-opus-5-5-low": 64e3,
|
|
4754
|
+
"claude-opus-5-5-medium": 64e3,
|
|
4755
|
+
"claude-opus-5-5-high": 64e3,
|
|
4756
|
+
"claude-sonnet-5-5": 64e3,
|
|
4757
|
+
"claude-sonnet-5-5-low": 64e3,
|
|
4758
|
+
"claude-sonnet-5-5-medium": 64e3,
|
|
4759
|
+
"claude-sonnet-5-5-high": 64e3,
|
|
3941
4760
|
"claude-opus-4-6": 64e3,
|
|
3942
4761
|
"claude-opus-4-6-thinking": 64e3,
|
|
3943
4762
|
"claude-sonnet-4-6": 64e3,
|
|
@@ -4029,6 +4848,30 @@ const MODELS = [
|
|
|
4029
4848
|
contextWindow: 1048576,
|
|
4030
4849
|
maxTokens: 65536
|
|
4031
4850
|
},
|
|
4851
|
+
{
|
|
4852
|
+
id: "claude-opus-5-5",
|
|
4853
|
+
name: "Claude Opus 5.5",
|
|
4854
|
+
inputModalities: ["text", "image"],
|
|
4855
|
+
contextWindow: 1048576,
|
|
4856
|
+
maxTokens: 64e3,
|
|
4857
|
+
reasoningEfforts: [
|
|
4858
|
+
"low",
|
|
4859
|
+
"medium",
|
|
4860
|
+
"high"
|
|
4861
|
+
]
|
|
4862
|
+
},
|
|
4863
|
+
{
|
|
4864
|
+
id: "claude-sonnet-5-5",
|
|
4865
|
+
name: "Claude Sonnet 5.5",
|
|
4866
|
+
inputModalities: ["text", "image"],
|
|
4867
|
+
contextWindow: 1048576,
|
|
4868
|
+
maxTokens: 64e3,
|
|
4869
|
+
reasoningEfforts: [
|
|
4870
|
+
"low",
|
|
4871
|
+
"medium",
|
|
4872
|
+
"high"
|
|
4873
|
+
]
|
|
4874
|
+
},
|
|
4032
4875
|
{
|
|
4033
4876
|
id: "claude-opus-4-6",
|
|
4034
4877
|
name: "Claude Opus 4.6",
|
|
@@ -5265,7 +6108,7 @@ const MAX_VISIBLE_REASONING_CHARS = 12e3;
|
|
|
5265
6108
|
const DEFAULT_POOL_COOLDOWN_MS = 15 * 6e4;
|
|
5266
6109
|
const REASONING_DELTA_FLUSH_CHARS = 768;
|
|
5267
6110
|
const REASONING_TRUNCATED_NOTICE = "\n\n[Reasoning summary truncated to keep the DSH web UI responsive.]";
|
|
5268
|
-
/** Cap on
|
|
6111
|
+
/** Cap on live turns whose routing state is remembered at once. */
|
|
5269
6112
|
const MAX_TRACKED_TURN_STATES = 200;
|
|
5270
6113
|
var ResponsesClient = class {
|
|
5271
6114
|
oauth;
|
|
@@ -5277,13 +6120,20 @@ var ResponsesClient = class {
|
|
|
5277
6120
|
reasoningSummary;
|
|
5278
6121
|
accountPool;
|
|
5279
6122
|
/**
|
|
5280
|
-
* Opaque backend
|
|
6123
|
+
* Opaque backend routing state, keyed by a unique model-request nonce.
|
|
6124
|
+
* The host does not expose a reliable human-turn identity, so this is the
|
|
6125
|
+
* conservative no-cross-request-reuse fallback, not full turn continuity.
|
|
5281
6126
|
*
|
|
5282
6127
|
* The Codex backend hands `x-codex-turn-state` back on each response and
|
|
5283
|
-
* expects it on the next request of the
|
|
5284
|
-
*
|
|
5285
|
-
*
|
|
5286
|
-
*
|
|
6128
|
+
* expects it on the next request of the SAME turn, which lets it resume the
|
|
6129
|
+
* turn instead of re-ingesting the whole history.
|
|
6130
|
+
*
|
|
6131
|
+
* It is a client/server contract with a one-turn scope: the official client
|
|
6132
|
+
* creates a fresh per-turn session and warns that replaying the token across
|
|
6133
|
+
* turns breaks routing. The value is also account-scoped, so each entry
|
|
6134
|
+
* records the auth owner that minted it and is discarded when the signer
|
|
6135
|
+
* changes. It is only ever an optimization, so a miss costs a full resend and
|
|
6136
|
+
* never correctness.
|
|
5287
6137
|
*/
|
|
5288
6138
|
turnStates = /* @__PURE__ */ new Map();
|
|
5289
6139
|
constructor(oauth, attachments, options = {}) {
|
|
@@ -5302,13 +6152,17 @@ var ResponsesClient = class {
|
|
|
5302
6152
|
const options = normalizeGenerateOptions(rawOptions);
|
|
5303
6153
|
const hiddenSandboxControls = hiddenSandboxControlToolNames(options);
|
|
5304
6154
|
const sessionId = stableSessionId(options.sessionId);
|
|
6155
|
+
const turnKey = turnKeyFor(sessionId);
|
|
5305
6156
|
let currentModel = options.model;
|
|
5306
6157
|
let attemptOptions = options;
|
|
5307
6158
|
let response;
|
|
6159
|
+
let release;
|
|
5308
6160
|
while (true) {
|
|
5309
6161
|
const payload = await buildResponsesPayload(attemptOptions, this.attachments, this.localRawImages, this.outputVerbosity(), this.fastMode(), this.reasoningSummary(), promptCacheKeyFor(sessionId));
|
|
5310
6162
|
try {
|
|
5311
|
-
|
|
6163
|
+
const opened = await this.send(payload, sessionId, turnKey, options.signal);
|
|
6164
|
+
response = opened.response;
|
|
6165
|
+
release = opened.release;
|
|
5312
6166
|
break;
|
|
5313
6167
|
} catch (error) {
|
|
5314
6168
|
if (error instanceof LlmError && (error.code === "NOT_FOUND" || error.status === 404)) {
|
|
@@ -5328,42 +6182,47 @@ var ResponsesClient = class {
|
|
|
5328
6182
|
try {
|
|
5329
6183
|
yield* wrapStreamWithWatchdog((watchdogSignal) => parseResponsesStream(response, watchdogSignal, hiddenSandboxControls), options.signal, 3e5, "LLM_STREAM_IDLE_TIMEOUT", "Codex");
|
|
5330
6184
|
} finally {
|
|
6185
|
+
this.turnStates.delete(turnKey);
|
|
6186
|
+
release?.();
|
|
5331
6187
|
this.onGenerationFinished();
|
|
5332
6188
|
}
|
|
5333
6189
|
}
|
|
5334
|
-
async send(payload, sessionId, signal) {
|
|
5335
|
-
if (this.accountPool !== null) return this.sendWithPool(payload, sessionId, signal);
|
|
6190
|
+
async send(payload, sessionId, turnKey, signal) {
|
|
6191
|
+
if (this.accountPool !== null) return this.sendWithPool(payload, sessionId, turnKey, signal);
|
|
5336
6192
|
let credentials = await this.oauth.credentials();
|
|
5337
|
-
let response = await this.request(payload, credentials, sessionId, signal);
|
|
6193
|
+
let response = await this.request(payload, credentials, sessionId, turnKey, signal);
|
|
5338
6194
|
if (response.status === 401) {
|
|
5339
6195
|
await response.body?.cancel().catch(() => void 0);
|
|
5340
6196
|
credentials = await this.oauth.credentials(true);
|
|
5341
|
-
response = await this.request(payload, credentials, sessionId, signal);
|
|
6197
|
+
response = await this.request(payload, credentials, sessionId, turnKey, signal);
|
|
5342
6198
|
}
|
|
5343
6199
|
if (!response.ok) throw await responseError(response);
|
|
5344
|
-
this.rememberTurnState(response,
|
|
5345
|
-
return response;
|
|
6200
|
+
this.rememberTurnState(response, turnKey, credentials);
|
|
6201
|
+
return { response };
|
|
5346
6202
|
}
|
|
5347
6203
|
/**
|
|
5348
|
-
* Record the
|
|
6204
|
+
* Record the routing state a response carried, for this turn's next request.
|
|
5349
6205
|
*
|
|
5350
6206
|
* A response that carries none clears any stored value: a backend that stops
|
|
5351
6207
|
* sending the header has stopped honouring it, and replaying a stale value
|
|
5352
6208
|
* would be guessing. An empty header is treated the same as absent.
|
|
5353
6209
|
*/
|
|
5354
|
-
rememberTurnState(response,
|
|
6210
|
+
rememberTurnState(response, turnKey, credentials) {
|
|
5355
6211
|
const next = response.headers.get(CODEX_TURN_STATE_HEADER)?.trim();
|
|
5356
|
-
if (next === void 0 || next === "") this.turnStates.delete(
|
|
5357
|
-
else this.storeTurnState(
|
|
6212
|
+
if (next === void 0 || next === "") this.turnStates.delete(turnKey);
|
|
6213
|
+
else this.storeTurnState(turnKey, next, credentials);
|
|
5358
6214
|
}
|
|
5359
6215
|
/**
|
|
5360
|
-
* Bounded store: a long-lived host serves many sessions, and nothing
|
|
5361
|
-
* signals that
|
|
5362
|
-
* entry. The value is an optimization, so a miss only costs a
|
|
6216
|
+
* Bounded store: a long-lived host serves many sessions and turns, and nothing
|
|
6217
|
+
* here ever signals that either ended, so the map is capped and evicts the
|
|
6218
|
+
* oldest entry. The value is an optimization, so a miss only costs a resend.
|
|
5363
6219
|
*/
|
|
5364
|
-
storeTurnState(
|
|
5365
|
-
this.turnStates.delete(
|
|
5366
|
-
this.turnStates.set(
|
|
6220
|
+
storeTurnState(turnKey, value, credentials) {
|
|
6221
|
+
this.turnStates.delete(turnKey);
|
|
6222
|
+
this.turnStates.set(turnKey, {
|
|
6223
|
+
value,
|
|
6224
|
+
owner: authOwnerKey(credentials)
|
|
6225
|
+
});
|
|
5367
6226
|
while (this.turnStates.size > MAX_TRACKED_TURN_STATES) {
|
|
5368
6227
|
const oldest = this.turnStates.keys().next();
|
|
5369
6228
|
if (oldest.done === true) break;
|
|
@@ -5371,6 +6230,23 @@ var ResponsesClient = class {
|
|
|
5371
6230
|
}
|
|
5372
6231
|
}
|
|
5373
6232
|
/**
|
|
6233
|
+
* Routing state this turn may replay, or undefined.
|
|
6234
|
+
*
|
|
6235
|
+
* A token minted by a different auth owner is dropped rather than sent: the
|
|
6236
|
+
* value is account-scoped, and sending it to another account is at best a
|
|
6237
|
+
* routing hint for the wrong machine and at worst a replay of state that
|
|
6238
|
+
* account never issued. Dropping it only costs a full resend.
|
|
6239
|
+
*/
|
|
6240
|
+
turnStateFor(turnKey, credentials) {
|
|
6241
|
+
const entry = this.turnStates.get(turnKey);
|
|
6242
|
+
if (entry === void 0) return void 0;
|
|
6243
|
+
if (entry.owner !== authOwnerKey(credentials)) {
|
|
6244
|
+
this.turnStates.delete(turnKey);
|
|
6245
|
+
return;
|
|
6246
|
+
}
|
|
6247
|
+
return entry.value;
|
|
6248
|
+
}
|
|
6249
|
+
/**
|
|
5374
6250
|
* Send one payload with account rotation.
|
|
5375
6251
|
*
|
|
5376
6252
|
* The pool picks the account — skipping cooling, quota-exhausted and failed
|
|
@@ -5380,48 +6256,72 @@ var ResponsesClient = class {
|
|
|
5380
6256
|
* refresh is rejected leaves the rotation instead of invalidating the others.
|
|
5381
6257
|
* The payload is account-independent, so it is never rebuilt between attempts.
|
|
5382
6258
|
*/
|
|
5383
|
-
|
|
6259
|
+
/** What one pool attempt produced, including the account that served it. */
|
|
6260
|
+
async sendWithPool(payload, sessionId, turnKey, signal) {
|
|
5384
6261
|
const pool = this.accountPool;
|
|
5385
6262
|
const tried = /* @__PURE__ */ new Set();
|
|
5386
6263
|
while (true) {
|
|
5387
|
-
const
|
|
6264
|
+
const selected = await pool.getEffectiveAccount(tried, this.fetchFn);
|
|
6265
|
+
const account = selected.account;
|
|
6266
|
+
let credentials = selected.credentials;
|
|
5388
6267
|
tried.add(account.id);
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
6268
|
+
const release = await chatGPTConcurrency().acquire(account.id, signal);
|
|
6269
|
+
let held = true;
|
|
6270
|
+
const free = () => {
|
|
6271
|
+
if (!held) return;
|
|
6272
|
+
held = false;
|
|
6273
|
+
release();
|
|
6274
|
+
};
|
|
6275
|
+
try {
|
|
6276
|
+
let response = await this.request(payload, credentials, sessionId, turnKey, signal);
|
|
6277
|
+
if (response.status === 401) {
|
|
6278
|
+
await response.body?.cancel().catch(() => void 0);
|
|
6279
|
+
try {
|
|
6280
|
+
credentials = await pool.refreshAccountNow(account.id);
|
|
6281
|
+
response = await this.request(payload, credentials, sessionId, turnKey, signal);
|
|
6282
|
+
} catch (error) {
|
|
6283
|
+
await pool.markAuthFailed(account.id, error instanceof Error ? error.message : "ChatGPT sign-in expired.").catch(() => void 0);
|
|
6284
|
+
free();
|
|
6285
|
+
if (await pool.hasAnotherAvailableAccount(tried)) continue;
|
|
6286
|
+
throw new LlmError("ChatGPT sign-in has expired. Sign in again.", "AUTH", {
|
|
6287
|
+
status: 401,
|
|
6288
|
+
cause: error
|
|
6289
|
+
});
|
|
6290
|
+
}
|
|
6291
|
+
}
|
|
6292
|
+
if (response.status === 429) {
|
|
6293
|
+
const after = retryAfterMs$1(response.headers);
|
|
6294
|
+
await response.body?.cancel().catch(() => void 0);
|
|
6295
|
+
await pool.markCooldown(account.id, after ?? DEFAULT_POOL_COOLDOWN_MS, "Codex 429").catch(() => void 0);
|
|
6296
|
+
free();
|
|
5397
6297
|
if (await pool.hasAnotherAvailableAccount(tried)) continue;
|
|
5398
|
-
throw new LlmError("
|
|
5399
|
-
status:
|
|
5400
|
-
|
|
6298
|
+
throw new LlmError("Codex rate limit reached.", "RATE_LIMIT", {
|
|
6299
|
+
status: 429,
|
|
6300
|
+
...after === void 0 ? {} : { providerRetryAfterMs: after }
|
|
5401
6301
|
});
|
|
5402
6302
|
}
|
|
6303
|
+
if (!response.ok) {
|
|
6304
|
+
const error = await responseError(response);
|
|
6305
|
+
free();
|
|
6306
|
+
throw error;
|
|
6307
|
+
}
|
|
6308
|
+
this.rememberTurnState(response, turnKey, credentials);
|
|
6309
|
+
return {
|
|
6310
|
+
response,
|
|
6311
|
+
release: free
|
|
6312
|
+
};
|
|
6313
|
+
} catch (error) {
|
|
6314
|
+
free();
|
|
6315
|
+
throw error;
|
|
5403
6316
|
}
|
|
5404
|
-
if (response.status === 429) {
|
|
5405
|
-
const after = retryAfterMs$1(response.headers);
|
|
5406
|
-
await response.body?.cancel().catch(() => void 0);
|
|
5407
|
-
await pool.markCooldown(account.id, after ?? DEFAULT_POOL_COOLDOWN_MS, "Codex 429").catch(() => void 0);
|
|
5408
|
-
if (await pool.hasAnotherAvailableAccount(tried)) continue;
|
|
5409
|
-
throw new LlmError("Codex rate limit reached.", "RATE_LIMIT", {
|
|
5410
|
-
status: 429,
|
|
5411
|
-
...after === void 0 ? {} : { providerRetryAfterMs: after }
|
|
5412
|
-
});
|
|
5413
|
-
}
|
|
5414
|
-
if (!response.ok) throw await responseError(response);
|
|
5415
|
-
this.rememberTurnState(response, sessionId);
|
|
5416
|
-
return response;
|
|
5417
6317
|
}
|
|
5418
6318
|
}
|
|
5419
|
-
async request(payload, credentials, sessionId, signal) {
|
|
6319
|
+
async request(payload, credentials, sessionId, turnKey, signal) {
|
|
5420
6320
|
try {
|
|
5421
6321
|
return await this.fetchFn(CODEX_RESPONSES_URL, {
|
|
5422
6322
|
method: "POST",
|
|
5423
6323
|
headers: {
|
|
5424
|
-
...codexHeaders(credentials, sessionId, { turnState: this.
|
|
6324
|
+
...codexHeaders(credentials, sessionId, { turnState: this.turnStateFor(turnKey, credentials) }),
|
|
5425
6325
|
"content-type": "application/json",
|
|
5426
6326
|
accept: "text/event-stream"
|
|
5427
6327
|
},
|
|
@@ -5445,6 +6345,16 @@ var ResponsesClient = class {
|
|
|
5445
6345
|
function promptCacheKeyFor(sessionId) {
|
|
5446
6346
|
return sessionId;
|
|
5447
6347
|
}
|
|
6348
|
+
/** Request-local fallback; never infer a human turn identity from message history. */
|
|
6349
|
+
function turnKeyFor(sessionId) {
|
|
6350
|
+
return `${sessionId}#${createHash("sha256").update(sessionId).update("\0").update(String(perRequestNonce())).digest("hex").slice(0, 24)}`;
|
|
6351
|
+
}
|
|
6352
|
+
/** A value no two requests in this process share. */
|
|
6353
|
+
let requestCounter = 0;
|
|
6354
|
+
function perRequestNonce() {
|
|
6355
|
+
requestCounter += 1;
|
|
6356
|
+
return requestCounter;
|
|
6357
|
+
}
|
|
5448
6358
|
async function* parseResponsesStream(response, signal, hiddenSandboxControls = /* @__PURE__ */ new Set()) {
|
|
5449
6359
|
if (response.body === null) throw new LlmError("Codex returned no response stream.", "PROVIDER_ERROR");
|
|
5450
6360
|
const reader = response.body.getReader();
|
|
@@ -5750,16 +6660,28 @@ function visibleReasoningDelta(delta, currentVisibleChars, alreadyTruncated) {
|
|
|
5750
6660
|
truncated: true
|
|
5751
6661
|
};
|
|
5752
6662
|
}
|
|
6663
|
+
/**
|
|
6664
|
+
* Map one response's usage onto DSH's disjoint accounting.
|
|
6665
|
+
*
|
|
6666
|
+
* `input_tokens` is the whole input, so cached input has to be subtracted out of
|
|
6667
|
+
* it and reported on its own field. Cache WRITES are counted separately from
|
|
6668
|
+
* reads and billed separately: leaving a write inside `inputTokens` would make a
|
|
6669
|
+
* cold prefix look cheaper than it was and hide the cost of a write. A field the
|
|
6670
|
+
* service omits is unknown, not zero, so it is simply not reported.
|
|
6671
|
+
*/
|
|
5753
6672
|
function mapUsage(value) {
|
|
5754
6673
|
if (value === null) return null;
|
|
5755
6674
|
const totalInput = number(value.input_tokens) ?? 0;
|
|
5756
6675
|
const outputTokens = number(value.output_tokens) ?? 0;
|
|
5757
|
-
const
|
|
6676
|
+
const details = record$2(value.input_tokens_details);
|
|
6677
|
+
const cached = number(details?.cached_tokens);
|
|
6678
|
+
const written = number(details?.cache_write_tokens);
|
|
5758
6679
|
const reasoning = number(record$2(value.output_tokens_details)?.reasoning_tokens);
|
|
5759
6680
|
return {
|
|
5760
|
-
inputTokens: Math.max(0, totalInput - cached),
|
|
6681
|
+
inputTokens: Math.max(0, totalInput - (cached ?? 0) - (written ?? 0)),
|
|
5761
6682
|
outputTokens,
|
|
5762
|
-
...cached
|
|
6683
|
+
...cached === void 0 ? {} : { cacheReadTokens: cached },
|
|
6684
|
+
...written === void 0 ? {} : { cacheWriteTokens: written },
|
|
5763
6685
|
...reasoning === void 0 ? {} : { reasoningTokens: reasoning }
|
|
5764
6686
|
};
|
|
5765
6687
|
}
|
|
@@ -6661,7 +7583,7 @@ function field(value, name) {
|
|
|
6661
7583
|
const candidate = value[name];
|
|
6662
7584
|
return typeof candidate === "string" && candidate !== "" ? candidate : null;
|
|
6663
7585
|
}
|
|
6664
|
-
function isRecord$
|
|
7586
|
+
function isRecord$23(value) {
|
|
6665
7587
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6666
7588
|
}
|
|
6667
7589
|
function readPreferencesUpdate(value, current) {
|
|
@@ -6695,7 +7617,7 @@ function readPreferencesUpdate(value, current) {
|
|
|
6695
7617
|
patch.searchProvider = value.searchProvider;
|
|
6696
7618
|
}
|
|
6697
7619
|
if ("contextWindowOverrides" in value) {
|
|
6698
|
-
if (!isRecord$
|
|
7620
|
+
if (!isRecord$23(value.contextWindowOverrides)) throw new PreferenceError("contextWindowOverrides must be an object.");
|
|
6699
7621
|
const overrides = {};
|
|
6700
7622
|
for (const [model, contextWindow] of Object.entries(value.contextWindowOverrides)) {
|
|
6701
7623
|
if (!isCodexModelId(model)) throw new PreferenceError("Unknown Codex model for a context window override.");
|
|
@@ -7567,7 +8489,7 @@ const schemaFields = /* @__PURE__ */ new Set([
|
|
|
7567
8489
|
"required",
|
|
7568
8490
|
"propertyOrdering"
|
|
7569
8491
|
]);
|
|
7570
|
-
function isRecord$
|
|
8492
|
+
function isRecord$22(value) {
|
|
7571
8493
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7572
8494
|
}
|
|
7573
8495
|
function mergeSchemas(left, right) {
|
|
@@ -7575,7 +8497,7 @@ function mergeSchemas(left, right) {
|
|
|
7575
8497
|
...left,
|
|
7576
8498
|
...right
|
|
7577
8499
|
};
|
|
7578
|
-
if (isRecord$
|
|
8500
|
+
if (isRecord$22(left.properties) && isRecord$22(right.properties)) merged.properties = {
|
|
7579
8501
|
...left.properties,
|
|
7580
8502
|
...right.properties
|
|
7581
8503
|
};
|
|
@@ -7583,7 +8505,7 @@ function mergeSchemas(left, right) {
|
|
|
7583
8505
|
return merged;
|
|
7584
8506
|
}
|
|
7585
8507
|
function toAntigravityToolSchema(schema) {
|
|
7586
|
-
if (!isRecord$
|
|
8508
|
+
if (!isRecord$22(schema)) return schema;
|
|
7587
8509
|
const root = schema;
|
|
7588
8510
|
function resolveReference(reference) {
|
|
7589
8511
|
let target = root;
|
|
@@ -7591,13 +8513,13 @@ function toAntigravityToolSchema(schema) {
|
|
|
7591
8513
|
const path = reference === "#" ? [] : reference.slice(2).split("/");
|
|
7592
8514
|
for (const segment of path) {
|
|
7593
8515
|
const key = segment.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
7594
|
-
target = isRecord$
|
|
8516
|
+
target = isRecord$22(target) && Object.hasOwn(target, key) ? target[key] : void 0;
|
|
7595
8517
|
}
|
|
7596
|
-
if (!isRecord$
|
|
8518
|
+
if (!isRecord$22(target)) throw new LlmError(`Antigravity tool schema reference was not found: ${reference}`, "PROVIDER_ERROR");
|
|
7597
8519
|
return target;
|
|
7598
8520
|
}
|
|
7599
8521
|
function convert(node, references) {
|
|
7600
|
-
if (!isRecord$
|
|
8522
|
+
if (!isRecord$22(node)) return {};
|
|
7601
8523
|
let inherited = {};
|
|
7602
8524
|
if (typeof node.$ref === "string") {
|
|
7603
8525
|
if (references.has(node.$ref)) throw new LlmError(`Antigravity tool schema contains a recursive reference: ${node.$ref}`, "PROVIDER_ERROR");
|
|
@@ -7606,8 +8528,8 @@ function toAntigravityToolSchema(schema) {
|
|
|
7606
8528
|
if (Array.isArray(node.allOf)) for (const branch of node.allOf) inherited = mergeSchemas(inherited, convert(branch, references));
|
|
7607
8529
|
const out = {};
|
|
7608
8530
|
for (const [key, value] of Object.entries(node)) if (schemaFields.has(key)) out[key] = value;
|
|
7609
|
-
if (isRecord$
|
|
7610
|
-
if (isRecord$
|
|
8531
|
+
if (isRecord$22(node.properties)) out.properties = Object.fromEntries(Object.entries(node.properties).map(([name, child]) => [name, convert(child, references)]));
|
|
8532
|
+
if (isRecord$22(node.items)) out.items = convert(node.items, references);
|
|
7611
8533
|
const alternatives = Array.isArray(node.anyOf) ? node.anyOf : node.oneOf;
|
|
7612
8534
|
if (Array.isArray(alternatives)) out.anyOf = alternatives.map((child) => convert(child, references));
|
|
7613
8535
|
if (Array.isArray(node.type)) {
|
|
@@ -7635,10 +8557,10 @@ let toolCallCounter = 0;
|
|
|
7635
8557
|
function sanitizeText$5(text) {
|
|
7636
8558
|
return text.replace(/\0/g, "");
|
|
7637
8559
|
}
|
|
7638
|
-
function isRecord$
|
|
8560
|
+
function isRecord$21(value) {
|
|
7639
8561
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7640
8562
|
}
|
|
7641
|
-
function asString$
|
|
8563
|
+
function asString$14(value) {
|
|
7642
8564
|
return typeof value === "string" ? value : void 0;
|
|
7643
8565
|
}
|
|
7644
8566
|
function safeJsonParse$5(text) {
|
|
@@ -7654,26 +8576,26 @@ function sanitizeToolCallId(id, fallbackName) {
|
|
|
7654
8576
|
function toolCallIdNeeded(modelId, runtimeModel) {
|
|
7655
8577
|
return modelId.startsWith("claude-") || modelId.startsWith("gpt-oss-") || runtimeModel.startsWith("claude-") || runtimeModel.startsWith("gpt-oss-");
|
|
7656
8578
|
}
|
|
7657
|
-
function parseArguments(raw) {
|
|
7658
|
-
if (isRecord$
|
|
8579
|
+
function parseArguments$1(raw) {
|
|
8580
|
+
if (isRecord$21(raw)) return raw;
|
|
7659
8581
|
if (raw === void 0 || raw === null || raw === "") return {};
|
|
7660
8582
|
const parsed = typeof raw === "string" ? safeJsonParse$5(raw) : raw;
|
|
7661
|
-
return isRecord$
|
|
8583
|
+
return isRecord$21(parsed) ? parsed : {};
|
|
7662
8584
|
}
|
|
7663
8585
|
const NO_RESOLVED_IMAGES$5 = /* @__PURE__ */ new Map();
|
|
7664
8586
|
function attachmentOf$5(block) {
|
|
7665
8587
|
const attachment = block.attachment;
|
|
7666
|
-
if (!isRecord$
|
|
8588
|
+
if (!isRecord$21(attachment)) return void 0;
|
|
7667
8589
|
return typeof attachment.attachmentId === "string" ? attachment : void 0;
|
|
7668
8590
|
}
|
|
7669
|
-
function attachmentLabel$
|
|
7670
|
-
const attachment = isRecord$
|
|
7671
|
-
return asString$
|
|
8591
|
+
function attachmentLabel$6(block) {
|
|
8592
|
+
const attachment = isRecord$21(block.attachment) ? block.attachment : void 0;
|
|
8593
|
+
return asString$14(attachment?.name) || asString$14(attachment?.attachmentId);
|
|
7672
8594
|
}
|
|
7673
8595
|
function collectImageRefs$4(content, refs) {
|
|
7674
8596
|
if (!Array.isArray(content)) return;
|
|
7675
8597
|
for (const block of content) {
|
|
7676
|
-
if (!isRecord$
|
|
8598
|
+
if (!isRecord$21(block)) continue;
|
|
7677
8599
|
if (block.type === "image") {
|
|
7678
8600
|
const attachment = attachmentOf$5(block);
|
|
7679
8601
|
if (attachment) refs.set(attachment.attachmentId, attachment);
|
|
@@ -7682,7 +8604,7 @@ function collectImageRefs$4(content, refs) {
|
|
|
7682
8604
|
if (block.type === "tool-result") collectImageRefs$4(block.content, refs);
|
|
7683
8605
|
}
|
|
7684
8606
|
}
|
|
7685
|
-
function isAbort$
|
|
8607
|
+
function isAbort$4(error, signal) {
|
|
7686
8608
|
return signal?.aborted === true || error instanceof Error && error.name === "AbortError";
|
|
7687
8609
|
}
|
|
7688
8610
|
/**
|
|
@@ -7711,13 +8633,13 @@ function base64Length$4(bytes) {
|
|
|
7711
8633
|
function requestImageBytes$4(block) {
|
|
7712
8634
|
const attachment = attachmentOf$5(block);
|
|
7713
8635
|
if (attachment) return base64Length$4(attachment.bytes);
|
|
7714
|
-
const inline = asString$
|
|
8636
|
+
const inline = asString$14(block.data) || asString$14(block.base64);
|
|
7715
8637
|
return inline ? inline.length : void 0;
|
|
7716
8638
|
}
|
|
7717
8639
|
function collectRequestImageBytes$4(content, lengths) {
|
|
7718
8640
|
if (!Array.isArray(content)) return;
|
|
7719
8641
|
for (const block of content) {
|
|
7720
|
-
if (!isRecord$
|
|
8642
|
+
if (!isRecord$21(block) || block.type !== "image") continue;
|
|
7721
8643
|
const bytes = requestImageBytes$4(block);
|
|
7722
8644
|
if (bytes !== void 0) lengths.push(bytes);
|
|
7723
8645
|
}
|
|
@@ -7752,7 +8674,7 @@ function offloadOldestRequestImages$4(options) {
|
|
|
7752
8674
|
if (remaining.count === 0 || !Array.isArray(message.content)) return message;
|
|
7753
8675
|
let replaced = false;
|
|
7754
8676
|
const content = message.content.map((block) => {
|
|
7755
|
-
if (remaining.count === 0 || !isRecord$
|
|
8677
|
+
if (remaining.count === 0 || !isRecord$21(block) || block.type !== "image") return block;
|
|
7756
8678
|
if (requestImageBytes$4(block) === void 0) return block;
|
|
7757
8679
|
remaining.count -= 1;
|
|
7758
8680
|
replaced = true;
|
|
@@ -7804,21 +8726,21 @@ async function resolveRequestImages$4(options, attachments, signal) {
|
|
|
7804
8726
|
data: Buffer.from(stored.data).toString("base64")
|
|
7805
8727
|
});
|
|
7806
8728
|
} catch (error) {
|
|
7807
|
-
if (isAbort$
|
|
8729
|
+
if (isAbort$4(error, signal)) throw error;
|
|
7808
8730
|
resolved.set(attachmentId, { kind: "unavailable" });
|
|
7809
8731
|
}
|
|
7810
8732
|
}));
|
|
7811
8733
|
return resolved;
|
|
7812
8734
|
}
|
|
7813
|
-
function unavailableImageText$
|
|
7814
|
-
const label = attachmentLabel$
|
|
8735
|
+
function unavailableImageText$6(block) {
|
|
8736
|
+
const label = attachmentLabel$6(block);
|
|
7815
8737
|
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]`;
|
|
7816
8738
|
}
|
|
7817
8739
|
function imageBlockToPart(block, images) {
|
|
7818
|
-
let data = asString$
|
|
7819
|
-
const source = isRecord$
|
|
7820
|
-
if (!data && source) data = asString$
|
|
7821
|
-
let mimeType = asString$
|
|
8740
|
+
let data = asString$14(block.data) || asString$14(block.base64);
|
|
8741
|
+
const source = isRecord$21(block.source) ? block.source : void 0;
|
|
8742
|
+
if (!data && source) data = asString$14(source.data) || asString$14(source.base64);
|
|
8743
|
+
let mimeType = asString$14(block.mimeType) || asString$14(block.mediaType) || (source ? asString$14(source.mimeType) || asString$14(source.mediaType) : void 0) || "image/png";
|
|
7822
8744
|
if (data?.startsWith("data:")) {
|
|
7823
8745
|
const match = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
7824
8746
|
if (match) {
|
|
@@ -7841,10 +8763,10 @@ function contentToUserParts(content, images) {
|
|
|
7841
8763
|
if (typeof content === "string") return [{ text: sanitizeText$5(content) }];
|
|
7842
8764
|
if (!Array.isArray(content)) return [];
|
|
7843
8765
|
const parts = [];
|
|
7844
|
-
for (const block of content) if (isRecord$
|
|
7845
|
-
else if (isRecord$
|
|
8766
|
+
for (const block of content) if (isRecord$21(block) && block.type === "text" && typeof block.text === "string") parts.push({ text: sanitizeText$5(block.text) });
|
|
8767
|
+
else if (isRecord$21(block) && block.type === "image") {
|
|
7846
8768
|
const img = imageBlockToPart(block, images);
|
|
7847
|
-
parts.push(img ?? { text: unavailableImageText$
|
|
8769
|
+
parts.push(img ?? { text: unavailableImageText$6(block) });
|
|
7848
8770
|
}
|
|
7849
8771
|
return parts;
|
|
7850
8772
|
}
|
|
@@ -7857,9 +8779,9 @@ function toolResultImageParts(blocks, images) {
|
|
|
7857
8779
|
if (!Array.isArray(blocks)) return [];
|
|
7858
8780
|
const parts = [];
|
|
7859
8781
|
for (const block of blocks) {
|
|
7860
|
-
if (!isRecord$
|
|
8782
|
+
if (!isRecord$21(block)) continue;
|
|
7861
8783
|
if (block.type === "image") {
|
|
7862
|
-
parts.push(imageBlockToPart(block, images) ?? { text: unavailableImageText$
|
|
8784
|
+
parts.push(imageBlockToPart(block, images) ?? { text: unavailableImageText$6(block) });
|
|
7863
8785
|
continue;
|
|
7864
8786
|
}
|
|
7865
8787
|
if (block.type === "tool-result") parts.push(...toolResultImageParts(block.content, images));
|
|
@@ -7869,11 +8791,11 @@ function toolResultImageParts(blocks, images) {
|
|
|
7869
8791
|
function toolResultText$5(blocks) {
|
|
7870
8792
|
if (!Array.isArray(blocks)) return "";
|
|
7871
8793
|
return blocks.map((block) => {
|
|
7872
|
-
if (!isRecord$
|
|
8794
|
+
if (!isRecord$21(block)) return "";
|
|
7873
8795
|
if (block.type === "text" && typeof block.text === "string") return sanitizeText$5(block.text);
|
|
7874
8796
|
if (block.type === "tool-result") return toolResultText$5(block.content);
|
|
7875
8797
|
if (block.type === "image") {
|
|
7876
|
-
const label = attachmentLabel$
|
|
8798
|
+
const label = attachmentLabel$6(block);
|
|
7877
8799
|
return label ? `[image: ${label}]` : "[image]";
|
|
7878
8800
|
}
|
|
7879
8801
|
return "";
|
|
@@ -7883,16 +8805,16 @@ function replayBlockFor$1(message, index) {
|
|
|
7883
8805
|
const source = message.source;
|
|
7884
8806
|
if (!source || source.kind !== "model" || source.provider !== "antigravity") return void 0;
|
|
7885
8807
|
const state = source.replayState;
|
|
7886
|
-
if (!isRecord$
|
|
8808
|
+
if (!isRecord$21(state)) return void 0;
|
|
7887
8809
|
if (Array.isArray(state.blocks)) return state.blocks[index];
|
|
7888
|
-
const resp = isRecord$
|
|
8810
|
+
const resp = isRecord$21(state.response) ? state.response : void 0;
|
|
7889
8811
|
if (resp) {
|
|
7890
8812
|
if (Array.isArray(resp.outputItems)) return resp.outputItems[index];
|
|
7891
8813
|
if (Array.isArray(resp.blocks)) return resp.blocks[index];
|
|
7892
8814
|
}
|
|
7893
8815
|
}
|
|
7894
8816
|
function thoughtSignature(part) {
|
|
7895
|
-
return asString$
|
|
8817
|
+
return asString$14(part?.thoughtSignature) || asString$14(part?.thought_signature) || asString$14(part?.thinkingSignature) || asString$14(part?.textSignature);
|
|
7896
8818
|
}
|
|
7897
8819
|
function replayPart(part) {
|
|
7898
8820
|
const copy = { ...part };
|
|
@@ -7903,15 +8825,48 @@ function replayPart(part) {
|
|
|
7903
8825
|
if (typeof copy.text === "string") copy.text = sanitizeText$5(copy.text);
|
|
7904
8826
|
return copy;
|
|
7905
8827
|
}
|
|
8828
|
+
/** Claude requires a signature on each thinking block, not a separate SSE part. */
|
|
8829
|
+
function claudeReplayParts(parts) {
|
|
8830
|
+
const result = [];
|
|
8831
|
+
let pending = "";
|
|
8832
|
+
for (const part of parts) {
|
|
8833
|
+
const signature = thoughtSignature(part);
|
|
8834
|
+
if (part.thought === true && typeof part.text === "string") {
|
|
8835
|
+
pending += part.text;
|
|
8836
|
+
if (signature) {
|
|
8837
|
+
result.push({
|
|
8838
|
+
thought: true,
|
|
8839
|
+
text: pending,
|
|
8840
|
+
thoughtSignature: signature
|
|
8841
|
+
});
|
|
8842
|
+
pending = "";
|
|
8843
|
+
}
|
|
8844
|
+
continue;
|
|
8845
|
+
}
|
|
8846
|
+
if (signature && !part.functionCall && !part.functionResponse && !part.text && pending) {
|
|
8847
|
+
result.push({
|
|
8848
|
+
thought: true,
|
|
8849
|
+
text: pending,
|
|
8850
|
+
thoughtSignature: signature
|
|
8851
|
+
});
|
|
8852
|
+
pending = "";
|
|
8853
|
+
continue;
|
|
8854
|
+
}
|
|
8855
|
+
pending = "";
|
|
8856
|
+
if (part.thought !== true) result.push(part);
|
|
8857
|
+
}
|
|
8858
|
+
return result;
|
|
8859
|
+
}
|
|
7906
8860
|
function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
7907
8861
|
const parts = [];
|
|
7908
8862
|
if (!Array.isArray(message.content)) return parts;
|
|
7909
8863
|
for (let index = 0; index < message.content.length; index++) {
|
|
7910
8864
|
const block = message.content[index];
|
|
7911
|
-
if (!isRecord$
|
|
8865
|
+
if (!isRecord$21(block)) continue;
|
|
8866
|
+
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;
|
|
7912
8867
|
const replay = replayBlockFor$1(message, index);
|
|
7913
|
-
const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$
|
|
7914
|
-
if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$
|
|
8868
|
+
const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$21) : [];
|
|
8869
|
+
if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$14(part.text) || "").join("") === sanitizeText$5(String(block.text || ""))) {
|
|
7915
8870
|
parts.push(...originalParts.map(replayPart));
|
|
7916
8871
|
continue;
|
|
7917
8872
|
}
|
|
@@ -7931,8 +8886,8 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
7931
8886
|
} else if (block.type === "tool-call") {
|
|
7932
8887
|
const toolId = String(block.id || "");
|
|
7933
8888
|
const toolName = String(block.name || "");
|
|
7934
|
-
const originalCall = originalParts.find((part) => isRecord$
|
|
7935
|
-
const wireId = asString$
|
|
8889
|
+
const originalCall = originalParts.find((part) => isRecord$21(part.functionCall));
|
|
8890
|
+
const wireId = asString$14((isRecord$21(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
|
|
7936
8891
|
toolCalls.set(toolId, {
|
|
7937
8892
|
name: toolName,
|
|
7938
8893
|
id: wireId
|
|
@@ -7941,7 +8896,7 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
7941
8896
|
parts.push({
|
|
7942
8897
|
functionCall: {
|
|
7943
8898
|
name: toolName,
|
|
7944
|
-
args: parseArguments(block.arguments),
|
|
8899
|
+
args: parseArguments$1(block.arguments),
|
|
7945
8900
|
...wireId ? { id: wireId } : {}
|
|
7946
8901
|
},
|
|
7947
8902
|
...effectiveSignature ? { thoughtSignature: effectiveSignature } : {}
|
|
@@ -7949,7 +8904,7 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
7949
8904
|
parts.push(...originalParts.filter((part) => !part.functionCall).map(replayPart));
|
|
7950
8905
|
}
|
|
7951
8906
|
}
|
|
7952
|
-
return parts;
|
|
8907
|
+
return runtimeModel.startsWith("claude-") ? claudeReplayParts(parts) : parts;
|
|
7953
8908
|
}
|
|
7954
8909
|
function pushToolResult(contents, result, toolCalls, model, runtimeModel, images = NO_RESOLVED_IMAGES$5) {
|
|
7955
8910
|
const toolCallId = String(result.toolCallId || "");
|
|
@@ -7984,7 +8939,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
|
|
|
7984
8939
|
continue;
|
|
7985
8940
|
}
|
|
7986
8941
|
const content = Array.isArray(message.content) ? message.content : [];
|
|
7987
|
-
const userParts = contentToUserParts(content.filter((b) => !isRecord$
|
|
8942
|
+
const userParts = contentToUserParts(content.filter((b) => !isRecord$21(b) || b.type !== "tool-result"), images);
|
|
7988
8943
|
if (role === "system") {
|
|
7989
8944
|
if (userParts.length) contents.push({
|
|
7990
8945
|
role: GEMINI_ROLE.user,
|
|
@@ -7996,7 +8951,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
|
|
|
7996
8951
|
role: GEMINI_ROLE.user,
|
|
7997
8952
|
parts: userParts
|
|
7998
8953
|
});
|
|
7999
|
-
for (const b of content) if (isRecord$
|
|
8954
|
+
for (const b of content) if (isRecord$21(b) && b.type === "tool-result") pushToolResult(contents, b, toolCalls, model, runtimeModel, images);
|
|
8000
8955
|
}
|
|
8001
8956
|
return contents;
|
|
8002
8957
|
}
|
|
@@ -8119,7 +9074,7 @@ const USAGE_FIELDS = [
|
|
|
8119
9074
|
"totalTokenCount"
|
|
8120
9075
|
];
|
|
8121
9076
|
function collectUsage(value, state) {
|
|
8122
|
-
if (!isRecord$
|
|
9077
|
+
if (!isRecord$21(value)) return;
|
|
8123
9078
|
for (const key of USAGE_FIELDS) {
|
|
8124
9079
|
const count = value[key];
|
|
8125
9080
|
if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0) continue;
|
|
@@ -8149,15 +9104,15 @@ function processStreamLine$2(line, state) {
|
|
|
8149
9104
|
}
|
|
8150
9105
|
if (!json) return [];
|
|
8151
9106
|
const chunk = safeJsonParse$5(json);
|
|
8152
|
-
if (!isRecord$
|
|
8153
|
-
const responseData = isRecord$
|
|
9107
|
+
if (!isRecord$21(chunk)) return [];
|
|
9108
|
+
const responseData = isRecord$21(chunk.response) ? chunk.response : chunk;
|
|
8154
9109
|
const candidates = Array.isArray(responseData.candidates) ? responseData.candidates : [];
|
|
8155
|
-
const candidate = isRecord$
|
|
8156
|
-
const content = isRecord$
|
|
9110
|
+
const candidate = isRecord$21(candidates[0]) ? candidates[0] : void 0;
|
|
9111
|
+
const content = isRecord$21(candidate?.content) ? candidate.content : void 0;
|
|
8157
9112
|
const parts = Array.isArray(content?.parts) ? content.parts : [];
|
|
8158
9113
|
const out = [];
|
|
8159
9114
|
for (const part of parts) {
|
|
8160
|
-
if (!isRecord$
|
|
9115
|
+
if (!isRecord$21(part)) continue;
|
|
8161
9116
|
if (typeof part.text === "string" && part.text !== "") {
|
|
8162
9117
|
const isThinking = Boolean(part.thought);
|
|
8163
9118
|
const blockType = isThinking ? "reasoning" : "text";
|
|
@@ -8189,7 +9144,7 @@ function processStreamLine$2(line, state) {
|
|
|
8189
9144
|
index: state.currentBlock.index,
|
|
8190
9145
|
text: delta
|
|
8191
9146
|
});
|
|
8192
|
-
} else if (!isRecord$
|
|
9147
|
+
} else if (!isRecord$21(part.functionCall) && thoughtSignature(part)) {
|
|
8193
9148
|
if (state.replayBlocks.length === 0) {
|
|
8194
9149
|
const type = part.thought ? "reasoning" : "text";
|
|
8195
9150
|
state.blocks.push({
|
|
@@ -8213,12 +9168,12 @@ function processStreamLine$2(line, state) {
|
|
|
8213
9168
|
}
|
|
8214
9169
|
state.replayBlocks[state.replayBlocks.length - 1].parts.push(replayPart(part));
|
|
8215
9170
|
}
|
|
8216
|
-
if (isRecord$
|
|
9171
|
+
if (isRecord$21(part.functionCall)) {
|
|
8217
9172
|
out.push(...closeCurrentBlock(state));
|
|
8218
9173
|
const fc = part.functionCall;
|
|
8219
|
-
const toolName = asString$
|
|
8220
|
-
const toolId = asString$
|
|
8221
|
-
const argsText = JSON.stringify(isRecord$
|
|
9174
|
+
const toolName = asString$14(fc.name) || "";
|
|
9175
|
+
const toolId = asString$14(fc.id) || sanitizeToolCallId("", toolName);
|
|
9176
|
+
const argsText = JSON.stringify(isRecord$21(fc.args) ? fc.args : {});
|
|
8222
9177
|
const index = state.blocks.length;
|
|
8223
9178
|
const block = {
|
|
8224
9179
|
type: "tool-call",
|
|
@@ -8255,7 +9210,7 @@ function processStreamLine$2(line, state) {
|
|
|
8255
9210
|
}
|
|
8256
9211
|
collectUsage(chunk.usageMetadata, state);
|
|
8257
9212
|
if (responseData !== chunk) collectUsage(responseData.usageMetadata, state);
|
|
8258
|
-
const finishReason = asString$
|
|
9213
|
+
const finishReason = asString$14(candidate?.finishReason) || asString$14(responseData.finishReason);
|
|
8259
9214
|
if (finishReason) {
|
|
8260
9215
|
state.finishReason = finishReason;
|
|
8261
9216
|
out.push(...closeCurrentBlock(state));
|
|
@@ -9909,6 +10864,7 @@ const CALLBACK_ALLOWED_ORIGINS = [
|
|
|
9909
10864
|
"http://localhost:3000"
|
|
9910
10865
|
];
|
|
9911
10866
|
const DISCOVERY_TIMEOUT_MS$3 = 15e3;
|
|
10867
|
+
const CATALOG_CACHE_TTL_MS$3 = 1800 * 1e3;
|
|
9912
10868
|
const STREAM_IDLE_TIMEOUT_MS$4 = 3e5;
|
|
9913
10869
|
const STREAM_IDLE_TIMEOUT_CODE$4 = "LLM_STREAM_IDLE_TIMEOUT";
|
|
9914
10870
|
/**
|
|
@@ -9925,6 +10881,8 @@ const HEADER_PROJECT_SLUG = "x-command-code-project-slug";
|
|
|
9925
10881
|
const HEADER_TASTE_LEARNING = "x-command-code-taste-learning";
|
|
9926
10882
|
const HEADER_SESSION_ID = "x-command-code-session-id";
|
|
9927
10883
|
const HEADER_OSS_PRIMARY_PROVIDER = "x-command-code-oss-primary-provider";
|
|
10884
|
+
/** Official header that enforces Zero Data Retention (ZDR) routing. */
|
|
10885
|
+
const HEADER_ZDR = "x-cmd-zdr";
|
|
9928
10886
|
function resolveApiEnv(raw = process.env.DSH_COMMAND_CODE_ENV) {
|
|
9929
10887
|
const value = (raw || "").trim().toLowerCase();
|
|
9930
10888
|
return value === "staging" || value === "local" ? value : "prod";
|
|
@@ -9952,6 +10910,21 @@ function wireForModel$2(modelId) {
|
|
|
9952
10910
|
return /^claude[-/]/i.test(modelId.trim()) ? "anthropic" : "openai";
|
|
9953
10911
|
}
|
|
9954
10912
|
/**
|
|
10913
|
+
* Wire one catalog entry says it is served on, when the catalog said so.
|
|
10914
|
+
*
|
|
10915
|
+
* The provider publishes `supported_endpoints` per model, and that is the
|
|
10916
|
+
* authority on which route answers for it. A model the catalog does not describe
|
|
10917
|
+
* returns undefined so the caller falls back to {@link wireForModel} instead of
|
|
10918
|
+
* being sent to a route nobody vouched for.
|
|
10919
|
+
*/
|
|
10920
|
+
function wireForCatalogEntry$1(entry) {
|
|
10921
|
+
for (const endpoint of entry.supportedEndpoints ?? []) {
|
|
10922
|
+
if (/\/v1\/messages\b|\bmessages\b/i.test(endpoint)) return "anthropic";
|
|
10923
|
+
if (/\/v1\/responses\b|\bresponses\b/i.test(endpoint)) return "responses";
|
|
10924
|
+
if (/chat\/completions|\bcompletions\b/i.test(endpoint)) return "openai";
|
|
10925
|
+
}
|
|
10926
|
+
}
|
|
10927
|
+
/**
|
|
9955
10928
|
* Reasoning levels one model advertises, in DSH's vocabulary.
|
|
9956
10929
|
*
|
|
9957
10930
|
* The registry is the authority: a model it describes but gives no
|
|
@@ -10457,13 +11430,13 @@ function commandCodeHeaders(apiKey, extra = {}) {
|
|
|
10457
11430
|
function timeoutSignal$3(signal, ms) {
|
|
10458
11431
|
return signal ? AbortSignal.any([signal, AbortSignal.timeout(ms)]) : AbortSignal.timeout(ms);
|
|
10459
11432
|
}
|
|
10460
|
-
function isRecord$
|
|
11433
|
+
function isRecord$20(value) {
|
|
10461
11434
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10462
11435
|
}
|
|
10463
11436
|
function asRecord$9(value) {
|
|
10464
|
-
return isRecord$
|
|
11437
|
+
return isRecord$20(value) ? value : void 0;
|
|
10465
11438
|
}
|
|
10466
|
-
function asString$
|
|
11439
|
+
function asString$13(value) {
|
|
10467
11440
|
if (typeof value === "string" && value.trim() !== "") return value;
|
|
10468
11441
|
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
10469
11442
|
}
|
|
@@ -10476,10 +11449,19 @@ function asNumber$3(value) {
|
|
|
10476
11449
|
}
|
|
10477
11450
|
function firstString$1(record, keys) {
|
|
10478
11451
|
for (const key of keys) {
|
|
10479
|
-
const value = asString$
|
|
11452
|
+
const value = asString$13(record[key]);
|
|
10480
11453
|
if (value !== void 0) return value;
|
|
10481
11454
|
}
|
|
10482
11455
|
}
|
|
11456
|
+
/** First key that holds a non-empty array of strings. */
|
|
11457
|
+
function firstStringArray(record, keys) {
|
|
11458
|
+
for (const key of keys) {
|
|
11459
|
+
const value = record[key];
|
|
11460
|
+
if (!Array.isArray(value)) continue;
|
|
11461
|
+
const entries = value.filter((entry) => typeof entry === "string" && entry !== "");
|
|
11462
|
+
if (entries.length > 0) return entries;
|
|
11463
|
+
}
|
|
11464
|
+
}
|
|
10483
11465
|
function firstNumber$2(record, keys) {
|
|
10484
11466
|
for (const key of keys) {
|
|
10485
11467
|
const value = asNumber$3(record[key]);
|
|
@@ -10496,7 +11478,7 @@ function deepValue(value, keys, depth = 0) {
|
|
|
10496
11478
|
}
|
|
10497
11479
|
return;
|
|
10498
11480
|
}
|
|
10499
|
-
if (!isRecord$
|
|
11481
|
+
if (!isRecord$20(value)) return void 0;
|
|
10500
11482
|
for (const key of keys) if (value[key] !== void 0 && value[key] !== null) return value[key];
|
|
10501
11483
|
for (const nested of Object.values(value)) {
|
|
10502
11484
|
const hit = deepValue(nested, keys, depth + 1);
|
|
@@ -10510,7 +11492,7 @@ function collectRecords(value, keys, depth = 0, out = []) {
|
|
|
10510
11492
|
for (const entry of value) collectRecords(entry, keys, depth + 1, out);
|
|
10511
11493
|
return out;
|
|
10512
11494
|
}
|
|
10513
|
-
if (!isRecord$
|
|
11495
|
+
if (!isRecord$20(value)) return out;
|
|
10514
11496
|
if (keys.some((key) => value[key] !== void 0)) out.push(value);
|
|
10515
11497
|
for (const nested of Object.values(value)) collectRecords(nested, keys, depth + 1, out);
|
|
10516
11498
|
return out;
|
|
@@ -10714,7 +11696,7 @@ function parseCreditBalances(payload, consumed = []) {
|
|
|
10714
11696
|
/** Resolve the plan id the subscription or credits payload reports, when either does. */
|
|
10715
11697
|
function parsePlanId(payloads) {
|
|
10716
11698
|
for (const payload of payloads) {
|
|
10717
|
-
const id = asString$
|
|
11699
|
+
const id = asString$13(deepValue(payload, [
|
|
10718
11700
|
"planId",
|
|
10719
11701
|
"plan_id",
|
|
10720
11702
|
"priceId",
|
|
@@ -10733,7 +11715,7 @@ function parsePlanId(payloads) {
|
|
|
10733
11715
|
*/
|
|
10734
11716
|
function parseSubscriptionStatus(payload) {
|
|
10735
11717
|
const root = asRecord$9(payload) ?? {};
|
|
10736
|
-
return asString$
|
|
11718
|
+
return asString$13(deepValue(asRecord$9(root.data) ?? root, ["status"])) ?? null;
|
|
10737
11719
|
}
|
|
10738
11720
|
/** End of the current billing period, in Unix milliseconds. */
|
|
10739
11721
|
function parseSubscriptionPeriodEnd(payload) {
|
|
@@ -10986,6 +11968,7 @@ function extractUnlimited(payload) {
|
|
|
10986
11968
|
return deepValue(payload, ["unlimited", "isUnlimited"]) === true;
|
|
10987
11969
|
}
|
|
10988
11970
|
let cachedCatalog$1;
|
|
11971
|
+
let catalogIsRehydrated = false;
|
|
10989
11972
|
/** Bumped by every cache clear so a fetch already in flight cannot publish. */
|
|
10990
11973
|
let catalogCacheEpoch$2 = 0;
|
|
10991
11974
|
let catalogInFlight$2 = null;
|
|
@@ -11020,7 +12003,8 @@ function parseProviderModels(payload) {
|
|
|
11020
12003
|
"contextLength",
|
|
11021
12004
|
"context_window",
|
|
11022
12005
|
"contextWindow"
|
|
11023
|
-
])
|
|
12006
|
+
]),
|
|
12007
|
+
...firstStringArray(record, ["supported_endpoints", "supportedEndpoints"]) === void 0 ? {} : { supportedEndpoints: firstStringArray(record, ["supported_endpoints", "supportedEndpoints"]) }
|
|
11024
12008
|
});
|
|
11025
12009
|
}
|
|
11026
12010
|
return models;
|
|
@@ -11067,6 +12051,7 @@ async function loadProviderModels(options = {}) {
|
|
|
11067
12051
|
models,
|
|
11068
12052
|
fetchedAt
|
|
11069
12053
|
};
|
|
12054
|
+
catalogIsRehydrated = true;
|
|
11070
12055
|
}, 0);
|
|
11071
12056
|
const warm = cachedCatalog$1;
|
|
11072
12057
|
if (rehydratedAt > 0 && warm !== void 0) {
|
|
@@ -11088,6 +12073,7 @@ function refreshProviderModels$1(options = {}) {
|
|
|
11088
12073
|
models,
|
|
11089
12074
|
fetchedAt
|
|
11090
12075
|
};
|
|
12076
|
+
catalogIsRehydrated = false;
|
|
11091
12077
|
writeCatalogSnapshot(catalogSnapshotName("command-code", options.apiEnv ?? resolveApiEnv()), models, fetchedAt);
|
|
11092
12078
|
}
|
|
11093
12079
|
return models.length > 0 ? models : cachedCatalog$1?.models ?? [];
|
|
@@ -11097,10 +12083,19 @@ function refreshProviderModels$1(options = {}) {
|
|
|
11097
12083
|
if (catalogInFlight$2 === request) catalogInFlight$2 = null;
|
|
11098
12084
|
});
|
|
11099
12085
|
}
|
|
12086
|
+
function isCatalogStale() {
|
|
12087
|
+
if (cachedCatalog$1 === void 0) return true;
|
|
12088
|
+
if (catalogIsRehydrated) return true;
|
|
12089
|
+
return Date.now() - cachedCatalog$1.fetchedAt >= CATALOG_CACHE_TTL_MS$3;
|
|
12090
|
+
}
|
|
12091
|
+
function getCachedCatalogFetchedAt() {
|
|
12092
|
+
return cachedCatalog$1?.fetchedAt ?? null;
|
|
12093
|
+
}
|
|
11100
12094
|
function clearCachedCatalog$3() {
|
|
11101
12095
|
catalogCacheEpoch$2 += 1;
|
|
11102
12096
|
cachedCatalog$1 = void 0;
|
|
11103
12097
|
catalogInFlight$2 = null;
|
|
12098
|
+
catalogIsRehydrated = false;
|
|
11104
12099
|
catalogSnapshotScopesLoaded$2.clear();
|
|
11105
12100
|
}
|
|
11106
12101
|
async function getJson(path, apiKey, options = {}) {
|
|
@@ -11256,7 +12251,7 @@ function buildModelOptions$2(catalog, enabledModelIds, overrides) {
|
|
|
11256
12251
|
contextWindow: overrides[model.id] && overrides[model.id] > 0 ? overrides[model.id] : contextWindow,
|
|
11257
12252
|
defaultMaxTokens: maxOutputTokensFor$4(model.id),
|
|
11258
12253
|
...efforts.length > 0 ? { reasoningEfforts: efforts } : {},
|
|
11259
|
-
wire: wireForModel$2(model.id)
|
|
12254
|
+
wire: wireForCatalogEntry$1(model) ?? wireForModel$2(model.id)
|
|
11260
12255
|
};
|
|
11261
12256
|
});
|
|
11262
12257
|
}
|
|
@@ -11272,10 +12267,10 @@ function buildModelOptions$2(catalog, enabledModelIds, overrides) {
|
|
|
11272
12267
|
*
|
|
11273
12268
|
* https://commandcode.ai/blog/command-code-provider-api
|
|
11274
12269
|
*/
|
|
11275
|
-
function isRecord$
|
|
12270
|
+
function isRecord$19(value) {
|
|
11276
12271
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11277
12272
|
}
|
|
11278
|
-
function asString$
|
|
12273
|
+
function asString$12(value) {
|
|
11279
12274
|
return typeof value === "string" ? value : void 0;
|
|
11280
12275
|
}
|
|
11281
12276
|
function safeJsonParse$4(text) {
|
|
@@ -11288,7 +12283,7 @@ function safeJsonParse$4(text) {
|
|
|
11288
12283
|
function sanitizeText$4(text) {
|
|
11289
12284
|
return text.replace(/\0/g, "");
|
|
11290
12285
|
}
|
|
11291
|
-
function isAbort$
|
|
12286
|
+
function isAbort$3(error, signal) {
|
|
11292
12287
|
return signal?.aborted === true || error instanceof Error && error.name === "AbortError";
|
|
11293
12288
|
}
|
|
11294
12289
|
const NO_RESOLVED_IMAGES$4 = /* @__PURE__ */ new Map();
|
|
@@ -11312,17 +12307,17 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$4 = /* @__PURE__ */ new Set([
|
|
|
11312
12307
|
]);
|
|
11313
12308
|
function attachmentOf$4(block) {
|
|
11314
12309
|
const attachment = block.attachment;
|
|
11315
|
-
if (!isRecord$
|
|
12310
|
+
if (!isRecord$19(attachment)) return void 0;
|
|
11316
12311
|
return typeof attachment.attachmentId === "string" ? attachment : void 0;
|
|
11317
12312
|
}
|
|
11318
|
-
function attachmentLabel$
|
|
11319
|
-
const attachment = isRecord$
|
|
11320
|
-
return asString$
|
|
12313
|
+
function attachmentLabel$5(block) {
|
|
12314
|
+
const attachment = isRecord$19(block.attachment) ? block.attachment : void 0;
|
|
12315
|
+
return asString$12(attachment?.name) || asString$12(attachment?.attachmentId);
|
|
11321
12316
|
}
|
|
11322
12317
|
function collectImageRefs$3(content, refs) {
|
|
11323
12318
|
if (!Array.isArray(content)) return;
|
|
11324
12319
|
for (const block of content) {
|
|
11325
|
-
if (!isRecord$
|
|
12320
|
+
if (!isRecord$19(block)) continue;
|
|
11326
12321
|
if (block.type === "image") {
|
|
11327
12322
|
const attachment = attachmentOf$4(block);
|
|
11328
12323
|
if (attachment) refs.set(attachment.attachmentId, attachment);
|
|
@@ -11337,13 +12332,13 @@ function base64Length$3(bytes) {
|
|
|
11337
12332
|
function requestImageBytes$3(block) {
|
|
11338
12333
|
const attachment = attachmentOf$4(block);
|
|
11339
12334
|
if (attachment) return base64Length$3(attachment.bytes);
|
|
11340
|
-
const inline = asString$
|
|
12335
|
+
const inline = asString$12(block.data) || asString$12(block.base64);
|
|
11341
12336
|
return inline ? inline.length : void 0;
|
|
11342
12337
|
}
|
|
11343
12338
|
function collectRequestImageBytes$3(content, lengths) {
|
|
11344
12339
|
if (!Array.isArray(content)) return;
|
|
11345
12340
|
for (const block of content) {
|
|
11346
|
-
if (!isRecord$
|
|
12341
|
+
if (!isRecord$19(block) || block.type !== "image") continue;
|
|
11347
12342
|
const bytes = requestImageBytes$3(block);
|
|
11348
12343
|
if (bytes !== void 0) lengths.push(bytes);
|
|
11349
12344
|
}
|
|
@@ -11370,7 +12365,7 @@ function offloadOldestRequestImages$3(options) {
|
|
|
11370
12365
|
if (remaining.count === 0 || !Array.isArray(message.content)) return message;
|
|
11371
12366
|
let replaced = false;
|
|
11372
12367
|
const content = message.content.map((block) => {
|
|
11373
|
-
if (remaining.count === 0 || !isRecord$
|
|
12368
|
+
if (remaining.count === 0 || !isRecord$19(block) || block.type !== "image") return block;
|
|
11374
12369
|
if (requestImageBytes$3(block) === void 0) return block;
|
|
11375
12370
|
remaining.count -= 1;
|
|
11376
12371
|
replaced = true;
|
|
@@ -11412,21 +12407,21 @@ async function resolveRequestImages$3(options, attachments, signal) {
|
|
|
11412
12407
|
data: Buffer.from(stored.data).toString("base64")
|
|
11413
12408
|
});
|
|
11414
12409
|
} catch (error) {
|
|
11415
|
-
if (isAbort$
|
|
12410
|
+
if (isAbort$3(error, signal)) throw error;
|
|
11416
12411
|
resolved.set(attachmentId, { kind: "unavailable" });
|
|
11417
12412
|
}
|
|
11418
12413
|
}));
|
|
11419
12414
|
return resolved;
|
|
11420
12415
|
}
|
|
11421
|
-
function unavailableImageText$
|
|
11422
|
-
const label = attachmentLabel$
|
|
12416
|
+
function unavailableImageText$5(block) {
|
|
12417
|
+
const label = attachmentLabel$5(block);
|
|
11423
12418
|
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]`;
|
|
11424
12419
|
}
|
|
11425
12420
|
function imageBlockToInline$3(block, images) {
|
|
11426
|
-
let data = asString$
|
|
11427
|
-
const source = isRecord$
|
|
11428
|
-
if (!data && source) data = asString$
|
|
11429
|
-
let mediaType = asString$
|
|
12421
|
+
let data = asString$12(block.data) || asString$12(block.base64);
|
|
12422
|
+
const source = isRecord$19(block.source) ? block.source : void 0;
|
|
12423
|
+
if (!data && source) data = asString$12(source.data) || asString$12(source.base64);
|
|
12424
|
+
let mediaType = asString$12(block.mimeType) || asString$12(block.mediaType) || (source ? asString$12(source.mimeType) || asString$12(source.mediaType) : void 0) || "image/png";
|
|
11430
12425
|
if (data?.startsWith("data:")) {
|
|
11431
12426
|
const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
11432
12427
|
if (matched) {
|
|
@@ -11450,7 +12445,7 @@ function textOf$5(content) {
|
|
|
11450
12445
|
if (!Array.isArray(content)) return "";
|
|
11451
12446
|
const parts = [];
|
|
11452
12447
|
for (const block of content) {
|
|
11453
|
-
if (!isRecord$
|
|
12448
|
+
if (!isRecord$19(block)) continue;
|
|
11454
12449
|
if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$4(block.text));
|
|
11455
12450
|
else if (block.type === "tool-result") parts.push(textOf$5(block.content));
|
|
11456
12451
|
}
|
|
@@ -11459,10 +12454,10 @@ function textOf$5(content) {
|
|
|
11459
12454
|
function toolResultText$4(blocks) {
|
|
11460
12455
|
if (!Array.isArray(blocks)) return "";
|
|
11461
12456
|
return blocks.map((block) => {
|
|
11462
|
-
if (!isRecord$
|
|
12457
|
+
if (!isRecord$19(block)) return "";
|
|
11463
12458
|
if (block.type === "text" && typeof block.text === "string") return sanitizeText$4(block.text);
|
|
11464
12459
|
if (block.type === "tool-result") return toolResultText$4(block.content);
|
|
11465
|
-
if (block.type === "image") return `[image: ${attachmentLabel$
|
|
12460
|
+
if (block.type === "image") return `[image: ${attachmentLabel$5(block) ?? "attached image"}]`;
|
|
11466
12461
|
return "";
|
|
11467
12462
|
}).join("");
|
|
11468
12463
|
}
|
|
@@ -11477,7 +12472,7 @@ function toolResultBlocks$2(blocks, images) {
|
|
|
11477
12472
|
const out = [];
|
|
11478
12473
|
let hasImage = false;
|
|
11479
12474
|
for (const block of blocks) {
|
|
11480
|
-
if (!isRecord$
|
|
12475
|
+
if (!isRecord$19(block)) continue;
|
|
11481
12476
|
if (block.type === "text" && typeof block.text === "string") {
|
|
11482
12477
|
out.push({
|
|
11483
12478
|
type: "text",
|
|
@@ -11498,7 +12493,7 @@ function toolResultBlocks$2(blocks, images) {
|
|
|
11498
12493
|
});
|
|
11499
12494
|
else out.push({
|
|
11500
12495
|
type: "text",
|
|
11501
|
-
text: unavailableImageText$
|
|
12496
|
+
text: unavailableImageText$5(block)
|
|
11502
12497
|
});
|
|
11503
12498
|
continue;
|
|
11504
12499
|
}
|
|
@@ -11526,7 +12521,7 @@ function toolResultImageBlocks$2(blocks, images) {
|
|
|
11526
12521
|
if (!Array.isArray(blocks)) return [];
|
|
11527
12522
|
const out = [];
|
|
11528
12523
|
for (const block of blocks) {
|
|
11529
|
-
if (!isRecord$
|
|
12524
|
+
if (!isRecord$19(block)) continue;
|
|
11530
12525
|
if (block.type === "image") {
|
|
11531
12526
|
const inline = imageBlockToInline$3(block, images);
|
|
11532
12527
|
if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
|
|
@@ -11535,7 +12530,7 @@ function toolResultImageBlocks$2(blocks, images) {
|
|
|
11535
12530
|
});
|
|
11536
12531
|
else out.push({
|
|
11537
12532
|
type: "text",
|
|
11538
|
-
text: unavailableImageText$
|
|
12533
|
+
text: unavailableImageText$5(block)
|
|
11539
12534
|
});
|
|
11540
12535
|
continue;
|
|
11541
12536
|
}
|
|
@@ -11570,7 +12565,7 @@ function nonSystemMessages$4(options) {
|
|
|
11570
12565
|
}
|
|
11571
12566
|
/** Drop the JSON-Schema keywords provider gateways reject or ignore. */
|
|
11572
12567
|
function stripMetaSchema$2(schema) {
|
|
11573
|
-
if (!isRecord$
|
|
12568
|
+
if (!isRecord$19(schema)) return {
|
|
11574
12569
|
type: "object",
|
|
11575
12570
|
properties: {}
|
|
11576
12571
|
};
|
|
@@ -11587,7 +12582,7 @@ function openAIUserContent$2(message, images) {
|
|
|
11587
12582
|
const parts = [];
|
|
11588
12583
|
let hasImage = false;
|
|
11589
12584
|
for (const block of message.content) {
|
|
11590
|
-
if (!isRecord$
|
|
12585
|
+
if (!isRecord$19(block)) continue;
|
|
11591
12586
|
if (block.type === "text" && typeof block.text === "string") {
|
|
11592
12587
|
const text = sanitizeText$4(block.text);
|
|
11593
12588
|
if (text !== "") parts.push({
|
|
@@ -11604,7 +12599,7 @@ function openAIUserContent$2(message, images) {
|
|
|
11604
12599
|
});
|
|
11605
12600
|
} else parts.push({
|
|
11606
12601
|
type: "text",
|
|
11607
|
-
text: unavailableImageText$
|
|
12602
|
+
text: unavailableImageText$5(block)
|
|
11608
12603
|
});
|
|
11609
12604
|
}
|
|
11610
12605
|
}
|
|
@@ -11615,7 +12610,7 @@ function openAIAssistantContent$2(message) {
|
|
|
11615
12610
|
const textParts = [];
|
|
11616
12611
|
const toolCalls = [];
|
|
11617
12612
|
for (const block of message.content) {
|
|
11618
|
-
if (!isRecord$
|
|
12613
|
+
if (!isRecord$19(block)) continue;
|
|
11619
12614
|
if (block.type === "text" && typeof block.text === "string") textParts.push(sanitizeText$4(block.text));
|
|
11620
12615
|
else if (block.type === "tool-call" && typeof block.name === "string") toolCalls.push({
|
|
11621
12616
|
id: typeof block.id === "string" && block.id !== "" ? block.id : `call_${toolCalls.length}`,
|
|
@@ -11647,7 +12642,7 @@ function buildOpenAIRequest$1(options, images = NO_RESOLVED_IMAGES$4) {
|
|
|
11647
12642
|
while (index < conversation.length && isToolResultMessage$4(conversation[index])) {
|
|
11648
12643
|
const current = conversation[index];
|
|
11649
12644
|
const block = current.content[0];
|
|
11650
|
-
const callId = isRecord$
|
|
12645
|
+
const callId = isRecord$19(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
|
|
11651
12646
|
messages.push({
|
|
11652
12647
|
role: "tool",
|
|
11653
12648
|
tool_call_id: callId,
|
|
@@ -11708,7 +12703,7 @@ function anthropicUserContent$2(message, images) {
|
|
|
11708
12703
|
if (!Array.isArray(message.content)) return [];
|
|
11709
12704
|
const blocks = [];
|
|
11710
12705
|
for (const block of message.content) {
|
|
11711
|
-
if (!isRecord$
|
|
12706
|
+
if (!isRecord$19(block)) continue;
|
|
11712
12707
|
if (block.type === "text" && typeof block.text === "string") {
|
|
11713
12708
|
const text = sanitizeText$4(block.text);
|
|
11714
12709
|
if (text !== "") blocks.push({
|
|
@@ -11727,7 +12722,7 @@ function anthropicUserContent$2(message, images) {
|
|
|
11727
12722
|
});
|
|
11728
12723
|
else blocks.push({
|
|
11729
12724
|
type: "text",
|
|
11730
|
-
text: unavailableImageText$
|
|
12725
|
+
text: unavailableImageText$5(block)
|
|
11731
12726
|
});
|
|
11732
12727
|
} else if (block.type === "tool-result") {
|
|
11733
12728
|
const callId = typeof block.toolCallId === "string" ? block.toolCallId : "";
|
|
@@ -11745,7 +12740,7 @@ function anthropicUserContent$2(message, images) {
|
|
|
11745
12740
|
function anthropicAssistantContent$2(message) {
|
|
11746
12741
|
const blocks = [];
|
|
11747
12742
|
for (const block of message.content) {
|
|
11748
|
-
if (!isRecord$
|
|
12743
|
+
if (!isRecord$19(block)) continue;
|
|
11749
12744
|
if (block.type === "text" && typeof block.text === "string") {
|
|
11750
12745
|
const text = sanitizeText$4(block.text);
|
|
11751
12746
|
if (text !== "") blocks.push({
|
|
@@ -11758,7 +12753,7 @@ function anthropicAssistantContent$2(message) {
|
|
|
11758
12753
|
type: "tool_use",
|
|
11759
12754
|
id: typeof block.id === "string" && block.id !== "" ? block.id : `toolu_${blocks.length}`,
|
|
11760
12755
|
name: block.name,
|
|
11761
|
-
input: isRecord$
|
|
12756
|
+
input: isRecord$19(parsed) ? parsed : {}
|
|
11762
12757
|
});
|
|
11763
12758
|
}
|
|
11764
12759
|
}
|
|
@@ -11835,7 +12830,136 @@ function buildAnthropicRequest$1(options, images = NO_RESOLVED_IMAGES$4) {
|
|
|
11835
12830
|
}
|
|
11836
12831
|
/** Build the body for whichever endpoint serves `modelId`. */
|
|
11837
12832
|
function buildRequest$1(options, wire, images = NO_RESOLVED_IMAGES$4) {
|
|
11838
|
-
|
|
12833
|
+
if (wire === "anthropic") return buildAnthropicRequest$1(options, images);
|
|
12834
|
+
if (wire === "responses") return buildResponsesRequest(options, images);
|
|
12835
|
+
return buildOpenAIRequest$1(options, images);
|
|
12836
|
+
}
|
|
12837
|
+
/**
|
|
12838
|
+
* Build one `/responses` body.
|
|
12839
|
+
*
|
|
12840
|
+
* The Responses API takes a flat `input` list instead of `messages`, and its
|
|
12841
|
+
* reasoning and tool calls are item types rather than message fields. This is a
|
|
12842
|
+
* separate builder rather than a reshaping of the Chat Completions one: the two
|
|
12843
|
+
* APIs differ in more than field names, and a translated body is a request the
|
|
12844
|
+
* route rejects.
|
|
12845
|
+
*/
|
|
12846
|
+
function responsesUserContent(message, images) {
|
|
12847
|
+
if (!Array.isArray(message.content)) return [];
|
|
12848
|
+
const parts = [];
|
|
12849
|
+
for (const block of message.content) {
|
|
12850
|
+
if (!isRecord$19(block)) continue;
|
|
12851
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
12852
|
+
const text = sanitizeText$4(block.text);
|
|
12853
|
+
if (text !== "") parts.push({
|
|
12854
|
+
type: "input_text",
|
|
12855
|
+
text
|
|
12856
|
+
});
|
|
12857
|
+
} else if (block.type === "image") {
|
|
12858
|
+
const inline = imageBlockToInline$3(block, images);
|
|
12859
|
+
if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) parts.push({
|
|
12860
|
+
type: "input_image",
|
|
12861
|
+
image_url: "data:" + inline.mediaType + ";base64," + inline.data
|
|
12862
|
+
});
|
|
12863
|
+
else parts.push({
|
|
12864
|
+
type: "input_text",
|
|
12865
|
+
text: unavailableImageText$5(block)
|
|
12866
|
+
});
|
|
12867
|
+
}
|
|
12868
|
+
}
|
|
12869
|
+
return parts;
|
|
12870
|
+
}
|
|
12871
|
+
function responsesToolResultImageBlocks(blocks, images) {
|
|
12872
|
+
if (!Array.isArray(blocks)) return [];
|
|
12873
|
+
const out = [];
|
|
12874
|
+
for (const block of blocks) {
|
|
12875
|
+
if (!isRecord$19(block)) continue;
|
|
12876
|
+
if (block.type === "image") {
|
|
12877
|
+
const inline = imageBlockToInline$3(block, images);
|
|
12878
|
+
if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
|
|
12879
|
+
type: "input_image",
|
|
12880
|
+
image_url: "data:" + inline.mediaType + ";base64," + inline.data
|
|
12881
|
+
});
|
|
12882
|
+
else out.push({
|
|
12883
|
+
type: "input_text",
|
|
12884
|
+
text: unavailableImageText$5(block)
|
|
12885
|
+
});
|
|
12886
|
+
continue;
|
|
12887
|
+
}
|
|
12888
|
+
if (block.type === "tool-result") out.push(...responsesToolResultImageBlocks(block.content, images));
|
|
12889
|
+
}
|
|
12890
|
+
return out;
|
|
12891
|
+
}
|
|
12892
|
+
function buildResponsesRequest(options, images = NO_RESOLVED_IMAGES$4) {
|
|
12893
|
+
const input = [];
|
|
12894
|
+
const system = leadingSystemText$4(options);
|
|
12895
|
+
const conversation = nonSystemMessages$4(options);
|
|
12896
|
+
for (let index = 0; index < conversation.length; index++) {
|
|
12897
|
+
const message = conversation[index];
|
|
12898
|
+
if (isToolResultMessage$4(message)) {
|
|
12899
|
+
const imageBlocks = [];
|
|
12900
|
+
while (index < conversation.length && isToolResultMessage$4(conversation[index])) {
|
|
12901
|
+
const current = conversation[index];
|
|
12902
|
+
const toolResult = Array.isArray(current.content) ? current.content.find((b) => isRecord$19(b) && b.type === "tool-result") : void 0;
|
|
12903
|
+
const callId = (isRecord$19(toolResult) && typeof toolResult.toolCallId === "string" ? toolResult.toolCallId : "") || (typeof current.source?.callId === "string" ? current.source.callId : "");
|
|
12904
|
+
input.push({
|
|
12905
|
+
type: "function_call_output",
|
|
12906
|
+
call_id: callId,
|
|
12907
|
+
output: toolResultText$4(current.content)
|
|
12908
|
+
});
|
|
12909
|
+
imageBlocks.push(...responsesToolResultImageBlocks(current.content, images));
|
|
12910
|
+
index += 1;
|
|
12911
|
+
}
|
|
12912
|
+
index -= 1;
|
|
12913
|
+
if (imageBlocks.length > 0) input.push({
|
|
12914
|
+
role: "user",
|
|
12915
|
+
content: imageBlocks
|
|
12916
|
+
});
|
|
12917
|
+
continue;
|
|
12918
|
+
}
|
|
12919
|
+
if (message.role === "assistant") {
|
|
12920
|
+
const { content, toolCalls } = openAIAssistantContent$2(message);
|
|
12921
|
+
if (content !== "") input.push({
|
|
12922
|
+
role: "assistant",
|
|
12923
|
+
content
|
|
12924
|
+
});
|
|
12925
|
+
for (const call of toolCalls) {
|
|
12926
|
+
const fn = isRecord$19(call.function) ? call.function : void 0;
|
|
12927
|
+
input.push({
|
|
12928
|
+
type: "function_call",
|
|
12929
|
+
call_id: call.id,
|
|
12930
|
+
name: typeof fn?.name === "string" ? fn.name : "",
|
|
12931
|
+
arguments: typeof fn?.arguments === "string" ? fn.arguments : "{}"
|
|
12932
|
+
});
|
|
12933
|
+
}
|
|
12934
|
+
continue;
|
|
12935
|
+
}
|
|
12936
|
+
const content = responsesUserContent(message, images);
|
|
12937
|
+
if (content.length === 0) continue;
|
|
12938
|
+
input.push({
|
|
12939
|
+
role: "user",
|
|
12940
|
+
content
|
|
12941
|
+
});
|
|
12942
|
+
}
|
|
12943
|
+
const effort = wireReasoningEffort(options.reasoningEffort === void 0 ? void 0 : String(options.reasoningEffort));
|
|
12944
|
+
const maxTokens = options.maxTokens ?? maxOutputTokensFor$4(options.model);
|
|
12945
|
+
return {
|
|
12946
|
+
model: options.model,
|
|
12947
|
+
input,
|
|
12948
|
+
stream: true,
|
|
12949
|
+
max_output_tokens: maxTokens,
|
|
12950
|
+
...system === void 0 ? {} : { instructions: system },
|
|
12951
|
+
...options.temperature === void 0 ? {} : { temperature: options.temperature },
|
|
12952
|
+
...options.tools && options.tools.length > 0 ? {
|
|
12953
|
+
tools: options.tools.map((tool) => ({
|
|
12954
|
+
type: "function",
|
|
12955
|
+
name: tool.name,
|
|
12956
|
+
description: tool.description,
|
|
12957
|
+
parameters: stripMetaSchema$2(tool.parameters)
|
|
12958
|
+
})),
|
|
12959
|
+
tool_choice: "auto"
|
|
12960
|
+
} : {},
|
|
12961
|
+
...effort === void 0 || effort === "" ? {} : { reasoning: { effort } }
|
|
12962
|
+
};
|
|
11839
12963
|
}
|
|
11840
12964
|
function createStreamState$5(wire) {
|
|
11841
12965
|
return {
|
|
@@ -11922,24 +13046,24 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
11922
13046
|
}
|
|
11923
13047
|
if (payload === "") return [];
|
|
11924
13048
|
const chunk = safeJsonParse$4(payload);
|
|
11925
|
-
if (!isRecord$
|
|
13049
|
+
if (!isRecord$19(chunk)) return [];
|
|
11926
13050
|
const out = [];
|
|
11927
|
-
const usage = isRecord$
|
|
13051
|
+
const usage = isRecord$19(chunk.usage) ? chunk.usage : void 0;
|
|
11928
13052
|
if (usage) {
|
|
11929
13053
|
state.sawUsage = true;
|
|
11930
13054
|
const prompt = numberOr$5(usage.prompt_tokens, 0);
|
|
11931
|
-
const details = isRecord$
|
|
13055
|
+
const details = isRecord$19(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
|
|
11932
13056
|
const cached = details ? numberOr$5(details.cached_tokens, 0) : 0;
|
|
11933
13057
|
state.inputTokens = Math.max(0, prompt - cached);
|
|
11934
13058
|
state.cacheReadTokens = cached;
|
|
11935
13059
|
state.outputTokens = numberOr$5(usage.completion_tokens, state.outputTokens);
|
|
11936
|
-
if (isRecord$
|
|
13060
|
+
if (isRecord$19(usage.completion_tokens_details)) state.reasoningTokens = numberOr$5(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
|
|
11937
13061
|
}
|
|
11938
13062
|
const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
|
|
11939
|
-
const choice = isRecord$
|
|
11940
|
-
const delta = isRecord$
|
|
13063
|
+
const choice = isRecord$19(choices[0]) ? choices[0] : void 0;
|
|
13064
|
+
const delta = isRecord$19(choice?.delta) ? choice.delta : void 0;
|
|
11941
13065
|
if (delta) {
|
|
11942
|
-
const reasoning = asString$
|
|
13066
|
+
const reasoning = asString$12(delta.reasoning_content) ?? asString$12(delta.reasoning);
|
|
11943
13067
|
if (reasoning !== void 0 && reasoning !== "") {
|
|
11944
13068
|
out.push(...closeToolCalls$4(state));
|
|
11945
13069
|
if (state.current === null || state.current.type !== "reasoning") out.push(...openTextBlock$3(state, "reasoning"));
|
|
@@ -11951,7 +13075,7 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
11951
13075
|
text: sanitizeText$4(reasoning)
|
|
11952
13076
|
});
|
|
11953
13077
|
}
|
|
11954
|
-
const content = asString$
|
|
13078
|
+
const content = asString$12(delta.content);
|
|
11955
13079
|
if (content !== void 0 && content !== "") {
|
|
11956
13080
|
out.push(...closeToolCalls$4(state));
|
|
11957
13081
|
if (state.current === null || state.current.type !== "text") out.push(...openTextBlock$3(state, "text"));
|
|
@@ -11965,11 +13089,11 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
11965
13089
|
}
|
|
11966
13090
|
const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
|
|
11967
13091
|
for (const entry of toolDeltas) {
|
|
11968
|
-
if (!isRecord$
|
|
13092
|
+
if (!isRecord$19(entry)) continue;
|
|
11969
13093
|
out.push(...applyOpenAIToolDelta$1(entry, state));
|
|
11970
13094
|
}
|
|
11971
13095
|
}
|
|
11972
|
-
const finish = asString$
|
|
13096
|
+
const finish = asString$12(choice?.finish_reason);
|
|
11973
13097
|
if (finish !== void 0 && finish !== "") {
|
|
11974
13098
|
state.finishReason = finish;
|
|
11975
13099
|
out.push(...closeCurrent$3(state));
|
|
@@ -11979,15 +13103,15 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
11979
13103
|
}
|
|
11980
13104
|
function applyOpenAIToolDelta$1(entry, state) {
|
|
11981
13105
|
const wireIndex = typeof entry.index === "number" ? entry.index : 0;
|
|
11982
|
-
const fn = isRecord$
|
|
13106
|
+
const fn = isRecord$19(entry.function) ? entry.function : {};
|
|
11983
13107
|
const out = [];
|
|
11984
13108
|
let call = state.toolCalls.get(wireIndex);
|
|
11985
13109
|
if (call === void 0) {
|
|
11986
13110
|
out.push(...closeCurrent$3(state));
|
|
11987
13111
|
call = {
|
|
11988
13112
|
blockIndex: state.blocks.length,
|
|
11989
|
-
id: asString$
|
|
11990
|
-
name: asString$
|
|
13113
|
+
id: asString$12(entry.id) ?? `call_${wireIndex}`,
|
|
13114
|
+
name: asString$12(fn.name) ?? "",
|
|
11991
13115
|
arguments: "",
|
|
11992
13116
|
started: false
|
|
11993
13117
|
};
|
|
@@ -12000,13 +13124,13 @@ function applyOpenAIToolDelta$1(entry, state) {
|
|
|
12000
13124
|
state.toolCalls.set(wireIndex, call);
|
|
12001
13125
|
} else {
|
|
12002
13126
|
if (call.id === `call_${wireIndex}`) {
|
|
12003
|
-
const id = asString$
|
|
13127
|
+
const id = asString$12(entry.id);
|
|
12004
13128
|
if (id !== void 0) call.id = id;
|
|
12005
13129
|
}
|
|
12006
|
-
const name = asString$
|
|
13130
|
+
const name = asString$12(fn.name);
|
|
12007
13131
|
if (name !== void 0 && name !== "") call.name = name;
|
|
12008
13132
|
}
|
|
12009
|
-
const argsDelta = asString$
|
|
13133
|
+
const argsDelta = asString$12(fn.arguments) ?? "";
|
|
12010
13134
|
if (argsDelta !== "") call.arguments += argsDelta;
|
|
12011
13135
|
if (!call.started) {
|
|
12012
13136
|
call.started = true;
|
|
@@ -12037,12 +13161,12 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
12037
13161
|
const payload = trimmed.slice(5).trim();
|
|
12038
13162
|
if (payload === "" || payload === "[DONE]") return [];
|
|
12039
13163
|
const event = safeJsonParse$4(payload);
|
|
12040
|
-
if (!isRecord$
|
|
12041
|
-
const type = asString$
|
|
13164
|
+
if (!isRecord$19(event)) return [];
|
|
13165
|
+
const type = asString$12(event.type);
|
|
12042
13166
|
const out = [];
|
|
12043
13167
|
if (type === "message_start") {
|
|
12044
|
-
const message = isRecord$
|
|
12045
|
-
const usage = message && isRecord$
|
|
13168
|
+
const message = isRecord$19(event.message) ? event.message : void 0;
|
|
13169
|
+
const usage = message && isRecord$19(message.usage) ? message.usage : void 0;
|
|
12046
13170
|
if (usage) {
|
|
12047
13171
|
state.sawUsage = true;
|
|
12048
13172
|
state.inputTokens = numberOr$5(usage.input_tokens, 0);
|
|
@@ -12050,21 +13174,21 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
12050
13174
|
state.cacheWriteTokens = numberOr$5(usage.cache_creation_input_tokens, 0);
|
|
12051
13175
|
state.outputTokens = numberOr$5(usage.output_tokens, 0);
|
|
12052
13176
|
}
|
|
12053
|
-
const stop = message ? asString$
|
|
13177
|
+
const stop = message ? asString$12(message.stop_reason) : void 0;
|
|
12054
13178
|
if (stop !== void 0 && stop !== null) state.finishReason = stop;
|
|
12055
13179
|
return out;
|
|
12056
13180
|
}
|
|
12057
13181
|
if (type === "content_block_start") {
|
|
12058
13182
|
const contentIndex = numberOr$5(event.index, 0);
|
|
12059
|
-
const block = isRecord$
|
|
12060
|
-
const blockType = asString$
|
|
13183
|
+
const block = isRecord$19(event.content_block) ? event.content_block : {};
|
|
13184
|
+
const blockType = asString$12(block.type);
|
|
12061
13185
|
out.push(...closeCurrent$3(state));
|
|
12062
13186
|
if (blockType === "tool_use") {
|
|
12063
13187
|
const index = state.blocks.length;
|
|
12064
13188
|
const pending = {
|
|
12065
13189
|
blockIndex: index,
|
|
12066
|
-
id: asString$
|
|
12067
|
-
name: asString$
|
|
13190
|
+
id: asString$12(block.id) ?? `toolu_${contentIndex}`,
|
|
13191
|
+
name: asString$12(block.name) ?? "",
|
|
12068
13192
|
arguments: "",
|
|
12069
13193
|
started: true
|
|
12070
13194
|
};
|
|
@@ -12106,11 +13230,11 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
12106
13230
|
}
|
|
12107
13231
|
if (type === "content_block_delta") {
|
|
12108
13232
|
const contentIndex = numberOr$5(event.index, 0);
|
|
12109
|
-
const delta = isRecord$
|
|
12110
|
-
const deltaType = asString$
|
|
13233
|
+
const delta = isRecord$19(event.delta) ? event.delta : {};
|
|
13234
|
+
const deltaType = asString$12(delta.type);
|
|
12111
13235
|
if (deltaType === "input_json_delta") {
|
|
12112
13236
|
const pending = state.toolCalls.get(contentIndex);
|
|
12113
|
-
const partial = asString$
|
|
13237
|
+
const partial = asString$12(delta.partial_json) ?? "";
|
|
12114
13238
|
if (pending !== void 0) {
|
|
12115
13239
|
pending.arguments += partial;
|
|
12116
13240
|
out.push({
|
|
@@ -12123,7 +13247,7 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
12123
13247
|
}
|
|
12124
13248
|
return out;
|
|
12125
13249
|
}
|
|
12126
|
-
const text = deltaType === "thinking_delta" ? asString$
|
|
13250
|
+
const text = deltaType === "thinking_delta" ? asString$12(delta.thinking) : asString$12(delta.text);
|
|
12127
13251
|
if (text !== void 0 && text !== "") {
|
|
12128
13252
|
const index = state.contentIndexes.get(contentIndex) ?? state.current?.index;
|
|
12129
13253
|
const kind = deltaType === "thinking_delta" ? "reasoning" : "text";
|
|
@@ -12179,10 +13303,10 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
12179
13303
|
return out;
|
|
12180
13304
|
}
|
|
12181
13305
|
if (type === "message_delta") {
|
|
12182
|
-
const delta = isRecord$
|
|
12183
|
-
const stop = delta ? asString$
|
|
13306
|
+
const delta = isRecord$19(event.delta) ? event.delta : void 0;
|
|
13307
|
+
const stop = delta ? asString$12(delta.stop_reason) : void 0;
|
|
12184
13308
|
if (stop !== void 0 && stop !== "") state.finishReason = stop;
|
|
12185
|
-
const usage = isRecord$
|
|
13309
|
+
const usage = isRecord$19(event.usage) ? event.usage : void 0;
|
|
12186
13310
|
if (usage) {
|
|
12187
13311
|
state.sawUsage = true;
|
|
12188
13312
|
state.outputTokens = numberOr$5(usage.output_tokens, state.outputTokens);
|
|
@@ -12193,7 +13317,7 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
12193
13317
|
state.done = true;
|
|
12194
13318
|
return closeStream$4(state);
|
|
12195
13319
|
}
|
|
12196
|
-
if (type === "error") throw new LlmError$1(`Command Code stream error: ${asString$
|
|
13320
|
+
if (type === "error") throw new LlmError$1(`Command Code stream error: ${asString$12((isRecord$19(event.error) ? event.error : {}).message) ?? "unknown error"}`, "PROVIDER_ERROR");
|
|
12197
13321
|
return out;
|
|
12198
13322
|
}
|
|
12199
13323
|
function tokenUsage$4(state) {
|
|
@@ -12207,10 +13331,200 @@ function tokenUsage$4(state) {
|
|
|
12207
13331
|
}
|
|
12208
13332
|
function finishReasonFor$4(state) {
|
|
12209
13333
|
const reason = state.finishReason ?? "";
|
|
12210
|
-
if (reason === "length" || reason === "max_tokens") return { kind: "max-tokens" };
|
|
13334
|
+
if (reason === "length" || reason === "max_tokens" || reason === "max_output_tokens") return { kind: "max-tokens" };
|
|
12211
13335
|
if (state.hasToolCall || reason === "tool_calls" || reason === "tool_use") return { kind: "tool-calls" };
|
|
12212
13336
|
return { kind: "stop" };
|
|
12213
13337
|
}
|
|
13338
|
+
/**
|
|
13339
|
+
* Fold one SSE line from `/responses`.
|
|
13340
|
+
*
|
|
13341
|
+
* The Responses stream is event-typed rather than delta-shaped: text arrives as
|
|
13342
|
+
* `response.output_text.delta`, tool calls as `function_call_arguments.delta`
|
|
13343
|
+
* keyed by an item id, and the turn ends on `response.completed` or
|
|
13344
|
+
* `response.failed`. Those are read as written; there is no Chat Completions
|
|
13345
|
+
* shape to reinterpret.
|
|
13346
|
+
*/
|
|
13347
|
+
function processResponsesStreamLine(line, state) {
|
|
13348
|
+
const trimmed = line.trim();
|
|
13349
|
+
if (trimmed === "" || !trimmed.startsWith("data:")) return [];
|
|
13350
|
+
const payload = trimmed.slice(5).trim();
|
|
13351
|
+
if (payload === "" || payload === "[DONE]") return [];
|
|
13352
|
+
let parsed;
|
|
13353
|
+
try {
|
|
13354
|
+
parsed = JSON.parse(payload);
|
|
13355
|
+
} catch {
|
|
13356
|
+
return [];
|
|
13357
|
+
}
|
|
13358
|
+
if (!isRecord$19(parsed)) return [];
|
|
13359
|
+
const type = typeof parsed.type === "string" ? parsed.type : "";
|
|
13360
|
+
if (type === "response.output_text.delta") {
|
|
13361
|
+
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
13362
|
+
if (delta === "") return [];
|
|
13363
|
+
state.hasContent = true;
|
|
13364
|
+
const opened = openBlock(state, "text");
|
|
13365
|
+
state.current.text += delta;
|
|
13366
|
+
return [...opened, {
|
|
13367
|
+
type: "text-delta",
|
|
13368
|
+
index: state.current.index,
|
|
13369
|
+
text: delta
|
|
13370
|
+
}];
|
|
13371
|
+
}
|
|
13372
|
+
if (type === "response.reasoning_summary_text.delta") {
|
|
13373
|
+
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
13374
|
+
if (delta === "") return [];
|
|
13375
|
+
state.hasContent = true;
|
|
13376
|
+
const opened = openBlock(state, "reasoning");
|
|
13377
|
+
state.current.text += delta;
|
|
13378
|
+
return [...opened, {
|
|
13379
|
+
type: "reasoning-delta",
|
|
13380
|
+
index: state.current.index,
|
|
13381
|
+
text: delta
|
|
13382
|
+
}];
|
|
13383
|
+
}
|
|
13384
|
+
if (type === "response.output_item.added") {
|
|
13385
|
+
const item = isRecord$19(parsed.item) ? parsed.item : null;
|
|
13386
|
+
if (item === null || item.type !== "function_call") return [];
|
|
13387
|
+
return startResponsesToolCall(state, parsed, item);
|
|
13388
|
+
}
|
|
13389
|
+
if (type === "response.function_call_arguments.delta") {
|
|
13390
|
+
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
13391
|
+
const call = responsesToolCall(state, parsed.item_id ?? parsed.call_id);
|
|
13392
|
+
if (call === void 0 || delta === "") return [];
|
|
13393
|
+
call.arguments += delta;
|
|
13394
|
+
return [{
|
|
13395
|
+
type: "tool-call-delta",
|
|
13396
|
+
index: call.blockIndex,
|
|
13397
|
+
id: toToolCallId(call.id),
|
|
13398
|
+
name: call.name,
|
|
13399
|
+
argumentsDelta: delta
|
|
13400
|
+
}];
|
|
13401
|
+
}
|
|
13402
|
+
if (type === "response.function_call_arguments.done") {
|
|
13403
|
+
const call = responsesToolCall(state, parsed.item_id ?? parsed.call_id);
|
|
13404
|
+
if (call === void 0) return [];
|
|
13405
|
+
if (typeof parsed.arguments === "string") call.arguments = parsed.arguments;
|
|
13406
|
+
return [];
|
|
13407
|
+
}
|
|
13408
|
+
if (type === "response.completed" || type === "response.incomplete") {
|
|
13409
|
+
const response = isRecord$19(parsed.response) ? parsed.response : null;
|
|
13410
|
+
if (response !== null) {
|
|
13411
|
+
if (response.status === "failed") {
|
|
13412
|
+
state.done = true;
|
|
13413
|
+
const errorObj = isRecord$19(response.error) ? response.error : null;
|
|
13414
|
+
const detail = errorObj && typeof errorObj.message === "string" ? errorObj.message : typeof response.error === "string" ? response.error : "";
|
|
13415
|
+
throw new LlmError$1(detail === "" ? "Command Code responses stream failed" : `Command Code responses stream failed: ${detail}`, "PROVIDER_ERROR");
|
|
13416
|
+
}
|
|
13417
|
+
readResponsesUsage(response, state);
|
|
13418
|
+
}
|
|
13419
|
+
state.done = true;
|
|
13420
|
+
if (type === "response.incomplete") {
|
|
13421
|
+
const details = response && isRecord$19(response.incomplete_details) ? response.incomplete_details : null;
|
|
13422
|
+
const reason = details && typeof details.reason === "string" ? details.reason : "";
|
|
13423
|
+
state.finishReason = reason === "max_output_tokens" || reason === "length" || reason === "max_tokens" ? "length" : reason || "length";
|
|
13424
|
+
} else state.finishReason = "stop";
|
|
13425
|
+
return [];
|
|
13426
|
+
}
|
|
13427
|
+
if (type === "response.failed" || type === "error") {
|
|
13428
|
+
state.done = true;
|
|
13429
|
+
const errorObj = isRecord$19(parsed.error) ? parsed.error : isRecord$19(parsed.response) && isRecord$19(parsed.response.error) ? parsed.response.error : null;
|
|
13430
|
+
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 : "");
|
|
13431
|
+
throw new LlmError$1(detail === "" ? "Command Code responses stream failed" : `Command Code responses stream failed: ${detail}`, "PROVIDER_ERROR");
|
|
13432
|
+
}
|
|
13433
|
+
return [];
|
|
13434
|
+
}
|
|
13435
|
+
function openBlock(state, type) {
|
|
13436
|
+
if (state.current !== null && state.current.type === type) return [];
|
|
13437
|
+
const out = closeCurrent$3(state);
|
|
13438
|
+
state.current = {
|
|
13439
|
+
index: state.blocks.length,
|
|
13440
|
+
type,
|
|
13441
|
+
text: ""
|
|
13442
|
+
};
|
|
13443
|
+
state.blocks.push({
|
|
13444
|
+
type,
|
|
13445
|
+
text: ""
|
|
13446
|
+
});
|
|
13447
|
+
out.push({
|
|
13448
|
+
type: "block-start",
|
|
13449
|
+
index: state.current.index,
|
|
13450
|
+
blockType: type
|
|
13451
|
+
});
|
|
13452
|
+
return out;
|
|
13453
|
+
}
|
|
13454
|
+
function startResponsesToolCall(state, event, item) {
|
|
13455
|
+
const out = closeCurrent$3(state);
|
|
13456
|
+
const index = state.blocks.length;
|
|
13457
|
+
const name = typeof item.name === "string" ? item.name : "";
|
|
13458
|
+
const itemId = typeof item.id === "string" ? item.id : typeof event.item_id === "string" ? event.item_id : null;
|
|
13459
|
+
const call = {
|
|
13460
|
+
blockIndex: index,
|
|
13461
|
+
id: typeof item.call_id === "string" ? item.call_id : `call_${String(itemId ?? index)}`,
|
|
13462
|
+
name,
|
|
13463
|
+
arguments: "",
|
|
13464
|
+
started: true
|
|
13465
|
+
};
|
|
13466
|
+
state.blocks.push({
|
|
13467
|
+
type: "tool-call",
|
|
13468
|
+
id: toToolCallId(call.id),
|
|
13469
|
+
name,
|
|
13470
|
+
arguments: ""
|
|
13471
|
+
});
|
|
13472
|
+
state.toolCalls.set(index, call);
|
|
13473
|
+
if (itemId !== null) responsesItemIndexOf(state).set(itemId, call);
|
|
13474
|
+
state.hasToolCall = true;
|
|
13475
|
+
out.push({
|
|
13476
|
+
type: "block-start",
|
|
13477
|
+
index,
|
|
13478
|
+
blockType: "tool-call"
|
|
13479
|
+
});
|
|
13480
|
+
out.push({
|
|
13481
|
+
type: "tool-call-delta",
|
|
13482
|
+
index,
|
|
13483
|
+
id: toToolCallId(call.id),
|
|
13484
|
+
name,
|
|
13485
|
+
argumentsDelta: ""
|
|
13486
|
+
});
|
|
13487
|
+
return out;
|
|
13488
|
+
}
|
|
13489
|
+
/** Item id -> call, held beside the stream state that produced it. */
|
|
13490
|
+
const responsesItemIndex = /* @__PURE__ */ new WeakMap();
|
|
13491
|
+
function responsesItemIndexOf(state) {
|
|
13492
|
+
let index = responsesItemIndex.get(state);
|
|
13493
|
+
if (index === void 0) {
|
|
13494
|
+
index = /* @__PURE__ */ new Map();
|
|
13495
|
+
responsesItemIndex.set(state, index);
|
|
13496
|
+
}
|
|
13497
|
+
return index;
|
|
13498
|
+
}
|
|
13499
|
+
/**
|
|
13500
|
+
* The call a function-arguments event refers to.
|
|
13501
|
+
*
|
|
13502
|
+
* The event carries `item_id` while the recorded call carries `call_id`, so
|
|
13503
|
+
* matching on the call id alone silently dropped every argument delta. The
|
|
13504
|
+
* call-id fallback stays for a provider that only sends one of the two.
|
|
13505
|
+
*/
|
|
13506
|
+
function responsesToolCall(state, key) {
|
|
13507
|
+
if (typeof key !== "string" || key === "") return void 0;
|
|
13508
|
+
const match = responsesItemIndex.get(state)?.get(key);
|
|
13509
|
+
if (match !== void 0) return match;
|
|
13510
|
+
for (const call of state.toolCalls.values()) if (call.id === toToolCallId(key)) return call;
|
|
13511
|
+
}
|
|
13512
|
+
function readResponsesUsage(response, state) {
|
|
13513
|
+
const usage = isRecord$19(response.usage) ? response.usage : null;
|
|
13514
|
+
if (usage === null) return;
|
|
13515
|
+
const cached = isRecord$19(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cached_tokens) : 0;
|
|
13516
|
+
const written = isRecord$19(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cache_write_tokens) : 0;
|
|
13517
|
+
state.inputTokens = Math.max(0, numberOrZero(usage.input_tokens) - cached - written);
|
|
13518
|
+
state.cacheReadTokens = cached;
|
|
13519
|
+
state.cacheWriteTokens = written;
|
|
13520
|
+
state.outputTokens = numberOrZero(usage.output_tokens);
|
|
13521
|
+
const outputDetails = isRecord$19(usage.output_tokens_details) ? usage.output_tokens_details : null;
|
|
13522
|
+
if (outputDetails !== null) state.reasoningTokens = numberOrZero(outputDetails.reasoning_tokens);
|
|
13523
|
+
state.sawUsage = true;
|
|
13524
|
+
}
|
|
13525
|
+
function numberOrZero(value) {
|
|
13526
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
|
|
13527
|
+
}
|
|
12214
13528
|
/** Flush every open block, then emit usage and the terminal finish. */
|
|
12215
13529
|
function closeStream$4(state) {
|
|
12216
13530
|
if (state.finished) return [];
|
|
@@ -12231,6 +13545,213 @@ function assertStreamComplete$4(state) {
|
|
|
12231
13545
|
if (!state.done && state.finishReason === null) throw new LlmError$1("Command Code stream ended before its terminal event", "PROVIDER_ERROR");
|
|
12232
13546
|
}
|
|
12233
13547
|
//#endregion
|
|
13548
|
+
//#region src/host/common/capabilities.ts
|
|
13549
|
+
/** Error thrown by requireCapability when a capability contract fails. */
|
|
13550
|
+
var CapabilityError = class extends Error {
|
|
13551
|
+
query;
|
|
13552
|
+
evaluation;
|
|
13553
|
+
constructor(message, query, evaluation) {
|
|
13554
|
+
super(message);
|
|
13555
|
+
this.name = "CapabilityError";
|
|
13556
|
+
this.query = query;
|
|
13557
|
+
this.evaluation = evaluation;
|
|
13558
|
+
}
|
|
13559
|
+
};
|
|
13560
|
+
/** Known Ollama vision model prefixes per official model documentation. */
|
|
13561
|
+
const KNOWN_OLLAMA_VISION_PREFIXES = [
|
|
13562
|
+
"llava",
|
|
13563
|
+
"bakllava",
|
|
13564
|
+
"llama3.2-vision",
|
|
13565
|
+
"moondream",
|
|
13566
|
+
"minicpm-v",
|
|
13567
|
+
"qwen2.5-vl",
|
|
13568
|
+
"qwen2-vl"
|
|
13569
|
+
];
|
|
13570
|
+
/**
|
|
13571
|
+
* Matcher for Ollama vision models, aligned with src/host/ollama/types.ts.
|
|
13572
|
+
* Checks exact base name before ':' or '/' to prevent partial hijacking (e.g. 'llava-evil').
|
|
13573
|
+
*/
|
|
13574
|
+
function isKnownOllamaVisionModel(modelId) {
|
|
13575
|
+
const base = modelId.toLowerCase().trim().split(":")[0]?.trim() ?? "";
|
|
13576
|
+
return KNOWN_OLLAMA_VISION_PREFIXES.includes(base);
|
|
13577
|
+
}
|
|
13578
|
+
/** Ollama thinking models with level control ('low'|'medium'|'high'). */
|
|
13579
|
+
const KNOWN_OLLAMA_THINKING_LEVELS_PREFIXES = ["gpt-oss"];
|
|
13580
|
+
/** Ollama thinking models with boolean control (true|false). */
|
|
13581
|
+
const KNOWN_OLLAMA_THINKING_BOOLEAN_PREFIXES = [
|
|
13582
|
+
"deepseek-r1",
|
|
13583
|
+
"qwq",
|
|
13584
|
+
"qwen3"
|
|
13585
|
+
];
|
|
13586
|
+
/** Matcher for Ollama thinking models, aligned with src/host/ollama/types.ts. */
|
|
13587
|
+
function isKnownOllamaThinkingModel(modelId) {
|
|
13588
|
+
const base = modelId.toLowerCase().trim().split(":")[0]?.trim() ?? "";
|
|
13589
|
+
return KNOWN_OLLAMA_THINKING_LEVELS_PREFIXES.includes(base) || KNOWN_OLLAMA_THINKING_BOOLEAN_PREFIXES.includes(base);
|
|
13590
|
+
}
|
|
13591
|
+
/** Immutable validated capability evidence registry. */
|
|
13592
|
+
const CAPABILITY_EVIDENCE_REGISTRY = Object.freeze([
|
|
13593
|
+
{
|
|
13594
|
+
id: "ollama-native-image",
|
|
13595
|
+
provider: "ollama",
|
|
13596
|
+
wire: ["openai", "native"],
|
|
13597
|
+
modelSelector: isKnownOllamaVisionModel,
|
|
13598
|
+
authMode: "api-key",
|
|
13599
|
+
capability: "native-image",
|
|
13600
|
+
status: "supported",
|
|
13601
|
+
evidenceLevel: "offline-contract",
|
|
13602
|
+
implemented: true,
|
|
13603
|
+
date: "2026-10-03",
|
|
13604
|
+
testPath: "test/ollama-projection.test.ts",
|
|
13605
|
+
versionTag: "0.2.0-rc.2",
|
|
13606
|
+
notes: "Supported strictly for verified vision model prefixes (llava, bakllava, llama3.2-vision, moondream, minicpm-v, qwen2.5-vl, qwen2-vl). Exact boundary prevents llava-evil."
|
|
13607
|
+
},
|
|
13608
|
+
{
|
|
13609
|
+
id: "ollama-thinking-control",
|
|
13610
|
+
provider: "ollama",
|
|
13611
|
+
wire: ["openai", "native"],
|
|
13612
|
+
modelSelector: isKnownOllamaThinkingModel,
|
|
13613
|
+
authMode: "api-key",
|
|
13614
|
+
capability: "thinking-control",
|
|
13615
|
+
status: "supported",
|
|
13616
|
+
evidenceLevel: "offline-contract",
|
|
13617
|
+
implemented: true,
|
|
13618
|
+
date: "2026-10-03",
|
|
13619
|
+
testPath: "test/ollama-projection.test.ts",
|
|
13620
|
+
link: "https://github.com/ollama/ollama/blob/main/docs/capabilities/thinking.mdx",
|
|
13621
|
+
versionTag: "0.2.0-rc.2",
|
|
13622
|
+
notes: "Model-level think control for gpt-oss (levels) and deepseek-r1/qwq/qwen3 (boolean). Replay across turns remains unsupported."
|
|
13623
|
+
},
|
|
13624
|
+
{
|
|
13625
|
+
id: "command-code-zdr",
|
|
13626
|
+
provider: "command-code",
|
|
13627
|
+
wire: [
|
|
13628
|
+
"responses",
|
|
13629
|
+
"anthropic",
|
|
13630
|
+
"openai",
|
|
13631
|
+
"chat-completions",
|
|
13632
|
+
"messages"
|
|
13633
|
+
],
|
|
13634
|
+
modelSelector: "*",
|
|
13635
|
+
authMode: [
|
|
13636
|
+
"api-key",
|
|
13637
|
+
"token",
|
|
13638
|
+
"oauth"
|
|
13639
|
+
],
|
|
13640
|
+
capability: "zdr",
|
|
13641
|
+
status: "supported",
|
|
13642
|
+
evidenceLevel: "offline-contract",
|
|
13643
|
+
implemented: true,
|
|
13644
|
+
date: "2026-10-03",
|
|
13645
|
+
testPath: "test/command-code-adapter.test.ts",
|
|
13646
|
+
link: "https://github.com/CommandCodeAI/pi-commandcode-provider/blob/main/index.ts",
|
|
13647
|
+
versionTag: "0.2.0-rc.2",
|
|
13648
|
+
notes: "Official contract: x-cmd-zdr: 1 header active across provider wires. 422 cmd_zdr_no_providers cannot silently degrade."
|
|
13649
|
+
}
|
|
13650
|
+
].map((r) => Object.freeze({
|
|
13651
|
+
...r,
|
|
13652
|
+
wire: Array.isArray(r.wire) ? Object.freeze([...r.wire]) : r.wire,
|
|
13653
|
+
authMode: Array.isArray(r.authMode) ? Object.freeze([...r.authMode]) : r.authMode,
|
|
13654
|
+
modelSelector: Array.isArray(r.modelSelector) ? Object.freeze([...r.modelSelector]) : r.modelSelector
|
|
13655
|
+
})));
|
|
13656
|
+
function matchesWire(expected, actual) {
|
|
13657
|
+
const normActual = actual.toLowerCase().trim();
|
|
13658
|
+
if (typeof expected === "string") {
|
|
13659
|
+
if (expected === "*") return true;
|
|
13660
|
+
return expected.toLowerCase().trim() === normActual;
|
|
13661
|
+
}
|
|
13662
|
+
return expected.some((w) => w.toLowerCase().trim() === normActual);
|
|
13663
|
+
}
|
|
13664
|
+
function matchesAuth(expected, actual) {
|
|
13665
|
+
const normActual = actual.toLowerCase().trim();
|
|
13666
|
+
if (typeof expected === "string") {
|
|
13667
|
+
if (expected === "*") return true;
|
|
13668
|
+
return expected.toLowerCase().trim() === normActual;
|
|
13669
|
+
}
|
|
13670
|
+
return expected.some((a) => a.toLowerCase().trim() === normActual);
|
|
13671
|
+
}
|
|
13672
|
+
function matchesModel(selector, model) {
|
|
13673
|
+
const normModel = model.toLowerCase().trim();
|
|
13674
|
+
if (typeof selector === "function") return selector(model);
|
|
13675
|
+
if (typeof selector === "string") {
|
|
13676
|
+
if (selector === "*") return true;
|
|
13677
|
+
const normSelector = selector.toLowerCase().trim();
|
|
13678
|
+
return normModel === normSelector || normModel.startsWith(normSelector + ":") || normModel.startsWith(normSelector + "/");
|
|
13679
|
+
}
|
|
13680
|
+
return selector.some((s) => {
|
|
13681
|
+
const normS = s.toLowerCase().trim();
|
|
13682
|
+
return normModel === normS || normModel.startsWith(normS + ":") || normModel.startsWith(normS + "/");
|
|
13683
|
+
});
|
|
13684
|
+
}
|
|
13685
|
+
/** Query evidence records matching the given criteria. Supports optional pure registry argument for tests. */
|
|
13686
|
+
function queryCapabilityEvidence(query, registry = CAPABILITY_EVIDENCE_REGISTRY) {
|
|
13687
|
+
return registry.filter((rec) => {
|
|
13688
|
+
if (query.provider && rec.provider.toLowerCase() !== query.provider.toLowerCase().trim()) return false;
|
|
13689
|
+
if (query.capability && rec.capability !== query.capability) return false;
|
|
13690
|
+
if (query.wire && !matchesWire(rec.wire, query.wire)) return false;
|
|
13691
|
+
if (query.authMode && !matchesAuth(rec.authMode, query.authMode)) return false;
|
|
13692
|
+
if (query.model && !matchesModel(rec.modelSelector, query.model)) return false;
|
|
13693
|
+
return true;
|
|
13694
|
+
});
|
|
13695
|
+
}
|
|
13696
|
+
/**
|
|
13697
|
+
* Evaluate whether a capability is permitted for a concrete request target.
|
|
13698
|
+
* Fails closed if query is missing explicit fields, or lacks matching verified evidence.
|
|
13699
|
+
*/
|
|
13700
|
+
function evaluateCapability(query, registry = CAPABILITY_EVIDENCE_REGISTRY) {
|
|
13701
|
+
if (!query || typeof query.provider !== "string" || !query.provider.trim() || typeof query.wire !== "string" || !query.wire.trim() || typeof query.model !== "string" || !query.model.trim() || typeof query.authMode !== "string" || !query.authMode.trim() || typeof query.capability !== "string" || !query.capability.trim()) return {
|
|
13702
|
+
allowed: false,
|
|
13703
|
+
state: "unknown",
|
|
13704
|
+
implemented: false,
|
|
13705
|
+
reason: "Capability query requires non-empty provider, wire, model, authMode, and capability"
|
|
13706
|
+
};
|
|
13707
|
+
const matching = queryCapabilityEvidence(query, registry);
|
|
13708
|
+
if (matching.length === 0) return {
|
|
13709
|
+
allowed: false,
|
|
13710
|
+
state: "unknown",
|
|
13711
|
+
implemented: false,
|
|
13712
|
+
reason: `No matching verified evidence for ${query.provider}/${query.wire}/${query.model} (auth: ${query.authMode}, capability: ${query.capability}).`
|
|
13713
|
+
};
|
|
13714
|
+
const record = matching[0];
|
|
13715
|
+
const isSupportedLevel = record.evidenceLevel === "live-validated" || record.evidenceLevel === "offline-contract";
|
|
13716
|
+
const isAllowed = record.implemented && record.status === "supported" && isSupportedLevel;
|
|
13717
|
+
return {
|
|
13718
|
+
allowed: isAllowed,
|
|
13719
|
+
state: record.status,
|
|
13720
|
+
implemented: record.implemented,
|
|
13721
|
+
evidenceLevel: record.evidenceLevel,
|
|
13722
|
+
evidence: record,
|
|
13723
|
+
reason: isAllowed ? void 0 : record.notes ?? `Capability '${query.capability}' is not permitted.`
|
|
13724
|
+
};
|
|
13725
|
+
}
|
|
13726
|
+
/**
|
|
13727
|
+
* Require that a capability is supported and allowed. Throws CapabilityError otherwise.
|
|
13728
|
+
*/
|
|
13729
|
+
function requireCapability(query, registry = CAPABILITY_EVIDENCE_REGISTRY) {
|
|
13730
|
+
const result = evaluateCapability(query, registry);
|
|
13731
|
+
if (!result.allowed) throw new CapabilityError(`Capability requirement rejected: '${query.capability}' on ${query.provider} (${query.wire}/${query.model}, auth: ${query.authMode}): ${result.reason ?? "not permitted"}`, query, result);
|
|
13732
|
+
return result;
|
|
13733
|
+
}
|
|
13734
|
+
/** Whether Ollama image input is supported for the target model. */
|
|
13735
|
+
function supportsOllamaImage(model, wire = "openai", authMode = "api-key") {
|
|
13736
|
+
return evaluateCapability({
|
|
13737
|
+
provider: "ollama",
|
|
13738
|
+
wire,
|
|
13739
|
+
model,
|
|
13740
|
+
authMode,
|
|
13741
|
+
capability: "native-image"
|
|
13742
|
+
}).allowed;
|
|
13743
|
+
}
|
|
13744
|
+
/** Whether Ollama thinking control is supported for the target model. */
|
|
13745
|
+
function supportsOllamaThinkingControl(model, wire = "openai", authMode = "api-key") {
|
|
13746
|
+
return evaluateCapability({
|
|
13747
|
+
provider: "ollama",
|
|
13748
|
+
wire,
|
|
13749
|
+
model,
|
|
13750
|
+
authMode,
|
|
13751
|
+
capability: "thinking-control"
|
|
13752
|
+
}).allowed;
|
|
13753
|
+
}
|
|
13754
|
+
//#endregion
|
|
12234
13755
|
//#region src/host/command-code/adapter.ts
|
|
12235
13756
|
/**
|
|
12236
13757
|
* Transient-failure retry policy for the `command-code` route.
|
|
@@ -12264,6 +13785,41 @@ const RETRY_POLICY$5 = resolveRetryPolicy({
|
|
|
12264
13785
|
function resolveDefaultReasoningEffort$3(efforts, configuredEffort) {
|
|
12265
13786
|
if (configuredEffort && efforts.includes(configuredEffort)) return ReasoningEffortId(configuredEffort);
|
|
12266
13787
|
}
|
|
13788
|
+
/**
|
|
13789
|
+
* Resolves whether Zero Data Retention (ZDR) routing is active for Command Code.
|
|
13790
|
+
* An explicit boolean on adapter options takes precedence over host environment variables.
|
|
13791
|
+
* When not specified in options, DSH_COMMAND_CODE_ZDR is consulted first, then CMD_ZDR.
|
|
13792
|
+
*/
|
|
13793
|
+
function resolveZeroDataRetention(optionsZdr) {
|
|
13794
|
+
if (optionsZdr !== void 0) return optionsZdr;
|
|
13795
|
+
if (process.env.DSH_COMMAND_CODE_ZDR !== void 0) return process.env.DSH_COMMAND_CODE_ZDR === "1";
|
|
13796
|
+
return process.env.CMD_ZDR === "1";
|
|
13797
|
+
}
|
|
13798
|
+
/**
|
|
13799
|
+
* Classifies model-specific access or plan entitlement denials.
|
|
13800
|
+
* These are failures of permissions/entitlement for this model/account,
|
|
13801
|
+
* not invalid API credentials, so the account must not be marked invalid
|
|
13802
|
+
* and whole-account rotation must not occur.
|
|
13803
|
+
*/
|
|
13804
|
+
function isCommandCodeModelAccessDenied(status, detail) {
|
|
13805
|
+
if (status === 403 || status === 404 || status === 400) {
|
|
13806
|
+
const lower = detail.toLowerCase();
|
|
13807
|
+
if (lower.includes("upgrade_required") || lower.includes("not entitled") || lower.includes("entitlement") || lower.includes("model_not_found") || lower.includes("model_not_allowed") || lower.includes("model_access_denied") || lower.includes("permission_denied") || lower.includes("access_denied") || lower.includes("insufficient_permissions") || lower.includes("model") && (lower.includes("access") || lower.includes("permission") || lower.includes("entitled") || lower.includes("forbidden") || lower.includes("not allowed") || lower.includes("unauthorized") || lower.includes("not supported") || lower.includes("plan") || lower.includes("tier")) || lower.includes("plan") && (lower.includes("upgrade") || lower.includes("tier") || lower.includes("include") || lower.includes("support"))) return true;
|
|
13808
|
+
if (status === 403 && !isCommandCodeCredentialInvalid(status, detail)) return true;
|
|
13809
|
+
}
|
|
13810
|
+
return false;
|
|
13811
|
+
}
|
|
13812
|
+
/**
|
|
13813
|
+
* Classifies actual credential invalidity (e.g. 401 Unauthorized, or 403 with explicit key errors).
|
|
13814
|
+
*/
|
|
13815
|
+
function isCommandCodeCredentialInvalid(status, detail) {
|
|
13816
|
+
if (status === 401) return true;
|
|
13817
|
+
if (status === 403) {
|
|
13818
|
+
const lower = detail.toLowerCase();
|
|
13819
|
+
if (lower.includes("invalid_api_key") || lower.includes("invalid_token") || lower.includes("bad_api_key") || lower.includes("invalid key") || lower.includes("bad api key") || lower.includes("api key invalid") || lower.includes("key revoked") || lower.includes("revoked_key") || lower.includes("expired_key") || lower.includes("key expired") || lower.includes("token expired") || lower.includes("incorrect api key") || lower.includes("authentication failed")) return true;
|
|
13820
|
+
}
|
|
13821
|
+
return false;
|
|
13822
|
+
}
|
|
12267
13823
|
/** Cooldown one rate-limited key takes when the provider states no delay. */
|
|
12268
13824
|
const POOL_COOLDOWN_MS$4 = 15 * 6e4;
|
|
12269
13825
|
var CommandCodeAdapter = class extends LlmAdapter {
|
|
@@ -12380,7 +13936,16 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
12380
13936
|
}
|
|
12381
13937
|
async *requestStream(options, signal) {
|
|
12382
13938
|
const fetchFn = this.options.fetchFn ?? fetch;
|
|
12383
|
-
const
|
|
13939
|
+
const catalogEntry = (await this.catalog()).find((entry) => entry.id === options.model);
|
|
13940
|
+
const wire = (catalogEntry === void 0 ? void 0 : wireForCatalogEntry$1(catalogEntry)) ?? wireForModel$2(options.model);
|
|
13941
|
+
const isZdr = resolveZeroDataRetention(this.options.zeroDataRetention);
|
|
13942
|
+
if (isZdr) requireCapability({
|
|
13943
|
+
provider: PROVIDER_ID$5,
|
|
13944
|
+
wire,
|
|
13945
|
+
model: options.model,
|
|
13946
|
+
authMode: "api-key",
|
|
13947
|
+
capability: "zdr"
|
|
13948
|
+
});
|
|
12384
13949
|
const requestOptions = offloadOldestRequestImages$3(normalizeGenerateOptions(options));
|
|
12385
13950
|
const images = await resolveRequestImages$3(requestOptions, this.options.attachments, signal);
|
|
12386
13951
|
const body = JSON.stringify(buildRequest$1(requestOptions, wire, images));
|
|
@@ -12404,17 +13969,17 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
12404
13969
|
apiKey = effective.credentials.apiKey;
|
|
12405
13970
|
apiEnv = effective.apiEnv;
|
|
12406
13971
|
}
|
|
12407
|
-
const endpoint = `${providerUrl(apiEnv)}${wire
|
|
12408
|
-
const
|
|
13972
|
+
const endpoint = `${providerUrl(apiEnv)}${endpointPathFor(wire)}`;
|
|
13973
|
+
const baseHeaders = {
|
|
12409
13974
|
...commandCodeHeaders(apiKey),
|
|
12410
13975
|
"user-agent": PLUGIN_USER_AGENT,
|
|
12411
13976
|
accept: "text/event-stream",
|
|
12412
|
-
"
|
|
12413
|
-
} : {
|
|
12414
|
-
...commandCodeHeaders(apiKey),
|
|
12415
|
-
"user-agent": PLUGIN_USER_AGENT,
|
|
12416
|
-
accept: "text/event-stream"
|
|
13977
|
+
...isZdr ? { [HEADER_ZDR]: "1" } : {}
|
|
12417
13978
|
};
|
|
13979
|
+
const headers = wire === "anthropic" ? {
|
|
13980
|
+
...baseHeaders,
|
|
13981
|
+
"anthropic-version": "2023-06-01"
|
|
13982
|
+
} : baseHeaders;
|
|
12418
13983
|
try {
|
|
12419
13984
|
response = await fetchFn(endpoint, {
|
|
12420
13985
|
method: "POST",
|
|
@@ -12428,8 +13993,13 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
12428
13993
|
}
|
|
12429
13994
|
if (response.ok) break;
|
|
12430
13995
|
detail = (await response.text().catch(() => "")).slice(0, 600);
|
|
13996
|
+
if (response.status === 422) {
|
|
13997
|
+
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"}).`, "PROVIDER_ERROR", { status: 422 });
|
|
13998
|
+
break;
|
|
13999
|
+
}
|
|
12431
14000
|
if (pool === null || accountId === void 0) break;
|
|
12432
|
-
if (response.status
|
|
14001
|
+
if (isCommandCodeModelAccessDenied(response.status, detail)) break;
|
|
14002
|
+
if (isCommandCodeCredentialInvalid(response.status, detail)) {
|
|
12433
14003
|
await pool.markAuthFailed(accountId, `${PROVIDER_NAME$5} rejected the stored API key (${response.status}).`, "invalid").catch(() => void 0);
|
|
12434
14004
|
if (await pool.hasAnotherAvailableAccount(tried)) continue;
|
|
12435
14005
|
break;
|
|
@@ -12444,7 +14014,12 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
12444
14014
|
}
|
|
12445
14015
|
if (response === void 0 || !response.ok) {
|
|
12446
14016
|
const status = response?.status ?? 500;
|
|
12447
|
-
if (status ===
|
|
14017
|
+
if (status === 422) {
|
|
14018
|
+
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"}).`, "PROVIDER_ERROR", { status: 422 });
|
|
14019
|
+
throw new LlmError(`${PROVIDER_NAME$5} validation error (422): ${detail || "Unprocessable Entity"}`, "PROVIDER_ERROR", { status: 422 });
|
|
14020
|
+
}
|
|
14021
|
+
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}` : ""}`, "PROVIDER_ERROR", { status });
|
|
14022
|
+
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}` : ""}`, "INVALID_CREDENTIAL", { status });
|
|
12448
14023
|
if (status === 429) {
|
|
12449
14024
|
const after = response === void 0 ? void 0 : retryAfterMs$1(response.headers);
|
|
12450
14025
|
throw new LlmError(`${PROVIDER_NAME$5} rate limit or plan quota reached (429). Check the quota card in Settings > Command Code.${detail ? ` ${detail}` : ""}`, "RATE_LIMIT", {
|
|
@@ -12482,8 +14057,16 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
12482
14057
|
}
|
|
12483
14058
|
}
|
|
12484
14059
|
};
|
|
14060
|
+
/** Path suffix the chosen route answers on. */
|
|
14061
|
+
function endpointPathFor(wire) {
|
|
14062
|
+
if (wire === "anthropic") return "/messages";
|
|
14063
|
+
if (wire === "responses") return "/responses";
|
|
14064
|
+
return "/chat/completions";
|
|
14065
|
+
}
|
|
12485
14066
|
function processLine$1(line, state, wire) {
|
|
12486
|
-
|
|
14067
|
+
if (wire === "anthropic") return processAnthropicStreamLine$1(line, state);
|
|
14068
|
+
if (wire === "responses") return processResponsesStreamLine(line, state);
|
|
14069
|
+
return processOpenAIStreamLine$1(line, state);
|
|
12487
14070
|
}
|
|
12488
14071
|
//#endregion
|
|
12489
14072
|
//#region src/host/command-code/account-pool.ts
|
|
@@ -13211,6 +14794,9 @@ async function getCommandCodeWebStatus(store, modelSettings, preferences, option
|
|
|
13211
14794
|
}),
|
|
13212
14795
|
quota: quota ?? null,
|
|
13213
14796
|
lastFetchedAt: quota?.fetchedAt ?? null,
|
|
14797
|
+
catalogFetchedAt: getCachedCatalogFetchedAt(),
|
|
14798
|
+
catalogStale: isCatalogStale(),
|
|
14799
|
+
...resolveZeroDataRetention(options.zeroDataRetention) ? { zeroDataRetention: true } : options.zeroDataRetention !== void 0 ? { zeroDataRetention: false } : {},
|
|
13214
14800
|
models,
|
|
13215
14801
|
contextWindowOverrides: settings.contextWindowOverrides,
|
|
13216
14802
|
defaultReasoningEffort: settings.defaultReasoningEffort,
|
|
@@ -13571,6 +15157,48 @@ function ollamaHeaders(apiKey) {
|
|
|
13571
15157
|
"content-type": "application/json"
|
|
13572
15158
|
};
|
|
13573
15159
|
}
|
|
15160
|
+
/**
|
|
15161
|
+
* Tightly-scoped check for known vision-capable models in Ollama.
|
|
15162
|
+
* Conservative allowlist of known vision families; unknown models default to false.
|
|
15163
|
+
*/
|
|
15164
|
+
function ollamaModelSupportsImage(modelId) {
|
|
15165
|
+
return supportsOllamaImage(modelId, "openai", "api-key");
|
|
15166
|
+
}
|
|
15167
|
+
/**
|
|
15168
|
+
* Resolve model-specific thinking support in Ollama.
|
|
15169
|
+
* Source: official https://github.com/ollama/ollama/blob/main/docs/capabilities/thinking.mdx
|
|
15170
|
+
* - 'levels': gpt-oss family (values low, medium, high; cannot disable thinking)
|
|
15171
|
+
* - 'boolean': deepseek-r1, qwq, qwen3 families (values true, false)
|
|
15172
|
+
* - 'none': all other / unknown models (omit thinking control entirely)
|
|
15173
|
+
*/
|
|
15174
|
+
function thinkingModeForModel(modelId) {
|
|
15175
|
+
if (!supportsOllamaThinkingControl(modelId, "native", "api-key")) return "none";
|
|
15176
|
+
const base = modelId.toLowerCase().split(":")[0] ?? "";
|
|
15177
|
+
if (base === "gpt-oss") return "levels";
|
|
15178
|
+
if (base === "deepseek-r1" || base === "qwq" || base === "qwen3") return "boolean";
|
|
15179
|
+
return "none";
|
|
15180
|
+
}
|
|
15181
|
+
/**
|
|
15182
|
+
* Map reasoning effort to wire think parameter for the target model.
|
|
15183
|
+
* Per Ollama docs:
|
|
15184
|
+
* - gpt-oss: only 'low' | 'medium' | 'high' are valid. gpt-oss cannot disable thinking, so 'none'
|
|
15185
|
+
* as well as 'xhigh'/'max'/garbage MUST be omitted (undefined).
|
|
15186
|
+
* - boolean models: 'none' -> false; 'low'|'medium'|'high'|'auto'|'true' -> true; garbage -> undefined.
|
|
15187
|
+
* - all other models: omit (undefined).
|
|
15188
|
+
*/
|
|
15189
|
+
function thinkForModel(modelId, reasoningEffort) {
|
|
15190
|
+
if (reasoningEffort === void 0 || reasoningEffort === null) return void 0;
|
|
15191
|
+
const mode = thinkingModeForModel(modelId);
|
|
15192
|
+
if (mode === "none") return void 0;
|
|
15193
|
+
const effort = String(reasoningEffort).toLowerCase();
|
|
15194
|
+
if (mode === "boolean") {
|
|
15195
|
+
if (effort === "none") return false;
|
|
15196
|
+
if (effort === "low" || effort === "medium" || effort === "high" || effort === "auto" || effort === "true") return true;
|
|
15197
|
+
return;
|
|
15198
|
+
}
|
|
15199
|
+
if (effort === "low" || effort === "medium" || effort === "high") return effort;
|
|
15200
|
+
if (effort === "auto" || effort === "true") return "medium";
|
|
15201
|
+
}
|
|
13574
15202
|
//#endregion
|
|
13575
15203
|
//#region src/host/ollama/token-store.ts
|
|
13576
15204
|
function credentialPath$4() {
|
|
@@ -13742,36 +15370,79 @@ function buildBody(wire, request) {
|
|
|
13742
15370
|
if (wire === "openai") return buildOpenAIBody(request);
|
|
13743
15371
|
return buildNativeBody(request);
|
|
13744
15372
|
}
|
|
15373
|
+
function toBareBase64(image) {
|
|
15374
|
+
const match = /^data:[^;]+;base64,(.+)$/.exec(image);
|
|
15375
|
+
return match ? match[1] : image;
|
|
15376
|
+
}
|
|
15377
|
+
function toDataUrl(image, defaultMediaType = "image/png") {
|
|
15378
|
+
if (image.startsWith("data:") || image.startsWith("http://") || image.startsWith("https://")) return image;
|
|
15379
|
+
return `data:${defaultMediaType};base64,${image}`;
|
|
15380
|
+
}
|
|
15381
|
+
function parseArguments(raw) {
|
|
15382
|
+
if (typeof raw === "object" && raw !== null && !Array.isArray(raw)) return raw;
|
|
15383
|
+
if (raw === void 0 || raw === null || raw === "") return {};
|
|
15384
|
+
if (typeof raw === "string") {
|
|
15385
|
+
const trimmed = raw.trim();
|
|
15386
|
+
if (trimmed === "" || trimmed === "{}") return {};
|
|
15387
|
+
const parsed = JSON.parse(trimmed);
|
|
15388
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
|
|
15389
|
+
throw new Error(`Tool call arguments must be a JSON object, got ${typeof parsed}`);
|
|
15390
|
+
}
|
|
15391
|
+
throw new Error(`Invalid tool call arguments: ${String(raw)}`);
|
|
15392
|
+
}
|
|
13745
15393
|
function buildOpenAIBody(request) {
|
|
13746
|
-
const messages =
|
|
13747
|
-
|
|
13748
|
-
|
|
13749
|
-
|
|
13750
|
-
|
|
13751
|
-
|
|
13752
|
-
|
|
13753
|
-
|
|
13754
|
-
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13759
|
-
|
|
13760
|
-
|
|
13761
|
-
|
|
13762
|
-
|
|
13763
|
-
|
|
13764
|
-
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
|
|
13768
|
-
|
|
15394
|
+
const messages = [];
|
|
15395
|
+
let pendingToolImages = [];
|
|
15396
|
+
const flushToolImages = () => {
|
|
15397
|
+
if (pendingToolImages.length > 0) {
|
|
15398
|
+
messages.push({
|
|
15399
|
+
role: "user",
|
|
15400
|
+
content: pendingToolImages.map((image) => ({
|
|
15401
|
+
type: "image_url",
|
|
15402
|
+
image_url: { url: toDataUrl(image) }
|
|
15403
|
+
}))
|
|
15404
|
+
});
|
|
15405
|
+
pendingToolImages = [];
|
|
15406
|
+
}
|
|
15407
|
+
};
|
|
15408
|
+
for (const message of request.messages) {
|
|
15409
|
+
if (message.role === "tool") {
|
|
15410
|
+
messages.push({
|
|
15411
|
+
role: "tool",
|
|
15412
|
+
tool_call_id: message.toolCallId ?? "",
|
|
15413
|
+
content: message.content
|
|
15414
|
+
});
|
|
15415
|
+
if (message.images !== void 0 && message.images.length > 0) pendingToolImages.push(...message.images);
|
|
15416
|
+
continue;
|
|
15417
|
+
}
|
|
15418
|
+
flushToolImages();
|
|
15419
|
+
if (message.role === "assistant" && message.toolCalls !== void 0 && message.toolCalls.length > 0) {
|
|
15420
|
+
messages.push({
|
|
15421
|
+
role: "assistant",
|
|
15422
|
+
content: message.content,
|
|
15423
|
+
tool_calls: message.toolCalls.map((call) => ({
|
|
15424
|
+
id: call.id,
|
|
15425
|
+
type: "function",
|
|
15426
|
+
function: {
|
|
15427
|
+
name: call.name,
|
|
15428
|
+
arguments: typeof call.arguments === "string" ? call.arguments : JSON.stringify(call.arguments ?? {})
|
|
15429
|
+
}
|
|
15430
|
+
}))
|
|
15431
|
+
});
|
|
15432
|
+
continue;
|
|
15433
|
+
}
|
|
15434
|
+
messages.push(openAIContent(message));
|
|
15435
|
+
}
|
|
15436
|
+
flushToolImages();
|
|
13769
15437
|
const body = {
|
|
13770
15438
|
model: request.model,
|
|
13771
15439
|
messages,
|
|
13772
15440
|
stream: true,
|
|
13773
15441
|
max_tokens: request.maxOutputTokens ?? 8192
|
|
13774
15442
|
};
|
|
15443
|
+
if (typeof request.think === "string") body.reasoning_effort = request.think;
|
|
15444
|
+
else if (request.think === true) body.reasoning_effort = "auto";
|
|
15445
|
+
else if (request.think === false) body.reasoning_effort = "none";
|
|
13775
15446
|
if (request.tools !== void 0 && request.tools.length > 0) body.tools = request.tools.map((tool) => ({
|
|
13776
15447
|
type: "function",
|
|
13777
15448
|
function: {
|
|
@@ -13785,28 +15456,30 @@ function buildOpenAIBody(request) {
|
|
|
13785
15456
|
}
|
|
13786
15457
|
function buildNativeBody(request) {
|
|
13787
15458
|
const messages = request.messages.map((message) => {
|
|
13788
|
-
if (message.role === "tool")
|
|
13789
|
-
|
|
13790
|
-
|
|
13791
|
-
|
|
15459
|
+
if (message.role === "tool") {
|
|
15460
|
+
const item = {
|
|
15461
|
+
role: "tool",
|
|
15462
|
+
content: message.content
|
|
15463
|
+
};
|
|
15464
|
+
if (message.images !== void 0 && message.images.length > 0) item.images = message.images.map(toBareBase64);
|
|
15465
|
+
return item;
|
|
15466
|
+
}
|
|
13792
15467
|
if (message.role === "assistant" && message.toolCalls !== void 0 && message.toolCalls.length > 0) return {
|
|
13793
15468
|
role: "assistant",
|
|
13794
15469
|
content: message.content,
|
|
13795
15470
|
tool_calls: message.toolCalls.map((call) => ({ function: {
|
|
13796
15471
|
name: call.name,
|
|
13797
|
-
arguments: call.arguments
|
|
15472
|
+
arguments: parseArguments(call.arguments)
|
|
13798
15473
|
} }))
|
|
13799
15474
|
};
|
|
13800
|
-
return
|
|
13801
|
-
role: message.role,
|
|
13802
|
-
content: message.content
|
|
13803
|
-
};
|
|
15475
|
+
return nativeContent(message);
|
|
13804
15476
|
});
|
|
13805
15477
|
const body = {
|
|
13806
15478
|
model: request.model,
|
|
13807
15479
|
messages,
|
|
13808
15480
|
stream: true
|
|
13809
15481
|
};
|
|
15482
|
+
if (request.think !== void 0) body.think = request.think;
|
|
13810
15483
|
const options = { num_predict: request.maxOutputTokens ?? 8192 };
|
|
13811
15484
|
if (request.temperature !== void 0) options.temperature = request.temperature;
|
|
13812
15485
|
body.options = options;
|
|
@@ -13820,6 +15493,42 @@ function buildNativeBody(request) {
|
|
|
13820
15493
|
}));
|
|
13821
15494
|
return body;
|
|
13822
15495
|
}
|
|
15496
|
+
/**
|
|
15497
|
+
* A user turn on the OpenAI surface: text stays text, images become parts.
|
|
15498
|
+
*
|
|
15499
|
+
* Ollama's OpenAI compatibility takes the standard `image_url` part with a data URL.
|
|
15500
|
+
*/
|
|
15501
|
+
function openAIContent(message) {
|
|
15502
|
+
if (message.images === void 0 || message.images.length === 0) return {
|
|
15503
|
+
role: message.role,
|
|
15504
|
+
content: message.content
|
|
15505
|
+
};
|
|
15506
|
+
return {
|
|
15507
|
+
role: message.role,
|
|
15508
|
+
content: [{
|
|
15509
|
+
type: "text",
|
|
15510
|
+
text: message.content
|
|
15511
|
+
}, ...message.images.map((image) => ({
|
|
15512
|
+
type: "image_url",
|
|
15513
|
+
image_url: { url: toDataUrl(image) }
|
|
15514
|
+
}))]
|
|
15515
|
+
};
|
|
15516
|
+
}
|
|
15517
|
+
/**
|
|
15518
|
+
* A user turn on the native surface, where images are a sibling array of raw
|
|
15519
|
+
* base64 strings rather than data URLs or interleaved content parts.
|
|
15520
|
+
*/
|
|
15521
|
+
function nativeContent(message) {
|
|
15522
|
+
if (message.images === void 0 || message.images.length === 0) return {
|
|
15523
|
+
role: message.role,
|
|
15524
|
+
content: message.content
|
|
15525
|
+
};
|
|
15526
|
+
return {
|
|
15527
|
+
role: message.role,
|
|
15528
|
+
content: message.content,
|
|
15529
|
+
images: message.images.map(toBareBase64)
|
|
15530
|
+
};
|
|
15531
|
+
}
|
|
13823
15532
|
/** The endpoint one request goes to. */
|
|
13824
15533
|
function chatUrl(wire) {
|
|
13825
15534
|
return wire === "openai" ? `${CLOUD_BASE_URL}${OPENAI_CHAT_PATH}` : `${CLOUD_BASE_URL}${NATIVE_CHAT_PATH}`;
|
|
@@ -13936,6 +15645,11 @@ function parseOpenAIChunk(record, pending) {
|
|
|
13936
15645
|
type: "text",
|
|
13937
15646
|
text: fields.content
|
|
13938
15647
|
});
|
|
15648
|
+
const thinking = typeof fields.thinking === "string" ? fields.thinking : typeof fields.reasoning === "string" ? fields.reasoning : typeof fields.reasoning_content === "string" ? fields.reasoning_content : "";
|
|
15649
|
+
if (thinking !== "") events.push({
|
|
15650
|
+
type: "thinking",
|
|
15651
|
+
text: thinking
|
|
15652
|
+
});
|
|
13939
15653
|
if (Array.isArray(fields.tool_calls)) for (const raw of fields.tool_calls) accumulateToolCall(raw, pending, true);
|
|
13940
15654
|
}
|
|
13941
15655
|
if (typeof entry.finish_reason === "string" && entry.finish_reason !== "") events.push({
|
|
@@ -13959,6 +15673,11 @@ function parseNativeChunk(record, pending) {
|
|
|
13959
15673
|
type: "text",
|
|
13960
15674
|
text: fields.content
|
|
13961
15675
|
});
|
|
15676
|
+
const thinking = typeof fields.thinking === "string" ? fields.thinking : typeof fields.reasoning === "string" ? fields.reasoning : typeof fields.reasoning_content === "string" ? fields.reasoning_content : "";
|
|
15677
|
+
if (thinking !== "") events.push({
|
|
15678
|
+
type: "thinking",
|
|
15679
|
+
text: thinking
|
|
15680
|
+
});
|
|
13962
15681
|
if (Array.isArray(fields.tool_calls)) for (const raw of fields.tool_calls) accumulateToolCall(raw, pending, false);
|
|
13963
15682
|
}
|
|
13964
15683
|
if (record.done === true) events.push({
|
|
@@ -14094,6 +15813,7 @@ function createStreamState$4() {
|
|
|
14094
15813
|
return {
|
|
14095
15814
|
nextBlockIndex: 0,
|
|
14096
15815
|
textBlock: null,
|
|
15816
|
+
thinkingBlock: null,
|
|
14097
15817
|
toolCalls: /* @__PURE__ */ new Map(),
|
|
14098
15818
|
hasContent: false
|
|
14099
15819
|
};
|
|
@@ -14101,30 +15821,85 @@ function createStreamState$4() {
|
|
|
14101
15821
|
/** Fold one event into chunks, opening and closing blocks as the stream needs. */
|
|
14102
15822
|
function applyEvent(state, event) {
|
|
14103
15823
|
if (event.type === "text") return applyText(state, event.text);
|
|
15824
|
+
if (event.type === "thinking") return applyThinking(state, event.text);
|
|
14104
15825
|
if (event.type === "tool_call") return applyToolCall(state, event.call);
|
|
14105
15826
|
return [];
|
|
14106
15827
|
}
|
|
15828
|
+
/**
|
|
15829
|
+
* Fold a thinking delta into its own block.
|
|
15830
|
+
*
|
|
15831
|
+
* The trace and the answer interleave, so a text delta or a tool call closes
|
|
15832
|
+
* the reasoning block: two open blocks at once would hand the caller chunks in
|
|
15833
|
+
* an order the stream never produced.
|
|
15834
|
+
*/
|
|
15835
|
+
function applyThinking(state, text) {
|
|
15836
|
+
state.hasContent = true;
|
|
15837
|
+
if (state.thinkingBlock === null) {
|
|
15838
|
+
const out = closeText(state);
|
|
15839
|
+
const index = state.nextBlockIndex;
|
|
15840
|
+
state.nextBlockIndex += 1;
|
|
15841
|
+
state.thinkingBlock = {
|
|
15842
|
+
index,
|
|
15843
|
+
text
|
|
15844
|
+
};
|
|
15845
|
+
return [
|
|
15846
|
+
...out,
|
|
15847
|
+
{
|
|
15848
|
+
type: "block-start",
|
|
15849
|
+
index,
|
|
15850
|
+
blockType: "reasoning"
|
|
15851
|
+
},
|
|
15852
|
+
{
|
|
15853
|
+
type: "reasoning-delta",
|
|
15854
|
+
index,
|
|
15855
|
+
text
|
|
15856
|
+
}
|
|
15857
|
+
];
|
|
15858
|
+
}
|
|
15859
|
+
state.thinkingBlock.text += text;
|
|
15860
|
+
return [{
|
|
15861
|
+
type: "reasoning-delta",
|
|
15862
|
+
index: state.thinkingBlock.index,
|
|
15863
|
+
text
|
|
15864
|
+
}];
|
|
15865
|
+
}
|
|
15866
|
+
function closeThinking(state) {
|
|
15867
|
+
const block = state.thinkingBlock;
|
|
15868
|
+
if (block === null) return [];
|
|
15869
|
+
state.thinkingBlock = null;
|
|
15870
|
+
return [{
|
|
15871
|
+
type: "block-end",
|
|
15872
|
+
index: block.index,
|
|
15873
|
+
block: {
|
|
15874
|
+
type: "reasoning",
|
|
15875
|
+
text: block.text
|
|
15876
|
+
}
|
|
15877
|
+
}];
|
|
15878
|
+
}
|
|
14107
15879
|
function applyText(state, text) {
|
|
14108
15880
|
state.hasContent = true;
|
|
15881
|
+
const closed = closeThinking(state);
|
|
14109
15882
|
if (state.textBlock === null) {
|
|
15883
|
+
closed.push({
|
|
15884
|
+
type: "block-start",
|
|
15885
|
+
index: state.nextBlockIndex,
|
|
15886
|
+
blockType: "text"
|
|
15887
|
+
});
|
|
14110
15888
|
const index = state.nextBlockIndex;
|
|
14111
15889
|
state.nextBlockIndex += 1;
|
|
14112
15890
|
state.textBlock = {
|
|
14113
15891
|
index,
|
|
14114
15892
|
text
|
|
14115
15893
|
};
|
|
14116
|
-
|
|
14117
|
-
type: "block-start",
|
|
14118
|
-
index,
|
|
14119
|
-
blockType: "text"
|
|
14120
|
-
}, {
|
|
15894
|
+
closed.push({
|
|
14121
15895
|
type: "text-delta",
|
|
14122
15896
|
index,
|
|
14123
15897
|
text
|
|
14124
|
-
}
|
|
15898
|
+
});
|
|
15899
|
+
return closed;
|
|
14125
15900
|
}
|
|
14126
15901
|
state.textBlock.text += text;
|
|
14127
|
-
return [{
|
|
15902
|
+
return [...closed, {
|
|
14128
15903
|
type: "text-delta",
|
|
14129
15904
|
index: state.textBlock.index,
|
|
14130
15905
|
text
|
|
@@ -14133,6 +15908,7 @@ function applyText(state, text) {
|
|
|
14133
15908
|
function applyToolCall(state, call) {
|
|
14134
15909
|
state.hasContent = true;
|
|
14135
15910
|
const out = [];
|
|
15911
|
+
out.push(...closeThinking(state));
|
|
14136
15912
|
out.push(...closeText(state));
|
|
14137
15913
|
const index = state.nextBlockIndex;
|
|
14138
15914
|
state.nextBlockIndex += 1;
|
|
@@ -14195,7 +15971,11 @@ function closeToolCalls$3(state) {
|
|
|
14195
15971
|
*/
|
|
14196
15972
|
function closeStream$3(state) {
|
|
14197
15973
|
const sawToolCall = state.toolCalls.size > 0;
|
|
14198
|
-
const out = [
|
|
15974
|
+
const out = [
|
|
15975
|
+
...closeThinking(state),
|
|
15976
|
+
...closeText(state),
|
|
15977
|
+
...closeToolCalls$3(state)
|
|
15978
|
+
];
|
|
14199
15979
|
out.push({
|
|
14200
15980
|
type: "finish",
|
|
14201
15981
|
reason: sawToolCall ? { kind: "tool-calls" } : { kind: "stop" }
|
|
@@ -14297,7 +16077,7 @@ var OllamaAdapter = class extends LlmAdapter {
|
|
|
14297
16077
|
provider: prov,
|
|
14298
16078
|
id: model.id,
|
|
14299
16079
|
name: model.name ?? model.id,
|
|
14300
|
-
inputModalities: ["text", "image"]
|
|
16080
|
+
inputModalities: ollamaModelSupportsImage(model.id) ? ["text", "image"] : ["text"]
|
|
14301
16081
|
}));
|
|
14302
16082
|
}
|
|
14303
16083
|
async resolveModel(provider, modelId, signal) {
|
|
@@ -14307,7 +16087,7 @@ var OllamaAdapter = class extends LlmAdapter {
|
|
|
14307
16087
|
provider,
|
|
14308
16088
|
id: modelId,
|
|
14309
16089
|
name: entry?.name ?? modelId,
|
|
14310
|
-
inputModalities: ["text", "image"],
|
|
16090
|
+
inputModalities: ollamaModelSupportsImage(modelId) ? ["text", "image"] : ["text"],
|
|
14311
16091
|
context: { contextWindow: contextWindowFor(entry) },
|
|
14312
16092
|
...outputReservation(contextWindowFor(entry), DEFAULT_MAX_OUTPUT_TOKENS)
|
|
14313
16093
|
};
|
|
@@ -14321,10 +16101,11 @@ var OllamaAdapter = class extends LlmAdapter {
|
|
|
14321
16101
|
async *stream(options) {
|
|
14322
16102
|
yield* wrapStreamWithWatchdog((watchdogSignal) => this.requestStream(options, watchdogSignal), options.signal, STREAM_IDLE_TIMEOUT_MS$4, STREAM_IDLE_TIMEOUT_CODE$4, PROVIDER_NAME$4);
|
|
14323
16103
|
}
|
|
14324
|
-
async *requestStream(
|
|
16104
|
+
async *requestStream(rawOptions, signal) {
|
|
14325
16105
|
const fetchFn = this.options.fetchFn ?? fetch;
|
|
16106
|
+
const options = normalizeGenerateOptions(rawOptions);
|
|
14326
16107
|
const wire = wireForModel$1(options.model);
|
|
14327
|
-
const request = toOllamaRequest(options);
|
|
16108
|
+
const request = await toOllamaRequest(options, this.options.attachments, signal);
|
|
14328
16109
|
const pool = this.accountPool;
|
|
14329
16110
|
const tried = /* @__PURE__ */ new Set();
|
|
14330
16111
|
let lastStatus;
|
|
@@ -14364,7 +16145,7 @@ var OllamaAdapter = class extends LlmAdapter {
|
|
|
14364
16145
|
spent = event.usage;
|
|
14365
16146
|
continue;
|
|
14366
16147
|
}
|
|
14367
|
-
if (event.type === "text" || event.type === "tool_call") {
|
|
16148
|
+
if (event.type === "text" || event.type === "thinking" || event.type === "tool_call") {
|
|
14368
16149
|
for (const chunk of applyEvent(state, event)) yield chunk;
|
|
14369
16150
|
continue;
|
|
14370
16151
|
}
|
|
@@ -14393,18 +16174,134 @@ var OllamaAdapter = class extends LlmAdapter {
|
|
|
14393
16174
|
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 });
|
|
14394
16175
|
}
|
|
14395
16176
|
};
|
|
14396
|
-
|
|
14397
|
-
|
|
14398
|
-
|
|
14399
|
-
|
|
14400
|
-
|
|
14401
|
-
|
|
14402
|
-
|
|
14403
|
-
|
|
14404
|
-
|
|
14405
|
-
|
|
16177
|
+
function isAbort$2(error, signal) {
|
|
16178
|
+
return signal?.aborted === true || error instanceof Error && error.name === "AbortError";
|
|
16179
|
+
}
|
|
16180
|
+
function isRecord$18(value) {
|
|
16181
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16182
|
+
}
|
|
16183
|
+
function asString$11(value) {
|
|
16184
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
16185
|
+
}
|
|
16186
|
+
function attachmentLabel$4(block) {
|
|
16187
|
+
const attachment = isRecord$18(block.attachment) ? block.attachment : void 0;
|
|
16188
|
+
return asString$11(attachment?.name) || asString$11(attachment?.attachmentId);
|
|
16189
|
+
}
|
|
16190
|
+
function unavailableImageText$4(block) {
|
|
16191
|
+
const label = attachmentLabel$4(block);
|
|
16192
|
+
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]`;
|
|
16193
|
+
}
|
|
16194
|
+
function abortException(signal) {
|
|
16195
|
+
if (signal?.reason !== void 0) return signal.reason instanceof Error ? signal.reason : new Error(String(signal.reason));
|
|
16196
|
+
return new DOMException("The operation was aborted", "AbortError");
|
|
16197
|
+
}
|
|
16198
|
+
function unsupportedImageText$1(model, block) {
|
|
16199
|
+
const label = attachmentLabel$4(block);
|
|
16200
|
+
return `[image unsupported: ${label ? `${label}: ` : ""}model ${model} is not known to declare image support; remove the attachment or switch to a vision model]`;
|
|
16201
|
+
}
|
|
16202
|
+
function combineTextParts(parts) {
|
|
16203
|
+
let result = "";
|
|
16204
|
+
for (const part of parts) {
|
|
16205
|
+
if (!part) continue;
|
|
16206
|
+
if (!result) result = part;
|
|
16207
|
+
else if (part.startsWith("[image ") || result.endsWith("\n")) result = result.trimEnd() + "\n\n" + part;
|
|
16208
|
+
else result += part;
|
|
16209
|
+
}
|
|
16210
|
+
return result;
|
|
16211
|
+
}
|
|
16212
|
+
async function processMessageContent(content, model, attachments, signal) {
|
|
16213
|
+
if (signal?.aborted) throw abortException(signal);
|
|
16214
|
+
if (typeof content === "string") return { text: content };
|
|
16215
|
+
if (!Array.isArray(content)) return { text: "" };
|
|
16216
|
+
const textParts = [];
|
|
16217
|
+
const images = [];
|
|
16218
|
+
for (const part of content) {
|
|
16219
|
+
if (typeof part === "string") {
|
|
16220
|
+
textParts.push(part);
|
|
16221
|
+
continue;
|
|
16222
|
+
}
|
|
16223
|
+
if (!isRecord$18(part)) continue;
|
|
16224
|
+
if (part.type === "text") {
|
|
16225
|
+
if (typeof part.text === "string" && part.text !== "") textParts.push(part.text);
|
|
14406
16226
|
continue;
|
|
14407
16227
|
}
|
|
16228
|
+
if (part.type === "image") {
|
|
16229
|
+
if (!ollamaModelSupportsImage(model)) {
|
|
16230
|
+
textParts.push(unsupportedImageText$1(model, part));
|
|
16231
|
+
continue;
|
|
16232
|
+
}
|
|
16233
|
+
const reference = isImageRef(part.attachment) ? part.attachment : isImageRef(part.source) ? part.source : null;
|
|
16234
|
+
if (reference !== null) {
|
|
16235
|
+
if (!attachments) {
|
|
16236
|
+
textParts.push(unavailableImageText$4(part));
|
|
16237
|
+
continue;
|
|
16238
|
+
}
|
|
16239
|
+
try {
|
|
16240
|
+
if (signal?.aborted) throw abortException(signal);
|
|
16241
|
+
const loaded = await attachments.readImage(reference, signal);
|
|
16242
|
+
if (signal?.aborted) throw abortException(signal);
|
|
16243
|
+
if (loaded === null) textParts.push(unavailableImageText$4(part));
|
|
16244
|
+
else images.push(encodeImage(loaded.data, loaded.ref.mediaType));
|
|
16245
|
+
} catch (error) {
|
|
16246
|
+
if (isAbort$2(error, signal)) throw error;
|
|
16247
|
+
textParts.push(unavailableImageText$4(part));
|
|
16248
|
+
}
|
|
16249
|
+
continue;
|
|
16250
|
+
}
|
|
16251
|
+
const inline = part.source;
|
|
16252
|
+
if (isRecord$18(inline)) {
|
|
16253
|
+
const data = inline.data;
|
|
16254
|
+
if (typeof data === "string" && data !== "") {
|
|
16255
|
+
images.push(encodeImage(data, asMediaType(inline.mediaType)));
|
|
16256
|
+
continue;
|
|
16257
|
+
}
|
|
16258
|
+
}
|
|
16259
|
+
if (typeof part.image === "string" && part.image !== "") {
|
|
16260
|
+
images.push(part.image);
|
|
16261
|
+
continue;
|
|
16262
|
+
}
|
|
16263
|
+
textParts.push(unavailableImageText$4(part));
|
|
16264
|
+
continue;
|
|
16265
|
+
}
|
|
16266
|
+
}
|
|
16267
|
+
return {
|
|
16268
|
+
text: combineTextParts(textParts),
|
|
16269
|
+
...images.length > 0 ? { images } : {}
|
|
16270
|
+
};
|
|
16271
|
+
}
|
|
16272
|
+
/**
|
|
16273
|
+
* Project DSH's request shape onto Ollama's, per surface.
|
|
16274
|
+
* Consumes the canonical Message vocabulary produced by normalizeGenerateOptions.
|
|
16275
|
+
*/
|
|
16276
|
+
async function toOllamaRequest(options, attachments, signal) {
|
|
16277
|
+
if (signal?.aborted) throw abortException(signal);
|
|
16278
|
+
const messages = [];
|
|
16279
|
+
const trimmedSystem = typeof options.system === "string" && options.system.trim() !== "" ? options.system.trim() : void 0;
|
|
16280
|
+
if (trimmedSystem !== void 0) messages.push({
|
|
16281
|
+
role: "system",
|
|
16282
|
+
content: trimmedSystem
|
|
16283
|
+
});
|
|
16284
|
+
for (let index = 0; index < options.messages.length; index++) {
|
|
16285
|
+
const message = options.messages[index];
|
|
16286
|
+
if (index === 0 && trimmedSystem !== void 0 && (message.role === "system" || message.role === "developer")) {
|
|
16287
|
+
if (textOf$4(message.content).trim() === trimmedSystem) continue;
|
|
16288
|
+
}
|
|
16289
|
+
if ((message.source?.kind === "tool" || Array.isArray(message.content) && message.content.some((b) => b.type === "tool-result")) && Array.isArray(message.content)) {
|
|
16290
|
+
const toolResultBlocks = message.content.filter((b) => b.type === "tool-result");
|
|
16291
|
+
if (toolResultBlocks.length > 0) {
|
|
16292
|
+
for (const block of toolResultBlocks) {
|
|
16293
|
+
const toolCallId = String(block.toolCallId ?? (isRecord$18(message.source) ? message.source.callId : "") ?? "");
|
|
16294
|
+
const processed = await processMessageContent(block.content, options.model, attachments, signal);
|
|
16295
|
+
messages.push({
|
|
16296
|
+
role: "tool",
|
|
16297
|
+
content: processed.text,
|
|
16298
|
+
...toolCallId !== "" ? { toolCallId } : {},
|
|
16299
|
+
...processed.images ? { images: processed.images } : {}
|
|
16300
|
+
});
|
|
16301
|
+
}
|
|
16302
|
+
continue;
|
|
16303
|
+
}
|
|
16304
|
+
}
|
|
14408
16305
|
const toolCalls = assistantToolCalls(message.content);
|
|
14409
16306
|
if (toolCalls.length > 0) {
|
|
14410
16307
|
messages.push({
|
|
@@ -14414,9 +16311,26 @@ function toOllamaRequest(options) {
|
|
|
14414
16311
|
});
|
|
14415
16312
|
continue;
|
|
14416
16313
|
}
|
|
16314
|
+
if (message.role === "assistant") {
|
|
16315
|
+
messages.push({
|
|
16316
|
+
role: "assistant",
|
|
16317
|
+
content: textOf$4(message.content)
|
|
16318
|
+
});
|
|
16319
|
+
continue;
|
|
16320
|
+
}
|
|
16321
|
+
if (message.role === "system" || message.role === "developer") {
|
|
16322
|
+
const text = textOf$4(message.content).trim();
|
|
16323
|
+
if (text !== "") messages.push({
|
|
16324
|
+
role: "system",
|
|
16325
|
+
content: text
|
|
16326
|
+
});
|
|
16327
|
+
continue;
|
|
16328
|
+
}
|
|
16329
|
+
const processed = await processMessageContent(message.content, options.model, attachments, signal);
|
|
14417
16330
|
messages.push({
|
|
14418
|
-
role:
|
|
14419
|
-
content:
|
|
16331
|
+
role: "user",
|
|
16332
|
+
content: processed.text,
|
|
16333
|
+
...processed.images ? { images: processed.images } : {}
|
|
14420
16334
|
});
|
|
14421
16335
|
}
|
|
14422
16336
|
const request = {
|
|
@@ -14425,6 +16339,8 @@ function toOllamaRequest(options) {
|
|
|
14425
16339
|
};
|
|
14426
16340
|
if (options.maxTokens !== void 0) request.maxOutputTokens = options.maxTokens;
|
|
14427
16341
|
if (options.temperature !== void 0) request.temperature = options.temperature;
|
|
16342
|
+
const think = thinkForModel(options.model, options.reasoningEffort);
|
|
16343
|
+
if (think !== void 0) request.think = think;
|
|
14428
16344
|
const tools = options.tools;
|
|
14429
16345
|
if (Array.isArray(tools) && tools.length > 0) request.tools = tools.map((tool) => ({
|
|
14430
16346
|
name: tool.name,
|
|
@@ -14455,6 +16371,23 @@ function assistantToolCalls(content) {
|
|
|
14455
16371
|
}
|
|
14456
16372
|
return calls;
|
|
14457
16373
|
}
|
|
16374
|
+
function isImageRef(value) {
|
|
16375
|
+
return typeof value === "object" && value !== null && typeof value.attachmentId === "string";
|
|
16376
|
+
}
|
|
16377
|
+
function asMediaType(value) {
|
|
16378
|
+
return typeof value === "string" && value !== "" ? value : "image/png";
|
|
16379
|
+
}
|
|
16380
|
+
/**
|
|
16381
|
+
* The base64 payload Ollama wants, with or without a data URL prefix.
|
|
16382
|
+
*
|
|
16383
|
+
* The native surface takes the bare payload; a `data:` URL is accepted by both
|
|
16384
|
+
* surfaces once, so one encoding serves either and avoids a route-specific
|
|
16385
|
+
* guess about what a given model accepts.
|
|
16386
|
+
*/
|
|
16387
|
+
function encodeImage(data, mediaType) {
|
|
16388
|
+
const base64 = typeof data === "string" ? data : Buffer.from(data).toString("base64");
|
|
16389
|
+
return base64.startsWith("data:") ? base64 : `data:${mediaType};base64,${base64}`;
|
|
16390
|
+
}
|
|
14458
16391
|
function textOf$4(content) {
|
|
14459
16392
|
if (typeof content === "string") return content;
|
|
14460
16393
|
if (Array.isArray(content)) return content.map((part) => {
|
|
@@ -20368,6 +22301,22 @@ function redactToken(token) {
|
|
|
20368
22301
|
if (token === void 0 || token === null || token === "") return "<none>";
|
|
20369
22302
|
return "sha256:" + createHash("sha256").update(token).digest("hex").slice(0, 12) + "/len:" + token.length;
|
|
20370
22303
|
}
|
|
22304
|
+
/**
|
|
22305
|
+
* Adapter-selected auth owner (nonsecret hash).
|
|
22306
|
+
*
|
|
22307
|
+
* Scoped to the specific account and credential token/key selected by the adapter.
|
|
22308
|
+
* Any account change or token/key replacement produces a different hash,
|
|
22309
|
+
* preventing thinking/signature replay across different authentication boundaries.
|
|
22310
|
+
*/
|
|
22311
|
+
function computeMinimaxAuthOwner(credentials, accountId) {
|
|
22312
|
+
const token = (credentials?.apiKey || credentials?.accessToken || "").trim();
|
|
22313
|
+
if (!token) return "";
|
|
22314
|
+
const hash = createHash("sha256");
|
|
22315
|
+
if (accountId && accountId.trim() !== "") hash.update(`acc:${accountId}\0`);
|
|
22316
|
+
if (credentials?.region && credentials.region.trim() !== "") hash.update(`reg:${credentials.region}\0`);
|
|
22317
|
+
hash.update(`tok:${token}`);
|
|
22318
|
+
return hash.digest("hex").slice(0, 32);
|
|
22319
|
+
}
|
|
20371
22320
|
//#endregion
|
|
20372
22321
|
//#region src/host/minimax-code/mapper.ts
|
|
20373
22322
|
/**
|
|
@@ -20457,6 +22406,31 @@ function safeJsonParse$2(text) {
|
|
|
20457
22406
|
function sanitizeText$2(text) {
|
|
20458
22407
|
return text.replace(/\0/g, "");
|
|
20459
22408
|
}
|
|
22409
|
+
function jsonSafeValue$1(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
22410
|
+
if (value === null) return null;
|
|
22411
|
+
switch (typeof value) {
|
|
22412
|
+
case "string":
|
|
22413
|
+
case "boolean": return value;
|
|
22414
|
+
case "number":
|
|
22415
|
+
if (!Number.isFinite(value)) return void 0;
|
|
22416
|
+
return Object.is(value, -0) ? 0 : value;
|
|
22417
|
+
case "object": break;
|
|
22418
|
+
default: return;
|
|
22419
|
+
}
|
|
22420
|
+
if (seen.has(value)) return void 0;
|
|
22421
|
+
seen.add(value);
|
|
22422
|
+
try {
|
|
22423
|
+
if (Array.isArray(value)) return Array.from(value, (item) => jsonSafeValue$1(item, seen) ?? null);
|
|
22424
|
+
const record = {};
|
|
22425
|
+
for (const key of Object.keys(value)) {
|
|
22426
|
+
const child = jsonSafeValue$1(value[key], seen);
|
|
22427
|
+
if (child !== void 0) record[key] = child;
|
|
22428
|
+
}
|
|
22429
|
+
return record;
|
|
22430
|
+
} finally {
|
|
22431
|
+
seen.delete(value);
|
|
22432
|
+
}
|
|
22433
|
+
}
|
|
20460
22434
|
/** Media types the wire accepts as inline base64. */
|
|
20461
22435
|
const SUPPORTED_IMAGE_MEDIA_TYPES$2 = /* @__PURE__ */ new Set([
|
|
20462
22436
|
"image/png",
|
|
@@ -20640,9 +22614,92 @@ function anthropicUserContent(message, images) {
|
|
|
20640
22614
|
}
|
|
20641
22615
|
return blocks;
|
|
20642
22616
|
}
|
|
20643
|
-
|
|
22617
|
+
/**
|
|
22618
|
+
* Native blocks to replay for one assistant turn, as the service issued them.
|
|
22619
|
+
*
|
|
22620
|
+
* Read from the message's stored replay state rather than rebuilt from the
|
|
22621
|
+
* visible reasoning text: a rebuilt block is not the block the model signed, and
|
|
22622
|
+
* the difference is exactly what the provider validates. Falls back to nothing
|
|
22623
|
+
* when a turn carries no stored state, which is the current behaviour for
|
|
22624
|
+
* history this route did not produce.
|
|
22625
|
+
*/
|
|
22626
|
+
/** Fingerprint the entire array of emitted visible blocks in an assistant message. */
|
|
22627
|
+
function computeVisibleContentHash(blocks) {
|
|
22628
|
+
if (!Array.isArray(blocks)) return "";
|
|
22629
|
+
const canonical = blocks.map((b) => {
|
|
22630
|
+
if (!isRecord$15(b)) return null;
|
|
22631
|
+
const type = asString$8(b.type) ?? "";
|
|
22632
|
+
if (type === "text" || type === "reasoning") return [type, sanitizeText$2(asString$8(b.text) ?? "")];
|
|
22633
|
+
if (type === "tool-call") return [
|
|
22634
|
+
type,
|
|
22635
|
+
asString$8(b.id) ?? "",
|
|
22636
|
+
asString$8(b.name) ?? "",
|
|
22637
|
+
toolCallArguments$2(b.arguments)
|
|
22638
|
+
];
|
|
22639
|
+
return [type, jsonSafeValue$1(b)];
|
|
22640
|
+
});
|
|
22641
|
+
return createHash("sha256").update(JSON.stringify(canonical)).digest("hex").slice(0, 32);
|
|
22642
|
+
}
|
|
22643
|
+
/**
|
|
22644
|
+
* Verbatim wire block to replay for one reasoning block.
|
|
22645
|
+
*
|
|
22646
|
+
* Verifies route, model, and auth owner provenance. Fails safely on legacy unscoped state
|
|
22647
|
+
* or any mismatch, dropping the replay block rather than submitting invalid state.
|
|
22648
|
+
* Preserves raw native text and signature binding.
|
|
22649
|
+
*/
|
|
22650
|
+
function replayedThinkingBlock$1(message, index, expectedScope, block) {
|
|
22651
|
+
const source = message.source;
|
|
22652
|
+
if (source === void 0 || source === null || !isRecord$15(source)) return void 0;
|
|
22653
|
+
if (source.provider && source.provider !== PROVIDER_ID$2 && source.provider !== "dsh-chatgpt-subscription") return;
|
|
22654
|
+
if (source.model && expectedScope && source.model !== expectedScope.model) return;
|
|
22655
|
+
const state = source.replayState;
|
|
22656
|
+
if (!isRecord$15(state)) return void 0;
|
|
22657
|
+
const resp = isRecord$15(state.response) ? state.response : state;
|
|
22658
|
+
const stateRoute = asString$8(resp.route) ?? asString$8(resp.provider);
|
|
22659
|
+
const stateModel = asString$8(resp.model);
|
|
22660
|
+
const stateAuthOwner = asString$8(resp.authOwner);
|
|
22661
|
+
if (!stateRoute || !stateModel || !stateAuthOwner || stateAuthOwner.trim() === "") return;
|
|
22662
|
+
if (expectedScope === void 0) return void 0;
|
|
22663
|
+
if (expectedScope.route && stateRoute !== expectedScope.route) return void 0;
|
|
22664
|
+
if (expectedScope.model && stateModel !== expectedScope.model) return void 0;
|
|
22665
|
+
if (!expectedScope.authOwner || expectedScope.authOwner.trim() === "" || stateAuthOwner !== expectedScope.authOwner) return;
|
|
22666
|
+
let candidate;
|
|
22667
|
+
if (Array.isArray(state.blocks)) {
|
|
22668
|
+
const entry = state.blocks[index];
|
|
22669
|
+
if (isRecord$15(entry)) candidate = entry;
|
|
22670
|
+
}
|
|
22671
|
+
if (candidate === void 0 && Array.isArray(resp.blocks)) {
|
|
22672
|
+
const entry = resp.blocks[index];
|
|
22673
|
+
if (isRecord$15(entry)) candidate = entry;
|
|
22674
|
+
}
|
|
22675
|
+
if (candidate === void 0 && Array.isArray(resp.nativeBlocks)) {
|
|
22676
|
+
const entry = resp.nativeBlocks[index];
|
|
22677
|
+
if (isRecord$15(entry)) candidate = entry;
|
|
22678
|
+
}
|
|
22679
|
+
if (candidate === void 0) return void 0;
|
|
22680
|
+
if (Array.isArray(state.blocks) && state.blocks.length !== message.content.length) return void 0;
|
|
22681
|
+
if (Array.isArray(resp.blocks) && resp.blocks.length !== message.content.length) return void 0;
|
|
22682
|
+
const stateVisibleHash = asString$8(resp.visibleContentHash);
|
|
22683
|
+
if (!stateVisibleHash || stateVisibleHash.trim() === "") return void 0;
|
|
22684
|
+
if (computeVisibleContentHash(message.content) !== stateVisibleHash) return void 0;
|
|
22685
|
+
if (candidate.type !== "thinking" && candidate.type !== "redacted_thinking") return;
|
|
22686
|
+
const visibleText = asString$8(block?.text) ?? "";
|
|
22687
|
+
if (candidate.type === "redacted_thinking") {
|
|
22688
|
+
if (visibleText !== "") return void 0;
|
|
22689
|
+
const data = asString$8(candidate.data);
|
|
22690
|
+
if (!data || data.trim() === "") return void 0;
|
|
22691
|
+
return structuredClone(candidate);
|
|
22692
|
+
}
|
|
22693
|
+
if (sanitizeText$2(asString$8(candidate.thinking) ?? "") !== sanitizeText$2(visibleText)) return;
|
|
22694
|
+
const signature = asString$8(candidate.signature);
|
|
22695
|
+
if (!signature || signature.trim() === "") return void 0;
|
|
22696
|
+
return structuredClone(candidate);
|
|
22697
|
+
}
|
|
22698
|
+
function anthropicAssistantContent(message, expectedScope) {
|
|
20644
22699
|
const blocks = [];
|
|
20645
|
-
|
|
22700
|
+
if (!Array.isArray(message.content)) return blocks;
|
|
22701
|
+
for (let index = 0; index < message.content.length; index++) {
|
|
22702
|
+
const block = message.content[index];
|
|
20646
22703
|
if (!isRecord$15(block)) continue;
|
|
20647
22704
|
if (block.type === "text" && typeof block.text === "string") {
|
|
20648
22705
|
const text = sanitizeText$2(block.text);
|
|
@@ -20660,6 +22717,12 @@ function anthropicAssistantContent(message) {
|
|
|
20660
22717
|
name: block.name,
|
|
20661
22718
|
input: isRecord$15(parsed) ? parsed : {}
|
|
20662
22719
|
});
|
|
22720
|
+
continue;
|
|
22721
|
+
}
|
|
22722
|
+
if (block.type === "reasoning") {
|
|
22723
|
+
const replay = replayedThinkingBlock$1(message, index, expectedScope, block);
|
|
22724
|
+
if (replay !== void 0) blocks.push(replay);
|
|
22725
|
+
continue;
|
|
20663
22726
|
}
|
|
20664
22727
|
}
|
|
20665
22728
|
return blocks;
|
|
@@ -20808,6 +22871,12 @@ function markMinimaxCacheBreakpoints(body) {
|
|
|
20808
22871
|
}
|
|
20809
22872
|
/** Build one Anthropic Messages body for this subscription. */
|
|
20810
22873
|
function buildMinimaxRequest(options, images = NO_RESOLVED_IMAGES$2, request = {}) {
|
|
22874
|
+
const expectedScope = request.authOwner !== void 0 ? {
|
|
22875
|
+
route: request.route ?? PROVIDER_ID$2,
|
|
22876
|
+
model: options.model,
|
|
22877
|
+
authOwner: request.authOwner,
|
|
22878
|
+
provider: PROVIDER_ID$2
|
|
22879
|
+
} : void 0;
|
|
20811
22880
|
const entries = [];
|
|
20812
22881
|
for (const message of nonSystemMessages$2(options)) {
|
|
20813
22882
|
if (isToolResultMessage$2(message)) {
|
|
@@ -20819,7 +22888,7 @@ function buildMinimaxRequest(options, images = NO_RESOLVED_IMAGES$2, request = {
|
|
|
20819
22888
|
}
|
|
20820
22889
|
entries.push({
|
|
20821
22890
|
role: message.role === "assistant" ? "assistant" : "user",
|
|
20822
|
-
content: message.role === "assistant" ? anthropicAssistantContent(message) : anthropicUserContent(message, images)
|
|
22891
|
+
content: message.role === "assistant" ? anthropicAssistantContent(message, expectedScope) : anthropicUserContent(message, images)
|
|
20823
22892
|
});
|
|
20824
22893
|
}
|
|
20825
22894
|
const system = leadingSystemText$2(options);
|
|
@@ -20867,8 +22936,16 @@ function assertRequestBodyFits(body, limit = maxMessageBodyBytes()) {
|
|
|
20867
22936
|
if (bytes <= limit) return serialized;
|
|
20868
22937
|
throw new LlmError$1("MiniMax Code(编程订阅) request was not sent: the serialized body is " + bytes + " bytes, above the " + limit + "-byte ceiling this route enforces. Compact the conversation or start a new session, and check for large tool results or attached media.", "PROVIDER_ERROR");
|
|
20869
22938
|
}
|
|
20870
|
-
function createStreamState() {
|
|
22939
|
+
function createStreamState(options) {
|
|
20871
22940
|
return {
|
|
22941
|
+
provenance: options?.model && options?.authOwner ? {
|
|
22942
|
+
route: options.route ?? PROVIDER_ID$2,
|
|
22943
|
+
model: options.model,
|
|
22944
|
+
authOwner: options.authOwner,
|
|
22945
|
+
provider: options.provider ?? PROVIDER_ID$2
|
|
22946
|
+
} : void 0,
|
|
22947
|
+
replayBlocks: [],
|
|
22948
|
+
pendingThinking: /* @__PURE__ */ new Map(),
|
|
20872
22949
|
blocks: [],
|
|
20873
22950
|
current: null,
|
|
20874
22951
|
toolCalls: /* @__PURE__ */ new Map(),
|
|
@@ -20912,6 +22989,7 @@ function openTextBlock$1(state, type) {
|
|
|
20912
22989
|
type,
|
|
20913
22990
|
text: ""
|
|
20914
22991
|
});
|
|
22992
|
+
state.replayBlocks[index] = null;
|
|
20915
22993
|
out.push({
|
|
20916
22994
|
type: "block-start",
|
|
20917
22995
|
index,
|
|
@@ -20929,6 +23007,7 @@ function closeToolCalls$1(state) {
|
|
|
20929
23007
|
arguments: call.arguments === "" ? "{}" : call.arguments
|
|
20930
23008
|
};
|
|
20931
23009
|
state.blocks[call.blockIndex] = block;
|
|
23010
|
+
state.replayBlocks[call.blockIndex] = null;
|
|
20932
23011
|
out.push({
|
|
20933
23012
|
type: "block-end",
|
|
20934
23013
|
index: call.blockIndex,
|
|
@@ -20961,9 +23040,34 @@ function closeMinimaxStream(state) {
|
|
|
20961
23040
|
type: "usage",
|
|
20962
23041
|
usage: tokenUsage$2(state)
|
|
20963
23042
|
});
|
|
23043
|
+
const paddedBlocks = state.blocks.map((_, i) => {
|
|
23044
|
+
const b = state.replayBlocks[i];
|
|
23045
|
+
return b !== void 0 && b !== null ? jsonSafeValue$1(b) : null;
|
|
23046
|
+
});
|
|
23047
|
+
const replayThinking = paddedBlocks.filter((b) => b !== null);
|
|
23048
|
+
const hasReplay = replayThinking.length > 0;
|
|
23049
|
+
const visibleContentHash = computeVisibleContentHash(state.blocks);
|
|
23050
|
+
const replayState = hasReplay ? state.provenance ? {
|
|
23051
|
+
response: {
|
|
23052
|
+
provider: state.provenance.provider ?? PROVIDER_ID$2,
|
|
23053
|
+
route: state.provenance.route ?? PROVIDER_ID$2,
|
|
23054
|
+
model: state.provenance.model,
|
|
23055
|
+
authOwner: state.provenance.authOwner,
|
|
23056
|
+
visibleContentHash,
|
|
23057
|
+
minimaxThinking: replayThinking
|
|
23058
|
+
},
|
|
23059
|
+
blocks: paddedBlocks
|
|
23060
|
+
} : {
|
|
23061
|
+
response: {
|
|
23062
|
+
visibleContentHash,
|
|
23063
|
+
minimaxThinking: replayThinking
|
|
23064
|
+
},
|
|
23065
|
+
blocks: paddedBlocks
|
|
23066
|
+
} : void 0;
|
|
20964
23067
|
out.push({
|
|
20965
23068
|
type: "finish",
|
|
20966
|
-
reason: finishReasonFor$2(state)
|
|
23069
|
+
reason: finishReasonFor$2(state),
|
|
23070
|
+
...replayState !== void 0 ? { replayState } : {}
|
|
20967
23071
|
});
|
|
20968
23072
|
return out;
|
|
20969
23073
|
}
|
|
@@ -21034,8 +23138,40 @@ function processMinimaxStreamLine(line, state) {
|
|
|
21034
23138
|
return out;
|
|
21035
23139
|
}
|
|
21036
23140
|
if (blockType === "thinking" || blockType === "redacted_thinking") {
|
|
21037
|
-
|
|
21038
|
-
|
|
23141
|
+
const index = state.blocks.length;
|
|
23142
|
+
const kind = blockType === "redacted_thinking" ? "redacted_thinking" : "thinking";
|
|
23143
|
+
const data = asString$8(block.data) ?? "";
|
|
23144
|
+
const signature = asString$8(block.signature) ?? "";
|
|
23145
|
+
const thinking = asString$8(block.thinking) ?? "";
|
|
23146
|
+
state.current = {
|
|
23147
|
+
index,
|
|
23148
|
+
type: "reasoning",
|
|
23149
|
+
text: kind === "thinking" ? thinking : ""
|
|
23150
|
+
};
|
|
23151
|
+
state.blocks.push({
|
|
23152
|
+
type: "reasoning",
|
|
23153
|
+
text: state.current.text
|
|
23154
|
+
});
|
|
23155
|
+
const initialReplay = isRecord$15(event.content_block) ? structuredClone(event.content_block) : { type: blockType };
|
|
23156
|
+
state.replayBlocks[index] = initialReplay;
|
|
23157
|
+
state.pendingThinking.set(contentIndex, {
|
|
23158
|
+
dshIndex: index,
|
|
23159
|
+
kind,
|
|
23160
|
+
text: thinking,
|
|
23161
|
+
signature,
|
|
23162
|
+
data
|
|
23163
|
+
});
|
|
23164
|
+
state.contentIndexes.set(contentIndex, index);
|
|
23165
|
+
out.push({
|
|
23166
|
+
type: "block-start",
|
|
23167
|
+
index,
|
|
23168
|
+
blockType: "reasoning"
|
|
23169
|
+
});
|
|
23170
|
+
if (state.current.text !== "") out.push({
|
|
23171
|
+
type: "reasoning-delta",
|
|
23172
|
+
index,
|
|
23173
|
+
text: state.current.text
|
|
23174
|
+
});
|
|
21039
23175
|
return out;
|
|
21040
23176
|
}
|
|
21041
23177
|
out.push(...openTextBlock$1(state, "text"));
|
|
@@ -21061,8 +23197,37 @@ function processMinimaxStreamLine(line, state) {
|
|
|
21061
23197
|
}
|
|
21062
23198
|
return out;
|
|
21063
23199
|
}
|
|
23200
|
+
if (deltaType === "signature_delta") {
|
|
23201
|
+
const signature = asString$8(delta.signature) ?? "";
|
|
23202
|
+
const pending = state.pendingThinking.get(contentIndex);
|
|
23203
|
+
if (pending !== void 0 && signature !== "") {
|
|
23204
|
+
pending.signature += signature;
|
|
23205
|
+
const replay = state.replayBlocks[pending.dshIndex];
|
|
23206
|
+
if (replay !== void 0 && replay !== null) replay.signature = (asString$8(replay.signature) ?? "") + signature;
|
|
23207
|
+
}
|
|
23208
|
+
return out;
|
|
23209
|
+
}
|
|
23210
|
+
if (deltaType === "data_delta") {
|
|
23211
|
+
const data = asString$8(delta.data) ?? "";
|
|
23212
|
+
const pending = state.pendingThinking.get(contentIndex);
|
|
23213
|
+
if (pending !== void 0 && data !== "") {
|
|
23214
|
+
pending.data = (pending.data ?? "") + data;
|
|
23215
|
+
const replay = state.replayBlocks[pending.dshIndex];
|
|
23216
|
+
if (replay !== void 0 && replay !== null) replay.data = (asString$8(replay.data) ?? "") + data;
|
|
23217
|
+
}
|
|
23218
|
+
return out;
|
|
23219
|
+
}
|
|
21064
23220
|
const text = deltaType === "thinking_delta" ? asString$8(delta.thinking) : asString$8(delta.text);
|
|
21065
23221
|
if (text !== void 0 && text !== "") {
|
|
23222
|
+
const pending = state.pendingThinking.get(contentIndex);
|
|
23223
|
+
if (pending !== void 0) {
|
|
23224
|
+
pending.text += text;
|
|
23225
|
+
const replay = state.replayBlocks[pending.dshIndex];
|
|
23226
|
+
if (replay !== void 0 && replay !== null) {
|
|
23227
|
+
const field = replay.type === "redacted_thinking" ? "data" : "thinking";
|
|
23228
|
+
replay[field] = (asString$8(replay[field]) ?? "") + text;
|
|
23229
|
+
}
|
|
23230
|
+
}
|
|
21066
23231
|
const index = state.contentIndexes.get(contentIndex) ?? state.current?.index;
|
|
21067
23232
|
const kind = deltaType === "thinking_delta" ? "reasoning" : "text";
|
|
21068
23233
|
if (state.current === null || state.current.index !== index) {
|
|
@@ -21077,6 +23242,7 @@ function processMinimaxStreamLine(line, state) {
|
|
|
21077
23242
|
type: kind,
|
|
21078
23243
|
text: ""
|
|
21079
23244
|
});
|
|
23245
|
+
state.replayBlocks[next] = null;
|
|
21080
23246
|
state.contentIndexes.set(contentIndex, next);
|
|
21081
23247
|
out.push({
|
|
21082
23248
|
type: "block-start",
|
|
@@ -21159,7 +23325,7 @@ const MINIMAX_CODE_MODELS = [
|
|
|
21159
23325
|
maxAttachments: null,
|
|
21160
23326
|
maxImageBytes: null,
|
|
21161
23327
|
maxVideoBytes: null,
|
|
21162
|
-
|
|
23328
|
+
filesApiDocumented: false,
|
|
21163
23329
|
description: "Thinking is always on and has no selectable level. Text input only."
|
|
21164
23330
|
},
|
|
21165
23331
|
{
|
|
@@ -21175,7 +23341,7 @@ const MINIMAX_CODE_MODELS = [
|
|
|
21175
23341
|
maxAttachments: null,
|
|
21176
23342
|
maxImageBytes: null,
|
|
21177
23343
|
maxVideoBytes: null,
|
|
21178
|
-
|
|
23344
|
+
filesApiDocumented: false,
|
|
21179
23345
|
description: "The high-speed M2.7. Thinking is always on with no selectable level. Text input only."
|
|
21180
23346
|
},
|
|
21181
23347
|
{
|
|
@@ -21191,7 +23357,7 @@ const MINIMAX_CODE_MODELS = [
|
|
|
21191
23357
|
maxAttachments: 9,
|
|
21192
23358
|
maxImageBytes: 10 * 1024 * 1024,
|
|
21193
23359
|
maxVideoBytes: 50 * 1024 * 1024,
|
|
21194
|
-
|
|
23360
|
+
filesApiDocumented: true,
|
|
21195
23361
|
description: "Flagship subscription model. Thinking is on by default and can be disabled. Accepts text, image and video; up to 9 attachments, 10MB per image and 50MB per video."
|
|
21196
23362
|
},
|
|
21197
23363
|
{
|
|
@@ -21214,7 +23380,7 @@ const MINIMAX_CODE_MODELS = [
|
|
|
21214
23380
|
maxAttachments: 4,
|
|
21215
23381
|
maxImageBytes: 10 * 1024 * 1024,
|
|
21216
23382
|
maxVideoBytes: 50 * 1024 * 1024,
|
|
21217
|
-
|
|
23383
|
+
filesApiDocumented: true,
|
|
21218
23384
|
description: "Preview Flash model with a 1M context window. Thinking is forced on with a selectable effort level. Accepts up to 4 attachments."
|
|
21219
23385
|
}
|
|
21220
23386
|
];
|
|
@@ -23399,11 +25565,6 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
23399
25565
|
const contextWindow = contextWindowForModel(options.model, settings.contextWindowOverrides);
|
|
23400
25566
|
const requestOptions = offloadOldestRequestImages$2(normalizeGenerateOptions(options), maxRequestImageBytes());
|
|
23401
25567
|
const images = await resolveRequestImages$2(requestOptions, this.options.attachments, signal);
|
|
23402
|
-
const requestedMax = requestOptions.maxTokens ?? maxOutputTokensFor$1(options.model, contextWindow);
|
|
23403
|
-
const body = assertRequestBodyFits(buildMinimaxRequest({
|
|
23404
|
-
...requestOptions,
|
|
23405
|
-
maxTokens: clampOutputToContext(requestedMax, contextWindow, estimatedInputTokens(requestOptions))
|
|
23406
|
-
}, images, { cacheControl: true }));
|
|
23407
25568
|
let credentials;
|
|
23408
25569
|
let accountId;
|
|
23409
25570
|
try {
|
|
@@ -23414,6 +25575,19 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
23414
25575
|
if (error instanceof MinimaxCodeUnauthorizedError) throw new LlmError(error.message, "INVALID_CREDENTIAL", { cause: error });
|
|
23415
25576
|
throw new LlmError("MiniMax Code(编程订阅) credential could not be prepared: " + (error instanceof Error ? error.message : String(error)), "MISSING_CREDENTIAL", { cause: error });
|
|
23416
25577
|
}
|
|
25578
|
+
let authOwner = computeMinimaxAuthOwner(credentials, accountId);
|
|
25579
|
+
const effectiveMax = clampOutputToContext(requestOptions.maxTokens ?? maxOutputTokensFor$1(options.model, contextWindow), contextWindow, estimatedInputTokens(requestOptions));
|
|
25580
|
+
const buildBodyForOwner = (owner) => {
|
|
25581
|
+
return assertRequestBodyFits(buildMinimaxRequest({
|
|
25582
|
+
...requestOptions,
|
|
25583
|
+
maxTokens: effectiveMax
|
|
25584
|
+
}, images, {
|
|
25585
|
+
cacheControl: true,
|
|
25586
|
+
authOwner: owner,
|
|
25587
|
+
route: PROVIDER_ID$2
|
|
25588
|
+
}));
|
|
25589
|
+
};
|
|
25590
|
+
let body = buildBodyForOwner(authOwner);
|
|
23417
25591
|
let response;
|
|
23418
25592
|
for (let attempt = 0;; attempt += 1) {
|
|
23419
25593
|
try {
|
|
@@ -23433,6 +25607,8 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
23433
25607
|
const refused = credentials.accessToken;
|
|
23434
25608
|
try {
|
|
23435
25609
|
credentials = await this.renewCredential(accountId, fetchFn, signal, refused);
|
|
25610
|
+
authOwner = computeMinimaxAuthOwner(credentials, accountId);
|
|
25611
|
+
body = buildBodyForOwner(authOwner);
|
|
23436
25612
|
} catch (error) {
|
|
23437
25613
|
if (error instanceof MinimaxCodeUnauthorizedError) throw new LlmError(error.message, "INVALID_CREDENTIAL", { cause: error });
|
|
23438
25614
|
throw new LlmError("MiniMax Code(编程订阅) credential could not be renewed after the service refused " + redactToken(refused) + ": " + (error instanceof Error ? error.message : String(error)), "INVALID_CREDENTIAL", { cause: error });
|
|
@@ -23451,7 +25627,12 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
23451
25627
|
if (response.body === null) throw new LlmError("MiniMax Code(编程订阅) returned an empty response body", "PROVIDER_ERROR");
|
|
23452
25628
|
const reader = response.body.getReader();
|
|
23453
25629
|
const decoder = new TextDecoder();
|
|
23454
|
-
const state = createStreamState(
|
|
25630
|
+
const state = createStreamState({
|
|
25631
|
+
model: options.model,
|
|
25632
|
+
authOwner,
|
|
25633
|
+
route: PROVIDER_ID$2,
|
|
25634
|
+
provider: PROVIDER_ID$2
|
|
25635
|
+
});
|
|
23455
25636
|
let buffer = "";
|
|
23456
25637
|
try {
|
|
23457
25638
|
while (true) {
|
|
@@ -27717,6 +29898,7 @@ function createStreamState$2() {
|
|
|
27717
29898
|
inputTokens: 0,
|
|
27718
29899
|
outputTokens: 0,
|
|
27719
29900
|
cacheReadTokens: 0,
|
|
29901
|
+
cacheWriteTokens: 0,
|
|
27720
29902
|
reasoningTokens: 0,
|
|
27721
29903
|
sawUsage: false
|
|
27722
29904
|
};
|
|
@@ -27798,8 +29980,10 @@ function processStreamLine$1(line, state) {
|
|
|
27798
29980
|
const prompt = numberOr$1(usage.prompt_tokens, 0);
|
|
27799
29981
|
const details = isRecord$8(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
|
|
27800
29982
|
const cached = details ? numberOr$1(details.cached_tokens, 0) : 0;
|
|
27801
|
-
|
|
29983
|
+
const written = details ? numberOr$1(details.cache_write_tokens, 0) : 0;
|
|
29984
|
+
state.inputTokens = Math.max(0, prompt - cached - written);
|
|
27802
29985
|
state.cacheReadTokens = cached;
|
|
29986
|
+
state.cacheWriteTokens = written;
|
|
27803
29987
|
state.outputTokens = numberOr$1(usage.completion_tokens, state.outputTokens);
|
|
27804
29988
|
if (isRecord$8(usage.completion_tokens_details)) state.reasoningTokens = numberOr$1(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
|
|
27805
29989
|
}
|
|
@@ -27900,6 +30084,7 @@ function tokenUsage$1(state) {
|
|
|
27900
30084
|
inputTokens: state.inputTokens,
|
|
27901
30085
|
outputTokens: state.outputTokens,
|
|
27902
30086
|
...state.cacheReadTokens > 0 ? { cacheReadTokens: state.cacheReadTokens } : {},
|
|
30087
|
+
...state.cacheWriteTokens > 0 ? { cacheWriteTokens: state.cacheWriteTokens } : {},
|
|
27903
30088
|
...state.reasoningTokens > 0 ? { reasoningTokens: state.reasoningTokens } : {}
|
|
27904
30089
|
};
|
|
27905
30090
|
}
|
|
@@ -39752,8 +41937,16 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
39752
41937
|
logger: ctx.logger
|
|
39753
41938
|
});
|
|
39754
41939
|
const proxyFetch = proxyManager.createFetch();
|
|
41940
|
+
const providerLimits = readModelRequestLimits();
|
|
41941
|
+
const modelFetch = Object.fromEntries(CONTROLLED_PROVIDERS.map((provider) => [provider, createControlledModelFetch(createDiagnosticFetch(proxyFetch, {
|
|
41942
|
+
provider,
|
|
41943
|
+
onRecord: (record) => ctx.logger.info("[provider-diagnostics] " + JSON.stringify(record))
|
|
41944
|
+
}), {
|
|
41945
|
+
provider,
|
|
41946
|
+
limits: providerLimits
|
|
41947
|
+
})]));
|
|
39755
41948
|
const antigravityAdapter = new AntigravityAdapter(antigravityStore, antigravityModelSettings, antigravityPreferences, {
|
|
39756
|
-
fetchFn:
|
|
41949
|
+
fetchFn: modelFetch.antigravity,
|
|
39757
41950
|
attachments: ctx.attachments
|
|
39758
41951
|
}, antigravityAccountPool);
|
|
39759
41952
|
let antigravityRegistration;
|
|
@@ -39780,7 +41973,7 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
39780
41973
|
conflict: () => commandCodeConflict
|
|
39781
41974
|
}, commandCodeAccountPool);
|
|
39782
41975
|
const commandCodeAdapter = new CommandCodeAdapter(commandCodeStore, commandCodeModelSettings, commandCodePreferences, {
|
|
39783
|
-
fetchFn:
|
|
41976
|
+
fetchFn: modelFetch["command-code"],
|
|
39784
41977
|
attachments: ctx.attachments
|
|
39785
41978
|
}, commandCodeAccountPool);
|
|
39786
41979
|
let commandCodeRegistration;
|
|
@@ -39788,11 +41981,14 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
39788
41981
|
const ollamaStore = new FileCredentialStore$5();
|
|
39789
41982
|
const ollamaModelSettings = new FileModelSettingsStore$5();
|
|
39790
41983
|
const ollamaAccountPool = new OllamaAccountPool({ store: ollamaStore });
|
|
39791
|
-
const ollamaAdapter = new OllamaAdapter(ollamaStore, ollamaModelSettings, {
|
|
41984
|
+
const ollamaAdapter = new OllamaAdapter(ollamaStore, ollamaModelSettings, {
|
|
41985
|
+
fetchFn: modelFetch.ollama,
|
|
41986
|
+
attachments: ctx.attachments
|
|
41987
|
+
}, ollamaAccountPool);
|
|
39792
41988
|
let ollamaRegistration;
|
|
39793
41989
|
let ollamaConflict = null;
|
|
39794
41990
|
const kimiCodeAdapter = new KimiCodeAdapter(kimiCodeStore, kimiCodeModelSettings, kimiCodePreferences, {
|
|
39795
|
-
fetchFn:
|
|
41991
|
+
fetchFn: modelFetch["kimi-code"],
|
|
39796
41992
|
attachments: ctx.attachments,
|
|
39797
41993
|
videos: { readVideo: async (ref) => ({
|
|
39798
41994
|
data: await readVideoBytes(ref),
|
|
@@ -39854,7 +42050,7 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
39854
42050
|
conflict: () => kimiCodeConflict
|
|
39855
42051
|
}, kimiCodeAccountPool);
|
|
39856
42052
|
const minimaxCodeAdapter = new MinimaxCodeAdapter(minimaxCodeStore, {
|
|
39857
|
-
fetchFn:
|
|
42053
|
+
fetchFn: modelFetch["minimax-code"],
|
|
39858
42054
|
attachments: ctx.attachments,
|
|
39859
42055
|
accountPool: minimaxCodeAccountPool
|
|
39860
42056
|
}, minimaxCodeModelSettings, minimaxCodePreferences);
|
|
@@ -39904,7 +42100,7 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
39904
42100
|
checkin: minimaxCodeCheckin
|
|
39905
42101
|
}, minimaxCodeModelSettings, minimaxCodePreferences);
|
|
39906
42102
|
const workBuddyAdapter = new WorkBuddyAdapter(workBuddyStore, workBuddyModelSettings, workBuddyPreferences, {
|
|
39907
|
-
fetchFn:
|
|
42103
|
+
fetchFn: modelFetch.workbuddy,
|
|
39908
42104
|
attachments: ctx.attachments,
|
|
39909
42105
|
accountPool: workBuddyAccountPool
|
|
39910
42106
|
});
|
|
@@ -39946,7 +42142,7 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
39946
42142
|
checkin: workBuddyCheckin
|
|
39947
42143
|
});
|
|
39948
42144
|
const claudeAdapter = new ClaudeAdapter(claudeStore, claudeModelSettings, claudePreferences, {
|
|
39949
|
-
fetchFn:
|
|
42145
|
+
fetchFn: modelFetch.claude,
|
|
39950
42146
|
attachments: ctx.attachments,
|
|
39951
42147
|
accountPool: claudeAccountPool
|
|
39952
42148
|
});
|
|
@@ -39983,7 +42179,7 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
39983
42179
|
const usage = new UsageService(oauth, { fetchFn: proxyFetch });
|
|
39984
42180
|
codexAccountPool.setQuotaBlockedUntil((account, now) => usage.blockedUntilFor(account.credentials, now));
|
|
39985
42181
|
const adapter = new CodexChatGptAdapter(new ResponsesClient(oauth, ctx.attachments, {
|
|
39986
|
-
fetchFn:
|
|
42182
|
+
fetchFn: modelFetch["codex-chatgpt"],
|
|
39987
42183
|
accountPool: codexAccountPool,
|
|
39988
42184
|
localRawImages: { baseUrl: localWebServerBaseUrl(ctx.webServer.host, ctx.webServer.port) },
|
|
39989
42185
|
onGenerationFinished: () => usage.invalidate(),
|