@ljoukov/llm 2.1.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -30,6 +30,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ CODEX_APPLY_PATCH_FREEFORM_TOOL_DESCRIPTION: () => CODEX_APPLY_PATCH_FREEFORM_TOOL_DESCRIPTION,
34
+ CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION: () => CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION,
35
+ CODEX_APPLY_PATCH_LARK_GRAMMAR: () => CODEX_APPLY_PATCH_LARK_GRAMMAR,
36
+ FIREWORKS_DEFAULT_GLM_MODEL: () => FIREWORKS_DEFAULT_GLM_MODEL,
37
+ FIREWORKS_DEFAULT_KIMI_MODEL: () => FIREWORKS_DEFAULT_KIMI_MODEL,
38
+ FIREWORKS_DEFAULT_MINIMAX_MODEL: () => FIREWORKS_DEFAULT_MINIMAX_MODEL,
39
+ FIREWORKS_MODEL_IDS: () => FIREWORKS_MODEL_IDS,
33
40
  InMemoryAgentFilesystem: () => InMemoryAgentFilesystem,
34
41
  LlmJsonCallError: () => LlmJsonCallError,
35
42
  appendMarkdownSourcesSection: () => appendMarkdownSourcesSection,
@@ -42,6 +49,7 @@ __export(index_exports, {
42
49
  createCodexReadFileTool: () => createCodexReadFileTool,
43
50
  createFilesystemToolSetForModel: () => createFilesystemToolSetForModel,
44
51
  createGeminiFilesystemToolSet: () => createGeminiFilesystemToolSet,
52
+ createGeminiReadFileTool: () => createGeminiReadFileTool,
45
53
  createGlobTool: () => createGlobTool,
46
54
  createGrepFilesTool: () => createGrepFilesTool,
47
55
  createGrepSearchTool: () => createGrepSearchTool,
@@ -50,9 +58,11 @@ __export(index_exports, {
50
58
  createListDirectoryTool: () => createListDirectoryTool,
51
59
  createModelAgnosticFilesystemToolSet: () => createModelAgnosticFilesystemToolSet,
52
60
  createNodeAgentFilesystem: () => createNodeAgentFilesystem,
53
- createReadFileTool: () => createReadFileTool,
61
+ createReadFilesTool: () => createReadFilesTool,
54
62
  createReplaceTool: () => createReplaceTool,
63
+ createRgSearchTool: () => createRgSearchTool,
55
64
  createWriteFileTool: () => createWriteFileTool,
65
+ customTool: () => customTool,
56
66
  encodeChatGptAuthJson: () => encodeChatGptAuthJson,
57
67
  encodeChatGptAuthJsonB64: () => encodeChatGptAuthJsonB64,
58
68
  estimateCallCostUsd: () => estimateCallCostUsd,
@@ -63,12 +73,14 @@ __export(index_exports, {
63
73
  generateText: () => generateText,
64
74
  getChatGptAuthProfile: () => getChatGptAuthProfile,
65
75
  getCurrentToolCallContext: () => getCurrentToolCallContext,
76
+ isFireworksModelId: () => isFireworksModelId,
66
77
  isGeminiModelId: () => isGeminiModelId,
67
78
  loadEnvFromFile: () => loadEnvFromFile,
68
79
  loadLocalEnv: () => loadLocalEnv,
69
80
  parseJsonFromLlmText: () => parseJsonFromLlmText,
70
81
  refreshChatGptOauthToken: () => refreshChatGptOauthToken,
71
82
  resolveFilesystemToolProfile: () => resolveFilesystemToolProfile,
83
+ resolveFireworksModelId: () => resolveFireworksModelId,
72
84
  runAgentLoop: () => runAgentLoop,
73
85
  runToolLoop: () => runToolLoop,
74
86
  sanitisePartForLogging: () => sanitisePartForLogging,
@@ -152,6 +164,35 @@ function createAsyncQueue() {
152
164
  return { push, close, fail, iterable: iterator() };
153
165
  }
154
166
 
167
+ // src/fireworks/pricing.ts
168
+ var FIREWORKS_KIMI_K25_PRICING = {
169
+ inputRate: 0.6 / 1e6,
170
+ cachedRate: 0.1 / 1e6,
171
+ outputRate: 3 / 1e6
172
+ };
173
+ var FIREWORKS_GLM_5_PRICING = {
174
+ inputRate: 1 / 1e6,
175
+ cachedRate: 0.2 / 1e6,
176
+ outputRate: 3.2 / 1e6
177
+ };
178
+ var FIREWORKS_MINIMAX_M21_PRICING = {
179
+ inputRate: 0.3 / 1e6,
180
+ cachedRate: 0.15 / 1e6,
181
+ outputRate: 1.2 / 1e6
182
+ };
183
+ function getFireworksPricing(modelId) {
184
+ if (modelId.includes("kimi-k2.5") || modelId.includes("kimi-k2p5")) {
185
+ return FIREWORKS_KIMI_K25_PRICING;
186
+ }
187
+ if (modelId.includes("glm-5")) {
188
+ return FIREWORKS_GLM_5_PRICING;
189
+ }
190
+ if (modelId.includes("minimax-m2.1") || modelId.includes("minimax-m2p1")) {
191
+ return FIREWORKS_MINIMAX_M21_PRICING;
192
+ }
193
+ return void 0;
194
+ }
195
+
155
196
  // src/google/pricing.ts
156
197
  var GEMINI_3_PRO_PREVIEW_PRICING = {
157
198
  threshold: 2e5,
@@ -209,12 +250,15 @@ var OPENAI_GPT_53_CODEX_PRICING = {
209
250
  cachedRate: 0.125 / 1e6,
210
251
  outputRate: 10 / 1e6
211
252
  };
212
- var OPENAI_GPT_51_CODEX_MINI_PRICING = {
253
+ var OPENAI_GPT_5_MINI_PRICING = {
213
254
  inputRate: 0.25 / 1e6,
214
255
  cachedRate: 0.025 / 1e6,
215
256
  outputRate: 2 / 1e6
216
257
  };
217
258
  function getOpenAiPricing(modelId) {
259
+ if (modelId.includes("gpt-5.3-codex-spark")) {
260
+ return OPENAI_GPT_5_MINI_PRICING;
261
+ }
218
262
  if (modelId.includes("gpt-5.3-codex")) {
219
263
  return OPENAI_GPT_53_CODEX_PRICING;
220
264
  }
@@ -224,8 +268,11 @@ function getOpenAiPricing(modelId) {
224
268
  if (modelId.includes("gpt-5.2")) {
225
269
  return OPENAI_GPT_52_PRICING;
226
270
  }
271
+ if (modelId.includes("gpt-5-mini")) {
272
+ return OPENAI_GPT_5_MINI_PRICING;
273
+ }
227
274
  if (modelId.includes("gpt-5.1-codex-mini")) {
228
- return OPENAI_GPT_51_CODEX_MINI_PRICING;
275
+ return OPENAI_GPT_5_MINI_PRICING;
229
276
  }
230
277
  return void 0;
231
278
  }
@@ -286,6 +333,14 @@ function estimateCallCostUsd({
286
333
  const outputCost = outputTokens * outputRate;
287
334
  return inputCost + cachedCost + outputCost;
288
335
  }
336
+ const fireworksPricing = getFireworksPricing(modelId);
337
+ if (fireworksPricing) {
338
+ const inputCost = nonCachedPrompt * fireworksPricing.inputRate;
339
+ const cachedCost = cachedTokens * fireworksPricing.cachedRate;
340
+ const outputTokens = responseTokens + thinkingTokens;
341
+ const outputCost = outputTokens * fireworksPricing.outputRate;
342
+ return inputCost + cachedCost + outputCost;
343
+ }
289
344
  const openAiPricing = getOpenAiPricing(modelId);
290
345
  if (openAiPricing) {
291
346
  const inputCost = nonCachedPrompt * openAiPricing.inputRate;
@@ -298,11 +353,14 @@ function estimateCallCostUsd({
298
353
  }
299
354
 
300
355
  // src/openai/chatgpt-codex.ts
301
- var import_node_os = __toESM(require("os"), 1);
356
+ var import_node_os2 = __toESM(require("os"), 1);
302
357
  var import_node_util = require("util");
303
358
 
304
359
  // src/openai/chatgpt-auth.ts
305
360
  var import_node_buffer = require("buffer");
361
+ var import_node_fs2 = __toESM(require("fs"), 1);
362
+ var import_node_os = __toESM(require("os"), 1);
363
+ var import_node_path2 = __toESM(require("path"), 1);
306
364
  var import_zod = require("zod");
307
365
 
308
366
  // src/utils/env.ts
@@ -367,34 +425,30 @@ function parseEnvLine(line) {
367
425
  }
368
426
 
369
427
  // src/openai/chatgpt-auth.ts
370
- var CHATGPT_AUTH_JSON_ENV = "CHATGPT_AUTH_JSON";
371
- var CHATGPT_AUTH_JSON_B64_ENV = "CHATGPT_AUTH_JSON_B64";
372
- var CHATGPT_ACCESS_ENV = "CHATGPT_ACCESS";
373
- var CHATGPT_REFRESH_ENV = "CHATGPT_REFRESH";
374
- var CHATGPT_EXPIRES_ENV = "CHATGPT_EXPIRES";
375
- var CHATGPT_ACCOUNT_ID_ENV = "CHATGPT_ACCOUNT_ID";
376
- var CHATGPT_ID_TOKEN_ENV = "CHATGPT_ID_TOKEN";
377
- var CHATGPT_ACCESS_TOKEN_ENV = "CHATGPT_ACCESS_TOKEN";
378
- var CHATGPT_REFRESH_TOKEN_ENV = "CHATGPT_REFRESH_TOKEN";
379
- var CHATGPT_EXPIRES_AT_ENV = "CHATGPT_EXPIRES_AT";
428
+ var CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV = "CHATGPT_AUTH_TOKEN_PROVIDER_URL";
429
+ var CHATGPT_AUTH_TOKEN_PROVIDER_STORE_ENV = "CHATGPT_AUTH_TOKEN_PROVIDER_STORE";
430
+ var CHATGPT_AUTH_SERVER_URL_ENV = "CHATGPT_AUTH_SERVER_URL";
431
+ var CHATGPT_AUTH_SERVER_STORE_ENV = "CHATGPT_AUTH_SERVER_STORE";
432
+ var CHATGPT_AUTH_API_KEY_ENV = "CHATGPT_AUTH_API_KEY";
433
+ var CHATGPT_AUTH_TOKEN_PROVIDER_API_KEY_ENV = "CHATGPT_AUTH_TOKEN_PROVIDER_API_KEY";
380
434
  var CHATGPT_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
381
435
  var CHATGPT_OAUTH_TOKEN_URL = "https://auth.openai.com/oauth/token";
382
436
  var CHATGPT_OAUTH_REDIRECT_URI = "http://localhost:1455/auth/callback";
383
437
  var TOKEN_EXPIRY_BUFFER_MS = 3e4;
384
- var AuthInputSchema = import_zod.z.object({
385
- access: import_zod.z.string().min(1).optional(),
386
- access_token: import_zod.z.string().min(1).optional(),
387
- accessToken: import_zod.z.string().min(1).optional(),
388
- refresh: import_zod.z.string().min(1).optional(),
389
- refresh_token: import_zod.z.string().min(1).optional(),
390
- refreshToken: import_zod.z.string().min(1).optional(),
391
- expires: import_zod.z.union([import_zod.z.number(), import_zod.z.string()]).optional(),
392
- expires_at: import_zod.z.union([import_zod.z.number(), import_zod.z.string()]).optional(),
393
- expiresAt: import_zod.z.union([import_zod.z.number(), import_zod.z.string()]).optional(),
394
- accountId: import_zod.z.string().min(1).optional(),
395
- account_id: import_zod.z.string().min(1).optional(),
396
- id_token: import_zod.z.string().optional(),
397
- idToken: import_zod.z.string().optional()
438
+ var CodexAuthFileSchema = import_zod.z.object({
439
+ OPENAI_API_KEY: import_zod.z.string().nullable().optional(),
440
+ last_refresh: import_zod.z.string().optional(),
441
+ tokens: import_zod.z.object({
442
+ access_token: import_zod.z.string().min(1).optional(),
443
+ refresh_token: import_zod.z.string().min(1).optional(),
444
+ id_token: import_zod.z.string().min(1).optional(),
445
+ account_id: import_zod.z.string().min(1).optional(),
446
+ // Allow a bit of flexibility if the file format changes.
447
+ accessToken: import_zod.z.string().min(1).optional(),
448
+ refreshToken: import_zod.z.string().min(1).optional(),
449
+ idToken: import_zod.z.string().min(1).optional(),
450
+ accountId: import_zod.z.string().min(1).optional()
451
+ }).optional()
398
452
  }).loose();
399
453
  var RefreshResponseSchema = import_zod.z.object({
400
454
  access_token: import_zod.z.string().min(1),
@@ -409,6 +463,44 @@ var ExchangeResponseSchema = import_zod.z.object({
409
463
  });
410
464
  var cachedProfile = null;
411
465
  var refreshPromise = null;
466
+ async function fetchChatGptAuthProfileFromTokenProvider(options) {
467
+ const base = options.baseUrl.replace(/\/+$/u, "");
468
+ const store = options.store?.trim() ? options.store.trim() : "kv";
469
+ const url = new URL(`${base}/v1/token`);
470
+ url.searchParams.set("store", store);
471
+ const response = await fetch(url.toString(), {
472
+ method: "GET",
473
+ headers: {
474
+ Authorization: `Bearer ${options.apiKey}`,
475
+ "x-chatgpt-auth": options.apiKey,
476
+ Accept: "application/json"
477
+ }
478
+ });
479
+ if (!response.ok) {
480
+ const body = await response.text();
481
+ throw new Error(`ChatGPT token provider request failed (${response.status}): ${body}`);
482
+ }
483
+ const payload = await response.json();
484
+ if (!payload || typeof payload !== "object") {
485
+ throw new Error("ChatGPT token provider returned invalid JSON.");
486
+ }
487
+ const accessToken = payload.accessToken ?? payload.access_token;
488
+ const accountId = payload.accountId ?? payload.account_id;
489
+ const expiresAt = payload.expiresAt ?? payload.expires_at;
490
+ if (typeof accessToken !== "string" || accessToken.trim().length === 0) {
491
+ throw new Error("ChatGPT token provider response missing accessToken.");
492
+ }
493
+ if (typeof accountId !== "string" || accountId.trim().length === 0) {
494
+ throw new Error("ChatGPT token provider response missing accountId.");
495
+ }
496
+ const expires = normalizeEpochMillis(expiresAt) ?? Date.now() + 5 * 6e4;
497
+ return {
498
+ access: accessToken,
499
+ refresh: "token_provider",
500
+ expires,
501
+ accountId
502
+ };
503
+ }
412
504
  function encodeChatGptAuthJson(profile) {
413
505
  const payload = {
414
506
  access: profile.access,
@@ -447,7 +539,7 @@ async function exchangeChatGptOauthCode({
447
539
  const payload = ExchangeResponseSchema.parse(await response.json());
448
540
  return profileFromTokenResponse(payload);
449
541
  }
450
- async function refreshChatGptOauthToken(refreshToken) {
542
+ async function refreshChatGptOauthToken(refreshToken, fallback) {
451
543
  const params = new URLSearchParams();
452
544
  params.set("grant_type", "refresh_token");
453
545
  params.set("client_id", CHATGPT_OAUTH_CLIENT_ID);
@@ -464,9 +556,35 @@ async function refreshChatGptOauthToken(refreshToken) {
464
556
  throw new Error(`ChatGPT OAuth refresh failed (${response.status}): ${body}`);
465
557
  }
466
558
  const payload = RefreshResponseSchema.parse(await response.json());
467
- return profileFromTokenResponse(payload);
559
+ return profileFromTokenResponse(payload, fallback);
468
560
  }
469
561
  async function getChatGptAuthProfile() {
562
+ loadLocalEnv();
563
+ const tokenProviderUrl = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV] ?? process.env[CHATGPT_AUTH_SERVER_URL_ENV];
564
+ const tokenProviderKey = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_API_KEY_ENV] ?? process.env[CHATGPT_AUTH_API_KEY_ENV];
565
+ if (tokenProviderUrl && tokenProviderUrl.trim().length > 0 && tokenProviderKey && tokenProviderKey.trim().length > 0) {
566
+ if (cachedProfile && !isExpired(cachedProfile)) {
567
+ return cachedProfile;
568
+ }
569
+ if (refreshPromise) {
570
+ return refreshPromise;
571
+ }
572
+ refreshPromise = (async () => {
573
+ try {
574
+ const store = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_STORE_ENV] ?? process.env[CHATGPT_AUTH_SERVER_STORE_ENV];
575
+ const profile = await fetchChatGptAuthProfileFromTokenProvider({
576
+ baseUrl: tokenProviderUrl,
577
+ apiKey: tokenProviderKey,
578
+ store: store ?? void 0
579
+ });
580
+ cachedProfile = profile;
581
+ return profile;
582
+ } finally {
583
+ refreshPromise = null;
584
+ }
585
+ })();
586
+ return refreshPromise;
587
+ }
470
588
  if (cachedProfile && !isExpired(cachedProfile)) {
471
589
  return cachedProfile;
472
590
  }
@@ -475,8 +593,8 @@ async function getChatGptAuthProfile() {
475
593
  }
476
594
  refreshPromise = (async () => {
477
595
  try {
478
- const baseProfile = cachedProfile ?? loadAuthProfileFromEnv();
479
- const profile = isExpired(baseProfile) ? await refreshChatGptOauthToken(baseProfile.refresh) : baseProfile;
596
+ const baseProfile = cachedProfile ?? loadAuthProfileFromCodexStore();
597
+ const profile = isExpired(baseProfile) ? await refreshAndPersistCodexProfile(baseProfile) : baseProfile;
480
598
  cachedProfile = profile;
481
599
  return profile;
482
600
  } finally {
@@ -485,39 +603,111 @@ async function getChatGptAuthProfile() {
485
603
  })();
486
604
  return refreshPromise;
487
605
  }
488
- function profileFromTokenResponse(payload) {
489
- const expires = Date.now() + normalizeNumber(payload.expires_in) * 1e3;
490
- const accountId = extractChatGptAccountId(payload.id_token ?? "") ?? extractChatGptAccountId(payload.access_token);
606
+ function resolveCodexHome() {
607
+ const codexHome = process.env.CODEX_HOME;
608
+ if (codexHome && codexHome.trim().length > 0) {
609
+ return codexHome.trim();
610
+ }
611
+ return import_node_path2.default.join(import_node_os.default.homedir(), ".codex");
612
+ }
613
+ function resolveCodexAuthJsonPath() {
614
+ return import_node_path2.default.join(resolveCodexHome(), "auth.json");
615
+ }
616
+ function loadAuthProfileFromCodexStore() {
617
+ const authPath = resolveCodexAuthJsonPath();
618
+ let raw;
619
+ try {
620
+ raw = import_node_fs2.default.readFileSync(authPath, "utf8");
621
+ } catch {
622
+ throw new Error(
623
+ `ChatGPT auth not configured. Set ${CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV}+${CHATGPT_AUTH_API_KEY_ENV} or login via Codex to create ${authPath}.`
624
+ );
625
+ }
626
+ let parsed;
627
+ try {
628
+ parsed = CodexAuthFileSchema.parse(JSON.parse(raw));
629
+ } catch (e) {
630
+ throw new Error(
631
+ `Failed to parse Codex auth store at ${authPath}. (${e?.message ?? e})`
632
+ );
633
+ }
634
+ const tokens = parsed.tokens;
635
+ if (!tokens) {
636
+ throw new Error(
637
+ `Codex auth store at ${authPath} is missing tokens. Re-login via Codex, or configure ${CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV}.`
638
+ );
639
+ }
640
+ const access = tokens.access_token ?? tokens.accessToken ?? void 0;
641
+ const refresh = tokens.refresh_token ?? tokens.refreshToken ?? void 0;
642
+ const idToken = tokens.id_token ?? tokens.idToken ?? void 0;
643
+ if (!access || !refresh) {
644
+ throw new Error(
645
+ `Codex auth store at ${authPath} is missing access_token/refresh_token. Re-login via Codex, or configure ${CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV}.`
646
+ );
647
+ }
648
+ const expires = extractJwtExpiry(access) ?? extractJwtExpiry(idToken ?? "") ?? Date.now() + 5 * 6e4;
649
+ const accountId = tokens.account_id ?? tokens.accountId ?? extractChatGptAccountId(idToken ?? "") ?? extractChatGptAccountId(access);
491
650
  if (!accountId) {
492
- throw new Error("Failed to extract chatgpt_account_id from access token.");
651
+ throw new Error(`Codex auth store at ${authPath} is missing chatgpt_account_id/account_id.`);
493
652
  }
494
653
  return {
495
- access: payload.access_token,
496
- refresh: payload.refresh_token,
654
+ access,
655
+ refresh,
497
656
  expires,
498
657
  accountId,
499
- idToken: payload.id_token
658
+ idToken: idToken ?? void 0
500
659
  };
501
660
  }
502
- function normalizeAuthProfile(data) {
503
- const access = data.access ?? data.access_token ?? data.accessToken ?? void 0;
504
- const refresh = data.refresh ?? data.refresh_token ?? data.refreshToken ?? void 0;
505
- if (!access || !refresh) {
506
- throw new Error("ChatGPT credentials must include access and refresh.");
661
+ async function refreshAndPersistCodexProfile(baseProfile) {
662
+ const refreshed = await refreshChatGptOauthToken(baseProfile.refresh, {
663
+ accountId: baseProfile.accountId,
664
+ idToken: baseProfile.idToken
665
+ });
666
+ persistCodexTokens(refreshed);
667
+ return refreshed;
668
+ }
669
+ function persistCodexTokens(profile) {
670
+ const authPath = resolveCodexAuthJsonPath();
671
+ const codexHome = import_node_path2.default.dirname(authPath);
672
+ let doc = {};
673
+ try {
674
+ doc = JSON.parse(import_node_fs2.default.readFileSync(authPath, "utf8"));
675
+ } catch {
676
+ doc = {};
677
+ }
678
+ if (!doc || typeof doc !== "object") {
679
+ doc = {};
507
680
  }
508
- const expiresRaw = data.expires ?? data.expires_at ?? data.expiresAt;
509
- const idToken = data.idToken ?? data.id_token ?? void 0;
510
- const expires = normalizeEpochMillis(expiresRaw) ?? extractJwtExpiry(idToken ?? access) ?? Date.now() + 5 * 6e4;
511
- const accountId = data.accountId ?? data.account_id ?? extractChatGptAccountId(idToken ?? "") ?? extractChatGptAccountId(access);
681
+ if (!doc.tokens || typeof doc.tokens !== "object") {
682
+ doc.tokens = {};
683
+ }
684
+ doc.tokens.access_token = profile.access;
685
+ doc.tokens.refresh_token = profile.refresh;
686
+ doc.tokens.account_id = profile.accountId;
687
+ if (profile.idToken) {
688
+ doc.tokens.id_token = profile.idToken;
689
+ }
690
+ doc.last_refresh = (/* @__PURE__ */ new Date()).toISOString();
691
+ import_node_fs2.default.mkdirSync(codexHome, { recursive: true, mode: 448 });
692
+ const tmpPath = `${authPath}.tmp.${process.pid}.${Math.random().toString(16).slice(2)}`;
693
+ import_node_fs2.default.writeFileSync(tmpPath, `${JSON.stringify(doc, null, 2)}
694
+ `, { mode: 384 });
695
+ import_node_fs2.default.renameSync(tmpPath, authPath);
696
+ }
697
+ function profileFromTokenResponse(payload, fallback) {
698
+ const expires = Date.now() + normalizeNumber(payload.expires_in) * 1e3;
699
+ const fallbackAccountId = fallback?.accountId;
700
+ const fallbackIdToken = fallback?.idToken;
701
+ const accountId = extractChatGptAccountId(payload.id_token ?? "") ?? extractChatGptAccountId(payload.access_token) ?? fallbackAccountId;
512
702
  if (!accountId) {
513
- throw new Error("ChatGPT credentials missing chatgpt_account_id.");
703
+ throw new Error("Failed to extract chatgpt_account_id from access token.");
514
704
  }
515
705
  return {
516
- access,
517
- refresh,
706
+ access: payload.access_token,
707
+ refresh: payload.refresh_token,
518
708
  expires,
519
709
  accountId,
520
- idToken: idToken ?? void 0
710
+ idToken: payload.id_token ?? fallbackIdToken
521
711
  };
522
712
  }
523
713
  function normalizeEpochMillis(value) {
@@ -546,31 +736,6 @@ function isExpired(profile) {
546
736
  }
547
737
  return Date.now() + TOKEN_EXPIRY_BUFFER_MS >= expires;
548
738
  }
549
- function loadAuthProfileFromEnv() {
550
- loadLocalEnv();
551
- const rawJson = process.env[CHATGPT_AUTH_JSON_ENV];
552
- if (rawJson && rawJson.trim().length > 0) {
553
- return normalizeAuthProfile(AuthInputSchema.parse(JSON.parse(rawJson)));
554
- }
555
- const rawB64 = process.env[CHATGPT_AUTH_JSON_B64_ENV];
556
- if (rawB64 && rawB64.trim().length > 0) {
557
- const decoded = import_node_buffer.Buffer.from(rawB64.trim(), "base64url").toString("utf8");
558
- return normalizeAuthProfile(AuthInputSchema.parse(JSON.parse(decoded)));
559
- }
560
- const access = process.env[CHATGPT_ACCESS_ENV] ?? process.env[CHATGPT_ACCESS_TOKEN_ENV] ?? void 0;
561
- const refresh = process.env[CHATGPT_REFRESH_ENV] ?? process.env[CHATGPT_REFRESH_TOKEN_ENV] ?? void 0;
562
- const expires = process.env[CHATGPT_EXPIRES_ENV] ?? process.env[CHATGPT_EXPIRES_AT_ENV] ?? void 0;
563
- const accountId = process.env[CHATGPT_ACCOUNT_ID_ENV] ?? void 0;
564
- const idToken = process.env[CHATGPT_ID_TOKEN_ENV] ?? void 0;
565
- const parsed = AuthInputSchema.parse({
566
- access,
567
- refresh,
568
- expires,
569
- accountId,
570
- idToken
571
- });
572
- return normalizeAuthProfile(parsed);
573
- }
574
739
  function decodeJwtPayload(token) {
575
740
  const segments = token.split(".");
576
741
  if (segments.length < 2) {
@@ -601,8 +766,12 @@ function extractChatGptAccountId(token) {
601
766
  if (!payload || typeof payload !== "object") {
602
767
  return void 0;
603
768
  }
604
- const accountId = payload.chatgpt_account_id;
605
- return typeof accountId === "string" && accountId.length > 0 ? accountId : void 0;
769
+ const direct = payload.chatgpt_account_id;
770
+ if (typeof direct === "string" && direct.length > 0) {
771
+ return direct;
772
+ }
773
+ const namespaced = payload["https://api.openai.com/auth"]?.chatgpt_account_id;
774
+ return typeof namespaced === "string" && namespaced.length > 0 ? namespaced : void 0;
606
775
  }
607
776
 
608
777
  // src/openai/chatgpt-codex.ts
@@ -638,7 +807,19 @@ async function streamChatGptCodexResponse(options) {
638
807
  return parseEventStream(body);
639
808
  }
640
809
  async function collectChatGptCodexResponse(options) {
641
- const stream = await streamChatGptCodexResponse(options);
810
+ let stream;
811
+ try {
812
+ stream = await streamChatGptCodexResponse(options);
813
+ } catch (error) {
814
+ if (shouldRetryWithoutReasoningSummary(options.request, error)) {
815
+ stream = await streamChatGptCodexResponse({
816
+ ...options,
817
+ request: removeReasoningSummary(options.request)
818
+ });
819
+ } else {
820
+ throw error;
821
+ }
822
+ }
642
823
  const toolCalls = /* @__PURE__ */ new Map();
643
824
  const toolCallOrder = [];
644
825
  const webSearchCalls = /* @__PURE__ */ new Map();
@@ -647,6 +828,7 @@ async function collectChatGptCodexResponse(options) {
647
828
  const reasoningText = "";
648
829
  let reasoningSummaryText = "";
649
830
  let usage;
831
+ let responseId;
650
832
  let model;
651
833
  let status;
652
834
  let blocked = false;
@@ -687,7 +869,18 @@ async function collectChatGptCodexResponse(options) {
687
869
  if (!toolCalls.has(callId)) {
688
870
  toolCallOrder.push(callId);
689
871
  }
690
- toolCalls.set(callId, { id, callId, name, arguments: args });
872
+ toolCalls.set(callId, { kind: "function", id, callId, name, arguments: args });
873
+ }
874
+ } else if (item.type === "custom_tool_call") {
875
+ const id = typeof item.id === "string" ? item.id : "";
876
+ const callId = typeof item.call_id === "string" ? item.call_id : id;
877
+ const name = typeof item.name === "string" ? item.name : "";
878
+ const input = typeof item.input === "string" ? item.input : "";
879
+ if (callId) {
880
+ if (!toolCalls.has(callId)) {
881
+ toolCallOrder.push(callId);
882
+ }
883
+ toolCalls.set(callId, { kind: "custom", id, callId, name, input });
691
884
  }
692
885
  } else if (item.type === "web_search_call") {
693
886
  const id = typeof item.id === "string" ? item.id : "";
@@ -709,6 +902,7 @@ async function collectChatGptCodexResponse(options) {
709
902
  const response = event.response;
710
903
  if (response) {
711
904
  usage = response.usage;
905
+ responseId = typeof response.id === "string" ? response.id : responseId;
712
906
  model = typeof response.model === "string" ? response.model : void 0;
713
907
  status = typeof response.status === "string" ? response.status : void 0;
714
908
  }
@@ -718,6 +912,7 @@ async function collectChatGptCodexResponse(options) {
718
912
  const response = event.response;
719
913
  if (response) {
720
914
  usage = response.usage;
915
+ responseId = typeof response.id === "string" ? response.id : responseId;
721
916
  model = typeof response.model === "string" ? response.model : void 0;
722
917
  status = typeof response.status === "string" ? response.status : void 0;
723
918
  }
@@ -727,6 +922,7 @@ async function collectChatGptCodexResponse(options) {
727
922
  const response = event.response;
728
923
  if (response) {
729
924
  usage = response.usage;
925
+ responseId = typeof response.id === "string" ? response.id : responseId;
730
926
  model = typeof response.model === "string" ? response.model : void 0;
731
927
  status = typeof response.status === "string" ? response.status : void 0;
732
928
  }
@@ -744,15 +940,38 @@ async function collectChatGptCodexResponse(options) {
744
940
  toolCalls: orderedToolCalls,
745
941
  webSearchCalls: orderedWebSearchCalls,
746
942
  usage,
943
+ id: responseId,
747
944
  model,
748
945
  status,
749
946
  blocked
750
947
  };
751
948
  }
949
+ function shouldRetryWithoutReasoningSummary(request, error) {
950
+ if (!request.reasoning?.summary) {
951
+ return false;
952
+ }
953
+ if (!(error instanceof Error)) {
954
+ return false;
955
+ }
956
+ const message = error.message.toLowerCase();
957
+ return message.includes("unsupported parameter") && message.includes("reasoning.summary");
958
+ }
959
+ function removeReasoningSummary(request) {
960
+ const reasoning = request.reasoning;
961
+ if (!reasoning?.summary) {
962
+ return request;
963
+ }
964
+ return {
965
+ ...request,
966
+ reasoning: {
967
+ effort: reasoning.effort
968
+ }
969
+ };
970
+ }
752
971
  function buildUserAgent() {
753
972
  const node = process.version;
754
- const platform = import_node_os.default.platform();
755
- const release = import_node_os.default.release();
973
+ const platform = import_node_os2.default.platform();
974
+ const release = import_node_os2.default.release();
756
975
  return `@ljoukov/llm (node ${node}; ${platform} ${release})`;
757
976
  }
758
977
  async function* parseEventStream(stream) {
@@ -900,6 +1119,110 @@ function createCallScheduler(options = {}) {
900
1119
  return { run };
901
1120
  }
902
1121
 
1122
+ // src/fireworks/client.ts
1123
+ var import_openai = __toESM(require("openai"), 1);
1124
+ var import_undici = require("undici");
1125
+ var DEFAULT_FIREWORKS_BASE_URL = "https://api.fireworks.ai/inference/v1";
1126
+ var DEFAULT_FIREWORKS_TIMEOUT_MS = 15 * 6e4;
1127
+ var cachedClient = null;
1128
+ var cachedFetch = null;
1129
+ var cachedBaseUrl = null;
1130
+ var cachedApiKey = null;
1131
+ var cachedTimeoutMs = null;
1132
+ function resolveTimeoutMs() {
1133
+ if (cachedTimeoutMs !== null) {
1134
+ return cachedTimeoutMs;
1135
+ }
1136
+ const raw = process.env.FIREWORKS_TIMEOUT_MS;
1137
+ const parsed = raw ? Number(raw) : Number.NaN;
1138
+ cachedTimeoutMs = Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_FIREWORKS_TIMEOUT_MS;
1139
+ return cachedTimeoutMs;
1140
+ }
1141
+ function resolveBaseUrl() {
1142
+ if (cachedBaseUrl !== null) {
1143
+ return cachedBaseUrl;
1144
+ }
1145
+ loadLocalEnv();
1146
+ const raw = process.env.FIREWORKS_BASE_URL?.trim();
1147
+ cachedBaseUrl = raw && raw.length > 0 ? raw : DEFAULT_FIREWORKS_BASE_URL;
1148
+ return cachedBaseUrl;
1149
+ }
1150
+ function resolveApiKey() {
1151
+ if (cachedApiKey !== null) {
1152
+ return cachedApiKey;
1153
+ }
1154
+ loadLocalEnv();
1155
+ const raw = process.env.FIREWORKS_TOKEN ?? process.env.FIREWORKS_API_KEY;
1156
+ const token = raw?.trim();
1157
+ if (!token) {
1158
+ throw new Error(
1159
+ "FIREWORKS_TOKEN (or FIREWORKS_API_KEY) must be provided to access Fireworks APIs."
1160
+ );
1161
+ }
1162
+ cachedApiKey = token;
1163
+ return cachedApiKey;
1164
+ }
1165
+ function getFireworksFetch() {
1166
+ if (cachedFetch) {
1167
+ return cachedFetch;
1168
+ }
1169
+ const timeoutMs = resolveTimeoutMs();
1170
+ const dispatcher = new import_undici.Agent({
1171
+ bodyTimeout: timeoutMs,
1172
+ headersTimeout: timeoutMs
1173
+ });
1174
+ cachedFetch = ((input, init) => {
1175
+ return (0, import_undici.fetch)(input, {
1176
+ ...init ?? {},
1177
+ dispatcher
1178
+ });
1179
+ });
1180
+ return cachedFetch;
1181
+ }
1182
+ function getFireworksClient() {
1183
+ if (cachedClient) {
1184
+ return cachedClient;
1185
+ }
1186
+ cachedClient = new import_openai.default({
1187
+ apiKey: resolveApiKey(),
1188
+ baseURL: resolveBaseUrl(),
1189
+ timeout: resolveTimeoutMs(),
1190
+ fetch: getFireworksFetch()
1191
+ });
1192
+ return cachedClient;
1193
+ }
1194
+
1195
+ // src/fireworks/calls.ts
1196
+ var scheduler = createCallScheduler({
1197
+ maxParallelRequests: 3,
1198
+ minIntervalBetweenStartMs: 200,
1199
+ startJitterMs: 200
1200
+ });
1201
+ async function runFireworksCall(fn) {
1202
+ return scheduler.run(async () => fn(getFireworksClient()));
1203
+ }
1204
+
1205
+ // src/fireworks/models.ts
1206
+ var FIREWORKS_MODEL_IDS = ["kimi-k2.5", "glm-5", "minimax-m2.1"];
1207
+ var FIREWORKS_DEFAULT_KIMI_MODEL = "kimi-k2.5";
1208
+ var FIREWORKS_DEFAULT_GLM_MODEL = "glm-5";
1209
+ var FIREWORKS_DEFAULT_MINIMAX_MODEL = "minimax-m2.1";
1210
+ var FIREWORKS_CANONICAL_MODEL_IDS = {
1211
+ "kimi-k2.5": "accounts/fireworks/models/kimi-k2p5",
1212
+ "glm-5": "accounts/fireworks/models/glm-5",
1213
+ "minimax-m2.1": "accounts/fireworks/models/minimax-m2p1"
1214
+ };
1215
+ function isFireworksModelId(value) {
1216
+ return FIREWORKS_MODEL_IDS.includes(value.trim());
1217
+ }
1218
+ function resolveFireworksModelId(model) {
1219
+ const trimmed = model.trim();
1220
+ if (!isFireworksModelId(trimmed)) {
1221
+ return void 0;
1222
+ }
1223
+ return FIREWORKS_CANONICAL_MODEL_IDS[trimmed];
1224
+ }
1225
+
903
1226
  // src/google/client.ts
904
1227
  var import_genai = require("@google/genai");
905
1228
 
@@ -968,6 +1291,7 @@ function getGoogleAuthOptions(scopes) {
968
1291
  // src/google/client.ts
969
1292
  var GEMINI_MODEL_IDS = [
970
1293
  "gemini-3-pro-preview",
1294
+ "gemini-3-flash-preview",
971
1295
  "gemini-2.5-pro",
972
1296
  "gemini-flash-latest",
973
1297
  "gemini-flash-lite-latest"
@@ -1207,7 +1531,7 @@ function retryDelayMs(attempt) {
1207
1531
  const jitter = Math.floor(Math.random() * 200);
1208
1532
  return base + jitter;
1209
1533
  }
1210
- var scheduler = createCallScheduler({
1534
+ var scheduler2 = createCallScheduler({
1211
1535
  maxParallelRequests: 3,
1212
1536
  minIntervalBetweenStartMs: 200,
1213
1537
  startJitterMs: 200,
@@ -1223,46 +1547,46 @@ var scheduler = createCallScheduler({
1223
1547
  }
1224
1548
  });
1225
1549
  async function runGeminiCall(fn) {
1226
- return scheduler.run(async () => fn(await getGeminiClient()));
1550
+ return scheduler2.run(async () => fn(await getGeminiClient()));
1227
1551
  }
1228
1552
 
1229
1553
  // src/openai/client.ts
1230
- var import_openai = __toESM(require("openai"), 1);
1231
- var import_undici = require("undici");
1232
- var cachedApiKey = null;
1233
- var cachedClient = null;
1234
- var cachedFetch = null;
1235
- var cachedTimeoutMs = null;
1554
+ var import_openai2 = __toESM(require("openai"), 1);
1555
+ var import_undici2 = require("undici");
1556
+ var cachedApiKey2 = null;
1557
+ var cachedClient2 = null;
1558
+ var cachedFetch2 = null;
1559
+ var cachedTimeoutMs2 = null;
1236
1560
  var DEFAULT_OPENAI_TIMEOUT_MS = 15 * 6e4;
1237
1561
  function resolveOpenAiTimeoutMs() {
1238
- if (cachedTimeoutMs !== null) {
1239
- return cachedTimeoutMs;
1562
+ if (cachedTimeoutMs2 !== null) {
1563
+ return cachedTimeoutMs2;
1240
1564
  }
1241
1565
  const raw = process.env.OPENAI_STREAM_TIMEOUT_MS ?? process.env.OPENAI_TIMEOUT_MS;
1242
1566
  const parsed = raw ? Number(raw) : Number.NaN;
1243
- cachedTimeoutMs = Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_OPENAI_TIMEOUT_MS;
1244
- return cachedTimeoutMs;
1567
+ cachedTimeoutMs2 = Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_OPENAI_TIMEOUT_MS;
1568
+ return cachedTimeoutMs2;
1245
1569
  }
1246
1570
  function getOpenAiFetch() {
1247
- if (cachedFetch) {
1248
- return cachedFetch;
1571
+ if (cachedFetch2) {
1572
+ return cachedFetch2;
1249
1573
  }
1250
1574
  const timeoutMs = resolveOpenAiTimeoutMs();
1251
- const dispatcher = new import_undici.Agent({
1575
+ const dispatcher = new import_undici2.Agent({
1252
1576
  bodyTimeout: timeoutMs,
1253
1577
  headersTimeout: timeoutMs
1254
1578
  });
1255
- cachedFetch = ((input, init) => {
1256
- return (0, import_undici.fetch)(input, {
1579
+ cachedFetch2 = ((input, init) => {
1580
+ return (0, import_undici2.fetch)(input, {
1257
1581
  ...init ?? {},
1258
1582
  dispatcher
1259
1583
  });
1260
1584
  });
1261
- return cachedFetch;
1585
+ return cachedFetch2;
1262
1586
  }
1263
1587
  function getOpenAiApiKey() {
1264
- if (cachedApiKey !== null) {
1265
- return cachedApiKey;
1588
+ if (cachedApiKey2 !== null) {
1589
+ return cachedApiKey2;
1266
1590
  }
1267
1591
  loadLocalEnv();
1268
1592
  const raw = process.env.OPENAI_API_KEY;
@@ -1270,32 +1594,32 @@ function getOpenAiApiKey() {
1270
1594
  if (!value) {
1271
1595
  throw new Error("OPENAI_API_KEY must be provided to access OpenAI APIs.");
1272
1596
  }
1273
- cachedApiKey = value;
1274
- return cachedApiKey;
1597
+ cachedApiKey2 = value;
1598
+ return cachedApiKey2;
1275
1599
  }
1276
1600
  function getOpenAiClient() {
1277
- if (cachedClient) {
1278
- return cachedClient;
1601
+ if (cachedClient2) {
1602
+ return cachedClient2;
1279
1603
  }
1280
1604
  const apiKey = getOpenAiApiKey();
1281
1605
  const timeoutMs = resolveOpenAiTimeoutMs();
1282
- cachedClient = new import_openai.default({
1606
+ cachedClient2 = new import_openai2.default({
1283
1607
  apiKey,
1284
1608
  fetch: getOpenAiFetch(),
1285
1609
  timeout: timeoutMs
1286
1610
  });
1287
- return cachedClient;
1611
+ return cachedClient2;
1288
1612
  }
1289
1613
 
1290
1614
  // src/openai/calls.ts
1291
1615
  var DEFAULT_OPENAI_REASONING_EFFORT = "medium";
1292
- var scheduler2 = createCallScheduler({
1616
+ var scheduler3 = createCallScheduler({
1293
1617
  maxParallelRequests: 3,
1294
1618
  minIntervalBetweenStartMs: 200,
1295
1619
  startJitterMs: 200
1296
1620
  });
1297
1621
  async function runOpenAiCall(fn) {
1298
- return scheduler2.run(async () => fn(getOpenAiClient()));
1622
+ return scheduler3.run(async () => fn(getOpenAiClient()));
1299
1623
  }
1300
1624
 
1301
1625
  // src/llm.ts
@@ -1311,7 +1635,16 @@ var LlmJsonCallError = class extends Error {
1311
1635
  }
1312
1636
  };
1313
1637
  function tool(options) {
1314
- return options;
1638
+ return {
1639
+ type: "function",
1640
+ ...options
1641
+ };
1642
+ }
1643
+ function customTool(options) {
1644
+ return {
1645
+ type: "custom",
1646
+ ...options
1647
+ };
1315
1648
  }
1316
1649
  function isPlainRecord(value) {
1317
1650
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -1657,6 +1990,10 @@ function resolveProvider(model) {
1657
1990
  if (model.startsWith("gemini-")) {
1658
1991
  return { provider: "gemini", model };
1659
1992
  }
1993
+ const fireworksModel = resolveFireworksModelId(model);
1994
+ if (fireworksModel) {
1995
+ return { provider: "fireworks", model: fireworksModel };
1996
+ }
1660
1997
  return { provider: "openai", model };
1661
1998
  }
1662
1999
  function isOpenAiCodexModel(modelId) {
@@ -1686,6 +2023,27 @@ function toOpenAiReasoningEffort(effort) {
1686
2023
  function resolveOpenAiVerbosity(modelId) {
1687
2024
  return isOpenAiCodexModel(modelId) ? "medium" : "high";
1688
2025
  }
2026
+ function isRetryableChatGptTransportError(error) {
2027
+ if (!(error instanceof Error)) {
2028
+ return false;
2029
+ }
2030
+ const message = error.message.toLowerCase();
2031
+ return message === "terminated" || message.includes("socket hang up") || message.includes("fetch failed") || message.includes("network");
2032
+ }
2033
+ async function collectChatGptCodexResponseWithRetry(options, maxAttempts = 2) {
2034
+ let attempt = 1;
2035
+ while (true) {
2036
+ try {
2037
+ return await collectChatGptCodexResponse(options);
2038
+ } catch (error) {
2039
+ if (attempt >= maxAttempts || !isRetryableChatGptTransportError(error)) {
2040
+ throw error;
2041
+ }
2042
+ await new Promise((resolve) => setTimeout(resolve, 250 * attempt));
2043
+ attempt += 1;
2044
+ }
2045
+ }
2046
+ }
1689
2047
  function isInlineImageMime(mimeType) {
1690
2048
  if (!mimeType) {
1691
2049
  return false;
@@ -2268,6 +2626,53 @@ function toChatGptInput(contents) {
2268
2626
  input
2269
2627
  };
2270
2628
  }
2629
+ function toFireworksMessages(contents, options) {
2630
+ const systemMessages = [];
2631
+ const messages = [];
2632
+ if (options?.responseMimeType === "application/json") {
2633
+ systemMessages.push("Return valid JSON only. Do not include markdown or prose outside JSON.");
2634
+ }
2635
+ if (options?.responseJsonSchema) {
2636
+ systemMessages.push(`Target JSON schema:
2637
+ ${JSON.stringify(options.responseJsonSchema)}`);
2638
+ }
2639
+ for (const content of contents) {
2640
+ const text = content.parts.map((part) => {
2641
+ if (part.type === "text") {
2642
+ return part.text;
2643
+ }
2644
+ const mimeType = part.mimeType ?? "application/octet-stream";
2645
+ if (isInlineImageMime(mimeType)) {
2646
+ return `[image:${mimeType}]`;
2647
+ }
2648
+ return `[file:${mimeType}]`;
2649
+ }).join("\n").trim();
2650
+ if (content.role === "system" || content.role === "developer") {
2651
+ if (text.length > 0) {
2652
+ systemMessages.push(text);
2653
+ }
2654
+ continue;
2655
+ }
2656
+ if (content.role === "tool" || content.role === "assistant") {
2657
+ messages.push({
2658
+ role: "assistant",
2659
+ content: text.length > 0 ? text : "(empty content)"
2660
+ });
2661
+ continue;
2662
+ }
2663
+ messages.push({
2664
+ role: "user",
2665
+ content: text.length > 0 ? text : "(empty content)"
2666
+ });
2667
+ }
2668
+ if (systemMessages.length > 0) {
2669
+ messages.unshift({
2670
+ role: "system",
2671
+ content: systemMessages.join("\n\n")
2672
+ });
2673
+ }
2674
+ return messages;
2675
+ }
2271
2676
  function toGeminiTools(tools) {
2272
2677
  if (!tools || tools.length === 0) {
2273
2678
  return void 0;
@@ -2441,6 +2846,41 @@ function extractChatGptUsageTokens(usage) {
2441
2846
  totalTokens
2442
2847
  };
2443
2848
  }
2849
+ function extractFireworksUsageTokens(usage) {
2850
+ if (!usage || typeof usage !== "object") {
2851
+ return void 0;
2852
+ }
2853
+ const promptTokens = toMaybeNumber(
2854
+ usage.prompt_tokens ?? usage.input_tokens
2855
+ );
2856
+ const cachedTokens = toMaybeNumber(
2857
+ usage.prompt_tokens_details?.cached_tokens ?? usage.input_tokens_details?.cached_tokens
2858
+ );
2859
+ const outputTokensRaw = toMaybeNumber(
2860
+ usage.completion_tokens ?? usage.output_tokens
2861
+ );
2862
+ const reasoningTokens = toMaybeNumber(
2863
+ usage.completion_tokens_details?.reasoning_tokens ?? usage.output_tokens_details?.reasoning_tokens
2864
+ );
2865
+ const totalTokens = toMaybeNumber(
2866
+ usage.total_tokens ?? usage.totalTokenCount
2867
+ );
2868
+ let responseTokens;
2869
+ if (outputTokensRaw !== void 0) {
2870
+ const adjusted = outputTokensRaw - (reasoningTokens ?? 0);
2871
+ responseTokens = adjusted >= 0 ? adjusted : 0;
2872
+ }
2873
+ if (promptTokens === void 0 && cachedTokens === void 0 && responseTokens === void 0 && reasoningTokens === void 0 && totalTokens === void 0) {
2874
+ return void 0;
2875
+ }
2876
+ return {
2877
+ promptTokens,
2878
+ cachedTokens,
2879
+ responseTokens,
2880
+ thinkingTokens: reasoningTokens,
2881
+ totalTokens
2882
+ };
2883
+ }
2444
2884
  var MODERATION_FINISH_REASONS = /* @__PURE__ */ new Set([
2445
2885
  import_genai2.FinishReason.SAFETY,
2446
2886
  import_genai2.FinishReason.BLOCKLIST,
@@ -2479,8 +2919,8 @@ function parseOpenAiToolArguments(raw) {
2479
2919
  function formatZodIssues(issues) {
2480
2920
  const messages = [];
2481
2921
  for (const issue of issues) {
2482
- const path5 = issue.path.length > 0 ? issue.path.map(String).join(".") : "input";
2483
- messages.push(`${path5}: ${issue.message}`);
2922
+ const path6 = issue.path.length > 0 ? issue.path.map(String).join(".") : "input";
2923
+ messages.push(`${path6}: ${issue.message}`);
2484
2924
  }
2485
2925
  return messages.join("; ");
2486
2926
  }
@@ -2496,7 +2936,7 @@ function buildToolErrorOutput(message, issues) {
2496
2936
  return output;
2497
2937
  }
2498
2938
  async function executeToolCall(params) {
2499
- const { toolName, tool: tool2, rawInput, parseError } = params;
2939
+ const { callKind, toolName, tool: tool2, rawInput, parseError } = params;
2500
2940
  if (!tool2) {
2501
2941
  const message = `Unknown tool: ${toolName}`;
2502
2942
  return {
@@ -2504,6 +2944,39 @@ async function executeToolCall(params) {
2504
2944
  outputPayload: buildToolErrorOutput(message)
2505
2945
  };
2506
2946
  }
2947
+ if (callKind === "custom") {
2948
+ if (!isCustomTool(tool2)) {
2949
+ const message = `Tool ${toolName} was called as custom_tool_call but is declared as function.`;
2950
+ const outputPayload = buildToolErrorOutput(message);
2951
+ return {
2952
+ result: { toolName, input: rawInput, output: outputPayload, error: message },
2953
+ outputPayload
2954
+ };
2955
+ }
2956
+ const input = typeof rawInput === "string" ? rawInput : String(rawInput ?? "");
2957
+ try {
2958
+ const output = await tool2.execute(input);
2959
+ return {
2960
+ result: { toolName, input, output },
2961
+ outputPayload: output
2962
+ };
2963
+ } catch (error) {
2964
+ const message = error instanceof Error ? error.message : String(error);
2965
+ const outputPayload = buildToolErrorOutput(`Tool ${toolName} failed: ${message}`);
2966
+ return {
2967
+ result: { toolName, input, output: outputPayload, error: message },
2968
+ outputPayload
2969
+ };
2970
+ }
2971
+ }
2972
+ if (isCustomTool(tool2)) {
2973
+ const message = `Tool ${toolName} was called as function_call but is declared as custom.`;
2974
+ const outputPayload = buildToolErrorOutput(message);
2975
+ return {
2976
+ result: { toolName, input: rawInput, output: outputPayload, error: message },
2977
+ outputPayload
2978
+ };
2979
+ }
2507
2980
  if (parseError) {
2508
2981
  const message = `Invalid JSON for tool ${toolName}: ${parseError}`;
2509
2982
  return {
@@ -2560,8 +3033,12 @@ function normalizeChatGptToolIds(params) {
2560
3033
  rawItemId = nextItemId ?? rawItemId;
2561
3034
  }
2562
3035
  const callValue = sanitizeChatGptToolId(rawCallId || rawItemId || (0, import_node_crypto.randomBytes)(8).toString("hex"));
2563
- let itemValue = sanitizeChatGptToolId(rawItemId || `fc-${callValue}`);
2564
- if (!itemValue.startsWith("fc")) {
3036
+ let itemValue = sanitizeChatGptToolId(rawItemId || callValue);
3037
+ if (params.callKind === "custom") {
3038
+ if (!itemValue.startsWith("ctc")) {
3039
+ itemValue = `ctc_${itemValue}`;
3040
+ }
3041
+ } else if (!itemValue.startsWith("fc")) {
2565
3042
  itemValue = `fc-${itemValue}`;
2566
3043
  }
2567
3044
  return { callId: callValue, itemId: itemValue };
@@ -2626,7 +3103,7 @@ function extractOpenAiResponseParts(response) {
2626
3103
  }
2627
3104
  return { parts, blocked };
2628
3105
  }
2629
- function extractOpenAiFunctionCalls(output) {
3106
+ function extractOpenAiToolCalls(output) {
2630
3107
  const calls = [];
2631
3108
  if (!Array.isArray(output)) {
2632
3109
  return calls;
@@ -2635,22 +3112,78 @@ function extractOpenAiFunctionCalls(output) {
2635
3112
  if (!item || typeof item !== "object") {
2636
3113
  continue;
2637
3114
  }
2638
- if (item.type === "function_call") {
3115
+ const itemType = item.type;
3116
+ if (itemType === "function_call") {
2639
3117
  const name = typeof item.name === "string" ? item.name : "";
2640
3118
  const args = typeof item.arguments === "string" ? item.arguments : "";
2641
3119
  const call_id = typeof item.call_id === "string" ? item.call_id : "";
2642
3120
  const id = typeof item.id === "string" ? item.id : void 0;
2643
3121
  if (name && call_id) {
2644
- calls.push({ name, arguments: args, call_id, id });
3122
+ calls.push({ kind: "function", name, arguments: args, call_id, id });
3123
+ }
3124
+ continue;
3125
+ }
3126
+ if (itemType === "custom_tool_call") {
3127
+ const name = typeof item.name === "string" ? item.name : "";
3128
+ const input = typeof item.input === "string" ? item.input : "";
3129
+ const call_id = typeof item.call_id === "string" ? item.call_id : "";
3130
+ const id = typeof item.id === "string" ? item.id : void 0;
3131
+ if (name && call_id) {
3132
+ calls.push({ kind: "custom", name, input, call_id, id });
2645
3133
  }
2646
3134
  }
2647
3135
  }
2648
3136
  return calls;
2649
3137
  }
3138
+ function extractFireworksMessageText(message) {
3139
+ if (!message || typeof message !== "object") {
3140
+ return "";
3141
+ }
3142
+ const content = message.content;
3143
+ if (typeof content === "string") {
3144
+ return content;
3145
+ }
3146
+ if (!Array.isArray(content)) {
3147
+ return "";
3148
+ }
3149
+ let text = "";
3150
+ for (const part of content) {
3151
+ const textPart = part.text;
3152
+ if (typeof textPart === "string") {
3153
+ text += textPart;
3154
+ }
3155
+ }
3156
+ return text;
3157
+ }
3158
+ function extractFireworksToolCalls(message) {
3159
+ if (!message || typeof message !== "object") {
3160
+ return [];
3161
+ }
3162
+ const toolCalls = message.tool_calls;
3163
+ if (!Array.isArray(toolCalls)) {
3164
+ return [];
3165
+ }
3166
+ const calls = [];
3167
+ for (const call of toolCalls) {
3168
+ if (!call || typeof call !== "object") {
3169
+ continue;
3170
+ }
3171
+ const id = typeof call.id === "string" ? call.id : "";
3172
+ const fn = call.function;
3173
+ const name = fn && typeof fn === "object" && typeof fn.name === "string" ? fn.name ?? "" : "";
3174
+ const args = fn && typeof fn === "object" && typeof fn.arguments === "string" ? fn.arguments ?? "" : "";
3175
+ if (id && name) {
3176
+ calls.push({ id, name, arguments: args });
3177
+ }
3178
+ }
3179
+ return calls;
3180
+ }
2650
3181
  function resolveGeminiThinkingConfig(modelId) {
2651
3182
  switch (modelId) {
2652
3183
  case "gemini-3-pro-preview":
2653
3184
  return { includeThoughts: true };
3185
+ case "gemini-3-flash-preview":
3186
+ return { includeThoughts: true, thinkingBudget: 16384 };
2654
3187
  case "gemini-2.5-pro":
2655
3188
  return { includeThoughts: true, thinkingBudget: 32768 };
2656
3189
  case "gemini-flash-latest":
@@ -2826,7 +3359,7 @@ async function runTextCall(params) {
2826
3359
  };
2827
3360
  let sawResponseDelta = false;
2828
3361
  let sawThoughtDelta = false;
2829
- const result = await collectChatGptCodexResponse({
3362
+ const result = await collectChatGptCodexResponseWithRetry({
2830
3363
  request: requestPayload,
2831
3364
  signal,
2832
3365
  onDelta: (delta) => {
@@ -2857,6 +3390,47 @@ async function runTextCall(params) {
2857
3390
  if (!sawResponseDelta && fallbackText.length > 0) {
2858
3391
  pushDelta("response", fallbackText);
2859
3392
  }
3393
+ } else if (provider === "fireworks") {
3394
+ if (request.tools && request.tools.length > 0) {
3395
+ throw new Error(
3396
+ "Fireworks provider does not support provider-native tools in generateText; use runToolLoop for function tools."
3397
+ );
3398
+ }
3399
+ const fireworksMessages = toFireworksMessages(contents, {
3400
+ responseMimeType: request.responseMimeType,
3401
+ responseJsonSchema: request.responseJsonSchema
3402
+ });
3403
+ await runFireworksCall(async (client) => {
3404
+ const responseFormat = request.responseJsonSchema ? {
3405
+ type: "json_schema",
3406
+ json_schema: {
3407
+ name: "llm-response",
3408
+ schema: request.responseJsonSchema
3409
+ }
3410
+ } : request.responseMimeType === "application/json" ? { type: "json_object" } : void 0;
3411
+ const response = await client.chat.completions.create(
3412
+ {
3413
+ model: modelForProvider,
3414
+ messages: fireworksMessages,
3415
+ ...responseFormat ? { response_format: responseFormat } : {}
3416
+ },
3417
+ { signal }
3418
+ );
3419
+ modelVersion = typeof response.model === "string" ? response.model : request.model;
3420
+ queue.push({ type: "model", modelVersion });
3421
+ const choice = Array.isArray(response.choices) ? response.choices[0] : void 0;
3422
+ if (choice?.finish_reason === "content_filter") {
3423
+ blocked = true;
3424
+ queue.push({ type: "blocked" });
3425
+ }
3426
+ const textOutput = extractFireworksMessageText(
3427
+ choice?.message
3428
+ );
3429
+ if (textOutput.length > 0) {
3430
+ pushDelta("response", textOutput);
3431
+ }
3432
+ latestUsage = extractFireworksUsageTokens(response.usage);
3433
+ });
2860
3434
  } else {
2861
3435
  const geminiContents = contents.map(convertLlmContentToGeminiContent);
2862
3436
  const config = {
@@ -2981,11 +3555,12 @@ function buildJsonSchemaConfig(request) {
2981
3555
  const schemaName = (request.openAiSchemaName ?? "llm-response").trim() || "llm-response";
2982
3556
  const providerInfo = resolveProvider(request.model);
2983
3557
  const isOpenAiVariant = providerInfo.provider === "openai" || providerInfo.provider === "chatgpt";
3558
+ const isGeminiVariant = providerInfo.provider === "gemini";
2984
3559
  const baseJsonSchema = (0, import_zod_to_json_schema.zodToJsonSchema)(request.schema, {
2985
3560
  name: schemaName,
2986
3561
  target: isOpenAiVariant ? "openAi" : "jsonSchema7"
2987
3562
  });
2988
- const responseJsonSchema = isOpenAiVariant ? resolveOpenAiSchemaRoot(baseJsonSchema) : addGeminiPropertyOrdering(baseJsonSchema);
3563
+ const responseJsonSchema = isOpenAiVariant ? resolveOpenAiSchemaRoot(baseJsonSchema) : isGeminiVariant ? addGeminiPropertyOrdering(baseJsonSchema) : resolveOpenAiSchemaRoot(baseJsonSchema);
2989
3564
  if (isOpenAiVariant && !isJsonSchemaObject(responseJsonSchema)) {
2990
3565
  throw new Error("OpenAI structured outputs require a JSON object schema at the root.");
2991
3566
  }
@@ -3152,15 +3727,46 @@ var DEFAULT_TOOL_LOOP_MAX_STEPS = 8;
3152
3727
  function resolveToolLoopContents(input) {
3153
3728
  return resolveTextContents(input);
3154
3729
  }
3155
- function buildOpenAiFunctionTools(tools) {
3730
+ function isCustomTool(toolDef) {
3731
+ return toolDef.type === "custom";
3732
+ }
3733
+ function buildOpenAiToolsFromToolSet(tools) {
3156
3734
  const toolEntries = Object.entries(tools);
3157
- return toolEntries.map(([name, toolDef]) => ({
3158
- type: "function",
3159
- name,
3160
- description: toolDef.description ?? void 0,
3161
- parameters: buildOpenAiToolSchema(toolDef.inputSchema, name),
3162
- strict: true
3163
- }));
3735
+ return toolEntries.map(([name, toolDef]) => {
3736
+ if (isCustomTool(toolDef)) {
3737
+ return {
3738
+ type: "custom",
3739
+ name,
3740
+ description: toolDef.description ?? void 0,
3741
+ ...toolDef.format ? { format: toolDef.format } : {}
3742
+ };
3743
+ }
3744
+ return {
3745
+ type: "function",
3746
+ name,
3747
+ description: toolDef.description ?? void 0,
3748
+ parameters: buildOpenAiToolSchema(toolDef.inputSchema, name),
3749
+ strict: true
3750
+ };
3751
+ });
3752
+ }
3753
+ function buildFireworksToolsFromToolSet(tools) {
3754
+ const toolEntries = Object.entries(tools);
3755
+ return toolEntries.map(([name, toolDef]) => {
3756
+ if (isCustomTool(toolDef)) {
3757
+ throw new Error(
3758
+ `Fireworks provider does not support custom/freeform tools (${name}). Use JSON function tools instead.`
3759
+ );
3760
+ }
3761
+ return {
3762
+ type: "function",
3763
+ function: {
3764
+ name,
3765
+ description: toolDef.description ?? void 0,
3766
+ parameters: buildOpenAiToolSchema(toolDef.inputSchema, name)
3767
+ }
3768
+ };
3769
+ });
3164
3770
  }
3165
3771
  function buildOpenAiToolSchema(schema, name) {
3166
3772
  const rawSchema = (0, import_zod_to_json_schema.zodToJsonSchema)(schema, { name, target: "openAi" });
@@ -3172,11 +3778,18 @@ function buildOpenAiToolSchema(schema, name) {
3172
3778
  }
3173
3779
  function buildGeminiFunctionDeclarations(tools) {
3174
3780
  const toolEntries = Object.entries(tools);
3175
- const functionDeclarations = toolEntries.map(([name, toolDef]) => ({
3176
- name,
3177
- description: toolDef.description ?? "",
3178
- parametersJsonSchema: buildGeminiToolSchema(toolDef.inputSchema, name)
3179
- }));
3781
+ const functionDeclarations = toolEntries.map(([name, toolDef]) => {
3782
+ if (isCustomTool(toolDef)) {
3783
+ throw new Error(
3784
+ `Gemini provider does not support custom/freeform tools (${name}). Use JSON function tools instead.`
3785
+ );
3786
+ }
3787
+ return {
3788
+ name,
3789
+ description: toolDef.description ?? "",
3790
+ parametersJsonSchema: buildGeminiToolSchema(toolDef.inputSchema, name)
3791
+ };
3792
+ });
3180
3793
  return [{ functionDeclarations }];
3181
3794
  }
3182
3795
  function buildGeminiToolSchema(schema, name) {
@@ -3237,9 +3850,9 @@ async function runToolLoop(request) {
3237
3850
  let finalText = "";
3238
3851
  let finalThoughts = "";
3239
3852
  if (providerInfo.provider === "openai") {
3240
- const openAiFunctionTools = buildOpenAiFunctionTools(request.tools);
3853
+ const openAiAgentTools = buildOpenAiToolsFromToolSet(request.tools);
3241
3854
  const openAiNativeTools = toOpenAiTools(request.modelTools);
3242
- const openAiTools = openAiNativeTools ? [...openAiNativeTools, ...openAiFunctionTools] : [...openAiFunctionTools];
3855
+ const openAiTools = openAiNativeTools ? [...openAiNativeTools, ...openAiAgentTools] : [...openAiAgentTools];
3243
3856
  const reasoningEffort = resolveOpenAiReasoningEffort(
3244
3857
  providerInfo.model,
3245
3858
  request.openAiReasoningEffort
@@ -3331,9 +3944,9 @@ async function runToolLoop(request) {
3331
3944
  if (usageTokens) {
3332
3945
  emitEvent({ type: "usage", usage: usageTokens, costUsd: stepCostUsd, modelVersion });
3333
3946
  }
3334
- const functionCalls = extractOpenAiFunctionCalls(finalResponse.output);
3947
+ const responseToolCalls = extractOpenAiToolCalls(finalResponse.output);
3335
3948
  const stepToolCalls = [];
3336
- if (functionCalls.length === 0) {
3949
+ if (responseToolCalls.length === 0) {
3337
3950
  finalText = responseText;
3338
3951
  finalThoughts = reasoningSummary;
3339
3952
  steps.push({
@@ -3347,10 +3960,21 @@ async function runToolLoop(request) {
3347
3960
  });
3348
3961
  return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
3349
3962
  }
3350
- const callInputs = functionCalls.map((call, index) => {
3963
+ const callInputs = responseToolCalls.map((call, index) => {
3351
3964
  const toolIndex = index + 1;
3352
3965
  const toolId = buildToolLogId(turn, toolIndex);
3353
3966
  const toolName = call.name;
3967
+ if (call.kind === "custom") {
3968
+ return {
3969
+ call,
3970
+ toolName,
3971
+ value: call.input,
3972
+ parseError: void 0,
3973
+ toolId,
3974
+ turn,
3975
+ toolIndex
3976
+ };
3977
+ }
3354
3978
  const { value, error: parseError } = parseOpenAiToolArguments(call.arguments);
3355
3979
  return { call, toolName, value, parseError, toolId, turn, toolIndex };
3356
3980
  });
@@ -3365,6 +3989,7 @@ async function runToolLoop(request) {
3365
3989
  },
3366
3990
  async () => {
3367
3991
  const { result, outputPayload } = await executeToolCall({
3992
+ callKind: entry.call.kind,
3368
3993
  toolName: entry.toolName,
3369
3994
  tool: request.tools[entry.toolName],
3370
3995
  rawInput: entry.value,
@@ -3378,11 +4003,19 @@ async function runToolLoop(request) {
3378
4003
  const toolOutputs = [];
3379
4004
  for (const { entry, result, outputPayload } of callResults) {
3380
4005
  stepToolCalls.push({ ...result, callId: entry.call.call_id });
3381
- toolOutputs.push({
3382
- type: "function_call_output",
3383
- call_id: entry.call.call_id,
3384
- output: mergeToolOutput(outputPayload)
3385
- });
4006
+ if (entry.call.kind === "custom") {
4007
+ toolOutputs.push({
4008
+ type: "custom_tool_call_output",
4009
+ call_id: entry.call.call_id,
4010
+ output: mergeToolOutput(outputPayload)
4011
+ });
4012
+ } else {
4013
+ toolOutputs.push({
4014
+ type: "function_call_output",
4015
+ call_id: entry.call.call_id,
4016
+ output: mergeToolOutput(outputPayload)
4017
+ });
4018
+ }
3386
4019
  }
3387
4020
  steps.push({
3388
4021
  step: steps.length + 1,
@@ -3399,24 +4032,28 @@ async function runToolLoop(request) {
3399
4032
  throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
3400
4033
  }
3401
4034
  if (providerInfo.provider === "chatgpt") {
3402
- const openAiFunctionTools = buildOpenAiFunctionTools(request.tools);
4035
+ const openAiAgentTools = buildOpenAiToolsFromToolSet(request.tools);
3403
4036
  const openAiNativeTools = toOpenAiTools(request.modelTools);
3404
- const openAiTools = openAiNativeTools ? [...openAiNativeTools, ...openAiFunctionTools] : [...openAiFunctionTools];
4037
+ const openAiTools = openAiNativeTools ? [...openAiNativeTools, ...openAiAgentTools] : [...openAiAgentTools];
3405
4038
  const reasoningEffort = resolveOpenAiReasoningEffort(
3406
4039
  request.model,
3407
4040
  request.openAiReasoningEffort
3408
4041
  );
3409
4042
  const toolLoopInput = toChatGptInput(contents);
4043
+ const conversationId = `tool-loop-${(0, import_node_crypto.randomBytes)(8).toString("hex")}`;
4044
+ const promptCacheKey = conversationId;
3410
4045
  let input = [...toolLoopInput.input];
3411
4046
  for (let stepIndex = 0; stepIndex < maxSteps; stepIndex += 1) {
3412
4047
  const turn = stepIndex + 1;
3413
- const response = await collectChatGptCodexResponse({
4048
+ const response = await collectChatGptCodexResponseWithRetry({
4049
+ sessionId: conversationId,
3414
4050
  request: {
3415
4051
  model: providerInfo.model,
3416
4052
  store: false,
3417
4053
  stream: true,
3418
4054
  instructions: toolLoopInput.instructions ?? "You are a helpful assistant.",
3419
4055
  input,
4056
+ prompt_cache_key: promptCacheKey,
3420
4057
  include: ["reasoning.encrypted_content"],
3421
4058
  tools: openAiTools,
3422
4059
  tool_choice: "auto",
@@ -3447,8 +4084,8 @@ async function runToolLoop(request) {
3447
4084
  totalCostUsd += stepCostUsd;
3448
4085
  const responseText = (response.text ?? "").trim();
3449
4086
  const reasoningSummaryText = (response.reasoningSummaryText ?? "").trim();
3450
- const functionCalls = response.toolCalls ?? [];
3451
- if (functionCalls.length === 0) {
4087
+ const responseToolCalls = response.toolCalls ?? [];
4088
+ if (responseToolCalls.length === 0) {
3452
4089
  finalText = responseText;
3453
4090
  finalThoughts = reasoningSummaryText;
3454
4091
  steps.push({
@@ -3464,12 +4101,16 @@ async function runToolLoop(request) {
3464
4101
  }
3465
4102
  const toolCalls = [];
3466
4103
  const toolOutputs = [];
3467
- const callInputs = functionCalls.map((call, index) => {
4104
+ const callInputs = responseToolCalls.map((call, index) => {
3468
4105
  const toolIndex = index + 1;
3469
4106
  const toolId = buildToolLogId(turn, toolIndex);
3470
4107
  const toolName = call.name;
3471
- const { value, error: parseError } = parseOpenAiToolArguments(call.arguments);
3472
- const ids = normalizeChatGptToolIds({ callId: call.callId, itemId: call.id });
4108
+ const { value, error: parseError } = call.kind === "custom" ? { value: call.input, error: void 0 } : parseOpenAiToolArguments(call.arguments);
4109
+ const ids = normalizeChatGptToolIds({
4110
+ callKind: call.kind,
4111
+ callId: call.callId,
4112
+ itemId: call.id
4113
+ });
3473
4114
  return { call, toolName, value, parseError, ids, toolId, turn, toolIndex };
3474
4115
  });
3475
4116
  const callResults = await Promise.all(
@@ -3483,6 +4124,7 @@ async function runToolLoop(request) {
3483
4124
  },
3484
4125
  async () => {
3485
4126
  const { result, outputPayload } = await executeToolCall({
4127
+ callKind: entry.call.kind,
3486
4128
  toolName: entry.toolName,
3487
4129
  tool: request.tools[entry.toolName],
3488
4130
  rawInput: entry.value,
@@ -3495,19 +4137,35 @@ async function runToolLoop(request) {
3495
4137
  );
3496
4138
  for (const { entry, result, outputPayload } of callResults) {
3497
4139
  toolCalls.push({ ...result, callId: entry.ids.callId });
3498
- toolOutputs.push({
3499
- type: "function_call",
3500
- id: entry.ids.itemId,
3501
- call_id: entry.ids.callId,
3502
- name: entry.toolName,
3503
- arguments: entry.call.arguments,
3504
- status: "completed"
3505
- });
3506
- toolOutputs.push({
3507
- type: "function_call_output",
3508
- call_id: entry.ids.callId,
3509
- output: mergeToolOutput(outputPayload)
3510
- });
4140
+ if (entry.call.kind === "custom") {
4141
+ toolOutputs.push({
4142
+ type: "custom_tool_call",
4143
+ id: entry.ids.itemId,
4144
+ call_id: entry.ids.callId,
4145
+ name: entry.toolName,
4146
+ input: entry.call.input,
4147
+ status: "completed"
4148
+ });
4149
+ toolOutputs.push({
4150
+ type: "custom_tool_call_output",
4151
+ call_id: entry.ids.callId,
4152
+ output: mergeToolOutput(outputPayload)
4153
+ });
4154
+ } else {
4155
+ toolOutputs.push({
4156
+ type: "function_call",
4157
+ id: entry.ids.itemId,
4158
+ call_id: entry.ids.callId,
4159
+ name: entry.toolName,
4160
+ arguments: entry.call.arguments,
4161
+ status: "completed"
4162
+ });
4163
+ toolOutputs.push({
4164
+ type: "function_call_output",
4165
+ call_id: entry.ids.callId,
4166
+ output: mergeToolOutput(outputPayload)
4167
+ });
4168
+ }
3511
4169
  }
3512
4170
  steps.push({
3513
4171
  step: steps.length + 1,
@@ -3522,6 +4180,134 @@ async function runToolLoop(request) {
3522
4180
  }
3523
4181
  throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
3524
4182
  }
4183
+ if (providerInfo.provider === "fireworks") {
4184
+ if (request.modelTools && request.modelTools.length > 0) {
4185
+ throw new Error(
4186
+ "Fireworks provider does not support provider-native modelTools in runToolLoop."
4187
+ );
4188
+ }
4189
+ const fireworksTools = buildFireworksToolsFromToolSet(request.tools);
4190
+ const messages = toFireworksMessages(contents);
4191
+ for (let stepIndex = 0; stepIndex < maxSteps; stepIndex += 1) {
4192
+ const turn = stepIndex + 1;
4193
+ const response = await runFireworksCall(async (client) => {
4194
+ return await client.chat.completions.create(
4195
+ {
4196
+ model: providerInfo.model,
4197
+ messages,
4198
+ tools: fireworksTools,
4199
+ tool_choice: "auto",
4200
+ parallel_tool_calls: true
4201
+ },
4202
+ { signal: request.signal }
4203
+ );
4204
+ });
4205
+ const modelVersion = typeof response.model === "string" ? response.model : request.model;
4206
+ request.onEvent?.({ type: "model", modelVersion });
4207
+ const choice = Array.isArray(response.choices) ? response.choices[0] : void 0;
4208
+ if (choice?.finish_reason === "content_filter") {
4209
+ request.onEvent?.({ type: "blocked" });
4210
+ }
4211
+ const message = choice?.message;
4212
+ const responseText = extractFireworksMessageText(message).trim();
4213
+ if (responseText.length > 0) {
4214
+ request.onEvent?.({ type: "delta", channel: "response", text: responseText });
4215
+ }
4216
+ const usageTokens = extractFireworksUsageTokens(response.usage);
4217
+ const stepCostUsd = estimateCallCostUsd({
4218
+ modelId: modelVersion,
4219
+ tokens: usageTokens,
4220
+ responseImages: 0
4221
+ });
4222
+ totalCostUsd += stepCostUsd;
4223
+ if (usageTokens) {
4224
+ request.onEvent?.({
4225
+ type: "usage",
4226
+ usage: usageTokens,
4227
+ costUsd: stepCostUsd,
4228
+ modelVersion
4229
+ });
4230
+ }
4231
+ const responseToolCalls = extractFireworksToolCalls(message);
4232
+ if (responseToolCalls.length === 0) {
4233
+ finalText = responseText;
4234
+ finalThoughts = "";
4235
+ steps.push({
4236
+ step: steps.length + 1,
4237
+ modelVersion,
4238
+ text: responseText || void 0,
4239
+ thoughts: void 0,
4240
+ toolCalls: [],
4241
+ usage: usageTokens,
4242
+ costUsd: stepCostUsd
4243
+ });
4244
+ return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
4245
+ }
4246
+ const stepToolCalls = [];
4247
+ const callInputs = responseToolCalls.map((call, index) => {
4248
+ const toolIndex = index + 1;
4249
+ const toolId = buildToolLogId(turn, toolIndex);
4250
+ const { value, error: parseError } = parseOpenAiToolArguments(call.arguments);
4251
+ return { call, toolName: call.name, value, parseError, toolId, turn, toolIndex };
4252
+ });
4253
+ const callResults = await Promise.all(
4254
+ callInputs.map(async (entry) => {
4255
+ return await toolCallContextStorage.run(
4256
+ {
4257
+ toolName: entry.toolName,
4258
+ toolId: entry.toolId,
4259
+ turn: entry.turn,
4260
+ toolIndex: entry.toolIndex
4261
+ },
4262
+ async () => {
4263
+ const { result, outputPayload } = await executeToolCall({
4264
+ callKind: "function",
4265
+ toolName: entry.toolName,
4266
+ tool: request.tools[entry.toolName],
4267
+ rawInput: entry.value,
4268
+ parseError: entry.parseError
4269
+ });
4270
+ return { entry, result, outputPayload };
4271
+ }
4272
+ );
4273
+ })
4274
+ );
4275
+ const assistantToolCalls = [];
4276
+ const toolMessages = [];
4277
+ for (const { entry, result, outputPayload } of callResults) {
4278
+ stepToolCalls.push({ ...result, callId: entry.call.id });
4279
+ assistantToolCalls.push({
4280
+ id: entry.call.id,
4281
+ type: "function",
4282
+ function: {
4283
+ name: entry.toolName,
4284
+ arguments: entry.call.arguments
4285
+ }
4286
+ });
4287
+ toolMessages.push({
4288
+ role: "tool",
4289
+ tool_call_id: entry.call.id,
4290
+ content: mergeToolOutput(outputPayload)
4291
+ });
4292
+ }
4293
+ steps.push({
4294
+ step: steps.length + 1,
4295
+ modelVersion,
4296
+ text: responseText || void 0,
4297
+ thoughts: void 0,
4298
+ toolCalls: stepToolCalls,
4299
+ usage: usageTokens,
4300
+ costUsd: stepCostUsd
4301
+ });
4302
+ messages.push({
4303
+ role: "assistant",
4304
+ ...responseText.length > 0 ? { content: responseText } : {},
4305
+ tool_calls: assistantToolCalls
4306
+ });
4307
+ messages.push(...toolMessages);
4308
+ }
4309
+ throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
4310
+ }
3525
4311
  const geminiFunctionTools = buildGeminiFunctionDeclarations(request.tools);
3526
4312
  const geminiNativeTools = toGeminiTools(request.modelTools);
3527
4313
  const geminiTools = geminiNativeTools ? geminiNativeTools.concat(geminiFunctionTools) : geminiFunctionTools;
@@ -3671,6 +4457,7 @@ async function runToolLoop(request) {
3671
4457
  },
3672
4458
  async () => {
3673
4459
  const { result, outputPayload } = await executeToolCall({
4460
+ callKind: "function",
3674
4461
  toolName: entry.toolName,
3675
4462
  tool: request.tools[entry.toolName],
3676
4463
  rawInput: entry.rawInput
@@ -3950,26 +4737,26 @@ ${lines}`;
3950
4737
  }
3951
4738
 
3952
4739
  // src/tools/filesystemTools.ts
3953
- var import_node_path4 = __toESM(require("path"), 1);
4740
+ var import_node_path5 = __toESM(require("path"), 1);
3954
4741
  var import_zod5 = require("zod");
3955
4742
 
3956
4743
  // src/tools/applyPatch.ts
3957
- var import_node_path3 = __toESM(require("path"), 1);
4744
+ var import_node_path4 = __toESM(require("path"), 1);
3958
4745
  var import_zod4 = require("zod");
3959
4746
 
3960
4747
  // src/tools/filesystem.ts
3961
- var import_node_fs2 = require("fs");
3962
- var import_node_path2 = __toESM(require("path"), 1);
4748
+ var import_node_fs3 = require("fs");
4749
+ var import_node_path3 = __toESM(require("path"), 1);
3963
4750
  var InMemoryAgentFilesystem = class {
3964
4751
  #files = /* @__PURE__ */ new Map();
3965
4752
  #dirs = /* @__PURE__ */ new Map();
3966
4753
  #clock = 0;
3967
4754
  constructor(initialFiles = {}) {
3968
- const root = import_node_path2.default.resolve("/");
4755
+ const root = import_node_path3.default.resolve("/");
3969
4756
  this.#dirs.set(root, { mtimeMs: this.#nextMtime() });
3970
4757
  for (const [filePath, content] of Object.entries(initialFiles)) {
3971
- const absolutePath = import_node_path2.default.resolve(filePath);
3972
- this.#ensureDirSync(import_node_path2.default.dirname(absolutePath));
4758
+ const absolutePath = import_node_path3.default.resolve(filePath);
4759
+ this.#ensureDirSync(import_node_path3.default.dirname(absolutePath));
3973
4760
  this.#files.set(absolutePath, {
3974
4761
  content,
3975
4762
  mtimeMs: this.#nextMtime()
@@ -3977,7 +4764,7 @@ var InMemoryAgentFilesystem = class {
3977
4764
  }
3978
4765
  }
3979
4766
  async readTextFile(filePath) {
3980
- const absolutePath = import_node_path2.default.resolve(filePath);
4767
+ const absolutePath = import_node_path3.default.resolve(filePath);
3981
4768
  const file = this.#files.get(absolutePath);
3982
4769
  if (!file) {
3983
4770
  throw createNoSuchFileError("open", absolutePath);
@@ -3985,24 +4772,24 @@ var InMemoryAgentFilesystem = class {
3985
4772
  return file.content;
3986
4773
  }
3987
4774
  async writeTextFile(filePath, content) {
3988
- const absolutePath = import_node_path2.default.resolve(filePath);
3989
- const parentPath = import_node_path2.default.dirname(absolutePath);
4775
+ const absolutePath = import_node_path3.default.resolve(filePath);
4776
+ const parentPath = import_node_path3.default.dirname(absolutePath);
3990
4777
  if (!this.#dirs.has(parentPath)) {
3991
4778
  throw createNoSuchFileError("open", parentPath);
3992
4779
  }
3993
4780
  this.#files.set(absolutePath, { content, mtimeMs: this.#nextMtime() });
3994
4781
  }
3995
4782
  async deleteFile(filePath) {
3996
- const absolutePath = import_node_path2.default.resolve(filePath);
4783
+ const absolutePath = import_node_path3.default.resolve(filePath);
3997
4784
  if (!this.#files.delete(absolutePath)) {
3998
4785
  throw createNoSuchFileError("unlink", absolutePath);
3999
4786
  }
4000
4787
  }
4001
4788
  async ensureDir(directoryPath) {
4002
- this.#ensureDirSync(import_node_path2.default.resolve(directoryPath));
4789
+ this.#ensureDirSync(import_node_path3.default.resolve(directoryPath));
4003
4790
  }
4004
4791
  async readDir(directoryPath) {
4005
- const absolutePath = import_node_path2.default.resolve(directoryPath);
4792
+ const absolutePath = import_node_path3.default.resolve(directoryPath);
4006
4793
  const directory = this.#dirs.get(absolutePath);
4007
4794
  if (!directory) {
4008
4795
  throw createNoSuchFileError("scandir", absolutePath);
@@ -4013,10 +4800,10 @@ var InMemoryAgentFilesystem = class {
4013
4800
  if (dirPath === absolutePath) {
4014
4801
  continue;
4015
4802
  }
4016
- if (import_node_path2.default.dirname(dirPath) !== absolutePath) {
4803
+ if (import_node_path3.default.dirname(dirPath) !== absolutePath) {
4017
4804
  continue;
4018
4805
  }
4019
- const name = import_node_path2.default.basename(dirPath);
4806
+ const name = import_node_path3.default.basename(dirPath);
4020
4807
  if (seenNames.has(name)) {
4021
4808
  continue;
4022
4809
  }
@@ -4029,10 +4816,10 @@ var InMemoryAgentFilesystem = class {
4029
4816
  });
4030
4817
  }
4031
4818
  for (const [filePath, fileRecord] of this.#files.entries()) {
4032
- if (import_node_path2.default.dirname(filePath) !== absolutePath) {
4819
+ if (import_node_path3.default.dirname(filePath) !== absolutePath) {
4033
4820
  continue;
4034
4821
  }
4035
- const name = import_node_path2.default.basename(filePath);
4822
+ const name = import_node_path3.default.basename(filePath);
4036
4823
  if (seenNames.has(name)) {
4037
4824
  continue;
4038
4825
  }
@@ -4048,7 +4835,7 @@ var InMemoryAgentFilesystem = class {
4048
4835
  return entries;
4049
4836
  }
4050
4837
  async stat(entryPath) {
4051
- const absolutePath = import_node_path2.default.resolve(entryPath);
4838
+ const absolutePath = import_node_path3.default.resolve(entryPath);
4052
4839
  const file = this.#files.get(absolutePath);
4053
4840
  if (file) {
4054
4841
  return { kind: "file", mtimeMs: file.mtimeMs };
@@ -4064,7 +4851,7 @@ var InMemoryAgentFilesystem = class {
4064
4851
  return Object.fromEntries(entries.map(([filePath, record]) => [filePath, record.content]));
4065
4852
  }
4066
4853
  #ensureDirSync(directoryPath) {
4067
- const absolutePath = import_node_path2.default.resolve(directoryPath);
4854
+ const absolutePath = import_node_path3.default.resolve(directoryPath);
4068
4855
  const parts = [];
4069
4856
  let cursor = absolutePath;
4070
4857
  for (; ; ) {
@@ -4072,7 +4859,7 @@ var InMemoryAgentFilesystem = class {
4072
4859
  break;
4073
4860
  }
4074
4861
  parts.push(cursor);
4075
- const parent = import_node_path2.default.dirname(cursor);
4862
+ const parent = import_node_path3.default.dirname(cursor);
4076
4863
  if (parent === cursor) {
4077
4864
  break;
4078
4865
  }
@@ -4095,18 +4882,18 @@ var InMemoryAgentFilesystem = class {
4095
4882
  };
4096
4883
  function createNodeAgentFilesystem() {
4097
4884
  return {
4098
- readTextFile: async (filePath) => import_node_fs2.promises.readFile(filePath, "utf8"),
4099
- writeTextFile: async (filePath, content) => import_node_fs2.promises.writeFile(filePath, content, "utf8"),
4100
- deleteFile: async (filePath) => import_node_fs2.promises.unlink(filePath),
4885
+ readTextFile: async (filePath) => import_node_fs3.promises.readFile(filePath, "utf8"),
4886
+ writeTextFile: async (filePath, content) => import_node_fs3.promises.writeFile(filePath, content, "utf8"),
4887
+ deleteFile: async (filePath) => import_node_fs3.promises.unlink(filePath),
4101
4888
  ensureDir: async (directoryPath) => {
4102
- await import_node_fs2.promises.mkdir(directoryPath, { recursive: true });
4889
+ await import_node_fs3.promises.mkdir(directoryPath, { recursive: true });
4103
4890
  },
4104
4891
  readDir: async (directoryPath) => {
4105
- const entries = await import_node_fs2.promises.readdir(directoryPath, { withFileTypes: true });
4892
+ const entries = await import_node_fs3.promises.readdir(directoryPath, { withFileTypes: true });
4106
4893
  const result = [];
4107
4894
  for (const entry of entries) {
4108
- const entryPath = import_node_path2.default.resolve(directoryPath, entry.name);
4109
- const stats = await import_node_fs2.promises.lstat(entryPath);
4895
+ const entryPath = import_node_path3.default.resolve(directoryPath, entry.name);
4896
+ const stats = await import_node_fs3.promises.lstat(entryPath);
4110
4897
  result.push({
4111
4898
  name: entry.name,
4112
4899
  path: entryPath,
@@ -4117,7 +4904,7 @@ function createNodeAgentFilesystem() {
4117
4904
  return result;
4118
4905
  },
4119
4906
  stat: async (entryPath) => {
4120
- const stats = await import_node_fs2.promises.lstat(entryPath);
4907
+ const stats = await import_node_fs3.promises.lstat(entryPath);
4121
4908
  return {
4122
4909
  kind: statsToKind(stats),
4123
4910
  mtimeMs: stats.mtimeMs
@@ -4159,12 +4946,104 @@ var UPDATE_FILE_PREFIX = "*** Update File: ";
4159
4946
  var MOVE_TO_PREFIX = "*** Move to: ";
4160
4947
  var END_OF_FILE_LINE = "*** End of File";
4161
4948
  var DEFAULT_MAX_PATCH_BYTES = 1024 * 1024;
4949
+ var CODEX_APPLY_PATCH_INPUT_DESCRIPTION = "The entire contents of the apply_patch command";
4950
+ var CODEX_APPLY_PATCH_FREEFORM_TOOL_DESCRIPTION = "Use the `apply_patch` tool to edit files. This is a FREEFORM tool, so do not wrap the patch in JSON.";
4951
+ var CODEX_APPLY_PATCH_LARK_GRAMMAR = [
4952
+ "start: begin_patch hunk+ end_patch",
4953
+ 'begin_patch: "*** Begin Patch" LF',
4954
+ 'end_patch: "*** End Patch" LF?',
4955
+ "",
4956
+ "hunk: add_hunk | delete_hunk | update_hunk",
4957
+ 'add_hunk: "*** Add File: " filename LF add_line+',
4958
+ 'delete_hunk: "*** Delete File: " filename LF',
4959
+ 'update_hunk: "*** Update File: " filename LF change_move? change?',
4960
+ "",
4961
+ "filename: /(.+)/",
4962
+ 'add_line: "+" /(.*)/ LF -> line',
4963
+ "",
4964
+ 'change_move: "*** Move to: " filename LF',
4965
+ "change: (change_context | change_line)+ eof_line?",
4966
+ 'change_context: ("@@" | "@@ " /(.+)/) LF',
4967
+ 'change_line: ("+" | "-" | " ") /(.*)/ LF',
4968
+ 'eof_line: "*** End of File" LF',
4969
+ "",
4970
+ "%import common.LF"
4971
+ ].join("\n");
4972
+ var CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION = [
4973
+ "Use the `apply_patch` tool to edit files.",
4974
+ "Your patch language is a stripped\u2011down, file\u2011oriented diff format designed to be easy to parse and safe to apply. You can think of it as a high\u2011level envelope:",
4975
+ "",
4976
+ "*** Begin Patch",
4977
+ "[ one or more file sections ]",
4978
+ "*** End Patch",
4979
+ "",
4980
+ "Within that envelope, you get a sequence of file operations.",
4981
+ "You MUST include a header to specify the action you are taking.",
4982
+ "Each operation starts with one of three headers:",
4983
+ "",
4984
+ "*** Add File: <path> - create a new file. Every following line is a + line (the initial contents).",
4985
+ "*** Delete File: <path> - remove an existing file. Nothing follows.",
4986
+ "*** Update File: <path> - patch an existing file in place (optionally with a rename).",
4987
+ "",
4988
+ "May be immediately followed by *** Move to: <new path> if you want to rename the file.",
4989
+ "Then one or more \u201Chunks\u201D, each introduced by @@ (optionally followed by a hunk header).",
4990
+ "Within a hunk each line starts with:",
4991
+ "",
4992
+ "For instructions on [context_before] and [context_after]:",
4993
+ "- By default, show 3 lines of code immediately above and 3 lines immediately below each change. If a change is within 3 lines of a previous change, do NOT duplicate the first change\u2019s [context_after] lines in the second change\u2019s [context_before] lines.",
4994
+ "- If 3 lines of context is insufficient to uniquely identify the snippet of code within the file, use the @@ operator to indicate the class or function to which the snippet belongs. For instance, we might have:",
4995
+ "@@ class BaseClass",
4996
+ "[3 lines of pre-context]",
4997
+ "- [old_code]",
4998
+ "+ [new_code]",
4999
+ "[3 lines of post-context]",
5000
+ "",
5001
+ "- If a code block is repeated so many times in a class or function such that even a single `@@` statement and 3 lines of context cannot uniquely identify the snippet of code, you can use multiple `@@` statements to jump to the right context. For instance:",
5002
+ "",
5003
+ "@@ class BaseClass",
5004
+ "@@ def method():",
5005
+ "[3 lines of pre-context]",
5006
+ "- [old_code]",
5007
+ "+ [new_code]",
5008
+ "[3 lines of post-context]",
5009
+ "",
5010
+ "The full grammar definition is below:",
5011
+ "Patch := Begin { FileOp } End",
5012
+ 'Begin := "*** Begin Patch" NEWLINE',
5013
+ 'End := "*** End Patch" NEWLINE',
5014
+ "FileOp := AddFile | DeleteFile | UpdateFile",
5015
+ 'AddFile := "*** Add File: " path NEWLINE { "+" line NEWLINE }',
5016
+ 'DeleteFile := "*** Delete File: " path NEWLINE',
5017
+ 'UpdateFile := "*** Update File: " path NEWLINE [ MoveTo ] { Hunk }',
5018
+ 'MoveTo := "*** Move to: " newPath NEWLINE',
5019
+ 'Hunk := "@@" [ header ] NEWLINE { HunkLine } [ "*** End of File" NEWLINE ]',
5020
+ 'HunkLine := (" " | "-" | "+") text NEWLINE',
5021
+ "",
5022
+ "A full patch can combine several operations:",
5023
+ "",
5024
+ "*** Begin Patch",
5025
+ "*** Add File: hello.txt",
5026
+ "+Hello world",
5027
+ "*** Update File: src/app.py",
5028
+ "*** Move to: src/main.py",
5029
+ "@@ def greet():",
5030
+ '-print("Hi")',
5031
+ '+print("Hello, world!")',
5032
+ "*** Delete File: obsolete.txt",
5033
+ "*** End Patch",
5034
+ "",
5035
+ "It is important to remember:",
5036
+ "",
5037
+ "- You must include a header with your intended action (Add/Delete/Update)",
5038
+ "- You must prefix new lines with `+` even when creating a new file",
5039
+ "- File references can only be relative, NEVER ABSOLUTE."
5040
+ ].join("\n");
4162
5041
  var applyPatchToolInputSchema = import_zod4.z.object({
4163
- input: import_zod4.z.string().min(1).describe("The entire apply_patch payload, including Begin/End markers.")
5042
+ input: import_zod4.z.string().min(1).describe(CODEX_APPLY_PATCH_INPUT_DESCRIPTION)
4164
5043
  });
4165
5044
  function createApplyPatchTool(options = {}) {
4166
5045
  return tool({
4167
- description: options.description ?? "Apply edits using a Codex-style apply_patch payload with Begin/End markers.",
5046
+ description: options.description ?? CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION,
4168
5047
  inputSchema: applyPatchToolInputSchema,
4169
5048
  execute: async ({ input }) => applyPatch({
4170
5049
  patch: input,
@@ -4177,7 +5056,7 @@ function createApplyPatchTool(options = {}) {
4177
5056
  });
4178
5057
  }
4179
5058
  async function applyPatch(request) {
4180
- const cwd = import_node_path3.default.resolve(request.cwd ?? process.cwd());
5059
+ const cwd = import_node_path4.default.resolve(request.cwd ?? process.cwd());
4181
5060
  const adapter = request.fs ?? createNodeAgentFilesystem();
4182
5061
  const allowOutsideCwd = request.allowOutsideCwd === true;
4183
5062
  const patchBytes = Buffer.byteLength(request.patch, "utf8");
@@ -4199,7 +5078,7 @@ async function applyPatch(request) {
4199
5078
  kind: "add",
4200
5079
  path: absolutePath2
4201
5080
  });
4202
- await adapter.ensureDir(import_node_path3.default.dirname(absolutePath2));
5081
+ await adapter.ensureDir(import_node_path4.default.dirname(absolutePath2));
4203
5082
  await adapter.writeTextFile(absolutePath2, operation.content);
4204
5083
  added.push(toDisplayPath(absolutePath2, cwd));
4205
5084
  continue;
@@ -4233,7 +5112,7 @@ async function applyPatch(request) {
4233
5112
  fromPath: absolutePath,
4234
5113
  toPath: destinationPath
4235
5114
  });
4236
- await adapter.ensureDir(import_node_path3.default.dirname(destinationPath));
5115
+ await adapter.ensureDir(import_node_path4.default.dirname(destinationPath));
4237
5116
  await adapter.writeTextFile(destinationPath, next);
4238
5117
  await adapter.deleteFile(absolutePath);
4239
5118
  modified.push(toDisplayPath(destinationPath, cwd));
@@ -4264,22 +5143,22 @@ function resolvePatchPath(rawPath, cwd, allowOutsideCwd) {
4264
5143
  if (trimmed.length === 0) {
4265
5144
  throw new Error("apply_patch failed: empty file path");
4266
5145
  }
4267
- const absolutePath = import_node_path3.default.isAbsolute(trimmed) ? import_node_path3.default.resolve(trimmed) : import_node_path3.default.resolve(cwd, trimmed);
5146
+ const absolutePath = import_node_path4.default.isAbsolute(trimmed) ? import_node_path4.default.resolve(trimmed) : import_node_path4.default.resolve(cwd, trimmed);
4268
5147
  if (!allowOutsideCwd && !isPathInsideCwd(absolutePath, cwd)) {
4269
5148
  throw new Error(`apply_patch failed: path "${trimmed}" resolves outside cwd "${cwd}"`);
4270
5149
  }
4271
5150
  return absolutePath;
4272
5151
  }
4273
5152
  function isPathInsideCwd(candidatePath, cwd) {
4274
- const relative = import_node_path3.default.relative(cwd, candidatePath);
4275
- return relative === "" || !relative.startsWith("..") && !import_node_path3.default.isAbsolute(relative);
5153
+ const relative = import_node_path4.default.relative(cwd, candidatePath);
5154
+ return relative === "" || !relative.startsWith("..") && !import_node_path4.default.isAbsolute(relative);
4276
5155
  }
4277
5156
  function toDisplayPath(absolutePath, cwd) {
4278
- const relative = import_node_path3.default.relative(cwd, absolutePath);
5157
+ const relative = import_node_path4.default.relative(cwd, absolutePath);
4279
5158
  if (relative === "") {
4280
5159
  return ".";
4281
5160
  }
4282
- if (!relative.startsWith("..") && !import_node_path3.default.isAbsolute(relative)) {
5161
+ if (!relative.startsWith("..") && !import_node_path4.default.isAbsolute(relative)) {
4283
5162
  return relative;
4284
5163
  }
4285
5164
  return absolutePath;
@@ -4559,6 +5438,8 @@ function formatSummary(added, modified, deleted) {
4559
5438
 
4560
5439
  // src/tools/filesystemTools.ts
4561
5440
  var DEFAULT_READ_FILE_LINE_LIMIT = 2e3;
5441
+ var DEFAULT_READ_FILES_LINE_LIMIT = 200;
5442
+ var DEFAULT_READ_FILES_CHAR_LIMIT = 4e3;
4562
5443
  var DEFAULT_LIST_DIR_LIMIT = 25;
4563
5444
  var DEFAULT_LIST_DIR_DEPTH = 2;
4564
5445
  var DEFAULT_GREP_LIMIT = 100;
@@ -4592,12 +5473,29 @@ var codexGrepFilesInputSchema = import_zod5.z.object({
4592
5473
  limit: import_zod5.z.number().int().min(1).optional().describe("Maximum number of file paths to return (defaults to 100).")
4593
5474
  });
4594
5475
  var applyPatchInputSchema = import_zod5.z.object({
4595
- input: import_zod5.z.string().min(1)
5476
+ input: import_zod5.z.string().min(1).describe(CODEX_APPLY_PATCH_INPUT_DESCRIPTION)
4596
5477
  });
4597
5478
  var geminiReadFileInputSchema = import_zod5.z.object({
4598
5479
  file_path: import_zod5.z.string().min(1),
4599
- offset: import_zod5.z.number().int().min(0).optional(),
4600
- limit: import_zod5.z.number().int().min(1).optional()
5480
+ offset: import_zod5.z.number().int().min(0).nullish(),
5481
+ limit: import_zod5.z.number().int().min(1).nullish()
5482
+ });
5483
+ var geminiReadFilesInputSchema = import_zod5.z.object({
5484
+ paths: import_zod5.z.array(import_zod5.z.string().min(1)).min(1),
5485
+ line_offset: import_zod5.z.number().int().min(0).nullish(),
5486
+ line_limit: import_zod5.z.number().int().min(1).nullish(),
5487
+ char_offset: import_zod5.z.number().int().min(0).nullish(),
5488
+ char_limit: import_zod5.z.number().int().min(1).nullish(),
5489
+ include_line_numbers: import_zod5.z.boolean().nullish()
5490
+ }).superRefine((value, context) => {
5491
+ const hasLineWindow = value.line_offset !== void 0 || value.line_limit !== void 0;
5492
+ const hasCharWindow = value.char_offset !== void 0 || value.char_limit !== void 0;
5493
+ if (hasLineWindow && hasCharWindow) {
5494
+ context.addIssue({
5495
+ code: import_zod5.z.ZodIssueCode.custom,
5496
+ message: "Use either line_* or char_* window arguments, not both."
5497
+ });
5498
+ }
4601
5499
  });
4602
5500
  var geminiWriteFileInputSchema = import_zod5.z.object({
4603
5501
  file_path: import_zod5.z.string().min(1),
@@ -4608,31 +5506,41 @@ var geminiReplaceInputSchema = import_zod5.z.object({
4608
5506
  instruction: import_zod5.z.string().min(1),
4609
5507
  old_string: import_zod5.z.string(),
4610
5508
  new_string: import_zod5.z.string(),
4611
- expected_replacements: import_zod5.z.number().int().min(1).optional()
5509
+ expected_replacements: import_zod5.z.number().int().min(1).nullish()
4612
5510
  });
4613
5511
  var geminiListDirectoryInputSchema = import_zod5.z.object({
4614
5512
  dir_path: import_zod5.z.string().min(1),
4615
- ignore: import_zod5.z.array(import_zod5.z.string()).optional(),
5513
+ ignore: import_zod5.z.array(import_zod5.z.string()).nullish(),
4616
5514
  file_filtering_options: import_zod5.z.object({
4617
- respect_git_ignore: import_zod5.z.boolean().optional(),
4618
- respect_gemini_ignore: import_zod5.z.boolean().optional()
4619
- }).optional()
5515
+ respect_git_ignore: import_zod5.z.boolean().nullish(),
5516
+ respect_gemini_ignore: import_zod5.z.boolean().nullish()
5517
+ }).nullish()
5518
+ });
5519
+ var geminiRgSearchInputSchema = import_zod5.z.object({
5520
+ pattern: import_zod5.z.string().min(1),
5521
+ path: import_zod5.z.string().nullish(),
5522
+ glob: import_zod5.z.string().nullish(),
5523
+ case_sensitive: import_zod5.z.boolean().nullish(),
5524
+ exclude_pattern: import_zod5.z.string().nullish(),
5525
+ names_only: import_zod5.z.boolean().nullish(),
5526
+ max_matches_per_file: import_zod5.z.number().int().min(1).nullish(),
5527
+ max_results: import_zod5.z.number().int().min(1).nullish()
4620
5528
  });
4621
5529
  var geminiGrepSearchInputSchema = import_zod5.z.object({
4622
5530
  pattern: import_zod5.z.string().min(1),
4623
- dir_path: import_zod5.z.string().optional(),
4624
- include: import_zod5.z.string().optional(),
4625
- exclude_pattern: import_zod5.z.string().optional(),
4626
- names_only: import_zod5.z.boolean().optional(),
4627
- max_matches_per_file: import_zod5.z.number().int().min(1).optional(),
4628
- total_max_matches: import_zod5.z.number().int().min(1).optional()
5531
+ dir_path: import_zod5.z.string().nullish(),
5532
+ include: import_zod5.z.string().nullish(),
5533
+ exclude_pattern: import_zod5.z.string().nullish(),
5534
+ names_only: import_zod5.z.boolean().nullish(),
5535
+ max_matches_per_file: import_zod5.z.number().int().min(1).nullish(),
5536
+ total_max_matches: import_zod5.z.number().int().min(1).nullish()
4629
5537
  });
4630
5538
  var geminiGlobInputSchema = import_zod5.z.object({
4631
5539
  pattern: import_zod5.z.string().min(1),
4632
- dir_path: import_zod5.z.string().optional(),
4633
- case_sensitive: import_zod5.z.boolean().optional(),
4634
- respect_git_ignore: import_zod5.z.boolean().optional(),
4635
- respect_gemini_ignore: import_zod5.z.boolean().optional()
5540
+ dir_path: import_zod5.z.string().nullish(),
5541
+ case_sensitive: import_zod5.z.boolean().nullish(),
5542
+ respect_git_ignore: import_zod5.z.boolean().nullish(),
5543
+ respect_gemini_ignore: import_zod5.z.boolean().nullish()
4636
5544
  });
4637
5545
  function resolveFilesystemToolProfile(model, profile = "auto") {
4638
5546
  if (profile !== "auto") {
@@ -4676,7 +5584,7 @@ function createCodexFilesystemToolSet(options = {}) {
4676
5584
  }
4677
5585
  function createGeminiFilesystemToolSet(options = {}) {
4678
5586
  return {
4679
- read_file: createReadFileTool(options),
5587
+ read_file: createGeminiReadFileTool(options),
4680
5588
  write_file: createWriteFileTool(options),
4681
5589
  replace: createReplaceTool(options),
4682
5590
  list_directory: createListDirectoryTool(options),
@@ -4688,10 +5596,14 @@ function createModelAgnosticFilesystemToolSet(options = {}) {
4688
5596
  return createGeminiFilesystemToolSet(options);
4689
5597
  }
4690
5598
  function createCodexApplyPatchTool(options = {}) {
4691
- return tool({
4692
- description: "Use the `apply_patch` tool to edit files. This is a FREEFORM tool, so do not wrap the patch in JSON.",
4693
- inputSchema: applyPatchInputSchema,
4694
- execute: async ({ input }) => {
5599
+ return customTool({
5600
+ description: CODEX_APPLY_PATCH_FREEFORM_TOOL_DESCRIPTION,
5601
+ format: {
5602
+ type: "grammar",
5603
+ syntax: "lark",
5604
+ definition: CODEX_APPLY_PATCH_LARK_GRAMMAR
5605
+ },
5606
+ execute: async (input) => {
4695
5607
  const runtime = resolveRuntime(options);
4696
5608
  const result = await applyPatch({
4697
5609
  patch: input,
@@ -4735,13 +5647,20 @@ function createGrepFilesTool(options = {}) {
4735
5647
  execute: async (input) => grepFilesCodex(input, options)
4736
5648
  });
4737
5649
  }
4738
- function createReadFileTool(options = {}) {
5650
+ function createGeminiReadFileTool(options = {}) {
4739
5651
  return tool({
4740
- description: "Reads and returns content of a specified file.",
5652
+ description: "Reads and returns the content of a specified file. Supports optional 0-based line offset and line limit.",
4741
5653
  inputSchema: geminiReadFileInputSchema,
4742
5654
  execute: async (input) => readFileGemini(input, options)
4743
5655
  });
4744
5656
  }
5657
+ function createReadFilesTool(options = {}) {
5658
+ return tool({
5659
+ description: "Reads one or more files with optional line-based or character-based slicing, similar to a controlled head/tail view.",
5660
+ inputSchema: geminiReadFilesInputSchema,
5661
+ execute: async (input) => readFilesGemini(input, options)
5662
+ });
5663
+ }
4745
5664
  function createWriteFileTool(options = {}) {
4746
5665
  return tool({
4747
5666
  description: "Writes content to a specified file in the local filesystem.",
@@ -4770,6 +5689,13 @@ function createGrepSearchTool(options = {}) {
4770
5689
  execute: async (input) => grepSearchGemini(input, options)
4771
5690
  });
4772
5691
  }
5692
+ function createRgSearchTool(options = {}) {
5693
+ return tool({
5694
+ description: "Searches for a regex pattern within file contents.",
5695
+ inputSchema: geminiRgSearchInputSchema,
5696
+ execute: async (input) => rgSearchGemini(input, options)
5697
+ });
5698
+ }
4773
5699
  function createGlobTool(options = {}) {
4774
5700
  return tool({
4775
5701
  description: "Finds files matching glob patterns, sorted by modification time (newest first).",
@@ -4779,7 +5705,7 @@ function createGlobTool(options = {}) {
4779
5705
  }
4780
5706
  async function readFileCodex(input, options) {
4781
5707
  const runtime = resolveRuntime(options);
4782
- if (!import_node_path4.default.isAbsolute(input.file_path)) {
5708
+ if (!import_node_path5.default.isAbsolute(input.file_path)) {
4783
5709
  throw new Error("file_path must be an absolute path");
4784
5710
  }
4785
5711
  const filePath = resolvePathWithPolicy(input.file_path, runtime.cwd, runtime.allowOutsideCwd);
@@ -4830,7 +5756,7 @@ async function readFileCodex(input, options) {
4830
5756
  }
4831
5757
  async function listDirectoryCodex(input, options) {
4832
5758
  const runtime = resolveRuntime(options);
4833
- if (!import_node_path4.default.isAbsolute(input.dir_path)) {
5759
+ if (!import_node_path5.default.isAbsolute(input.dir_path)) {
4834
5760
  throw new Error("dir_path must be an absolute path");
4835
5761
  }
4836
5762
  const dirPath = resolvePathWithPolicy(input.dir_path, runtime.cwd, runtime.allowOutsideCwd);
@@ -4927,9 +5853,6 @@ async function readFileGemini(input, options) {
4927
5853
  path: filePath
4928
5854
  });
4929
5855
  const content = await runtime.filesystem.readTextFile(filePath);
4930
- if (input.offset === void 0 && input.limit === void 0) {
4931
- return content;
4932
- }
4933
5856
  const lines = splitLines(content);
4934
5857
  const offset = Math.max(0, input.offset ?? 0);
4935
5858
  const limit = input.limit ?? DEFAULT_READ_FILE_LINE_LIMIT;
@@ -4937,7 +5860,59 @@ async function readFileGemini(input, options) {
4937
5860
  return "";
4938
5861
  }
4939
5862
  const end = Math.min(lines.length, offset + limit);
4940
- return lines.slice(offset, end).join("\n");
5863
+ return lines.slice(offset, end).map(
5864
+ (line, index) => `L${offset + index + 1}: ${truncateAtCodePointBoundary(line ?? "", runtime.maxLineLength)}`
5865
+ ).join("\n");
5866
+ }
5867
+ async function readFilesGemini(input, options) {
5868
+ const runtime = resolveRuntime(options);
5869
+ const useCharWindow = input.char_offset !== void 0 || input.char_limit !== void 0;
5870
+ const lineOffset = Math.max(0, input.line_offset ?? 0);
5871
+ const lineLimit = input.line_limit ?? DEFAULT_READ_FILES_LINE_LIMIT;
5872
+ const charOffset = Math.max(0, input.char_offset ?? 0);
5873
+ const charLimit = input.char_limit ?? DEFAULT_READ_FILES_CHAR_LIMIT;
5874
+ const includeLineNumbers = input.include_line_numbers !== false;
5875
+ const sections = [];
5876
+ for (const rawPath of input.paths) {
5877
+ const filePath = resolvePathWithPolicy(rawPath, runtime.cwd, runtime.allowOutsideCwd);
5878
+ await runAccessHook2(runtime, {
5879
+ cwd: runtime.cwd,
5880
+ tool: "read_files",
5881
+ action: "read",
5882
+ path: filePath
5883
+ });
5884
+ const content = await runtime.filesystem.readTextFile(filePath);
5885
+ const displayPath = normalizeSlashes(toDisplayPath2(filePath, runtime.cwd));
5886
+ sections.push(`==> ${displayPath} <==`);
5887
+ if (useCharWindow) {
5888
+ if (charOffset >= content.length) {
5889
+ sections.push("");
5890
+ continue;
5891
+ }
5892
+ const end2 = Math.min(content.length, charOffset + charLimit);
5893
+ sections.push(content.slice(charOffset, end2));
5894
+ continue;
5895
+ }
5896
+ const lines = splitLines(content);
5897
+ if (lineOffset >= lines.length) {
5898
+ sections.push("");
5899
+ continue;
5900
+ }
5901
+ const end = Math.min(lines.length, lineOffset + lineLimit);
5902
+ const selected = lines.slice(lineOffset, end);
5903
+ if (includeLineNumbers) {
5904
+ for (let index = 0; index < selected.length; index += 1) {
5905
+ const lineNumber = lineOffset + index + 1;
5906
+ const line = selected[index] ?? "";
5907
+ sections.push(
5908
+ `L${lineNumber}: ${truncateAtCodePointBoundary(line, runtime.maxLineLength)}`
5909
+ );
5910
+ }
5911
+ continue;
5912
+ }
5913
+ sections.push(selected.join("\n"));
5914
+ }
5915
+ return sections.join("\n");
4941
5916
  }
4942
5917
  async function writeFileGemini(input, options) {
4943
5918
  const runtime = resolveRuntime(options);
@@ -4948,7 +5923,7 @@ async function writeFileGemini(input, options) {
4948
5923
  action: "write",
4949
5924
  path: filePath
4950
5925
  });
4951
- await runtime.filesystem.ensureDir(import_node_path4.default.dirname(filePath));
5926
+ await runtime.filesystem.ensureDir(import_node_path5.default.dirname(filePath));
4952
5927
  await runtime.filesystem.writeTextFile(filePath, input.content);
4953
5928
  return `Successfully wrote file: ${toDisplayPath2(filePath, runtime.cwd)}`;
4954
5929
  }
@@ -4969,7 +5944,7 @@ async function replaceFileContentGemini(input, options) {
4969
5944
  originalContent = await runtime.filesystem.readTextFile(filePath);
4970
5945
  } catch (error) {
4971
5946
  if (isNoEntError(error) && oldValue.length === 0) {
4972
- await runtime.filesystem.ensureDir(import_node_path4.default.dirname(filePath));
5947
+ await runtime.filesystem.ensureDir(import_node_path5.default.dirname(filePath));
4973
5948
  await runtime.filesystem.writeTextFile(filePath, newValue);
4974
5949
  return `Successfully wrote new file: ${toDisplayPath2(filePath, runtime.cwd)}`;
4975
5950
  }
@@ -5020,25 +5995,25 @@ async function listDirectoryGemini(input, options) {
5020
5995
  return label;
5021
5996
  }).join("\n");
5022
5997
  }
5023
- async function grepSearchGemini(input, options) {
5998
+ async function rgSearchGemini(input, options, toolName = "rg_search") {
5024
5999
  const runtime = resolveRuntime(options);
5025
6000
  const pattern = input.pattern.trim();
5026
6001
  if (pattern.length === 0) {
5027
6002
  throw new Error("pattern must not be empty");
5028
6003
  }
5029
- const include = input.include?.trim();
6004
+ const glob = input.glob?.trim();
5030
6005
  const searchPath = resolvePathWithPolicy(
5031
- input.dir_path ?? runtime.cwd,
6006
+ input.path ?? runtime.cwd,
5032
6007
  runtime.cwd,
5033
6008
  runtime.allowOutsideCwd
5034
6009
  );
5035
6010
  await runAccessHook2(runtime, {
5036
6011
  cwd: runtime.cwd,
5037
- tool: "grep_search",
6012
+ tool: toolName,
5038
6013
  action: "search",
5039
6014
  path: searchPath,
5040
6015
  pattern,
5041
- include
6016
+ include: glob
5042
6017
  });
5043
6018
  const searchPathInfo = await runtime.filesystem.stat(searchPath);
5044
6019
  const filesToScan = await collectSearchFiles({
@@ -5047,10 +6022,10 @@ async function grepSearchGemini(input, options) {
5047
6022
  rootKind: searchPathInfo.kind,
5048
6023
  maxScannedFiles: runtime.grepMaxScannedFiles
5049
6024
  });
5050
- const matcher = include ? createGlobMatcher(include) : null;
5051
- const patternRegex = compileRegex(pattern);
6025
+ const matcher = glob ? createGlobMatcher(glob) : null;
6026
+ const patternRegex = compileRegex(pattern, input.case_sensitive === true ? "m" : "im");
5052
6027
  const excludeRegex = input.exclude_pattern ? compileRegex(input.exclude_pattern) : null;
5053
- const totalMaxMatches = input.total_max_matches ?? DEFAULT_GREP_LIMIT;
6028
+ const totalMaxMatches = input.max_results ?? DEFAULT_GREP_LIMIT;
5054
6029
  const perFileMaxMatches = input.max_matches_per_file ?? Number.POSITIVE_INFINITY;
5055
6030
  const matches = [];
5056
6031
  const fileMatches = /* @__PURE__ */ new Set();
@@ -5105,6 +6080,21 @@ async function grepSearchGemini(input, options) {
5105
6080
  }
5106
6081
  return matches.slice(0, totalMaxMatches).map((match) => `${match.filePath}:${match.lineNumber}:${match.line ?? ""}`).join("\n");
5107
6082
  }
6083
+ async function grepSearchGemini(input, options) {
6084
+ return rgSearchGemini(
6085
+ {
6086
+ pattern: input.pattern,
6087
+ path: input.dir_path,
6088
+ glob: input.include,
6089
+ exclude_pattern: input.exclude_pattern,
6090
+ names_only: input.names_only,
6091
+ max_matches_per_file: input.max_matches_per_file,
6092
+ max_results: input.total_max_matches
6093
+ },
6094
+ options,
6095
+ "grep_search"
6096
+ );
6097
+ }
5108
6098
  async function globFilesGemini(input, options) {
5109
6099
  const runtime = resolveRuntime(options);
5110
6100
  const dirPath = resolvePathWithPolicy(
@@ -5132,7 +6122,7 @@ async function globFilesGemini(input, options) {
5132
6122
  });
5133
6123
  const matched = [];
5134
6124
  for (const filePath of files) {
5135
- const relativePath = normalizeSlashes(import_node_path4.default.relative(dirPath, filePath));
6125
+ const relativePath = normalizeSlashes(import_node_path5.default.relative(dirPath, filePath));
5136
6126
  if (!matcher(relativePath)) {
5137
6127
  continue;
5138
6128
  }
@@ -5146,11 +6136,11 @@ async function globFilesGemini(input, options) {
5146
6136
  return "No files found.";
5147
6137
  }
5148
6138
  matched.sort((left, right) => right.mtimeMs - left.mtimeMs);
5149
- return matched.map((entry) => normalizeSlashes(import_node_path4.default.resolve(entry.filePath))).join("\n");
6139
+ return matched.map((entry) => normalizeSlashes(toDisplayPath2(entry.filePath, runtime.cwd))).join("\n");
5150
6140
  }
5151
6141
  function resolveRuntime(options) {
5152
6142
  return {
5153
- cwd: import_node_path4.default.resolve(options.cwd ?? process.cwd()),
6143
+ cwd: import_node_path5.default.resolve(options.cwd ?? process.cwd()),
5154
6144
  filesystem: options.fs ?? createNodeAgentFilesystem(),
5155
6145
  allowOutsideCwd: options.allowOutsideCwd === true,
5156
6146
  checkAccess: options.checkAccess,
@@ -5181,22 +6171,22 @@ function mapApplyPatchAction(action) {
5181
6171
  return "move";
5182
6172
  }
5183
6173
  function resolvePathWithPolicy(inputPath, cwd, allowOutsideCwd) {
5184
- const absolutePath = import_node_path4.default.isAbsolute(inputPath) ? import_node_path4.default.resolve(inputPath) : import_node_path4.default.resolve(cwd, inputPath);
6174
+ const absolutePath = import_node_path5.default.isAbsolute(inputPath) ? import_node_path5.default.resolve(inputPath) : import_node_path5.default.resolve(cwd, inputPath);
5185
6175
  if (!allowOutsideCwd && !isPathInsideCwd2(absolutePath, cwd)) {
5186
6176
  throw new Error(`path "${inputPath}" resolves outside cwd "${cwd}"`);
5187
6177
  }
5188
6178
  return absolutePath;
5189
6179
  }
5190
6180
  function isPathInsideCwd2(candidatePath, cwd) {
5191
- const relative = import_node_path4.default.relative(cwd, candidatePath);
5192
- return relative === "" || !relative.startsWith("..") && !import_node_path4.default.isAbsolute(relative);
6181
+ const relative = import_node_path5.default.relative(cwd, candidatePath);
6182
+ return relative === "" || !relative.startsWith("..") && !import_node_path5.default.isAbsolute(relative);
5193
6183
  }
5194
6184
  function toDisplayPath2(absolutePath, cwd) {
5195
- const relative = import_node_path4.default.relative(cwd, absolutePath);
6185
+ const relative = import_node_path5.default.relative(cwd, absolutePath);
5196
6186
  if (relative === "") {
5197
6187
  return ".";
5198
6188
  }
5199
- if (!relative.startsWith("..") && !import_node_path4.default.isAbsolute(relative)) {
6189
+ if (!relative.startsWith("..") && !import_node_path5.default.isAbsolute(relative)) {
5200
6190
  return relative;
5201
6191
  }
5202
6192
  return absolutePath;
@@ -5406,9 +6396,9 @@ async function collectSearchFiles(params) {
5406
6396
  }
5407
6397
  return files;
5408
6398
  }
5409
- function compileRegex(pattern) {
6399
+ function compileRegex(pattern, flags = "m") {
5410
6400
  try {
5411
- return new RegExp(pattern, "m");
6401
+ return new RegExp(pattern, flags);
5412
6402
  } catch (error) {
5413
6403
  const message = error instanceof Error ? error.message : String(error);
5414
6404
  throw new Error(`invalid regex pattern: ${message}`);
@@ -5423,7 +6413,7 @@ function createGlobMatcher(pattern, caseSensitive = false) {
5423
6413
  }));
5424
6414
  return (candidatePath) => {
5425
6415
  const normalizedPath = normalizeSlashes(candidatePath);
5426
- const basename = import_node_path4.default.posix.basename(normalizedPath);
6416
+ const basename = import_node_path5.default.posix.basename(normalizedPath);
5427
6417
  return compiled.some(
5428
6418
  (entry) => entry.regex.test(entry.applyToBasename ? basename : normalizedPath)
5429
6419
  );
@@ -5587,6 +6577,13 @@ function mergeToolSets(base, extra) {
5587
6577
  }
5588
6578
  // Annotate the CommonJS export names for ESM import in node:
5589
6579
  0 && (module.exports = {
6580
+ CODEX_APPLY_PATCH_FREEFORM_TOOL_DESCRIPTION,
6581
+ CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION,
6582
+ CODEX_APPLY_PATCH_LARK_GRAMMAR,
6583
+ FIREWORKS_DEFAULT_GLM_MODEL,
6584
+ FIREWORKS_DEFAULT_KIMI_MODEL,
6585
+ FIREWORKS_DEFAULT_MINIMAX_MODEL,
6586
+ FIREWORKS_MODEL_IDS,
5590
6587
  InMemoryAgentFilesystem,
5591
6588
  LlmJsonCallError,
5592
6589
  appendMarkdownSourcesSection,
@@ -5599,6 +6596,7 @@ function mergeToolSets(base, extra) {
5599
6596
  createCodexReadFileTool,
5600
6597
  createFilesystemToolSetForModel,
5601
6598
  createGeminiFilesystemToolSet,
6599
+ createGeminiReadFileTool,
5602
6600
  createGlobTool,
5603
6601
  createGrepFilesTool,
5604
6602
  createGrepSearchTool,
@@ -5607,9 +6605,11 @@ function mergeToolSets(base, extra) {
5607
6605
  createListDirectoryTool,
5608
6606
  createModelAgnosticFilesystemToolSet,
5609
6607
  createNodeAgentFilesystem,
5610
- createReadFileTool,
6608
+ createReadFilesTool,
5611
6609
  createReplaceTool,
6610
+ createRgSearchTool,
5612
6611
  createWriteFileTool,
6612
+ customTool,
5613
6613
  encodeChatGptAuthJson,
5614
6614
  encodeChatGptAuthJsonB64,
5615
6615
  estimateCallCostUsd,
@@ -5620,12 +6620,14 @@ function mergeToolSets(base, extra) {
5620
6620
  generateText,
5621
6621
  getChatGptAuthProfile,
5622
6622
  getCurrentToolCallContext,
6623
+ isFireworksModelId,
5623
6624
  isGeminiModelId,
5624
6625
  loadEnvFromFile,
5625
6626
  loadLocalEnv,
5626
6627
  parseJsonFromLlmText,
5627
6628
  refreshChatGptOauthToken,
5628
6629
  resolveFilesystemToolProfile,
6630
+ resolveFireworksModelId,
5629
6631
  runAgentLoop,
5630
6632
  runToolLoop,
5631
6633
  sanitisePartForLogging,