@kenkaiiii/gg-ai 5.93.0 → 5.95.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -16
- package/dist/index.cjs +240 -517
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -41
- package/dist/index.d.ts +17 -41
- package/dist/index.js +239 -512
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -30,11 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
CLAUDE_CODE_FALLBACK_VERSION: () => CLAUDE_CODE_FALLBACK_VERSION,
|
|
34
|
-
CODEX_CLIENT_VERSION: () => CODEX_CLIENT_VERSION,
|
|
35
33
|
EventStream: () => EventStream,
|
|
36
34
|
FAST_MODE_SUFFIX: () => FAST_MODE_SUFFIX,
|
|
37
35
|
GGAIError: () => GGAIError,
|
|
36
|
+
GG_CODER_USER_AGENT: () => GG_CODER_USER_AGENT,
|
|
38
37
|
LOCAL_NO_API_KEY: () => LOCAL_NO_API_KEY,
|
|
39
38
|
PRECONNECT_INTERVAL_MS: () => PRECONNECT_INTERVAL_MS,
|
|
40
39
|
ProviderError: () => ProviderError,
|
|
@@ -52,8 +51,6 @@ __export(index_exports, {
|
|
|
52
51
|
formatChatError: () => formatChatError,
|
|
53
52
|
formatError: () => formatError,
|
|
54
53
|
formatErrorForDisplay: () => formatErrorForDisplay,
|
|
55
|
-
getClaudeCliUserAgent: () => getClaudeCliUserAgent,
|
|
56
|
-
getClaudeCodeVersion: () => getClaudeCodeVersion,
|
|
57
54
|
hasLoneSurrogate: () => hasLoneSurrogate,
|
|
58
55
|
isHardBillingMessage: () => isHardBillingMessage,
|
|
59
56
|
isUsageLimitError: () => isUsageLimitError,
|
|
@@ -68,7 +65,6 @@ __export(index_exports, {
|
|
|
68
65
|
palsuThinking: () => palsuThinking,
|
|
69
66
|
palsuToolCall: () => palsuToolCall,
|
|
70
67
|
parseFastModeRejection: () => parseFastModeRejection,
|
|
71
|
-
pendingClaudeCodeVersionRefresh: () => pendingClaudeCodeVersionRefresh,
|
|
72
68
|
preconnectOrigin: () => preconnectOrigin,
|
|
73
69
|
preconnectProvider: () => preconnectProvider,
|
|
74
70
|
prewarmAnthropicCache: () => prewarmAnthropicCache,
|
|
@@ -96,7 +92,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
96
92
|
var FAST_MODE_SUFFIX = "-fast";
|
|
97
93
|
var FAST_MODE_BASE_MODELS = {
|
|
98
94
|
anthropic: ["claude-opus-5-5"],
|
|
99
|
-
openai: ["gpt-6-astra", "gpt-6.1-sol", "gpt-6-luna"]
|
|
95
|
+
openai: ["gpt-6-astra", "gpt-6.1-sol", "gpt-6.1-terra", "gpt-6-luna"]
|
|
100
96
|
};
|
|
101
97
|
function resolveFastModeModel(provider, model) {
|
|
102
98
|
if (!model.endsWith(FAST_MODE_SUFFIX)) return { model, fast: false };
|
|
@@ -337,6 +333,18 @@ function formatError(err) {
|
|
|
337
333
|
}
|
|
338
334
|
const miniMax = err.provider === "minimax" ? formatMiniMaxError(err, cleanMessage) : void 0;
|
|
339
335
|
if (miniMax) return miniMax;
|
|
336
|
+
if (isUsageLimitError(err) && err.provider === "openai" && /chatgpt/i.test(err.message)) {
|
|
337
|
+
return {
|
|
338
|
+
headline: "ChatGPT plan usage limit reached.",
|
|
339
|
+
source: "provider",
|
|
340
|
+
message: "GG Coder has used what your ChatGPT plan allows for now. That can be your plan's limit or one you set for GG Coder.",
|
|
341
|
+
provider: err.provider,
|
|
342
|
+
statusCode: err.statusCode,
|
|
343
|
+
...err.requestId ? { requestId: err.requestId } : {},
|
|
344
|
+
...err.resetsAt ? { resetsAt: err.resetsAt } : {},
|
|
345
|
+
guidance: err.hint ?? "Check or raise it at chatgpt.com/settings/usage, or add an OpenAI API key to keep going."
|
|
346
|
+
};
|
|
347
|
+
}
|
|
340
348
|
if (isUsageLimitError(err)) {
|
|
341
349
|
const resetClause = err.resetsAt ? ` It resets at ${formatResetTime(err.resetsAt)}.` : "";
|
|
342
350
|
return {
|
|
@@ -702,145 +710,6 @@ var StreamResult = class _StreamResult {
|
|
|
702
710
|
}
|
|
703
711
|
};
|
|
704
712
|
|
|
705
|
-
// src/claude-code-version.ts
|
|
706
|
-
var import_promises = __toESM(require("fs/promises"), 1);
|
|
707
|
-
var import_node_os = __toESM(require("os"), 1);
|
|
708
|
-
var import_node_path = __toESM(require("path"), 1);
|
|
709
|
-
|
|
710
|
-
// src/utils/diag.ts
|
|
711
|
-
var _diagFn = null;
|
|
712
|
-
function setProviderDiagnostic(fn) {
|
|
713
|
-
_diagFn = fn;
|
|
714
|
-
}
|
|
715
|
-
function providerDiag(phase, data) {
|
|
716
|
-
_diagFn?.(phase, data);
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
// src/claude-code-version.ts
|
|
720
|
-
var NPM_LATEST_URL = "https://registry.npmjs.org/@anthropic-ai/claude-code/latest";
|
|
721
|
-
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
722
|
-
var FETCH_TIMEOUT_MS = 3e3;
|
|
723
|
-
var CLAUDE_CODE_FALLBACK_VERSION = "2.1.316";
|
|
724
|
-
function isOlder(a, b) {
|
|
725
|
-
const pa = a.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
726
|
-
const pb = b.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
727
|
-
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
728
|
-
const x = pa[i] ?? 0;
|
|
729
|
-
const y = pb[i] ?? 0;
|
|
730
|
-
if (x !== y) return x < y;
|
|
731
|
-
}
|
|
732
|
-
return false;
|
|
733
|
-
}
|
|
734
|
-
function atLeastFallback(version) {
|
|
735
|
-
return isOlder(version, CLAUDE_CODE_FALLBACK_VERSION) ? CLAUDE_CODE_FALLBACK_VERSION : version;
|
|
736
|
-
}
|
|
737
|
-
var memoryCache = null;
|
|
738
|
-
var inflight = null;
|
|
739
|
-
function agentDir() {
|
|
740
|
-
return import_node_path.default.join(import_node_os.default.homedir(), ".gg");
|
|
741
|
-
}
|
|
742
|
-
function cachePath() {
|
|
743
|
-
return import_node_path.default.join(agentDir(), "claude-code-version.json");
|
|
744
|
-
}
|
|
745
|
-
async function readDiskCache() {
|
|
746
|
-
try {
|
|
747
|
-
const raw = await import_promises.default.readFile(cachePath(), "utf-8");
|
|
748
|
-
const parsed = JSON.parse(raw);
|
|
749
|
-
if (typeof parsed.version === "string" && typeof parsed.fetchedAt === "number") {
|
|
750
|
-
return parsed;
|
|
751
|
-
}
|
|
752
|
-
return null;
|
|
753
|
-
} catch {
|
|
754
|
-
return null;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
async function writeDiskCache(data) {
|
|
758
|
-
try {
|
|
759
|
-
await import_promises.default.mkdir(agentDir(), { recursive: true, mode: 448 });
|
|
760
|
-
await import_promises.default.writeFile(cachePath(), JSON.stringify(data), { mode: 384 });
|
|
761
|
-
} catch (err) {
|
|
762
|
-
providerDiag("claude_code_version_cache_write_failed", {
|
|
763
|
-
error: err instanceof Error ? err.message : String(err)
|
|
764
|
-
});
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
async function fetchLatest() {
|
|
768
|
-
const controller = new AbortController();
|
|
769
|
-
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
770
|
-
try {
|
|
771
|
-
const response = await fetch(NPM_LATEST_URL, { signal: controller.signal });
|
|
772
|
-
if (!response.ok) return null;
|
|
773
|
-
const data = await response.json();
|
|
774
|
-
if (typeof data.version === "string" && /^\d/.test(data.version)) {
|
|
775
|
-
return data.version;
|
|
776
|
-
}
|
|
777
|
-
return null;
|
|
778
|
-
} catch {
|
|
779
|
-
return null;
|
|
780
|
-
} finally {
|
|
781
|
-
clearTimeout(timer);
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
var refreshing = null;
|
|
785
|
-
function refreshInBackground() {
|
|
786
|
-
refreshing ??= (async () => {
|
|
787
|
-
try {
|
|
788
|
-
const fetched = await fetchLatest();
|
|
789
|
-
if (!fetched) return;
|
|
790
|
-
await writeDiskCache({ version: fetched, fetchedAt: Date.now() });
|
|
791
|
-
memoryCache = { version: fetched, expiresAt: Date.now() + CACHE_TTL_MS };
|
|
792
|
-
} finally {
|
|
793
|
-
refreshing = null;
|
|
794
|
-
}
|
|
795
|
-
})();
|
|
796
|
-
return refreshing;
|
|
797
|
-
}
|
|
798
|
-
function pendingClaudeCodeVersionRefresh() {
|
|
799
|
-
return refreshing;
|
|
800
|
-
}
|
|
801
|
-
async function getClaudeCodeVersion() {
|
|
802
|
-
if (memoryCache && Date.now() < memoryCache.expiresAt) {
|
|
803
|
-
return memoryCache.version;
|
|
804
|
-
}
|
|
805
|
-
if (inflight) return inflight;
|
|
806
|
-
inflight = (async () => {
|
|
807
|
-
const disk = await readDiskCache();
|
|
808
|
-
const diskFresh = disk && Date.now() - disk.fetchedAt < CACHE_TTL_MS;
|
|
809
|
-
if (disk && diskFresh) {
|
|
810
|
-
const version = atLeastFallback(disk.version);
|
|
811
|
-
memoryCache = { version, expiresAt: Date.now() + CACHE_TTL_MS };
|
|
812
|
-
return version;
|
|
813
|
-
}
|
|
814
|
-
if (disk) {
|
|
815
|
-
const version = atLeastFallback(disk.version);
|
|
816
|
-
memoryCache = { version, expiresAt: Date.now() + 5 * 60 * 1e3 };
|
|
817
|
-
void refreshInBackground();
|
|
818
|
-
return version;
|
|
819
|
-
}
|
|
820
|
-
const fetched = await fetchLatest();
|
|
821
|
-
if (fetched) {
|
|
822
|
-
await writeDiskCache({ version: fetched, fetchedAt: Date.now() });
|
|
823
|
-
memoryCache = { version: fetched, expiresAt: Date.now() + CACHE_TTL_MS };
|
|
824
|
-
return fetched;
|
|
825
|
-
}
|
|
826
|
-
const resolved = CLAUDE_CODE_FALLBACK_VERSION;
|
|
827
|
-
memoryCache = { version: resolved, expiresAt: Date.now() + 5 * 60 * 1e3 };
|
|
828
|
-
providerDiag("claude_code_version_fallback", { version: resolved });
|
|
829
|
-
return resolved;
|
|
830
|
-
})();
|
|
831
|
-
try {
|
|
832
|
-
return await inflight;
|
|
833
|
-
} finally {
|
|
834
|
-
inflight = null;
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
function claudeCliUserAgent(version) {
|
|
838
|
-
return `claude-cli/${version} (external, cli)`;
|
|
839
|
-
}
|
|
840
|
-
async function getClaudeCliUserAgent() {
|
|
841
|
-
return claudeCliUserAgent(await getClaudeCodeVersion());
|
|
842
|
-
}
|
|
843
|
-
|
|
844
713
|
// src/utils/provider-options.ts
|
|
845
714
|
var RESERVED_BODY_FIELDS = /* @__PURE__ */ new Set([
|
|
846
715
|
"contents",
|
|
@@ -1376,7 +1245,7 @@ function toolCallNameRuleFor(provider, options) {
|
|
|
1376
1245
|
return TOOL_CALL_NAME_RULES.anthropic;
|
|
1377
1246
|
case "openai":
|
|
1378
1247
|
if (options?.accountId) return TOOL_CALL_NAME_RULES["openai-responses"];
|
|
1379
|
-
return isDefaultOrHost(options?.baseUrl, "api.openai.com") ? TOOL_CALL_NAME_RULES["openai-
|
|
1248
|
+
return isDefaultOrHost(options?.baseUrl, "api.openai.com") ? TOOL_CALL_NAME_RULES["openai-responses"] : TOOL_CALL_NAME_RULES.generic;
|
|
1380
1249
|
case "gemini":
|
|
1381
1250
|
return TOOL_CALL_NAME_RULES.gemini;
|
|
1382
1251
|
default:
|
|
@@ -1574,8 +1443,8 @@ function usesDeferredToolLoading(options) {
|
|
|
1574
1443
|
const firstParty = !options.baseUrl || options.baseUrl.includes("api.anthropic.com");
|
|
1575
1444
|
return firstParty && supportsAnthropicDeferredTools(options.model);
|
|
1576
1445
|
}
|
|
1577
|
-
if (options.provider === "openai" && options.accountId) {
|
|
1578
|
-
return supportsResponsesToolSearch(options.model);
|
|
1446
|
+
if (options.provider === "openai" && !options.accountId) {
|
|
1447
|
+
return isDefaultOrHost(options.baseUrl, "api.openai.com") && supportsResponsesToolSearch(options.model);
|
|
1579
1448
|
}
|
|
1580
1449
|
return false;
|
|
1581
1450
|
}
|
|
@@ -2066,7 +1935,7 @@ function toGlmReasoningEffort(level) {
|
|
|
2066
1935
|
}
|
|
2067
1936
|
function toCodexReasoningEffort(level, model) {
|
|
2068
1937
|
if (level !== "ultra") return level;
|
|
2069
|
-
return model === "gpt-6-astra" || model === "gpt-6.1-sol" ? "xhigh" : "max";
|
|
1938
|
+
return model === "gpt-6-astra" || model === "gpt-6.1-sol" || model === "gpt-6.1-terra" ? "xhigh" : "max";
|
|
2070
1939
|
}
|
|
2071
1940
|
var DECLARED_EFFORT_ORDER = ["low", "medium", "high", "xhigh", "max"];
|
|
2072
1941
|
function effortForRequest(level, model, declared) {
|
|
@@ -2150,12 +2019,12 @@ function createProviderFetch(timeoutMs, { useEnvProxy = nodeUsesEnvProxy() } = {
|
|
|
2150
2019
|
};
|
|
2151
2020
|
const dispatcher = useEnvProxy ? new import_undici.EnvHttpProxyAgent(timeouts) : new import_undici.Agent(timeouts);
|
|
2152
2021
|
const builtinFetch = globalThis.fetch;
|
|
2153
|
-
const providerFetch2 = async (input,
|
|
2154
|
-
if (globalThis.fetch !== builtinFetch || input instanceof Request ||
|
|
2155
|
-
return globalThis.fetch(input,
|
|
2022
|
+
const providerFetch2 = async (input, init) => {
|
|
2023
|
+
if (globalThis.fetch !== builtinFetch || input instanceof Request || init?.body instanceof FormData) {
|
|
2024
|
+
return globalThis.fetch(input, init);
|
|
2156
2025
|
}
|
|
2157
2026
|
const response = await (0, import_undici.fetch)(input, {
|
|
2158
|
-
...
|
|
2027
|
+
...init,
|
|
2159
2028
|
dispatcher
|
|
2160
2029
|
});
|
|
2161
2030
|
return response;
|
|
@@ -2163,8 +2032,8 @@ function createProviderFetch(timeoutMs, { useEnvProxy = nodeUsesEnvProxy() } = {
|
|
|
2163
2032
|
return Object.assign(providerFetch2, { Response: globalThis.Response });
|
|
2164
2033
|
}
|
|
2165
2034
|
function withBodyActivity(fetchImpl, onActivity) {
|
|
2166
|
-
return async (input,
|
|
2167
|
-
const response = await fetchImpl(input,
|
|
2035
|
+
return async (input, init) => {
|
|
2036
|
+
const response = await fetchImpl(input, init);
|
|
2168
2037
|
if (!response.body || !response.headers.get("content-type")?.includes("text/event-stream")) {
|
|
2169
2038
|
return response;
|
|
2170
2039
|
}
|
|
@@ -2203,8 +2072,7 @@ var anthropicServerFallback = {
|
|
|
2203
2072
|
}
|
|
2204
2073
|
};
|
|
2205
2074
|
function serverFallbackKey(options) {
|
|
2206
|
-
|
|
2207
|
-
return `${options.baseUrl ?? process.env.ANTHROPIC_BASE_URL ?? ""}|${auth}`;
|
|
2075
|
+
return options.baseUrl ?? process.env.ANTHROPIC_BASE_URL ?? "";
|
|
2208
2076
|
}
|
|
2209
2077
|
function isDirectAnthropicApi(baseUrl) {
|
|
2210
2078
|
const effective = baseUrl ?? process.env.ANTHROPIC_BASE_URL;
|
|
@@ -2237,30 +2105,18 @@ function sumUsageIterations(usage) {
|
|
|
2237
2105
|
}
|
|
2238
2106
|
return totals;
|
|
2239
2107
|
}
|
|
2240
|
-
async function withClaudeUserAgent(options) {
|
|
2241
|
-
if (options.userAgent || !options.apiKey?.startsWith("sk-ant-oat")) return options;
|
|
2242
|
-
return { ...options, userAgent: await getClaudeCliUserAgent() };
|
|
2243
|
-
}
|
|
2244
2108
|
function createClient(options) {
|
|
2245
|
-
const
|
|
2246
|
-
const userAgent = isOAuth ? options.userAgent ?? claudeCliUserAgent(CLAUDE_CODE_FALLBACK_VERSION) : "";
|
|
2247
|
-
const cacheKey = `${options.apiKey ?? ""}|${options.baseUrl ?? ""}|${userAgent}`;
|
|
2109
|
+
const cacheKey = `${options.apiKey ?? ""}|${options.baseUrl ?? ""}`;
|
|
2248
2110
|
if (!options.fetch) {
|
|
2249
2111
|
const cached = anthropicClientCache.get(cacheKey);
|
|
2250
2112
|
if (cached) return cached;
|
|
2251
2113
|
}
|
|
2252
2114
|
const client = new import_sdk.default({
|
|
2253
|
-
|
|
2115
|
+
apiKey: options.apiKey,
|
|
2254
2116
|
...options.baseUrl ? { baseURL: options.baseUrl } : {},
|
|
2255
2117
|
// Default transport lifts undici's 300s header/body caps (see provider-fetch.ts).
|
|
2256
2118
|
fetch: options.fetch ?? providerFetch,
|
|
2257
|
-
maxRetries: 0
|
|
2258
|
-
...isOAuth ? {
|
|
2259
|
-
defaultHeaders: {
|
|
2260
|
-
"user-agent": userAgent,
|
|
2261
|
-
"x-app": "cli"
|
|
2262
|
-
}
|
|
2263
|
-
} : {}
|
|
2119
|
+
maxRetries: 0
|
|
2264
2120
|
});
|
|
2265
2121
|
if (!options.fetch) {
|
|
2266
2122
|
if (anthropicClientCache.size >= 8) {
|
|
@@ -2273,13 +2129,10 @@ function createClient(options) {
|
|
|
2273
2129
|
}
|
|
2274
2130
|
async function prewarmAnthropicCache(options) {
|
|
2275
2131
|
try {
|
|
2276
|
-
const client = createClient(
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
userAgent: options.userAgent
|
|
2281
|
-
})
|
|
2282
|
-
);
|
|
2132
|
+
const client = createClient({
|
|
2133
|
+
apiKey: options.apiKey,
|
|
2134
|
+
baseUrl: options.baseUrl
|
|
2135
|
+
});
|
|
2283
2136
|
const cacheControl = toAnthropicCacheControl(options.cacheRetention ?? "long", options.baseUrl);
|
|
2284
2137
|
const { system, messages } = toAnthropicMessages(
|
|
2285
2138
|
[
|
|
@@ -2288,21 +2141,13 @@ async function prewarmAnthropicCache(options) {
|
|
|
2288
2141
|
],
|
|
2289
2142
|
cacheControl
|
|
2290
2143
|
);
|
|
2291
|
-
const isOAuth = options.apiKey.startsWith("sk-ant-oat");
|
|
2292
|
-
const fullSystem = isOAuth ? [
|
|
2293
|
-
{
|
|
2294
|
-
type: "text",
|
|
2295
|
-
text: "You are Claude Code, Anthropic's official CLI for Claude."
|
|
2296
|
-
},
|
|
2297
|
-
...system ?? []
|
|
2298
|
-
] : system;
|
|
2299
2144
|
const tools = options.tools?.length ? toAnthropicTools(options.tools, {
|
|
2300
2145
|
cacheControl,
|
|
2301
2146
|
// Keep the serialized tool bytes identical to runStream so the
|
|
2302
2147
|
// prewarmed prompt cache actually hits — both are gated by the flag.
|
|
2303
2148
|
enableFineGrainedToolStreaming: fineGrainedToolStreamingEnabled()
|
|
2304
2149
|
}) : void 0;
|
|
2305
|
-
if (estimatePrefixTokens(
|
|
2150
|
+
if (estimatePrefixTokens(system, tools) < anthropicMinCacheableTokens(options.model)) {
|
|
2306
2151
|
return;
|
|
2307
2152
|
}
|
|
2308
2153
|
await client.messages.create(
|
|
@@ -2310,7 +2155,7 @@ async function prewarmAnthropicCache(options) {
|
|
|
2310
2155
|
model: options.model,
|
|
2311
2156
|
max_tokens: 1,
|
|
2312
2157
|
messages,
|
|
2313
|
-
...
|
|
2158
|
+
...system ? { system } : {},
|
|
2314
2159
|
...tools ? {
|
|
2315
2160
|
tools: [
|
|
2316
2161
|
...tools,
|
|
@@ -2321,10 +2166,7 @@ async function prewarmAnthropicCache(options) {
|
|
|
2321
2166
|
{
|
|
2322
2167
|
signal: options.signal ?? void 0,
|
|
2323
2168
|
...(() => {
|
|
2324
|
-
const betas = [
|
|
2325
|
-
...isOAuth ? ["claude-code-20250219", "oauth-2025-04-20"] : [],
|
|
2326
|
-
...cacheControl?.ttl === "1h" ? ["extended-cache-ttl-2025-04-11"] : []
|
|
2327
|
-
];
|
|
2169
|
+
const betas = cacheControl?.ttl === "1h" ? ["extended-cache-ttl-2025-04-11"] : [];
|
|
2328
2170
|
return betas.length ? { headers: { "anthropic-beta": betas.join(",") } } : {};
|
|
2329
2171
|
})()
|
|
2330
2172
|
}
|
|
@@ -2336,8 +2178,7 @@ function streamAnthropic(options) {
|
|
|
2336
2178
|
return new StreamResult(runStream(options), options.signal);
|
|
2337
2179
|
}
|
|
2338
2180
|
async function* runStream(options) {
|
|
2339
|
-
const client = createClient(
|
|
2340
|
-
const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
|
|
2181
|
+
const client = createClient(options);
|
|
2341
2182
|
const useStreaming = options.streaming !== false && !options.prewarm;
|
|
2342
2183
|
const cacheControl = toAnthropicCacheControl(options.cacheRetention, options.baseUrl);
|
|
2343
2184
|
const supportsFirstPartyToolExtras = !options.baseUrl || options.baseUrl.includes("api.anthropic.com");
|
|
@@ -2347,18 +2188,11 @@ async function* runStream(options) {
|
|
|
2347
2188
|
const useServerFallback = options.provider !== "minimax" && isDirectAnthropicApi(options.baseUrl) && !anthropicServerFallback.disabled.has(fallbackKey);
|
|
2348
2189
|
const deferredPlan = options.provider === "anthropic" && isDirectAnthropicApi(options.baseUrl) && supportsAnthropicDeferredTools(options.model) ? planDeferredTools(options.tools, options.deferredTools, downgradedMessages) : void 0;
|
|
2349
2190
|
const toolReferences = deferredPlan?.loaded;
|
|
2350
|
-
const { system
|
|
2191
|
+
const { system, messages } = toAnthropicMessages(downgradedMessages, cacheControl, {
|
|
2351
2192
|
fallbackBlocks: useServerFallback,
|
|
2352
2193
|
toolReferences
|
|
2353
2194
|
});
|
|
2354
2195
|
const useFastMode = options.speed === "fast" && options.provider === "anthropic" && isDirectAnthropicApi(options.baseUrl);
|
|
2355
|
-
const system = isOAuth ? [
|
|
2356
|
-
{
|
|
2357
|
-
type: "text",
|
|
2358
|
-
text: "You are Claude Code, Anthropic's official CLI for Claude."
|
|
2359
|
-
},
|
|
2360
|
-
...rawSystem ?? []
|
|
2361
|
-
] : rawSystem;
|
|
2362
2196
|
let maxTokens = options.maxTokens ?? 4096;
|
|
2363
2197
|
let thinking;
|
|
2364
2198
|
let outputConfig;
|
|
@@ -2434,7 +2268,6 @@ async function* runStream(options) {
|
|
|
2434
2268
|
const params = mergeProviderOptions(baseParams, options.providerOptions);
|
|
2435
2269
|
const hasAdaptiveThinking = isAdaptiveThinkingModel(options.model);
|
|
2436
2270
|
const betaHeaders = [
|
|
2437
|
-
...isOAuth ? ["claude-code-20250219", "oauth-2025-04-20"] : [],
|
|
2438
2271
|
...options.compaction ? ["compact-2026-01-12"] : [],
|
|
2439
2272
|
...options.clearToolUses ? ["context-management-2025-06-27"] : [],
|
|
2440
2273
|
// Eager tool-input streaming beta — opt-in only (see
|
|
@@ -2930,6 +2763,15 @@ function fnv1aHash(value) {
|
|
|
2930
2763
|
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
2931
2764
|
}
|
|
2932
2765
|
|
|
2766
|
+
// src/utils/diag.ts
|
|
2767
|
+
var _diagFn = null;
|
|
2768
|
+
function setProviderDiagnostic(fn) {
|
|
2769
|
+
_diagFn = fn;
|
|
2770
|
+
}
|
|
2771
|
+
function providerDiag(phase, data) {
|
|
2772
|
+
_diagFn?.(phase, data);
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2933
2775
|
// src/providers/moonshot-video.ts
|
|
2934
2776
|
async function uploadMoonshotVideos(client, messages, signal) {
|
|
2935
2777
|
for (const msg of messages) {
|
|
@@ -3173,11 +3015,11 @@ async function* runStream2(options) {
|
|
|
3173
3015
|
}
|
|
3174
3016
|
const requestParams = mergeProviderOptions(params, options.providerOptions);
|
|
3175
3017
|
if (getEnvironment()?.GGAI_DUMP_REQUEST) {
|
|
3176
|
-
const
|
|
3018
|
+
const fs = await import("fs");
|
|
3177
3019
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3178
3020
|
const dumpPath = `/tmp/ggai-request-${ts}.json`;
|
|
3179
|
-
|
|
3180
|
-
|
|
3021
|
+
fs.writeFileSync(dumpPath, JSON.stringify(requestParams, null, 2));
|
|
3022
|
+
fs.appendFileSync(
|
|
3181
3023
|
"/tmp/ggai-requests.log",
|
|
3182
3024
|
`[${ts}] ${dumpPath} messages=${requestParams.messages.length}
|
|
3183
3025
|
`
|
|
@@ -3506,10 +3348,6 @@ function toError2(err, provider = "openai") {
|
|
|
3506
3348
|
return new ProviderError(provider, String(err));
|
|
3507
3349
|
}
|
|
3508
3350
|
|
|
3509
|
-
// src/providers/openai-codex.ts
|
|
3510
|
-
var import_node_os2 = __toESM(require("os"), 1);
|
|
3511
|
-
var zstd = __toESM(require("@bokuweb/zstd-wasm"), 1);
|
|
3512
|
-
|
|
3513
3351
|
// src/utils/sse.ts
|
|
3514
3352
|
function parseSseBuffer(buffer) {
|
|
3515
3353
|
const events = [];
|
|
@@ -3561,6 +3399,9 @@ function extractRequestIdFromMessage(message) {
|
|
|
3561
3399
|
return match?.[1];
|
|
3562
3400
|
}
|
|
3563
3401
|
|
|
3402
|
+
// src/user-agent.ts
|
|
3403
|
+
var GG_CODER_USER_AGENT = "ggcoder (+https://github.com/KenKaiii/gg-coder)";
|
|
3404
|
+
|
|
3564
3405
|
// src/providers/responses-stream.ts
|
|
3565
3406
|
function isEncryptedReasoning(data) {
|
|
3566
3407
|
return data.type === "reasoning" && typeof data.id === "string" && typeof data.encrypted_content === "string";
|
|
@@ -3608,9 +3449,11 @@ async function* consumeResponsesEvents(events, ctx) {
|
|
|
3608
3449
|
});
|
|
3609
3450
|
}
|
|
3610
3451
|
if (type === "response.failed") {
|
|
3611
|
-
const nested = event.error;
|
|
3452
|
+
const nested = event.error ?? event.response?.error;
|
|
3612
3453
|
const message = nested?.message ?? `${ctx.label} response failed.`;
|
|
3613
3454
|
const requestId = extractRequestIdFromMessage(message) ?? event.request_id;
|
|
3455
|
+
const usageLimit = nested ? ctx.errorChunk?.(nested, requestId) : null;
|
|
3456
|
+
if (usageLimit) throw usageLimit;
|
|
3614
3457
|
throw new ProviderError(ctx.provider, message, {
|
|
3615
3458
|
...requestId != null ? { requestId } : {}
|
|
3616
3459
|
});
|
|
@@ -3960,6 +3803,7 @@ function toResponsesInput(messages, options) {
|
|
|
3960
3803
|
...sendItemId ? { id: mapId(itemId ?? callId, idMap) } : {},
|
|
3961
3804
|
call_id: mapId(callId, idMap),
|
|
3962
3805
|
name: part.name,
|
|
3806
|
+
...options.toolNamespace ? { namespace: options.toolNamespace } : {},
|
|
3963
3807
|
arguments: JSON.stringify(part.args)
|
|
3964
3808
|
});
|
|
3965
3809
|
}
|
|
@@ -4023,85 +3867,46 @@ function toResponsesInput(messages, options) {
|
|
|
4023
3867
|
return { system, input };
|
|
4024
3868
|
}
|
|
4025
3869
|
|
|
4026
|
-
// src/providers/openai-
|
|
4027
|
-
var DEFAULT_BASE_URL = "https://
|
|
4028
|
-
var
|
|
4029
|
-
var
|
|
4030
|
-
var zstdInitPromise;
|
|
4031
|
-
async function encodeCodexRequest(body) {
|
|
4032
|
-
const json = JSON.stringify(body);
|
|
4033
|
-
const raw = new TextEncoder().encode(json);
|
|
4034
|
-
if (raw.byteLength < CODEX_REQUEST_COMPRESSION_MIN_BYTES) {
|
|
4035
|
-
return {
|
|
4036
|
-
body: json,
|
|
4037
|
-
compressed: false,
|
|
4038
|
-
rawBytes: raw.byteLength,
|
|
4039
|
-
encodedBytes: raw.byteLength
|
|
4040
|
-
};
|
|
4041
|
-
}
|
|
4042
|
-
try {
|
|
4043
|
-
zstdInitPromise ??= zstd.init();
|
|
4044
|
-
await zstdInitPromise;
|
|
4045
|
-
const compressed = Uint8Array.from(zstd.compress(raw));
|
|
4046
|
-
if (compressed.byteLength >= raw.byteLength) {
|
|
4047
|
-
return {
|
|
4048
|
-
body: json,
|
|
4049
|
-
compressed: false,
|
|
4050
|
-
rawBytes: raw.byteLength,
|
|
4051
|
-
encodedBytes: raw.byteLength
|
|
4052
|
-
};
|
|
4053
|
-
}
|
|
4054
|
-
return {
|
|
4055
|
-
body: compressed,
|
|
4056
|
-
compressed: true,
|
|
4057
|
-
rawBytes: raw.byteLength,
|
|
4058
|
-
encodedBytes: compressed.byteLength
|
|
4059
|
-
};
|
|
4060
|
-
} catch (error) {
|
|
4061
|
-
providerDiag("codex_request_compression_failed", {
|
|
4062
|
-
error: error instanceof Error ? error.message : String(error),
|
|
4063
|
-
rawBytes: raw.byteLength
|
|
4064
|
-
});
|
|
4065
|
-
return {
|
|
4066
|
-
body: json,
|
|
4067
|
-
compressed: false,
|
|
4068
|
-
rawBytes: raw.byteLength,
|
|
4069
|
-
encodedBytes: raw.byteLength
|
|
4070
|
-
};
|
|
4071
|
-
}
|
|
4072
|
-
}
|
|
3870
|
+
// src/providers/openai-responses.ts
|
|
3871
|
+
var DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
3872
|
+
var CHATGPT_PLAN_TOOL_NAMESPACE = "gg";
|
|
3873
|
+
var CHATGPT_USAGE_URL = "https://chatgpt.com/settings/usage";
|
|
4073
3874
|
function usesResponsesLite(model) {
|
|
4074
3875
|
return model.startsWith("gpt-5.6-") || model.startsWith("gpt-6-") || model.startsWith("gpt-6.");
|
|
4075
3876
|
}
|
|
4076
|
-
function
|
|
3877
|
+
function isChatGPTPlanRoute(options) {
|
|
3878
|
+
return Boolean(options.accountId);
|
|
3879
|
+
}
|
|
3880
|
+
function toResponsesToolChoice(choice, tools) {
|
|
4077
3881
|
const resolved = choice ?? "auto";
|
|
4078
3882
|
if (typeof resolved === "object") {
|
|
4079
3883
|
throw new GGAIError(
|
|
4080
|
-
`OpenAI
|
|
3884
|
+
`OpenAI Responses does not support selecting the named tool \`${resolved.name}\`; use auto, none, or required.`,
|
|
4081
3885
|
{ source: "capability" }
|
|
4082
3886
|
);
|
|
4083
3887
|
}
|
|
4084
3888
|
if (resolved === "required" && !tools?.length) {
|
|
4085
|
-
throw new GGAIError("OpenAI
|
|
3889
|
+
throw new GGAIError("OpenAI cannot require a tool call when no tools are configured.", {
|
|
4086
3890
|
source: "capability"
|
|
4087
3891
|
});
|
|
4088
3892
|
}
|
|
4089
3893
|
return resolved;
|
|
4090
3894
|
}
|
|
4091
|
-
function
|
|
3895
|
+
function streamOpenAIResponses(options) {
|
|
4092
3896
|
return new StreamResult(runStream3(options), options.signal);
|
|
4093
3897
|
}
|
|
4094
3898
|
async function* runStream3(options, retriedWithoutReasoning = false) {
|
|
3899
|
+
const plan = isChatGPTPlanRoute(options);
|
|
4095
3900
|
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
4096
|
-
const url = `${baseUrl}/
|
|
3901
|
+
const url = `${baseUrl}/responses`;
|
|
4097
3902
|
const downgradedImages = downgradeUnsupportedImages(options.messages, options.supportsImages);
|
|
4098
3903
|
const downgraded = downgradeUnsupportedVideos(downgradedImages, options.supportsVideo);
|
|
4099
|
-
const deferredPlan = supportsResponsesToolSearch(options.model) ? planDeferredTools(options.tools, options.deferredTools, downgraded) : void 0;
|
|
3904
|
+
const deferredPlan = !plan && supportsResponsesToolSearch(options.model) ? planDeferredTools(options.tools, options.deferredTools, downgraded) : void 0;
|
|
4100
3905
|
const strictTools = options.strictTools ?? true;
|
|
4101
3906
|
const toolSearchLoads = deferredPlan ? new Map(
|
|
4102
3907
|
[...deferredPlan.loaded].map((name) => {
|
|
4103
3908
|
const tool = deferredPlan.byName.get(name);
|
|
4104
|
-
const [wire] = tool ?
|
|
3909
|
+
const [wire] = tool ? toResponsesTools([tool], strictTools) : [];
|
|
4105
3910
|
return [name, { ...wire, defer_loading: true }];
|
|
4106
3911
|
})
|
|
4107
3912
|
) : void 0;
|
|
@@ -4109,28 +3914,36 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
|
|
|
4109
3914
|
const { system, input } = toResponsesInput(downgraded, {
|
|
4110
3915
|
supportsImages: options.supportsImages,
|
|
4111
3916
|
toolSearchLoads,
|
|
4112
|
-
mapId:
|
|
3917
|
+
mapId: remapCallId,
|
|
3918
|
+
...plan ? { toolNamespace: CHATGPT_PLAN_TOOL_NAMESPACE } : {},
|
|
4113
3919
|
// Stamped reasoning belongs to another transport (e.g. Grok's) and would
|
|
4114
|
-
// be rejected here;
|
|
3920
|
+
// be rejected here; OpenAI's own items are never stamped.
|
|
4115
3921
|
keepReasoning: (part) => part.origin === void 0
|
|
4116
3922
|
});
|
|
4117
|
-
const
|
|
4118
|
-
const liteShape = options.responsesLite ?? responsesLite;
|
|
3923
|
+
const gpt6 = usesResponsesLite(options.model);
|
|
4119
3924
|
const body = {
|
|
4120
3925
|
model: options.model,
|
|
4121
3926
|
store: false,
|
|
4122
3927
|
stream: true,
|
|
4123
3928
|
instructions: system,
|
|
4124
3929
|
input,
|
|
4125
|
-
tool_choice:
|
|
4126
|
-
parallel_tool_calls:
|
|
3930
|
+
tool_choice: toResponsesToolChoice(options.toolChoice, liveTools),
|
|
3931
|
+
parallel_tool_calls: true,
|
|
4127
3932
|
include: ["reasoning.encrypted_content"]
|
|
4128
3933
|
};
|
|
4129
3934
|
if (liveTools?.length) {
|
|
4130
|
-
|
|
3935
|
+
const wire = toResponsesTools(liveTools, strictTools);
|
|
3936
|
+
body.tools = plan ? [
|
|
3937
|
+
{
|
|
3938
|
+
type: "namespace",
|
|
3939
|
+
name: CHATGPT_PLAN_TOOL_NAMESPACE,
|
|
3940
|
+
description: "GG Coder's tools for working in the user's project.",
|
|
3941
|
+
tools: wire
|
|
3942
|
+
}
|
|
3943
|
+
] : wire;
|
|
4131
3944
|
}
|
|
4132
3945
|
body.prompt_cache_key = normalizePromptCacheKey(options.promptCacheKey ?? "ggcoder");
|
|
4133
|
-
if (options.temperature != null && !options.thinking) {
|
|
3946
|
+
if (!plan && options.temperature != null && !options.thinking) {
|
|
4134
3947
|
body.temperature = options.temperature;
|
|
4135
3948
|
}
|
|
4136
3949
|
if (options.speed === "fast") {
|
|
@@ -4138,57 +3951,38 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
|
|
|
4138
3951
|
}
|
|
4139
3952
|
body.reasoning = {
|
|
4140
3953
|
// GPT-5.6/6 require at least low; older models still support thinking off.
|
|
4141
|
-
//
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
summary: "auto",
|
|
4145
|
-
...liteShape ? { context: "all_turns" } : {}
|
|
3954
|
+
// `ultra` is a client orchestration preset, not an API effort.
|
|
3955
|
+
effort: options.thinking ? toCodexReasoningEffort(options.thinking, options.model) : gpt6 ? "low" : "none",
|
|
3956
|
+
summary: "auto"
|
|
4146
3957
|
};
|
|
4147
|
-
if (
|
|
3958
|
+
if (gpt6) {
|
|
4148
3959
|
body.text = { verbosity: "low" };
|
|
4149
3960
|
}
|
|
4150
3961
|
const headers = {
|
|
4151
3962
|
"Content-Type": "application/json",
|
|
4152
3963
|
Accept: "text/event-stream",
|
|
4153
3964
|
Authorization: `Bearer ${options.apiKey}`,
|
|
4154
|
-
"
|
|
4155
|
-
originator: responsesLite ? "codex_cli_rs" : "ggcoder",
|
|
4156
|
-
"User-Agent": responsesLite ? `codex_cli_rs/${CODEX_CLIENT_VERSION}` : `ggcoder (${import_node_os2.default.platform()} ${import_node_os2.default.release()}; ${import_node_os2.default.arch()})`,
|
|
4157
|
-
...responsesLite ? { version: CODEX_CLIENT_VERSION } : {},
|
|
4158
|
-
...liteShape ? { "X-OpenAI-Internal-Codex-Responses-Lite": "true" } : {}
|
|
3965
|
+
"User-Agent": GG_CODER_USER_AGENT
|
|
4159
3966
|
};
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
}
|
|
4163
|
-
if (options.transportSessionId) {
|
|
4164
|
-
const transportSessionId = normalizePromptCacheKey(options.transportSessionId);
|
|
4165
|
-
headers["session_id"] = transportSessionId;
|
|
4166
|
-
headers["x-client-request-id"] = transportSessionId;
|
|
4167
|
-
}
|
|
4168
|
-
const encodedRequest = await encodeCodexRequest(
|
|
4169
|
-
mergeProviderOptions(body, options.providerOptions)
|
|
4170
|
-
);
|
|
4171
|
-
if (encodedRequest.compressed) headers["Content-Encoding"] = "zstd";
|
|
4172
|
-
providerDiag("codex_request_body", {
|
|
4173
|
-
rawBytes: encodedRequest.rawBytes,
|
|
4174
|
-
encodedBytes: encodedRequest.encodedBytes,
|
|
4175
|
-
compressed: encodedRequest.compressed
|
|
4176
|
-
});
|
|
3967
|
+
const json = JSON.stringify(mergeProviderOptions(body, options.providerOptions));
|
|
3968
|
+
providerDiag("openai_responses_request_body", { rawBytes: json.length, plan });
|
|
4177
3969
|
const response = await providerFetch(url, {
|
|
4178
3970
|
method: "POST",
|
|
4179
3971
|
headers,
|
|
4180
|
-
body:
|
|
3972
|
+
body: json,
|
|
4181
3973
|
signal: options.signal
|
|
4182
3974
|
});
|
|
4183
3975
|
if (!response.ok) {
|
|
4184
3976
|
const text = await response.text().catch(() => "");
|
|
4185
|
-
const parsed =
|
|
4186
|
-
const message = parsed.message ?? `
|
|
3977
|
+
const parsed = parseErrorBody(text, response.status);
|
|
3978
|
+
const message = parsed.message ?? `OpenAI returned HTTP ${response.status}.`;
|
|
4187
3979
|
const requestId = parsed.requestId ?? readHeader(response.headers, "x-request-id", "openai-request-id", "x-oai-request-id");
|
|
4188
3980
|
if (!retriedWithoutReasoning && !options.signal?.aborted && response.status === 400 && (parsed.errorObj?.code === "invalid_encrypted_content" || /encrypted content.*could not be (?:verified|decrypted|parsed)/i.test(message)) && options.messages.some(
|
|
4189
3981
|
(msg) => msg.role === "assistant" && Array.isArray(msg.content) && msg.content.some((part) => part.type === "raw" && isEncryptedReasoning(part.data))
|
|
4190
3982
|
)) {
|
|
4191
|
-
providerDiag("
|
|
3983
|
+
providerDiag("openai_responses_retry_without_encrypted_reasoning", {
|
|
3984
|
+
status: response.status
|
|
3985
|
+
});
|
|
4192
3986
|
const messages = options.messages.map(
|
|
4193
3987
|
(msg) => msg.role === "assistant" && Array.isArray(msg.content) ? {
|
|
4194
3988
|
...msg,
|
|
@@ -4199,13 +3993,19 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
|
|
|
4199
3993
|
);
|
|
4200
3994
|
return yield* runStream3({ ...options, messages }, true);
|
|
4201
3995
|
}
|
|
4202
|
-
|
|
4203
|
-
|
|
3996
|
+
if (plan) {
|
|
3997
|
+
const planError = chatGPTPlanError(
|
|
3998
|
+
parsed.errorObj,
|
|
3999
|
+
response.status,
|
|
4000
|
+
requestId,
|
|
4001
|
+
message,
|
|
4002
|
+
options.model
|
|
4003
|
+
);
|
|
4004
|
+
if (planError) throw planError;
|
|
4005
|
+
}
|
|
4204
4006
|
let hint;
|
|
4205
|
-
if (response.status ===
|
|
4206
|
-
hint = "This model
|
|
4207
|
-
} else if (response.status === 404 && text.includes("does not exist")) {
|
|
4208
|
-
hint = "This model is not in OpenAI's current catalog for your ChatGPT account. Choose another available model using the model selector.";
|
|
4007
|
+
if (response.status === 404 && text.includes("does not exist")) {
|
|
4008
|
+
hint = plan ? "This model isn't available on your ChatGPT plan. Choose another model using the model selector." : "This model isn't available to your OpenAI API key. Choose another model using the model selector.";
|
|
4209
4009
|
}
|
|
4210
4010
|
throw new ProviderError("openai", message, {
|
|
4211
4011
|
statusCode: response.status,
|
|
@@ -4214,14 +4014,14 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
|
|
|
4214
4014
|
});
|
|
4215
4015
|
}
|
|
4216
4016
|
if (!response.body) {
|
|
4217
|
-
throw new ProviderError("openai", "No response body from
|
|
4017
|
+
throw new ProviderError("openai", "No response body from OpenAI");
|
|
4218
4018
|
}
|
|
4219
4019
|
return yield* consumeResponsesEvents(parseSSE(response.body), {
|
|
4220
4020
|
provider: "openai",
|
|
4221
|
-
label: "
|
|
4222
|
-
diagPrefix: "
|
|
4021
|
+
label: "OpenAI",
|
|
4022
|
+
diagPrefix: "openai_responses",
|
|
4223
4023
|
thinking: !!options.thinking,
|
|
4224
|
-
errorChunk: (errorObj, requestId) =>
|
|
4024
|
+
errorChunk: (errorObj, requestId) => plan ? chatGPTPlanError(errorObj, void 0, requestId, void 0, options.model) : null
|
|
4225
4025
|
});
|
|
4226
4026
|
}
|
|
4227
4027
|
async function* parseSSE(body) {
|
|
@@ -4234,7 +4034,7 @@ async function* parseSSE(body) {
|
|
|
4234
4034
|
}
|
|
4235
4035
|
}
|
|
4236
4036
|
}
|
|
4237
|
-
function
|
|
4037
|
+
function remapCallId(id, idMap) {
|
|
4238
4038
|
const existing = idMap.get(id);
|
|
4239
4039
|
if (existing) return existing;
|
|
4240
4040
|
const withPrefix = id.startsWith("fc_") || id.startsWith("fc-") ? id : `fc_${id.replace(/^toolu_/, "")}`;
|
|
@@ -4248,7 +4048,7 @@ function remapCodexId(id, idMap) {
|
|
|
4248
4048
|
idMap.set(id, mapped);
|
|
4249
4049
|
return mapped;
|
|
4250
4050
|
}
|
|
4251
|
-
function
|
|
4051
|
+
function toResponsesTools(tools, strictTools) {
|
|
4252
4052
|
return tools.map((tool) => {
|
|
4253
4053
|
let parameters = resolveToolSchema(tool);
|
|
4254
4054
|
let strict = null;
|
|
@@ -4269,7 +4069,7 @@ function toCodexTools(tools, strictTools) {
|
|
|
4269
4069
|
};
|
|
4270
4070
|
});
|
|
4271
4071
|
}
|
|
4272
|
-
function
|
|
4072
|
+
function parseErrorBody(text, statusCode) {
|
|
4273
4073
|
if (!text) return {};
|
|
4274
4074
|
try {
|
|
4275
4075
|
const parsed = JSON.parse(text);
|
|
@@ -4293,23 +4093,70 @@ function parseCodexErrorBody(text, statusCode) {
|
|
|
4293
4093
|
return bounded ? { message: bounded } : {};
|
|
4294
4094
|
}
|
|
4295
4095
|
}
|
|
4296
|
-
|
|
4297
|
-
var CODEX_RATE_LIMIT_CODE = /rate_limit_exceeded/i;
|
|
4298
|
-
function codexUsageLimitError(errorObj, statusCode, requestId) {
|
|
4096
|
+
function chatGPTPlanError(errorObj, statusCode, requestId, message, model) {
|
|
4299
4097
|
const code = String(errorObj?.code ?? errorObj?.type ?? "");
|
|
4300
|
-
const
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4098
|
+
const base = { ...requestId ? { requestId } : {}, cause: errorObj };
|
|
4099
|
+
switch (code) {
|
|
4100
|
+
// The plan's usage — or the limit the user set for GG Coder — is spent, or
|
|
4101
|
+
// can't be checked right now. Both stop plan requests; the canonical
|
|
4102
|
+
// "usage limit reached" message lets the session fall back to an API key.
|
|
4103
|
+
case "subscription_sharing_usage_limit_exceeded":
|
|
4104
|
+
case "subscription_sharing_usage_unavailable":
|
|
4105
|
+
return new ProviderError("openai", "ChatGPT usage limit reached", {
|
|
4106
|
+
...base,
|
|
4107
|
+
statusCode: statusCode ?? (code.endsWith("unavailable") ? 503 : 429),
|
|
4108
|
+
hint: code === "subscription_sharing_usage_unavailable" ? "OpenAI couldn't check your ChatGPT plan usage just now. Try again shortly, or add an OpenAI API key to keep going." : `Check or raise what GG Coder may use at ${CHATGPT_USAGE_URL}, or add an OpenAI API key to keep going.`
|
|
4109
|
+
});
|
|
4110
|
+
case "subscription_sharing_user_not_eligible":
|
|
4111
|
+
return new ProviderError(
|
|
4112
|
+
"openai",
|
|
4113
|
+
"ChatGPT plan use isn't available for this account or workspace.",
|
|
4114
|
+
{
|
|
4115
|
+
...base,
|
|
4116
|
+
statusCode: statusCode ?? 403,
|
|
4117
|
+
hint: "Add an OpenAI API key, or ask your workspace admin to allow ChatGPT plan use in other apps."
|
|
4118
|
+
}
|
|
4119
|
+
);
|
|
4120
|
+
// The account's plan doesn't include this model (live: 400 model_not_found,
|
|
4121
|
+
// "…not supported when using Codex with a ChatGPT account").
|
|
4122
|
+
case "model_not_found":
|
|
4123
|
+
return new ProviderError(
|
|
4124
|
+
"openai",
|
|
4125
|
+
`${model ?? "This model"} isn't included in your ChatGPT plan.`,
|
|
4126
|
+
{
|
|
4127
|
+
...base,
|
|
4128
|
+
statusCode: statusCode ?? 400,
|
|
4129
|
+
hint: "Pick a model your plan includes (the model picker marks the others), or use an OpenAI API key for this one."
|
|
4130
|
+
}
|
|
4131
|
+
);
|
|
4132
|
+
case "subscription_sharing_unsupported_capability": {
|
|
4133
|
+
const param = typeof errorObj?.param === "string" ? errorObj.param : void 0;
|
|
4134
|
+
if (param?.includes("service_tier")) {
|
|
4135
|
+
return new ProviderError("openai", "Fast mode isn't included in your ChatGPT plan.", {
|
|
4136
|
+
...base,
|
|
4137
|
+
statusCode: statusCode ?? 400,
|
|
4138
|
+
hint: "Switch to the standard model, or use an OpenAI API key for Fast mode."
|
|
4139
|
+
});
|
|
4140
|
+
}
|
|
4141
|
+
return new ProviderError(
|
|
4142
|
+
"openai",
|
|
4143
|
+
message ?? `The ChatGPT plan route doesn't support ${param ?? "part of this request"}.`,
|
|
4144
|
+
{
|
|
4145
|
+
...base,
|
|
4146
|
+
statusCode: statusCode ?? 400,
|
|
4147
|
+
hint: `${param ? `\`${param}\` isn't` : "Part of this request isn't"} available on the ChatGPT plan. Choose another model, or add an OpenAI API key.`
|
|
4148
|
+
}
|
|
4149
|
+
);
|
|
4150
|
+
}
|
|
4151
|
+
case "subscription_sharing_invalid_user":
|
|
4152
|
+
return new ProviderError("openai", message ?? "ChatGPT couldn't validate your sign-in.", {
|
|
4153
|
+
...base,
|
|
4154
|
+
statusCode: statusCode ?? 401,
|
|
4155
|
+
hint: "Continue with ChatGPT again to reconnect."
|
|
4156
|
+
});
|
|
4157
|
+
default:
|
|
4158
|
+
return null;
|
|
4159
|
+
}
|
|
4313
4160
|
}
|
|
4314
4161
|
|
|
4315
4162
|
// src/providers/xai-responses.ts
|
|
@@ -4443,92 +4290,17 @@ async function* synthesizeResponseEvents(response) {
|
|
|
4443
4290
|
}
|
|
4444
4291
|
|
|
4445
4292
|
// src/providers/gemini.ts
|
|
4446
|
-
var
|
|
4447
|
-
var
|
|
4448
|
-
var
|
|
4449
|
-
var GEMINI_CLI_API_CLIENT = "gemini-cli/0.0.0";
|
|
4450
|
-
var CODE_ASSIST_NON_STREAMING_RETRIES = 3;
|
|
4451
|
-
var CODE_ASSIST_NON_STREAMING_RETRY_DELAY_MS = 1e3;
|
|
4293
|
+
var DEFAULT_BASE_URL2 = "https://generativelanguage.googleapis.com/v1beta";
|
|
4294
|
+
var NON_STREAMING_RETRIES = 3;
|
|
4295
|
+
var NON_STREAMING_RETRY_DELAY_MS = 1e3;
|
|
4452
4296
|
var SYNTHETIC_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
|
|
4453
|
-
var CODE_ASSIST_SUPPORTED_MODELS = /* @__PURE__ */ new Set([
|
|
4454
|
-
"gemini-3-pro-preview",
|
|
4455
|
-
"gemini-3.1-pro-preview",
|
|
4456
|
-
"gemini-3.1-pro-preview-customtools",
|
|
4457
|
-
"gemini-3-flash-preview",
|
|
4458
|
-
"gemini-3.5-flash",
|
|
4459
|
-
"gemini-3-flash",
|
|
4460
|
-
"gemini-3.1-flash-lite",
|
|
4461
|
-
"gemini-3.7-flash",
|
|
4462
|
-
"gemini-3.8-flash",
|
|
4463
|
-
"gemini-3.5-flash-lite",
|
|
4464
|
-
"gemini-2.5-pro",
|
|
4465
|
-
"gemini-2.5-flash",
|
|
4466
|
-
"gemma-4-31b-it",
|
|
4467
|
-
"gemma-4-26b-a4b-it"
|
|
4468
|
-
]);
|
|
4469
|
-
function isGeminiApiKeyRoute(options) {
|
|
4470
|
-
return options.baseUrl?.includes("generativelanguage.googleapis.com") === true;
|
|
4471
|
-
}
|
|
4472
|
-
function getGoogleProject(options) {
|
|
4473
|
-
const env = getEnvironment();
|
|
4474
|
-
return options.projectId ?? env?.GOOGLE_CLOUD_PROJECT ?? env?.GOOGLE_CLOUD_PROJECT_ID;
|
|
4475
|
-
}
|
|
4476
|
-
function getCodeAssistEndpoint(method) {
|
|
4477
|
-
const env = getEnvironment();
|
|
4478
|
-
const endpoint = env?.CODE_ASSIST_ENDPOINT ?? DEFAULT_CODE_ASSIST_BASE_URL;
|
|
4479
|
-
const version = env?.CODE_ASSIST_API_VERSION || CODE_ASSIST_API_VERSION;
|
|
4480
|
-
return new URL(`${endpoint}/${version}:${method}`);
|
|
4481
|
-
}
|
|
4482
|
-
function formatUnsupportedModelMessage(model) {
|
|
4483
|
-
return `Gemini OAuth is configured to use the Gemini Code Assist subscription endpoint only. That endpoint does not currently expose model "${model}".`;
|
|
4484
|
-
}
|
|
4485
|
-
var ACCOUNT_GATED_MODELS = /* @__PURE__ */ new Set([
|
|
4486
|
-
"gemini-3-flash",
|
|
4487
|
-
"gemini-3.5-flash",
|
|
4488
|
-
"gemini-3.1-pro-preview",
|
|
4489
|
-
"gemini-3.1-pro-preview-customtools",
|
|
4490
|
-
"gemini-3.7-flash",
|
|
4491
|
-
"gemini-3.8-flash",
|
|
4492
|
-
"gemini-3.5-flash-lite"
|
|
4493
|
-
]);
|
|
4494
|
-
function accountGatedMessage(model) {
|
|
4495
|
-
if (model === "gemini-3.8-flash" || model === "gemini-3.5-flash-lite") {
|
|
4496
|
-
return `${model} is not available through Code Assist for this account. Public Gemini API availability does not guarantee Code Assist OAuth access.`;
|
|
4497
|
-
}
|
|
4498
|
-
return `Your Google account isn't entitled to "${model}" over Gemini Code Assist OAuth, so the API reports it as not found. This is an account-access limit, not a ggcoder bug.`;
|
|
4499
|
-
}
|
|
4500
|
-
function accountGatedHint(model) {
|
|
4501
|
-
if (model === "gemini-3.8-flash" || model === "gemini-3.5-flash-lite") {
|
|
4502
|
-
return "Use /model to select Gemini 3.1 Flash Lite, or retry once Google enables this model through Code Assist for your account.";
|
|
4503
|
-
}
|
|
4504
|
-
return `Newer Gemini models (3.5 Flash, 3.1 Pro Preview) are available only to Code Assist Standard/Enterprise accounts with preview/GA access enabled by a cloud admin. Try Gemini 3.1 Flash Lite with /model, or sign in with a Code Assist Standard/Enterprise account that has preview access.`;
|
|
4505
|
-
}
|
|
4506
|
-
function isCodeAssistLicenseRequired(status, body) {
|
|
4507
|
-
if (status !== 403) return false;
|
|
4508
|
-
try {
|
|
4509
|
-
const parsed = JSON.parse(body);
|
|
4510
|
-
const details = typeof parsed === "object" && parsed !== null && "error" in parsed ? parsed.error?.details : void 0;
|
|
4511
|
-
return Array.isArray(details) && details.some(
|
|
4512
|
-
(detail) => typeof detail === "object" && detail !== null && detail.reason === "SUBSCRIPTION_REQUIRED"
|
|
4513
|
-
);
|
|
4514
|
-
} catch {
|
|
4515
|
-
return false;
|
|
4516
|
-
}
|
|
4517
|
-
}
|
|
4518
4297
|
function isInvalidGeminiApiKey(status, body) {
|
|
4519
4298
|
if (status !== 400 && status !== 401 && status !== 403) return false;
|
|
4520
4299
|
return /"reason"\s*:\s*"API_KEY_INVALID"/.test(body) || /API key not valid/i.test(body);
|
|
4521
4300
|
}
|
|
4522
4301
|
var INVALID_API_KEY_MESSAGE = "Google rejected the Gemini API key: it is not valid.";
|
|
4523
4302
|
var INVALID_API_KEY_HINT = "Create a key at aistudio.google.com/apikey and add it again under Gemini in Providers (or `ggcoder login`).";
|
|
4524
|
-
|
|
4525
|
-
var LICENSE_REQUIRED_HINT = "Sign in to Gemini with a Google account that has a Gemini Code Assist Standard or Enterprise licence, or pick a model from another provider with /model.";
|
|
4526
|
-
function formatErrorMessage(status, body, model) {
|
|
4527
|
-
if (status === 404 && !CODE_ASSIST_SUPPORTED_MODELS.has(model)) {
|
|
4528
|
-
return `Gemini API error (404): ${body}
|
|
4529
|
-
|
|
4530
|
-
${formatUnsupportedModelMessage(model)}`;
|
|
4531
|
-
}
|
|
4303
|
+
function formatErrorMessage(status, body) {
|
|
4532
4304
|
return `Gemini API error (${status}): ${body}`;
|
|
4533
4305
|
}
|
|
4534
4306
|
function parseRetryDelaySeconds(body) {
|
|
@@ -4734,27 +4506,15 @@ function buildGenerateRequest(options) {
|
|
|
4734
4506
|
...systemInstruction ? { systemInstruction } : {},
|
|
4735
4507
|
...tools ? { tools } : {},
|
|
4736
4508
|
...toolConfig ? { toolConfig } : {},
|
|
4737
|
-
...Object.keys(generationConfig).length > 0 ? { generationConfig } : {}
|
|
4738
|
-
...options.promptCacheKey ? { session_id: options.promptCacheKey } : {}
|
|
4739
|
-
};
|
|
4740
|
-
}
|
|
4741
|
-
function buildCodeAssistRequest(options, request, projectId) {
|
|
4742
|
-
return {
|
|
4743
|
-
model: options.model,
|
|
4744
|
-
...projectId ? { project: projectId } : {},
|
|
4745
|
-
user_prompt_id: crypto.randomUUID(),
|
|
4746
|
-
request
|
|
4509
|
+
...Object.keys(generationConfig).length > 0 ? { generationConfig } : {}
|
|
4747
4510
|
};
|
|
4748
4511
|
}
|
|
4749
4512
|
var API_KEY_MODEL_IDS = {
|
|
4750
4513
|
"gemini-3-flash": "gemini-3.5-flash"
|
|
4751
4514
|
};
|
|
4752
|
-
function
|
|
4753
|
-
const
|
|
4754
|
-
|
|
4755
|
-
options.providerOptions
|
|
4756
|
-
);
|
|
4757
|
-
const base = (options.baseUrl ?? "").replace(/\/+$/, "");
|
|
4515
|
+
function buildRequestPlan(options, method) {
|
|
4516
|
+
const request = mergeProviderOptions(buildGenerateRequest(options), options.providerOptions);
|
|
4517
|
+
const base = (options.baseUrl ?? DEFAULT_BASE_URL2).replace(/\/+$/, "");
|
|
4758
4518
|
return {
|
|
4759
4519
|
url: new URL(
|
|
4760
4520
|
`${base}/models/${encodeURIComponent(API_KEY_MODEL_IDS[options.model] ?? options.model)}:${method}`
|
|
@@ -4763,27 +4523,7 @@ function buildApiKeyRequestPlan(options, method) {
|
|
|
4763
4523
|
"Content-Type": "application/json",
|
|
4764
4524
|
"x-goog-api-key": options.apiKey ?? ""
|
|
4765
4525
|
},
|
|
4766
|
-
body: request
|
|
4767
|
-
route: "api-key"
|
|
4768
|
-
};
|
|
4769
|
-
}
|
|
4770
|
-
function buildRequestPlan(options, method) {
|
|
4771
|
-
if (isGeminiApiKeyRoute(options)) return buildApiKeyRequestPlan(options, method);
|
|
4772
|
-
if (!CODE_ASSIST_SUPPORTED_MODELS.has(options.model)) {
|
|
4773
|
-
throw new ProviderError("gemini", formatUnsupportedModelMessage(options.model));
|
|
4774
|
-
}
|
|
4775
|
-
const projectId = getGoogleProject(options);
|
|
4776
|
-
const request = mergeProviderOptions(buildGenerateRequest(options), options.providerOptions);
|
|
4777
|
-
return {
|
|
4778
|
-
url: getCodeAssistEndpoint(method),
|
|
4779
|
-
headers: {
|
|
4780
|
-
Authorization: `Bearer ${options.apiKey}`,
|
|
4781
|
-
"Content-Type": "application/json",
|
|
4782
|
-
"User-Agent": GEMINI_CLI_USER_AGENT,
|
|
4783
|
-
"X-Goog-Api-Client": GEMINI_CLI_API_CLIENT
|
|
4784
|
-
},
|
|
4785
|
-
body: buildCodeAssistRequest(options, request, projectId),
|
|
4786
|
-
route: "code-assist"
|
|
4526
|
+
body: request
|
|
4787
4527
|
};
|
|
4788
4528
|
}
|
|
4789
4529
|
function normalizeGeminiStopReason(reason) {
|
|
@@ -4810,10 +4550,10 @@ async function* streamSse(response) {
|
|
|
4810
4550
|
}
|
|
4811
4551
|
}
|
|
4812
4552
|
function candidatesFromResponse(response) {
|
|
4813
|
-
return response.
|
|
4553
|
+
return response.candidates;
|
|
4814
4554
|
}
|
|
4815
4555
|
function usageFromResponse(response) {
|
|
4816
|
-
return response.
|
|
4556
|
+
return response.usageMetadata;
|
|
4817
4557
|
}
|
|
4818
4558
|
function partsFromResponse(response) {
|
|
4819
4559
|
return candidatesFromResponse(response)?.[0]?.content?.parts ?? [];
|
|
@@ -4835,7 +4575,7 @@ function readFunctionCallPart(part) {
|
|
|
4835
4575
|
function makeToolCallId(index, providerId) {
|
|
4836
4576
|
return providerId ?? `gemini_call_${index}_${crypto.randomUUID().replace(/-/g, "")}`;
|
|
4837
4577
|
}
|
|
4838
|
-
function
|
|
4578
|
+
function shouldRetryStatus(status) {
|
|
4839
4579
|
return status === 429 || status === 499 || status >= 500 && status <= 599;
|
|
4840
4580
|
}
|
|
4841
4581
|
function isAbortError(err) {
|
|
@@ -4858,7 +4598,7 @@ async function sleep(ms, signal) {
|
|
|
4858
4598
|
if (signal?.aborted) onAbort();
|
|
4859
4599
|
});
|
|
4860
4600
|
}
|
|
4861
|
-
async function
|
|
4601
|
+
async function fetchGemini(plan, options) {
|
|
4862
4602
|
try {
|
|
4863
4603
|
const response = await providerFetch(plan.url, {
|
|
4864
4604
|
method: "POST",
|
|
@@ -4869,11 +4609,8 @@ async function fetchCodeAssist(plan, options) {
|
|
|
4869
4609
|
if (!response.ok) {
|
|
4870
4610
|
const text = await response.text().catch(() => "");
|
|
4871
4611
|
const quota = parseGeminiQuota(response.status, text);
|
|
4872
|
-
const
|
|
4873
|
-
|
|
4874
|
-
const licenseRequired = codeAssist && isCodeAssistLicenseRequired(response.status, text);
|
|
4875
|
-
const invalidKey = !codeAssist && isInvalidGeminiApiKey(response.status, text);
|
|
4876
|
-
let message = invalidKey ? INVALID_API_KEY_MESSAGE : licenseRequired ? LICENSE_REQUIRED_MESSAGE : accountGated ? accountGatedMessage(options.model) : formatErrorMessage(response.status, text, options.model);
|
|
4612
|
+
const invalidKey = isInvalidGeminiApiKey(response.status, text);
|
|
4613
|
+
let message = invalidKey ? INVALID_API_KEY_MESSAGE : formatErrorMessage(response.status, text);
|
|
4877
4614
|
let resetsAt;
|
|
4878
4615
|
if (quota?.exhausted) {
|
|
4879
4616
|
message = `Gemini quota exhausted \u2014 usage limit reached. ${message}`;
|
|
@@ -4883,7 +4620,7 @@ async function fetchCodeAssist(plan, options) {
|
|
|
4883
4620
|
throw new ProviderError("gemini", message, {
|
|
4884
4621
|
statusCode: response.status,
|
|
4885
4622
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
4886
|
-
...invalidKey ? { hint: INVALID_API_KEY_HINT, source: "auth" } :
|
|
4623
|
+
...invalidKey ? { hint: INVALID_API_KEY_HINT, source: "auth" } : {}
|
|
4887
4624
|
});
|
|
4888
4625
|
}
|
|
4889
4626
|
return response;
|
|
@@ -4891,26 +4628,26 @@ async function fetchCodeAssist(plan, options) {
|
|
|
4891
4628
|
throw toError3(err);
|
|
4892
4629
|
}
|
|
4893
4630
|
}
|
|
4894
|
-
async function
|
|
4631
|
+
async function fetchGeminiWithRetry(plan, options) {
|
|
4895
4632
|
let lastError;
|
|
4896
|
-
for (let attempt = 0; attempt <=
|
|
4633
|
+
for (let attempt = 0; attempt <= NON_STREAMING_RETRIES; attempt++) {
|
|
4897
4634
|
try {
|
|
4898
|
-
return await
|
|
4635
|
+
return await fetchGemini(plan, options);
|
|
4899
4636
|
} catch (err) {
|
|
4900
4637
|
const error = toError3(err);
|
|
4901
4638
|
const statusCode = error instanceof ProviderError ? error.statusCode : void 0;
|
|
4902
|
-
if (options.signal?.aborted || isAbortError(error) || attempt ===
|
|
4639
|
+
if (options.signal?.aborted || isAbortError(error) || attempt === NON_STREAMING_RETRIES || statusCode != null && !shouldRetryStatus(statusCode)) {
|
|
4903
4640
|
throw error;
|
|
4904
4641
|
}
|
|
4905
4642
|
lastError = error;
|
|
4906
4643
|
}
|
|
4907
4644
|
try {
|
|
4908
|
-
await sleep(
|
|
4645
|
+
await sleep(NON_STREAMING_RETRY_DELAY_MS, options.signal);
|
|
4909
4646
|
} catch (err) {
|
|
4910
4647
|
throw toError3(err);
|
|
4911
4648
|
}
|
|
4912
4649
|
}
|
|
4913
|
-
throw lastError ?? new ProviderError("gemini", "Gemini
|
|
4650
|
+
throw lastError ?? new ProviderError("gemini", "Gemini request failed.");
|
|
4914
4651
|
}
|
|
4915
4652
|
function streamGemini(options) {
|
|
4916
4653
|
return new StreamResult(runStream5(options), options.signal);
|
|
@@ -4920,7 +4657,7 @@ async function* runStream5(options) {
|
|
|
4920
4657
|
const method = useStreaming ? "streamGenerateContent" : "generateContent";
|
|
4921
4658
|
const plan = buildRequestPlan(options, method);
|
|
4922
4659
|
if (useStreaming) plan.url.searchParams.set("alt", "sse");
|
|
4923
|
-
const response = useStreaming ? await
|
|
4660
|
+
const response = useStreaming ? await fetchGemini(plan, options) : await fetchGeminiWithRetry(plan, options);
|
|
4924
4661
|
const contentParts = [];
|
|
4925
4662
|
const pendingToolCalls = [];
|
|
4926
4663
|
let textAccum = "";
|
|
@@ -5231,7 +4968,7 @@ async function postJson(request) {
|
|
|
5231
4968
|
}
|
|
5232
4969
|
function httpError(provider, response, text, headerRequestId, clean) {
|
|
5233
4970
|
const status = response.status;
|
|
5234
|
-
const parsed =
|
|
4971
|
+
const parsed = parseErrorBody2(text);
|
|
5235
4972
|
const rawMessage = parsed.message ?? (parsed.isJson ? "" : text.trim());
|
|
5236
4973
|
const message = !rawMessage ? emptyProviderErrorMessage(status) : isRawHtmlErrorEcho(rawMessage) ? providerHtmlErrorMessage(status) : clean(rawMessage);
|
|
5237
4974
|
const requestId = headerRequestId ?? parsed.requestId;
|
|
@@ -5257,7 +4994,7 @@ function httpError(provider, response, text, headerRequestId, clean) {
|
|
|
5257
4994
|
}
|
|
5258
4995
|
return new ProviderError(provider, message, base);
|
|
5259
4996
|
}
|
|
5260
|
-
function
|
|
4997
|
+
function parseErrorBody2(text) {
|
|
5261
4998
|
let parsed;
|
|
5262
4999
|
try {
|
|
5263
5000
|
parsed = JSON.parse(text);
|
|
@@ -5293,8 +5030,8 @@ function bound(text) {
|
|
|
5293
5030
|
const trimmed = text.trim();
|
|
5294
5031
|
return trimmed.length > MAX_ERROR_MESSAGE_CHARS ? `${trimmed.slice(0, MAX_ERROR_MESSAGE_CHARS)}\u2026` : trimmed;
|
|
5295
5032
|
}
|
|
5296
|
-
function joinUrl(baseUrl,
|
|
5297
|
-
return `${baseUrl.replace(/\/+$/, "")}/${
|
|
5033
|
+
function joinUrl(baseUrl, path) {
|
|
5034
|
+
return `${baseUrl.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
|
|
5298
5035
|
}
|
|
5299
5036
|
|
|
5300
5037
|
// src/providers/gemini-embeddings.ts
|
|
@@ -5689,10 +5426,7 @@ var OPENAI_EMBED_BATCH_SIZE = 2048;
|
|
|
5689
5426
|
var OPENROUTER_EMBED_BATCH_SIZE = 64;
|
|
5690
5427
|
var LOCAL_EMBED_BATCH_SIZE = 64;
|
|
5691
5428
|
var OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
|
5692
|
-
var
|
|
5693
|
-
var KIMI_CODE_USER_AGENT = `kimi-code-cli/${process.env.KIMI_CODE_VERSION ?? "1.0.11"}`;
|
|
5694
|
-
var GROK_CLI_PROXY_HOST = "cli-chat-proxy.grok.com";
|
|
5695
|
-
var GROK_CLI_VERSION = process.env.GROK_CLI_VERSION ?? "1.0.67";
|
|
5429
|
+
var GLM_BASE_URL = "https://api.z.ai/api/paas/v4";
|
|
5696
5430
|
providerRegistry.register("anthropic", {
|
|
5697
5431
|
stream: (options) => streamAnthropic(options)
|
|
5698
5432
|
});
|
|
@@ -5705,12 +5439,12 @@ providerRegistry.register("xiaomi", {
|
|
|
5705
5439
|
});
|
|
5706
5440
|
providerRegistry.register("openai", {
|
|
5707
5441
|
stream: (options) => {
|
|
5708
|
-
if (options.accountId) {
|
|
5709
|
-
return
|
|
5442
|
+
if (options.accountId || isOpenAIHost(options.baseUrl)) {
|
|
5443
|
+
return streamOpenAIResponses(options);
|
|
5710
5444
|
}
|
|
5711
5445
|
return streamOpenAI(options);
|
|
5712
5446
|
},
|
|
5713
|
-
// OpenAI API-key auth only; ChatGPT
|
|
5447
|
+
// OpenAI API-key auth only; the ChatGPT plan route has no embeddings API.
|
|
5714
5448
|
// OpenAI has no task/input-type parameter, so `inputType` is ignored.
|
|
5715
5449
|
embed: (request) => embedOpenAICompatible(request, {
|
|
5716
5450
|
provider: "openai",
|
|
@@ -5720,22 +5454,24 @@ providerRegistry.register("openai", {
|
|
|
5720
5454
|
});
|
|
5721
5455
|
providerRegistry.register("gemini", {
|
|
5722
5456
|
stream: (options) => streamGemini(options),
|
|
5723
|
-
// Native Gemini API with an AI Studio key
|
|
5457
|
+
// Native Gemini API with an AI Studio key.
|
|
5724
5458
|
embed: (request) => embedGemini(request),
|
|
5725
5459
|
embedBatchSize: GEMINI_EMBED_BATCH_SIZE
|
|
5726
5460
|
});
|
|
5727
5461
|
providerRegistry.register("glm", {
|
|
5728
5462
|
stream: (options) => streamOpenAI({
|
|
5729
5463
|
...options,
|
|
5730
|
-
baseUrl: options.baseUrl ??
|
|
5464
|
+
baseUrl: options.baseUrl ?? GLM_BASE_URL
|
|
5731
5465
|
})
|
|
5732
5466
|
});
|
|
5733
5467
|
providerRegistry.register("moonshot", {
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5468
|
+
// A Moonshot key goes to the public API; a Kimi Code plan key carries its
|
|
5469
|
+
// own baseUrl (api.kimi.com / api.kimi.ai). Both get GG Coder's own identity.
|
|
5470
|
+
stream: (options) => streamOpenAI({
|
|
5471
|
+
...options,
|
|
5472
|
+
baseUrl: options.baseUrl ?? "https://api.moonshot.ai/v1",
|
|
5473
|
+
defaultHeaders: { "User-Agent": GG_CODER_USER_AGENT, ...options.defaultHeaders }
|
|
5474
|
+
})
|
|
5739
5475
|
});
|
|
5740
5476
|
providerRegistry.register("deepseek", {
|
|
5741
5477
|
stream: (options) => streamOpenAI({
|
|
@@ -5784,27 +5520,10 @@ providerRegistry.register("sakana", {
|
|
|
5784
5520
|
})
|
|
5785
5521
|
});
|
|
5786
5522
|
providerRegistry.register("xai", {
|
|
5787
|
-
//
|
|
5788
|
-
//
|
|
5789
|
-
//
|
|
5790
|
-
|
|
5791
|
-
// Subscription OAuth (SuperGrok / X Premium) routes to the Grok CLI chat proxy
|
|
5792
|
-
// instead, which serves the same `/v1/responses` surface but gates on Grok-CLI
|
|
5793
|
-
// client identity. Inject those headers centrally here — exactly as the Kimi
|
|
5794
|
-
// endpoint above — so EVERY stream (agent loop, compaction, title-gen,
|
|
5795
|
-
// sub-agents) is accepted rather than depending on each call site to thread
|
|
5796
|
-
// headers. Caller-provided headers still win on collision.
|
|
5797
|
-
stream: (options) => {
|
|
5798
|
-
const baseUrl = options.baseUrl ?? "https://api.x.ai/v1";
|
|
5799
|
-
const defaultHeaders = baseUrl.includes(GROK_CLI_PROXY_HOST) ? {
|
|
5800
|
-
"X-XAI-Token-Auth": "xai-grok-cli",
|
|
5801
|
-
"x-grok-client-version": GROK_CLI_VERSION,
|
|
5802
|
-
"x-grok-client-identifier": "ggcoder",
|
|
5803
|
-
"x-grok-model-override": options.model,
|
|
5804
|
-
...options.defaultHeaders
|
|
5805
|
-
} : options.defaultHeaders;
|
|
5806
|
-
return streamXaiResponses({ ...options, baseUrl, defaultHeaders });
|
|
5807
|
-
}
|
|
5523
|
+
// xAI API key on xAI's Responses API (see providers/xai-responses.ts): Chat
|
|
5524
|
+
// Completions is deprecated for Grok reasoning models and can't carry the
|
|
5525
|
+
// encrypted reasoning that keeps long tool loops coherent.
|
|
5526
|
+
stream: (options) => streamXaiResponses({ ...options, baseUrl: options.baseUrl ?? "https://api.x.ai/v1" })
|
|
5808
5527
|
});
|
|
5809
5528
|
providerRegistry.register("minimax", {
|
|
5810
5529
|
stream: (options) => streamAnthropic({
|
|
@@ -5855,6 +5574,14 @@ providerRegistry.register("local", {
|
|
|
5855
5574
|
}
|
|
5856
5575
|
)
|
|
5857
5576
|
});
|
|
5577
|
+
function isOpenAIHost(baseUrl) {
|
|
5578
|
+
if (!baseUrl) return true;
|
|
5579
|
+
try {
|
|
5580
|
+
return new URL(baseUrl).hostname === "api.openai.com";
|
|
5581
|
+
} catch {
|
|
5582
|
+
return false;
|
|
5583
|
+
}
|
|
5584
|
+
}
|
|
5858
5585
|
function requireLocalBaseUrl(baseUrl) {
|
|
5859
5586
|
if (!baseUrl) {
|
|
5860
5587
|
throw new GGAIError(
|
|
@@ -6045,16 +5772,16 @@ function l2Normalize(vector) {
|
|
|
6045
5772
|
|
|
6046
5773
|
// src/utils/preconnect.ts
|
|
6047
5774
|
var PRECONNECT_INTERVAL_MS = 3e4;
|
|
6048
|
-
function defaultBaseUrl(provider
|
|
5775
|
+
function defaultBaseUrl(provider) {
|
|
6049
5776
|
switch (provider) {
|
|
6050
5777
|
case "anthropic":
|
|
6051
5778
|
return "https://api.anthropic.com";
|
|
6052
5779
|
case "openai":
|
|
6053
|
-
return
|
|
5780
|
+
return "https://api.openai.com/v1";
|
|
6054
5781
|
case "gemini":
|
|
6055
|
-
return "https://
|
|
5782
|
+
return "https://generativelanguage.googleapis.com/v1beta";
|
|
6056
5783
|
case "glm":
|
|
6057
|
-
return "https://api.z.ai/api/
|
|
5784
|
+
return "https://api.z.ai/api/paas/v4";
|
|
6058
5785
|
case "moonshot":
|
|
6059
5786
|
return "https://api.moonshot.ai/v1";
|
|
6060
5787
|
case "deepseek":
|
|
@@ -6087,7 +5814,7 @@ function isLocalHost(hostname) {
|
|
|
6087
5814
|
return a === 127 || a === 10 || a === 192 && b === 168 || a === 172 && b >= 16 && b <= 31;
|
|
6088
5815
|
}
|
|
6089
5816
|
function preconnectTarget(options) {
|
|
6090
|
-
const raw = options.baseUrl ?? defaultBaseUrl(options.provider
|
|
5817
|
+
const raw = options.baseUrl ?? defaultBaseUrl(options.provider);
|
|
6091
5818
|
if (!raw || options.provider === "local" || options.provider === "palsu") return void 0;
|
|
6092
5819
|
let url;
|
|
6093
5820
|
try {
|
|
@@ -6602,11 +6329,10 @@ function palsuRerankScore(query, document) {
|
|
|
6602
6329
|
}
|
|
6603
6330
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6604
6331
|
0 && (module.exports = {
|
|
6605
|
-
CLAUDE_CODE_FALLBACK_VERSION,
|
|
6606
|
-
CODEX_CLIENT_VERSION,
|
|
6607
6332
|
EventStream,
|
|
6608
6333
|
FAST_MODE_SUFFIX,
|
|
6609
6334
|
GGAIError,
|
|
6335
|
+
GG_CODER_USER_AGENT,
|
|
6610
6336
|
LOCAL_NO_API_KEY,
|
|
6611
6337
|
PRECONNECT_INTERVAL_MS,
|
|
6612
6338
|
ProviderError,
|
|
@@ -6624,8 +6350,6 @@ function palsuRerankScore(query, document) {
|
|
|
6624
6350
|
formatChatError,
|
|
6625
6351
|
formatError,
|
|
6626
6352
|
formatErrorForDisplay,
|
|
6627
|
-
getClaudeCliUserAgent,
|
|
6628
|
-
getClaudeCodeVersion,
|
|
6629
6353
|
hasLoneSurrogate,
|
|
6630
6354
|
isHardBillingMessage,
|
|
6631
6355
|
isUsageLimitError,
|
|
@@ -6640,7 +6364,6 @@ function palsuRerankScore(query, document) {
|
|
|
6640
6364
|
palsuThinking,
|
|
6641
6365
|
palsuToolCall,
|
|
6642
6366
|
parseFastModeRejection,
|
|
6643
|
-
pendingClaudeCodeVersionRefresh,
|
|
6644
6367
|
preconnectOrigin,
|
|
6645
6368
|
preconnectProvider,
|
|
6646
6369
|
prewarmAnthropicCache,
|