@agent-native/core 0.153.2 → 0.153.5

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 (92) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/AGENTS.md +4 -0
  3. package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
  4. package/corpus/templates/analytics/actions/bigquery-query.ts +1 -0
  5. package/corpus/templates/analytics/actions/bigquery.ts +1 -0
  6. package/corpus/templates/analytics/actions/content-calendar-schema.ts +1 -0
  7. package/corpus/templates/analytics/actions/content-calendar.ts +1 -0
  8. package/corpus/templates/analytics/actions/gcloud.ts +1 -0
  9. package/corpus/templates/analytics/actions/get-data-program.ts +1 -0
  10. package/corpus/templates/analytics/actions/get-error-issue.ts +1 -0
  11. package/corpus/templates/analytics/actions/get-monitor-stats.ts +1 -0
  12. package/corpus/templates/analytics/actions/get-monitor.ts +1 -0
  13. package/corpus/templates/analytics/actions/get-session-replay-events.ts +1 -0
  14. package/corpus/templates/analytics/actions/get-session-replay-summary.ts +1 -0
  15. package/corpus/templates/analytics/actions/get-session-replay-timeline.ts +1 -0
  16. package/corpus/templates/analytics/actions/gong-calls.ts +1 -0
  17. package/corpus/templates/analytics/actions/gong-native-insights.ts +1 -0
  18. package/corpus/templates/analytics/actions/grafana.ts +1 -0
  19. package/corpus/templates/analytics/actions/hubspot-deals.ts +1 -0
  20. package/corpus/templates/analytics/actions/hubspot-metrics.ts +1 -0
  21. package/corpus/templates/analytics/actions/hubspot-pipelines.ts +1 -0
  22. package/corpus/templates/analytics/actions/hubspot-records.ts +1 -0
  23. package/corpus/templates/analytics/actions/jira-search.ts +1 -0
  24. package/corpus/templates/analytics/actions/jira.ts +1 -0
  25. package/corpus/templates/analytics/actions/list-error-issues.ts +1 -0
  26. package/corpus/templates/analytics/actions/list-monitors.ts +1 -0
  27. package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -0
  28. package/corpus/templates/analytics/actions/match-error-issues.ts +1 -0
  29. package/corpus/templates/analytics/actions/prometheus.ts +1 -0
  30. package/corpus/templates/analytics/actions/pylon-issues.ts +1 -0
  31. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -0
  32. package/corpus/templates/analytics/actions/query-dashboard-panel.ts +1 -0
  33. package/corpus/templates/analytics/actions/query-inbound-forms.ts +1 -0
  34. package/corpus/templates/analytics/actions/run-monitor-check.ts +1 -0
  35. package/corpus/templates/analytics/actions/sentry.ts +1 -0
  36. package/corpus/templates/analytics/actions/seo-blog-pages.ts +1 -0
  37. package/corpus/templates/analytics/actions/seo-page-keywords.ts +1 -0
  38. package/corpus/templates/analytics/actions/seo-top-keywords.ts +1 -0
  39. package/corpus/templates/analytics/actions/slack-messages.ts +1 -0
  40. package/corpus/templates/analytics/actions/stripe.ts +1 -0
  41. package/corpus/templates/analytics/actions/test-custom-api-connection.ts +1 -0
  42. package/corpus/templates/analytics/server/lib/real-data-actions.ts +38 -47
  43. package/corpus/templates/analytics/server/plugins/agent-chat.ts +41 -34
  44. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +9 -6
  45. package/corpus/templates/clips/desktop/src-tauri/src/rewind_clip.rs +70 -10
  46. package/corpus/templates/forms/AGENTS.md +6 -0
  47. package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
  48. package/corpus/templates/mail/AGENTS.md +5 -4
  49. package/corpus/templates/mail/actions/get-automation-settings.ts +17 -6
  50. package/corpus/templates/mail/actions/send-email.ts +17 -9
  51. package/corpus/templates/mail/actions/send-queued-drafts.ts +21 -11
  52. package/corpus/templates/mail/actions/update-automation-settings.ts +20 -6
  53. package/corpus/templates/mail/app/i18n/en-US.ts +5 -0
  54. package/corpus/templates/mail/app/pages/SettingsPage.tsx +68 -7
  55. package/corpus/templates/mail/server/lib/automation-settings.ts +27 -0
  56. package/corpus/templates/mail/server/plugins/agent-chat.ts +2 -0
  57. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +3 -3
  58. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +17 -4
  59. package/corpus/templates/slides/app/context/DeckContext.tsx +3 -2
  60. package/corpus/templates/slides/app/pages/DeckEditor.tsx +44 -0
  61. package/corpus/templates/slides/changelog/2026-08-12-arrow-key-navigation-in-the-slide-film-strip-now-scrolls-sli.md +6 -0
  62. package/corpus/templates/slides/changelog/2026-08-12-duplicate-a-slide-from-the-film-strip-with-cmd-ctrl-c-then-c.md +6 -0
  63. package/corpus/templates/slides/changelog/2026-08-12-presenting-a-deck-now-returns-you-to-the-slide-you-were-view.md +6 -0
  64. package/dist/action.d.ts +13 -0
  65. package/dist/action.js +3 -0
  66. package/dist/agent/engine/tool-call-journal-seed.d.ts +27 -10
  67. package/dist/agent/engine/tool-call-journal-seed.js +46 -32
  68. package/dist/agent/production-agent.d.ts +33 -0
  69. package/dist/agent/production-agent.js +172 -57
  70. package/dist/agent/run-loop-with-resume.d.ts +1 -1
  71. package/dist/agent/run-loop-with-resume.js +49 -35
  72. package/dist/client/agent-chat-adapter.js +204 -273
  73. package/dist/client/resources/mcp-integration-catalog.d.ts +7 -0
  74. package/dist/client/resources/mcp-integration-catalog.js +14 -1
  75. package/dist/client/settings/AgentsSection.js +46 -30
  76. package/dist/client/sse-event-processor.d.ts +7 -0
  77. package/dist/client/sse-event-processor.js +21 -1
  78. package/dist/collab/awareness.d.ts +2 -2
  79. package/dist/collab/routes.d.ts +1 -1
  80. package/dist/collab/struct-routes.d.ts +1 -1
  81. package/dist/notifications/routes.d.ts +1 -1
  82. package/dist/observability/routes.d.ts +3 -3
  83. package/dist/provider-api/actions/github-repo-files.js +1 -0
  84. package/dist/provider-api/actions/provider-api.js +1 -0
  85. package/dist/provider-api/actions/staged-datasets.js +1 -0
  86. package/dist/provider-api/corpus-jobs.js +1 -0
  87. package/dist/server/action-discovery.js +2 -0
  88. package/dist/server/agent-chat-plugin.js +1 -0
  89. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  90. package/dist/server/realtime-token.d.ts +1 -1
  91. package/dist/server/transcribe-voice.d.ts +1 -1
  92. package/package.json +3 -3
