@agent-native/core 0.149.0 → 0.149.2
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/skills/dashboard-management/SKILL.md +2 -0
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +150 -46
- package/corpus/templates/analytics/app/global.css +1 -1
- package/corpus/templates/analytics/app/i18n-data.ts +37 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +32 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +2 -0
- package/corpus/templates/analytics/changelog/2026-08-10-dashboard-tables-can-be-copied-and-sorted-by-multiple-column.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/assets/app/global.css +1 -1
- package/corpus/templates/assets/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/brain/app/global.css +1 -1
- package/corpus/templates/brain/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-10-clips-desktop-sign-in-now-starts-with-magic-links-and-google.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.css +1 -0
- package/corpus/templates/clips/desktop/src/app.tsx +274 -137
- package/corpus/templates/clips/desktop/src/styles.css +35 -0
- package/corpus/templates/content/app/global.css +1 -0
- package/corpus/templates/crm/app/global.css +1 -1
- package/corpus/templates/crm/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/forms/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/plan/app/global.css +1 -0
- package/corpus/templates/plan/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/plan/server/ui-plan-html.ts +4 -1
- package/corpus/templates/slides/AGENTS.md +11 -10
- package/corpus/templates/slides/actions/add-deck.ts +2 -0
- package/corpus/templates/slides/actions/add-slide.ts +15 -1
- package/corpus/templates/slides/actions/create-deck.ts +18 -6
- package/corpus/templates/slides/actions/get-deck.ts +29 -1
- package/corpus/templates/slides/actions/patch-deck.ts +139 -10
- package/corpus/templates/slides/actions/save-deck.ts +24 -1
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +46 -0
- package/corpus/templates/slides/app/components/editor/BlockBubbleMenu.tsx +194 -3
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +10 -1
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +134 -618
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +74 -63
- package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +13 -1
- package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +56 -174
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +239 -116
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +29 -7
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +45 -0
- package/corpus/templates/slides/app/components/layout/AgentWorkIndicator.tsx +1 -1
- package/corpus/templates/slides/app/components/layout/Layout.tsx +34 -35
- package/corpus/templates/slides/app/components/layout/layout-route-policy.ts +2 -5
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +45 -40
- package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +63 -16
- package/corpus/templates/slides/app/hooks/use-generating-slide-preview.ts +25 -3
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +5 -4
- package/corpus/templates/slides/app/lib/export-pdf-client.ts +84 -25
- package/corpus/templates/slides/app/lib/import-uploaded-deck.ts +11 -0
- package/corpus/templates/slides/app/lib/recent-references.ts +23 -1
- package/corpus/templates/slides/app/lib/slide-animation-elements.ts +41 -3
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +16 -27
- package/corpus/templates/slides/app/pages/Index.tsx +256 -98
- package/corpus/templates/slides/changelog/2026-08-08-google-slides-export-now-tells-you-why-a-deck-fell-back-to-a.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-delete-key-now-removes-a-selected-image.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-editing-a-slide-in-an-imported-deck-no-longer-fails-to-save.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-fixed-pdf-and-custom-size-powerpoint-imports-rendering-with-.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-images-from-sites-without-cors-no-longer-export-blank.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-imported-pdf-headings-no-longer-lose-the-space-between-color.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-imported-slide-text-no-longer-renders-too-large-for-its-box.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-large-decks-no-longer-render-slowly-or-glitch-in-the-editor.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-revise-highlighted-slide-text-with-ai.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-the-deck-editor-no-longer-stays-dimmed-after-the-window-narro.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-ai-editing-avatar-badge.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-generated-decks-keep-a-clear-human-readable-title.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-new-deck-creation-now-shows-progress-opens-the-editor-direct.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-presentation-reveals-now-follow-valid-targets.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-editing-controls-are-consolidated-into-one-focused-me.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-now-verify-and-restyle-every-imported-slide-in-one-pa.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-only-suggests-a-google-connection-for-relevant-reques.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-the-google-slides-import-option-is-now-labeled-slides.md +6 -0
- package/corpus/templates/slides/server/handlers/import/html-converter.ts +115 -22
- package/corpus/templates/slides/server/handlers/import/pdf-fidelity-parser.ts +11 -2
- package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
- package/corpus/templates/slides/server/lib/fetch-remote-image.ts +192 -0
- package/corpus/templates/slides/server/lib/image-proxy-url.ts +192 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -3
- package/corpus/templates/slides/server/routes/api/image-proxy.get.ts +65 -0
- package/corpus/templates/slides/shared/api.ts +2 -1
- package/corpus/templates/slides/shared/deck-title.ts +135 -0
- package/corpus/templates/tasks/app/components/tasks/TaskListRow.tsx +4 -1
- package/dist/agent/engine/ai-sdk-engine.js +1 -1
- package/dist/agent/production-agent.d.ts +21 -1
- package/dist/agent/production-agent.js +129 -10
- package/dist/agent/tool-approval-store.d.ts +18 -0
- package/dist/agent/tool-approval-store.js +122 -0
- package/dist/agent/types.d.ts +1 -1
- package/dist/cli/code-agent-executor.js +11 -2
- package/dist/client/AgentPanel.js +31 -6
- package/dist/client/AssistantChat.d.ts +3 -2
- package/dist/client/AssistantChat.js +7 -20
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat-adapter.js +11 -0
- package/dist/client/agent-chat.d.ts +1 -1
- package/dist/client/chat/markdown-renderer.js +14 -2
- package/dist/client/chat/message-components.d.ts +6 -2
- package/dist/client/chat/message-components.js +25 -47
- package/dist/client/chat/tool-call-display.d.ts +3 -5
- package/dist/client/chat/tool-call-display.js +7 -212
- package/dist/client/chat-first/apps-rail.js +3 -3
- package/dist/client/chat-first/browser-pane.js +4 -1
- package/dist/client/chat-first/chat-history.d.ts +3 -1
- package/dist/client/chat-first/chat-history.js +2 -2
- package/dist/client/chat-first/surface-tabs.d.ts +1 -1
- package/dist/client/chat-first/surface-tabs.js +52 -41
- package/dist/client/chat-first/types.d.ts +3 -0
- package/dist/client/chat-first.d.ts +10 -0
- package/dist/client/chat-first.js +37 -2
- package/dist/client/components/ui/message-scroller.js +4 -1
- package/dist/client/i18n.js +3 -1
- package/dist/client/progress/RunsTray.js +14 -1
- package/dist/client/resources/McpConnectionSuggestion.js +9 -1
- package/dist/client/sse-event-processor.js +10 -0
- package/dist/client/use-chat-models.js +156 -80
- package/dist/integrations/webhook-handler.js +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/auth.js +262 -31
- package/dist/server/onboarding-html.js +56 -9
- package/dist/shared/reasoning-effort.d.ts +8 -8
- package/dist/shared/reasoning-effort.js +10 -10
- package/dist/shared/streaming-text-smoothing.js +41 -11
- package/dist/styles/agent-native.css +19 -32
- package/dist/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/docs/content/template-chat.mdx +1 -1
- package/package.json +2 -2
- package/src/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from "@/components/editor/NewDeckReferenceStep";
|
|
34
34
|
import PromptPopover, {
|
|
35
35
|
uploadPromptFiles,
|
|
36
|
+
type PromptImportSelection,
|
|
36
37
|
type UploadedFile,
|
|
37
38
|
} from "@/components/editor/PromptDialog";
|
|
38
39
|
import {
|
|
@@ -59,10 +60,12 @@ import { createDeckAgentMessage } from "@/lib/agent-visible-message";
|
|
|
59
60
|
import { savePromptToComposerDraft } from "@/lib/composer-draft";
|
|
60
61
|
import { sortDecksByRecency } from "@/lib/deck-sorting";
|
|
61
62
|
import {
|
|
63
|
+
IMPORT_ACTION_TIMEOUT_MS,
|
|
62
64
|
importUploadedDeckIntoDeck,
|
|
63
65
|
type ImportedSourceDeck,
|
|
64
66
|
} from "@/lib/import-uploaded-deck";
|
|
65
67
|
import {
|
|
68
|
+
forgetRecentReference,
|
|
66
69
|
readRecentReferences,
|
|
67
70
|
rememberRecentReference,
|
|
68
71
|
type RecentReference,
|
|
@@ -235,7 +238,7 @@ export default function Index() {
|
|
|
235
238
|
loadError,
|
|
236
239
|
reloadDecks,
|
|
237
240
|
} = useDecks();
|
|
238
|
-
const { designSystems
|
|
241
|
+
const { designSystems } = useDesignSystems();
|
|
239
242
|
const {
|
|
240
243
|
referenceDeck: workspaceReferenceDeck,
|
|
241
244
|
designSystem: workspaceDesignSystem,
|
|
@@ -293,27 +296,25 @@ export default function Index() {
|
|
|
293
296
|
() => new Map(designSystems.map((ds) => [ds.id, ds.title])),
|
|
294
297
|
[designSystems],
|
|
295
298
|
);
|
|
296
|
-
// A workspace default the caller cannot open is reported by the action as
|
|
297
|
-
// `unavailable` rather than absent; preselecting it would send every new
|
|
298
|
-
// prompt at a deck that 404s, so fall back to no reference instead.
|
|
299
|
-
const workspaceReferenceDeckId =
|
|
300
|
-
workspaceReferenceDeck && !workspaceReferenceDeck.unavailable
|
|
301
|
-
? workspaceReferenceDeck.id
|
|
302
|
-
: null;
|
|
303
299
|
const workspaceDesignSystemId =
|
|
304
300
|
workspaceDesignSystem && !workspaceDesignSystem.unavailable
|
|
305
301
|
? workspaceDesignSystem.id
|
|
306
302
|
: null;
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
303
|
+
const lastUsedDesignSystemId =
|
|
304
|
+
recentReferences.find(
|
|
305
|
+
(reference) =>
|
|
306
|
+
reference.kind === "design-system" &&
|
|
307
|
+
designSystems.some((designSystem) => designSystem.id === reference.id),
|
|
308
|
+
)?.id ?? null;
|
|
309
|
+
const lastUsedReferenceDeckId =
|
|
310
|
+
recentReferences.find(
|
|
311
|
+
(reference) =>
|
|
312
|
+
reference.kind === "deck" &&
|
|
313
|
+
decks.some((deck) => deck.id === reference.id),
|
|
314
|
+
)?.id ?? null;
|
|
312
315
|
const initialDesignSystemId =
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
defaultSystem?.id ??
|
|
316
|
-
null;
|
|
316
|
+
lastUsedDesignSystemId ?? workspaceDesignSystemId;
|
|
317
|
+
const initialReferenceDeckId = lastUsedReferenceDeckId;
|
|
317
318
|
const deckFilter = searchParams.get("createdBy") === "me" ? "mine" : "all";
|
|
318
319
|
const visibleDecks = useMemo(
|
|
319
320
|
() =>
|
|
@@ -331,24 +332,16 @@ export default function Index() {
|
|
|
331
332
|
},
|
|
332
333
|
[],
|
|
333
334
|
);
|
|
335
|
+
const forgetReference = useCallback((kind: RecentReference["kind"]) => {
|
|
336
|
+
const result = forgetRecentReference(kind);
|
|
337
|
+
if (result.readable) setRecentReferences(result.items);
|
|
338
|
+
}, []);
|
|
334
339
|
|
|
335
340
|
useEffect(() => {
|
|
336
341
|
const result = readRecentReferences();
|
|
337
342
|
if (result.readable) setRecentReferences(result.items);
|
|
338
343
|
}, []);
|
|
339
344
|
|
|
340
|
-
useEffect(() => {
|
|
341
|
-
if (initialDesignSystemId) {
|
|
342
|
-
rememberReference({
|
|
343
|
-
id: initialDesignSystemId,
|
|
344
|
-
kind: "design-system",
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
if (workspaceReferenceDeckId) {
|
|
348
|
-
rememberReference({ id: workspaceReferenceDeckId, kind: "deck" });
|
|
349
|
-
}
|
|
350
|
-
}, [initialDesignSystemId, rememberReference, workspaceReferenceDeckId]);
|
|
351
|
-
|
|
352
345
|
const initialPrompt = searchParams.get("initialPrompt")?.trim() ?? "";
|
|
353
346
|
const onboardingPreview = searchParams.get("onboarding") === "preview";
|
|
354
347
|
const openInitialPrompt = useCallback(() => {
|
|
@@ -429,10 +422,10 @@ export default function Index() {
|
|
|
429
422
|
designSystemAutoRef.current = true;
|
|
430
423
|
referenceDeckAutoRef.current = true;
|
|
431
424
|
setSelectedDesignSystemId(initialDesignSystemId ?? null);
|
|
432
|
-
setSelectedReferenceDeckId(
|
|
425
|
+
setSelectedReferenceDeckId(initialReferenceDeckId ?? null);
|
|
433
426
|
setShowNewDeckPrompt(true);
|
|
434
427
|
},
|
|
435
|
-
[initialDesignSystemId,
|
|
428
|
+
[initialDesignSystemId, initialReferenceDeckId],
|
|
436
429
|
);
|
|
437
430
|
|
|
438
431
|
const setNewDeckPromptOpen = useCallback(
|
|
@@ -485,13 +478,13 @@ export default function Index() {
|
|
|
485
478
|
}
|
|
486
479
|
}, [initialDesignSystemId, designSystems.length, showNewDeckPrompt]);
|
|
487
480
|
|
|
488
|
-
// Same as above for the reference-deck picker:
|
|
481
|
+
// Same as above for the reference-deck picker: the local last-used reference
|
|
489
482
|
// can still be loading when the dialog opens, so re-apply it once it
|
|
490
483
|
// resolves unless the user already picked a reference deck.
|
|
491
484
|
useEffect(() => {
|
|
492
485
|
if (!showNewDeckPrompt || !referenceDeckAutoRef.current) return;
|
|
493
|
-
setSelectedReferenceDeckId(
|
|
494
|
-
}, [
|
|
486
|
+
setSelectedReferenceDeckId(initialReferenceDeckId ?? null);
|
|
487
|
+
}, [initialReferenceDeckId, showNewDeckPrompt]);
|
|
495
488
|
|
|
496
489
|
// Restore a prompt that was held back when the user wasn't signed in:
|
|
497
490
|
// we wrote the text to sessionStorage before redirecting to sign-in,
|
|
@@ -515,9 +508,9 @@ export default function Index() {
|
|
|
515
508
|
designSystemAutoRef.current = true;
|
|
516
509
|
referenceDeckAutoRef.current = true;
|
|
517
510
|
setSelectedDesignSystemId(initialDesignSystemId ?? null);
|
|
518
|
-
setSelectedReferenceDeckId(
|
|
511
|
+
setSelectedReferenceDeckId(initialReferenceDeckId ?? null);
|
|
519
512
|
setShowNewDeckPrompt(true);
|
|
520
|
-
}, [initialDesignSystemId,
|
|
513
|
+
}, [initialDesignSystemId, initialReferenceDeckId, session]);
|
|
521
514
|
|
|
522
515
|
// Recovering from a failed deck-generation kickoff (see
|
|
523
516
|
// recoverFromGenerationSetupFailure below) navigates back to this route
|
|
@@ -597,20 +590,44 @@ export default function Index() {
|
|
|
597
590
|
const deckId = deck.id;
|
|
598
591
|
setNewDeckPromptOpen(false);
|
|
599
592
|
|
|
600
|
-
|
|
601
|
-
|
|
593
|
+
// Leave the grid as soon as the optimistic deck exists. Persistence and
|
|
594
|
+
// source import can take several seconds for a large PDF, so the editor's
|
|
595
|
+
// generation state is the only useful surface while that work finishes.
|
|
596
|
+
navigate(`/deck/${deck.id}?generating=1`, {
|
|
597
|
+
replace: true,
|
|
598
|
+
flushSync: true,
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
const recoverFromGenerationSetupFailure = (description: string) => {
|
|
602
602
|
if (!savePromptForRetry(prompt)) {
|
|
603
603
|
setNewDeckInitialPrompt({ text: prompt, key: Date.now() });
|
|
604
604
|
}
|
|
605
605
|
setNewDeckRetryFiles(filesForGeneration);
|
|
606
606
|
deleteDeck(deckId);
|
|
607
|
-
toast.error(t("home.generationStartFailed"), {
|
|
608
|
-
|
|
607
|
+
toast.error(t("home.generationStartFailed"), { description });
|
|
608
|
+
if (
|
|
609
|
+
typeof window !== "undefined" &&
|
|
610
|
+
deckIdFromPathname(window.location.pathname) === deckId
|
|
611
|
+
) {
|
|
612
|
+
navigate("/", {
|
|
613
|
+
replace: true,
|
|
614
|
+
state: {
|
|
615
|
+
retryPrompt: prompt,
|
|
616
|
+
retryFiles: filesForGeneration,
|
|
617
|
+
} satisfies DeckGenerationRetryState,
|
|
618
|
+
flushSync: true,
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
const persisted = await ensureDeckPersisted(deck.id);
|
|
624
|
+
if (!persisted.persisted) {
|
|
625
|
+
recoverFromGenerationSetupFailure(
|
|
626
|
+
describeDeckPersistenceFailure(
|
|
609
627
|
persisted,
|
|
610
628
|
t("home.generationStartFailedDescription"),
|
|
611
629
|
),
|
|
612
|
-
|
|
613
|
-
setShowNewDeckPrompt(true);
|
|
630
|
+
);
|
|
614
631
|
return;
|
|
615
632
|
}
|
|
616
633
|
|
|
@@ -621,26 +638,17 @@ export default function Index() {
|
|
|
621
638
|
deckId,
|
|
622
639
|
);
|
|
623
640
|
} catch (error) {
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
toast.error(t("home.generationStartFailed"), {
|
|
630
|
-
description:
|
|
631
|
-
error instanceof Error
|
|
632
|
-
? error.message
|
|
633
|
-
: t("home.generationStartFailedDescription"),
|
|
634
|
-
});
|
|
635
|
-
setShowNewDeckPrompt(true);
|
|
641
|
+
recoverFromGenerationSetupFailure(
|
|
642
|
+
error instanceof Error
|
|
643
|
+
? error.message
|
|
644
|
+
: t("home.generationStartFailedDescription"),
|
|
645
|
+
);
|
|
636
646
|
return;
|
|
637
647
|
}
|
|
638
648
|
|
|
639
649
|
clearPendingPromptForRetry();
|
|
640
650
|
setNewDeckInitialPrompt(null);
|
|
641
651
|
setNewDeckRetryFiles([]);
|
|
642
|
-
navigate(`/deck/${deck.id}`, { flushSync: true });
|
|
643
|
-
|
|
644
652
|
const trimmedPrompt = prompt.trim();
|
|
645
653
|
const hasImportedGoogleDocContext = trimmedPrompt.includes("<google-doc ");
|
|
646
654
|
const googleDocUrls = hasImportedGoogleDocContext
|
|
@@ -661,11 +669,11 @@ export default function Index() {
|
|
|
661
669
|
"If the action cannot read a private document, tell the user the exact sharing step from the action error instead of generating from the URL alone.",
|
|
662
670
|
].join("\n")
|
|
663
671
|
: "";
|
|
664
|
-
const referenceDeckContext =
|
|
665
|
-
await
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
672
|
+
const [referenceDeckContext, hydratedDesignSystemContext] =
|
|
673
|
+
await Promise.all([
|
|
674
|
+
loadReferenceDeckGenerationContext(referenceDeckId),
|
|
675
|
+
loadDesignSystemGenerationContext(selectedDesignSystem?.id),
|
|
676
|
+
]);
|
|
669
677
|
const designSystemContext = selectedDesignSystem
|
|
670
678
|
? [
|
|
671
679
|
"",
|
|
@@ -702,19 +710,20 @@ export default function Index() {
|
|
|
702
710
|
"Source-preserving improvement mode:",
|
|
703
711
|
`- The target deck already contains ${importedSourceDeck.slideCount} imported source slides. Treat those slides as the user's complete source, not as inspiration for a new deck.`,
|
|
704
712
|
"- Keep the exact source slide count, order, IDs, factual meaning, notes, images, charts, tables, diagrams, and freeform objects unless the user explicitly asks to change one of them.",
|
|
705
|
-
"- Read `get-deck` before editing, load the linked design system with `get-design-system`, then
|
|
713
|
+
"- Read `get-deck` once before editing to obtain every existing slide ID and source HTML, load the linked design system with `get-design-system`, then make a deck-wide restyle with one `patch-deck` call using `requireAllSourceSlides: true` and one `patch-slide` operation with `fields.content` for every source slide ID. Do not split a full-deck restyle into arbitrary batches or fall back to one-by-one `update-slide` calls; use `update-slide` only for a targeted one-slide edit. Keep every original `<img>` source and enough original factual copy for each slide; for PDF slides, use restrained design-system chrome around the page without obscuring it.",
|
|
706
714
|
"- Do not call `add-slide`, delete slides, reorder slides, or replace source images with generic cards. Do not claim success until `get-deck` verifies the same slide IDs and count after the edits.",
|
|
715
|
+
'- After the patch succeeds, verify with `get-deck` using `compact: "true"` so only slide IDs, count, and previews are returned. Do not report an initial or partial pass, and do not leave any source slides for a later run.',
|
|
707
716
|
"- If `get-deck` reports partial source fidelity or skipped images, stop and report the exact warning instead of claiming a reliable restyle.",
|
|
708
717
|
].join("\n")
|
|
709
718
|
: "";
|
|
710
719
|
const sourceModeInstructions = importedSourceDeck
|
|
711
720
|
? [
|
|
712
721
|
"The request is an in-place visual improvement of an imported source deck. Make a coherent style pass across every existing slide while preserving all source content and media.",
|
|
713
|
-
"Do not use the new-deck add-slide workflow for this source-preserving request.",
|
|
722
|
+
"Do not use the new-deck add-slide workflow for this source-preserving request. Finish every source slide in this run; if patch-deck rejects incomplete coverage, continue with the returned missing IDs instead of reporting success with a partial deck.",
|
|
714
723
|
].join("\n")
|
|
715
724
|
: [
|
|
716
725
|
"Start a `manage-progress` run so progress appears in the app header. Add the first slide as soon as it is ready, then continue one slide at a time so the editor visibly fills in.",
|
|
717
|
-
"After reading any requested or imported source material, but before adding the first slide, choose a concise, specific deck title from the user's request and source material. Call `patch-deck` with `deckId: \"" +
|
|
726
|
+
"After reading any requested or imported source material, but before adding the first slide, choose a concise, specific deck title from the user's request and source material. Never use the deck id, run id, file id, or another opaque alphanumeric token as the title. Call `patch-deck` with `deckId: \"" +
|
|
718
727
|
deckId +
|
|
719
728
|
'\"` and `operations: [{ "op": "patch-deck-fields", "fields": { "title": "<generated title>" } }]`. Include only `title` in `fields`; omit all other optional fields. Never leave a generated deck named "Untitled Deck" or another placeholder.',
|
|
720
729
|
"If the user asks for a standalone visual, diagram, hero, one-pager, poster, or a couple of visuals, create only the requested one/few polished visual slides. Do not pad the result into a full presentation.",
|
|
@@ -753,10 +762,6 @@ export default function Index() {
|
|
|
753
762
|
).catch(() => {});
|
|
754
763
|
deleteClientAppState("guided-questions").catch(() => {});
|
|
755
764
|
|
|
756
|
-
navigate(`/deck/${deck.id}?generating=1`, {
|
|
757
|
-
replace: true,
|
|
758
|
-
flushSync: true,
|
|
759
|
-
});
|
|
760
765
|
agentSubmit(createDeckAgentMessage(trimmedPrompt), context, {
|
|
761
766
|
newTab: true,
|
|
762
767
|
reuseEmptyTab: true,
|
|
@@ -773,18 +778,150 @@ export default function Index() {
|
|
|
773
778
|
[setNewDeckPromptOpen],
|
|
774
779
|
);
|
|
775
780
|
|
|
781
|
+
const handlePromptSkip = useCallback(() => {
|
|
782
|
+
setNewDeckPromptOpen(false, { clearInitialPrompt: false });
|
|
783
|
+
setPendingDeck({ prompt: "", files: [] });
|
|
784
|
+
setShowNewDeckReferenceStep(true);
|
|
785
|
+
}, [setNewDeckPromptOpen]);
|
|
786
|
+
|
|
787
|
+
const handleDirectImport = useCallback(
|
|
788
|
+
async (selection: PromptImportSelection): Promise<boolean> => {
|
|
789
|
+
if (!session) {
|
|
790
|
+
setSignInPromptHadFiles(selection.kind !== "google-slides");
|
|
791
|
+
setShowSignInDialog(true);
|
|
792
|
+
return false;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
if (selection.kind === "google-slides") {
|
|
796
|
+
const imported = (await callAction("import-google-slides-reference", {
|
|
797
|
+
presentationUrl: selection.url,
|
|
798
|
+
})) as {
|
|
799
|
+
id?: unknown;
|
|
800
|
+
imported?: unknown;
|
|
801
|
+
slideCount?: unknown;
|
|
802
|
+
};
|
|
803
|
+
if (
|
|
804
|
+
typeof imported.id !== "string" ||
|
|
805
|
+
!imported.id ||
|
|
806
|
+
imported.imported !== true ||
|
|
807
|
+
typeof imported.slideCount !== "number" ||
|
|
808
|
+
imported.slideCount < 1
|
|
809
|
+
) {
|
|
810
|
+
throw new Error(
|
|
811
|
+
"The Google Slides presentation did not create a deck.",
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
await reloadDecks();
|
|
815
|
+
navigate(`/deck/${imported.id}`, { flushSync: true });
|
|
816
|
+
return true;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
const uploaded = await uploadPromptFiles(selection.files);
|
|
820
|
+
const file = uploaded[0];
|
|
821
|
+
if (!file) throw new Error("The selected file could not be uploaded.");
|
|
822
|
+
|
|
823
|
+
if (selection.kind === "pptx") {
|
|
824
|
+
const imported = (await callAction("import-pptx", {
|
|
825
|
+
filePath: file.path,
|
|
826
|
+
designSystemId: initialDesignSystemId,
|
|
827
|
+
})) as {
|
|
828
|
+
id?: unknown;
|
|
829
|
+
imported?: unknown;
|
|
830
|
+
slideCount?: unknown;
|
|
831
|
+
};
|
|
832
|
+
if (
|
|
833
|
+
typeof imported.id !== "string" ||
|
|
834
|
+
!imported.id ||
|
|
835
|
+
imported.imported !== true ||
|
|
836
|
+
typeof imported.slideCount !== "number" ||
|
|
837
|
+
imported.slideCount < 1
|
|
838
|
+
) {
|
|
839
|
+
throw new Error("The PowerPoint presentation did not create a deck.");
|
|
840
|
+
}
|
|
841
|
+
await reloadDecks();
|
|
842
|
+
navigate(`/deck/${imported.id}`, { flushSync: true });
|
|
843
|
+
return true;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
let deck: ReturnType<typeof createDeck> | undefined;
|
|
847
|
+
flushSync(() => {
|
|
848
|
+
deck = createDeck(undefined, {
|
|
849
|
+
noDefaultSlides: true,
|
|
850
|
+
designSystemId: initialDesignSystemId,
|
|
851
|
+
});
|
|
852
|
+
});
|
|
853
|
+
if (!deck) throw new Error("The PDF deck could not be created.");
|
|
854
|
+
|
|
855
|
+
const persisted = await ensureDeckPersisted(deck.id);
|
|
856
|
+
if (!persisted.persisted) {
|
|
857
|
+
deleteDeck(deck.id);
|
|
858
|
+
throw new Error(
|
|
859
|
+
describeDeckPersistenceFailure(
|
|
860
|
+
persisted,
|
|
861
|
+
"The PDF deck could not be saved.",
|
|
862
|
+
),
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
try {
|
|
867
|
+
const imported = (await callAction("import-file", {
|
|
868
|
+
filePath: file.path,
|
|
869
|
+
format: "pdf",
|
|
870
|
+
deckId: deck.id,
|
|
871
|
+
importIntoDeck: true,
|
|
872
|
+
})) as {
|
|
873
|
+
imported?: unknown;
|
|
874
|
+
deckId?: unknown;
|
|
875
|
+
pageCount?: unknown;
|
|
876
|
+
};
|
|
877
|
+
if (
|
|
878
|
+
imported.imported !== true ||
|
|
879
|
+
imported.deckId !== deck.id ||
|
|
880
|
+
typeof imported.pageCount !== "number" ||
|
|
881
|
+
imported.pageCount < 1
|
|
882
|
+
) {
|
|
883
|
+
throw new Error("The PDF could not be imported into the new deck.");
|
|
884
|
+
}
|
|
885
|
+
await reloadDecks();
|
|
886
|
+
navigate(`/deck/${deck.id}`, { flushSync: true });
|
|
887
|
+
return true;
|
|
888
|
+
} catch (error) {
|
|
889
|
+
deleteDeck(deck.id);
|
|
890
|
+
throw error;
|
|
891
|
+
}
|
|
892
|
+
},
|
|
893
|
+
[
|
|
894
|
+
callAction,
|
|
895
|
+
createDeck,
|
|
896
|
+
deleteDeck,
|
|
897
|
+
ensureDeckPersisted,
|
|
898
|
+
initialDesignSystemId,
|
|
899
|
+
navigate,
|
|
900
|
+
reloadDecks,
|
|
901
|
+
session,
|
|
902
|
+
],
|
|
903
|
+
);
|
|
904
|
+
|
|
776
905
|
const handleReferenceSelect = useCallback(
|
|
777
906
|
async (selection: NewDeckReferenceSelection) => {
|
|
778
907
|
const pending = pendingDeck;
|
|
779
908
|
if (!pending) return;
|
|
780
|
-
if (selection.designSystemId) {
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
909
|
+
if (selection.designSystemId !== undefined) {
|
|
910
|
+
if (selection.designSystemId) {
|
|
911
|
+
rememberReference({
|
|
912
|
+
id: selection.designSystemId,
|
|
913
|
+
kind: "design-system",
|
|
914
|
+
});
|
|
915
|
+
} else {
|
|
916
|
+
forgetReference("design-system");
|
|
917
|
+
}
|
|
785
918
|
}
|
|
786
|
-
if (selection.referenceDeckId) {
|
|
787
|
-
|
|
919
|
+
if (selection.referenceDeckId !== undefined) {
|
|
920
|
+
if (selection.referenceDeckId) {
|
|
921
|
+
rememberReference({ id: selection.referenceDeckId, kind: "deck" });
|
|
922
|
+
} else {
|
|
923
|
+
forgetReference("deck");
|
|
924
|
+
}
|
|
788
925
|
}
|
|
789
926
|
setShowNewDeckReferenceStep(false);
|
|
790
927
|
setPendingDeck(null);
|
|
@@ -794,7 +931,12 @@ export default function Index() {
|
|
|
794
931
|
selection,
|
|
795
932
|
);
|
|
796
933
|
},
|
|
797
|
-
[
|
|
934
|
+
[
|
|
935
|
+
forgetReference,
|
|
936
|
+
handleCreateDeckWithPrompt,
|
|
937
|
+
pendingDeck,
|
|
938
|
+
rememberReference,
|
|
939
|
+
],
|
|
798
940
|
);
|
|
799
941
|
|
|
800
942
|
const handleReferenceImport = useCallback(
|
|
@@ -813,9 +955,11 @@ export default function Index() {
|
|
|
813
955
|
let importedReference: ImportedReference | null = null;
|
|
814
956
|
let generationFiles = uploaded;
|
|
815
957
|
if (pptxReference) {
|
|
816
|
-
const imported = (await callAction(
|
|
817
|
-
|
|
818
|
-
|
|
958
|
+
const imported = (await callAction(
|
|
959
|
+
"import-pptx",
|
|
960
|
+
{ filePath: pptxReference.path },
|
|
961
|
+
{ timeoutMs: IMPORT_ACTION_TIMEOUT_MS },
|
|
962
|
+
)) as {
|
|
819
963
|
id?: unknown;
|
|
820
964
|
imported?: unknown;
|
|
821
965
|
slideCount?: unknown;
|
|
@@ -854,12 +998,16 @@ export default function Index() {
|
|
|
854
998
|
);
|
|
855
999
|
}
|
|
856
1000
|
try {
|
|
857
|
-
const imported = (await callAction(
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1001
|
+
const imported = (await callAction(
|
|
1002
|
+
"import-file",
|
|
1003
|
+
{
|
|
1004
|
+
filePath: pdfReference.path,
|
|
1005
|
+
format: "pdf",
|
|
1006
|
+
deckId: referenceDeck.id,
|
|
1007
|
+
importIntoDeck: true,
|
|
1008
|
+
},
|
|
1009
|
+
{ timeoutMs: IMPORT_ACTION_TIMEOUT_MS },
|
|
1010
|
+
)) as {
|
|
863
1011
|
imported?: unknown;
|
|
864
1012
|
deckId?: unknown;
|
|
865
1013
|
pageCount?: unknown;
|
|
@@ -894,7 +1042,6 @@ export default function Index() {
|
|
|
894
1042
|
);
|
|
895
1043
|
if (importedReference) {
|
|
896
1044
|
await reloadDecks();
|
|
897
|
-
rememberReference({ id: importedReference.id, kind: "deck" });
|
|
898
1045
|
setSelectedReferenceDeckId(importedReference.id);
|
|
899
1046
|
}
|
|
900
1047
|
return importedReference;
|
|
@@ -917,7 +1064,6 @@ export default function Index() {
|
|
|
917
1064
|
ensureDeckPersisted,
|
|
918
1065
|
pendingDeck,
|
|
919
1066
|
reloadDecks,
|
|
920
|
-
rememberReference,
|
|
921
1067
|
t,
|
|
922
1068
|
],
|
|
923
1069
|
);
|
|
@@ -957,7 +1103,6 @@ export default function Index() {
|
|
|
957
1103
|
source: "google-slides",
|
|
958
1104
|
};
|
|
959
1105
|
await reloadDecks();
|
|
960
|
-
rememberReference({ id: importedReference.id, kind: "deck" });
|
|
961
1106
|
setSelectedReferenceDeckId(importedReference.id);
|
|
962
1107
|
return importedReference;
|
|
963
1108
|
} catch (error) {
|
|
@@ -972,7 +1117,7 @@ export default function Index() {
|
|
|
972
1117
|
setReferenceImporting(false);
|
|
973
1118
|
}
|
|
974
1119
|
},
|
|
975
|
-
[callAction, reloadDecks,
|
|
1120
|
+
[callAction, reloadDecks, t],
|
|
976
1121
|
);
|
|
977
1122
|
|
|
978
1123
|
const handleReferenceSkip = useCallback(() => {
|
|
@@ -983,11 +1128,22 @@ export default function Index() {
|
|
|
983
1128
|
}
|
|
984
1129
|
setShowNewDeckReferenceStep(false);
|
|
985
1130
|
setPendingDeck(null);
|
|
1131
|
+
forgetReference("design-system");
|
|
1132
|
+
forgetReference("deck");
|
|
1133
|
+
if (!pending.prompt.trim() && pending.files.length === 0) {
|
|
1134
|
+
handleCreateDeckBlank();
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
986
1137
|
void handleCreateDeckWithPrompt(pending.prompt, pending.files, {
|
|
987
1138
|
designSystemId: null,
|
|
988
1139
|
referenceDeckId: null,
|
|
989
1140
|
});
|
|
990
|
-
}, [
|
|
1141
|
+
}, [
|
|
1142
|
+
forgetReference,
|
|
1143
|
+
handleCreateDeckBlank,
|
|
1144
|
+
handleCreateDeckWithPrompt,
|
|
1145
|
+
pendingDeck,
|
|
1146
|
+
]);
|
|
991
1147
|
|
|
992
1148
|
const handleConfirmDelete = () => {
|
|
993
1149
|
if (deckToDelete) {
|
|
@@ -1310,9 +1466,11 @@ export default function Index() {
|
|
|
1310
1466
|
onOpenChange={setNewDeckPromptOpen}
|
|
1311
1467
|
title={t("home.newDeckPromptTitle")}
|
|
1312
1468
|
placeholder={t("home.newDeckPlaceholder")}
|
|
1313
|
-
onSkip={
|
|
1469
|
+
onSkip={handlePromptSkip}
|
|
1314
1470
|
skipLabel={t("home.skipPrompt")}
|
|
1315
1471
|
onSubmit={handlePromptSubmit}
|
|
1472
|
+
onImport={handleDirectImport}
|
|
1473
|
+
importFromLabel={t("home.importFrom")}
|
|
1316
1474
|
importingLabel={t("editorToolbar.importing")}
|
|
1317
1475
|
onBeforeUpload={(prompt, files) => {
|
|
1318
1476
|
if (session) return true;
|
|
@@ -1330,11 +1488,14 @@ export default function Index() {
|
|
|
1330
1488
|
open={showNewDeckReferenceStep}
|
|
1331
1489
|
onOpenChange={(open) => {
|
|
1332
1490
|
if (!open) {
|
|
1333
|
-
const
|
|
1491
|
+
const pending = pendingDeck;
|
|
1334
1492
|
setShowNewDeckReferenceStep(false);
|
|
1335
1493
|
setPendingDeck(null);
|
|
1336
|
-
if (
|
|
1337
|
-
setNewDeckInitialPrompt({
|
|
1494
|
+
if (pending) {
|
|
1495
|
+
setNewDeckInitialPrompt({
|
|
1496
|
+
text: pending.prompt,
|
|
1497
|
+
key: Date.now(),
|
|
1498
|
+
});
|
|
1338
1499
|
setShowNewDeckPrompt(true);
|
|
1339
1500
|
}
|
|
1340
1501
|
}
|
|
@@ -1342,8 +1503,7 @@ export default function Index() {
|
|
|
1342
1503
|
designSystems={designSystems}
|
|
1343
1504
|
decks={decks}
|
|
1344
1505
|
defaultDesignSystemId={initialDesignSystemId}
|
|
1345
|
-
defaultReferenceDeckId={
|
|
1346
|
-
recentReferences={recentReferences}
|
|
1506
|
+
defaultReferenceDeckId={initialReferenceDeckId}
|
|
1347
1507
|
onSelect={(selection) => void handleReferenceSelect(selection)}
|
|
1348
1508
|
onImport={handleReferenceImport}
|
|
1349
1509
|
onImportSource={handleReferenceSourceImport}
|
|
@@ -1355,8 +1515,6 @@ export default function Index() {
|
|
|
1355
1515
|
chooseDeckLabel={t("home.referenceDeckPlaceholder")}
|
|
1356
1516
|
importingLabel={t("editorToolbar.importing")}
|
|
1357
1517
|
skipLabel={t("home.referenceDeckNone")}
|
|
1358
|
-
starredLabel={t("home.referenceDeckStarredGroup")}
|
|
1359
|
-
otherDecksLabel={t("home.referenceDeckOtherGroup")}
|
|
1360
1518
|
searchDecksLabel={t("root.searchDecks")}
|
|
1361
1519
|
promptSummary={pendingDeck?.prompt}
|
|
1362
1520
|
/>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: fixed
|
|
3
|
+
date: 2026-08-09
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Fixed direct edits to a PDF/PPTX-imported deck's slide text sometimes failing to save with a generic "Internal server error" — the source-preservation guard meant to stop an agent from silently dropping the original artwork or copy was also blocking ordinary human edits, which have no way to opt out of it.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: fixed
|
|
3
|
+
date: 2026-08-09
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Fixed images vanishing from exported PDFs and PowerPoint files when they came from a site that blocks direct browser access, such as a blog or a stock photo host. Those images are now fetched through the app and appear in the export.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: fixed
|
|
3
|
+
date: 2026-08-09
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Fixed imported PDF/PowerPoint slide text rendering larger than its original box (often overlapping neighboring text) whenever the source page's physical size didn't match the deck canvas's assumed size — font sizes now scale by the same factor as element positions instead of a fixed point-to-pixel conversion.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: fixed
|
|
3
|
+
date: 2026-08-09
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Fixed decks with many slides loading slowly and rendering incorrectly in the editor. Every slide thumbnail measured its full layout on mount, so a long deck forced hundreds of page reflows at once; off-screen thumbnails now wait until they scroll into view, and the browser skips painting them entirely until then. The hover buttons on each thumbnail also no longer blur what is behind them, which was making the rail flicker and leaving dark patches over the editor.
|