@ljoukov/llm 3.0.2 → 3.0.4
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 +24 -0
- package/dist/index.cjs +1166 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -7
- package/dist/index.d.ts +52 -7
- package/dist/index.js +1151 -136
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -171,9 +171,6 @@ function getOpenAiPricing(modelId) {
|
|
|
171
171
|
if (modelId.includes("gpt-5.3-codex")) {
|
|
172
172
|
return OPENAI_GPT_53_CODEX_PRICING;
|
|
173
173
|
}
|
|
174
|
-
if (modelId.includes("gpt-5-codex")) {
|
|
175
|
-
return OPENAI_GPT_53_CODEX_PRICING;
|
|
176
|
-
}
|
|
177
174
|
if (modelId.includes("gpt-5.2")) {
|
|
178
175
|
return OPENAI_GPT_52_PRICING;
|
|
179
176
|
}
|
|
@@ -696,6 +693,22 @@ var ResponsesWebSocketHttpError = class extends Error {
|
|
|
696
693
|
this.headers = options.headers;
|
|
697
694
|
}
|
|
698
695
|
};
|
|
696
|
+
var UNSUPPORTED_WEBSOCKET_STATUS_CODES = /* @__PURE__ */ new Set([400, 404, 405, 406, 426, 501]);
|
|
697
|
+
var WEBSOCKET_CONNECT_TIMEOUT_MS = 3e4;
|
|
698
|
+
function parseUnexpectedServerResponseStatus(message) {
|
|
699
|
+
const match = /unexpected server response:\s*(\d+)/i.exec(message);
|
|
700
|
+
if (!match) {
|
|
701
|
+
return null;
|
|
702
|
+
}
|
|
703
|
+
const status = Number(match[1]);
|
|
704
|
+
if (!Number.isFinite(status) || status <= 0) {
|
|
705
|
+
return null;
|
|
706
|
+
}
|
|
707
|
+
return status;
|
|
708
|
+
}
|
|
709
|
+
function supportsUnexpectedResponseEvent() {
|
|
710
|
+
return !("bun" in process.versions);
|
|
711
|
+
}
|
|
699
712
|
function resolveResponsesWebSocketMode(raw, fallback = "auto") {
|
|
700
713
|
const value = raw?.trim().toLowerCase();
|
|
701
714
|
if (value === "auto" || value === "off" || value === "only") {
|
|
@@ -730,9 +743,13 @@ function toWebSocketUrl(httpOrHttpsUrl) {
|
|
|
730
743
|
}
|
|
731
744
|
function isResponsesWebSocketUnsupportedError(error) {
|
|
732
745
|
if (error instanceof ResponsesWebSocketHttpError) {
|
|
733
|
-
return
|
|
746
|
+
return UNSUPPORTED_WEBSOCKET_STATUS_CODES.has(error.status);
|
|
734
747
|
}
|
|
735
748
|
const message = error instanceof Error ? error.message.toLowerCase() : "";
|
|
749
|
+
const status = parseUnexpectedServerResponseStatus(message);
|
|
750
|
+
if (status !== null) {
|
|
751
|
+
return UNSUPPORTED_WEBSOCKET_STATUS_CODES.has(status);
|
|
752
|
+
}
|
|
736
753
|
return message.includes("unexpected server response: 426");
|
|
737
754
|
}
|
|
738
755
|
function createAdaptiveResponsesStream(options) {
|
|
@@ -971,12 +988,20 @@ async function createResponsesWebSocketStream(options) {
|
|
|
971
988
|
}
|
|
972
989
|
async function connectWebSocket(options) {
|
|
973
990
|
return await new Promise((resolve, reject) => {
|
|
991
|
+
const shouldListenForUnexpectedResponse = supportsUnexpectedResponseEvent();
|
|
974
992
|
const socket = new WebSocket(options.url, {
|
|
975
993
|
headers: options.headers,
|
|
976
|
-
handshakeTimeout:
|
|
994
|
+
handshakeTimeout: WEBSOCKET_CONNECT_TIMEOUT_MS
|
|
977
995
|
});
|
|
978
996
|
let settled = false;
|
|
979
997
|
let responseBody = "";
|
|
998
|
+
let connectTimeout = setTimeout(() => {
|
|
999
|
+
rejectOnce(
|
|
1000
|
+
new Error(
|
|
1001
|
+
`Responses WebSocket connection timed out after ${WEBSOCKET_CONNECT_TIMEOUT_MS}ms.`
|
|
1002
|
+
)
|
|
1003
|
+
);
|
|
1004
|
+
}, WEBSOCKET_CONNECT_TIMEOUT_MS);
|
|
980
1005
|
const rejectOnce = (error) => {
|
|
981
1006
|
if (settled) {
|
|
982
1007
|
return;
|
|
@@ -1001,9 +1026,15 @@ async function connectWebSocket(options) {
|
|
|
1001
1026
|
rejectOnce(createAbortError(options.signal?.reason));
|
|
1002
1027
|
};
|
|
1003
1028
|
const cleanup = (removeAbortListener = true) => {
|
|
1029
|
+
if (connectTimeout) {
|
|
1030
|
+
clearTimeout(connectTimeout);
|
|
1031
|
+
connectTimeout = null;
|
|
1032
|
+
}
|
|
1004
1033
|
socket.removeListener("open", onOpen);
|
|
1005
1034
|
socket.removeListener("error", onError);
|
|
1006
|
-
|
|
1035
|
+
if (shouldListenForUnexpectedResponse) {
|
|
1036
|
+
socket.removeListener("unexpected-response", onUnexpectedResponse);
|
|
1037
|
+
}
|
|
1007
1038
|
if (removeAbortListener && options.signal) {
|
|
1008
1039
|
options.signal.removeEventListener("abort", onAbort);
|
|
1009
1040
|
}
|
|
@@ -1054,7 +1085,9 @@ async function connectWebSocket(options) {
|
|
|
1054
1085
|
};
|
|
1055
1086
|
socket.once("open", onOpen);
|
|
1056
1087
|
socket.once("error", onError);
|
|
1057
|
-
|
|
1088
|
+
if (shouldListenForUnexpectedResponse) {
|
|
1089
|
+
socket.once("unexpected-response", onUnexpectedResponse);
|
|
1090
|
+
}
|
|
1058
1091
|
if (options.signal) {
|
|
1059
1092
|
if (options.signal.aborted) {
|
|
1060
1093
|
onAbort();
|
|
@@ -1549,6 +1582,66 @@ function parseEventBlock(raw) {
|
|
|
1549
1582
|
}
|
|
1550
1583
|
}
|
|
1551
1584
|
|
|
1585
|
+
// src/utils/modelConcurrency.ts
|
|
1586
|
+
var MIN_MODEL_CONCURRENCY_CAP = 1;
|
|
1587
|
+
var MAX_MODEL_CONCURRENCY_CAP = 64;
|
|
1588
|
+
var DEFAULT_MODEL_CONCURRENCY_CAP = 3;
|
|
1589
|
+
function parsePositiveInteger(raw) {
|
|
1590
|
+
if (raw === void 0) {
|
|
1591
|
+
return void 0;
|
|
1592
|
+
}
|
|
1593
|
+
const normalized = raw.trim();
|
|
1594
|
+
if (!normalized) {
|
|
1595
|
+
return void 0;
|
|
1596
|
+
}
|
|
1597
|
+
if (!/^-?\d+$/u.test(normalized)) {
|
|
1598
|
+
return void 0;
|
|
1599
|
+
}
|
|
1600
|
+
const parsed = Number.parseInt(normalized, 10);
|
|
1601
|
+
if (!Number.isFinite(parsed)) {
|
|
1602
|
+
return void 0;
|
|
1603
|
+
}
|
|
1604
|
+
return parsed;
|
|
1605
|
+
}
|
|
1606
|
+
function clampModelConcurrencyCap(value) {
|
|
1607
|
+
if (!Number.isFinite(value)) {
|
|
1608
|
+
return DEFAULT_MODEL_CONCURRENCY_CAP;
|
|
1609
|
+
}
|
|
1610
|
+
const rounded = Math.floor(value);
|
|
1611
|
+
if (rounded < MIN_MODEL_CONCURRENCY_CAP) {
|
|
1612
|
+
return MIN_MODEL_CONCURRENCY_CAP;
|
|
1613
|
+
}
|
|
1614
|
+
if (rounded > MAX_MODEL_CONCURRENCY_CAP) {
|
|
1615
|
+
return MAX_MODEL_CONCURRENCY_CAP;
|
|
1616
|
+
}
|
|
1617
|
+
return rounded;
|
|
1618
|
+
}
|
|
1619
|
+
function normalizeModelIdForEnv(modelId) {
|
|
1620
|
+
return modelId.trim().replace(/[^A-Za-z0-9]+/gu, "_").replace(/^_+|_+$/gu, "").toUpperCase();
|
|
1621
|
+
}
|
|
1622
|
+
function resolveModelConcurrencyCap(options) {
|
|
1623
|
+
const env = options.env ?? process.env;
|
|
1624
|
+
const providerPrefix = options.providerEnvPrefix;
|
|
1625
|
+
const defaultCap = clampModelConcurrencyCap(options.defaultCap ?? DEFAULT_MODEL_CONCURRENCY_CAP);
|
|
1626
|
+
const normalizedModelId = options.modelId ? normalizeModelIdForEnv(options.modelId) : "";
|
|
1627
|
+
const candidateKeys = [
|
|
1628
|
+
...normalizedModelId ? [
|
|
1629
|
+
`${providerPrefix}_MAX_PARALLEL_REQUESTS_MODEL_${normalizedModelId}`,
|
|
1630
|
+
`LLM_MAX_PARALLEL_REQUESTS_MODEL_${normalizedModelId}`
|
|
1631
|
+
] : [],
|
|
1632
|
+
`${providerPrefix}_MAX_PARALLEL_REQUESTS_PER_MODEL`,
|
|
1633
|
+
"LLM_MAX_PARALLEL_REQUESTS_PER_MODEL"
|
|
1634
|
+
];
|
|
1635
|
+
for (const key of candidateKeys) {
|
|
1636
|
+
const parsed = parsePositiveInteger(env[key]);
|
|
1637
|
+
if (parsed === void 0) {
|
|
1638
|
+
continue;
|
|
1639
|
+
}
|
|
1640
|
+
return clampModelConcurrencyCap(parsed);
|
|
1641
|
+
}
|
|
1642
|
+
return defaultCap;
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1552
1645
|
// src/utils/scheduler.ts
|
|
1553
1646
|
function sleep(ms) {
|
|
1554
1647
|
return new Promise((resolve) => {
|
|
@@ -1564,13 +1657,72 @@ function toError(value) {
|
|
|
1564
1657
|
}
|
|
1565
1658
|
return new Error("Unknown error");
|
|
1566
1659
|
}
|
|
1660
|
+
function getStatusCode(error) {
|
|
1661
|
+
if (!error || typeof error !== "object") {
|
|
1662
|
+
return void 0;
|
|
1663
|
+
}
|
|
1664
|
+
const maybe = error;
|
|
1665
|
+
const candidates = [maybe.status, maybe.statusCode];
|
|
1666
|
+
for (const candidate of candidates) {
|
|
1667
|
+
if (typeof candidate === "number") {
|
|
1668
|
+
return candidate;
|
|
1669
|
+
}
|
|
1670
|
+
if (typeof candidate === "string") {
|
|
1671
|
+
const parsed = Number.parseInt(candidate, 10);
|
|
1672
|
+
if (Number.isFinite(parsed)) {
|
|
1673
|
+
return parsed;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
if (typeof maybe.code === "number") {
|
|
1678
|
+
return maybe.code;
|
|
1679
|
+
}
|
|
1680
|
+
return void 0;
|
|
1681
|
+
}
|
|
1682
|
+
function getErrorText(error) {
|
|
1683
|
+
if (error instanceof Error) {
|
|
1684
|
+
return error.message.toLowerCase();
|
|
1685
|
+
}
|
|
1686
|
+
if (typeof error === "string") {
|
|
1687
|
+
return error.toLowerCase();
|
|
1688
|
+
}
|
|
1689
|
+
if (error && typeof error === "object") {
|
|
1690
|
+
const maybe = error;
|
|
1691
|
+
const code = typeof maybe.code === "string" ? maybe.code : "";
|
|
1692
|
+
const message = typeof maybe.message === "string" ? maybe.message : "";
|
|
1693
|
+
return `${code} ${message}`.trim().toLowerCase();
|
|
1694
|
+
}
|
|
1695
|
+
return "";
|
|
1696
|
+
}
|
|
1697
|
+
function defaultIsOverloadError(error) {
|
|
1698
|
+
const status = getStatusCode(error);
|
|
1699
|
+
if (status === 429 || status === 503 || status === 529) {
|
|
1700
|
+
return true;
|
|
1701
|
+
}
|
|
1702
|
+
const text = getErrorText(error);
|
|
1703
|
+
if (!text) {
|
|
1704
|
+
return false;
|
|
1705
|
+
}
|
|
1706
|
+
return text.includes("rate limit") || text.includes("too many requests") || text.includes("resource exhausted") || text.includes("resource_exhausted") || text.includes("overload");
|
|
1707
|
+
}
|
|
1567
1708
|
function createCallScheduler(options = {}) {
|
|
1568
1709
|
const maxParallelRequests = Math.max(1, Math.floor(options.maxParallelRequests ?? 3));
|
|
1710
|
+
const initialParallelRequests = Math.min(
|
|
1711
|
+
maxParallelRequests,
|
|
1712
|
+
Math.max(1, Math.floor(options.initialParallelRequests ?? Math.min(3, maxParallelRequests)))
|
|
1713
|
+
);
|
|
1714
|
+
const increaseAfterConsecutiveSuccesses = Math.max(
|
|
1715
|
+
1,
|
|
1716
|
+
Math.floor(options.increaseAfterConsecutiveSuccesses ?? 8)
|
|
1717
|
+
);
|
|
1569
1718
|
const minIntervalBetweenStartMs = Math.max(0, Math.floor(options.minIntervalBetweenStartMs ?? 0));
|
|
1570
1719
|
const startJitterMs = Math.max(0, Math.floor(options.startJitterMs ?? 0));
|
|
1571
1720
|
const retryPolicy = options.retry;
|
|
1721
|
+
const isOverloadError2 = options.isOverloadError ?? defaultIsOverloadError;
|
|
1572
1722
|
let activeCount = 0;
|
|
1573
1723
|
let lastStartTime = 0;
|
|
1724
|
+
let currentParallelLimit = initialParallelRequests;
|
|
1725
|
+
let consecutiveSuccesses = 0;
|
|
1574
1726
|
let startSpacingChain = Promise.resolve();
|
|
1575
1727
|
const queue = [];
|
|
1576
1728
|
async function applyStartSpacing() {
|
|
@@ -1601,6 +1753,10 @@ function createCallScheduler(options = {}) {
|
|
|
1601
1753
|
await applyStartSpacing();
|
|
1602
1754
|
return await fn();
|
|
1603
1755
|
} catch (error) {
|
|
1756
|
+
if (isOverloadError2(error)) {
|
|
1757
|
+
consecutiveSuccesses = 0;
|
|
1758
|
+
currentParallelLimit = Math.max(1, Math.ceil(currentParallelLimit / 2));
|
|
1759
|
+
}
|
|
1604
1760
|
const err = toError(error);
|
|
1605
1761
|
if (!retryPolicy || attempt >= retryPolicy.maxAttempts) {
|
|
1606
1762
|
throw err;
|
|
@@ -1620,7 +1776,7 @@ function createCallScheduler(options = {}) {
|
|
|
1620
1776
|
}
|
|
1621
1777
|
}
|
|
1622
1778
|
function drainQueue() {
|
|
1623
|
-
while (activeCount <
|
|
1779
|
+
while (activeCount < currentParallelLimit && queue.length > 0) {
|
|
1624
1780
|
const task = queue.shift();
|
|
1625
1781
|
if (!task) {
|
|
1626
1782
|
continue;
|
|
@@ -1634,6 +1790,11 @@ function createCallScheduler(options = {}) {
|
|
|
1634
1790
|
const job = async () => {
|
|
1635
1791
|
try {
|
|
1636
1792
|
const result = await attemptWithRetries(fn, 1);
|
|
1793
|
+
consecutiveSuccesses += 1;
|
|
1794
|
+
if (currentParallelLimit < maxParallelRequests && consecutiveSuccesses >= increaseAfterConsecutiveSuccesses) {
|
|
1795
|
+
currentParallelLimit += 1;
|
|
1796
|
+
consecutiveSuccesses = 0;
|
|
1797
|
+
}
|
|
1637
1798
|
resolve(result);
|
|
1638
1799
|
} catch (error) {
|
|
1639
1800
|
reject(toError(error));
|
|
@@ -1723,13 +1884,28 @@ function getFireworksClient() {
|
|
|
1723
1884
|
}
|
|
1724
1885
|
|
|
1725
1886
|
// src/fireworks/calls.ts
|
|
1726
|
-
var
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1887
|
+
var DEFAULT_SCHEDULER_KEY = "__default__";
|
|
1888
|
+
var schedulerByModel = /* @__PURE__ */ new Map();
|
|
1889
|
+
function getSchedulerForModel(modelId) {
|
|
1890
|
+
const normalizedModelId = modelId?.trim();
|
|
1891
|
+
const schedulerKey = normalizedModelId && normalizedModelId.length > 0 ? normalizedModelId : DEFAULT_SCHEDULER_KEY;
|
|
1892
|
+
const existing = schedulerByModel.get(schedulerKey);
|
|
1893
|
+
if (existing) {
|
|
1894
|
+
return existing;
|
|
1895
|
+
}
|
|
1896
|
+
const created = createCallScheduler({
|
|
1897
|
+
maxParallelRequests: resolveModelConcurrencyCap({
|
|
1898
|
+
providerEnvPrefix: "FIREWORKS",
|
|
1899
|
+
modelId: normalizedModelId
|
|
1900
|
+
}),
|
|
1901
|
+
minIntervalBetweenStartMs: 200,
|
|
1902
|
+
startJitterMs: 200
|
|
1903
|
+
});
|
|
1904
|
+
schedulerByModel.set(schedulerKey, created);
|
|
1905
|
+
return created;
|
|
1906
|
+
}
|
|
1907
|
+
async function runFireworksCall(fn, modelId) {
|
|
1908
|
+
return getSchedulerForModel(modelId).run(async () => fn(getFireworksClient()));
|
|
1733
1909
|
}
|
|
1734
1910
|
|
|
1735
1911
|
// src/fireworks/models.ts
|
|
@@ -1821,7 +1997,7 @@ function getGoogleAuthOptions(scopes) {
|
|
|
1821
1997
|
}
|
|
1822
1998
|
|
|
1823
1999
|
// src/google/client.ts
|
|
1824
|
-
var
|
|
2000
|
+
var GEMINI_TEXT_MODEL_IDS = [
|
|
1825
2001
|
"gemini-3-pro-preview",
|
|
1826
2002
|
"gemini-3.1-pro-preview",
|
|
1827
2003
|
"gemini-3-flash-preview",
|
|
@@ -1829,9 +2005,17 @@ var GEMINI_MODEL_IDS = [
|
|
|
1829
2005
|
"gemini-flash-latest",
|
|
1830
2006
|
"gemini-flash-lite-latest"
|
|
1831
2007
|
];
|
|
2008
|
+
var GEMINI_IMAGE_MODEL_IDS = ["gemini-3-pro-image-preview"];
|
|
2009
|
+
var GEMINI_MODEL_IDS = [...GEMINI_TEXT_MODEL_IDS, ...GEMINI_IMAGE_MODEL_IDS];
|
|
1832
2010
|
function isGeminiModelId(value) {
|
|
1833
2011
|
return GEMINI_MODEL_IDS.includes(value);
|
|
1834
2012
|
}
|
|
2013
|
+
function isGeminiTextModelId(value) {
|
|
2014
|
+
return GEMINI_TEXT_MODEL_IDS.includes(value);
|
|
2015
|
+
}
|
|
2016
|
+
function isGeminiImageModelId(value) {
|
|
2017
|
+
return GEMINI_IMAGE_MODEL_IDS.includes(value);
|
|
2018
|
+
}
|
|
1835
2019
|
var CLOUD_PLATFORM_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
|
|
1836
2020
|
var DEFAULT_VERTEX_LOCATION = "global";
|
|
1837
2021
|
var geminiConfiguration = {};
|
|
@@ -2057,6 +2241,18 @@ function shouldRetry(error) {
|
|
|
2057
2241
|
}
|
|
2058
2242
|
return false;
|
|
2059
2243
|
}
|
|
2244
|
+
function isOverloadError(error) {
|
|
2245
|
+
const status = getStatus(error);
|
|
2246
|
+
if (status === 429 || status === 503 || status === 529) {
|
|
2247
|
+
return true;
|
|
2248
|
+
}
|
|
2249
|
+
const reason = getErrorReason(error);
|
|
2250
|
+
if (reason && RATE_LIMIT_REASONS.has(reason)) {
|
|
2251
|
+
return true;
|
|
2252
|
+
}
|
|
2253
|
+
const message = getErrorMessage(error).toLowerCase();
|
|
2254
|
+
return message.includes("rate limit") || message.includes("too many requests") || message.includes("resource exhausted") || message.includes("resource_exhausted");
|
|
2255
|
+
}
|
|
2060
2256
|
function retryDelayMs(attempt) {
|
|
2061
2257
|
const baseRetryDelayMs = 500;
|
|
2062
2258
|
const maxRetryDelayMs = 4e3;
|
|
@@ -2064,23 +2260,39 @@ function retryDelayMs(attempt) {
|
|
|
2064
2260
|
const jitter = Math.floor(Math.random() * 200);
|
|
2065
2261
|
return base + jitter;
|
|
2066
2262
|
}
|
|
2067
|
-
var
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2263
|
+
var DEFAULT_SCHEDULER_KEY2 = "__default__";
|
|
2264
|
+
var schedulerByModel2 = /* @__PURE__ */ new Map();
|
|
2265
|
+
function getSchedulerForModel2(modelId) {
|
|
2266
|
+
const normalizedModelId = modelId?.trim();
|
|
2267
|
+
const schedulerKey = normalizedModelId && normalizedModelId.length > 0 ? normalizedModelId : DEFAULT_SCHEDULER_KEY2;
|
|
2268
|
+
const existing = schedulerByModel2.get(schedulerKey);
|
|
2269
|
+
if (existing) {
|
|
2270
|
+
return existing;
|
|
2271
|
+
}
|
|
2272
|
+
const created = createCallScheduler({
|
|
2273
|
+
maxParallelRequests: resolveModelConcurrencyCap({
|
|
2274
|
+
providerEnvPrefix: "GOOGLE",
|
|
2275
|
+
modelId: normalizedModelId
|
|
2276
|
+
}),
|
|
2277
|
+
minIntervalBetweenStartMs: 200,
|
|
2278
|
+
startJitterMs: 200,
|
|
2279
|
+
isOverloadError,
|
|
2280
|
+
retry: {
|
|
2281
|
+
maxAttempts: 3,
|
|
2282
|
+
getDelayMs: (attempt, error) => {
|
|
2283
|
+
if (!shouldRetry(error)) {
|
|
2284
|
+
return null;
|
|
2285
|
+
}
|
|
2286
|
+
const hintedDelay = getRetryAfterMs(error);
|
|
2287
|
+
return hintedDelay ?? retryDelayMs(attempt);
|
|
2076
2288
|
}
|
|
2077
|
-
const hintedDelay = getRetryAfterMs(error);
|
|
2078
|
-
return hintedDelay ?? retryDelayMs(attempt);
|
|
2079
2289
|
}
|
|
2080
|
-
}
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2290
|
+
});
|
|
2291
|
+
schedulerByModel2.set(schedulerKey, created);
|
|
2292
|
+
return created;
|
|
2293
|
+
}
|
|
2294
|
+
async function runGeminiCall(fn, modelId) {
|
|
2295
|
+
return getSchedulerForModel2(modelId).run(async () => fn(await getGeminiClient()));
|
|
2084
2296
|
}
|
|
2085
2297
|
|
|
2086
2298
|
// src/openai/client.ts
|
|
@@ -2241,13 +2453,51 @@ function getOpenAiClient() {
|
|
|
2241
2453
|
|
|
2242
2454
|
// src/openai/calls.ts
|
|
2243
2455
|
var DEFAULT_OPENAI_REASONING_EFFORT = "medium";
|
|
2244
|
-
var
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2456
|
+
var DEFAULT_SCHEDULER_KEY3 = "__default__";
|
|
2457
|
+
var schedulerByModel3 = /* @__PURE__ */ new Map();
|
|
2458
|
+
function getSchedulerForModel3(modelId) {
|
|
2459
|
+
const normalizedModelId = modelId?.trim();
|
|
2460
|
+
const schedulerKey = normalizedModelId && normalizedModelId.length > 0 ? normalizedModelId : DEFAULT_SCHEDULER_KEY3;
|
|
2461
|
+
const existing = schedulerByModel3.get(schedulerKey);
|
|
2462
|
+
if (existing) {
|
|
2463
|
+
return existing;
|
|
2464
|
+
}
|
|
2465
|
+
const created = createCallScheduler({
|
|
2466
|
+
maxParallelRequests: resolveModelConcurrencyCap({
|
|
2467
|
+
providerEnvPrefix: "OPENAI",
|
|
2468
|
+
modelId: normalizedModelId
|
|
2469
|
+
}),
|
|
2470
|
+
minIntervalBetweenStartMs: 200,
|
|
2471
|
+
startJitterMs: 200
|
|
2472
|
+
});
|
|
2473
|
+
schedulerByModel3.set(schedulerKey, created);
|
|
2474
|
+
return created;
|
|
2475
|
+
}
|
|
2476
|
+
async function runOpenAiCall(fn, modelId) {
|
|
2477
|
+
return getSchedulerForModel3(modelId).run(async () => fn(getOpenAiClient()));
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
// src/openai/models.ts
|
|
2481
|
+
var OPENAI_MODEL_IDS = [
|
|
2482
|
+
"gpt-5.3-codex",
|
|
2483
|
+
"gpt-5.3-codex-spark",
|
|
2484
|
+
"gpt-5.2",
|
|
2485
|
+
"gpt-5.1-codex-mini"
|
|
2486
|
+
];
|
|
2487
|
+
function isOpenAiModelId(value) {
|
|
2488
|
+
return OPENAI_MODEL_IDS.includes(value);
|
|
2489
|
+
}
|
|
2490
|
+
var CHATGPT_MODEL_IDS = [
|
|
2491
|
+
"chatgpt-gpt-5.3-codex",
|
|
2492
|
+
"chatgpt-gpt-5.3-codex-spark",
|
|
2493
|
+
"chatgpt-gpt-5.2",
|
|
2494
|
+
"chatgpt-gpt-5.1-codex-mini"
|
|
2495
|
+
];
|
|
2496
|
+
function isChatGptModelId(value) {
|
|
2497
|
+
return CHATGPT_MODEL_IDS.includes(value);
|
|
2498
|
+
}
|
|
2499
|
+
function stripChatGptPrefix(model) {
|
|
2500
|
+
return model.slice("chatgpt-".length);
|
|
2251
2501
|
}
|
|
2252
2502
|
|
|
2253
2503
|
// src/llm.ts
|
|
@@ -2255,6 +2505,23 @@ var toolCallContextStorage = new AsyncLocalStorage();
|
|
|
2255
2505
|
function getCurrentToolCallContext() {
|
|
2256
2506
|
return toolCallContextStorage.getStore() ?? null;
|
|
2257
2507
|
}
|
|
2508
|
+
var LLM_TEXT_MODEL_IDS = [
|
|
2509
|
+
...OPENAI_MODEL_IDS,
|
|
2510
|
+
...CHATGPT_MODEL_IDS,
|
|
2511
|
+
...FIREWORKS_MODEL_IDS,
|
|
2512
|
+
...GEMINI_TEXT_MODEL_IDS
|
|
2513
|
+
];
|
|
2514
|
+
var LLM_IMAGE_MODEL_IDS = [...GEMINI_IMAGE_MODEL_IDS];
|
|
2515
|
+
var LLM_MODEL_IDS = [...LLM_TEXT_MODEL_IDS, ...LLM_IMAGE_MODEL_IDS];
|
|
2516
|
+
function isLlmTextModelId(value) {
|
|
2517
|
+
return isOpenAiModelId(value) || isChatGptModelId(value) || isFireworksModelId(value) || isGeminiTextModelId(value);
|
|
2518
|
+
}
|
|
2519
|
+
function isLlmImageModelId(value) {
|
|
2520
|
+
return isGeminiImageModelId(value);
|
|
2521
|
+
}
|
|
2522
|
+
function isLlmModelId(value) {
|
|
2523
|
+
return isLlmTextModelId(value) || isLlmImageModelId(value);
|
|
2524
|
+
}
|
|
2258
2525
|
var LlmJsonCallError = class extends Error {
|
|
2259
2526
|
constructor(message, attempts) {
|
|
2260
2527
|
super(message);
|
|
@@ -2612,17 +2879,22 @@ function convertLlmContentToGeminiContent(content) {
|
|
|
2612
2879
|
};
|
|
2613
2880
|
}
|
|
2614
2881
|
function resolveProvider(model) {
|
|
2615
|
-
if (model
|
|
2616
|
-
return { provider: "chatgpt", model: model
|
|
2882
|
+
if (isChatGptModelId(model)) {
|
|
2883
|
+
return { provider: "chatgpt", model: stripChatGptPrefix(model) };
|
|
2617
2884
|
}
|
|
2618
|
-
if (model
|
|
2885
|
+
if (isGeminiTextModelId(model) || isGeminiImageModelId(model)) {
|
|
2619
2886
|
return { provider: "gemini", model };
|
|
2620
2887
|
}
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2888
|
+
if (isFireworksModelId(model)) {
|
|
2889
|
+
const fireworksModel = resolveFireworksModelId(model);
|
|
2890
|
+
if (fireworksModel) {
|
|
2891
|
+
return { provider: "fireworks", model: fireworksModel };
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
if (isOpenAiModelId(model)) {
|
|
2895
|
+
return { provider: "openai", model };
|
|
2624
2896
|
}
|
|
2625
|
-
|
|
2897
|
+
throw new Error(`Unsupported text model: ${model}`);
|
|
2626
2898
|
}
|
|
2627
2899
|
function isOpenAiCodexModel(modelId) {
|
|
2628
2900
|
return modelId.includes("codex");
|
|
@@ -3964,7 +4236,7 @@ async function runTextCall(params) {
|
|
|
3964
4236
|
}
|
|
3965
4237
|
}
|
|
3966
4238
|
}
|
|
3967
|
-
});
|
|
4239
|
+
}, modelForProvider);
|
|
3968
4240
|
} else if (provider === "chatgpt") {
|
|
3969
4241
|
const chatGptInput = toChatGptInput(contents);
|
|
3970
4242
|
const reasoningEffort = resolveOpenAiReasoningEffort(
|
|
@@ -4059,7 +4331,7 @@ async function runTextCall(params) {
|
|
|
4059
4331
|
pushDelta("response", textOutput);
|
|
4060
4332
|
}
|
|
4061
4333
|
latestUsage = extractFireworksUsageTokens(response.usage);
|
|
4062
|
-
});
|
|
4334
|
+
}, modelForProvider);
|
|
4063
4335
|
} else {
|
|
4064
4336
|
const geminiContents = contents.map(convertLlmContentToGeminiContent);
|
|
4065
4337
|
const config = {
|
|
@@ -4127,7 +4399,7 @@ async function runTextCall(params) {
|
|
|
4127
4399
|
}
|
|
4128
4400
|
}
|
|
4129
4401
|
grounding = latestGrounding;
|
|
4130
|
-
});
|
|
4402
|
+
}, modelForProvider);
|
|
4131
4403
|
}
|
|
4132
4404
|
const mergedParts = mergeConsecutiveTextParts(responseParts);
|
|
4133
4405
|
const content = mergedParts.length > 0 ? { role: responseRole ?? "assistant", parts: mergedParts } : void 0;
|
|
@@ -4554,7 +4826,7 @@ async function runToolLoop(request) {
|
|
|
4554
4826
|
}
|
|
4555
4827
|
}
|
|
4556
4828
|
return await stream.finalResponse();
|
|
4557
|
-
});
|
|
4829
|
+
}, providerInfo.model);
|
|
4558
4830
|
modelVersion = typeof finalResponse.model === "string" ? finalResponse.model : request.model;
|
|
4559
4831
|
emitEvent({ type: "model", modelVersion });
|
|
4560
4832
|
if (finalResponse.error) {
|
|
@@ -4830,7 +5102,7 @@ async function runToolLoop(request) {
|
|
|
4830
5102
|
},
|
|
4831
5103
|
{ signal: request.signal }
|
|
4832
5104
|
);
|
|
4833
|
-
});
|
|
5105
|
+
}, providerInfo.model);
|
|
4834
5106
|
const modelVersion = typeof response.model === "string" ? response.model : request.model;
|
|
4835
5107
|
request.onEvent?.({ type: "model", modelVersion });
|
|
4836
5108
|
const choice = Array.isArray(response.choices) ? response.choices[0] : void 0;
|
|
@@ -5027,7 +5299,7 @@ async function runToolLoop(request) {
|
|
|
5027
5299
|
usageMetadata: latestUsageMetadata,
|
|
5028
5300
|
modelVersion: resolvedModelVersion ?? request.model
|
|
5029
5301
|
};
|
|
5030
|
-
});
|
|
5302
|
+
}, request.model);
|
|
5031
5303
|
const usageTokens = extractGeminiUsageTokens(response.usageMetadata);
|
|
5032
5304
|
const modelVersion = response.modelVersion ?? request.model;
|
|
5033
5305
|
const stepCostUsd = estimateCallCostUsd({
|
|
@@ -5365,13 +5637,630 @@ function appendMarkdownSourcesSection(value, sources) {
|
|
|
5365
5637
|
${lines}`;
|
|
5366
5638
|
}
|
|
5367
5639
|
|
|
5640
|
+
// src/agent/subagents.ts
|
|
5641
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
5642
|
+
import { z as z4 } from "zod";
|
|
5643
|
+
var DEFAULT_SUBAGENT_MAX_AGENTS = 4;
|
|
5644
|
+
var DEFAULT_SUBAGENT_MAX_DEPTH = 2;
|
|
5645
|
+
var DEFAULT_SUBAGENT_WAIT_TIMEOUT_MS = 1500;
|
|
5646
|
+
var DEFAULT_SUBAGENT_MAX_WAIT_TIMEOUT_MS = 9e4;
|
|
5647
|
+
var MAX_SUBAGENT_MAX_AGENTS = 64;
|
|
5648
|
+
var MAX_SUBAGENT_MAX_DEPTH = 12;
|
|
5649
|
+
var MAX_SUBAGENT_MAX_STEPS = 64;
|
|
5650
|
+
var MAX_SUBAGENT_WAIT_TIMEOUT_MS = 6e5;
|
|
5651
|
+
var SUBAGENT_CONTROL_TOOL_NAMES = ["send_input", "resume_agent", "wait", "close_agent"];
|
|
5652
|
+
var subagentInputItemSchema = z4.object({
|
|
5653
|
+
text: z4.string().optional(),
|
|
5654
|
+
image_url: z4.string().optional(),
|
|
5655
|
+
name: z4.string().optional(),
|
|
5656
|
+
path: z4.string().optional(),
|
|
5657
|
+
type: z4.string().optional()
|
|
5658
|
+
}).passthrough();
|
|
5659
|
+
var spawnAgentInputSchema = z4.object({
|
|
5660
|
+
prompt: z4.string().optional().describe("Initial prompt for the subagent."),
|
|
5661
|
+
message: z4.string().optional().describe("Codex-style alias for prompt."),
|
|
5662
|
+
items: z4.array(subagentInputItemSchema).optional().describe("Optional Codex-style input items."),
|
|
5663
|
+
agent_type: z4.string().optional().describe("Codex-style agent type hint."),
|
|
5664
|
+
instructions: z4.string().optional().describe("Optional extra instructions for this subagent instance."),
|
|
5665
|
+
model: z4.string().optional().describe("Optional model override. Must be one of this package's supported text model ids."),
|
|
5666
|
+
max_steps: z4.number().int().min(1).max(MAX_SUBAGENT_MAX_STEPS).optional().describe("Optional max step budget for each subagent run.")
|
|
5667
|
+
}).refine((value) => Boolean(resolvePromptValue(value.prompt, value.message, value.items)), {
|
|
5668
|
+
message: "Either prompt, message, or items must contain non-empty input."
|
|
5669
|
+
});
|
|
5670
|
+
var sendInputSchema = z4.object({
|
|
5671
|
+
agent_id: z4.string().optional().describe("Target subagent id."),
|
|
5672
|
+
id: z4.string().optional().describe("Codex-style alias for agent_id."),
|
|
5673
|
+
input: z4.string().optional().describe("New user input queued for the subagent."),
|
|
5674
|
+
message: z4.string().optional().describe("Codex-style alias for input."),
|
|
5675
|
+
items: z4.array(subagentInputItemSchema).optional().describe("Optional Codex-style input items."),
|
|
5676
|
+
interrupt: z4.boolean().optional().describe("If true and currently running, aborts active run before queuing input.")
|
|
5677
|
+
}).refine((value) => Boolean(resolveAgentIdValue(value.agent_id, value.id)), {
|
|
5678
|
+
message: "agent_id (or id) is required."
|
|
5679
|
+
}).refine((value) => Boolean(resolvePromptValue(value.input, value.message, value.items)), {
|
|
5680
|
+
message: "input (or message/items) is required."
|
|
5681
|
+
});
|
|
5682
|
+
var resumeAgentSchema = z4.object({
|
|
5683
|
+
agent_id: z4.string().optional().describe("Target subagent id."),
|
|
5684
|
+
id: z4.string().optional().describe("Codex-style alias for agent_id.")
|
|
5685
|
+
}).refine((value) => Boolean(resolveAgentIdValue(value.agent_id, value.id)), {
|
|
5686
|
+
message: "agent_id (or id) is required."
|
|
5687
|
+
});
|
|
5688
|
+
var waitSchema = z4.object({
|
|
5689
|
+
agent_id: z4.string().optional().describe("Target subagent id."),
|
|
5690
|
+
id: z4.string().optional().describe("Codex-style alias for agent_id."),
|
|
5691
|
+
ids: z4.array(z4.string().min(1)).optional().describe("Codex-style list of agent ids."),
|
|
5692
|
+
timeout_ms: z4.number().int().min(1).optional().describe("Optional wait timeout in milliseconds.")
|
|
5693
|
+
}).refine(
|
|
5694
|
+
(value) => Boolean(resolveAgentIdValue(value.agent_id, value.id)) || Array.isArray(value.ids) && value.ids.length > 0,
|
|
5695
|
+
{
|
|
5696
|
+
message: "agent_id/id or ids is required."
|
|
5697
|
+
}
|
|
5698
|
+
);
|
|
5699
|
+
var closeSchema = z4.object({
|
|
5700
|
+
agent_id: z4.string().optional().describe("Target subagent id."),
|
|
5701
|
+
id: z4.string().optional().describe("Codex-style alias for agent_id.")
|
|
5702
|
+
}).refine((value) => Boolean(resolveAgentIdValue(value.agent_id, value.id)), {
|
|
5703
|
+
message: "agent_id (or id) is required."
|
|
5704
|
+
});
|
|
5705
|
+
function resolveSubagentToolConfig(selection, currentDepth) {
|
|
5706
|
+
const defaults = {
|
|
5707
|
+
maxAgents: DEFAULT_SUBAGENT_MAX_AGENTS,
|
|
5708
|
+
maxDepth: DEFAULT_SUBAGENT_MAX_DEPTH,
|
|
5709
|
+
defaultWaitTimeoutMs: DEFAULT_SUBAGENT_WAIT_TIMEOUT_MS,
|
|
5710
|
+
maxWaitTimeoutMs: DEFAULT_SUBAGENT_MAX_WAIT_TIMEOUT_MS,
|
|
5711
|
+
promptPattern: "codex",
|
|
5712
|
+
inheritTools: true,
|
|
5713
|
+
inheritFilesystemTool: true
|
|
5714
|
+
};
|
|
5715
|
+
if (selection === void 0 || selection === false) {
|
|
5716
|
+
return {
|
|
5717
|
+
enabled: false,
|
|
5718
|
+
...defaults
|
|
5719
|
+
};
|
|
5720
|
+
}
|
|
5721
|
+
const config = selection === true ? {} : selection;
|
|
5722
|
+
const maxAgents = normalizeInteger(
|
|
5723
|
+
config.maxAgents,
|
|
5724
|
+
defaults.maxAgents,
|
|
5725
|
+
1,
|
|
5726
|
+
MAX_SUBAGENT_MAX_AGENTS
|
|
5727
|
+
);
|
|
5728
|
+
const maxDepth = normalizeInteger(config.maxDepth, defaults.maxDepth, 1, MAX_SUBAGENT_MAX_DEPTH);
|
|
5729
|
+
const defaultWaitTimeoutMs = normalizeInteger(
|
|
5730
|
+
config.defaultWaitTimeoutMs,
|
|
5731
|
+
defaults.defaultWaitTimeoutMs,
|
|
5732
|
+
1,
|
|
5733
|
+
MAX_SUBAGENT_WAIT_TIMEOUT_MS
|
|
5734
|
+
);
|
|
5735
|
+
const maxWaitTimeoutMs = normalizeInteger(
|
|
5736
|
+
config.maxWaitTimeoutMs,
|
|
5737
|
+
defaults.maxWaitTimeoutMs,
|
|
5738
|
+
defaultWaitTimeoutMs,
|
|
5739
|
+
MAX_SUBAGENT_WAIT_TIMEOUT_MS
|
|
5740
|
+
);
|
|
5741
|
+
const promptPattern = config.promptPattern ?? defaults.promptPattern;
|
|
5742
|
+
const instructions = trimToUndefined(config.instructions);
|
|
5743
|
+
const maxSteps = normalizeOptionalInteger(config.maxSteps, 1, MAX_SUBAGENT_MAX_STEPS);
|
|
5744
|
+
const enabled = config.enabled !== false && currentDepth < maxDepth;
|
|
5745
|
+
return {
|
|
5746
|
+
enabled,
|
|
5747
|
+
maxAgents,
|
|
5748
|
+
maxDepth,
|
|
5749
|
+
defaultWaitTimeoutMs,
|
|
5750
|
+
maxWaitTimeoutMs,
|
|
5751
|
+
promptPattern,
|
|
5752
|
+
...instructions ? { instructions } : {},
|
|
5753
|
+
...config.model ? { model: config.model } : {},
|
|
5754
|
+
...maxSteps ? { maxSteps } : {},
|
|
5755
|
+
inheritTools: config.inheritTools !== false,
|
|
5756
|
+
inheritFilesystemTool: config.inheritFilesystemTool !== false
|
|
5757
|
+
};
|
|
5758
|
+
}
|
|
5759
|
+
function buildCodexSubagentOrchestratorInstructions(params) {
|
|
5760
|
+
return [
|
|
5761
|
+
"Subagent orchestration tools are available: spawn_agent, send_input, resume_agent, wait, close_agent.",
|
|
5762
|
+
"Use this control pattern:",
|
|
5763
|
+
"1. spawn_agent with a focused prompt.",
|
|
5764
|
+
"2. wait on that agent_id until it is no longer running.",
|
|
5765
|
+
"3. For follow-up turns, send_input then resume_agent.",
|
|
5766
|
+
"4. close_agent when delegation is complete.",
|
|
5767
|
+
`Limits: max active subagents ${params.maxAgents}, max depth ${params.maxDepth}, current depth ${params.currentDepth}.`
|
|
5768
|
+
].join("\n");
|
|
5769
|
+
}
|
|
5770
|
+
function buildCodexSubagentWorkerInstructions(params) {
|
|
5771
|
+
return [
|
|
5772
|
+
`You are a delegated subagent at depth ${params.depth}/${params.maxDepth}.`,
|
|
5773
|
+
"Focus on the delegated task, use available tools when needed, and return concise actionable output.",
|
|
5774
|
+
"If blocked, report the blocker explicitly."
|
|
5775
|
+
].join("\n");
|
|
5776
|
+
}
|
|
5777
|
+
function createSubagentToolController(options) {
|
|
5778
|
+
if (!options.config.enabled) {
|
|
5779
|
+
return {
|
|
5780
|
+
tools: {},
|
|
5781
|
+
closeAll: async () => {
|
|
5782
|
+
}
|
|
5783
|
+
};
|
|
5784
|
+
}
|
|
5785
|
+
const agents = /* @__PURE__ */ new Map();
|
|
5786
|
+
const tools = {
|
|
5787
|
+
spawn_agent: tool({
|
|
5788
|
+
description: "Spawns a subagent asynchronously. Returns immediately with agent status and id.",
|
|
5789
|
+
inputSchema: spawnAgentInputSchema,
|
|
5790
|
+
execute: async (input) => {
|
|
5791
|
+
if (countActiveAgents(agents) >= options.config.maxAgents) {
|
|
5792
|
+
throw new Error(
|
|
5793
|
+
`Subagent limit reached (${options.config.maxAgents}). Close existing agents before spawning new ones.`
|
|
5794
|
+
);
|
|
5795
|
+
}
|
|
5796
|
+
const childDepth = options.parentDepth + 1;
|
|
5797
|
+
if (childDepth > options.config.maxDepth) {
|
|
5798
|
+
throw new Error(
|
|
5799
|
+
`Subagent depth limit reached (${options.config.maxDepth}). Cannot spawn at depth ${childDepth}.`
|
|
5800
|
+
);
|
|
5801
|
+
}
|
|
5802
|
+
let model = options.config.model ?? options.parentModel;
|
|
5803
|
+
if (input.model) {
|
|
5804
|
+
if (!isLlmTextModelId(input.model)) {
|
|
5805
|
+
throw new Error(`Unsupported subagent model id: ${input.model}`);
|
|
5806
|
+
}
|
|
5807
|
+
model = input.model;
|
|
5808
|
+
}
|
|
5809
|
+
const id = `agent_${randomBytes2(6).toString("hex")}`;
|
|
5810
|
+
const now = Date.now();
|
|
5811
|
+
const initialPrompt = resolvePromptValue(input.prompt, input.message, input.items);
|
|
5812
|
+
if (!initialPrompt) {
|
|
5813
|
+
throw new Error("spawn_agent requires prompt/message/items with non-empty text.");
|
|
5814
|
+
}
|
|
5815
|
+
const agent = {
|
|
5816
|
+
id,
|
|
5817
|
+
depth: childDepth,
|
|
5818
|
+
model,
|
|
5819
|
+
status: "idle",
|
|
5820
|
+
createdAtMs: now,
|
|
5821
|
+
updatedAtMs: now,
|
|
5822
|
+
pendingInputs: [initialPrompt],
|
|
5823
|
+
history: [],
|
|
5824
|
+
...options.buildChildInstructions ? {
|
|
5825
|
+
instructions: trimToUndefined(
|
|
5826
|
+
options.buildChildInstructions(input.instructions, childDepth)
|
|
5827
|
+
)
|
|
5828
|
+
} : input.instructions ? { instructions: trimToUndefined(input.instructions) } : {},
|
|
5829
|
+
...input.max_steps ? { maxSteps: input.max_steps } : options.config.maxSteps ? { maxSteps: options.config.maxSteps } : {},
|
|
5830
|
+
turns: 0,
|
|
5831
|
+
notification: "spawned",
|
|
5832
|
+
notificationMessage: `Spawned subagent ${id}.`,
|
|
5833
|
+
version: 1,
|
|
5834
|
+
waiters: /* @__PURE__ */ new Set()
|
|
5835
|
+
};
|
|
5836
|
+
agents.set(id, agent);
|
|
5837
|
+
startRun(agent, options);
|
|
5838
|
+
return buildToolResponse(agent, {
|
|
5839
|
+
notification: "spawned",
|
|
5840
|
+
message: `Spawned subagent ${id}.`
|
|
5841
|
+
});
|
|
5842
|
+
}
|
|
5843
|
+
}),
|
|
5844
|
+
send_input: tool({
|
|
5845
|
+
description: "Queues new input for an existing subagent.",
|
|
5846
|
+
inputSchema: sendInputSchema,
|
|
5847
|
+
execute: async (input) => {
|
|
5848
|
+
const agentId = resolveAgentIdValue(input.agent_id, input.id);
|
|
5849
|
+
if (!agentId) {
|
|
5850
|
+
throw new Error("send_input requires agent_id or id.");
|
|
5851
|
+
}
|
|
5852
|
+
const agent = requireAgent(agents, agentId);
|
|
5853
|
+
const nextInput = resolvePromptValue(input.input, input.message, input.items);
|
|
5854
|
+
if (!nextInput) {
|
|
5855
|
+
throw new Error("send_input requires input/message/items with non-empty text.");
|
|
5856
|
+
}
|
|
5857
|
+
if (agent.status === "closed") {
|
|
5858
|
+
throw new Error(`Subagent ${agent.id} is closed.`);
|
|
5859
|
+
}
|
|
5860
|
+
if (input.interrupt && agent.abortController) {
|
|
5861
|
+
agent.abortController.abort("send_input_interrupt");
|
|
5862
|
+
agent.pendingInputs.unshift(nextInput);
|
|
5863
|
+
setNotification(agent, "input_queued", `Interrupted ${agent.id} and queued new input.`);
|
|
5864
|
+
return buildToolResponse(agent);
|
|
5865
|
+
}
|
|
5866
|
+
agent.pendingInputs.push(nextInput);
|
|
5867
|
+
setNotification(agent, "input_queued", `Queued input for ${agent.id}.`);
|
|
5868
|
+
return buildToolResponse(agent);
|
|
5869
|
+
}
|
|
5870
|
+
}),
|
|
5871
|
+
resume_agent: tool({
|
|
5872
|
+
description: "Resumes a subagent run when queued input is available.",
|
|
5873
|
+
inputSchema: resumeAgentSchema,
|
|
5874
|
+
execute: async (input) => {
|
|
5875
|
+
const agentId = resolveAgentIdValue(input.agent_id, input.id);
|
|
5876
|
+
if (!agentId) {
|
|
5877
|
+
throw new Error("resume_agent requires agent_id or id.");
|
|
5878
|
+
}
|
|
5879
|
+
const agent = requireAgent(agents, agentId);
|
|
5880
|
+
if (agent.status === "closed") {
|
|
5881
|
+
setNotification(agent, "already_closed", `Subagent ${agent.id} is already closed.`);
|
|
5882
|
+
return buildToolResponse(agent, {
|
|
5883
|
+
notification: "already_closed",
|
|
5884
|
+
message: `Subagent ${agent.id} is already closed.`
|
|
5885
|
+
});
|
|
5886
|
+
}
|
|
5887
|
+
const outcome = startRun(agent, options);
|
|
5888
|
+
if (outcome === "started") {
|
|
5889
|
+
return buildToolResponse(agent, {
|
|
5890
|
+
notification: "run_started",
|
|
5891
|
+
message: `Started subagent ${agent.id}.`
|
|
5892
|
+
});
|
|
5893
|
+
}
|
|
5894
|
+
if (outcome === "already_running") {
|
|
5895
|
+
setNotification(agent, "already_running", `Subagent ${agent.id} is already running.`);
|
|
5896
|
+
return buildToolResponse(agent);
|
|
5897
|
+
}
|
|
5898
|
+
setNotification(agent, "no_pending_input", `Subagent ${agent.id} has no queued input.`);
|
|
5899
|
+
return buildToolResponse(agent);
|
|
5900
|
+
}
|
|
5901
|
+
}),
|
|
5902
|
+
wait: tool({
|
|
5903
|
+
description: "Waits for a running subagent to change state or until timeout. Returns current status.",
|
|
5904
|
+
inputSchema: waitSchema,
|
|
5905
|
+
execute: async (input) => {
|
|
5906
|
+
const usesIdsArray = Array.isArray(input.ids) && input.ids.length > 0;
|
|
5907
|
+
const ids = resolveAgentIdList(input.agent_id, input.id, input.ids);
|
|
5908
|
+
if (ids.length === 0) {
|
|
5909
|
+
throw new Error("wait requires agent_id/id or ids.");
|
|
5910
|
+
}
|
|
5911
|
+
const timeoutMs = normalizeInteger(
|
|
5912
|
+
input.timeout_ms,
|
|
5913
|
+
options.config.defaultWaitTimeoutMs,
|
|
5914
|
+
1,
|
|
5915
|
+
options.config.maxWaitTimeoutMs
|
|
5916
|
+
);
|
|
5917
|
+
if (usesIdsArray) {
|
|
5918
|
+
const status = await waitForAnyAgentStatus(agents, ids, timeoutMs);
|
|
5919
|
+
return { status, timed_out: Object.keys(status).length === 0, timeout_ms: timeoutMs };
|
|
5920
|
+
}
|
|
5921
|
+
const agent = requireAgent(agents, ids[0]);
|
|
5922
|
+
if (agent.status === "running") {
|
|
5923
|
+
const completed = await waitUntilNotRunning(agent, timeoutMs);
|
|
5924
|
+
if (!completed) {
|
|
5925
|
+
setNotification(
|
|
5926
|
+
agent,
|
|
5927
|
+
"timeout",
|
|
5928
|
+
`Timed out after ${timeoutMs}ms while waiting for ${agent.id}.`
|
|
5929
|
+
);
|
|
5930
|
+
return buildToolResponse(agent, void 0, { timed_out: true, timeout_ms: timeoutMs });
|
|
5931
|
+
}
|
|
5932
|
+
}
|
|
5933
|
+
return buildToolResponse(agent, void 0, { timed_out: false, timeout_ms: timeoutMs });
|
|
5934
|
+
}
|
|
5935
|
+
}),
|
|
5936
|
+
close_agent: tool({
|
|
5937
|
+
description: "Closes a subagent and aborts its current run if it is still running.",
|
|
5938
|
+
inputSchema: closeSchema,
|
|
5939
|
+
execute: async (input) => {
|
|
5940
|
+
const agentId = resolveAgentIdValue(input.agent_id, input.id);
|
|
5941
|
+
if (!agentId) {
|
|
5942
|
+
throw new Error("close_agent requires agent_id or id.");
|
|
5943
|
+
}
|
|
5944
|
+
const agent = requireAgent(agents, agentId);
|
|
5945
|
+
if (agent.status === "closed") {
|
|
5946
|
+
setNotification(agent, "already_closed", `Subagent ${agent.id} is already closed.`);
|
|
5947
|
+
return buildToolResponse(agent, void 0, { cancelled: false });
|
|
5948
|
+
}
|
|
5949
|
+
const cancelled = closeSubagent(agent, `Closed ${agent.id}.`);
|
|
5950
|
+
return buildToolResponse(
|
|
5951
|
+
agent,
|
|
5952
|
+
{ notification: "closed", message: `Closed ${agent.id}.` },
|
|
5953
|
+
{ cancelled }
|
|
5954
|
+
);
|
|
5955
|
+
}
|
|
5956
|
+
})
|
|
5957
|
+
};
|
|
5958
|
+
return {
|
|
5959
|
+
tools,
|
|
5960
|
+
closeAll: async () => {
|
|
5961
|
+
const running = [];
|
|
5962
|
+
for (const agent of agents.values()) {
|
|
5963
|
+
if (agent.status !== "closed") {
|
|
5964
|
+
closeSubagent(agent, `Parent agent loop closed ${agent.id}.`);
|
|
5965
|
+
}
|
|
5966
|
+
if (agent.runningPromise) {
|
|
5967
|
+
running.push(agent.runningPromise);
|
|
5968
|
+
}
|
|
5969
|
+
}
|
|
5970
|
+
if (running.length > 0) {
|
|
5971
|
+
await Promise.race([Promise.allSettled(running), sleep2(2e3)]);
|
|
5972
|
+
}
|
|
5973
|
+
}
|
|
5974
|
+
};
|
|
5975
|
+
}
|
|
5976
|
+
function requireAgent(agents, id) {
|
|
5977
|
+
const agent = agents.get(id);
|
|
5978
|
+
if (!agent) {
|
|
5979
|
+
throw new Error(`Unknown subagent id: ${id}`);
|
|
5980
|
+
}
|
|
5981
|
+
return agent;
|
|
5982
|
+
}
|
|
5983
|
+
function resolveAgentIdValue(agentId, idAlias) {
|
|
5984
|
+
const preferred = agentId?.trim();
|
|
5985
|
+
if (preferred) {
|
|
5986
|
+
return preferred;
|
|
5987
|
+
}
|
|
5988
|
+
const alias = idAlias?.trim();
|
|
5989
|
+
return alias ?? "";
|
|
5990
|
+
}
|
|
5991
|
+
function resolveAgentIdList(agentId, idAlias, ids) {
|
|
5992
|
+
if (Array.isArray(ids) && ids.length > 0) {
|
|
5993
|
+
return [...new Set(ids.map((value) => value.trim()).filter(Boolean))];
|
|
5994
|
+
}
|
|
5995
|
+
const single = resolveAgentIdValue(agentId, idAlias);
|
|
5996
|
+
return single ? [single] : [];
|
|
5997
|
+
}
|
|
5998
|
+
function resolvePromptValue(prompt, message, items) {
|
|
5999
|
+
const promptValue = prompt?.trim();
|
|
6000
|
+
if (promptValue) {
|
|
6001
|
+
return promptValue;
|
|
6002
|
+
}
|
|
6003
|
+
const messageValue = message?.trim();
|
|
6004
|
+
if (messageValue) {
|
|
6005
|
+
return messageValue;
|
|
6006
|
+
}
|
|
6007
|
+
const itemText = resolveInputItemsText(items);
|
|
6008
|
+
return itemText ?? "";
|
|
6009
|
+
}
|
|
6010
|
+
function resolveInputItemsText(items) {
|
|
6011
|
+
if (!items || items.length === 0) {
|
|
6012
|
+
return void 0;
|
|
6013
|
+
}
|
|
6014
|
+
const lines = [];
|
|
6015
|
+
for (const item of items) {
|
|
6016
|
+
if (typeof item.text === "string" && item.text.trim().length > 0) {
|
|
6017
|
+
lines.push(item.text.trim());
|
|
6018
|
+
continue;
|
|
6019
|
+
}
|
|
6020
|
+
const itemType = typeof item.type === "string" ? item.type.trim() : "";
|
|
6021
|
+
const name = typeof item.name === "string" ? item.name.trim() : "";
|
|
6022
|
+
const path6 = typeof item.path === "string" ? item.path.trim() : "";
|
|
6023
|
+
const imageUrl = typeof item.image_url === "string" ? item.image_url.trim() : "";
|
|
6024
|
+
const compact = [itemType, name, path6 || imageUrl].filter(Boolean).join(" ");
|
|
6025
|
+
if (compact) {
|
|
6026
|
+
lines.push(compact);
|
|
6027
|
+
}
|
|
6028
|
+
}
|
|
6029
|
+
if (lines.length === 0) {
|
|
6030
|
+
return void 0;
|
|
6031
|
+
}
|
|
6032
|
+
return lines.join("\n");
|
|
6033
|
+
}
|
|
6034
|
+
function countActiveAgents(agents) {
|
|
6035
|
+
let count = 0;
|
|
6036
|
+
for (const agent of agents.values()) {
|
|
6037
|
+
if (agent.status !== "closed") {
|
|
6038
|
+
count += 1;
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
return count;
|
|
6042
|
+
}
|
|
6043
|
+
async function waitForAnyAgentStatus(agents, ids, timeoutMs) {
|
|
6044
|
+
const requested = ids.map((id) => requireAgent(agents, id));
|
|
6045
|
+
const deadline = Date.now() + timeoutMs;
|
|
6046
|
+
while (true) {
|
|
6047
|
+
const status = {};
|
|
6048
|
+
for (const agent of requested) {
|
|
6049
|
+
if (agent.status !== "running") {
|
|
6050
|
+
status[agent.id] = buildSnapshot(agent);
|
|
6051
|
+
}
|
|
6052
|
+
}
|
|
6053
|
+
if (Object.keys(status).length > 0) {
|
|
6054
|
+
return status;
|
|
6055
|
+
}
|
|
6056
|
+
const remaining = deadline - Date.now();
|
|
6057
|
+
if (remaining <= 0) {
|
|
6058
|
+
return {};
|
|
6059
|
+
}
|
|
6060
|
+
await Promise.race(
|
|
6061
|
+
requested.map(async (agent) => {
|
|
6062
|
+
const changed = await waitForVersionChange(agent, agent.version, remaining);
|
|
6063
|
+
if (!changed) {
|
|
6064
|
+
return;
|
|
6065
|
+
}
|
|
6066
|
+
})
|
|
6067
|
+
);
|
|
6068
|
+
}
|
|
6069
|
+
}
|
|
6070
|
+
function setNotification(agent, notification, message) {
|
|
6071
|
+
agent.notification = notification;
|
|
6072
|
+
agent.notificationMessage = message;
|
|
6073
|
+
agent.updatedAtMs = Date.now();
|
|
6074
|
+
agent.version += 1;
|
|
6075
|
+
notifyWaiters(agent);
|
|
6076
|
+
}
|
|
6077
|
+
function setLifecycle(agent, status, notification, message) {
|
|
6078
|
+
agent.status = status;
|
|
6079
|
+
setNotification(agent, notification, message);
|
|
6080
|
+
}
|
|
6081
|
+
function notifyWaiters(agent) {
|
|
6082
|
+
if (agent.waiters.size === 0) {
|
|
6083
|
+
return;
|
|
6084
|
+
}
|
|
6085
|
+
const waiters = [...agent.waiters];
|
|
6086
|
+
agent.waiters.clear();
|
|
6087
|
+
for (const notify of waiters) {
|
|
6088
|
+
notify();
|
|
6089
|
+
}
|
|
6090
|
+
}
|
|
6091
|
+
function startRun(agent, options) {
|
|
6092
|
+
if (agent.runningPromise) {
|
|
6093
|
+
return "already_running";
|
|
6094
|
+
}
|
|
6095
|
+
const nextInput = agent.pendingInputs.shift();
|
|
6096
|
+
if (!nextInput) {
|
|
6097
|
+
return "no_pending_input";
|
|
6098
|
+
}
|
|
6099
|
+
const input = [...agent.history, { role: "user", content: nextInput }];
|
|
6100
|
+
const abortController = new AbortController();
|
|
6101
|
+
agent.abortController = abortController;
|
|
6102
|
+
agent.lastError = void 0;
|
|
6103
|
+
setLifecycle(
|
|
6104
|
+
agent,
|
|
6105
|
+
"running",
|
|
6106
|
+
"run_started",
|
|
6107
|
+
`Subagent ${agent.id} started run ${agent.turns + 1}.`
|
|
6108
|
+
);
|
|
6109
|
+
const runPromise = (async () => {
|
|
6110
|
+
try {
|
|
6111
|
+
const result = await options.runSubagent({
|
|
6112
|
+
agentId: agent.id,
|
|
6113
|
+
depth: agent.depth,
|
|
6114
|
+
model: agent.model,
|
|
6115
|
+
input,
|
|
6116
|
+
instructions: agent.instructions,
|
|
6117
|
+
maxSteps: agent.maxSteps,
|
|
6118
|
+
signal: abortController.signal
|
|
6119
|
+
});
|
|
6120
|
+
if (agent.status === "closed") {
|
|
6121
|
+
return;
|
|
6122
|
+
}
|
|
6123
|
+
agent.lastResult = result;
|
|
6124
|
+
agent.lastError = void 0;
|
|
6125
|
+
agent.turns += 1;
|
|
6126
|
+
agent.history = [...input, { role: "assistant", content: result.text }];
|
|
6127
|
+
setLifecycle(
|
|
6128
|
+
agent,
|
|
6129
|
+
"idle",
|
|
6130
|
+
"run_completed",
|
|
6131
|
+
`Subagent ${agent.id} completed run ${agent.turns}.`
|
|
6132
|
+
);
|
|
6133
|
+
} catch (error) {
|
|
6134
|
+
if (agent.status === "closed") {
|
|
6135
|
+
return;
|
|
6136
|
+
}
|
|
6137
|
+
if (abortController.signal.aborted) {
|
|
6138
|
+
setLifecycle(agent, "idle", "input_queued", `Subagent ${agent.id} run interrupted.`);
|
|
6139
|
+
return;
|
|
6140
|
+
}
|
|
6141
|
+
const message = toErrorMessage(error);
|
|
6142
|
+
agent.lastError = message;
|
|
6143
|
+
setLifecycle(agent, "failed", "run_failed", `Subagent ${agent.id} failed: ${message}`);
|
|
6144
|
+
} finally {
|
|
6145
|
+
agent.runningPromise = void 0;
|
|
6146
|
+
agent.abortController = void 0;
|
|
6147
|
+
}
|
|
6148
|
+
})();
|
|
6149
|
+
agent.runningPromise = runPromise;
|
|
6150
|
+
return "started";
|
|
6151
|
+
}
|
|
6152
|
+
function closeSubagent(agent, message) {
|
|
6153
|
+
const cancelled = Boolean(agent.runningPromise);
|
|
6154
|
+
agent.pendingInputs = [];
|
|
6155
|
+
if (agent.abortController) {
|
|
6156
|
+
agent.abortController.abort("close_agent");
|
|
6157
|
+
}
|
|
6158
|
+
setLifecycle(agent, "closed", "closed", message);
|
|
6159
|
+
return cancelled;
|
|
6160
|
+
}
|
|
6161
|
+
async function waitUntilNotRunning(agent, timeoutMs) {
|
|
6162
|
+
const deadline = Date.now() + timeoutMs;
|
|
6163
|
+
while (agent.status === "running") {
|
|
6164
|
+
const remaining = deadline - Date.now();
|
|
6165
|
+
if (remaining <= 0) {
|
|
6166
|
+
return false;
|
|
6167
|
+
}
|
|
6168
|
+
const currentVersion = agent.version;
|
|
6169
|
+
const changed = await waitForVersionChange(agent, currentVersion, remaining);
|
|
6170
|
+
if (!changed) {
|
|
6171
|
+
return false;
|
|
6172
|
+
}
|
|
6173
|
+
}
|
|
6174
|
+
return true;
|
|
6175
|
+
}
|
|
6176
|
+
async function waitForVersionChange(agent, version, timeoutMs) {
|
|
6177
|
+
if (agent.version !== version) {
|
|
6178
|
+
return true;
|
|
6179
|
+
}
|
|
6180
|
+
return await new Promise((resolve) => {
|
|
6181
|
+
const waiter = () => {
|
|
6182
|
+
cleanup();
|
|
6183
|
+
resolve(true);
|
|
6184
|
+
};
|
|
6185
|
+
const timeout = setTimeout(() => {
|
|
6186
|
+
cleanup();
|
|
6187
|
+
resolve(false);
|
|
6188
|
+
}, timeoutMs);
|
|
6189
|
+
const cleanup = () => {
|
|
6190
|
+
clearTimeout(timeout);
|
|
6191
|
+
agent.waiters.delete(waiter);
|
|
6192
|
+
};
|
|
6193
|
+
agent.waiters.add(waiter);
|
|
6194
|
+
});
|
|
6195
|
+
}
|
|
6196
|
+
function buildToolResponse(agent, override, extra = {}) {
|
|
6197
|
+
const notification = override?.notification ?? agent.notification;
|
|
6198
|
+
const message = override?.message ?? agent.notificationMessage;
|
|
6199
|
+
const snapshot = buildSnapshot(agent);
|
|
6200
|
+
return {
|
|
6201
|
+
agent_id: snapshot.agent_id,
|
|
6202
|
+
notification,
|
|
6203
|
+
message,
|
|
6204
|
+
status: snapshot.status,
|
|
6205
|
+
agent: snapshot,
|
|
6206
|
+
tool_availability: snapshot.status === "closed" ? [] : [...SUBAGENT_CONTROL_TOOL_NAMES],
|
|
6207
|
+
...extra
|
|
6208
|
+
};
|
|
6209
|
+
}
|
|
6210
|
+
function buildSnapshot(agent) {
|
|
6211
|
+
return {
|
|
6212
|
+
agent_id: agent.id,
|
|
6213
|
+
status: agent.status,
|
|
6214
|
+
depth: agent.depth,
|
|
6215
|
+
model: agent.model,
|
|
6216
|
+
pending_inputs: agent.pendingInputs.length,
|
|
6217
|
+
turns: agent.turns,
|
|
6218
|
+
created_at: new Date(agent.createdAtMs).toISOString(),
|
|
6219
|
+
updated_at: new Date(agent.updatedAtMs).toISOString(),
|
|
6220
|
+
...agent.lastError ? { last_error: agent.lastError } : {},
|
|
6221
|
+
...agent.lastResult ? {
|
|
6222
|
+
last_result: {
|
|
6223
|
+
text: agent.lastResult.text,
|
|
6224
|
+
thoughts: agent.lastResult.thoughts,
|
|
6225
|
+
step_count: agent.lastResult.steps.length,
|
|
6226
|
+
total_cost_usd: agent.lastResult.totalCostUsd
|
|
6227
|
+
}
|
|
6228
|
+
} : {}
|
|
6229
|
+
};
|
|
6230
|
+
}
|
|
6231
|
+
function normalizeInteger(value, fallback, min, max) {
|
|
6232
|
+
const parsed = Number.isFinite(value) ? Math.floor(value) : fallback;
|
|
6233
|
+
return Math.max(min, Math.min(max, parsed));
|
|
6234
|
+
}
|
|
6235
|
+
function normalizeOptionalInteger(value, min, max) {
|
|
6236
|
+
if (!Number.isFinite(value)) {
|
|
6237
|
+
return void 0;
|
|
6238
|
+
}
|
|
6239
|
+
return Math.max(min, Math.min(max, Math.floor(value)));
|
|
6240
|
+
}
|
|
6241
|
+
function trimToUndefined(value) {
|
|
6242
|
+
const trimmed = value?.trim();
|
|
6243
|
+
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
6244
|
+
}
|
|
6245
|
+
function toErrorMessage(error) {
|
|
6246
|
+
if (error instanceof Error) {
|
|
6247
|
+
return error.message;
|
|
6248
|
+
}
|
|
6249
|
+
return String(error);
|
|
6250
|
+
}
|
|
6251
|
+
function sleep2(ms) {
|
|
6252
|
+
return new Promise((resolve) => {
|
|
6253
|
+
setTimeout(resolve, ms);
|
|
6254
|
+
});
|
|
6255
|
+
}
|
|
6256
|
+
|
|
5368
6257
|
// src/tools/filesystemTools.ts
|
|
5369
6258
|
import path5 from "path";
|
|
5370
|
-
import { z as
|
|
6259
|
+
import { z as z6 } from "zod";
|
|
5371
6260
|
|
|
5372
6261
|
// src/tools/applyPatch.ts
|
|
5373
6262
|
import path4 from "path";
|
|
5374
|
-
import { z as
|
|
6263
|
+
import { z as z5 } from "zod";
|
|
5375
6264
|
|
|
5376
6265
|
// src/tools/filesystem.ts
|
|
5377
6266
|
import { promises as fs3 } from "fs";
|
|
@@ -5667,8 +6556,8 @@ var CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION = [
|
|
|
5667
6556
|
"- You must prefix new lines with `+` even when creating a new file",
|
|
5668
6557
|
"- File references can only be relative, NEVER ABSOLUTE."
|
|
5669
6558
|
].join("\n");
|
|
5670
|
-
var applyPatchToolInputSchema =
|
|
5671
|
-
input:
|
|
6559
|
+
var applyPatchToolInputSchema = z5.object({
|
|
6560
|
+
input: z5.string().min(1).describe(CODEX_APPLY_PATCH_INPUT_DESCRIPTION)
|
|
5672
6561
|
});
|
|
5673
6562
|
function createApplyPatchTool(options = {}) {
|
|
5674
6563
|
return tool({
|
|
@@ -6076,100 +6965,100 @@ var MAX_GREP_LIMIT = 2e3;
|
|
|
6076
6965
|
var DEFAULT_MAX_LINE_LENGTH = 500;
|
|
6077
6966
|
var DEFAULT_GREP_MAX_SCANNED_FILES = 2e4;
|
|
6078
6967
|
var DEFAULT_TAB_WIDTH = 4;
|
|
6079
|
-
var codexReadFileInputSchema =
|
|
6080
|
-
file_path:
|
|
6081
|
-
offset:
|
|
6082
|
-
limit:
|
|
6083
|
-
mode:
|
|
6084
|
-
indentation:
|
|
6085
|
-
anchor_line:
|
|
6086
|
-
max_levels:
|
|
6087
|
-
include_siblings:
|
|
6088
|
-
include_header:
|
|
6089
|
-
max_lines:
|
|
6968
|
+
var codexReadFileInputSchema = z6.object({
|
|
6969
|
+
file_path: z6.string().min(1).describe("Absolute path to the file"),
|
|
6970
|
+
offset: z6.number().int().min(1).optional().describe("The line number to start reading from. Must be 1 or greater."),
|
|
6971
|
+
limit: z6.number().int().min(1).optional().describe("The maximum number of lines to return."),
|
|
6972
|
+
mode: z6.enum(["slice", "indentation"]).optional().describe('Optional mode selector: "slice" (default) or "indentation".'),
|
|
6973
|
+
indentation: z6.object({
|
|
6974
|
+
anchor_line: z6.number().int().min(1).optional(),
|
|
6975
|
+
max_levels: z6.number().int().min(0).optional(),
|
|
6976
|
+
include_siblings: z6.boolean().optional(),
|
|
6977
|
+
include_header: z6.boolean().optional(),
|
|
6978
|
+
max_lines: z6.number().int().min(1).optional()
|
|
6090
6979
|
}).optional()
|
|
6091
6980
|
});
|
|
6092
|
-
var codexListDirInputSchema =
|
|
6093
|
-
dir_path:
|
|
6094
|
-
offset:
|
|
6095
|
-
limit:
|
|
6096
|
-
depth:
|
|
6981
|
+
var codexListDirInputSchema = z6.object({
|
|
6982
|
+
dir_path: z6.string().min(1).describe("Absolute path to the directory to list."),
|
|
6983
|
+
offset: z6.number().int().min(1).optional().describe("The entry number to start listing from. Must be 1 or greater."),
|
|
6984
|
+
limit: z6.number().int().min(1).optional().describe("The maximum number of entries to return."),
|
|
6985
|
+
depth: z6.number().int().min(1).optional().describe("The maximum directory depth to traverse. Must be 1 or greater.")
|
|
6097
6986
|
});
|
|
6098
|
-
var codexGrepFilesInputSchema =
|
|
6099
|
-
pattern:
|
|
6100
|
-
include:
|
|
6101
|
-
path:
|
|
6102
|
-
limit:
|
|
6987
|
+
var codexGrepFilesInputSchema = z6.object({
|
|
6988
|
+
pattern: z6.string().min(1).describe("Regular expression pattern to search for."),
|
|
6989
|
+
include: z6.string().optional().describe('Optional glob limiting searched files (for example "*.rs").'),
|
|
6990
|
+
path: z6.string().optional().describe("Directory or file path to search. Defaults to cwd."),
|
|
6991
|
+
limit: z6.number().int().min(1).optional().describe("Maximum number of file paths to return (defaults to 100).")
|
|
6103
6992
|
});
|
|
6104
|
-
var applyPatchInputSchema =
|
|
6105
|
-
input:
|
|
6993
|
+
var applyPatchInputSchema = z6.object({
|
|
6994
|
+
input: z6.string().min(1).describe(CODEX_APPLY_PATCH_INPUT_DESCRIPTION)
|
|
6106
6995
|
});
|
|
6107
|
-
var geminiReadFileInputSchema =
|
|
6108
|
-
file_path:
|
|
6109
|
-
offset:
|
|
6110
|
-
limit:
|
|
6996
|
+
var geminiReadFileInputSchema = z6.object({
|
|
6997
|
+
file_path: z6.string().min(1),
|
|
6998
|
+
offset: z6.number().int().min(0).nullish(),
|
|
6999
|
+
limit: z6.number().int().min(1).nullish()
|
|
6111
7000
|
});
|
|
6112
|
-
var geminiReadFilesInputSchema =
|
|
6113
|
-
paths:
|
|
6114
|
-
line_offset:
|
|
6115
|
-
line_limit:
|
|
6116
|
-
char_offset:
|
|
6117
|
-
char_limit:
|
|
6118
|
-
include_line_numbers:
|
|
7001
|
+
var geminiReadFilesInputSchema = z6.object({
|
|
7002
|
+
paths: z6.array(z6.string().min(1)).min(1),
|
|
7003
|
+
line_offset: z6.number().int().min(0).nullish(),
|
|
7004
|
+
line_limit: z6.number().int().min(1).nullish(),
|
|
7005
|
+
char_offset: z6.number().int().min(0).nullish(),
|
|
7006
|
+
char_limit: z6.number().int().min(1).nullish(),
|
|
7007
|
+
include_line_numbers: z6.boolean().nullish()
|
|
6119
7008
|
}).superRefine((value, context) => {
|
|
6120
7009
|
const hasLineWindow = value.line_offset !== void 0 || value.line_limit !== void 0;
|
|
6121
7010
|
const hasCharWindow = value.char_offset !== void 0 || value.char_limit !== void 0;
|
|
6122
7011
|
if (hasLineWindow && hasCharWindow) {
|
|
6123
7012
|
context.addIssue({
|
|
6124
|
-
code:
|
|
7013
|
+
code: z6.ZodIssueCode.custom,
|
|
6125
7014
|
message: "Use either line_* or char_* window arguments, not both."
|
|
6126
7015
|
});
|
|
6127
7016
|
}
|
|
6128
7017
|
});
|
|
6129
|
-
var geminiWriteFileInputSchema =
|
|
6130
|
-
file_path:
|
|
6131
|
-
content:
|
|
7018
|
+
var geminiWriteFileInputSchema = z6.object({
|
|
7019
|
+
file_path: z6.string().min(1),
|
|
7020
|
+
content: z6.string()
|
|
6132
7021
|
});
|
|
6133
|
-
var geminiReplaceInputSchema =
|
|
6134
|
-
file_path:
|
|
6135
|
-
instruction:
|
|
6136
|
-
old_string:
|
|
6137
|
-
new_string:
|
|
6138
|
-
expected_replacements:
|
|
7022
|
+
var geminiReplaceInputSchema = z6.object({
|
|
7023
|
+
file_path: z6.string().min(1),
|
|
7024
|
+
instruction: z6.string().min(1),
|
|
7025
|
+
old_string: z6.string(),
|
|
7026
|
+
new_string: z6.string(),
|
|
7027
|
+
expected_replacements: z6.number().int().min(1).nullish()
|
|
6139
7028
|
});
|
|
6140
|
-
var geminiListDirectoryInputSchema =
|
|
6141
|
-
dir_path:
|
|
6142
|
-
ignore:
|
|
6143
|
-
file_filtering_options:
|
|
6144
|
-
respect_git_ignore:
|
|
6145
|
-
respect_gemini_ignore:
|
|
7029
|
+
var geminiListDirectoryInputSchema = z6.object({
|
|
7030
|
+
dir_path: z6.string().min(1),
|
|
7031
|
+
ignore: z6.array(z6.string()).nullish(),
|
|
7032
|
+
file_filtering_options: z6.object({
|
|
7033
|
+
respect_git_ignore: z6.boolean().nullish(),
|
|
7034
|
+
respect_gemini_ignore: z6.boolean().nullish()
|
|
6146
7035
|
}).nullish()
|
|
6147
7036
|
});
|
|
6148
|
-
var geminiRgSearchInputSchema =
|
|
6149
|
-
pattern:
|
|
6150
|
-
path:
|
|
6151
|
-
glob:
|
|
6152
|
-
case_sensitive:
|
|
6153
|
-
exclude_pattern:
|
|
6154
|
-
names_only:
|
|
6155
|
-
max_matches_per_file:
|
|
6156
|
-
max_results:
|
|
7037
|
+
var geminiRgSearchInputSchema = z6.object({
|
|
7038
|
+
pattern: z6.string().min(1),
|
|
7039
|
+
path: z6.string().nullish(),
|
|
7040
|
+
glob: z6.string().nullish(),
|
|
7041
|
+
case_sensitive: z6.boolean().nullish(),
|
|
7042
|
+
exclude_pattern: z6.string().nullish(),
|
|
7043
|
+
names_only: z6.boolean().nullish(),
|
|
7044
|
+
max_matches_per_file: z6.number().int().min(1).nullish(),
|
|
7045
|
+
max_results: z6.number().int().min(1).nullish()
|
|
6157
7046
|
});
|
|
6158
|
-
var geminiGrepSearchInputSchema =
|
|
6159
|
-
pattern:
|
|
6160
|
-
dir_path:
|
|
6161
|
-
include:
|
|
6162
|
-
exclude_pattern:
|
|
6163
|
-
names_only:
|
|
6164
|
-
max_matches_per_file:
|
|
6165
|
-
total_max_matches:
|
|
7047
|
+
var geminiGrepSearchInputSchema = z6.object({
|
|
7048
|
+
pattern: z6.string().min(1),
|
|
7049
|
+
dir_path: z6.string().nullish(),
|
|
7050
|
+
include: z6.string().nullish(),
|
|
7051
|
+
exclude_pattern: z6.string().nullish(),
|
|
7052
|
+
names_only: z6.boolean().nullish(),
|
|
7053
|
+
max_matches_per_file: z6.number().int().min(1).nullish(),
|
|
7054
|
+
total_max_matches: z6.number().int().min(1).nullish()
|
|
6166
7055
|
});
|
|
6167
|
-
var geminiGlobInputSchema =
|
|
6168
|
-
pattern:
|
|
6169
|
-
dir_path:
|
|
6170
|
-
case_sensitive:
|
|
6171
|
-
respect_git_ignore:
|
|
6172
|
-
respect_gemini_ignore:
|
|
7056
|
+
var geminiGlobInputSchema = z6.object({
|
|
7057
|
+
pattern: z6.string().min(1),
|
|
7058
|
+
dir_path: z6.string().nullish(),
|
|
7059
|
+
case_sensitive: z6.boolean().nullish(),
|
|
7060
|
+
respect_git_ignore: z6.boolean().nullish(),
|
|
7061
|
+
respect_gemini_ignore: z6.boolean().nullish()
|
|
6173
7062
|
});
|
|
6174
7063
|
function resolveFilesystemToolProfile(model, profile = "auto") {
|
|
6175
7064
|
if (profile !== "auto") {
|
|
@@ -7157,19 +8046,54 @@ function isNoEntError(error) {
|
|
|
7157
8046
|
|
|
7158
8047
|
// src/agent.ts
|
|
7159
8048
|
async function runAgentLoop(request) {
|
|
7160
|
-
|
|
8049
|
+
return await runAgentLoopInternal(request, { depth: 0 });
|
|
8050
|
+
}
|
|
8051
|
+
async function runAgentLoopInternal(request, context) {
|
|
8052
|
+
const {
|
|
8053
|
+
tools: customTools,
|
|
8054
|
+
filesystemTool,
|
|
8055
|
+
filesystem_tool,
|
|
8056
|
+
subagentTool,
|
|
8057
|
+
subagent_tool,
|
|
8058
|
+
subagents,
|
|
8059
|
+
...toolLoopRequest
|
|
8060
|
+
} = request;
|
|
7161
8061
|
const filesystemSelection = filesystemTool ?? filesystem_tool;
|
|
8062
|
+
const subagentSelection = subagentTool ?? subagent_tool ?? subagents;
|
|
7162
8063
|
const filesystemTools = resolveFilesystemTools(request.model, filesystemSelection);
|
|
7163
|
-
const
|
|
8064
|
+
const resolvedSubagentConfig = resolveSubagentToolConfig(subagentSelection, context.depth);
|
|
8065
|
+
const subagentController = createSubagentController({
|
|
8066
|
+
model: request.model,
|
|
8067
|
+
depth: context.depth,
|
|
8068
|
+
customTools: customTools ?? {},
|
|
8069
|
+
filesystemSelection,
|
|
8070
|
+
subagentSelection,
|
|
8071
|
+
toolLoopRequest,
|
|
8072
|
+
resolvedSubagentConfig
|
|
8073
|
+
});
|
|
8074
|
+
const mergedTools = mergeToolSets(
|
|
8075
|
+
mergeToolSets(filesystemTools, subagentController?.tools ?? {}),
|
|
8076
|
+
customTools ?? {}
|
|
8077
|
+
);
|
|
7164
8078
|
if (Object.keys(mergedTools).length === 0) {
|
|
7165
8079
|
throw new Error(
|
|
7166
|
-
"runAgentLoop requires at least one tool. Provide `tools` or enable `
|
|
8080
|
+
"runAgentLoop requires at least one tool. Provide `tools`, enable `filesystemTool`, or enable `subagentTool`."
|
|
7167
8081
|
);
|
|
7168
8082
|
}
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
8083
|
+
const instructions = buildLoopInstructions(
|
|
8084
|
+
toolLoopRequest.instructions,
|
|
8085
|
+
resolvedSubagentConfig,
|
|
8086
|
+
context.depth
|
|
8087
|
+
);
|
|
8088
|
+
try {
|
|
8089
|
+
return await runToolLoop({
|
|
8090
|
+
...toolLoopRequest,
|
|
8091
|
+
...instructions ? { instructions } : {},
|
|
8092
|
+
tools: mergedTools
|
|
8093
|
+
});
|
|
8094
|
+
} finally {
|
|
8095
|
+
await subagentController?.closeAll();
|
|
8096
|
+
}
|
|
7173
8097
|
}
|
|
7174
8098
|
function resolveFilesystemTools(model, selection) {
|
|
7175
8099
|
if (selection === void 0 || selection === false) {
|
|
@@ -7197,14 +8121,91 @@ function mergeToolSets(base, extra) {
|
|
|
7197
8121
|
for (const [toolName, toolSpec] of Object.entries(extra)) {
|
|
7198
8122
|
if (Object.hasOwn(merged, toolName)) {
|
|
7199
8123
|
throw new Error(
|
|
7200
|
-
`Duplicate tool name "${toolName}" in runAgentLoop. Rename the
|
|
8124
|
+
`Duplicate tool name "${toolName}" in runAgentLoop. Rename one of the conflicting tools or disable an overlapping built-in tool.`
|
|
7201
8125
|
);
|
|
7202
8126
|
}
|
|
7203
8127
|
merged[toolName] = toolSpec;
|
|
7204
8128
|
}
|
|
7205
8129
|
return merged;
|
|
7206
8130
|
}
|
|
8131
|
+
function createSubagentController(params) {
|
|
8132
|
+
if (!params.resolvedSubagentConfig.enabled) {
|
|
8133
|
+
return null;
|
|
8134
|
+
}
|
|
8135
|
+
return createSubagentToolController({
|
|
8136
|
+
config: params.resolvedSubagentConfig,
|
|
8137
|
+
parentDepth: params.depth,
|
|
8138
|
+
parentModel: params.resolvedSubagentConfig.model ?? params.model,
|
|
8139
|
+
buildChildInstructions: (spawnInstructions, childDepth) => buildChildInstructions(spawnInstructions, params.resolvedSubagentConfig, childDepth),
|
|
8140
|
+
runSubagent: async (subagentRequest) => {
|
|
8141
|
+
const childCustomTools = params.resolvedSubagentConfig.inheritTools ? params.customTools : {};
|
|
8142
|
+
const childFilesystemSelection = params.resolvedSubagentConfig.inheritFilesystemTool ? params.filesystemSelection : false;
|
|
8143
|
+
return await runAgentLoopInternal(
|
|
8144
|
+
{
|
|
8145
|
+
model: subagentRequest.model,
|
|
8146
|
+
input: subagentRequest.input,
|
|
8147
|
+
instructions: subagentRequest.instructions,
|
|
8148
|
+
tools: childCustomTools,
|
|
8149
|
+
filesystemTool: childFilesystemSelection,
|
|
8150
|
+
subagentTool: params.subagentSelection,
|
|
8151
|
+
modelTools: params.toolLoopRequest.modelTools,
|
|
8152
|
+
maxSteps: subagentRequest.maxSteps,
|
|
8153
|
+
openAiReasoningEffort: params.toolLoopRequest.openAiReasoningEffort,
|
|
8154
|
+
signal: subagentRequest.signal
|
|
8155
|
+
},
|
|
8156
|
+
{ depth: params.depth + 1 }
|
|
8157
|
+
);
|
|
8158
|
+
}
|
|
8159
|
+
});
|
|
8160
|
+
}
|
|
8161
|
+
function buildLoopInstructions(baseInstructions, config, depth) {
|
|
8162
|
+
if (!config.enabled) {
|
|
8163
|
+
return trimToUndefined2(baseInstructions);
|
|
8164
|
+
}
|
|
8165
|
+
const blocks = [];
|
|
8166
|
+
const base = trimToUndefined2(baseInstructions);
|
|
8167
|
+
if (base) {
|
|
8168
|
+
blocks.push(base);
|
|
8169
|
+
}
|
|
8170
|
+
if (config.promptPattern === "codex") {
|
|
8171
|
+
blocks.push(
|
|
8172
|
+
buildCodexSubagentOrchestratorInstructions({
|
|
8173
|
+
currentDepth: depth,
|
|
8174
|
+
maxDepth: config.maxDepth,
|
|
8175
|
+
maxAgents: config.maxAgents
|
|
8176
|
+
})
|
|
8177
|
+
);
|
|
8178
|
+
}
|
|
8179
|
+
if (config.instructions) {
|
|
8180
|
+
blocks.push(config.instructions);
|
|
8181
|
+
}
|
|
8182
|
+
return blocks.length > 0 ? blocks.join("\n\n") : void 0;
|
|
8183
|
+
}
|
|
8184
|
+
function buildChildInstructions(spawnInstructions, config, childDepth) {
|
|
8185
|
+
const blocks = [];
|
|
8186
|
+
if (config.promptPattern === "codex") {
|
|
8187
|
+
blocks.push(
|
|
8188
|
+
buildCodexSubagentWorkerInstructions({
|
|
8189
|
+
depth: childDepth,
|
|
8190
|
+
maxDepth: config.maxDepth
|
|
8191
|
+
})
|
|
8192
|
+
);
|
|
8193
|
+
}
|
|
8194
|
+
if (config.instructions) {
|
|
8195
|
+
blocks.push(config.instructions);
|
|
8196
|
+
}
|
|
8197
|
+
const perSpawn = trimToUndefined2(spawnInstructions);
|
|
8198
|
+
if (perSpawn) {
|
|
8199
|
+
blocks.push(perSpawn);
|
|
8200
|
+
}
|
|
8201
|
+
return blocks.length > 0 ? blocks.join("\n\n") : void 0;
|
|
8202
|
+
}
|
|
8203
|
+
function trimToUndefined2(value) {
|
|
8204
|
+
const trimmed = value?.trim();
|
|
8205
|
+
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
8206
|
+
}
|
|
7207
8207
|
export {
|
|
8208
|
+
CHATGPT_MODEL_IDS,
|
|
7208
8209
|
CODEX_APPLY_PATCH_FREEFORM_TOOL_DESCRIPTION,
|
|
7209
8210
|
CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION,
|
|
7210
8211
|
CODEX_APPLY_PATCH_LARK_GRAMMAR,
|
|
@@ -7213,8 +8214,15 @@ export {
|
|
|
7213
8214
|
FIREWORKS_DEFAULT_KIMI_MODEL,
|
|
7214
8215
|
FIREWORKS_DEFAULT_MINIMAX_MODEL,
|
|
7215
8216
|
FIREWORKS_MODEL_IDS,
|
|
8217
|
+
GEMINI_IMAGE_MODEL_IDS,
|
|
8218
|
+
GEMINI_MODEL_IDS,
|
|
8219
|
+
GEMINI_TEXT_MODEL_IDS,
|
|
7216
8220
|
InMemoryAgentFilesystem,
|
|
8221
|
+
LLM_IMAGE_MODEL_IDS,
|
|
8222
|
+
LLM_MODEL_IDS,
|
|
8223
|
+
LLM_TEXT_MODEL_IDS,
|
|
7217
8224
|
LlmJsonCallError,
|
|
8225
|
+
OPENAI_MODEL_IDS,
|
|
7218
8226
|
appendMarkdownSourcesSection,
|
|
7219
8227
|
applyPatch,
|
|
7220
8228
|
configureGemini,
|
|
@@ -7249,8 +8257,15 @@ export {
|
|
|
7249
8257
|
generateText,
|
|
7250
8258
|
getChatGptAuthProfile,
|
|
7251
8259
|
getCurrentToolCallContext,
|
|
8260
|
+
isChatGptModelId,
|
|
7252
8261
|
isFireworksModelId,
|
|
8262
|
+
isGeminiImageModelId,
|
|
7253
8263
|
isGeminiModelId,
|
|
8264
|
+
isGeminiTextModelId,
|
|
8265
|
+
isLlmImageModelId,
|
|
8266
|
+
isLlmModelId,
|
|
8267
|
+
isLlmTextModelId,
|
|
8268
|
+
isOpenAiModelId,
|
|
7254
8269
|
loadEnvFromFile,
|
|
7255
8270
|
loadLocalEnv,
|
|
7256
8271
|
parseJsonFromLlmText,
|