@@ -239,6 +239,17 @@ export default function PresentationView({
239
239
 
240
240
  const isShared = deckId.startsWith("__shared__/");
241
241
 
242
+ // Exit handlers read these instead of closing over `currentIndex`/`deckId`/
243
+ // `isShared` so the mount-only fullscreenchange listener still lands on the
244
+ // right deck and slide even if this component is reused for a different
245
+ // deck without remounting (e.g. an agent-driven navigation).
246
+ const currentIndexRef = useRef(currentIndex);
247
+ currentIndexRef.current = currentIndex;
248
+ const deckIdRef = useRef(deckId);
249
+ deckIdRef.current = deckId;
250
+ const isSharedRef = useRef(isShared);
251
+ isSharedRef.current = isShared;
252
+
242
253
  useEffect(() => {
243
254
  setCurrentIndex((prev) => clampIndex(prev));
244
255
  setPrevIndex((prev) =>
@@ -348,7 +359,7 @@ export default function PresentationView({
348
359
  const token = deckId.replace("__shared__/", "");
349
360
  navigate(`/share/${token}`);
350
361
  } else {
351
- navigate(`/deck/${deckId}`);
362
+ navigate(`/deck/${deckId}?slide=${currentIndexRef.current + 1}`);
352
363
  }
353
364
  }, [navigate, deckId, isShared]);
354
365
 
@@ -465,11 +476,13 @@ export default function PresentationView({
465
476
  // fullscreen first — otherwise the gesture-fallback overlay handles it.
466
477
  if (enteredFullscreenRef.current && !document.fullscreenElement) {
467
478
  enteredFullscreenRef.current = false;
468
- if (isShared) {
469
- const token = deckId.replace("__shared__/", "");
479
+ if (isSharedRef.current) {
480
+ const token = deckIdRef.current.replace("__shared__/", "");
470
481
  navigate(`/share/${token}`);
471
482
  } else {
472
- navigate(`/deck/${deckId}`);
483
+ navigate(
484
+ `/deck/${deckIdRef.current}?slide=${currentIndexRef.current + 1}`,
485
+ );
473
486
  }
474
487
  }
475
488
  };
@@ -223,7 +223,7 @@ interface DeckContextType {
223
223
  options?: UpdateSlideOptions,
224
224
  ) => void;
225
225
  deleteSlide: (deckId: string, slideId: string) => void;
226
- duplicateSlide: (deckId: string, slideId: string) => void;
226
+ duplicateSlide: (deckId: string, slideId: string) => string | undefined;
227
227
  reorderSlides: (deckId: string, oldIndex: number, newIndex: number) => void;
228
228
  setDeckSlides: (deckId: string, slides: Slide[]) => void;
229
229
  /**
@@ -2223,7 +2223,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
2223
2223
  (deckId: string, slideId: string) => {
2224
2224
  const before = decksRef.current.find((d) => d.id === deckId);
2225
2225
  const original = before?.slides.find((slide) => slide.id === slideId);
2226
- if (!before || !original) return;
2226
+ if (!before || !original) return undefined;
2227
2227
 
2228
2228
  markDeckDirty(deckId);
2229
2229
  const copiedSlide: Slide = { ...original, id: nanoid(8) };
@@ -2254,6 +2254,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
2254
2254
  };
2255
2255
  enqueueDeckOp(deckId, op);
2256
2256
  recordUndo(before, op, { label: "Duplicate slide" });
2257
+ return copiedSlide.id;
2257
2258
  },
2258
2259
  [markDeckDirty, recordUndo, setDecksLocal],
2259
2260
  );
@@ -807,6 +807,50 @@ export default function DeckEditor() {
807
807
  return () => document.removeEventListener("keydown", handleKeyDown);
808
808
  }, [deck, id, activeSlideId, deleteSlideWithUndo, pinMode, drawMode]);
809
809
 
810
+ // Cmd/Ctrl+C then Cmd/Ctrl+V duplicates a slide thumbnail in the film
811
+ // strip. Scoped to an actually-focused thumbnail (rather than "no other
812
+ // handler claimed it", like the Delete-key handler below) so the shortcut
813
+ // can't fire from an unrelated toolbar button, dialog, or menu.
814
+ const copiedSlideIdRef = useRef<string | null>(null);
815
+ useEffect(() => {
816
+ const handleKeyDown = (e: KeyboardEvent) => {
817
+ if (!deck || !id) return;
818
+ if (!(e.metaKey || e.ctrlKey) || e.altKey) return;
819
+ const key = e.key.toLowerCase();
820
+ if (key !== "c" && key !== "v") return;
821
+ if (pinMode || drawMode) return;
822
+ if (
823
+ document.querySelector(
824
+ "[role='dialog'], [role='menu'], [role='listbox']",
825
+ )
826
+ ) {
827
+ return;
828
+ }
829
+ if (!canEdit) return;
830
+ const focusedThumbnail = document.activeElement?.closest(
831
+ "[data-slide-thumbnail-id]",
832
+ );
833
+ if (!focusedThumbnail) return;
834
+ const focusedSlideId = focusedThumbnail.getAttribute(
835
+ "data-slide-thumbnail-id",
836
+ );
837
+ if (!focusedSlideId) return;
838
+
839
+ if (key === "c") {
840
+ copiedSlideIdRef.current = focusedSlideId;
841
+ return;
842
+ }
843
+ const copiedSlideId = copiedSlideIdRef.current;
844
+ if (!copiedSlideId) return;
845
+ if (!deck.slides.some((s) => s.id === copiedSlideId)) return;
846
+ e.preventDefault();
847
+ const newSlideId = duplicateSlide(id, copiedSlideId);
848
+ if (newSlideId) setActiveSlideId(newSlideId);
849
+ };
850
+ document.addEventListener("keydown", handleKeyDown);
851
+ return () => document.removeEventListener("keydown", handleKeyDown);
852
+ }, [deck, id, duplicateSlide, canEdit, pinMode, drawMode]);
853
+
810
854
  // Resolve the active slide from URL/deck state. Imports replace slide IDs, so
811
855
  // keep this valid after deck contents change instead of only on first load.
812
856
  // Track the last URL ?slide param we processed so we can tell "the URL changed
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-12
4
+ ---
5
+
6
+ Arrow-key navigation in the slide film strip now scrolls slides below the fold into view
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-08-12
4
+ ---
5
+
6
+ Duplicate a slide from the film strip with Cmd/Ctrl+C then Cmd/Ctrl+V
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-12
4
+ ---
5
+
6
+ Presenting a deck now returns you to the slide you were viewing when you exit
package/dist/action.d.ts CHANGED
@@ -398,6 +398,15 @@ interface DefineActionWithSchema<TSchema extends StandardSchemaV1, TReturn = any
398
398
  * Only set this manually when you need to override the inference — e.g. a
399
399
  * POST action that only reads data but can't use GET for a protocol reason. */
400
400
  readOnly?: boolean;
401
+ /** Declares that a successful call returns real evidence retrieved from a data
402
+ * source at call time — a provider API, a warehouse, a connected repo, or the
403
+ * app's own event/observability store. Apps that police fabricated answers
404
+ * (see the Analytics final-response guard) read this instead of keeping a
405
+ * hand-maintained list of action names, which drifts the moment a new source
406
+ * action ships. Orthogonal to `readOnly`: a write that probes a live endpoint
407
+ * and returns the outcome is still grounding. Metadata-only reads (schema,
408
+ * catalogs, saved config) are not. */
409
+ grounding?: boolean;
401
410
  /** Set false for read-only tools that should stay available in Act mode but
402
411
  * must not run during Plan mode because they perform substantive work
403
412
  * rather than lightweight inspection. Defaults to allowed when read-only. */
@@ -538,6 +547,9 @@ interface DefineActionWithParams<TParams extends Record<string, ParameterSchema>
538
547
  /** If true, the framework will NOT emit a screen-refresh change event after a
539
548
  * successful call. Auto-inferred as `true` when `http.method === "GET"`. */
540
549
  readOnly?: boolean;
550
+ /** Declares that a successful call returns real evidence retrieved from a data
551
+ * source at call time. See the schema overload above. */
552
+ grounding?: boolean;
541
553
  /** Set false for read-only tools that should stay available in Act mode but
542
554
  * must not run during Plan mode. See the schema overload above. */
543
555
  allowInPlanMode?: boolean;
@@ -602,6 +614,7 @@ export interface ActionDefinition<TInput, TReturn> {
602
614
  readonly maxBodyBytes?: number;
603
615
  readonly agentTool?: boolean;
604
616
  readonly readOnly?: boolean;
617
+ readonly grounding?: boolean;
605
618
  readonly allowInPlanMode?: boolean;
606
619
  readonly planMode?: ActionPlanModeConfig<TInput>;
607
620
  readonly parallelSafe?: boolean;
package/dist/action.js CHANGED
@@ -164,6 +164,9 @@ export function defineAction(options) {
164
164
  : {}),
165
165
  ...(typeof agentTool === "boolean" ? { agentTool } : {}),
166
166
  ...(typeof readOnly === "boolean" ? { readOnly } : {}),
167
+ ...(typeof options.grounding === "boolean"
168
+ ? { grounding: options.grounding }
169
+ : {}),
167
170
  ...(typeof options.allowInPlanMode === "boolean"
168
171
  ? { allowInPlanMode: options.allowInPlanMode }
169
172
  : {}),
@@ -12,9 +12,33 @@ export interface PriorTurnToolCallSummary {
12
12
  * `PriorTurnToolCallSummary` for why this is a local shape, not an import. */
13
13
  export interface PriorTurnToolResultSummary {
14
14
  name: string;
15
+ /**
16
+ * Input of the `tool_start` this result was matched to, so the caller can
17
+ * rebuild the same `(tool, arguments)` breaker key its live counters use.
18
+ * Legacy `tool_done` events carry no input; those keep the positional
19
+ * FIFO-per-tool pairing documented in `tool-call-journal.ts`, so this is
20
+ * absent only when neither event carried one.
21
+ */
22
+ input?: unknown;
15
23
  content: string;
16
24
  isError: boolean;
17
25
  }
26
+ /**
27
+ * Outcome of reading the per-turn ledger. `unreadable` is deliberately NOT the
28
+ * same value as a turn with no history: the repetition ledger, the read-only
29
+ * result cache and the write-replay hard block are all seeded from this read,
30
+ * so a swallowed ledger failure silently restores the per-chunk ceilings those
31
+ * mechanisms exist to remove.
32
+ */
33
+ export type PriorTurnToolCallJournalRead = {
34
+ status: "read";
35
+ toolCallJournal: ToolCallJournal | null;
36
+ priorToolCalls: PriorTurnToolCallSummary[];
37
+ priorToolResults: PriorTurnToolResultSummary[];
38
+ } | {
39
+ status: "unreadable";
40
+ error: string;
41
+ };
18
42
  /**
19
43
  * Tool-call journal hard-block (resume safety). Snapshot the per-turn journal
20
44
  * ONCE here, before any tool runs in this chunk, so it reflects only PRIOR
@@ -25,9 +49,8 @@ export interface PriorTurnToolResultSummary {
25
49
  *
26
50
  * Loaded eagerly (not lazily mid-loop) so the current chunk's own
27
51
  * asynchronously-persisted tool_done events can never leak in and make a
28
- * same-chunk call wrongly short-circuit. Best-effort: any ledger failure
29
- * leaves the journal empty and all calls run normally. Fresh first-turn calls
30
- * see an empty journal and are unaffected.
52
+ * same-chunk call wrongly short-circuit. Fresh first-turn calls see an empty
53
+ * journal and are unaffected.
31
54
  *
32
55
  * Also returns the prior chunks' tool calls/results so the caller can seed
33
56
  * its own `toolCallHistory` / `toolResultHistory` accumulators — final
@@ -35,11 +58,5 @@ export interface PriorTurnToolResultSummary {
35
58
  * tools executed after the latest handoff. Otherwise a guard can reject a
36
59
  * grounded answer (or a successfully-created artifact) after the
37
60
  * evidence-producing query completed in a predecessor run.
38
- *
39
- * Moved verbatim out of `runAgentLoop`'s per-turn setup — behavior unchanged.
40
61
  */
41
- export declare function loadPriorTurnToolCallJournal(threadId: string | undefined, turnId?: string): Promise<{
42
- toolCallJournal: ToolCallJournal | null;
43
- priorToolCalls: PriorTurnToolCallSummary[];
44
- priorToolResults: PriorTurnToolResultSummary[];
45
- }>;
62
+ export declare function loadPriorTurnToolCallJournal(threadId: string | undefined, turnId?: string): Promise<PriorTurnToolCallJournalRead>;
@@ -10,9 +10,8 @@ import { classifyToolCallJournal, } from "../tool-call-journal.js";
10
10
  *
11
11
  * Loaded eagerly (not lazily mid-loop) so the current chunk's own
12
12
  * asynchronously-persisted tool_done events can never leak in and make a
13
- * same-chunk call wrongly short-circuit. Best-effort: any ledger failure
14
- * leaves the journal empty and all calls run normally. Fresh first-turn calls
15
- * see an empty journal and are unaffected.
13
+ * same-chunk call wrongly short-circuit. Fresh first-turn calls see an empty
14
+ * journal and are unaffected.
16
15
  *
17
16
  * Also returns the prior chunks' tool calls/results so the caller can seed
18
17
  * its own `toolCallHistory` / `toolResultHistory` accumulators — final
@@ -20,40 +19,55 @@ import { classifyToolCallJournal, } from "../tool-call-journal.js";
20
19
  * tools executed after the latest handoff. Otherwise a guard can reject a
21
20
  * grounded answer (or a successfully-created artifact) after the
22
21
  * evidence-producing query completed in a predecessor run.
23
- *
24
- * Moved verbatim out of `runAgentLoop`'s per-turn setup — behavior unchanged.
25
22
  */
26
23
  export async function loadPriorTurnToolCallJournal(threadId, turnId) {
27
- const priorToolCalls = [];
28
- const priorToolResults = [];
29
- let toolCallJournal = null;
30
24
  if (!threadId) {
31
- return { toolCallJournal, priorToolCalls, priorToolResults };
25
+ // No thread means no durable ledger exists for this turn at all — a true
26
+ // "no prior history", not a read that failed.
27
+ return {
28
+ status: "read",
29
+ toolCallJournal: null,
30
+ priorToolCalls: [],
31
+ priorToolResults: [],
32
+ };
32
33
  }
34
+ let priorEvents;
33
35
  try {
34
- const priorEvents = await getCurrentTurnEventsForThread(threadId, turnId);
35
- if (priorEvents.length > 0) {
36
- for (const event of priorEvents) {
37
- if (event.type === "tool_start") {
38
- priorToolCalls.push({
39
- name: event.tool,
40
- input: event.input,
41
- });
42
- }
43
- else if (event.type === "tool_done") {
44
- priorToolResults.push({
45
- name: event.tool,
46
- content: event.result,
47
- isError: event.isError === true,
48
- });
49
- }
50
- }
51
- toolCallJournal = classifyToolCallJournal(priorEvents);
52
- }
36
+ priorEvents = await getCurrentTurnEventsForThread(threadId, turnId);
37
+ }
38
+ catch (err) {
39
+ const error = err instanceof Error ? err.message : String(err);
40
+ console.warn(`[tool-call-journal] per-turn ledger read failed for thread ${threadId}: ${error}`);
41
+ return { status: "unreadable", error };
53
42
  }
54
- catch {
55
- // Journal is a hardening layer, never a gate — a failed ledger read just
56
- // means no hard-block this turn.
43
+ const priorToolCalls = [];
44
+ const priorToolResults = [];
45
+ // Open `tool_start` inputs per tool, so a legacy `tool_done` with no input of
46
+ // its own can still be attributed to the arguments it ran with.
47
+ const openInputsByTool = new Map();
48
+ for (const event of priorEvents) {
49
+ if (event.type === "tool_start") {
50
+ priorToolCalls.push({ name: event.tool, input: event.input });
51
+ const queue = openInputsByTool.get(event.tool);
52
+ if (queue)
53
+ queue.push(event.input);
54
+ else
55
+ openInputsByTool.set(event.tool, [event.input]);
56
+ }
57
+ else if (event.type === "tool_done") {
58
+ const fifoInput = openInputsByTool.get(event.tool)?.shift();
59
+ priorToolResults.push({
60
+ name: event.tool,
61
+ input: event.input ?? fifoInput,
62
+ content: event.result,
63
+ isError: event.isError === true,
64
+ });
65
+ }
57
66
  }
58
- return { toolCallJournal, priorToolCalls, priorToolResults };
67
+ return {
68
+ status: "read",
69
+ toolCallJournal: priorEvents.length > 0 ? classifyToolCallJournal(priorEvents) : null,
70
+ priorToolCalls,
71
+ priorToolResults,
72
+ };
59
73
  }
@@ -183,6 +183,8 @@ export interface ActionEntry {
183
183
  /** If true, completion does NOT trigger a screen-refresh change event.
184
184
  * Set automatically by `defineAction` when `http.method === "GET"`. */
185
185
  readOnly?: boolean;
186
+ /** If true, a successful call returns evidence retrieved from a live source. */
187
+ grounding?: boolean;
186
188
  /** False keeps a read-only tool available in Act mode but hides/blocks it in
187
189
  * Plan mode. Use for tools that perform substantive work even without
188
190
  * mutating state. */
@@ -613,6 +615,21 @@ export declare const MAX_SAME_ERROR_ACROSS_ARGUMENTS = 6;
613
615
  * legitimate re-check after a write.
614
616
  */
615
617
  export declare const MAX_IDENTICAL_TOOL_CALLS = 8;
618
+ /**
619
+ * A stop that ends the turn from inside the tool loop.
620
+ *
621
+ * `message` is the last thing the user reads, so it must name the remedy and
622
+ * must NOT quote a raw provider/tool error: both `isAutoRecoverableError`
623
+ * (client) and `isRecoverableContinuationError` (below) sniff this string for
624
+ * "timeout"/"connection"/"network", and a stop whose text happens to contain
625
+ * one is auto-continued into the very spiral it was raised to end. The raw
626
+ * error belongs in `details`, which nothing retries on.
627
+ */
628
+ export interface TerminalActionStop {
629
+ message: string;
630
+ errorCode?: string;
631
+ details?: string;
632
+ }
616
633
  /**
617
634
  * Convert ActionEntry registry to EngineTool array.
618
635
  */
@@ -687,6 +704,22 @@ export declare function findApprovedStructuredToolCall(history: AgentChatStructu
687
704
  input: unknown;
688
705
  callId: string;
689
706
  } | undefined;
707
+ /**
708
+ * Tool errors the model has no way to clear: the missing thing lives outside
709
+ * the turn (a credential, a role grant, a connected account, a runtime, the
710
+ * user's own approval). Every retry costs a full round-trip carrying the whole
711
+ * transcript and lands on the identical error, so these stop on the FIRST
712
+ * occurrence rather than after `MAX_SAME_ERROR_ACROSS_ARGUMENTS` of them.
713
+ *
714
+ * The distinction is the one `stopForBigQueryNotConfigured` draws in
715
+ * templates/analytics: a *configuration* gap is permanent for this turn, a
716
+ * *query* failure is not. Anything the model can act on — a stale read to
717
+ * rebase, a bad argument, a full quota it can free, a wrong dataset name, a
718
+ * statement timeout — must stay out of this list and keep its retries.
719
+ * Precision over recall: a wrong match kills a turn that would have succeeded,
720
+ * which is worse than one more retry.
721
+ */
722
+ export declare function permanentPreconditionRemedy(message: string): string | null;
690
723
  export declare function repeatedSourceSweepGuardMessage(opts: {
691
724
  toolName: string;
692
725
  priorCalls: number;