@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.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/AGENTS.md +4 -0
- package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
- package/corpus/templates/analytics/actions/bigquery-query.ts +1 -0
- package/corpus/templates/analytics/actions/bigquery.ts +1 -0
- package/corpus/templates/analytics/actions/content-calendar-schema.ts +1 -0
- package/corpus/templates/analytics/actions/content-calendar.ts +1 -0
- package/corpus/templates/analytics/actions/gcloud.ts +1 -0
- package/corpus/templates/analytics/actions/get-data-program.ts +1 -0
- package/corpus/templates/analytics/actions/get-error-issue.ts +1 -0
- package/corpus/templates/analytics/actions/get-monitor-stats.ts +1 -0
- package/corpus/templates/analytics/actions/get-monitor.ts +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-events.ts +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-summary.ts +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-timeline.ts +1 -0
- package/corpus/templates/analytics/actions/gong-calls.ts +1 -0
- package/corpus/templates/analytics/actions/gong-native-insights.ts +1 -0
- package/corpus/templates/analytics/actions/grafana.ts +1 -0
- package/corpus/templates/analytics/actions/hubspot-deals.ts +1 -0
- package/corpus/templates/analytics/actions/hubspot-metrics.ts +1 -0
- package/corpus/templates/analytics/actions/hubspot-pipelines.ts +1 -0
- package/corpus/templates/analytics/actions/hubspot-records.ts +1 -0
- package/corpus/templates/analytics/actions/jira-search.ts +1 -0
- package/corpus/templates/analytics/actions/jira.ts +1 -0
- package/corpus/templates/analytics/actions/list-error-issues.ts +1 -0
- package/corpus/templates/analytics/actions/list-monitors.ts +1 -0
- package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -0
- package/corpus/templates/analytics/actions/match-error-issues.ts +1 -0
- package/corpus/templates/analytics/actions/prometheus.ts +1 -0
- package/corpus/templates/analytics/actions/pylon-issues.ts +1 -0
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -0
- package/corpus/templates/analytics/actions/query-dashboard-panel.ts +1 -0
- package/corpus/templates/analytics/actions/query-inbound-forms.ts +1 -0
- package/corpus/templates/analytics/actions/run-monitor-check.ts +1 -0
- package/corpus/templates/analytics/actions/sentry.ts +1 -0
- package/corpus/templates/analytics/actions/seo-blog-pages.ts +1 -0
- package/corpus/templates/analytics/actions/seo-page-keywords.ts +1 -0
- package/corpus/templates/analytics/actions/seo-top-keywords.ts +1 -0
- package/corpus/templates/analytics/actions/slack-messages.ts +1 -0
- package/corpus/templates/analytics/actions/stripe.ts +1 -0
- package/corpus/templates/analytics/actions/test-custom-api-connection.ts +1 -0
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +38 -47
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +41 -34
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +9 -6
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_clip.rs +70 -10
- package/corpus/templates/forms/AGENTS.md +6 -0
- package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/mail/AGENTS.md +5 -4
- package/corpus/templates/mail/actions/get-automation-settings.ts +17 -6
- package/corpus/templates/mail/actions/send-email.ts +17 -9
- package/corpus/templates/mail/actions/send-queued-drafts.ts +21 -11
- package/corpus/templates/mail/actions/update-automation-settings.ts +20 -6
- package/corpus/templates/mail/app/i18n/en-US.ts +5 -0
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +68 -7
- package/corpus/templates/mail/server/lib/automation-settings.ts +27 -0
- package/corpus/templates/mail/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +3 -3
- package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +17 -4
- package/corpus/templates/slides/app/context/DeckContext.tsx +3 -2
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +44 -0
- package/corpus/templates/slides/changelog/2026-08-12-arrow-key-navigation-in-the-slide-film-strip-now-scrolls-sli.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-12-duplicate-a-slide-from-the-film-strip-with-cmd-ctrl-c-then-c.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-12-presenting-a-deck-now-returns-you-to-the-slide-you-were-view.md +6 -0
- package/dist/action.d.ts +13 -0
- package/dist/action.js +3 -0
- package/dist/agent/engine/tool-call-journal-seed.d.ts +27 -10
- package/dist/agent/engine/tool-call-journal-seed.js +46 -32
- package/dist/agent/production-agent.d.ts +33 -0
- package/dist/agent/production-agent.js +172 -57
- package/dist/agent/run-loop-with-resume.d.ts +1 -1
- package/dist/agent/run-loop-with-resume.js +49 -35
- package/dist/client/agent-chat-adapter.js +204 -273
- package/dist/client/resources/mcp-integration-catalog.d.ts +7 -0
- package/dist/client/resources/mcp-integration-catalog.js +14 -1
- package/dist/client/settings/AgentsSection.js +46 -30
- package/dist/client/sse-event-processor.d.ts +7 -0
- package/dist/client/sse-event-processor.js +21 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/github-repo-files.js +1 -0
- package/dist/provider-api/actions/provider-api.js +1 -0
- package/dist/provider-api/actions/staged-datasets.js +1 -0
- package/dist/provider-api/corpus-jobs.js +1 -0
- package/dist/server/action-discovery.js +2 -0
- package/dist/server/agent-chat-plugin.js +1 -0
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- 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 (
|
|
469
|
-
const token =
|
|
479
|
+
if (isSharedRef.current) {
|
|
480
|
+
const token = deckIdRef.current.replace("__shared__/", "");
|
|
470
481
|
navigate(`/share/${token}`);
|
|
471
482
|
} else {
|
|
472
|
-
navigate(
|
|
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) =>
|
|
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
|
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.
|
|
29
|
-
*
|
|
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.
|
|
14
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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 {
|
|
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;
|