@agent-native/core 0.155.0 → 0.157.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/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
- package/corpus/templates/assets/app/i18n-data.ts +21 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +17 -13
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +102 -59
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +15 -1
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +16 -2
- package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
- package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +42 -2
- package/corpus/templates/slides/app/global.css +7 -40
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +130 -45
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/production-agent.d.ts +30 -0
- package/dist/agent/production-agent.js +100 -8
- package/dist/agent/types.d.ts +9 -0
- package/dist/client/AgentPanel.js +12 -9
- package/dist/client/AssistantChat.d.ts +15 -1
- package/dist/client/AssistantChat.js +110 -43
- package/dist/client/MultiTabAssistantChat.js +44 -27
- package/dist/client/chat/markdown-renderer.js +4 -2
- package/dist/client/chat/message-components.d.ts +2 -2
- package/dist/client/chat/message-components.js +69 -35
- package/dist/client/chat/run-recovery.d.ts +4 -1
- package/dist/client/chat/run-recovery.js +62 -30
- package/dist/client/chat/tool-call-display.d.ts +12 -3
- package/dist/client/chat/tool-call-display.js +79 -40
- package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
- package/dist/client/chat/widgets/DataChartWidget.js +8 -2
- package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
- package/dist/client/chat/widgets/DataTableWidget.js +23 -9
- package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
- package/dist/client/components/ui/message-scroller.d.ts +1 -1
- package/dist/client/components/ui/message-scroller.js +7 -3
- package/dist/client/composer/runtime-adapters.js +3 -2
- package/dist/client/context-xray/ContextMeter.js +5 -1
- package/dist/client/context-xray/ContextXRayPanel.js +5 -5
- package/dist/client/error-format.d.ts +4 -0
- package/dist/client/error-format.js +93 -5
- package/dist/client/i18n.js +83 -17
- package/dist/client/observability/ThumbsFeedback.js +10 -8
- package/dist/client/sharing/ShareButton.js +160 -54
- package/dist/coding-tools/run-code.js +2 -1
- package/dist/coding-tools/sandbox/background.d.ts +1 -0
- package/dist/coding-tools/sandbox/background.js +8 -1
- package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
- package/dist/coding-tools/sandbox/executions-store.js +41 -3
- package/dist/collab/routes.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/localization/core-messages/ar-SA.d.ts +3 -0
- package/dist/localization/core-messages/ar-SA.js +541 -0
- package/dist/localization/core-messages/de-DE.d.ts +3 -0
- package/dist/localization/core-messages/de-DE.js +513 -0
- package/dist/localization/core-messages/en-US.d.ts +513 -0
- package/dist/localization/core-messages/en-US.js +513 -0
- package/dist/localization/core-messages/es-ES.d.ts +3 -0
- package/dist/localization/core-messages/es-ES.js +520 -0
- package/dist/localization/core-messages/fr-FR.d.ts +3 -0
- package/dist/localization/core-messages/fr-FR.js +520 -0
- package/dist/localization/core-messages/hi-IN.d.ts +3 -0
- package/dist/localization/core-messages/hi-IN.js +513 -0
- package/dist/localization/core-messages/ja-JP.d.ts +3 -0
- package/dist/localization/core-messages/ja-JP.js +506 -0
- package/dist/localization/core-messages/ko-KR.d.ts +3 -0
- package/dist/localization/core-messages/ko-KR.js +506 -0
- package/dist/localization/core-messages/pt-BR.d.ts +3 -0
- package/dist/localization/core-messages/pt-BR.js +520 -0
- package/dist/localization/core-messages/zh-CN.d.ts +3 -0
- package/dist/localization/core-messages/zh-CN.js +506 -0
- package/dist/localization/core-messages/zh-TW.d.ts +3 -0
- package/dist/localization/core-messages/zh-TW.js +506 -0
- package/dist/localization/core-messages.d.ts +524 -0
- package/dist/localization/core-messages.js +124 -0
- package/dist/localization/default-messages.d.ts +2 -0
- package/dist/localization/default-messages.js +2 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/plugin-options.d.ts +7 -2
- package/dist/server/agent-chat-plugin.d.ts +10 -0
- package/dist/server/agent-chat-plugin.js +144 -41
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-run-context.d.ts +7 -1
- package/dist/server/agent-run-context.js +9 -2
- package/dist/server/agent-teams-run-queue.d.ts +3 -0
- package/dist/server/agent-teams.js +38 -9
- package/dist/server/index.d.ts +1 -1
- package/dist/server/request-context.d.ts +7 -0
- package/dist/server/request-context.js +15 -0
- package/docs/content/agent-surfaces.mdx +30 -0
- package/package.json +2 -2
|
@@ -223,7 +223,9 @@ interface DeckContextType {
|
|
|
223
223
|
deckId: string,
|
|
224
224
|
layout?: SlideLayout,
|
|
225
225
|
afterIndex?: number,
|
|
226
|
+
options?: { persistence?: "debounced" | "immediate" },
|
|
226
227
|
) => string;
|
|
228
|
+
flushDeckSave: (deckId: string) => Promise<void>;
|
|
227
229
|
updateSlide: (
|
|
228
230
|
deckId: string,
|
|
229
231
|
slideId: string,
|
|
@@ -499,6 +501,38 @@ function drainPendingDeckOps(deckId: string): Promise<void> {
|
|
|
499
501
|
return next;
|
|
500
502
|
}
|
|
501
503
|
|
|
504
|
+
/**
|
|
505
|
+
* Wait for a deck's in-flight save(s) to fully settle, including any
|
|
506
|
+
* follow-up drain chained by immediateFlushRequests for ops queued while a
|
|
507
|
+
* save was already running, and any requeued retry after a failed attempt.
|
|
508
|
+
* Used when a caller must not proceed (e.g. firing an agent request against
|
|
509
|
+
* a slide) until an "immediate" persistence op has actually reached the
|
|
510
|
+
* server. Throws if the save ultimately fails after retries exhaust, since
|
|
511
|
+
* `drainPendingDeckOps` swallows save errors internally to drive its own
|
|
512
|
+
* retry loop and its promise always resolves regardless of outcome.
|
|
513
|
+
*/
|
|
514
|
+
async function flushDeckSave(deckId: string): Promise<void> {
|
|
515
|
+
for (let i = 0; i < 40; i++) {
|
|
516
|
+
const active = inFlightSaveChains.get(deckId);
|
|
517
|
+
if (active) {
|
|
518
|
+
await active;
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
if (failedSaveDecks.has(deckId)) {
|
|
522
|
+
throw new Error(
|
|
523
|
+
`Failed to save deck ${deckId} after ${MAX_DECK_SAVE_RETRIES} attempts`,
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
if (pendingOpsQueue.has(deckId) || pendingSaves.has(deckId)) {
|
|
527
|
+
// A failed op was requeued for retry, or a debounced save is armed;
|
|
528
|
+
// wait for it to actually run rather than declaring success early.
|
|
529
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
502
536
|
function enqueueDeckOp(
|
|
503
537
|
deckId: string,
|
|
504
538
|
op: GranularOp,
|
|
@@ -2095,7 +2129,12 @@ export function DeckProvider({ children }: { children: ReactNode }) {
|
|
|
2095
2129
|
);
|
|
2096
2130
|
|
|
2097
2131
|
const addSlide = useCallback(
|
|
2098
|
-
(
|
|
2132
|
+
(
|
|
2133
|
+
deckId: string,
|
|
2134
|
+
layout: SlideLayout = "content",
|
|
2135
|
+
afterIndex?: number,
|
|
2136
|
+
addOptions?: { persistence?: "debounced" | "immediate" },
|
|
2137
|
+
) => {
|
|
2099
2138
|
markDeckDirty(deckId);
|
|
2100
2139
|
const newSlide: Slide = {
|
|
2101
2140
|
id: nanoid(8),
|
|
@@ -2128,7 +2167,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
|
|
|
2128
2167
|
afterSlideId,
|
|
2129
2168
|
fields: addSlideFields(newSlide),
|
|
2130
2169
|
};
|
|
2131
|
-
enqueueDeckOp(deckId, op);
|
|
2170
|
+
enqueueDeckOp(deckId, op, addOptions);
|
|
2132
2171
|
if (before) recordUndo(before, op, { label: "Add slide" });
|
|
2133
2172
|
|
|
2134
2173
|
return newSlide.id;
|
|
@@ -2329,6 +2368,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
|
|
|
2329
2368
|
refreshOpenDeck: refetchOpenDeckIfChanged,
|
|
2330
2369
|
getDeck,
|
|
2331
2370
|
addSlide,
|
|
2371
|
+
flushDeckSave,
|
|
2332
2372
|
updateSlide,
|
|
2333
2373
|
deleteSlide,
|
|
2334
2374
|
duplicateSlide,
|
|
@@ -290,53 +290,20 @@ button[title="Open agent sidebar"] {
|
|
|
290
290
|
|
|
291
291
|
.deck-editor-context-toolbar-host--narrow {
|
|
292
292
|
display: flex;
|
|
293
|
-
justify-content: flex-
|
|
293
|
+
justify-content: flex-start;
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
.deck-editor-context-toolbar-host--narrow
|
|
297
297
|
> [data-slide-inline-edit-surface="true"] {
|
|
298
298
|
min-width: 0;
|
|
299
|
-
width:
|
|
300
|
-
|
|
301
|
-
flex: 0 1 auto;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
@container deck-editor (max-width: 1149px) {
|
|
305
|
-
.deck-editor-context-toolbar-host--wide {
|
|
306
|
-
display: none;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
.deck-editor-context-toolbar-host--narrow {
|
|
310
|
-
display: flex;
|
|
311
|
-
}
|
|
299
|
+
width: 100%;
|
|
300
|
+
flex: 1 1 auto;
|
|
312
301
|
}
|
|
313
302
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
.deck-editor-context-toolbar-host--wide[data-context-toolbar-visible="true"] {
|
|
320
|
-
display: flex;
|
|
321
|
-
flex: 1 1 0%;
|
|
322
|
-
align-items: center;
|
|
323
|
-
justify-content: flex-end;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
.deck-editor-context-toolbar-host--wide
|
|
327
|
-
> [data-slide-inline-edit-surface="true"] {
|
|
328
|
-
min-width: 0;
|
|
329
|
-
max-width: 100%;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
.deck-editor-context-toolbar-host--wide .slide-context-toolbar--top-row {
|
|
333
|
-
height: 2.75rem;
|
|
334
|
-
justify-content: flex-end;
|
|
335
|
-
border: 0;
|
|
336
|
-
background: transparent;
|
|
337
|
-
padding-inline: 0;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
303
|
+
/* The element-controls toolbar (New Slide, text/style controls, zoom)
|
|
304
|
+
* always renders as its own row below the title/Share/Present bar, at every
|
|
305
|
+
* viewport size — the "wide" host above stays permanently hidden by the
|
|
306
|
+
* base rule so the row never merges into the title bar on large screens. */
|
|
340
307
|
|
|
341
308
|
@container (max-width: 36rem) {
|
|
342
309
|
.deck-grid {
|
|
@@ -514,11 +514,15 @@ const messages = {
|
|
|
514
514
|
generatingSlide: "Generating slide",
|
|
515
515
|
uploadFailed: "Upload failed",
|
|
516
516
|
uploadAttachedFileFailed: "Could not upload the attached file.",
|
|
517
|
+
newSlideSaveFailed: "Couldn't save the new slide. Please try again.",
|
|
517
518
|
addSlides: "Add slides",
|
|
518
519
|
addEmptySlide: "Add empty slide",
|
|
519
520
|
noAi: "no AI",
|
|
520
521
|
duplicateCurrentSlide: "Duplicate current slide",
|
|
521
522
|
promptPlaceholder: "Describe the slides you want...",
|
|
523
|
+
newSlide: "New slide",
|
|
524
|
+
closeAddSlides: "Close",
|
|
525
|
+
describeThisSlide: "Describe this slide",
|
|
522
526
|
},
|
|
523
527
|
presentation: {
|
|
524
528
|
loadFailed: "Could not load this presentation.",
|
|
@@ -182,6 +182,7 @@ export default function DeckEditor() {
|
|
|
182
182
|
duplicateSlide,
|
|
183
183
|
duplicateDeck,
|
|
184
184
|
addSlide,
|
|
185
|
+
flushDeckSave,
|
|
185
186
|
reorderSlides,
|
|
186
187
|
markDeckDirty,
|
|
187
188
|
undo,
|
|
@@ -218,6 +219,25 @@ export default function DeckEditor() {
|
|
|
218
219
|
pendingDeckNavigationBlocker.proceed();
|
|
219
220
|
}, [pendingDeckNavigationBlocker]);
|
|
220
221
|
const { generating } = useAgentGenerating();
|
|
222
|
+
// Dedicated instance (not the `generating` one above, which reflects ANY
|
|
223
|
+
// agent chat activity) so an unrelated concurrent run can't be mistaken
|
|
224
|
+
// for this one finishing and clear the flag early. Owning the submit call
|
|
225
|
+
// here — instead of in EditorSidebar, which unmounts when the rail closes
|
|
226
|
+
// on narrow viewports — keeps both the run-scoping and the completion
|
|
227
|
+
// tracking correct across a remount.
|
|
228
|
+
const { generating: addSlideAgentGenerating, submit: addSlideAgentSubmit } =
|
|
229
|
+
useAgentGenerating();
|
|
230
|
+
const sawAddSlideAgentGeneratingRef = useRef(false);
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
if (addSlideAgentGenerating) {
|
|
233
|
+
sawAddSlideAgentGeneratingRef.current = true;
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (addSlideGenerating && sawAddSlideAgentGeneratingRef.current) {
|
|
237
|
+
sawAddSlideAgentGeneratingRef.current = false;
|
|
238
|
+
setAddSlideGenerating(false);
|
|
239
|
+
}
|
|
240
|
+
}, [addSlideGenerating, addSlideAgentGenerating]);
|
|
221
241
|
// Generation intent can arrive after this route mounts because the user
|
|
222
242
|
// answers pre-generation questions from the empty editor.
|
|
223
243
|
const wasNewDeckCreation = useRef(searchParams.get("generating") === "1");
|
|
@@ -231,6 +251,14 @@ export default function DeckEditor() {
|
|
|
231
251
|
const [sidebarOpen, setSidebarOpen] = useState(
|
|
232
252
|
() => typeof window !== "undefined" && window.innerWidth >= 768,
|
|
233
253
|
);
|
|
254
|
+
// The slide just inserted via the toolbar's New Slide button, so the rail
|
|
255
|
+
// can anchor the "describe this slide" popover to its thumbnail once it
|
|
256
|
+
// mounts — even though the button that sets this now lives in the
|
|
257
|
+
// toolbar, outside the rail.
|
|
258
|
+
const [describeSlideId, setDescribeSlideId] = useState<string | null>(null);
|
|
259
|
+
useEffect(() => {
|
|
260
|
+
setDescribeSlideId(null);
|
|
261
|
+
}, [id]);
|
|
234
262
|
const [contextToolbarSlot, setContextToolbarSlot] =
|
|
235
263
|
useState<HTMLDivElement | null>(null);
|
|
236
264
|
const [wideContextToolbarSlot, setWideContextToolbarSlot] =
|
|
@@ -807,49 +835,92 @@ export default function DeckEditor() {
|
|
|
807
835
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
808
836
|
}, [deck, id, activeSlideId, deleteSlideWithUndo, pinMode, drawMode]);
|
|
809
837
|
|
|
810
|
-
//
|
|
811
|
-
//
|
|
812
|
-
//
|
|
813
|
-
//
|
|
838
|
+
// Command/Ctrl+C then Command/Ctrl+V on the slide rail duplicates the
|
|
839
|
+
// selected slide directly below itself. Only claims the shortcut when no
|
|
840
|
+
// slide element is selected — SlideEditor owns Cmd+C/V for object copy/paste
|
|
841
|
+
// in that case.
|
|
814
842
|
const copiedSlideIdRef = useRef<string | null>(null);
|
|
815
843
|
useEffect(() => {
|
|
816
844
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
817
|
-
if (!deck || !id) return;
|
|
845
|
+
if (!deck || !id || !canEdit) return;
|
|
818
846
|
if (!(e.metaKey || e.ctrlKey) || e.altKey) return;
|
|
819
847
|
const key = e.key.toLowerCase();
|
|
820
848
|
if (key !== "c" && key !== "v") return;
|
|
821
849
|
if (pinMode || drawMode) return;
|
|
850
|
+
|
|
851
|
+
// A live browser text selection (e.g. the user triple-clicked rendered,
|
|
852
|
+
// non-editable slide copy) means Cmd/Ctrl+C is a normal text copy —
|
|
853
|
+
// let it through instead of hijacking it into a slide duplicate.
|
|
854
|
+
if (key === "c" && (window.getSelection()?.toString().length ?? 0) > 0) {
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// Radix Popper positions Popover/DropdownMenu/Select/Tooltip content
|
|
859
|
+
// inside the same [data-radix-popper-content-wrapper]. A tooltip opens
|
|
860
|
+
// on plain hover, so treating every such wrapper as blocking would
|
|
861
|
+
// disable this shortcut just by mousing over a toolbar button; only
|
|
862
|
+
// wrappers that aren't tooltips (marked with data-agent-native-tooltip)
|
|
863
|
+
// should count as an open menu/popover/dialog owning the keystroke.
|
|
864
|
+
const isBlockingPopperWrapper = (el: Element) =>
|
|
865
|
+
el.matches("[data-radix-popper-content-wrapper]") &&
|
|
866
|
+
!el.querySelector("[data-agent-native-tooltip]");
|
|
867
|
+
const isInsideSafeZone = (el: Element | null) => {
|
|
868
|
+
if (!el) return false;
|
|
869
|
+
if (el instanceof HTMLInputElement) return true;
|
|
870
|
+
if (el instanceof HTMLTextAreaElement) return true;
|
|
871
|
+
if (el instanceof HTMLElement) {
|
|
872
|
+
if (el.isContentEditable) return true;
|
|
873
|
+
if (el.closest("[contenteditable='true']")) return true;
|
|
874
|
+
if (el.closest("input, textarea, [role='textbox']")) return true;
|
|
875
|
+
if (el.closest("[data-pin-popover]")) return true;
|
|
876
|
+
if (el.closest("[data-add-slide-popover]")) return true;
|
|
877
|
+
if (el.closest(".agent-panel-root")) return true;
|
|
878
|
+
if (el.closest("[role='dialog'], [role='alertdialog']")) return true;
|
|
879
|
+
const popperWrapper = el.closest(
|
|
880
|
+
"[data-radix-popper-content-wrapper]",
|
|
881
|
+
);
|
|
882
|
+
if (popperWrapper && isBlockingPopperWrapper(popperWrapper))
|
|
883
|
+
return true;
|
|
884
|
+
}
|
|
885
|
+
return false;
|
|
886
|
+
};
|
|
887
|
+
if (isInsideSafeZone(e.target as Element | null)) return;
|
|
888
|
+
if (isInsideSafeZone(document.activeElement)) return;
|
|
889
|
+
if (document.querySelector("[data-pin-popover]")) return;
|
|
890
|
+
if (document.querySelector("[data-add-slide-popover]")) return;
|
|
891
|
+
// A dialog/sheet/menu/popover owning focus elsewhere in the DOM (not
|
|
892
|
+
// just under the event target) still shouldn't let this document-level
|
|
893
|
+
// shortcut duplicate the slide underneath it.
|
|
822
894
|
if (
|
|
823
895
|
document.querySelector(
|
|
824
|
-
"[role='dialog'], [role='menu'], [role='listbox']",
|
|
896
|
+
"[role='dialog'], [role='alertdialog'], [role='menu'], [role='listbox']",
|
|
825
897
|
)
|
|
826
|
-
)
|
|
898
|
+
)
|
|
899
|
+
return;
|
|
900
|
+
if (
|
|
901
|
+
Array.from(
|
|
902
|
+
document.querySelectorAll("[data-radix-popper-content-wrapper]"),
|
|
903
|
+
).some(isBlockingPopperWrapper)
|
|
904
|
+
)
|
|
905
|
+
return;
|
|
906
|
+
if (document.querySelector("[data-slide-element-selected='true']"))
|
|
827
907
|
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
908
|
|
|
839
909
|
if (key === "c") {
|
|
840
|
-
|
|
910
|
+
if (!activeSlideId) return;
|
|
911
|
+
copiedSlideIdRef.current = activeSlideId;
|
|
841
912
|
return;
|
|
842
913
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
if (!deck.slides.some((s) => s.id ===
|
|
914
|
+
|
|
915
|
+
const copiedId = copiedSlideIdRef.current;
|
|
916
|
+
if (!copiedId || !deck.slides.some((s) => s.id === copiedId)) return;
|
|
846
917
|
e.preventDefault();
|
|
847
|
-
const
|
|
848
|
-
if (
|
|
918
|
+
const newId = duplicateSlide(id, copiedId);
|
|
919
|
+
if (newId) setActiveSlideId(newId);
|
|
849
920
|
};
|
|
850
921
|
document.addEventListener("keydown", handleKeyDown);
|
|
851
922
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
852
|
-
}, [deck, id,
|
|
923
|
+
}, [deck, id, canEdit, activeSlideId, duplicateSlide, pinMode, drawMode]);
|
|
853
924
|
|
|
854
925
|
// Resolve the active slide from URL/deck state. Imports replace slide IDs, so
|
|
855
926
|
// keep this valid after deck contents change instead of only on first load.
|
|
@@ -1083,9 +1154,30 @@ export default function DeckEditor() {
|
|
|
1083
1154
|
|
|
1084
1155
|
const handleAddEmptySlide = () => {
|
|
1085
1156
|
const activeIdx = deck.slides.findIndex((s) => s.id === activeSlideId);
|
|
1086
|
-
|
|
1087
|
-
|
|
1157
|
+
// Immediate persistence: this placeholder is immediately followed by an
|
|
1158
|
+
// agent request to `update-slide` it, which can reach the server before
|
|
1159
|
+
// the default 500ms debounce would have flushed the `add-slide` op.
|
|
1160
|
+
const newId = addSlide(
|
|
1161
|
+
id,
|
|
1162
|
+
"blank",
|
|
1163
|
+
activeIdx >= 0 ? activeIdx : undefined,
|
|
1164
|
+
{
|
|
1165
|
+
persistence: "immediate",
|
|
1166
|
+
},
|
|
1088
1167
|
);
|
|
1168
|
+
setActiveSlideId(newId);
|
|
1169
|
+
return newId;
|
|
1170
|
+
};
|
|
1171
|
+
|
|
1172
|
+
const handleNewSlideClick = () => {
|
|
1173
|
+
const newId = handleAddEmptySlide();
|
|
1174
|
+
if (newId) {
|
|
1175
|
+
// The rail owns the anchor node the describe-slide popover attaches
|
|
1176
|
+
// to, so it must be mounted even if it started closed on a narrow
|
|
1177
|
+
// viewport where the toolbar button is still reachable.
|
|
1178
|
+
setSidebarOpen(true);
|
|
1179
|
+
setDescribeSlideId(newId);
|
|
1180
|
+
}
|
|
1089
1181
|
};
|
|
1090
1182
|
|
|
1091
1183
|
return (
|
|
@@ -1101,7 +1193,6 @@ export default function DeckEditor() {
|
|
|
1101
1193
|
canEdit={canEdit}
|
|
1102
1194
|
canComment={canComment}
|
|
1103
1195
|
onTitleChange={(title) => updateDeck(id, { title })}
|
|
1104
|
-
slideCount={deck.slides.length}
|
|
1105
1196
|
currentSlideIndex={currentIndex >= 0 ? currentIndex : 0}
|
|
1106
1197
|
sidebarOpen={sidebarOpen}
|
|
1107
1198
|
onToggleSidebar={() => setSidebarOpen(!sidebarOpen)}
|
|
@@ -1113,6 +1204,8 @@ export default function DeckEditor() {
|
|
|
1113
1204
|
onShowHistory={() => setHistoryOpen((open) => !open)}
|
|
1114
1205
|
historyButtonRef={historyButtonRef}
|
|
1115
1206
|
currentSlide={currentSlide}
|
|
1207
|
+
onAddEmptySlide={canEdit ? handleNewSlideClick : undefined}
|
|
1208
|
+
addSlideGenerating={addSlideGenerating}
|
|
1116
1209
|
onWideContextToolbarSlotChange={setWideContextToolbarSlot}
|
|
1117
1210
|
activeUsers={slideActiveUsers.filter((u) => u.email !== session?.email)}
|
|
1118
1211
|
agentPresent={agentPresent}
|
|
@@ -1187,13 +1280,6 @@ export default function DeckEditor() {
|
|
|
1187
1280
|
}
|
|
1188
1281
|
return exportDeckToGoogleSlides(deck.title, slides, deck.aspectRatio);
|
|
1189
1282
|
}}
|
|
1190
|
-
currentSlideId={currentSlide?.id}
|
|
1191
|
-
addSlideGenerating={addSlideGenerating}
|
|
1192
|
-
onAddSlideGeneratingChange={setAddSlideGenerating}
|
|
1193
|
-
onAddEmptySlide={handleAddEmptySlide}
|
|
1194
|
-
onDuplicateCurrentSlide={
|
|
1195
|
-
currentSlide ? () => duplicateSlide(id, currentSlide.id) : undefined
|
|
1196
|
-
}
|
|
1197
1283
|
onChangeSlideTransition={
|
|
1198
1284
|
canEdit && currentSlide
|
|
1199
1285
|
? (transition) => updateSlide(id, currentSlide.id, { transition })
|
|
@@ -1226,6 +1312,13 @@ export default function DeckEditor() {
|
|
|
1226
1312
|
slides={deck.slides}
|
|
1227
1313
|
activeSlideId={currentSlide?.id || ""}
|
|
1228
1314
|
deckId={id}
|
|
1315
|
+
deckTitle={deck.title}
|
|
1316
|
+
describeSlideId={describeSlideId}
|
|
1317
|
+
onCloseDescribe={() => setDescribeSlideId(null)}
|
|
1318
|
+
onAwaitAddSlidePersisted={() => flushDeckSave(id)}
|
|
1319
|
+
onRemoveFailedSlide={(slideId) => deleteSlide(id, slideId)}
|
|
1320
|
+
addSlideAgentSubmit={addSlideAgentSubmit}
|
|
1321
|
+
onAddSlideGeneratingChange={setAddSlideGenerating}
|
|
1229
1322
|
onSelectSlide={(slideId) => {
|
|
1230
1323
|
setGeneratingSlideSelected(false);
|
|
1231
1324
|
setActiveSlideId(slideId);
|
|
@@ -1304,19 +1397,11 @@ export default function DeckEditor() {
|
|
|
1304
1397
|
contextToolbarLeading={
|
|
1305
1398
|
canEdit ? (
|
|
1306
1399
|
<EditorActionCluster
|
|
1307
|
-
deckId={id}
|
|
1308
|
-
deckTitle={deck.title}
|
|
1309
|
-
currentSlideId={currentSlide.id}
|
|
1310
|
-
slideCount={deck.slides.length}
|
|
1311
|
-
currentSlideIndex={currentIndex >= 0 ? currentIndex : 0}
|
|
1312
|
-
addSlideGenerating={addSlideGenerating}
|
|
1313
|
-
onAddSlideGeneratingChange={setAddSlideGenerating}
|
|
1314
|
-
onAddEmptySlide={handleAddEmptySlide}
|
|
1315
|
-
onDuplicateCurrentSlide={() =>
|
|
1316
|
-
duplicateSlide(id, currentSlide.id)
|
|
1317
|
-
}
|
|
1318
1400
|
textBoxMode={textBoxMode}
|
|
1319
1401
|
onToggleTextBoxMode={toggleTextBoxMode}
|
|
1402
|
+
onAddEmptySlide={handleNewSlideClick}
|
|
1403
|
+
addSlideGenerating={addSlideGenerating}
|
|
1404
|
+
currentSlideId={currentSlide.id}
|
|
1320
1405
|
slideTransition={currentSlide.transition}
|
|
1321
1406
|
onChangeSlideTransition={(transition) =>
|
|
1322
1407
|
updateSlide(id, currentSlide.id, { transition })
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createProductionAgentHandler, type ActionEntry, type ScriptEntry, type ProductionAgentOptions, type AgentLoopFinalResponseGuard, type AgentLoopFinalResponseGuardContext, type AgentLoopFinalResponseGuardResult, type AgentLoopToolCallSummary, type AgentLoopToolResultSummary, } from "./production-agent.js";
|
|
1
|
+
export { createProductionAgentHandler, type ActionEntry, type ScriptEntry, type ProductionAgentOptions, type AgentActionSurface, type AgentActionSurfaceDetails, type AgentLoopFinalResponseGuard, type AgentLoopFinalResponseGuardContext, type AgentLoopFinalResponseGuardResult, type AgentLoopToolCallSummary, type AgentLoopToolResultSummary, } from "./production-agent.js";
|
|
2
2
|
export { type ActionTool, type ScriptTool, type AgentMessage, type AgentChatRequest, type AgentChatEvent, type AgentChatAttachment, type AgentChatReference, type MentionProvider, type MentionProviderItem, } from "./types.js";
|
|
3
3
|
export { TripWire, type Processor, type ProcessorState, type ProcessorAbort, type ProcessOutputStreamArgs, type ProcessOutputStepArgs, type ProcessOutputResultArgs, } from "./processors.js";
|
|
4
4
|
export { DEFAULT_MODEL } from "./default-model.js";
|
|
@@ -255,6 +255,29 @@ export interface ActionEntry {
|
|
|
255
255
|
/** @deprecated Use `ActionEntry` instead */
|
|
256
256
|
export type ScriptEntry = ActionEntry;
|
|
257
257
|
export type AgentExecutionMode = "act" | "plan";
|
|
258
|
+
export interface AgentActionSurface {
|
|
259
|
+
allowedActionNames: readonly string[];
|
|
260
|
+
}
|
|
261
|
+
export interface AgentActionSurfaceDetails {
|
|
262
|
+
event: any;
|
|
263
|
+
ownerEmail: string | null;
|
|
264
|
+
orgId: string | null;
|
|
265
|
+
threadId?: string;
|
|
266
|
+
mode: AgentExecutionMode;
|
|
267
|
+
internalContinuation: boolean;
|
|
268
|
+
availableActionNames: readonly string[];
|
|
269
|
+
}
|
|
270
|
+
/** Read a persisted allowlist while preserving legacy absence and failing
|
|
271
|
+
* closed when the field is present but malformed. */
|
|
272
|
+
export declare function readPersistedAllowedActionNames(value: unknown): string[] | undefined;
|
|
273
|
+
export interface PersistedActionSurface {
|
|
274
|
+
orgId: string | null;
|
|
275
|
+
allowedActionNames: string[];
|
|
276
|
+
}
|
|
277
|
+
/** Read a nested persisted action surface. An absent envelope is legacy;
|
|
278
|
+
* a present but invalid envelope is an explicit org-less, empty surface. */
|
|
279
|
+
export declare function readPersistedActionSurface(value: unknown, propertyName: string): PersistedActionSurface | undefined;
|
|
280
|
+
export declare function filterActionsByAllowedNames(actions: Record<string, ActionEntry>, allowedActionNames: readonly string[]): Record<string, ActionEntry>;
|
|
258
281
|
export declare const PLAN_MODE_SYSTEM_PROMPT = "## Plan Mode Active\n\nYou are in Plan mode. This turn is for research, clarification, and a proposed approach only.\n\nHard rules:\n- Use only read-only tools. Do not edit files, write resources, run mutating bash commands, mutate SQL rows, navigate the UI, send notifications, create jobs, create tools, send messages or tasks to external agents, or change external systems.\n- If a needed detail is unclear, ask a concise clarifying question before proposing a plan.\n- When ready, present a concrete plan with the files/tools you expect to touch, the intended changes, validation steps, and notable risks.\n- Do not treat approval as implicit while Plan mode is still active. Tell the user to switch to Act mode with the mode selector or /act before implementation.";
|
|
259
282
|
export declare function isPlanModeToolCallAllowed(name: string, input: unknown, entry: ActionEntry): boolean;
|
|
260
283
|
export declare function createPlanModeActionRegistry(actions: Record<string, ActionEntry>): Record<string, ActionEntry>;
|
|
@@ -314,6 +337,13 @@ export interface ProductionAgentOptions {
|
|
|
314
337
|
displayMessage?: string;
|
|
315
338
|
attachments?: AgentChatAttachment[];
|
|
316
339
|
}>;
|
|
340
|
+
/**
|
|
341
|
+
* Resolve the exact action registry exposed to one interactive agent-chat
|
|
342
|
+
* request. Returned names are a hard allowlist: omitted actions are absent
|
|
343
|
+
* from both the provider schemas and the searchable registry. When set, all
|
|
344
|
+
* allowed actions are loaded directly on the first model request.
|
|
345
|
+
*/
|
|
346
|
+
resolveActionSurface?: (details: AgentActionSurfaceDetails) => AgentActionSurface | Promise<AgentActionSurface>;
|
|
317
347
|
/** Optional per-app agent run chunk budget in milliseconds. Defaults to
|
|
318
348
|
* AGENT_RUN_SOFT_TIMEOUT_MS when set, otherwise no framework-imposed
|
|
319
349
|
* timeout. When reached, the client receives an internal auto-continuation
|
|
@@ -16,7 +16,7 @@ import { completeRun as completeProgressRun, startRun as startProgressRun, updat
|
|
|
16
16
|
import { isRuntimeVisibleScope, parseSkillFrontmatter, } from "../server/agent-chat/skill-frontmatter.js";
|
|
17
17
|
import { canUseDeployCredentialFallbackForRequest, getProviderCredentialAuthFailure, readDeployCredentialEnv, } from "../server/credential-provider.js";
|
|
18
18
|
import { readBody } from "../server/h3-helpers.js";
|
|
19
|
-
import { getRequestRunContext, ensureRequestRunContext, getRequestContext, getRequestOrgId, getRequestUserEmail, runWithRequestContext, } from "../server/request-context.js";
|
|
19
|
+
import { assertRequestActionSurfaceIsolation, getRequestRunContext, ensureRequestRunContext, getRequestContext, getRequestOrgId, getRequestUserEmail, runWithRequestContext, } from "../server/request-context.js";
|
|
20
20
|
import { fireInternalDispatch } from "../server/self-dispatch.js";
|
|
21
21
|
import { isReasoningEffort, normalizeReasoningEffortForRequest, stepDownReasoningEffort, } from "../shared/reasoning-effort.js";
|
|
22
22
|
import { actionPreparationContinuationNote } from "./action-continuation-guidance.js";
|
|
@@ -391,6 +391,55 @@ export async function resolveOwnerEngineApiKey(input) {
|
|
|
391
391
|
export async function getOwnerAnthropicApiKey(ownerEmail) {
|
|
392
392
|
return getOwnerApiKey("anthropic", ownerEmail);
|
|
393
393
|
}
|
|
394
|
+
function hasOwn(value, propertyName) {
|
|
395
|
+
return (typeof value === "object" &&
|
|
396
|
+
value !== null &&
|
|
397
|
+
Object.prototype.hasOwnProperty.call(value, propertyName));
|
|
398
|
+
}
|
|
399
|
+
/** Read a persisted allowlist while preserving legacy absence and failing
|
|
400
|
+
* closed when the field is present but malformed. */
|
|
401
|
+
export function readPersistedAllowedActionNames(value) {
|
|
402
|
+
if (!hasOwn(value, "allowedActionNames"))
|
|
403
|
+
return undefined;
|
|
404
|
+
const names = value.allowedActionNames;
|
|
405
|
+
if (!Array.isArray(names) ||
|
|
406
|
+
!names.every((name) => typeof name === "string")) {
|
|
407
|
+
return [];
|
|
408
|
+
}
|
|
409
|
+
return [...new Set(names)];
|
|
410
|
+
}
|
|
411
|
+
/** Read a nested persisted action surface. An absent envelope is legacy;
|
|
412
|
+
* a present but invalid envelope is an explicit org-less, empty surface. */
|
|
413
|
+
export function readPersistedActionSurface(value, propertyName) {
|
|
414
|
+
if (!hasOwn(value, propertyName))
|
|
415
|
+
return undefined;
|
|
416
|
+
const surface = value[propertyName];
|
|
417
|
+
const allowedActionNames = readPersistedAllowedActionNames(surface) ?? [];
|
|
418
|
+
if (!hasOwn(surface, "orgId")) {
|
|
419
|
+
return { orgId: null, allowedActionNames: [] };
|
|
420
|
+
}
|
|
421
|
+
const orgId = surface.orgId;
|
|
422
|
+
if (orgId !== null &&
|
|
423
|
+
(typeof orgId !== "string" || orgId.trim().length === 0)) {
|
|
424
|
+
return { orgId: null, allowedActionNames: [] };
|
|
425
|
+
}
|
|
426
|
+
return { orgId, allowedActionNames };
|
|
427
|
+
}
|
|
428
|
+
export function filterActionsByAllowedNames(actions, allowedActionNames) {
|
|
429
|
+
const allowedNames = [...new Set(allowedActionNames)];
|
|
430
|
+
const unknownNames = allowedNames.filter((name) => !Object.prototype.hasOwnProperty.call(actions, name));
|
|
431
|
+
if (unknownNames.length > 0) {
|
|
432
|
+
throw new Error(`resolveActionSurface returned unknown action name(s): ${unknownNames.join(", ")}`);
|
|
433
|
+
}
|
|
434
|
+
const filtered = Object.fromEntries(allowedNames.map((name) => [name, actions[name]]));
|
|
435
|
+
// `attachToolSearch` closes over the registry it was originally attached to.
|
|
436
|
+
// Rebind it to this request's filtered registry so explicitly allowing
|
|
437
|
+
// `tool-search` cannot disclose actions that the resolver omitted.
|
|
438
|
+
if (filtered[TOOL_SEARCH_ACTION_NAME]) {
|
|
439
|
+
filtered[TOOL_SEARCH_ACTION_NAME] = createToolSearchEntry(() => filtered);
|
|
440
|
+
}
|
|
441
|
+
return filtered;
|
|
442
|
+
}
|
|
394
443
|
export const PLAN_MODE_SYSTEM_PROMPT = `## Plan Mode Active
|
|
395
444
|
|
|
396
445
|
You are in Plan mode. This turn is for research, clarification, and a proposed approach only.
|
|
@@ -6031,6 +6080,9 @@ export function resolveAgentRequestReasoningEffort({ model, requestEffort, confi
|
|
|
6031
6080
|
return normalizeReasoningEffortForRequest(model, isReasoningEffort(requestEffort) ? requestEffort : configuredEffort);
|
|
6032
6081
|
}
|
|
6033
6082
|
export function createProductionAgentHandler(options) {
|
|
6083
|
+
if (options.resolveActionSurface) {
|
|
6084
|
+
assertRequestActionSurfaceIsolation();
|
|
6085
|
+
}
|
|
6034
6086
|
// Undefined = let each engine pick its own defaultModel at request time.
|
|
6035
6087
|
const configuredModel = options.model;
|
|
6036
6088
|
// Resolve actions — prefer `actions`, fall back to deprecated `scripts`
|
|
@@ -6040,7 +6092,7 @@ export function createProductionAgentHandler(options) {
|
|
|
6040
6092
|
// the settings UI) show up to the LLM without a process restart. MCP tools
|
|
6041
6093
|
// are also scope-filtered per request — a user-scope server added by Alice
|
|
6042
6094
|
// must not appear in Bob's tool list in a shared-process deployment.
|
|
6043
|
-
const
|
|
6095
|
+
const getRequestActions = (actions = resolvedActions) => {
|
|
6044
6096
|
const filtered = {};
|
|
6045
6097
|
for (const [name, entry] of Object.entries(actions)) {
|
|
6046
6098
|
if (name.startsWith("mcp__") && !isMcpToolAllowedForRequest(name)) {
|
|
@@ -6048,8 +6100,9 @@ export function createProductionAgentHandler(options) {
|
|
|
6048
6100
|
}
|
|
6049
6101
|
filtered[name] = entry;
|
|
6050
6102
|
}
|
|
6051
|
-
return
|
|
6103
|
+
return filtered;
|
|
6052
6104
|
};
|
|
6105
|
+
const getEngineTools = (actions) => actionsToEngineTools(getRequestActions(actions));
|
|
6053
6106
|
return defineEventHandler(async (event) => {
|
|
6054
6107
|
// Diagnostic-only setup-timing instrumentation. Captures wall-clock offsets
|
|
6055
6108
|
// from handler entry through the work done BEFORE startRun so a slow pre-run
|
|
@@ -6089,12 +6142,20 @@ export function createProductionAgentHandler(options) {
|
|
|
6089
6142
|
// (the route HMAC-verifies the dispatch before invoking us). When set, we
|
|
6090
6143
|
// run the loop inline with the background soft-timeout, reusing the
|
|
6091
6144
|
// pre-claimed runId/turnId — we must NOT re-claim the slot or re-dispatch.
|
|
6092
|
-
const backgroundRunMarker =
|
|
6145
|
+
const backgroundRunMarker = preInjectedBody &&
|
|
6146
|
+
body[AGENT_CHAT_BACKGROUND_RUN_FIELD] &&
|
|
6093
6147
|
typeof body[AGENT_CHAT_BACKGROUND_RUN_FIELD] === "object" &&
|
|
6094
6148
|
typeof body[AGENT_CHAT_BACKGROUND_RUN_FIELD].runId === "string"
|
|
6095
6149
|
? body[AGENT_CHAT_BACKGROUND_RUN_FIELD]
|
|
6096
6150
|
: null;
|
|
6097
6151
|
const isBackgroundWorker = backgroundRunMarker !== null;
|
|
6152
|
+
// Both fields are internal durable-dispatch artifacts, never client input.
|
|
6153
|
+
// A body marker alone is not proof of worker identity: only the verified
|
|
6154
|
+
// `_process-run` route can install `preInjectedBody` on the event context.
|
|
6155
|
+
if (!isBackgroundWorker) {
|
|
6156
|
+
delete body[AGENT_CHAT_BACKGROUND_RUN_FIELD];
|
|
6157
|
+
delete body.__resolvedActionSurface;
|
|
6158
|
+
}
|
|
6098
6159
|
// DIAGNOSTIC-ONLY: progressive per-stage hang localizer for the bg worker.
|
|
6099
6160
|
// The worker's runId is available EARLY on the marker (the general `runId`
|
|
6100
6161
|
// var resolves much later), so capture it now and emit the LAST setup stage
|
|
@@ -6197,6 +6258,35 @@ export function createProductionAgentHandler(options) {
|
|
|
6197
6258
|
requestAttachments = preparedRequest.attachments;
|
|
6198
6259
|
}
|
|
6199
6260
|
}
|
|
6261
|
+
const availableRequestActions = getRequestActions();
|
|
6262
|
+
let surfacedRequestActions = availableRequestActions;
|
|
6263
|
+
if (options.resolveActionSurface) {
|
|
6264
|
+
const persistedSurface = isBackgroundWorker
|
|
6265
|
+
? readPersistedActionSurface(body, "__resolvedActionSurface")
|
|
6266
|
+
: undefined;
|
|
6267
|
+
const surface = persistedSurface !== undefined
|
|
6268
|
+
? persistedSurface
|
|
6269
|
+
: await options.resolveActionSurface({
|
|
6270
|
+
event,
|
|
6271
|
+
ownerEmail,
|
|
6272
|
+
orgId: getRequestOrgId() ?? null,
|
|
6273
|
+
threadId,
|
|
6274
|
+
mode: requestMode,
|
|
6275
|
+
internalContinuation: Boolean(internalContinuation),
|
|
6276
|
+
availableActionNames: Object.keys(availableRequestActions),
|
|
6277
|
+
});
|
|
6278
|
+
surfacedRequestActions = filterActionsByAllowedNames(availableRequestActions, surface.allowedActionNames);
|
|
6279
|
+
const allowedNames = Object.keys(surfacedRequestActions);
|
|
6280
|
+
const runCtx = ensureRequestRunContext();
|
|
6281
|
+
if (runCtx)
|
|
6282
|
+
runCtx.allowedActionNames = allowedNames;
|
|
6283
|
+
if (!isBackgroundWorker) {
|
|
6284
|
+
body.__resolvedActionSurface = {
|
|
6285
|
+
orgId: getRequestOrgId() ?? null,
|
|
6286
|
+
allowedActionNames: allowedNames,
|
|
6287
|
+
};
|
|
6288
|
+
}
|
|
6289
|
+
}
|
|
6200
6290
|
// DIAGNOSTIC-ONLY: owner/request context prep (resolveAgentOwnerEmail +
|
|
6201
6291
|
// prepareRequest) finished. A worker stuck before this points at the
|
|
6202
6292
|
// owner/request-context awaits.
|
|
@@ -6428,7 +6518,7 @@ export function createProductionAgentHandler(options) {
|
|
|
6428
6518
|
const screenContextThunk = () => (async () => {
|
|
6429
6519
|
const screenStart = Date.now();
|
|
6430
6520
|
try {
|
|
6431
|
-
const viewScreenAction =
|
|
6521
|
+
const viewScreenAction = surfacedRequestActions["view-screen"];
|
|
6432
6522
|
if (viewScreenAction) {
|
|
6433
6523
|
const result = await viewScreenAction.run({}, {
|
|
6434
6524
|
userEmail: getRequestUserEmail(),
|
|
@@ -6667,10 +6757,12 @@ export function createProductionAgentHandler(options) {
|
|
|
6667
6757
|
}
|
|
6668
6758
|
const screenContext = timeBlock + screenBlock + urlBlock + selectionBlock;
|
|
6669
6759
|
const requestActions = requestMode === "plan"
|
|
6670
|
-
? createPlanModeActionRegistry(
|
|
6671
|
-
:
|
|
6760
|
+
? createPlanModeActionRegistry(surfacedRequestActions)
|
|
6761
|
+
: surfacedRequestActions;
|
|
6672
6762
|
const availableRequestTools = getEngineTools(requestActions);
|
|
6673
|
-
const initialRequestTools =
|
|
6763
|
+
const initialRequestTools = options.resolveActionSurface
|
|
6764
|
+
? availableRequestTools
|
|
6765
|
+
: filterInitialEngineTools(availableRequestTools, options.initialToolNames);
|
|
6674
6766
|
const requestTools = requestMode === "plan"
|
|
6675
6767
|
? preloadPlanModeEngineTools({
|
|
6676
6768
|
request: requestMessage,
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -186,6 +186,15 @@ export interface AgentChatRequest {
|
|
|
186
186
|
*/
|
|
187
187
|
payloadRef?: boolean;
|
|
188
188
|
};
|
|
189
|
+
/**
|
|
190
|
+
* Server-resolved action authorization carried across authenticated durable
|
|
191
|
+
* background dispatches. Normal client requests must not trust this field;
|
|
192
|
+
* the foreground handler deletes and replaces it before persistence.
|
|
193
|
+
*/
|
|
194
|
+
__resolvedActionSurface?: {
|
|
195
|
+
orgId: string | null;
|
|
196
|
+
allowedActionNames: string[];
|
|
197
|
+
};
|
|
189
198
|
/**
|
|
190
199
|
* Stable identity for the logical assistant turn this request belongs to.
|
|
191
200
|
* The client sends the SAME turnId for the initial POST and every
|