@kenkaiiii/gg-ai 5.87.3 → 5.88.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/dist/index.cjs +302 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -1
- package/dist/index.d.ts +49 -1
- package/dist/index.js +299 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -399,6 +399,26 @@ function providerGuidance(provider, message, statusCode) {
|
|
|
399
399
|
// src/providers/anthropic.ts
|
|
400
400
|
import Anthropic from "@anthropic-ai/sdk";
|
|
401
401
|
|
|
402
|
+
// src/providers/cache-minimums.ts
|
|
403
|
+
var ANTHROPIC_MIN_CACHEABLE_TOKENS = [
|
|
404
|
+
[/haiku-4-5|opus-4-[56]/, 4096],
|
|
405
|
+
[/haiku-3-5|haiku-3\b/, 2048],
|
|
406
|
+
[/[a-z]-(?:[5-9]|\d{2})(?:-|$)/, 512],
|
|
407
|
+
// 5.x and later families (family name, then major)
|
|
408
|
+
[/sonnet-4|opus-4|sonnet-3-7/, 1024]
|
|
409
|
+
];
|
|
410
|
+
function anthropicMinCacheableTokens(model) {
|
|
411
|
+
for (const [pattern, min] of ANTHROPIC_MIN_CACHEABLE_TOKENS) {
|
|
412
|
+
if (pattern.test(model)) return min;
|
|
413
|
+
}
|
|
414
|
+
return 1024;
|
|
415
|
+
}
|
|
416
|
+
function estimatePrefixTokens(...parts) {
|
|
417
|
+
let chars = 0;
|
|
418
|
+
for (const part of parts) if (part !== void 0) chars += JSON.stringify(part).length;
|
|
419
|
+
return Math.ceil(chars / 3.5);
|
|
420
|
+
}
|
|
421
|
+
|
|
402
422
|
// src/utils/event-stream.ts
|
|
403
423
|
var EventStream = class {
|
|
404
424
|
queue = [];
|
|
@@ -1396,6 +1416,41 @@ function toolResultVideos(content) {
|
|
|
1396
1416
|
if (typeof content === "string") return [];
|
|
1397
1417
|
return content.filter((b) => b.type === "video");
|
|
1398
1418
|
}
|
|
1419
|
+
function planDeferredTools(tools, catalog, messages) {
|
|
1420
|
+
if (!catalog?.length) return void 0;
|
|
1421
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1422
|
+
for (const tool of catalog) if (!byName.has(tool.name)) byName.set(tool.name, tool);
|
|
1423
|
+
const loaded = /* @__PURE__ */ new Set();
|
|
1424
|
+
for (const message of messages) {
|
|
1425
|
+
if (message.role !== "tool") continue;
|
|
1426
|
+
for (const result of message.content) {
|
|
1427
|
+
for (const name of result.loadedTools ?? []) if (byName.has(name)) loaded.add(name);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
const live = (tools ?? []).filter((tool) => !(byName.has(tool.name) && loaded.has(tool.name)));
|
|
1431
|
+
if (live.length === 0) return void 0;
|
|
1432
|
+
const liveNames = new Set(live.map((tool) => tool.name));
|
|
1433
|
+
const deferred = [...byName.values()].filter((tool) => !liveNames.has(tool.name));
|
|
1434
|
+
return { live, deferred, loaded, byName };
|
|
1435
|
+
}
|
|
1436
|
+
function supportsAnthropicDeferredTools(model) {
|
|
1437
|
+
return /opus-4[-.][5-9]|sonnet-4[-.][5-9]|haiku-4[-.]5|opus-5|sonnet-5|haiku-5|fable-5|mythos-5/.test(
|
|
1438
|
+
model
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
function supportsResponsesToolSearch(model) {
|
|
1442
|
+
return /^gpt-(5\.[4-9]|[6-9])/.test(model);
|
|
1443
|
+
}
|
|
1444
|
+
function usesDeferredToolLoading(options) {
|
|
1445
|
+
if (options.provider === "anthropic") {
|
|
1446
|
+
const firstParty = !options.baseUrl || options.baseUrl.includes("api.anthropic.com");
|
|
1447
|
+
return firstParty && supportsAnthropicDeferredTools(options.model);
|
|
1448
|
+
}
|
|
1449
|
+
if (options.provider === "openai" && options.accountId) {
|
|
1450
|
+
return supportsResponsesToolSearch(options.model);
|
|
1451
|
+
}
|
|
1452
|
+
return false;
|
|
1453
|
+
}
|
|
1399
1454
|
function toAnthropicCacheControl(retention, baseUrl) {
|
|
1400
1455
|
const resolved = retention ?? "short";
|
|
1401
1456
|
if (resolved === "none") return void 0;
|
|
@@ -1438,6 +1493,8 @@ function toAnthropicMessages(messages, cacheControl, options) {
|
|
|
1438
1493
|
const keepFallbackBlocks = options?.fallbackBlocks === true;
|
|
1439
1494
|
const droppedToolCallIds = /* @__PURE__ */ new Set();
|
|
1440
1495
|
const unresolvedServerToolIds = unresolvedServerToolUseIds(messages);
|
|
1496
|
+
const toolReferences = options?.toolReferences;
|
|
1497
|
+
const referencedTools = /* @__PURE__ */ new Set();
|
|
1441
1498
|
const trajectoryStartIdx = messages.reduce(
|
|
1442
1499
|
(last, m, i) => opensTurn(m) ? i : last,
|
|
1443
1500
|
-1
|
|
@@ -1500,16 +1557,43 @@ function toAnthropicMessages(messages, cacheControl, options) {
|
|
|
1500
1557
|
if (msg.role === "tool") {
|
|
1501
1558
|
const results = droppedToolCallIds.size ? msg.content.filter((r) => !droppedToolCallIds.has(r.toolCallId)) : msg.content;
|
|
1502
1559
|
if (results.length === 0) continue;
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1560
|
+
const trailing = [];
|
|
1561
|
+
const blocks = results.map((result) => {
|
|
1562
|
+
const toolUseId = remapAnthropicToolCallId(result.toolCallId, idMap);
|
|
1563
|
+
const refs = toolReferences ? (result.loadedTools ?? []).filter(
|
|
1564
|
+
(name) => toolReferences.has(name) && !referencedTools.has(name)
|
|
1565
|
+
) : [];
|
|
1566
|
+
if (refs.length === 0) {
|
|
1567
|
+
return {
|
|
1568
|
+
type: "tool_result",
|
|
1569
|
+
tool_use_id: toolUseId,
|
|
1570
|
+
content: toAnthropicToolResultContent(result.content),
|
|
1571
|
+
is_error: result.isError
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
for (const name of refs) referencedTools.add(name);
|
|
1575
|
+
const original = toAnthropicToolResultContent(result.content);
|
|
1576
|
+
const parts = typeof original === "string" ? [{ type: "text", text: original }] : original;
|
|
1577
|
+
const first = parts.findIndex((part) => part.type === "text" && part.text !== "");
|
|
1578
|
+
parts.forEach((part, index) => {
|
|
1579
|
+
if (part.type === "text" && part.text === "") return;
|
|
1580
|
+
trailing.push(
|
|
1581
|
+
index === first && part.type === "text" ? { type: "text", text: `Result of tool call ${toolUseId}:
|
|
1582
|
+
${part.text}` } : part
|
|
1583
|
+
);
|
|
1584
|
+
});
|
|
1585
|
+
return {
|
|
1508
1586
|
type: "tool_result",
|
|
1509
|
-
tool_use_id:
|
|
1510
|
-
content:
|
|
1587
|
+
tool_use_id: toolUseId,
|
|
1588
|
+
content: refs.map((name) => ({ type: "tool_reference", tool_name: name })),
|
|
1511
1589
|
is_error: result.isError
|
|
1512
|
-
}
|
|
1590
|
+
};
|
|
1591
|
+
});
|
|
1592
|
+
out.push({
|
|
1593
|
+
role: "user",
|
|
1594
|
+
// Cast covers the video and tool_reference blocks, which aren't in this
|
|
1595
|
+
// SDK's first-party tool_result types.
|
|
1596
|
+
content: [...blocks, ...trailing]
|
|
1513
1597
|
});
|
|
1514
1598
|
}
|
|
1515
1599
|
}
|
|
@@ -1525,7 +1609,8 @@ function toAnthropicMessages(messages, cacheControl, options) {
|
|
|
1525
1609
|
markAnthropicCacheBreakpoint(out, tail, cacheControl);
|
|
1526
1610
|
} else {
|
|
1527
1611
|
if (anchor !== void 0) markAnthropicCacheBreakpoint(out, anchor, cacheControl);
|
|
1528
|
-
|
|
1612
|
+
const longRun = isLongToolRun(messages, trajectoryStartIdx);
|
|
1613
|
+
markAnthropicCacheBreakpoint(out, tail, longRun ? cacheControl : { type: "ephemeral" });
|
|
1529
1614
|
}
|
|
1530
1615
|
} else {
|
|
1531
1616
|
markAnthropicCacheBreakpoint(out, tail, cacheControl);
|
|
@@ -1555,6 +1640,28 @@ function toAnthropicMessages(messages, cacheControl, options) {
|
|
|
1555
1640
|
}
|
|
1556
1641
|
return { system, messages: out };
|
|
1557
1642
|
}
|
|
1643
|
+
var BLOCKING_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
1644
|
+
"wait_agent",
|
|
1645
|
+
"task_output",
|
|
1646
|
+
"subagent",
|
|
1647
|
+
"ask_user"
|
|
1648
|
+
]);
|
|
1649
|
+
var LONG_RUN_ROUNDS = 6;
|
|
1650
|
+
function isLongToolRun(messages, trajectoryStartIdx) {
|
|
1651
|
+
let rounds = 0;
|
|
1652
|
+
for (let i = Math.max(0, trajectoryStartIdx + 1); i < messages.length; i++) {
|
|
1653
|
+
const m = messages[i];
|
|
1654
|
+
if (m?.role !== "assistant" || typeof m.content === "string") continue;
|
|
1655
|
+
let called = false;
|
|
1656
|
+
for (const part of m.content) {
|
|
1657
|
+
if (part.type !== "tool_call") continue;
|
|
1658
|
+
called = true;
|
|
1659
|
+
if (BLOCKING_TOOL_NAMES.has(part.name)) return true;
|
|
1660
|
+
}
|
|
1661
|
+
if (called && ++rounds >= LONG_RUN_ROUNDS) return true;
|
|
1662
|
+
}
|
|
1663
|
+
return false;
|
|
1664
|
+
}
|
|
1558
1665
|
function markAnthropicCacheBreakpoint(out, index, cacheControl) {
|
|
1559
1666
|
const message = out[index];
|
|
1560
1667
|
if (!message) return;
|
|
@@ -1575,6 +1682,18 @@ function markAnthropicCacheBreakpoint(out, index, cacheControl) {
|
|
|
1575
1682
|
}
|
|
1576
1683
|
}
|
|
1577
1684
|
function toAnthropicTools(tools, options) {
|
|
1685
|
+
const deferred = (options?.deferred ?? []).map(
|
|
1686
|
+
(tool) => ({
|
|
1687
|
+
name: tool.name,
|
|
1688
|
+
description: tool.description,
|
|
1689
|
+
input_schema: tool.rawInputSchema ?? zodToJsonSchema(tool.parameters),
|
|
1690
|
+
...options?.enableFineGrainedToolStreaming ? { eager_input_streaming: true } : {},
|
|
1691
|
+
defer_loading: true
|
|
1692
|
+
})
|
|
1693
|
+
);
|
|
1694
|
+
return [...toAnthropicLiveTools(tools, options), ...deferred];
|
|
1695
|
+
}
|
|
1696
|
+
function toAnthropicLiveTools(tools, options) {
|
|
1578
1697
|
return tools.map((tool, index) => {
|
|
1579
1698
|
const anthropicTool = {
|
|
1580
1699
|
name: tool.name,
|
|
@@ -1861,6 +1980,7 @@ function parseToolArguments(argsJson) {
|
|
|
1861
1980
|
// src/utils/provider-fetch.ts
|
|
1862
1981
|
import { Agent, EnvHttpProxyAgent, fetch as undiciFetch } from "undici";
|
|
1863
1982
|
var PROVIDER_TRANSPORT_TIMEOUT_MS = 45 * 6e4;
|
|
1983
|
+
var PROVIDER_KEEP_ALIVE_TIMEOUT_MS = 3e4;
|
|
1864
1984
|
function nodeUsesEnvProxy({
|
|
1865
1985
|
env = process.env,
|
|
1866
1986
|
execArgv = process.execArgv,
|
|
@@ -1873,7 +1993,11 @@ function nodeUsesEnvProxy({
|
|
|
1873
1993
|
return major >= 24 || major === 22 && minor >= 21;
|
|
1874
1994
|
}
|
|
1875
1995
|
function createProviderFetch(timeoutMs, { useEnvProxy = nodeUsesEnvProxy() } = {}) {
|
|
1876
|
-
const timeouts = {
|
|
1996
|
+
const timeouts = {
|
|
1997
|
+
headersTimeout: timeoutMs,
|
|
1998
|
+
bodyTimeout: timeoutMs,
|
|
1999
|
+
keepAliveTimeout: PROVIDER_KEEP_ALIVE_TIMEOUT_MS
|
|
2000
|
+
};
|
|
1877
2001
|
const dispatcher = useEnvProxy ? new EnvHttpProxyAgent(timeouts) : new Agent(timeouts);
|
|
1878
2002
|
const builtinFetch = globalThis.fetch;
|
|
1879
2003
|
const providerFetch2 = async (input, init2) => {
|
|
@@ -2028,6 +2152,9 @@ async function prewarmAnthropicCache(options) {
|
|
|
2028
2152
|
// prewarmed prompt cache actually hits — both are gated by the flag.
|
|
2029
2153
|
enableFineGrainedToolStreaming: fineGrainedToolStreamingEnabled()
|
|
2030
2154
|
}) : void 0;
|
|
2155
|
+
if (estimatePrefixTokens(fullSystem, tools) < anthropicMinCacheableTokens(options.model)) {
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2031
2158
|
await client.messages.create(
|
|
2032
2159
|
{
|
|
2033
2160
|
model: options.model,
|
|
@@ -2068,8 +2195,11 @@ async function* runStream(options) {
|
|
|
2068
2195
|
const downgradedMessages = downgradeUnsupportedVideos(downgradedImages, options.supportsVideo);
|
|
2069
2196
|
const fallbackKey = serverFallbackKey(options);
|
|
2070
2197
|
const useServerFallback = options.provider !== "minimax" && isDirectAnthropicApi(options.baseUrl) && !anthropicServerFallback.disabled.has(fallbackKey);
|
|
2198
|
+
const deferredPlan = options.provider === "anthropic" && isDirectAnthropicApi(options.baseUrl) && supportsAnthropicDeferredTools(options.model) ? planDeferredTools(options.tools, options.deferredTools, downgradedMessages) : void 0;
|
|
2199
|
+
const toolReferences = deferredPlan?.loaded;
|
|
2071
2200
|
const { system: rawSystem, messages } = toAnthropicMessages(downgradedMessages, cacheControl, {
|
|
2072
|
-
fallbackBlocks: useServerFallback
|
|
2201
|
+
fallbackBlocks: useServerFallback,
|
|
2202
|
+
toolReferences
|
|
2073
2203
|
});
|
|
2074
2204
|
const useFastMode = options.speed === "fast" && options.provider === "anthropic" && isDirectAnthropicApi(options.baseUrl);
|
|
2075
2205
|
const system = isOAuth ? [
|
|
@@ -2111,20 +2241,20 @@ async function* runStream(options) {
|
|
|
2111
2241
|
...options.temperature != null && !thinking ? { temperature: options.temperature } : {},
|
|
2112
2242
|
...options.topP != null ? { top_p: options.topP } : {},
|
|
2113
2243
|
...options.stop ? { stop_sequences: options.stop } : {},
|
|
2114
|
-
...options.tools?.length || options.serverTools?.length || options.webSearch ? (() => {
|
|
2244
|
+
...(deferredPlan?.live ?? options.tools)?.length || options.serverTools?.length || options.webSearch ? (() => {
|
|
2115
2245
|
const reservedServerNames = /* @__PURE__ */ new Set();
|
|
2116
2246
|
if (options.webSearch) reservedServerNames.add("web_search");
|
|
2117
2247
|
for (const t of options.serverTools ?? []) {
|
|
2118
2248
|
const name = t.name;
|
|
2119
2249
|
if (name) reservedServerNames.add(name);
|
|
2120
2250
|
}
|
|
2121
|
-
const
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
}
|
|
2127
|
-
) : [];
|
|
2251
|
+
const notReserved = (t) => !reservedServerNames.has(t.name);
|
|
2252
|
+
const liveTools = deferredPlan?.live ?? options.tools ?? [];
|
|
2253
|
+
const clientTools = liveTools.length ? toAnthropicTools(liveTools.filter(notReserved), {
|
|
2254
|
+
...supportsFirstPartyToolExtras && cacheControl ? { cacheControl } : {},
|
|
2255
|
+
...supportsFirstPartyToolExtras && fineGrainedToolStreamingEnabled() ? { enableFineGrainedToolStreaming: true } : {},
|
|
2256
|
+
...deferredPlan ? { deferred: deferredPlan.deferred.filter(notReserved) } : {}
|
|
2257
|
+
}) : [];
|
|
2128
2258
|
return {
|
|
2129
2259
|
tools: [
|
|
2130
2260
|
...clientTools,
|
|
@@ -2145,6 +2275,13 @@ async function* runStream(options) {
|
|
|
2145
2275
|
...useFastMode ? { speed: "fast" } : {},
|
|
2146
2276
|
stream: useStreaming
|
|
2147
2277
|
};
|
|
2278
|
+
if (options.prewarm && estimatePrefixTokens(baseParams.system, baseParams.tools) < anthropicMinCacheableTokens(options.model)) {
|
|
2279
|
+
return {
|
|
2280
|
+
message: { role: "assistant", content: [] },
|
|
2281
|
+
stopReason: "end_turn",
|
|
2282
|
+
usage: { inputTokens: 0, outputTokens: 0 }
|
|
2283
|
+
};
|
|
2284
|
+
}
|
|
2148
2285
|
const params = mergeProviderOptions(baseParams, options.providerOptions);
|
|
2149
2286
|
const hasAdaptiveThinking = isAdaptiveThinkingModel(options.model);
|
|
2150
2287
|
const betaHeaders = [
|
|
@@ -2178,7 +2315,10 @@ async function* runStream(options) {
|
|
|
2178
2315
|
const { fallbacks: _dropped, ...rest } = params;
|
|
2179
2316
|
const retryParams = {
|
|
2180
2317
|
...rest,
|
|
2181
|
-
messages: toAnthropicMessages(downgradedMessages, cacheControl, {
|
|
2318
|
+
messages: toAnthropicMessages(downgradedMessages, cacheControl, {
|
|
2319
|
+
fallbackBlocks: false,
|
|
2320
|
+
toolReferences
|
|
2321
|
+
}).messages
|
|
2182
2322
|
};
|
|
2183
2323
|
return create(
|
|
2184
2324
|
retryParams,
|
|
@@ -2754,6 +2894,10 @@ function createClient2(options) {
|
|
|
2754
2894
|
...options.baseUrl ? { baseURL: options.baseUrl } : {},
|
|
2755
2895
|
// Default transport lifts undici's 300s header/body caps (see provider-fetch.ts).
|
|
2756
2896
|
fetch: options.fetch ?? providerFetch,
|
|
2897
|
+
// The agent loop owns retries (classified backoff, Retry-After, UI retry
|
|
2898
|
+
// events). The SDK default of 2 silent retries stacked under it: one 5xx
|
|
2899
|
+
// cost up to 3 hidden requests plus SDK sleeps before the loop even saw it.
|
|
2900
|
+
maxRetries: 0,
|
|
2757
2901
|
...options.defaultHeaders ? { defaultHeaders: options.defaultHeaders } : {}
|
|
2758
2902
|
});
|
|
2759
2903
|
if (!options.fetch) {
|
|
@@ -3528,6 +3672,15 @@ async function* consumeResponsesEvents(events, ctx) {
|
|
|
3528
3672
|
droppedToolCalls
|
|
3529
3673
|
});
|
|
3530
3674
|
}
|
|
3675
|
+
const addedOrder = [...toolCalls.keys()];
|
|
3676
|
+
const toolSlots = orderedItems.flatMap((e, i) => e.kind === "tool" ? [i] : []);
|
|
3677
|
+
const sortedTools = toolSlots.map((i) => orderedItems[i]).sort(
|
|
3678
|
+
(a, b) => a?.kind === "tool" && b?.kind === "tool" ? addedOrder.indexOf(a.id) - addedOrder.indexOf(b.id) : 0
|
|
3679
|
+
);
|
|
3680
|
+
toolSlots.forEach((slot, k) => {
|
|
3681
|
+
const entry = sortedTools[k];
|
|
3682
|
+
if (entry) orderedItems[slot] = entry;
|
|
3683
|
+
});
|
|
3531
3684
|
const seenTool = /* @__PURE__ */ new Set();
|
|
3532
3685
|
let textInserted = false;
|
|
3533
3686
|
for (const entry of orderedItems) {
|
|
@@ -3604,6 +3757,8 @@ function toResponsesInput(messages, options) {
|
|
|
3604
3757
|
let system;
|
|
3605
3758
|
const input = [];
|
|
3606
3759
|
const idMap = /* @__PURE__ */ new Map();
|
|
3760
|
+
const loadedTools = /* @__PURE__ */ new Set();
|
|
3761
|
+
let toolLoads = 0;
|
|
3607
3762
|
for (const msg of messages) {
|
|
3608
3763
|
if (msg.role === "system") {
|
|
3609
3764
|
system = msg.content;
|
|
@@ -3657,6 +3812,28 @@ function toResponsesInput(messages, options) {
|
|
|
3657
3812
|
call_id: mapId(callId, idMap),
|
|
3658
3813
|
output: text.length > 0 ? text : "(see attached image)"
|
|
3659
3814
|
});
|
|
3815
|
+
const loads = options.toolSearchLoads;
|
|
3816
|
+
const names = loads ? (result.loadedTools ?? []).filter((name) => loads.has(name) && !loadedTools.has(name)) : [];
|
|
3817
|
+
if (loads && names.length > 0) {
|
|
3818
|
+
for (const name of names) loadedTools.add(name);
|
|
3819
|
+
const loadId = `gg_tool_load_${++toolLoads}`;
|
|
3820
|
+
input.push(
|
|
3821
|
+
{
|
|
3822
|
+
type: "tool_search_call",
|
|
3823
|
+
call_id: loadId,
|
|
3824
|
+
execution: "client",
|
|
3825
|
+
status: "completed",
|
|
3826
|
+
arguments: { query: names.join(" "), limit: names.length }
|
|
3827
|
+
},
|
|
3828
|
+
{
|
|
3829
|
+
type: "tool_search_output",
|
|
3830
|
+
call_id: loadId,
|
|
3831
|
+
execution: "client",
|
|
3832
|
+
status: "completed",
|
|
3833
|
+
tools: names.map((name) => loads.get(name))
|
|
3834
|
+
}
|
|
3835
|
+
);
|
|
3836
|
+
}
|
|
3660
3837
|
if (options.supportsImages !== false && Array.isArray(result.content)) {
|
|
3661
3838
|
for (const block of result.content) {
|
|
3662
3839
|
if (block.type === "image") toolImages.push(block);
|
|
@@ -3755,8 +3932,19 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
|
|
|
3755
3932
|
const url = `${baseUrl}/codex/responses`;
|
|
3756
3933
|
const downgradedImages = downgradeUnsupportedImages(options.messages, options.supportsImages);
|
|
3757
3934
|
const downgraded = downgradeUnsupportedVideos(downgradedImages, options.supportsVideo);
|
|
3935
|
+
const deferredPlan = supportsResponsesToolSearch(options.model) ? planDeferredTools(options.tools, options.deferredTools, downgraded) : void 0;
|
|
3936
|
+
const strictTools = options.strictTools ?? true;
|
|
3937
|
+
const toolSearchLoads = deferredPlan ? new Map(
|
|
3938
|
+
[...deferredPlan.loaded].map((name) => {
|
|
3939
|
+
const tool = deferredPlan.byName.get(name);
|
|
3940
|
+
const [wire] = tool ? toCodexTools([tool], strictTools) : [];
|
|
3941
|
+
return [name, { ...wire, defer_loading: true }];
|
|
3942
|
+
})
|
|
3943
|
+
) : void 0;
|
|
3944
|
+
const liveTools = deferredPlan?.live ?? options.tools;
|
|
3758
3945
|
const { system, input } = toResponsesInput(downgraded, {
|
|
3759
3946
|
supportsImages: options.supportsImages,
|
|
3947
|
+
toolSearchLoads,
|
|
3760
3948
|
mapId: remapCodexId,
|
|
3761
3949
|
// Stamped reasoning belongs to another transport (e.g. Grok's) and would
|
|
3762
3950
|
// be rejected here; Codex's own items are never stamped.
|
|
@@ -3770,12 +3958,12 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
|
|
|
3770
3958
|
stream: true,
|
|
3771
3959
|
instructions: system,
|
|
3772
3960
|
input,
|
|
3773
|
-
tool_choice: toCodexToolChoice(options.toolChoice,
|
|
3961
|
+
tool_choice: toCodexToolChoice(options.toolChoice, liveTools),
|
|
3774
3962
|
parallel_tool_calls: !liteShape,
|
|
3775
3963
|
include: ["reasoning.encrypted_content"]
|
|
3776
3964
|
};
|
|
3777
|
-
if (
|
|
3778
|
-
body.tools = toCodexTools(
|
|
3965
|
+
if (liveTools?.length) {
|
|
3966
|
+
body.tools = toCodexTools(liveTools, strictTools);
|
|
3779
3967
|
}
|
|
3780
3968
|
body.prompt_cache_key = normalizePromptCacheKey(options.promptCacheKey ?? "ggcoder");
|
|
3781
3969
|
if (options.temperature != null && !options.thinking) {
|
|
@@ -5517,7 +5705,7 @@ function stream(requested) {
|
|
|
5517
5705
|
observePreparedContext(
|
|
5518
5706
|
replayable === sanitized ? wireMessages : replayable,
|
|
5519
5707
|
messages,
|
|
5520
|
-
options
|
|
5708
|
+
observedTools(options, messages)
|
|
5521
5709
|
)
|
|
5522
5710
|
);
|
|
5523
5711
|
} catch {
|
|
@@ -5525,6 +5713,11 @@ function stream(requested) {
|
|
|
5525
5713
|
}
|
|
5526
5714
|
return entry.stream(messages === options.messages ? options : { ...options, messages });
|
|
5527
5715
|
}
|
|
5716
|
+
function observedTools(options, messages) {
|
|
5717
|
+
if (!usesDeferredToolLoading(options)) return options.tools ?? [];
|
|
5718
|
+
const plan = planDeferredTools(options.tools, options.deferredTools, messages);
|
|
5719
|
+
return plan ? [...plan.live, ...plan.deferred] : options.tools ?? [];
|
|
5720
|
+
}
|
|
5528
5721
|
function stripMessageProvenance(messages) {
|
|
5529
5722
|
let stripped;
|
|
5530
5723
|
for (let index = 0; index < messages.length; index++) {
|
|
@@ -5664,6 +5857,85 @@ function l2Normalize(vector) {
|
|
|
5664
5857
|
return vector.map((value) => value / norm);
|
|
5665
5858
|
}
|
|
5666
5859
|
|
|
5860
|
+
// src/utils/preconnect.ts
|
|
5861
|
+
var PRECONNECT_INTERVAL_MS = 3e4;
|
|
5862
|
+
function defaultBaseUrl(provider, accountId) {
|
|
5863
|
+
switch (provider) {
|
|
5864
|
+
case "anthropic":
|
|
5865
|
+
return "https://api.anthropic.com";
|
|
5866
|
+
case "openai":
|
|
5867
|
+
return accountId ? "https://chatgpt.com/backend-api" : "https://api.openai.com/v1";
|
|
5868
|
+
case "gemini":
|
|
5869
|
+
return "https://cloudcode-pa.googleapis.com";
|
|
5870
|
+
case "glm":
|
|
5871
|
+
return "https://api.z.ai/api/coding/paas/v4";
|
|
5872
|
+
case "moonshot":
|
|
5873
|
+
return "https://api.moonshot.ai/v1";
|
|
5874
|
+
case "deepseek":
|
|
5875
|
+
return "https://api.deepseek.com/v1";
|
|
5876
|
+
case "openrouter":
|
|
5877
|
+
return "https://openrouter.ai/api/v1";
|
|
5878
|
+
case "xiaomi":
|
|
5879
|
+
return "https://token-plan-sgp.xiaomimimo.com/v1";
|
|
5880
|
+
case "minimax":
|
|
5881
|
+
return "https://api.minimax.io/anthropic";
|
|
5882
|
+
case "xai":
|
|
5883
|
+
return "https://api.x.ai/v1";
|
|
5884
|
+
case "huggingface":
|
|
5885
|
+
return "https://router.huggingface.co/v1";
|
|
5886
|
+
case "sakana":
|
|
5887
|
+
return "https://api.sakana.ai/v1";
|
|
5888
|
+
case "local":
|
|
5889
|
+
case "palsu":
|
|
5890
|
+
return void 0;
|
|
5891
|
+
}
|
|
5892
|
+
}
|
|
5893
|
+
function isLocalHost(hostname) {
|
|
5894
|
+
const host = hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
5895
|
+
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) return true;
|
|
5896
|
+
if (host === "::1" || host === "0.0.0.0") return true;
|
|
5897
|
+
if (host.includes(":")) return /^(f[cd]|fe[89ab])/.test(host);
|
|
5898
|
+
const octets = host.split(".").map(Number);
|
|
5899
|
+
if (octets.length !== 4 || octets.some((n) => !Number.isInteger(n))) return false;
|
|
5900
|
+
const [a = 0, b = 0] = octets;
|
|
5901
|
+
return a === 127 || a === 10 || a === 192 && b === 168 || a === 172 && b >= 16 && b <= 31;
|
|
5902
|
+
}
|
|
5903
|
+
function preconnectTarget(options) {
|
|
5904
|
+
const raw = options.baseUrl ?? defaultBaseUrl(options.provider, options.accountId);
|
|
5905
|
+
if (!raw || options.provider === "local" || options.provider === "palsu") return void 0;
|
|
5906
|
+
let url;
|
|
5907
|
+
try {
|
|
5908
|
+
url = new URL(raw);
|
|
5909
|
+
} catch {
|
|
5910
|
+
return void 0;
|
|
5911
|
+
}
|
|
5912
|
+
if (url.protocol !== "https:" || isLocalHost(url.hostname)) return void 0;
|
|
5913
|
+
url.pathname = url.pathname.replace(/\/+$/, "") || "/";
|
|
5914
|
+
url.search = "";
|
|
5915
|
+
url.hash = "";
|
|
5916
|
+
return url;
|
|
5917
|
+
}
|
|
5918
|
+
function preconnectOrigin(options) {
|
|
5919
|
+
return preconnectTarget(options)?.origin;
|
|
5920
|
+
}
|
|
5921
|
+
function preconnectProvider(options) {
|
|
5922
|
+
const target = preconnectTarget(options);
|
|
5923
|
+
if (!target) return void 0;
|
|
5924
|
+
const origin = target.origin;
|
|
5925
|
+
const now = options.now ?? Date.now();
|
|
5926
|
+
const last = options.warmedAt.get(origin);
|
|
5927
|
+
if (last !== void 0 && now - last < PRECONNECT_INTERVAL_MS) return void 0;
|
|
5928
|
+
options.warmedAt.set(origin, now);
|
|
5929
|
+
const fetchImpl = options.fetch ?? providerFetch;
|
|
5930
|
+
void fetchImpl(target.href, {
|
|
5931
|
+
method: "HEAD",
|
|
5932
|
+
redirect: "manual",
|
|
5933
|
+
signal: AbortSignal.timeout(1e4)
|
|
5934
|
+
}).then((response) => response.body?.cancel()).catch(() => {
|
|
5935
|
+
});
|
|
5936
|
+
return origin;
|
|
5937
|
+
}
|
|
5938
|
+
|
|
5667
5939
|
// src/chat-error.ts
|
|
5668
5940
|
function causeCode(error) {
|
|
5669
5941
|
if (!(error instanceof Error) || !error.cause || typeof error.cause !== "object") return "";
|
|
@@ -6141,6 +6413,7 @@ export {
|
|
|
6141
6413
|
EventStream,
|
|
6142
6414
|
FAST_MODE_SUFFIX,
|
|
6143
6415
|
GGAIError,
|
|
6416
|
+
PRECONNECT_INTERVAL_MS,
|
|
6144
6417
|
ProviderError,
|
|
6145
6418
|
REDACTED as REDACTION_MARKER,
|
|
6146
6419
|
ResponseStalledError,
|
|
@@ -6172,6 +6445,8 @@ export {
|
|
|
6172
6445
|
palsuToolCall,
|
|
6173
6446
|
parseFastModeRejection,
|
|
6174
6447
|
pendingClaudeCodeVersionRefresh,
|
|
6448
|
+
preconnectOrigin,
|
|
6449
|
+
preconnectProvider,
|
|
6175
6450
|
prewarmAnthropicCache,
|
|
6176
6451
|
providerRegistry,
|
|
6177
6452
|
redactText,
|