@agent-native/core 0.80.10 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +53 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +108 -15
  5. package/corpus/core/src/cli/design-connect.ts +419 -19
  6. package/corpus/core/src/client/AssistantChat.tsx +123 -26
  7. package/corpus/core/src/client/ConnectBuilderCard.tsx +1 -0
  8. package/corpus/core/src/client/chat/index.ts +1 -0
  9. package/corpus/core/src/client/chat/run-recovery.tsx +9 -7
  10. package/corpus/core/src/client/chat-view-transition.ts +33 -2
  11. package/corpus/core/src/client/composer/PromptComposer.tsx +21 -2
  12. package/corpus/core/src/client/index.ts +1 -0
  13. package/corpus/core/src/client/org/OrgSwitcher.tsx +26 -4
  14. package/corpus/core/src/client/sharing/ShareButton.tsx +3 -3
  15. package/corpus/core/src/client/sse-event-processor.ts +9 -0
  16. package/corpus/core/src/client/use-agent-chat-home-handoff.ts +31 -3
  17. package/corpus/core/src/db/client.ts +29 -2
  18. package/corpus/core/src/provider-api/index.ts +29 -0
  19. package/corpus/core/src/server/core-routes-plugin.ts +58 -20
  20. package/corpus/core/src/styles/agent-native.css +54 -0
  21. package/corpus/core/src/usage/store.ts +2 -2
  22. package/corpus/templates/analytics/app/components/layout/Layout.tsx +118 -10
  23. package/corpus/templates/analytics/app/components/layout/layout-route-policy.ts +7 -0
  24. package/corpus/templates/analytics/app/global.css +8 -0
  25. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +7 -1
  26. package/corpus/templates/analytics/app/lib/chat-handoff.ts +34 -0
  27. package/corpus/templates/analytics/app/pages/Ask.tsx +9 -18
  28. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -2
  29. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +109 -21
  30. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +4 -6
  31. package/corpus/templates/analytics/changelog/2026-06-30-ask-opens-a-fresh-chat-unless-you-were-just-chatting-and-das.md +6 -0
  32. package/corpus/templates/analytics/changelog/2026-06-30-dashboard-email-reports-are-more-reliable-and-use-cleaner.md +6 -0
  33. package/corpus/templates/analytics/changelog/2026-06-30-dashboard-toolbar-controls-use-a-quieter-share-button-and-ve.md +6 -0
  34. package/corpus/templates/analytics/changelog/2026-06-30-session-replay-rows-show-whole-minute-durations-in-the-playl.md +6 -0
  35. package/corpus/templates/analytics/changelog/2026-06-30-session-replays-now-render-captured-styling-and-keep-the-eve.md +6 -0
  36. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +16 -3
  37. package/corpus/templates/analytics/server/lib/dashboard-report.ts +31 -14
  38. package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +9 -2
  39. package/corpus/templates/assets/AGENTS.md +4 -0
  40. package/corpus/templates/assets/actions/_tool-activity.ts +46 -0
  41. package/corpus/templates/assets/actions/generate-image-batch.ts +26 -5
  42. package/corpus/templates/assets/actions/generate-image.ts +118 -67
  43. package/corpus/templates/assets/actions/list-draft-assets.ts +50 -0
  44. package/corpus/templates/assets/actions/open-asset-picker.ts +9 -0
  45. package/corpus/templates/assets/actions/rerun-generation-run.ts +52 -31
  46. package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +100 -0
  47. package/corpus/templates/assets/app/global.css +15 -0
  48. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +4 -0
  49. package/corpus/templates/assets/app/i18n/zh-TW.ts +7 -0
  50. package/corpus/templates/assets/app/i18n-data.ts +61 -0
  51. package/corpus/templates/assets/app/routes/_index.tsx +4 -0
  52. package/corpus/templates/assets/app/routes/library.tsx +233 -52
  53. package/corpus/templates/assets/changelog/2026-06-29-image-generation-can-now-render-requested-text-and-respect-b.md +6 -0
  54. package/corpus/templates/assets/changelog/2026-06-30-image-generation-no-longer-looks-stuck-while-the-provider-is-still-working.md +6 -0
  55. package/corpus/templates/assets/changelog/2026-06-30-tagged-presets-now-control-the-image-aspect-ratio.md +6 -0
  56. package/corpus/templates/assets/changelog/2026-06-30-the-assets-picker-now-supports-a-vertical-embedded-layout-fo.md +6 -0
  57. package/corpus/templates/assets/server/lib/generation.ts +135 -11
  58. package/corpus/templates/assets/shared/api.ts +4 -0
  59. package/corpus/templates/clips/actions/finalize-recording.ts +1 -12
  60. package/corpus/templates/clips/actions/list-ai-requests.ts +60 -0
  61. package/corpus/templates/clips/app/hooks/use-auto-title.ts +24 -25
  62. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +10 -5
  63. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -8
  64. package/corpus/templates/clips/changelog/2026-06-30-extension-save-recovery-avoids-false-upload-failures.md +6 -0
  65. package/corpus/templates/clips/changelog/2026-06-30-longer-chrome-extension-recordings-now-keep-saving-reliably-.md +6 -0
  66. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
  67. package/corpus/templates/clips/chrome-extension/src/background.ts +19 -10
  68. package/corpus/templates/clips/chrome-extension/src/content-script.ts +38 -12
  69. package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +224 -0
  70. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +119 -16
  71. package/corpus/templates/clips/chrome-extension/src/overlay.ts +16 -0
  72. package/corpus/templates/clips/server/lib/recording-upload-state.ts +48 -0
  73. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +9 -1
  74. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +63 -13
  75. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +74 -0
  76. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +32 -0
  77. package/corpus/templates/design/AGENTS.md +27 -0
  78. package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +1 -1
  79. package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +5 -5
  80. package/corpus/templates/design/actions/apply-component-prop-edit.ts +76 -25
  81. package/corpus/templates/design/actions/apply-design-state.ts +17 -4
  82. package/corpus/templates/design/actions/apply-motion-edit.ts +76 -115
  83. package/corpus/templates/design/actions/apply-shader-fill.ts +148 -56
  84. package/corpus/templates/design/actions/capture-design-state.ts +27 -4
  85. package/corpus/templates/design/actions/connect-localhost.ts +59 -22
  86. package/corpus/templates/design/actions/delete-design.ts +20 -0
  87. package/corpus/templates/design/actions/export-zip.ts +23 -8
  88. package/corpus/templates/design/actions/generate-design.ts +53 -1
  89. package/corpus/templates/design/actions/get-component-details.ts +21 -26
  90. package/corpus/templates/design/actions/get-motion-timeline.ts +135 -10
  91. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +116 -0
  92. package/corpus/templates/design/actions/import-design-tokens.ts +521 -0
  93. package/corpus/templates/design/actions/index-design-tokens.ts +18 -5
  94. package/corpus/templates/design/actions/insert-design-native-asset.ts +268 -0
  95. package/corpus/templates/design/actions/insert-figma-library-asset.ts +233 -0
  96. package/corpus/templates/design/actions/list-design-extensions.ts +32 -10
  97. package/corpus/templates/design/actions/list-design-native-assets.ts +105 -0
  98. package/corpus/templates/design/actions/list-design-states.ts +19 -1
  99. package/corpus/templates/design/actions/list-figma-library-assets.ts +292 -0
  100. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +238 -0
  101. package/corpus/templates/design/actions/navigate.ts +18 -3
  102. package/corpus/templates/design/actions/open-component-source.ts +7 -2
  103. package/corpus/templates/design/actions/preview-component-prop-edit.ts +32 -26
  104. package/corpus/templates/design/actions/preview-shader-fill.ts +9 -11
  105. package/corpus/templates/design/actions/provider-api-catalog.ts +2 -2
  106. package/corpus/templates/design/actions/provider-api-docs.ts +1 -1
  107. package/corpus/templates/design/actions/provider-api-request.ts +3 -3
  108. package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +48 -0
  109. package/corpus/templates/design/actions/run-design-audit.ts +74 -10
  110. package/corpus/templates/design/actions/run-design-extension-action.ts +1 -1
  111. package/corpus/templates/design/actions/view-screen.ts +1 -1
  112. package/corpus/templates/design/actions/write-local-file.ts +213 -0
  113. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +244 -3197
  114. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +30 -20
  115. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +795 -289
  116. package/corpus/templates/design/app/components/design/EditPanel.tsx +635 -234
  117. package/corpus/templates/design/app/components/design/LayersPanel.tsx +124 -32
  118. package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +161 -0
  119. package/corpus/templates/design/app/components/design/MotionDock.tsx +244 -266
  120. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +491 -56
  121. package/corpus/templates/design/app/components/design/ReviewPanel.tsx +55 -67
  122. package/corpus/templates/design/app/components/design/StatesPanel.tsx +38 -63
  123. package/corpus/templates/design/app/components/design/TokensPanel.tsx +264 -8
  124. package/corpus/templates/design/app/components/design/bridge/codegen.ts +125 -0
  125. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +4037 -0
  126. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +62 -0
  127. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +272 -0
  128. package/corpus/templates/design/app/components/design/bridge/nav.bridge.ts +116 -0
  129. package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +24 -0
  130. package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +78 -0
  131. package/corpus/templates/design/app/components/design/bridge/tsconfig.json +17 -0
  132. package/corpus/templates/design/app/components/design/bridge/tweak.bridge.ts +28 -0
  133. package/corpus/templates/design/app/components/design/bridge/zoom.bridge.ts +43 -0
  134. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +45 -16
  135. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +88 -9
  136. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +94 -9
  137. package/corpus/templates/design/app/components/layout/Layout.tsx +19 -3
  138. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  139. package/corpus/templates/design/app/global.css +7 -0
  140. package/corpus/templates/design/app/hooks/use-navigation-state.ts +23 -0
  141. package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
  142. package/corpus/templates/design/app/i18n-data.ts +369 -0
  143. package/corpus/templates/design/app/lib/pending-generation.ts +1 -0
  144. package/corpus/templates/design/app/pages/DesignEditor.tsx +3024 -616
  145. package/corpus/templates/design/app/pages/Index.tsx +5 -1
  146. package/corpus/templates/design/changelog/2026-06-30-applying-the-one-click-fix-for-a-small-tap-target-accessibil.md +6 -0
  147. package/corpus/templates/design/changelog/2026-06-30-canvas-creation-screen-dragging-undo-redo-and-image-fill-edi.md +6 -0
  148. package/corpus/templates/design/changelog/2026-06-30-component-prop-edits-and-shader-fills-now-preserve-rapid-sam.md +6 -0
  149. package/corpus/templates/design/changelog/2026-06-30-design-can-browse-figma-library-components-and-insert-them-i.md +6 -0
  150. package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +6 -0
  151. package/corpus/templates/design/changelog/2026-06-30-design-now-has-native-components-embedded-media-and-figma-im.md +6 -0
  152. package/corpus/templates/design/changelog/2026-06-30-design-preview-now-includes-a-publish-app-waitlist-option-fr.md +6 -0
  153. package/corpus/templates/design/changelog/2026-06-30-design-s-left-rail-now-matches-the-sidebar-chrome-and-uses-t.md +6 -0
  154. package/corpus/templates/design/changelog/2026-06-30-design-s-tools-create-menu-now-stays-compact-instead-of-rend.md +6 -0
  155. package/corpus/templates/design/changelog/2026-06-30-design-starter-prompts-now-begin-generating-immediately-and-.md +6 -0
  156. package/corpus/templates/design/changelog/2026-06-30-design-token-edits-now-stay-visible-in-previews-and-token-li.md +6 -0
  157. package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +6 -0
  158. package/corpus/templates/design/changelog/2026-06-30-drawing-rectangles-on-the-all-screens-canvas-no-longer-flash.md +6 -0
  159. package/corpus/templates/design/changelog/2026-06-30-fixed-code-native-design-studio-edits-so-component-props-mot.md +6 -0
  160. package/corpus/templates/design/changelog/2026-06-30-fixed-visual-editing-hover-overlays-and-spacing-handles-so-s.md +6 -0
  161. package/corpus/templates/design/changelog/2026-06-30-motion-edits-now-save-automatically-without-a-separate-css-a.md +6 -0
  162. package/corpus/templates/design/changelog/2026-06-30-motion-timelines-now-reopen-as-editable-tracks-after-writing.md +6 -0
  163. package/corpus/templates/design/changelog/2026-06-30-new-design-prompts-with-uploaded-screenshots-work-reliably-o.md +6 -0
  164. package/corpus/templates/design/changelog/2026-06-30-screen-previews-in-all-screens-view-now-keep-rounded-outline.md +6 -0
  165. package/corpus/templates/design/changelog/2026-06-30-selection-outlines-now-sit-flush-on-rectangles-drawn-directl.md +6 -0
  166. package/corpus/templates/design/changelog/2026-06-30-share-options-use-a-tighter-design-editor-popover-with-compa.md +6 -0
  167. package/corpus/templates/design/changelog/2026-06-30-the-collapsed-motion-panel-now-stays-tucked-under-the-left-s.md +6 -0
  168. package/corpus/templates/design/changelog/2026-06-30-the-design-inspector-now-shows-states-and-review-in-a-tighte.md +6 -0
  169. package/corpus/templates/design/changelog/2026-06-30-the-sidebar-keeps-the-organization-picker-space-stable-while.md +6 -0
  170. package/corpus/templates/design/changelog/2026-06-30-tokens-can-now-be-imported-from-pasted-notes-code-files-fold.md +6 -0
  171. package/corpus/templates/design/e2e/global-setup.ts +94 -2
  172. package/corpus/templates/design/e2e/helpers.ts +168 -65
  173. package/corpus/templates/design/package.json +3 -1
  174. package/corpus/templates/design/server/db/schema.ts +23 -0
  175. package/corpus/templates/design/server/handlers/uploads.ts +22 -1
  176. package/corpus/templates/design/server/lib/provider-api.ts +7 -4
  177. package/corpus/templates/design/server/lib/verify-write-grant.ts +108 -0
  178. package/corpus/templates/design/server/plugins/db.ts +39 -0
  179. package/corpus/templates/design/server/register-secrets.ts +38 -0
  180. package/corpus/templates/design/shared/board-file.ts +228 -0
  181. package/corpus/templates/design/shared/board-objects.ts +288 -0
  182. package/corpus/templates/design/shared/code-layer.ts +52 -0
  183. package/corpus/templates/design/shared/component-model.ts +35 -0
  184. package/corpus/templates/design/shared/motion-compiler.ts +137 -15
  185. package/corpus/templates/design/shared/motion-timeline.ts +2 -2
  186. package/corpus/templates/design/shared/resolve-tweaks.ts +32 -9
  187. package/corpus/templates/design/tsconfig.json +2 -1
  188. package/corpus/templates/slides/AGENTS.md +9 -0
  189. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +4 -0
  190. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +4 -24
  191. package/corpus/templates/slides/app/lib/export-pdf-client.ts +29 -20
  192. package/corpus/templates/slides/app/lib/export-pptx-client.ts +365 -0
  193. package/corpus/templates/slides/app/pages/DeckEditor.tsx +12 -9
  194. package/corpus/templates/slides/app/vite-env.d.ts +18 -0
  195. package/corpus/templates/slides/changelog/2026-06-30-powerpoint-downloads-now-preserve-the-rendered-slide-layout-.md +6 -0
  196. package/corpus/templates/slides/changelog/2026-06-30-unavailable-decks-open-in-a-cleaner-full-height-centered-sta.md +6 -0
  197. package/corpus/templates/slides/package.json +1 -0
  198. package/corpus/templates/slides/vite.config.ts +1 -0
  199. package/dist/agent/production-agent.d.ts.map +1 -1
  200. package/dist/agent/production-agent.js +94 -10
  201. package/dist/agent/production-agent.js.map +1 -1
  202. package/dist/cli/design-connect.d.ts +25 -0
  203. package/dist/cli/design-connect.d.ts.map +1 -1
  204. package/dist/cli/design-connect.js +357 -18
  205. package/dist/cli/design-connect.js.map +1 -1
  206. package/dist/client/AssistantChat.d.ts +14 -0
  207. package/dist/client/AssistantChat.d.ts.map +1 -1
  208. package/dist/client/AssistantChat.js +115 -22
  209. package/dist/client/AssistantChat.js.map +1 -1
  210. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  211. package/dist/client/ConnectBuilderCard.js +1 -0
  212. package/dist/client/ConnectBuilderCard.js.map +1 -1
  213. package/dist/client/chat/index.d.ts +1 -1
  214. package/dist/client/chat/index.d.ts.map +1 -1
  215. package/dist/client/chat/index.js +1 -1
  216. package/dist/client/chat/index.js.map +1 -1
  217. package/dist/client/chat/run-recovery.d.ts.map +1 -1
  218. package/dist/client/chat/run-recovery.js +5 -5
  219. package/dist/client/chat/run-recovery.js.map +1 -1
  220. package/dist/client/chat-view-transition.d.ts +6 -0
  221. package/dist/client/chat-view-transition.d.ts.map +1 -1
  222. package/dist/client/chat-view-transition.js +23 -2
  223. package/dist/client/chat-view-transition.js.map +1 -1
  224. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  225. package/dist/client/composer/PromptComposer.js +3 -2
  226. package/dist/client/composer/PromptComposer.js.map +1 -1
  227. package/dist/client/index.d.ts +1 -1
  228. package/dist/client/index.d.ts.map +1 -1
  229. package/dist/client/index.js +1 -1
  230. package/dist/client/index.js.map +1 -1
  231. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  232. package/dist/client/org/OrgSwitcher.js +11 -4
  233. package/dist/client/org/OrgSwitcher.js.map +1 -1
  234. package/dist/client/sharing/ShareButton.js +3 -3
  235. package/dist/client/sharing/ShareButton.js.map +1 -1
  236. package/dist/client/sse-event-processor.d.ts.map +1 -1
  237. package/dist/client/sse-event-processor.js +10 -0
  238. package/dist/client/sse-event-processor.js.map +1 -1
  239. package/dist/client/use-agent-chat-home-handoff.d.ts +8 -2
  240. package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
  241. package/dist/client/use-agent-chat-home-handoff.js +20 -6
  242. package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
  243. package/dist/collab/awareness.d.ts +2 -2
  244. package/dist/collab/awareness.d.ts.map +1 -1
  245. package/dist/collab/routes.d.ts +2 -2
  246. package/dist/db/client.d.ts +1 -0
  247. package/dist/db/client.d.ts.map +1 -1
  248. package/dist/db/client.js +28 -2
  249. package/dist/db/client.js.map +1 -1
  250. package/dist/notifications/routes.d.ts +3 -3
  251. package/dist/observability/routes.d.ts +3 -3
  252. package/dist/progress/routes.d.ts +1 -1
  253. package/dist/provider-api/index.d.ts +5 -4
  254. package/dist/provider-api/index.d.ts.map +1 -1
  255. package/dist/provider-api/index.js +28 -0
  256. package/dist/provider-api/index.js.map +1 -1
  257. package/dist/resources/handlers.d.ts +3 -3
  258. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  259. package/dist/server/core-routes-plugin.d.ts +25 -0
  260. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  261. package/dist/server/core-routes-plugin.js +43 -18
  262. package/dist/server/core-routes-plugin.js.map +1 -1
  263. package/dist/server/transcribe-voice.d.ts +1 -1
  264. package/dist/styles/agent-native.css +54 -0
  265. package/dist/usage/store.js +2 -2
  266. package/dist/usage/store.js.map +1 -1
  267. package/package.json +1 -1
