@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
@@ -21,6 +21,7 @@ import {
21
21
  DEFAULT_GENERATION_REFERENCE_LIMIT,
22
22
  generateWithManagedImageProvider,
23
23
  isImageGenerationSetupError,
24
+ resolveImageModelForRequest,
24
25
  selectReferences,
25
26
  } from "../server/lib/generation.js";
26
27
  import { compositeLogo } from "../server/lib/image-processing.js";
@@ -35,7 +36,6 @@ import {
35
36
  IMAGE_SIZES,
36
37
  STYLE_STRENGTHS,
37
38
  type ImageCategory,
38
- type ImageModel,
39
39
  type ImageQualityTier,
40
40
  type StyleBrief,
41
41
  } from "../shared/api.js";
@@ -44,22 +44,11 @@ import {
44
44
  serializeAsset,
45
45
  } from "./_helpers.js";
46
46
  import { readImageModelDefault } from "./_image-model-default.js";
47
+ import { withToolActivity } from "./_tool-activity.js";
47
48
  import { upsertVariantSlot, wasVariantSlotDismissed } from "./variant-slots.js";
48
49
 
49
50
  const IMAGE_GENERATION_TOOL_TIMEOUT_MS = 12 * 60_000;
50
51
 
51
- function resolveModelForTier(
52
- tier: ImageQualityTier | undefined,
53
- category: ImageCategory | undefined,
54
- ): ImageModel | undefined {
55
- if (!tier) return undefined;
56
- if (tier === "fast") return "gemini-3.1-flash-image";
57
- if (tier === "best") return "gemini-3-pro-image";
58
- return ["hero", "landing", "logo", "campaign"].includes(category ?? "")
59
- ? "gemini-3-pro-image"
60
- : "gemini-3.1-flash-image";
61
- }
62
-
63
52
  export default defineAction({
64
53
  description:
65
54
  "Generate one brand-consistent image from a brand kit/library. This is synchronous for images and returns the final asset with preview/download/embed URLs. Use @brand-kit mentions as libraryId and @preset mentions as presetId when present. Use generate-image-batch for multiple independent slots; do not poll image runs after this action returns.",
@@ -71,11 +60,38 @@ export default defineAction({
71
60
  "Brand kit/library ID. Pass the refId from a brand-kit @mention, or choose a kit from view-screen/list-libraries.",
72
61
  ),
73
62
  collectionId: z.string().optional(),
74
- presetId: z.string().optional(),
63
+ presetId: z
64
+ .string()
65
+ .optional()
66
+ .describe(
67
+ "Generation preset ID (from a @preset mention or list-generation-presets). A preset already defines aspectRatio, imageSize, model, tier, and category. When you set presetId, OMIT those args so the preset's values are used; only pass one of them when the user explicitly asks for a value that differs from the preset.",
68
+ ),
75
69
  sessionId: z.string().optional(),
76
70
  prompt: z.string().min(1),
77
- aspectRatio: z.enum(ASPECT_RATIOS).optional(),
78
- imageSize: z.enum(IMAGE_SIZES).optional(),
71
+ embeddedText: z
72
+ .string()
73
+ .optional()
74
+ .describe(
75
+ "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.",
76
+ ),
77
+ textPlacement: z
78
+ .string()
79
+ .optional()
80
+ .describe(
81
+ "Where/how the embedded text should appear, e.g. 'centered headline', 'lower-left label'.",
82
+ ),
83
+ aspectRatio: z
84
+ .enum(ASPECT_RATIOS)
85
+ .optional()
86
+ .describe(
87
+ "Image aspect ratio. When a presetId is set, omit this — the preset's aspect ratio is used. Pass a value only when there is no preset, or when the user explicitly asks for a ratio different from the preset's.",
88
+ ),
89
+ imageSize: z
90
+ .enum(IMAGE_SIZES)
91
+ .optional()
92
+ .describe(
93
+ "Output resolution tier. When a presetId is set, omit this — the preset's size is used unless the user explicitly requests a different one.",
94
+ ),
79
95
  model: z.enum(IMAGE_MODELS).optional(),
80
96
  tier: z.enum(IMAGE_QUALITY_TIERS).optional(),
81
97
  intent: z.enum(GENERATION_INTENTS).default("generate"),
@@ -251,11 +267,15 @@ export default defineAction({
251
267
  const category = (args.categories?.[0] ??
252
268
  preset?.category ??
253
269
  collection?.category) as ImageCategory | undefined;
254
- const resolvedModel = (args.model ??
255
- imageModelDefault ??
256
- resolveModelForTier(resolvedTier, category) ??
257
- preset?.model ??
258
- "gemini-3.1-flash-image") as (typeof IMAGE_MODELS)[number];
270
+ const resolvedModel = resolveImageModelForRequest({
271
+ explicitModel: args.model,
272
+ imageModelDefault,
273
+ explicitTier: args.tier,
274
+ resolvedTier,
275
+ category,
276
+ presetModel: preset?.model as (typeof IMAGE_MODELS)[number] | undefined,
277
+ embeddedText: args.embeddedText,
278
+ }) as (typeof IMAGE_MODELS)[number];
259
279
  const resolvedCategories =
260
280
  args.categories ??
261
281
  (preset?.category ? ([preset.category] as any) : undefined);
@@ -297,6 +317,8 @@ export default defineAction({
297
317
  .filter((item) => item?.trim())
298
318
  .join("\n\n"),
299
319
  prompt: promptForRun,
320
+ embeddedText: args.embeddedText,
321
+ textPlacement: args.textPlacement,
300
322
  referenceCount: references.length,
301
323
  includeLogo: args.includeLogo,
302
324
  aspectRatio: resolvedAspectRatio,
@@ -346,6 +368,8 @@ export default defineAction({
346
368
  collectionId: resolvedCollectionId ?? null,
347
369
  presetId: preset?.id ?? null,
348
370
  sessionId: session?.id ?? null,
371
+ embeddedText: args.embeddedText ?? null,
372
+ textPlacement: args.textPlacement ?? null,
349
373
  customInstructions: library.customInstructions ?? "",
350
374
  };
351
375
  const dismissibleSlot = args.dismissible !== false && Boolean(slotId);
@@ -357,6 +381,8 @@ export default defineAction({
357
381
  dismissible: dismissibleSlot,
358
382
  sourceAssetId: args.sourceAssetId,
359
383
  subjectAssetId: args.subjectAssetId,
384
+ embeddedText: args.embeddedText,
385
+ textPlacement: args.textPlacement,
360
386
  intent: args.intent,
361
387
  styleStrength: args.styleStrength,
362
388
  tier: resolvedTier,
@@ -404,22 +430,36 @@ export default defineAction({
404
430
  });
405
431
 
406
432
  try {
407
- const generated = await generateWithManagedImageProvider({
408
- prompt: promptForRun,
409
- compiledPrompt,
410
- references,
411
- model: resolvedModel,
412
- aspectRatio: resolvedAspectRatio,
413
- imageSize: resolvedImageSize,
414
- groundingMode: args.groundingMode,
415
- intent: args.intent,
416
- styleStrength: args.styleStrength,
417
- runId,
418
- libraryId: args.libraryId,
419
- collectionId: resolvedCollectionId ?? null,
420
- source: args.source,
421
- callerAppId: args.callerAppId,
422
- });
433
+ const generated = await withToolActivity(
434
+ context,
435
+ {
436
+ label: "Generating image.",
437
+ ongoingLabel: "Still generating image.",
438
+ // Intentionally no explicit `tool`: withToolActivity falls back to
439
+ // context.actionName, which is the ACTUAL dispatched tool. When this
440
+ // action is invoked directly that is "generate-image"; when it runs as
441
+ // a sub-step of generate-image-batch / rerun-generation-run it is the
442
+ // parent tool, so the activity event matches the real tool_start card
443
+ // instead of spawning an orphan "generate-image" activity card.
444
+ },
445
+ () =>
446
+ generateWithManagedImageProvider({
447
+ prompt: promptForRun,
448
+ compiledPrompt,
449
+ references,
450
+ model: resolvedModel,
451
+ aspectRatio: resolvedAspectRatio,
452
+ imageSize: resolvedImageSize,
453
+ groundingMode: args.groundingMode,
454
+ intent: args.intent,
455
+ styleStrength: args.styleStrength,
456
+ runId,
457
+ libraryId: args.libraryId,
458
+ collectionId: resolvedCollectionId ?? null,
459
+ source: args.source,
460
+ callerAppId: args.callerAppId,
461
+ }),
462
+ );
423
463
  await deleteAppState("image-generation-setup").catch(() => {});
424
464
  let image = generated.image;
425
465
  let mimeType = generated.mimeType;
@@ -468,37 +508,48 @@ export default defineAction({
468
508
  Artifacts: [],
469
509
  };
470
510
  }
471
- const asset = await createAssetFromBuffer({
472
- libraryId: args.libraryId,
473
- collectionId: resolvedCollectionId ?? null,
474
- buffer: image,
475
- mimeType,
476
- role: "generated",
477
- status: "candidate",
478
- prompt: args.prompt,
479
- model: generated.model,
480
- aspectRatio: resolvedAspectRatio,
481
- imageSize: resolvedImageSize,
482
- generationRunId: runId,
483
- metadata: {
484
- provider: generated.provider,
485
- compiledPrompt,
486
- referenceAssetIds: references.map((ref) => ref.id),
487
- sourceAssetId: args.sourceAssetId,
488
- subjectAssetId: args.subjectAssetId,
489
- intent: args.intent,
490
- styleStrength: args.styleStrength,
491
- tier: resolvedTier,
492
- includeLogo: args.includeLogo,
493
- presetId: preset?.id,
494
- sessionId: session?.id,
495
- generated: true,
496
- sourceUrl: generated.sourceUrl,
497
- providerGenerationId: generated.providerGenerationId,
498
- creditsCharged: generated.creditsCharged,
511
+ const asset = await withToolActivity(
512
+ context,
513
+ {
514
+ label: "Saving generated image.",
515
+ ongoingLabel: "Still saving generated image.",
516
+ // See above: omit `tool` so the activity is tagged with the real
517
+ // dispatched tool (context.actionName) rather than a hardcoded
518
+ // "generate-image" that orphans under batch/rerun.
499
519
  },
500
- category,
501
- });
520
+ () =>
521
+ createAssetFromBuffer({
522
+ libraryId: args.libraryId,
523
+ collectionId: resolvedCollectionId ?? null,
524
+ buffer: image,
525
+ mimeType,
526
+ role: "generated",
527
+ status: "candidate",
528
+ prompt: args.prompt,
529
+ model: generated.model,
530
+ aspectRatio: resolvedAspectRatio,
531
+ imageSize: resolvedImageSize,
532
+ generationRunId: runId,
533
+ metadata: {
534
+ provider: generated.provider,
535
+ compiledPrompt,
536
+ referenceAssetIds: references.map((ref) => ref.id),
537
+ sourceAssetId: args.sourceAssetId,
538
+ subjectAssetId: args.subjectAssetId,
539
+ intent: args.intent,
540
+ styleStrength: args.styleStrength,
541
+ tier: resolvedTier,
542
+ includeLogo: args.includeLogo,
543
+ presetId: preset?.id,
544
+ sessionId: session?.id,
545
+ generated: true,
546
+ sourceUrl: generated.sourceUrl,
547
+ providerGenerationId: generated.providerGenerationId,
548
+ creditsCharged: generated.creditsCharged,
549
+ },
550
+ category,
551
+ }),
552
+ );
502
553
  if (session) {
503
554
  const itemCreatedAt = nowIso();
504
555
  await db.insert(schema.assetGenerationSessionItems).values({
@@ -0,0 +1,50 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { accessFilter } from "@agent-native/core/sharing";
3
+ import { and, desc, eq, inArray, isNull } from "drizzle-orm";
4
+ import { z } from "zod";
5
+
6
+ import { getDb, schema } from "../server/db/index.js";
7
+ import { serializeAsset } from "./_helpers.js";
8
+
9
+ export default defineAction({
10
+ description:
11
+ "List unsaved draft generations (generated candidate assets) across accessible libraries, newest first.",
12
+ schema: z.object({
13
+ libraryId: z.string().optional(),
14
+ limit: z.coerce.number().int().min(1).max(500).optional(),
15
+ }),
16
+ http: { method: "GET" },
17
+ readOnly: true,
18
+ run: async ({ libraryId, limit }) => {
19
+ const db = getDb();
20
+ const libraryFilters = [
21
+ accessFilter(schema.assetLibraries, schema.assetLibraryShares),
22
+ isNull(schema.assetLibraries.archivedAt),
23
+ ];
24
+ if (libraryId) libraryFilters.push(eq(schema.assetLibraries.id, libraryId));
25
+ const accessibleLibraries = await db
26
+ .select({ id: schema.assetLibraries.id })
27
+ .from(schema.assetLibraries)
28
+ .where(and(...libraryFilters));
29
+ const libraryIds = accessibleLibraries.map((row) => row.id);
30
+ if (!libraryIds.length) return { count: 0, assets: [] };
31
+
32
+ const rows = await db
33
+ .select()
34
+ .from(schema.assets)
35
+ .where(
36
+ and(
37
+ inArray(schema.assets.libraryId, libraryIds),
38
+ eq(schema.assets.role, "generated"),
39
+ eq(schema.assets.status, "candidate"),
40
+ ),
41
+ )
42
+ .orderBy(desc(schema.assets.createdAt))
43
+ .limit(limit ?? 50);
44
+
45
+ return {
46
+ count: rows.length,
47
+ assets: rows.map((row) => serializeAsset(row)),
48
+ };
49
+ },
50
+ });
@@ -7,6 +7,7 @@ import { z } from "zod";
7
7
  import { IMAGE_QUALITY_TIERS, STYLE_STRENGTHS } from "../shared/api.js";
8
8
 
9
9
  const mediaTypeSchema = z.enum(["image", "video"]);
10
+ const layoutSchema = z.enum(["default", "vertical"]);
10
11
  const booleanParam = z.preprocess((value) => {
11
12
  if (typeof value === "boolean") return value;
12
13
  if (typeof value !== "string") return value;
@@ -77,6 +78,11 @@ const schema = z.object({
77
78
  .string()
78
79
  .optional()
79
80
  .describe("Calling app id, for audit grouping, e.g. design."),
81
+ layout: layoutSchema
82
+ .default("default")
83
+ .describe(
84
+ "Picker layout density. Use vertical when embedding in a narrow sidebar.",
85
+ ),
80
86
  });
81
87
 
82
88
  type OpenAssetPickerArgs = z.infer<typeof schema>;
@@ -132,6 +138,7 @@ function pickerPath(args: Partial<OpenAssetPickerArgs>): string {
132
138
  }
133
139
  if (args.includeLogo) params.set("includeLogo", "1");
134
140
  if (args.callerAppId?.trim()) params.set("callerAppId", args.callerAppId);
141
+ if (args.layout === "vertical") params.set("layout", "vertical");
135
142
  for (const runId of args.candidateRunIds ?? []) {
136
143
  if (runId.trim()) params.append("candidateRunIds", runId.trim());
137
144
  }
@@ -206,6 +213,7 @@ const action = defineAction({
206
213
  prompt: args.prompt ?? null,
207
214
  aspectRatio: args.aspectRatio ?? null,
208
215
  presetId: args.presetId ?? null,
216
+ layout: args.layout,
209
217
  _writeId: `open-asset-picker-${Date.now()}-${Math.random()
210
218
  .toString(36)
211
219
  .slice(2, 8)}`,
@@ -219,6 +227,7 @@ const action = defineAction({
219
227
  path,
220
228
  url: path,
221
229
  embed: true,
230
+ layout: args.layout,
222
231
  title:
223
232
  args.mediaType === "video"
224
233
  ? "Select a video asset"
@@ -1,4 +1,5 @@
1
1
  import { defineAction } from "@agent-native/core";
2
+ import type { ActionRunContext } from "@agent-native/core/action";
2
3
  import { assertAccess } from "@agent-native/core/sharing";
3
4
  import { eq } from "drizzle-orm";
4
5
  import { z } from "zod";
@@ -30,7 +31,10 @@ export default defineAction({
30
31
  ),
31
32
  }),
32
33
  parallelSafe: true,
33
- run: async ({ runId, slotId, sessionId, source, callerAppId }) => {
34
+ run: async (
35
+ { runId, slotId, sessionId, source, callerAppId },
36
+ context?: ActionRunContext,
37
+ ) => {
34
38
  const db = getDb();
35
39
  const [run] = await db
36
40
  .select()
@@ -52,6 +56,8 @@ export default defineAction({
52
56
  intent?: string;
53
57
  styleStrength?: string;
54
58
  subjectAssetId?: string;
59
+ embeddedText?: string | null;
60
+ textPlacement?: string | null;
55
61
  };
56
62
  includeLogo?: boolean;
57
63
  categories?: string[];
@@ -60,39 +66,54 @@ export default defineAction({
60
66
  intent?: string;
61
67
  styleStrength?: string;
62
68
  tier?: string | null;
69
+ embeddedText?: string | null;
70
+ textPlacement?: string | null;
63
71
  }>(run.metadata, {});
64
72
  const categories =
65
73
  metadata.settingsUsed?.categories ?? metadata.categories ?? undefined;
66
74
 
67
- return generateImage.run({
68
- libraryId: run.libraryId,
69
- collectionId: run.collectionId ?? undefined,
70
- presetId: run.presetId ?? undefined,
71
- sessionId: resolvedSessionId,
72
- prompt: run.prompt,
73
- aspectRatio: run.aspectRatio as any,
74
- imageSize: run.imageSize as any,
75
- model: run.model as any,
76
- tier: (metadata.settingsUsed?.tier ?? metadata.tier ?? undefined) as any,
77
- intent: (metadata.settingsUsed?.intent ??
78
- metadata.intent ??
79
- "generate") as any,
80
- styleStrength: (metadata.settingsUsed?.styleStrength ??
81
- metadata.styleStrength ??
82
- "balanced") as any,
83
- categories: categories as any,
84
- includeLogo: Boolean(
85
- metadata.settingsUsed?.includeLogo ?? metadata.includeLogo,
86
- ),
87
- groundingMode: run.groundingMode as any,
88
- sourceAssetId: metadata.sourceAssetId,
89
- subjectAssetId:
90
- metadata.settingsUsed?.subjectAssetId ??
91
- metadata.subjectAssetId ??
92
- undefined,
93
- slotId,
94
- source,
95
- callerAppId,
96
- });
75
+ return generateImage.run(
76
+ {
77
+ libraryId: run.libraryId,
78
+ collectionId: run.collectionId ?? undefined,
79
+ presetId: run.presetId ?? undefined,
80
+ sessionId: resolvedSessionId,
81
+ prompt: run.prompt,
82
+ embeddedText:
83
+ metadata.settingsUsed?.embeddedText ??
84
+ metadata.embeddedText ??
85
+ undefined,
86
+ textPlacement:
87
+ metadata.settingsUsed?.textPlacement ??
88
+ metadata.textPlacement ??
89
+ undefined,
90
+ aspectRatio: run.aspectRatio as any,
91
+ imageSize: run.imageSize as any,
92
+ model: run.model as any,
93
+ tier: (metadata.settingsUsed?.tier ??
94
+ metadata.tier ??
95
+ undefined) as any,
96
+ intent: (metadata.settingsUsed?.intent ??
97
+ metadata.intent ??
98
+ "generate") as any,
99
+ styleStrength: (metadata.settingsUsed?.styleStrength ??
100
+ metadata.styleStrength ??
101
+ "balanced") as any,
102
+ categories: categories as any,
103
+ includeLogo: Boolean(
104
+ metadata.settingsUsed?.includeLogo ?? metadata.includeLogo,
105
+ ),
106
+ groundingMode: run.groundingMode as any,
107
+ sourceAssetId: metadata.sourceAssetId,
108
+ subjectAssetId:
109
+ metadata.settingsUsed?.subjectAssetId ??
110
+ metadata.subjectAssetId ??
111
+ undefined,
112
+ slotId,
113
+ source,
114
+ callerAppId,
115
+ },
116
+ context,
117
+ );
97
118
  },
98
119
  });
@@ -0,0 +1,100 @@
1
+ import { useActionQuery, useT } from "@agent-native/core/client";
2
+ import { IconArrowUpRight, IconPhoto } from "@tabler/icons-react";
3
+ import { Link } from "react-router";
4
+
5
+ import { Button } from "@/components/ui/button";
6
+ import { Skeleton } from "@/components/ui/skeleton";
7
+
8
+ type DraftAsset = {
9
+ id: string;
10
+ title?: string | null;
11
+ prompt?: string | null;
12
+ mediaType?: string | null;
13
+ mimeType?: string | null;
14
+ thumbnailUrl?: string | null;
15
+ previewUrl?: string | null;
16
+ url?: string | null;
17
+ };
18
+
19
+ const RECENT_DRAFTS_LIMIT = 5;
20
+
21
+ export function RecentDraftsSection() {
22
+ const t = useT();
23
+ const { data, isLoading } = useActionQuery("list-draft-assets", {
24
+ limit: RECENT_DRAFTS_LIMIT,
25
+ });
26
+ const drafts = ((data as any)?.assets ?? []) as DraftAsset[];
27
+
28
+ if (!isLoading && drafts.length === 0) return null;
29
+
30
+ return (
31
+ <section className="space-y-3">
32
+ <div className="flex flex-wrap items-center justify-between gap-3">
33
+ <h2 className="text-sm font-semibold text-foreground">
34
+ {t("library.recentDrafts")}
35
+ </h2>
36
+ <Button asChild variant="outline" size="sm">
37
+ <Link to="/library?tab=drafts">
38
+ {t("library.viewAllDrafts")}
39
+ <IconArrowUpRight size={15} className="ml-1.5" />
40
+ </Link>
41
+ </Button>
42
+ </div>
43
+
44
+ <div className="grid grid-cols-3 gap-3 sm:grid-cols-5">
45
+ {isLoading
46
+ ? Array.from({ length: RECENT_DRAFTS_LIMIT }).map((_, index) => (
47
+ <Skeleton key={index} className="aspect-square rounded-lg" />
48
+ ))
49
+ : drafts.map((draft) => (
50
+ <Link
51
+ key={draft.id}
52
+ to={`/asset/${encodeURIComponent(draft.id)}`}
53
+ title={draft.title || draft.prompt || t("library.draftAsset")}
54
+ className="group block overflow-hidden rounded-lg border border-border bg-card shadow-sm transition hover:border-primary/60 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
55
+ >
56
+ <div className="aspect-square bg-muted">
57
+ <DraftThumbnail draft={draft} />
58
+ </div>
59
+ </Link>
60
+ ))}
61
+ </div>
62
+ </section>
63
+ );
64
+ }
65
+
66
+ function DraftThumbnail({ draft }: { draft: DraftAsset }) {
67
+ const t = useT();
68
+ const isVideo =
69
+ draft.mediaType === "video" || draft.mimeType?.startsWith("video/");
70
+ const source = draft.thumbnailUrl ?? draft.previewUrl ?? draft.url ?? "";
71
+
72
+ if (isVideo && !draft.thumbnailUrl) {
73
+ return (
74
+ <video
75
+ src={draft.previewUrl ?? draft.url ?? undefined}
76
+ muted
77
+ playsInline
78
+ preload="metadata"
79
+ className="h-full w-full object-cover transition group-hover:scale-[1.02]"
80
+ />
81
+ );
82
+ }
83
+
84
+ if (!source) {
85
+ return (
86
+ <div className="flex h-full w-full items-center justify-center text-muted-foreground">
87
+ <IconPhoto className="size-5" />
88
+ </div>
89
+ );
90
+ }
91
+
92
+ return (
93
+ <img
94
+ src={source}
95
+ alt={draft.title ?? draft.prompt ?? t("library.draftAsset")}
96
+ loading="lazy"
97
+ className="h-full w-full object-cover transition group-hover:scale-[1.02]"
98
+ />
99
+ );
100
+ }
@@ -191,6 +191,21 @@
191
191
  }
192
192
  }
193
193
 
194
+ .assets-picker-vertical .assets-library-dense-grid,
195
+ .assets-picker-vertical .assets-library-grid {
196
+ grid-template-columns: minmax(0, 1fr);
197
+ }
198
+
199
+ .assets-picker-vertical [role="tablist"] {
200
+ width: 100%;
201
+ }
202
+
203
+ .assets-picker-vertical [role="tab"] {
204
+ min-width: 0;
205
+ flex: 1 1 0;
206
+ padding-inline: 0.5rem;
207
+ }
208
+
194
209
  @container agent-native-main (min-width: 980px) {
195
210
  .assets-brand-kit-preview-grid {
196
211
  grid-template-columns: minmax(0, 1fr) 284px;
@@ -73,6 +73,7 @@ function navigationFromPath(pathname: string, search = "") {
73
73
  query: optionalParam(params, "q"),
74
74
  prompt: optionalParam(params, "prompt"),
75
75
  aspectRatio: optionalParam(params, "aspectRatio"),
76
+ layout: params.get("layout") === "vertical" ? "vertical" : undefined,
76
77
  };
77
78
  }
78
79
  const queryLibraryId = optionalParam(params, "libraryId");
@@ -153,6 +154,9 @@ function pathFromCommand(command: any): string | null {
153
154
  if (typeof command.aspectRatio === "string" && command.aspectRatio.trim()) {
154
155
  params.set("aspectRatio", command.aspectRatio.trim());
155
156
  }
157
+ if (command.layout === "vertical") {
158
+ params.set("layout", "vertical");
159
+ }
156
160
  const query = params.toString();
157
161
  return query ? `/library?${query}` : "/library";
158
162
  }
@@ -628,6 +628,13 @@ const messages = {
628
628
  videosCount: "{{count}} 個影片",
629
629
  },
630
630
  library: {
631
+ drafts: "草稿",
632
+ allLibraries: "所有資料庫",
633
+ noDrafts: "尚無草稿。",
634
+ noMatchingDrafts: "沒有符合的草稿。",
635
+ recentDrafts: "最近草稿",
636
+ viewAllDrafts: "查看所有草稿",
637
+ draftAsset: "草稿資產",
631
638
  addedToReferences: "已新增到參考。",
632
639
  addedAssetsToReferences: "已將 {{count}} 個資產新增到參考。",
633
640
  add: "新增",