@agent-native/core 0.91.2 → 0.92.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.
Files changed (216) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +17 -0
  3. package/corpus/core/docs/content/faq.mdx +17 -0
  4. package/corpus/core/docs/content/notifications.mdx +12 -6
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/agent/production-agent.ts +140 -46
  7. package/corpus/core/src/agent/tool-search.ts +71 -4
  8. package/corpus/core/src/cli/index.ts +20 -0
  9. package/corpus/core/src/cli/upgrade.ts +798 -0
  10. package/corpus/core/src/client/AssistantChat.tsx +1 -1
  11. package/corpus/core/src/client/HighlightedCodeBlock.tsx +20 -3
  12. package/corpus/core/src/client/agent-chat-adapter.ts +31 -6
  13. package/corpus/core/src/client/chat/message-components.tsx +85 -8
  14. package/corpus/core/src/client/chat/tool-call-display.tsx +355 -144
  15. package/corpus/core/src/client/code-agent-chat-adapter.ts +2 -9
  16. package/corpus/core/src/client/session-replay.ts +3 -97
  17. package/corpus/core/src/client/settings/SettingsPanel.tsx +533 -389
  18. package/corpus/core/src/client/settings/SettingsSection.tsx +154 -17
  19. package/corpus/core/src/client/sse-event-processor.ts +29 -2
  20. package/corpus/core/src/extensions/actions.ts +113 -5
  21. package/corpus/core/src/notifications/channels.ts +88 -25
  22. package/corpus/core/src/notifications/registry.ts +17 -3
  23. package/corpus/core/src/notifications/types.ts +4 -1
  24. package/corpus/core/src/server/agent-chat-plugin.ts +7 -3
  25. package/corpus/core/src/server/request-context.ts +7 -0
  26. package/corpus/core/src/styles/agent-conversation.css +1 -1
  27. package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  28. package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  29. package/corpus/core/src/templates/default/AGENTS.md +10 -3
  30. package/corpus/core/src/templates/default/package.json +2 -1
  31. package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  32. package/corpus/core/src/templates/headless/AGENTS.md +9 -3
  33. package/corpus/core/src/templates/headless/package.json +1 -0
  34. package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  35. package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  36. package/corpus/core/src/templates/workspace-root/AGENTS.md +10 -4
  37. package/corpus/core/src/templates/workspace-root/package.json +1 -0
  38. package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +20 -2
  39. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +5 -6
  40. package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  41. package/corpus/templates/analytics/AGENTS.md +7 -5
  42. package/corpus/templates/analytics/actions/save-monitor.ts +14 -0
  43. package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +41 -6
  44. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +122 -11
  45. package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +8 -2
  46. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +151 -32
  47. package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +17 -2
  48. package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +4 -0
  49. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +54 -190
  50. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-tables-keep-their-size-while-loading.md +6 -0
  51. package/corpus/templates/analytics/changelog/2026-07-08-monitoring-uptime-and-errors-tabs-now-clearly-show-which-view-is-active.md +6 -0
  52. package/corpus/templates/analytics/changelog/2026-07-08-session-replay-uses-stock-rrweb-sizing-again-so-recorded.md +6 -0
  53. package/corpus/templates/analytics/changelog/2026-07-08-sidebar-dashboard-menus-now-open-above-the-dashboard-canvas.md +6 -0
  54. package/corpus/templates/analytics/changelog/2026-07-08-uptime-alerting-clarifies-in-app-inbox-vs-email-and-lets-you-paste-slack-or-webhook-urls-per-monitor.md +6 -0
  55. package/corpus/templates/analytics/docs/uptime-monitoring.md +13 -11
  56. package/corpus/templates/analytics/server/db/schema-monitoring.ts +4 -0
  57. package/corpus/templates/analytics/server/lib/uptime-monitors.ts +60 -12
  58. package/corpus/templates/analytics/server/plugins/db.ts +10 -0
  59. package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +20 -2
  60. package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  61. package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +20 -2
  62. package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  63. package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +20 -2
  64. package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  65. package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +20 -2
  66. package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  67. package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +20 -2
  68. package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  69. package/corpus/templates/clips/changelog/2026-07-08-desktop-meeting-notes-stay-active-from-tray-and-shortcut-controls.md +6 -0
  70. package/corpus/templates/clips/changelog/2026-07-08-desktop-meeting-popovers-can-start-notes-and-join-the-meetin.md +6 -0
  71. package/corpus/templates/clips/changelog/2026-07-08-meeting-notes-keep-their-recording-state-when-the-desktop.md +6 -0
  72. package/corpus/templates/clips/changelog/2026-07-08-meeting-reminder-dropdowns-now-expand-fully-instead-of-being.md +6 -0
  73. package/corpus/templates/clips/desktop/src/app.tsx +123 -3
  74. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +15 -1
  75. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +23 -0
  76. package/corpus/templates/clips/desktop/src/styles.css +23 -1
  77. package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +1 -3
  78. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +40 -6
  79. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +4 -2
  80. package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +3 -5
  81. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +23 -19
  82. package/corpus/templates/clips/desktop/src-tauri/src/shortcuts.rs +3 -3
  83. package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +0 -1
  84. package/corpus/templates/clips/desktop/src-tauri/src/state.rs +5 -0
  85. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +18 -6
  86. package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +20 -2
  87. package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  88. package/corpus/templates/content/actions/_batch-utils.ts +8 -0
  89. package/corpus/templates/content/actions/_builder-cms-read-client.ts +7 -5
  90. package/corpus/templates/content/actions/_database-source-utils.ts +776 -319
  91. package/corpus/templates/content/actions/_database-utils.ts +6 -1
  92. package/corpus/templates/content/actions/_property-utils.ts +168 -0
  93. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +19 -12
  94. package/corpus/templates/content/actions/bind-content-database-source-field.ts +19 -12
  95. package/corpus/templates/content/actions/delete-document.ts +9 -13
  96. package/corpus/templates/content/actions/refresh-content-database-source.ts +5 -5
  97. package/corpus/templates/content/app/components/editor/body-hydration.ts +35 -11
  98. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +47 -5
  99. package/corpus/templates/content/app/hooks/use-documents.ts +8 -2
  100. package/corpus/templates/content/changelog/2026-07-08-builder-source-sync-now-completes-reliably-on-hosted-databases.md +6 -0
  101. package/corpus/templates/content/changelog/2026-07-08-fixed-builder-database-sync-so-large-sources-continue-past-t.md +6 -0
  102. package/corpus/templates/content/server/plugins/db.ts +19 -0
  103. package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +20 -2
  104. package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  105. package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +20 -2
  106. package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  107. package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +20 -2
  108. package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  109. package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  110. package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +20 -2
  111. package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  112. package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +20 -2
  113. package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  114. package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +20 -2
  115. package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  116. package/corpus/templates/videos/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  117. package/corpus/templates/voice/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  118. package/dist/agent/production-agent.d.ts +5 -1
  119. package/dist/agent/production-agent.d.ts.map +1 -1
  120. package/dist/agent/production-agent.js +112 -42
  121. package/dist/agent/production-agent.js.map +1 -1
  122. package/dist/agent/tool-search.d.ts +2 -0
  123. package/dist/agent/tool-search.d.ts.map +1 -1
  124. package/dist/agent/tool-search.js +60 -4
  125. package/dist/agent/tool-search.js.map +1 -1
  126. package/dist/cli/index.js +19 -0
  127. package/dist/cli/index.js.map +1 -1
  128. package/dist/cli/upgrade.d.ts +100 -0
  129. package/dist/cli/upgrade.d.ts.map +1 -0
  130. package/dist/cli/upgrade.js +678 -0
  131. package/dist/cli/upgrade.js.map +1 -0
  132. package/dist/client/AssistantChat.js +1 -1
  133. package/dist/client/AssistantChat.js.map +1 -1
  134. package/dist/client/HighlightedCodeBlock.d.ts +2 -0
  135. package/dist/client/HighlightedCodeBlock.d.ts.map +1 -1
  136. package/dist/client/HighlightedCodeBlock.js +10 -1
  137. package/dist/client/HighlightedCodeBlock.js.map +1 -1
  138. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  139. package/dist/client/agent-chat-adapter.js +32 -4
  140. package/dist/client/agent-chat-adapter.js.map +1 -1
  141. package/dist/client/chat/message-components.d.ts.map +1 -1
  142. package/dist/client/chat/message-components.js +61 -8
  143. package/dist/client/chat/message-components.js.map +1 -1
  144. package/dist/client/chat/tool-call-display.d.ts +12 -0
  145. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  146. package/dist/client/chat/tool-call-display.js +136 -42
  147. package/dist/client/chat/tool-call-display.js.map +1 -1
  148. package/dist/client/code-agent-chat-adapter.js +2 -9
  149. package/dist/client/code-agent-chat-adapter.js.map +1 -1
  150. package/dist/client/session-replay.d.ts +0 -8
  151. package/dist/client/session-replay.d.ts.map +1 -1
  152. package/dist/client/session-replay.js +3 -80
  153. package/dist/client/session-replay.js.map +1 -1
  154. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  155. package/dist/client/settings/SettingsPanel.js +52 -19
  156. package/dist/client/settings/SettingsPanel.js.map +1 -1
  157. package/dist/client/settings/SettingsSection.d.ts +19 -4
  158. package/dist/client/settings/SettingsSection.d.ts.map +1 -1
  159. package/dist/client/settings/SettingsSection.js +33 -4
  160. package/dist/client/settings/SettingsSection.js.map +1 -1
  161. package/dist/client/sse-event-processor.d.ts +9 -0
  162. package/dist/client/sse-event-processor.d.ts.map +1 -1
  163. package/dist/client/sse-event-processor.js +20 -2
  164. package/dist/client/sse-event-processor.js.map +1 -1
  165. package/dist/collab/routes.d.ts +1 -1
  166. package/dist/extensions/actions.d.ts.map +1 -1
  167. package/dist/extensions/actions.js +85 -5
  168. package/dist/extensions/actions.js.map +1 -1
  169. package/dist/notifications/channels.d.ts +8 -3
  170. package/dist/notifications/channels.d.ts.map +1 -1
  171. package/dist/notifications/channels.js +61 -22
  172. package/dist/notifications/channels.js.map +1 -1
  173. package/dist/notifications/registry.d.ts.map +1 -1
  174. package/dist/notifications/registry.js +14 -3
  175. package/dist/notifications/registry.js.map +1 -1
  176. package/dist/notifications/routes.d.ts +1 -1
  177. package/dist/notifications/types.d.ts +4 -1
  178. package/dist/notifications/types.d.ts.map +1 -1
  179. package/dist/notifications/types.js.map +1 -1
  180. package/dist/observability/routes.d.ts +1 -1
  181. package/dist/resources/handlers.d.ts +1 -1
  182. package/dist/server/agent-chat-plugin.d.ts +5 -1
  183. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  184. package/dist/server/agent-chat-plugin.js +2 -2
  185. package/dist/server/agent-chat-plugin.js.map +1 -1
  186. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  187. package/dist/server/request-context.d.ts +7 -0
  188. package/dist/server/request-context.d.ts.map +1 -1
  189. package/dist/server/request-context.js.map +1 -1
  190. package/dist/styles/agent-conversation.css +1 -1
  191. package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  192. package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  193. package/dist/templates/default/AGENTS.md +10 -3
  194. package/dist/templates/default/package.json +2 -1
  195. package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  196. package/dist/templates/headless/AGENTS.md +9 -3
  197. package/dist/templates/headless/package.json +1 -0
  198. package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  199. package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  200. package/dist/templates/workspace-root/AGENTS.md +10 -4
  201. package/dist/templates/workspace-root/package.json +1 -0
  202. package/docs/content/faq.mdx +17 -0
  203. package/docs/content/notifications.mdx +12 -6
  204. package/package.json +2 -2
  205. package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  206. package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  207. package/src/templates/default/AGENTS.md +10 -3
  208. package/src/templates/default/package.json +2 -1
  209. package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  210. package/src/templates/headless/AGENTS.md +9 -3
  211. package/src/templates/headless/package.json +1 -0
  212. package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  213. package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  214. package/src/templates/workspace-root/AGENTS.md +10 -4
  215. package/src/templates/workspace-root/package.json +1 -0
  216. package/corpus/templates/analytics/changelog/2026-07-08-session-replay-clamps-ultra-wide-viewports-while-keeping-the.md +0 -6