@@ -110,6 +110,11 @@ type SkipRange = {
110
110
  endMs: number;
111
111
  };
112
112
 
113
+ type ReplayViewportDimensions = {
114
+ width: number;
115
+ height: number;
116
+ };
117
+
113
118
  const DEFAULT_PLAYER_WIDTH = 1024;
114
119
  const DEFAULT_PLAYER_HEIGHT = 640;
115
120
  const DEFAULT_SPEED = 2;
@@ -334,9 +339,12 @@ function ReplayPlayer({
334
339
  height: number;
335
340
  } | null>(null);
336
341
  const [fitScale, setFitScale] = useState(1);
342
+ const initialDims = useMemo(() => replayViewportDimensions(events), [events]);
337
343
 
338
- const playerWidth = streamedDims?.width ?? DEFAULT_PLAYER_WIDTH;
339
- const playerHeight = streamedDims?.height ?? DEFAULT_PLAYER_HEIGHT;
344
+ const playerWidth =
345
+ streamedDims?.width ?? initialDims?.width ?? DEFAULT_PLAYER_WIDTH;
346
+ const playerHeight =
347
+ streamedDims?.height ?? initialDims?.height ?? DEFAULT_PLAYER_HEIGHT;
340
348
  const skipRanges = useMemo(() => buildIdleSkipRanges(events), [events]);
341
349
  const skipRangesRef = useLiveRef(skipRanges);
342
350
  const skipInactiveRef = useLiveRef(skipInactive);
@@ -414,7 +422,7 @@ function ReplayPlayer({
414
422
  if (cancelled || !stageRootRef.current) return;
415
423
 
416
424
  stageRootRef.current.innerHTML = "";
417
- setStreamedDims(null);
425
+ setStreamedDims(initialDims);
418
426
  localReplayer = new Replayer(events as any[], {
419
427
  root: stageRootRef.current,
420
428
  speed: DEFAULT_SPEED,
@@ -431,6 +439,7 @@ function ReplayPlayer({
431
439
  const meta = localReplayer.getMetaData?.();
432
440
  const total = Number(meta?.totalTime ?? replayDuration(events));
433
441
  setTotalTime(Number.isFinite(total) ? total : 0);
442
+ applyReplayFrameDimensions(localReplayer, initialDims);
434
443
  localReplayer.on?.("finish", () => {
435
444
  setPlaying(false);
436
445
  const finalTime = Number(localReplayer.getCurrentTime?.() ?? total);
@@ -438,10 +447,20 @@ function ReplayPlayer({
438
447
  });
439
448
  localReplayer.on?.("resize", (payload: unknown) => {
440
449
  const dims = payload as { width?: unknown; height?: unknown };
441
- if (typeof dims.width === "number" && typeof dims.height === "number") {
442
- setStreamedDims({ width: dims.width, height: dims.height });
450
+ const nextDims = normalizeReplayDimensions(dims.width, dims.height);
451
+ if (nextDims) {
452
+ applyReplayFrameDimensions(localReplayer, nextDims);
453
+ revealReplayFrame(localReplayer);
454
+ setStreamedDims(nextDims);
443
455
  }
444
456
  });
457
+ localReplayer.on?.("fullsnapshot-rebuilded", () => {
458
+ applyReplayFrameDimensions(
459
+ localReplayer,
460
+ replayViewportDimensions(events) ?? initialDims,
461
+ );
462
+ revealReplayFrame(localReplayer);
463
+ });
445
464
  updateTime(0);
446
465
  setStatus("ready");
447
466
  try {
@@ -456,6 +475,13 @@ function ReplayPlayer({
456
475
  }
457
476
  setPlaying(false);
458
477
  }
478
+ window.requestAnimationFrame(() => {
479
+ applyReplayFrameDimensions(
480
+ localReplayer,
481
+ replayViewportDimensions(events) ?? initialDims,
482
+ );
483
+ revealReplayFrame(localReplayer);
484
+ });
459
485
  }
460
486
 
461
487
  void loadReplay().catch((loadError: any) => {
@@ -479,7 +505,7 @@ function ReplayPlayer({
479
505
  replayerRef.current = null;
480
506
  if (stageRootRef.current) stageRootRef.current.innerHTML = "";
481
507
  };
482
- }, [events, t, updateTime]);
508
+ }, [events, initialDims, t, updateTime]);
483
509
 
484
510
  useEffect(() => {
485
511
  if (!playing || status !== "ready") {
@@ -842,7 +868,7 @@ function ReplayTimeline({
842
868
  const t = useT();
843
869
  const visibleMarkers = markers.slice(0, 120);
844
870
  return (
845
- <Card className="flex min-h-0 overflow-hidden">
871
+ <Card className="analytics-session-detail-timeline min-h-0 overflow-hidden">
846
872
  <CardContent className="flex min-h-0 flex-1 flex-col p-0">
847
873
  <div className="shrink-0 border-b px-3 py-2">
848
874
  <div className="flex items-center gap-2 text-sm font-semibold">
@@ -925,7 +951,7 @@ function DetailSkeleton() {
925
951
  return (
926
952
  <div className="analytics-session-detail-workbench grid min-h-0 flex-1 gap-3">
927
953
  <Skeleton className="h-full min-h-[420px] w-full" />
928
- <Skeleton className="h-full min-h-[420px] w-full" />
954
+ <Skeleton className="analytics-session-detail-timeline h-full min-h-[420px] w-full" />
929
955
  </div>
930
956
  );
931
957
  }
@@ -1008,13 +1034,13 @@ function sanitizeMutationData(data: AnyRecord): AnyRecord {
1008
1034
  typeof copy.value === "string" &&
1009
1035
  containsStylesheetNetworkLoad(copy.value)
1010
1036
  ) {
1011
- copy.value = "";
1037
+ copy.value = sanitizeCssText(copy.value);
1012
1038
  }
1013
1039
  if (
1014
1040
  typeof copy.textContent === "string" &&
1015
1041
  containsStylesheetNetworkLoad(copy.textContent)
1016
1042
  ) {
1017
- copy.textContent = "";
1043
+ copy.textContent = sanitizeCssText(copy.textContent);
1018
1044
  }
1019
1045
  return copy;
1020
1046
  });
@@ -1035,21 +1061,12 @@ function sanitizeSerializedNode(node: unknown): AnyRecord | null {
1035
1061
  childNodes: [],
1036
1062
  };
1037
1063
  }
1038
- if (next.type === 2 && tagName === "style") {
1039
- return {
1040
- ...next,
1041
- attributes: isRecord(next.attributes)
1042
- ? sanitizeAttributes(next.attributes)
1043
- : {},
1044
- childNodes: [],
1045
- };
1046
- }
1047
1064
  if (
1048
1065
  next.type === 3 &&
1049
1066
  typeof next.textContent === "string" &&
1050
1067
  containsStylesheetNetworkLoad(next.textContent)
1051
1068
  ) {
1052
- next.textContent = "";
1069
+ next.textContent = sanitizeCssText(next.textContent);
1053
1070
  }
1054
1071
  if (
1055
1072
  next.type === 2 &&
@@ -1073,6 +1090,13 @@ function containsStylesheetNetworkLoad(value: string): boolean {
1073
1090
  return /@import\b/i.test(value) || /\burl\s*\(/i.test(value);
1074
1091
  }
1075
1092
 
1093
+ function sanitizeCssText(value: string): string {
1094
+ if (!containsStylesheetNetworkLoad(value)) return value;
1095
+ return value
1096
+ .replace(/@import\s+(?:url\s*\()?[^;{}]+;?/gi, "")
1097
+ .replace(/\burl\s*\((?:\\.|[^\\)])*\)/gi, "none");
1098
+ }
1099
+
1076
1100
  function sanitizeAttributes(attributes: AnyRecord): AnyRecord {
1077
1101
  const next: AnyRecord = {};
1078
1102
  for (const [key, value] of Object.entries(attributes)) {
@@ -1080,7 +1104,11 @@ function sanitizeAttributes(attributes: AnyRecord): AnyRecord {
1080
1104
  if (normalized.startsWith("on")) continue;
1081
1105
  if (normalized === "srcdoc") continue;
1082
1106
  if (isReplayResourceAttribute(normalized)) continue;
1083
- if (normalized === "style" && /\burl\s*\(/i.test(String(value))) continue;
1107
+ if (normalized === "style") {
1108
+ const style = sanitizeCssText(String(value));
1109
+ if (style.trim()) next[key] = style;
1110
+ continue;
1111
+ }
1084
1112
  next[key] = value;
1085
1113
  }
1086
1114
  return next;
@@ -1240,6 +1268,66 @@ function currentUrlAt(events: AnyReplayEvent[], currentTime: number): string {
1240
1268
  return current;
1241
1269
  }
1242
1270
 
1271
+ export function replayViewportDimensions(
1272
+ events: AnyReplayEvent[],
1273
+ ): ReplayViewportDimensions | null {
1274
+ for (const event of events) {
1275
+ if (event.type !== RRWEB_EVENT_TYPE.Meta) continue;
1276
+ const dims = normalizeReplayDimensions(
1277
+ event.data?.width,
1278
+ event.data?.height,
1279
+ );
1280
+ if (dims) return dims;
1281
+ }
1282
+ return null;
1283
+ }
1284
+
1285
+ function normalizeReplayDimensions(
1286
+ width: unknown,
1287
+ height: unknown,
1288
+ ): ReplayViewportDimensions | null {
1289
+ if (
1290
+ typeof width !== "number" ||
1291
+ typeof height !== "number" ||
1292
+ !Number.isFinite(width) ||
1293
+ !Number.isFinite(height) ||
1294
+ width <= 0 ||
1295
+ height <= 0
1296
+ ) {
1297
+ return null;
1298
+ }
1299
+ return {
1300
+ width: Math.round(width),
1301
+ height: Math.round(height),
1302
+ };
1303
+ }
1304
+
1305
+ function applyReplayFrameDimensions(
1306
+ replayer: any,
1307
+ dims: ReplayViewportDimensions | null,
1308
+ ) {
1309
+ const width = dims?.width ?? DEFAULT_PLAYER_WIDTH;
1310
+ const height = dims?.height ?? DEFAULT_PLAYER_HEIGHT;
1311
+ const wrapper = replayer?.wrapper as HTMLElement | undefined;
1312
+ const iframe = replayer?.iframe as HTMLIFrameElement | undefined;
1313
+ const mouseTail = replayer?.mouseTail as HTMLCanvasElement | undefined;
1314
+ for (const element of [wrapper, iframe]) {
1315
+ if (!element) continue;
1316
+ element.style.width = `${width}px`;
1317
+ element.style.height = `${height}px`;
1318
+ }
1319
+ for (const element of [iframe, mouseTail]) {
1320
+ if (!element) continue;
1321
+ element.setAttribute("width", String(width));
1322
+ element.setAttribute("height", String(height));
1323
+ }
1324
+ }
1325
+
1326
+ function revealReplayFrame(replayer: any) {
1327
+ const iframe = replayer?.iframe as HTMLIFrameElement | undefined;
1328
+ if (iframe) iframe.style.display = "inherit";
1329
+ }
1330
+
1243
1331
  function replayStartedAt(events: AnyReplayEvent[]): number {
1244
1332
  const first = events.find((event) =>
1245
1333
  Number.isFinite(Number(event.timestamp)),
@@ -235,7 +235,7 @@ export default function SessionsPage() {
235
235
  >
236
236
  <span className="inline-flex h-10 w-[92px] items-center justify-center gap-2 rounded-md bg-primary/10 font-medium text-primary">
237
237
  <IconPlayerPlay className="h-4 w-4 fill-current" />
238
- {formatDuration(recording.durationMs)}
238
+ {formatSessionDuration(recording.durationMs)}
239
239
  </span>
240
240
  <span className="min-w-0">
241
241
  <span className="block truncate text-sm font-medium text-foreground">
@@ -523,13 +523,11 @@ function formatDateTime(value: string): string {
523
523
  }).format(date);
524
524
  }
525
525
 
526
- function formatDuration(ms: number | null): string {
527
- if (!ms || !Number.isFinite(ms) || ms <= 0) return "0s";
526
+ export function formatSessionDuration(ms: number | null): string {
527
+ if (!ms || !Number.isFinite(ms) || ms <= 0) return "0m";
528
528
  const seconds = Math.round(ms / 1000);
529
- if (seconds < 60) return `${seconds}s`;
530
529
  const minutes = Math.floor(seconds / 60);
531
- const remainingSeconds = seconds % 60;
532
- if (minutes < 60) return `${minutes}m ${remainingSeconds}s`;
530
+ if (minutes < 60) return `${minutes}m`;
533
531
  const hours = Math.floor(minutes / 60);
534
532
  const remainingMinutes = minutes % 60;
535
533
  return `${hours}h ${remainingMinutes}m`;
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-06-30
4
+ ---
5
+
6
+ Ask opens a fresh chat unless you were just chatting, and dashboard navigation keeps the sidebar closed from an empty Ask state.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-30
4
+ ---
5
+
6
+ Dashboard email reports are more reliable and use cleaner header copy.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-06-30
4
+ ---
5
+
6
+ Dashboard toolbar controls use a quieter share button and vertical actions menu.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-06-30
4
+ ---
5
+
6
+ Session replay rows show whole-minute durations in the playlist.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-30
4
+ ---
5
+
6
+ Session replays now render captured styling and keep the event timeline out of compact layouts.
@@ -41,14 +41,27 @@ export async function runDashboardReportsOnce(): Promise<{
41
41
  for (const sub of batch) {
42
42
  processed++;
43
43
  try {
44
- await runWithRequestContext(
44
+ const result = await runWithRequestContext(
45
45
  {
46
46
  userEmail: sub.ownerEmail,
47
47
  orgId: sub.orgId ?? undefined,
48
48
  },
49
- () => sendDashboardReportSubscription(sub),
49
+ () =>
50
+ sendDashboardReportSubscription(sub, { requireScreenshot: true }),
50
51
  );
51
- await markDashboardReportResult(sub, "success");
52
+ if (result.screenshotAttached) {
53
+ await markDashboardReportResult(sub, "success");
54
+ } else {
55
+ failed++;
56
+ const message = result.screenshotError
57
+ ? `Dashboard screenshot unavailable: ${result.screenshotError}`
58
+ : "Dashboard screenshot unavailable";
59
+ console.error(
60
+ `[dashboard-report] Subscription ${sub.id} sent without a screenshot:`,
61
+ message,
62
+ );
63
+ await markDashboardReportResult(sub, "error", message);
64
+ }
52
65
  } catch (err: any) {
53
66
  failed++;
54
67
  const message = err?.message ?? String(err);
@@ -42,8 +42,8 @@ const DASHBOARD_REPORT_SCREENSHOT_PARAM = "reportScreenshot";
42
42
  const DASHBOARD_REPORT_SETTINGS_PARAM = "reportSettings";
43
43
  const DASHBOARD_REPORT_CID = "dashboard-report-snapshot";
44
44
  const LOCAL_SCREENSHOT_TIMEOUT_MS = 90_000;
45
- const SERVERLESS_SCREENSHOT_TIMEOUT_MS = 25_000;
46
- const SERVERLESS_SECOND_READY_TIMEOUT_MS = 10_000;
45
+ const SERVERLESS_SCREENSHOT_TIMEOUT_MS = 60_000;
46
+ const SERVERLESS_SECOND_READY_TIMEOUT_MS = 30_000;
47
47
  const MAX_SCREENSHOT_VIEWPORT_HEIGHT = 30_000;
48
48
  const SCREENSHOT_VIEWPORT_PADDING = 64;
49
49
 
@@ -249,11 +249,28 @@ async function launchScreenshotBrowser() {
249
249
  }
250
250
 
251
251
  function screenshotTimeoutMs(): number {
252
+ const configured = positiveIntEnv("DASHBOARD_REPORT_SCREENSHOT_TIMEOUT_MS");
253
+ if (configured) return configured;
252
254
  return isServerlessBrowserRuntime()
253
255
  ? SERVERLESS_SCREENSHOT_TIMEOUT_MS
254
256
  : LOCAL_SCREENSHOT_TIMEOUT_MS;
255
257
  }
256
258
 
259
+ function secondReadyTimeoutMs(): number {
260
+ const configured = positiveIntEnv("DASHBOARD_REPORT_SECOND_READY_TIMEOUT_MS");
261
+ if (configured) return configured;
262
+ return isServerlessBrowserRuntime()
263
+ ? SERVERLESS_SECOND_READY_TIMEOUT_MS
264
+ : screenshotTimeoutMs();
265
+ }
266
+
267
+ function positiveIntEnv(name: string): number | null {
268
+ const raw = process.env[name]?.trim();
269
+ if (!raw) return null;
270
+ const parsed = Number.parseInt(raw, 10);
271
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
272
+ }
273
+
257
274
  async function waitForDashboardReportReady(
258
275
  page: any,
259
276
  timeout: number,
@@ -393,12 +410,7 @@ async function captureDashboardPng(
393
410
  await capture.waitFor({ state: "visible", timeout });
394
411
  await waitForDashboardReportReady(page, timeout);
395
412
  await scrollDashboardForLazyRendering(page);
396
- await waitForDashboardReportReady(
397
- page,
398
- isServerlessBrowserRuntime()
399
- ? SERVERLESS_SECOND_READY_TIMEOUT_MS
400
- : timeout,
401
- );
413
+ await waitForDashboardReportReady(page, secondReadyTimeoutMs());
402
414
 
403
415
  await fitViewportToDashboardCapture(page, capture, attempt.viewport);
404
416
  await capture.scrollIntoViewIfNeeded();
@@ -478,18 +490,15 @@ function renderReportEmailHtml(
478
490
  return `<!doctype html>
479
491
  <html>
480
492
  <body style="margin:0;padding:24px;background:#ffffff;color:#171717;font-family:Inter,Arial,sans-serif;">
481
- <h3 style="margin:0 0 8px;font-size:18px;line-height:1.35;font-weight:600;">
482
- Here's the report of <a href="${dashboardUrl}" style="color:#2563eb;text-decoration:none;">${title}</a> for ${date}.
483
- </h3>
493
+ <p style="margin:0 0 12px;font-size:15px;line-height:1.4;font-weight:600;">
494
+ Here's your report of <a href="${dashboardUrl}" style="color:#2563eb;text-decoration:none;">${title}</a> for ${date}
495
+ </p>
484
496
  ${screenshotBlock}
485
497
  <p style="margin:18px 0 0;color:#525866;font-size:13px;line-height:1.45;">
486
498
  <a href="${dashboardUrl}" style="color:#2563eb;text-decoration:none;">Open dashboard</a>
487
499
  <span style="color:#9ca3af;"> · </span>
488
500
  <a href="${reportSettingsUrl}" style="color:#2563eb;text-decoration:none;">Edit subscription settings</a>
489
501
  </p>
490
- <p style="margin:6px 0 0;color:#6b7280;font-size:12px;line-height:1.45;">
491
- Change recipients, delivery time, filters, or turn this report on/off.
492
- </p>
493
502
  </body>
494
503
  </html>`;
495
504
  }
@@ -521,6 +530,7 @@ function reportFilename(title: string): string {
521
530
 
522
531
  export async function sendDashboardReportSubscription(
523
532
  sub: DashboardReportSubscription,
533
+ options: { requireScreenshot?: boolean } = {},
524
534
  ): Promise<{
525
535
  dashboardUrl: string;
526
536
  recipientCount: number;
@@ -530,6 +540,13 @@ export async function sendDashboardReportSubscription(
530
540
  }> {
531
541
  const snapshot = await collectReportSnapshot(sub);
532
542
  const capture = await captureDashboardPngWithFallback(sub, snapshot);
543
+ if (!capture.png && options.requireScreenshot) {
544
+ throw new Error(
545
+ capture.error
546
+ ? `Dashboard screenshot unavailable: ${capture.error}`
547
+ : "Dashboard screenshot unavailable",
548
+ );
549
+ }
533
550
  const screenshotAttached = Boolean(capture.png);
534
551
  const html = renderReportEmailHtml(snapshot, { screenshotAttached });
535
552
  const text = renderReportText(snapshot, { screenshotAttached });
@@ -15,8 +15,15 @@ Use this skill before calling `generate-image`, `generate-image-batch`, or
15
15
  `presetId`, and `media-type` references choose image generation versus video
16
16
  generation. Call `view-screen` when the user says "this library" or "this
17
17
  image" and you need fresh IDs. The image model may default from the composer
18
- image-model picker; all other generation settings should be explicit action
19
- args, preset values, or action schema defaults.
18
+ image-model picker.
19
+ - A tagged `@preset` (presetId) owns `aspectRatio`, `imageSize`, `model`,
20
+ `tier`, and `category`. When a preset is set, do NOT pass those args yourself —
21
+ leave them out so the preset's saved values are used. You cannot see the
22
+ preset's settings from the presetId, so passing your own guess silently
23
+ overrides the preset (this is the usual cause of a preset's aspect ratio being
24
+ ignored). Pass one of these args alongside a preset ONLY when the user
25
+ explicitly asks for a value that differs from the preset. When there is no
26
+ preset, set them explicitly or rely on the action schema defaults.
20
27
  - Use category-tagged references. Blog heroes should prefer `hero`; diagrams
21
28
  should prefer `diagram`; product imagery should include `product` and `logo`
22
29
  references.
@@ -47,6 +47,10 @@ prompt, aspectRatio }`.
47
47
  composer is empty. The image model is the only remaining composer-side
48
48
  default; the image-model picker writes `imageGenerationModel`, which image
49
49
  generation actions may use when `model` is omitted.
50
+ - For exact visible copy inside a generated image, pass `embeddedText` and
51
+ optional `textPlacement` to `generate-image` or each `generate-image-batch`
52
+ slot. Keep the general `prompt` for creative direction; the structured text
53
+ fields are what allow the pipeline to render copy instead of suppressing it.
50
54
  - `asset-variants` is the shared live generation tray state. New image
51
55
  candidates should appear there through `generate-image` or
52
56
  `generate-image-batch`; do not invent page-local progress surfaces.
@@ -0,0 +1,46 @@
1
+ import type { ActionRunContext } from "@agent-native/core/action";
2
+
3
+ const DEFAULT_TOOL_ACTIVITY_INTERVAL_MS = 8_000;
4
+
5
+ type ToolActivityOptions = {
6
+ label: string;
7
+ ongoingLabel?: string;
8
+ intervalMs?: number;
9
+ tool?: string;
10
+ };
11
+
12
+ function canEmitToolActivity(
13
+ context: ActionRunContext | undefined,
14
+ ): context is ActionRunContext & Required<Pick<ActionRunContext, "send">> {
15
+ return context?.caller === "tool" && typeof context.send === "function";
16
+ }
17
+
18
+ export async function withToolActivity<T>(
19
+ context: ActionRunContext | undefined,
20
+ options: ToolActivityOptions,
21
+ work: () => Promise<T>,
22
+ ): Promise<T> {
23
+ if (!canEmitToolActivity(context)) return work();
24
+
25
+ const tool = options.tool ?? context.actionName;
26
+ const sendActivity = (label: string) => {
27
+ context.send({
28
+ type: "activity",
29
+ label,
30
+ ...(tool ? { tool } : {}),
31
+ });
32
+ };
33
+
34
+ sendActivity(options.label);
35
+ const interval = setInterval(
36
+ () => sendActivity(options.ongoingLabel ?? options.label),
37
+ options.intervalMs ?? DEFAULT_TOOL_ACTIVITY_INTERVAL_MS,
38
+ );
39
+ interval.unref?.();
40
+
41
+ try {
42
+ return await work();
43
+ } finally {
44
+ clearInterval(interval);
45
+ }
46
+ }
@@ -18,7 +18,6 @@ import {
18
18
  STYLE_STRENGTHS,
19
19
  } from "../shared/api.js";
20
20
  import { requireGenerationSessionInLibrary } from "./_helpers.js";
21
- import { readImageModelDefault } from "./_image-model-default.js";
22
21
  import generateImage from "./generate-image.js";
23
22
  import { upsertVariantSlot } from "./variant-slots.js";
24
23
 
@@ -35,14 +34,36 @@ export default defineAction({
35
34
  "Brand kit/library ID. Pass the refId from a brand-kit @mention, or choose a kit from view-screen/list-libraries.",
36
35
  ),
37
36
  collectionId: z.string().optional(),
38
- presetId: z.string().optional(),
37
+ presetId: z
38
+ .string()
39
+ .optional()
40
+ .describe(
41
+ "Generation preset ID (from a @preset mention or list-generation-presets). The preset already defines aspectRatio, imageSize, model, tier, and category. When you set presetId, OMIT each slot's aspectRatio/imageSize and the top-level model/tier so the preset's values are used; only pass one when the user explicitly asks for a value that differs from the preset.",
42
+ ),
39
43
  sessionId: z.string().optional(),
40
44
  slots: z
41
45
  .array(
42
46
  z.object({
43
47
  slotId: z.string(),
44
48
  prompt: z.string().min(1),
45
- aspectRatio: z.enum(ASPECT_RATIOS).optional(),
49
+ embeddedText: z
50
+ .string()
51
+ .optional()
52
+ .describe(
53
+ "Exact words to render inside the image, spelled exactly. When set, the image is allowed to contain this text; when omitted, the image avoids embedded text.",
54
+ ),
55
+ textPlacement: z
56
+ .string()
57
+ .optional()
58
+ .describe(
59
+ "Where/how the embedded text should appear, e.g. 'centered headline', 'lower-left label'.",
60
+ ),
61
+ aspectRatio: z
62
+ .enum(ASPECT_RATIOS)
63
+ .optional()
64
+ .describe(
65
+ "Slot aspect ratio. When a presetId is set, omit this — the preset's aspect ratio is used unless the user explicitly asks for a different ratio for this slot.",
66
+ ),
46
67
  imageSize: z.enum(IMAGE_SIZES).optional(),
47
68
  categories: z.array(z.enum(IMAGE_CATEGORIES)).optional(),
48
69
  referenceAssetIds: z.array(z.string()).optional(),
@@ -78,7 +99,6 @@ export default defineAction({
78
99
  parallelSafe: true,
79
100
  timeoutMs: IMAGE_GENERATION_TOOL_TIMEOUT_MS,
80
101
  run: async ({ slots, ...inputBase }, context?: ActionRunContext) => {
81
- const imageModelDefault = await readImageModelDefault();
82
102
  const libraryId = inputBase.libraryId;
83
103
  if (!libraryId) {
84
104
  throw new Error(
@@ -88,7 +108,6 @@ export default defineAction({
88
108
  const base = {
89
109
  ...inputBase,
90
110
  libraryId,
91
- model: inputBase.model ?? imageModelDefault,
92
111
  };
93
112
  await assertAccess("asset-library", base.libraryId, "editor");
94
113
  if (base.sessionId) {
@@ -123,6 +142,8 @@ export default defineAction({
123
142
  presetId: base.presetId,
124
143
  sessionId: base.sessionId,
125
144
  prompt: slot.prompt,
145
+ embeddedText: slot.embeddedText,
146
+ textPlacement: slot.textPlacement,
126
147
  aspectRatio: slot.aspectRatio,
127
148
  imageSize: slot.imageSize,
128
149
  model: base.model,