@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/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 [400, 404, 405, 406, 426, 501].includes(error.status);
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: 3e4
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
- socket.removeListener("unexpected-response", onUnexpectedResponse);
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
- socket.once("unexpected-response", onUnexpectedResponse);
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 < maxParallelRequests && queue.length > 0) {
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 scheduler = createCallScheduler({
1727
- maxParallelRequests: 3,
1728
- minIntervalBetweenStartMs: 200,
1729
- startJitterMs: 200
1730
- });
1731
- async function runFireworksCall(fn) {
1732
- return scheduler.run(async () => fn(getFireworksClient()));
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 GEMINI_MODEL_IDS = [
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 scheduler2 = createCallScheduler({
2068
- maxParallelRequests: 3,
2069
- minIntervalBetweenStartMs: 200,
2070
- startJitterMs: 200,
2071
- retry: {
2072
- maxAttempts: 3,
2073
- getDelayMs: (attempt, error) => {
2074
- if (!shouldRetry(error)) {
2075
- return null;
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
- async function runGeminiCall(fn) {
2083
- return scheduler2.run(async () => fn(await getGeminiClient()));
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 scheduler3 = createCallScheduler({
2245
- maxParallelRequests: 3,
2246
- minIntervalBetweenStartMs: 200,
2247
- startJitterMs: 200
2248
- });
2249
- async function runOpenAiCall(fn) {
2250
- return scheduler3.run(async () => fn(getOpenAiClient()));
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.startsWith("chatgpt-")) {
2616
- return { provider: "chatgpt", model: model.slice("chatgpt-".length) };
2882
+ if (isChatGptModelId(model)) {
2883
+ return { provider: "chatgpt", model: stripChatGptPrefix(model) };
2617
2884
  }
2618
- if (model.startsWith("gemini-")) {
2885
+ if (isGeminiTextModelId(model) || isGeminiImageModelId(model)) {
2619
2886
  return { provider: "gemini", model };
2620
2887
  }
2621
- const fireworksModel = resolveFireworksModelId(model);
2622
- if (fireworksModel) {
2623
- return { provider: "fireworks", model: fireworksModel };
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
- return { provider: "openai", model };
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 z5 } from "zod";
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 z4 } from "zod";
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 = z4.object({
5671
- input: z4.string().min(1).describe(CODEX_APPLY_PATCH_INPUT_DESCRIPTION)
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 = z5.object({
6080
- file_path: z5.string().min(1).describe("Absolute path to the file"),
6081
- offset: z5.number().int().min(1).optional().describe("The line number to start reading from. Must be 1 or greater."),
6082
- limit: z5.number().int().min(1).optional().describe("The maximum number of lines to return."),
6083
- mode: z5.enum(["slice", "indentation"]).optional().describe('Optional mode selector: "slice" (default) or "indentation".'),
6084
- indentation: z5.object({
6085
- anchor_line: z5.number().int().min(1).optional(),
6086
- max_levels: z5.number().int().min(0).optional(),
6087
- include_siblings: z5.boolean().optional(),
6088
- include_header: z5.boolean().optional(),
6089
- max_lines: z5.number().int().min(1).optional()
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 = z5.object({
6093
- dir_path: z5.string().min(1).describe("Absolute path to the directory to list."),
6094
- offset: z5.number().int().min(1).optional().describe("The entry number to start listing from. Must be 1 or greater."),
6095
- limit: z5.number().int().min(1).optional().describe("The maximum number of entries to return."),
6096
- depth: z5.number().int().min(1).optional().describe("The maximum directory depth to traverse. Must be 1 or greater.")
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 = z5.object({
6099
- pattern: z5.string().min(1).describe("Regular expression pattern to search for."),
6100
- include: z5.string().optional().describe('Optional glob limiting searched files (for example "*.rs").'),
6101
- path: z5.string().optional().describe("Directory or file path to search. Defaults to cwd."),
6102
- limit: z5.number().int().min(1).optional().describe("Maximum number of file paths to return (defaults to 100).")
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 = z5.object({
6105
- input: z5.string().min(1).describe(CODEX_APPLY_PATCH_INPUT_DESCRIPTION)
6993
+ var applyPatchInputSchema = z6.object({
6994
+ input: z6.string().min(1).describe(CODEX_APPLY_PATCH_INPUT_DESCRIPTION)
6106
6995
  });
6107
- var geminiReadFileInputSchema = z5.object({
6108
- file_path: z5.string().min(1),
6109
- offset: z5.number().int().min(0).nullish(),
6110
- limit: z5.number().int().min(1).nullish()
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 = z5.object({
6113
- paths: z5.array(z5.string().min(1)).min(1),
6114
- line_offset: z5.number().int().min(0).nullish(),
6115
- line_limit: z5.number().int().min(1).nullish(),
6116
- char_offset: z5.number().int().min(0).nullish(),
6117
- char_limit: z5.number().int().min(1).nullish(),
6118
- include_line_numbers: z5.boolean().nullish()
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: z5.ZodIssueCode.custom,
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 = z5.object({
6130
- file_path: z5.string().min(1),
6131
- content: z5.string()
7018
+ var geminiWriteFileInputSchema = z6.object({
7019
+ file_path: z6.string().min(1),
7020
+ content: z6.string()
6132
7021
  });
6133
- var geminiReplaceInputSchema = z5.object({
6134
- file_path: z5.string().min(1),
6135
- instruction: z5.string().min(1),
6136
- old_string: z5.string(),
6137
- new_string: z5.string(),
6138
- expected_replacements: z5.number().int().min(1).nullish()
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 = z5.object({
6141
- dir_path: z5.string().min(1),
6142
- ignore: z5.array(z5.string()).nullish(),
6143
- file_filtering_options: z5.object({
6144
- respect_git_ignore: z5.boolean().nullish(),
6145
- respect_gemini_ignore: z5.boolean().nullish()
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 = z5.object({
6149
- pattern: z5.string().min(1),
6150
- path: z5.string().nullish(),
6151
- glob: z5.string().nullish(),
6152
- case_sensitive: z5.boolean().nullish(),
6153
- exclude_pattern: z5.string().nullish(),
6154
- names_only: z5.boolean().nullish(),
6155
- max_matches_per_file: z5.number().int().min(1).nullish(),
6156
- max_results: z5.number().int().min(1).nullish()
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 = z5.object({
6159
- pattern: z5.string().min(1),
6160
- dir_path: z5.string().nullish(),
6161
- include: z5.string().nullish(),
6162
- exclude_pattern: z5.string().nullish(),
6163
- names_only: z5.boolean().nullish(),
6164
- max_matches_per_file: z5.number().int().min(1).nullish(),
6165
- total_max_matches: z5.number().int().min(1).nullish()
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 = z5.object({
6168
- pattern: z5.string().min(1),
6169
- dir_path: z5.string().nullish(),
6170
- case_sensitive: z5.boolean().nullish(),
6171
- respect_git_ignore: z5.boolean().nullish(),
6172
- respect_gemini_ignore: z5.boolean().nullish()
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
- const { tools: customTools, filesystemTool, filesystem_tool, ...toolLoopRequest } = request;
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 mergedTools = mergeToolSets(filesystemTools, customTools ?? {});
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 `filesystemTool`."
8080
+ "runAgentLoop requires at least one tool. Provide `tools`, enable `filesystemTool`, or enable `subagentTool`."
7167
8081
  );
7168
8082
  }
7169
- return runToolLoop({
7170
- ...toolLoopRequest,
7171
- tools: mergedTools
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 custom tool or disable that filesystem tool.`
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,