@@ -497,15 +497,31 @@ function createPlanModeBashAction(entry) {
497
497
  },
498
498
  };
499
499
  }
500
+ function createPlanModeBlockedAction(name, entry, reason) {
501
+ return {
502
+ ...entry,
503
+ allowInPlanMode: false,
504
+ readOnly: true,
505
+ tool: {
506
+ ...entry.tool,
507
+ description: `${entry.tool.description}\n\nPlan mode blocked: ${reason ?? "not available while planning"}.`,
508
+ },
509
+ run: async () => planModeBlockedMessage(name, reason),
510
+ };
511
+ }
500
512
  export function createPlanModeActionRegistry(actions) {
501
513
  const filtered = {};
502
514
  for (const [name, entry] of Object.entries(actions)) {
503
515
  if (name === TOOL_SEARCH_ACTION_NAME)
504
516
  continue;
505
- if (entry.allowInPlanMode === false)
517
+ if (entry.allowInPlanMode === false) {
518
+ filtered[name] = createPlanModeBlockedAction(name, entry, "not available while planning");
506
519
  continue;
507
- if (PLAN_MODE_BLOCKED_READONLY_TOOLS.has(name))
520
+ }
521
+ if (PLAN_MODE_BLOCKED_READONLY_TOOLS.has(name)) {
522
+ filtered[name] = createPlanModeBlockedAction(name, entry, "not available while planning");
508
523
  continue;
524
+ }
509
525
  const allowedActions = PLAN_MODE_ALLOWED_ACTIONS[name];
510
526
  if (allowedActions) {
511
527
  filtered[name] = createPlanModeGuardedAction(name, entry, allowedActions);
@@ -522,6 +538,9 @@ export function createPlanModeActionRegistry(actions) {
522
538
  if (entry.readOnly === true) {
523
539
  filtered[name] = entry;
524
540
  }
541
+ else {
542
+ filtered[name] = createPlanModeBlockedAction(name, entry, "write or side-effecting tool");
543
+ }
525
544
  }
526
545
  if (actions[TOOL_SEARCH_ACTION_NAME]) {
527
546
  filtered[TOOL_SEARCH_ACTION_NAME] = createToolSearchEntry(() => filtered);
@@ -1393,7 +1412,8 @@ function isReusableReadOnlyToolResult(part) {
1393
1412
  const lower = part.content.trim().toLowerCase();
1394
1413
  if (!lower)
1395
1414
  return false;
1396
- return !(lower.startsWith("error running ") ||
1415
+ return !(lower.startsWith("invalid action parameters for ") ||
1416
+ lower.startsWith("error running ") ||
1397
1417
  lower.includes("run aborted") ||
1398
1418
  lower.includes("tool call timed out") ||
1399
1419
  lower.includes("stale_run") ||
@@ -1465,13 +1485,68 @@ export function actionsToEngineTools(actions) {
1465
1485
  }
1466
1486
  return tools;
1467
1487
  }
1468
- function filterInitialEngineTools(tools, initialToolNames) {
1488
+ export function filterInitialEngineTools(tools, initialToolNames) {
1469
1489
  if (!initialToolNames)
1470
1490
  return tools;
1471
1491
  const names = new Set(initialToolNames);
1472
1492
  names.add(TOOL_SEARCH_ACTION_NAME);
1493
+ for (const tool of tools) {
1494
+ if (isDefaultLeanInitialToolName(tool.name)) {
1495
+ names.add(tool.name);
1496
+ }
1497
+ }
1473
1498
  return tools.filter((tool) => names.has(tool.name));
1474
1499
  }
1500
+ const DEFAULT_LEAN_INITIAL_TOOL_NAMES = new Set([
1501
+ // Broad provider/API/corpus primitives should be callable as soon as the
1502
+ // prompt teaches them; waiting for a discovery round-trip caused prod runs to
1503
+ // waste turns on provider work that was described but not loaded.
1504
+ "data-source-status",
1505
+ "provider-api-catalog",
1506
+ "provider-api-docs",
1507
+ "provider-api-request",
1508
+ "provider-corpus-job",
1509
+ "provider-corpus-jobs",
1510
+ "query-staged-dataset",
1511
+ "list-staged-datasets",
1512
+ "delete-staged-dataset",
1513
+ "run-code",
1514
+ "get-code-execution",
1515
+ "list-extensions",
1516
+ "get-extension",
1517
+ "update-extension",
1518
+ "list-extension-history",
1519
+ "get-extension-history-version",
1520
+ // Common first-class integration shortcuts. These are included only when the
1521
+ // current app/mode registry actually exposes them.
1522
+ "bigquery",
1523
+ "search-bigquery-schema",
1524
+ "bigquery-table-info",
1525
+ "ga4",
1526
+ "amplitude",
1527
+ "prometheus",
1528
+ "grafana",
1529
+ "sentry",
1530
+ "stripe",
1531
+ "account-deep-dive",
1532
+ "slack-messages",
1533
+ "hubspot-deals",
1534
+ "hubspot-records",
1535
+ "hubspot-pipelines",
1536
+ "hubspot-metrics",
1537
+ "gong-calls",
1538
+ "github-repo-files",
1539
+ "jira",
1540
+ "jira-search",
1541
+ "gcloud",
1542
+ "notion-search",
1543
+ "pylon-search",
1544
+ ]);
1545
+ function isDefaultLeanInitialToolName(name) {
1546
+ if (DEFAULT_LEAN_INITIAL_TOOL_NAMES.has(name))
1547
+ return true;
1548
+ return (name.startsWith("provider-api-") || name.startsWith("provider-corpus-"));
1549
+ }
1475
1550
  function extractToolSearchResultNames(value) {
1476
1551
  if (!value || typeof value !== "object")
1477
1552
  return [];
@@ -1781,7 +1856,7 @@ function toolInputSchemaErrorResult(toolName, input, error) {
1781
1856
  const rawToolInputAjv = new Ajv({
1782
1857
  strict: false,
1783
1858
  allErrors: true,
1784
- coerceTypes: false,
1859
+ coerceTypes: true,
1785
1860
  useDefaults: false,
1786
1861
  removeAdditional: false,
1787
1862
  });
@@ -2695,43 +2770,6 @@ export async function runAgentLoop(opts) {
2695
2770
  };
2696
2771
  }
2697
2772
  }
2698
- const cacheKey = actionEntry.readOnly === true
2699
- ? toolCallCacheKey(toolCall.name, toolCall.input)
2700
- : null;
2701
- if (cacheKey && readOnlyToolResultCache.has(cacheKey)) {
2702
- const repeats = (duplicateReadOnlyToolCalls.get(cacheKey) ?? 0) + 1;
2703
- duplicateReadOnlyToolCalls.set(cacheKey, repeats);
2704
- const previousResult = readOnlyToolResultCache.get(cacheKey) ?? "";
2705
- const result = `Skipped duplicate read-only call to ${toolCall.name}: identical input already ran in this turn. ` +
2706
- `Use the previous result already in the conversation instead of calling this tool again.\n\n` +
2707
- `Previous result:\n${previousResult}`;
2708
- send({
2709
- type: "tool_start",
2710
- tool: toolCall.name,
2711
- input: toolCall.input,
2712
- });
2713
- send({
2714
- type: "tool_done",
2715
- tool: toolCall.name,
2716
- input: toolCall.input,
2717
- result,
2718
- completedSideEffect: false,
2719
- });
2720
- recordToolResult(result, false);
2721
- if (repeats >= 3) {
2722
- requestedActionStop ??= {
2723
- message: "I stopped because the agent kept asking for the same read-only context it already had. Please send the request again if you want me to retry from a fresh turn.",
2724
- errorCode: "duplicate_read_only_tool",
2725
- };
2726
- }
2727
- return {
2728
- type: "tool-result",
2729
- toolCallId: toolCall.id,
2730
- toolName: toolCall.name,
2731
- toolInput: wireToolInput,
2732
- content: result,
2733
- };
2734
- }
2735
2773
  const DEFAULT_TOOL_RESULT_CHARS = 50_000;
2736
2774
  // Default action tools should not undercut durable/background runs. The
2737
2775
  // run-manager still aborts foreground hosted runs around 40s, while
@@ -2932,6 +2970,38 @@ export async function runAgentLoop(opts) {
2932
2970
  isError: true,
2933
2971
  };
2934
2972
  }
2973
+ const cacheKey = actionEntry.readOnly === true
2974
+ ? toolCallCacheKey(toolCall.name, toolCall.input)
2975
+ : null;
2976
+ if (cacheKey && readOnlyToolResultCache.has(cacheKey)) {
2977
+ const repeats = (duplicateReadOnlyToolCalls.get(cacheKey) ?? 0) + 1;
2978
+ duplicateReadOnlyToolCalls.set(cacheKey, repeats);
2979
+ const previousResult = readOnlyToolResultCache.get(cacheKey) ?? "";
2980
+ const result = `Skipped duplicate read-only call to ${toolCall.name}: identical input already ran in this turn. ` +
2981
+ `Use the previous result already in the conversation instead of calling this tool again.\n\n` +
2982
+ `Previous result:\n${previousResult}`;
2983
+ send({
2984
+ type: "tool_done",
2985
+ tool: toolCall.name,
2986
+ input: toolCall.input,
2987
+ result,
2988
+ completedSideEffect: false,
2989
+ });
2990
+ recordToolResult(result, false);
2991
+ if (repeats >= 3) {
2992
+ requestedActionStop ??= {
2993
+ message: "I stopped because the agent kept asking for the same read-only context it already had. Please send the request again if you want me to retry from a fresh turn.",
2994
+ errorCode: "duplicate_read_only_tool",
2995
+ };
2996
+ }
2997
+ return {
2998
+ type: "tool-result",
2999
+ toolCallId: toolCall.id,
3000
+ toolName: toolCall.name,
3001
+ toolInput: wireToolInput,
3002
+ content: result,
3003
+ };
3004
+ }
2935
3005
  if (opts.executionMode === "plan" &&
2936
3006
  !isPlanModeToolCallAllowed(toolCall.name, toolCall.input, actionEntry)) {
2937
3007
  const result = planModeBlockedMessage(toolCall.name);