@agent-native/core 0.107.2 → 0.109.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 (502) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +24 -0
  3. package/corpus/core/docs/content/actions.mdx +48 -0
  4. package/corpus/core/docs/content/locales/ar-SA/actions.mdx +38 -0
  5. package/corpus/core/docs/content/locales/de-DE/actions.mdx +38 -0
  6. package/corpus/core/docs/content/locales/es-ES/actions.mdx +38 -0
  7. package/corpus/core/docs/content/locales/fr-FR/actions.mdx +38 -0
  8. package/corpus/core/docs/content/locales/hi-IN/actions.mdx +38 -0
  9. package/corpus/core/docs/content/locales/ja-JP/actions.mdx +38 -0
  10. package/corpus/core/docs/content/locales/ko-KR/actions.mdx +38 -0
  11. package/corpus/core/docs/content/locales/pt-BR/actions.mdx +38 -0
  12. package/corpus/core/docs/content/locales/zh-CN/actions.mdx +38 -0
  13. package/corpus/core/docs/content/locales/zh-TW/actions.mdx +38 -0
  14. package/corpus/core/package.json +5 -1
  15. package/corpus/core/src/a2a/client.ts +140 -17
  16. package/corpus/core/src/a2a/handlers.ts +60 -0
  17. package/corpus/core/src/a2a/index.ts +6 -1
  18. package/corpus/core/src/a2a/invoke.ts +68 -1
  19. package/corpus/core/src/a2a/server.ts +13 -1
  20. package/corpus/core/src/a2a/types.ts +16 -0
  21. package/corpus/core/src/a2a-claims.ts +52 -0
  22. package/corpus/core/src/action.ts +7 -2
  23. package/corpus/core/src/agent/production-agent.ts +10 -4
  24. package/corpus/core/src/audit/record.ts +6 -0
  25. package/corpus/core/src/client/AssistantChat.tsx +648 -603
  26. package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -4
  27. package/corpus/core/src/client/agent-chat-adapter.ts +23 -37
  28. package/corpus/core/src/client/agent-sidebar-state.ts +4 -0
  29. package/corpus/core/src/client/analytics.ts +84 -0
  30. package/corpus/core/src/client/chat/message-components.tsx +94 -22
  31. package/corpus/core/src/client/chat/tool-call-display.tsx +170 -47
  32. package/corpus/core/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
  33. package/corpus/core/src/client/chat-thread-url.ts +11 -0
  34. package/corpus/core/src/client/error-capture.ts +12 -0
  35. package/corpus/core/src/client/extensions/ExtensionSlot.tsx +37 -1
  36. package/corpus/core/src/client/feature-flags/FeatureFlagsPanel.tsx +519 -0
  37. package/corpus/core/src/client/feature-flags/helpers.ts +77 -0
  38. package/corpus/core/src/client/feature-flags/index.ts +13 -0
  39. package/corpus/core/src/client/feature-flags/types.ts +29 -0
  40. package/corpus/core/src/client/feature-flags/use-feature-flag.ts +26 -0
  41. package/corpus/core/src/client/index.ts +13 -0
  42. package/corpus/core/src/client/route-chunk-recovery.ts +20 -8
  43. package/corpus/core/src/client/session-replay.ts +31 -0
  44. package/corpus/core/src/extensions/actions.ts +2 -14
  45. package/corpus/core/src/extensions/routes.ts +1 -1
  46. package/corpus/core/src/extensions/store.ts +1 -1
  47. package/corpus/core/src/feature-flags/a2a-action-route.ts +56 -0
  48. package/corpus/core/src/feature-flags/actions/get-feature-flags.ts +24 -0
  49. package/corpus/core/src/feature-flags/actions/list-feature-flags.ts +69 -0
  50. package/corpus/core/src/feature-flags/actions/set-feature-flag.ts +89 -0
  51. package/corpus/core/src/feature-flags/index.ts +21 -0
  52. package/corpus/core/src/feature-flags/permissions.ts +53 -0
  53. package/corpus/core/src/feature-flags/plugin.ts +44 -0
  54. package/corpus/core/src/feature-flags/registry.ts +96 -0
  55. package/corpus/core/src/feature-flags/store.ts +176 -0
  56. package/corpus/core/src/index.ts +15 -0
  57. package/corpus/core/src/localization/default-messages.ts +50 -0
  58. package/corpus/core/src/mcp/build-server.ts +2 -2
  59. package/corpus/core/src/progress/actions.ts +4 -2
  60. package/corpus/core/src/provider-api/index.ts +205 -105
  61. package/corpus/core/src/scripts/call-agent.ts +137 -17
  62. package/corpus/core/src/server/action-discovery.ts +12 -0
  63. package/corpus/core/src/server/action-routes.ts +47 -5
  64. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +40 -0
  65. package/corpus/core/src/server/agent-chat-plugin.ts +31 -0
  66. package/corpus/core/src/server/index.ts +1 -0
  67. package/corpus/core/src/settings/org-settings.ts +13 -0
  68. package/corpus/core/src/settings/store.ts +57 -0
  69. package/corpus/core/src/styles/agent-conversation.css +7 -0
  70. package/corpus/core/src/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
  71. package/corpus/core/src/templates/default/AGENTS.md +1 -0
  72. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +20 -0
  73. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +20 -0
  74. package/corpus/core/src/templates/default/app/i18n/en-US.ts +20 -0
  75. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +20 -0
  76. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
  77. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +19 -0
  78. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +20 -0
  79. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +19 -0
  80. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +20 -0
  81. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +19 -0
  82. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
  83. package/corpus/core/src/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
  84. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
  85. package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  86. package/corpus/core/src/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
  87. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  88. package/corpus/core/src/templates/workspace-core/AGENTS.md +1 -1
  89. package/corpus/core/src/templates/workspace-root/AGENTS.md +1 -1
  90. package/corpus/core/src/vite/action-types-plugin.ts +12 -0
  91. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -10
  92. package/corpus/templates/analytics/.agents/skills/feature-flags/SKILL.md +169 -0
  93. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +54 -23
  94. package/corpus/templates/analytics/.builder/skills/apollo/SKILL.md +19 -41
  95. package/corpus/templates/analytics/.builder/skills/commonroom/SKILL.md +20 -35
  96. package/corpus/templates/analytics/.builder/skills/github/SKILL.md +23 -67
  97. package/corpus/templates/analytics/.builder/skills/pylon/SKILL.md +25 -43
  98. package/corpus/templates/analytics/AGENTS.md +37 -16
  99. package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
  100. package/corpus/templates/analytics/actions/configure-gong-native-insights.ts +29 -0
  101. package/corpus/templates/analytics/actions/content-calendar-schema.ts +8 -4
  102. package/corpus/templates/analytics/actions/content-calendar.ts +12 -4
  103. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -1
  104. package/corpus/templates/analytics/actions/gong-calls.ts +113 -22
  105. package/corpus/templates/analytics/actions/gong-native-insights.ts +166 -0
  106. package/corpus/templates/analytics/actions/hubspot-deals.ts +190 -46
  107. package/corpus/templates/analytics/actions/list-workspace-feature-flags.ts +15 -0
  108. package/corpus/templates/analytics/actions/navigate.ts +2 -2
  109. package/corpus/templates/analytics/actions/pylon-issues.ts +123 -0
  110. package/corpus/templates/analytics/actions/set-workspace-feature-flag.ts +45 -0
  111. package/corpus/templates/analytics/actions/slack-messages.ts +179 -27
  112. package/corpus/templates/analytics/actions/view-screen.ts +13 -0
  113. package/corpus/templates/analytics/app/components/agents/FeatureFlagsFleetPanel.tsx +243 -0
  114. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +48 -152
  115. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +11 -3
  116. package/corpus/templates/analytics/app/components/ui/chart.tsx +1 -1
  117. package/corpus/templates/analytics/app/hooks/use-chart-tooltip-flip.ts +21 -6
  118. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +3 -1
  119. package/corpus/templates/analytics/app/i18n/zh-TW.ts +30 -0
  120. package/corpus/templates/analytics/app/i18n-data.ts +385 -0
  121. package/corpus/templates/analytics/app/pages/Agents.tsx +22 -2
  122. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +181 -30
  123. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +6 -0
  124. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +4 -3
  125. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-editors-can-add-shared-extensions-or-opt-into-per-.md +6 -0
  126. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extensions-show-a-loading-skeleton.md +6 -0
  127. package/corpus/templates/analytics/changelog/2026-07-17-errors-now-group-repeat-failures-consistently-and-keep-priva.md +6 -0
  128. package/corpus/templates/analytics/changelog/2026-07-17-gong-transcript-reviews-now-batch-bounded-call-windows-for-f.md +6 -0
  129. package/corpus/templates/analytics/changelog/2026-07-17-hubspot-deal-filters-now-run-in-hubspot-before-paging-result.md +6 -0
  130. package/corpus/templates/analytics/changelog/2026-07-17-manage-feature-flag-rollouts-across-your-organization-s-apps.md +6 -0
  131. package/corpus/templates/analytics/changelog/2026-07-17-notion-content-calendars-now-discover-the-matching-database-.md +6 -0
  132. package/corpus/templates/analytics/changelog/2026-07-17-pylon-dashboard-reads-now-use-the-paginated-issue-search-api.md +6 -0
  133. package/corpus/templates/analytics/changelog/2026-07-17-slack-reads-no-longer-join-channels-and-report-pagination-coverage.md +6 -0
  134. package/corpus/templates/analytics/server/handlers/notion.ts +14 -3
  135. package/corpus/templates/analytics/server/handlers/slack.ts +182 -29
  136. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -6
  137. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +6 -2
  138. package/corpus/templates/analytics/server/lib/db-admin-connections.ts +13 -5
  139. package/corpus/templates/analytics/server/lib/error-capture.ts +75 -8
  140. package/corpus/templates/analytics/server/lib/gong-native-policy.ts +72 -0
  141. package/corpus/templates/analytics/server/lib/gong.ts +54 -66
  142. package/corpus/templates/analytics/server/lib/hubspot.ts +40 -3
  143. package/corpus/templates/analytics/server/lib/notion.ts +83 -8
  144. package/corpus/templates/analytics/server/lib/real-data-actions.ts +4 -0
  145. package/corpus/templates/analytics/server/lib/slack.ts +242 -90
  146. package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +347 -0
  147. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -3
  148. package/corpus/templates/analytics/server/routes/api/pylon/accounts.get.ts +42 -1
  149. package/corpus/templates/analytics/server/routes/api/pylon/issues.get.ts +71 -1
  150. package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +44 -4
  151. package/corpus/templates/assets/.agents/skills/feature-flags/SKILL.md +169 -0
  152. package/corpus/templates/brain/.agents/skills/feature-flags/SKILL.md +169 -0
  153. package/corpus/templates/calendar/.agents/skills/feature-flags/SKILL.md +169 -0
  154. package/corpus/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
  155. package/corpus/templates/clips/.agents/skills/feature-flags/SKILL.md +169 -0
  156. package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +19 -1
  157. package/corpus/templates/clips/app/components/library/create-folder-dialog.tsx +123 -0
  158. package/corpus/templates/clips/app/components/library/library-grid.tsx +42 -4
  159. package/corpus/templates/clips/app/components/library/recording-card.tsx +30 -0
  160. package/corpus/templates/clips/app/entry.client.tsx +6 -1
  161. package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -1
  162. package/corpus/templates/clips/app/i18n/de-DE.ts +12 -1
  163. package/corpus/templates/clips/app/i18n/en-US.ts +12 -1
  164. package/corpus/templates/clips/app/i18n/es-ES.ts +11 -1
  165. package/corpus/templates/clips/app/i18n/fr-FR.ts +11 -1
  166. package/corpus/templates/clips/app/i18n/hi-IN.ts +10 -1
  167. package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -1
  168. package/corpus/templates/clips/app/i18n/ko-KR.ts +11 -1
  169. package/corpus/templates/clips/app/i18n/pt-BR.ts +11 -1
  170. package/corpus/templates/clips/app/i18n/zh-CN.ts +11 -1
  171. package/corpus/templates/clips/app/i18n/zh-TW.ts +11 -1
  172. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +72 -1
  173. package/corpus/templates/clips/changelog/2026-07-17-choose-which-workspace-receives-new-clips-recordings-and-des.md +6 -0
  174. package/corpus/templates/clips/changelog/2026-07-17-create-folders-directly-from-the-move-menu.md +6 -0
  175. package/corpus/templates/clips/changelog/2026-07-17-failed-desktop-uploads-now-offer-a-direct-way-to-reopen-clip.md +6 -0
  176. package/corpus/templates/clips/desktop/src/app.tsx +1 -1
  177. package/corpus/templates/clips/server/plugins/feature-flags.ts +11 -0
  178. package/corpus/templates/clips/shared/feature-flags.ts +30 -37
  179. package/corpus/templates/content/.agents/skills/feature-flags/SKILL.md +169 -0
  180. package/corpus/templates/content/app/entry.client.tsx +6 -1
  181. package/corpus/templates/design/.agents/skills/feature-flags/SKILL.md +169 -0
  182. package/corpus/templates/design/AGENTS.md +5 -3
  183. package/corpus/templates/design/actions/add-fusion-screens.ts +4 -6
  184. package/corpus/templates/design/actions/apply-fusion-edits.ts +4 -6
  185. package/corpus/templates/design/actions/create-fusion-app.ts +5 -4
  186. package/corpus/templates/design/actions/deploy-fusion-app.ts +4 -3
  187. package/corpus/templates/design/actions/get-fusion-deploy-status.ts +4 -6
  188. package/corpus/templates/design/actions/list-fusion-edits.ts +4 -3
  189. package/corpus/templates/design/actions/push-fusion-app.ts +4 -6
  190. package/corpus/templates/design/actions/queue-fusion-edit.ts +4 -3
  191. package/corpus/templates/design/actions/send-fusion-message.ts +4 -6
  192. package/corpus/templates/design/actions/sync-fusion-app.ts +4 -3
  193. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +1 -1
  194. package/corpus/templates/design/app/pages/Index.tsx +8 -6
  195. package/corpus/templates/design/server/plugins/feature-flags.ts +5 -0
  196. package/corpus/templates/design/shared/full-app.ts +10 -7
  197. package/corpus/templates/dispatch/.agents/skills/feature-flags/SKILL.md +169 -0
  198. package/corpus/templates/dispatch/AGENTS.md +5 -0
  199. package/corpus/templates/dispatch/changelog/2026-07-17-apps-page-links-to-other-available-apps.md +6 -0
  200. package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +6 -0
  201. package/corpus/templates/forms/.agents/skills/feature-flags/SKILL.md +169 -0
  202. package/corpus/templates/macros/.agents/skills/feature-flags/SKILL.md +169 -0
  203. package/corpus/templates/mail/.agents/skills/feature-flags/SKILL.md +169 -0
  204. package/corpus/templates/mail/app/entry.client.tsx +6 -1
  205. package/corpus/templates/plan/.agents/skills/feature-flags/SKILL.md +169 -0
  206. package/corpus/templates/slides/.agents/skills/feature-flags/SKILL.md +169 -0
  207. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +11 -7
  208. package/corpus/templates/slides/.env.example +0 -1
  209. package/corpus/templates/slides/AGENTS.md +4 -0
  210. package/corpus/templates/slides/DEVELOPING.md +2 -2
  211. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
  212. package/corpus/templates/slides/actions/logo-config.ts +6 -7
  213. package/corpus/templates/slides/actions/search-images.ts +11 -39
  214. package/corpus/templates/slides/actions/search-logos.ts +5 -52
  215. package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +1 -1
  216. package/corpus/templates/slides/app/components/editor/LogoSearchPanel.tsx +16 -26
  217. package/corpus/templates/slides/app/entry.client.tsx +6 -1
  218. package/corpus/templates/slides/server/lib/media-search-providers.ts +216 -0
  219. package/corpus/templates/slides/server/register-secrets.ts +30 -0
  220. package/corpus/templates/tasks/.agents/skills/feature-flags/SKILL.md +169 -0
  221. package/dist/a2a/client.d.ts +38 -1
  222. package/dist/a2a/client.d.ts.map +1 -1
  223. package/dist/a2a/client.js +81 -12
  224. package/dist/a2a/client.js.map +1 -1
  225. package/dist/a2a/handlers.d.ts.map +1 -1
  226. package/dist/a2a/handlers.js +47 -0
  227. package/dist/a2a/handlers.js.map +1 -1
  228. package/dist/a2a/index.d.ts +4 -4
  229. package/dist/a2a/index.d.ts.map +1 -1
  230. package/dist/a2a/index.js +2 -2
  231. package/dist/a2a/index.js.map +1 -1
  232. package/dist/a2a/invoke.d.ts +26 -2
  233. package/dist/a2a/invoke.d.ts.map +1 -1
  234. package/dist/a2a/invoke.js +30 -1
  235. package/dist/a2a/invoke.js.map +1 -1
  236. package/dist/a2a/server.d.ts.map +1 -1
  237. package/dist/a2a/server.js +14 -1
  238. package/dist/a2a/server.js.map +1 -1
  239. package/dist/a2a/types.d.ts +12 -0
  240. package/dist/a2a/types.d.ts.map +1 -1
  241. package/dist/a2a/types.js.map +1 -1
  242. package/dist/a2a-claims.d.ts +10 -0
  243. package/dist/a2a-claims.d.ts.map +1 -0
  244. package/dist/a2a-claims.js +41 -0
  245. package/dist/a2a-claims.js.map +1 -0
  246. package/dist/action.d.ts +7 -2
  247. package/dist/action.d.ts.map +1 -1
  248. package/dist/action.js.map +1 -1
  249. package/dist/agent/production-agent.d.ts +5 -0
  250. package/dist/agent/production-agent.d.ts.map +1 -1
  251. package/dist/agent/production-agent.js +5 -3
  252. package/dist/agent/production-agent.js.map +1 -1
  253. package/dist/audit/record.d.ts +3 -0
  254. package/dist/audit/record.d.ts.map +1 -1
  255. package/dist/audit/record.js +3 -0
  256. package/dist/audit/record.js.map +1 -1
  257. package/dist/client/AssistantChat.d.ts +14 -1
  258. package/dist/client/AssistantChat.d.ts.map +1 -1
  259. package/dist/client/AssistantChat.js +158 -136
  260. package/dist/client/AssistantChat.js.map +1 -1
  261. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  262. package/dist/client/MultiTabAssistantChat.js +27 -4
  263. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  264. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  265. package/dist/client/agent-chat-adapter.js +21 -39
  266. package/dist/client/agent-chat-adapter.js.map +1 -1
  267. package/dist/client/agent-sidebar-state.d.ts +1 -0
  268. package/dist/client/agent-sidebar-state.d.ts.map +1 -1
  269. package/dist/client/agent-sidebar-state.js +4 -0
  270. package/dist/client/agent-sidebar-state.js.map +1 -1
  271. package/dist/client/analytics.d.ts +14 -0
  272. package/dist/client/analytics.d.ts.map +1 -1
  273. package/dist/client/analytics.js +67 -0
  274. package/dist/client/analytics.js.map +1 -1
  275. package/dist/client/chat/message-components.d.ts +8 -0
  276. package/dist/client/chat/message-components.d.ts.map +1 -1
  277. package/dist/client/chat/message-components.js +62 -19
  278. package/dist/client/chat/message-components.js.map +1 -1
  279. package/dist/client/chat/tool-call-display.d.ts +6 -0
  280. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  281. package/dist/client/chat/tool-call-display.js +83 -14
  282. package/dist/client/chat/tool-call-display.js.map +1 -1
  283. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts +8 -0
  284. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts.map +1 -0
  285. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js +51 -0
  286. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js.map +1 -0
  287. package/dist/client/chat-thread-url.d.ts +2 -0
  288. package/dist/client/chat-thread-url.d.ts.map +1 -0
  289. package/dist/client/chat-thread-url.js +12 -0
  290. package/dist/client/chat-thread-url.js.map +1 -0
  291. package/dist/client/error-capture.d.ts.map +1 -1
  292. package/dist/client/error-capture.js +7 -0
  293. package/dist/client/error-capture.js.map +1 -1
  294. package/dist/client/extensions/ExtensionSlot.d.ts +3 -1
  295. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  296. package/dist/client/extensions/ExtensionSlot.js +28 -3
  297. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  298. package/dist/client/feature-flags/FeatureFlagsPanel.d.ts +10 -0
  299. package/dist/client/feature-flags/FeatureFlagsPanel.d.ts.map +1 -0
  300. package/dist/client/feature-flags/FeatureFlagsPanel.js +143 -0
  301. package/dist/client/feature-flags/FeatureFlagsPanel.js.map +1 -0
  302. package/dist/client/feature-flags/helpers.d.ts +16 -0
  303. package/dist/client/feature-flags/helpers.d.ts.map +1 -0
  304. package/dist/client/feature-flags/helpers.js +50 -0
  305. package/dist/client/feature-flags/helpers.js.map +1 -0
  306. package/dist/client/feature-flags/index.d.ts +5 -0
  307. package/dist/client/feature-flags/index.d.ts.map +1 -0
  308. package/dist/client/feature-flags/index.js +4 -0
  309. package/dist/client/feature-flags/index.js.map +1 -0
  310. package/dist/client/feature-flags/types.d.ts +27 -0
  311. package/dist/client/feature-flags/types.d.ts.map +1 -0
  312. package/dist/client/feature-flags/types.js +2 -0
  313. package/dist/client/feature-flags/types.js.map +1 -0
  314. package/dist/client/feature-flags/use-feature-flag.d.ts +8 -0
  315. package/dist/client/feature-flags/use-feature-flag.d.ts.map +1 -0
  316. package/dist/client/feature-flags/use-feature-flag.js +15 -0
  317. package/dist/client/feature-flags/use-feature-flag.js.map +1 -0
  318. package/dist/client/index.d.ts +2 -1
  319. package/dist/client/index.d.ts.map +1 -1
  320. package/dist/client/index.js +2 -1
  321. package/dist/client/index.js.map +1 -1
  322. package/dist/client/route-chunk-recovery.d.ts.map +1 -1
  323. package/dist/client/route-chunk-recovery.js +14 -9
  324. package/dist/client/route-chunk-recovery.js.map +1 -1
  325. package/dist/client/session-replay.d.ts +15 -0
  326. package/dist/client/session-replay.d.ts.map +1 -1
  327. package/dist/client/session-replay.js +20 -0
  328. package/dist/client/session-replay.js.map +1 -1
  329. package/dist/collab/struct-routes.d.ts +1 -1
  330. package/dist/extensions/actions.d.ts.map +1 -1
  331. package/dist/extensions/actions.js +2 -10
  332. package/dist/extensions/actions.js.map +1 -1
  333. package/dist/extensions/routes.d.ts.map +1 -1
  334. package/dist/extensions/routes.js +1 -1
  335. package/dist/extensions/routes.js.map +1 -1
  336. package/dist/extensions/store.js +1 -1
  337. package/dist/extensions/store.js.map +1 -1
  338. package/dist/feature-flags/a2a-action-route.d.ts +14 -0
  339. package/dist/feature-flags/a2a-action-route.d.ts.map +1 -0
  340. package/dist/feature-flags/a2a-action-route.js +50 -0
  341. package/dist/feature-flags/a2a-action-route.js.map +1 -0
  342. package/dist/feature-flags/actions/get-feature-flags.d.ts +3 -0
  343. package/dist/feature-flags/actions/get-feature-flags.d.ts.map +1 -0
  344. package/dist/feature-flags/actions/get-feature-flags.js +18 -0
  345. package/dist/feature-flags/actions/get-feature-flags.js.map +1 -0
  346. package/dist/feature-flags/actions/list-feature-flags.d.ts +28 -0
  347. package/dist/feature-flags/actions/list-feature-flags.d.ts.map +1 -0
  348. package/dist/feature-flags/actions/list-feature-flags.js +60 -0
  349. package/dist/feature-flags/actions/list-feature-flags.js.map +1 -0
  350. package/dist/feature-flags/actions/set-feature-flag.d.ts +26 -0
  351. package/dist/feature-flags/actions/set-feature-flag.d.ts.map +1 -0
  352. package/dist/feature-flags/actions/set-feature-flag.js +78 -0
  353. package/dist/feature-flags/actions/set-feature-flag.js.map +1 -0
  354. package/dist/feature-flags/index.d.ts +5 -0
  355. package/dist/feature-flags/index.d.ts.map +1 -0
  356. package/dist/feature-flags/index.js +5 -0
  357. package/dist/feature-flags/index.js.map +1 -0
  358. package/dist/feature-flags/permissions.d.ts +13 -0
  359. package/dist/feature-flags/permissions.d.ts.map +1 -0
  360. package/dist/feature-flags/permissions.js +37 -0
  361. package/dist/feature-flags/permissions.js.map +1 -0
  362. package/dist/feature-flags/plugin.d.ts +17 -0
  363. package/dist/feature-flags/plugin.d.ts.map +1 -0
  364. package/dist/feature-flags/plugin.js +29 -0
  365. package/dist/feature-flags/plugin.js.map +1 -0
  366. package/dist/feature-flags/registry.d.ts +23 -0
  367. package/dist/feature-flags/registry.d.ts.map +1 -0
  368. package/dist/feature-flags/registry.js +59 -0
  369. package/dist/feature-flags/registry.js.map +1 -0
  370. package/dist/feature-flags/store.d.ts +31 -0
  371. package/dist/feature-flags/store.d.ts.map +1 -0
  372. package/dist/feature-flags/store.js +124 -0
  373. package/dist/feature-flags/store.js.map +1 -0
  374. package/dist/index.d.ts +1 -0
  375. package/dist/index.d.ts.map +1 -1
  376. package/dist/index.js +1 -0
  377. package/dist/index.js.map +1 -1
  378. package/dist/localization/default-messages.d.ts +45 -0
  379. package/dist/localization/default-messages.d.ts.map +1 -1
  380. package/dist/localization/default-messages.js +45 -0
  381. package/dist/localization/default-messages.js.map +1 -1
  382. package/dist/mcp/build-server.d.ts +2 -0
  383. package/dist/mcp/build-server.d.ts.map +1 -1
  384. package/dist/mcp/build-server.js +2 -2
  385. package/dist/mcp/build-server.js.map +1 -1
  386. package/dist/notifications/routes.d.ts +2 -2
  387. package/dist/progress/actions.d.ts.map +1 -1
  388. package/dist/progress/actions.js +3 -2
  389. package/dist/progress/actions.js.map +1 -1
  390. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  391. package/dist/provider-api/index.d.ts.map +1 -1
  392. package/dist/provider-api/index.js +91 -8
  393. package/dist/provider-api/index.js.map +1 -1
  394. package/dist/resources/handlers.d.ts +3 -3
  395. package/dist/scripts/call-agent.d.ts.map +1 -1
  396. package/dist/scripts/call-agent.js +107 -16
  397. package/dist/scripts/call-agent.js.map +1 -1
  398. package/dist/server/action-discovery.d.ts.map +1 -1
  399. package/dist/server/action-discovery.js +12 -0
  400. package/dist/server/action-discovery.js.map +1 -1
  401. package/dist/server/action-routes.d.ts +3 -0
  402. package/dist/server/action-routes.d.ts.map +1 -1
  403. package/dist/server/action-routes.js +45 -5
  404. package/dist/server/action-routes.js.map +1 -1
  405. package/dist/server/agent-chat/action-filters-a2a.d.ts +6 -0
  406. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  407. package/dist/server/agent-chat/action-filters-a2a.js +27 -0
  408. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  409. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  410. package/dist/server/agent-chat-plugin.js +27 -1
  411. package/dist/server/agent-chat-plugin.js.map +1 -1
  412. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  413. package/dist/server/index.d.ts +1 -0
  414. package/dist/server/index.d.ts.map +1 -1
  415. package/dist/server/index.js +1 -0
  416. package/dist/server/index.js.map +1 -1
  417. package/dist/server/transcribe-voice.d.ts +1 -1
  418. package/dist/settings/org-settings.d.ts +2 -0
  419. package/dist/settings/org-settings.d.ts.map +1 -1
  420. package/dist/settings/org-settings.js +5 -1
  421. package/dist/settings/org-settings.js.map +1 -1
  422. package/dist/settings/store.d.ts +8 -0
  423. package/dist/settings/store.d.ts.map +1 -1
  424. package/dist/settings/store.js +48 -0
  425. package/dist/settings/store.js.map +1 -1
  426. package/dist/styles/agent-conversation.css +7 -0
  427. package/dist/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
  428. package/dist/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
  429. package/dist/templates/default/AGENTS.md +1 -0
  430. package/dist/templates/default/app/i18n/ar-SA.ts +20 -0
  431. package/dist/templates/default/app/i18n/de-DE.ts +20 -0
  432. package/dist/templates/default/app/i18n/en-US.ts +20 -0
  433. package/dist/templates/default/app/i18n/es-ES.ts +20 -0
  434. package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
  435. package/dist/templates/default/app/i18n/hi-IN.ts +19 -0
  436. package/dist/templates/default/app/i18n/ja-JP.ts +20 -0
  437. package/dist/templates/default/app/i18n/ko-KR.ts +19 -0
  438. package/dist/templates/default/app/i18n/pt-BR.ts +20 -0
  439. package/dist/templates/default/app/i18n/zh-CN.ts +19 -0
  440. package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
  441. package/dist/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
  442. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
  443. package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  444. package/dist/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
  445. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  446. package/dist/templates/workspace-core/AGENTS.md +1 -1
  447. package/dist/templates/workspace-root/AGENTS.md +1 -1
  448. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  449. package/dist/vite/action-types-plugin.js +12 -0
  450. package/dist/vite/action-types-plugin.js.map +1 -1
  451. package/docs/content/actions.mdx +48 -0
  452. package/docs/content/locales/ar-SA/actions.mdx +38 -0
  453. package/docs/content/locales/de-DE/actions.mdx +38 -0
  454. package/docs/content/locales/es-ES/actions.mdx +38 -0
  455. package/docs/content/locales/fr-FR/actions.mdx +38 -0
  456. package/docs/content/locales/hi-IN/actions.mdx +38 -0
  457. package/docs/content/locales/ja-JP/actions.mdx +38 -0
  458. package/docs/content/locales/ko-KR/actions.mdx +38 -0
  459. package/docs/content/locales/pt-BR/actions.mdx +38 -0
  460. package/docs/content/locales/zh-CN/actions.mdx +38 -0
  461. package/docs/content/locales/zh-TW/actions.mdx +38 -0
  462. package/package.json +5 -1
  463. package/src/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
  464. package/src/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
  465. package/src/templates/default/AGENTS.md +1 -0
  466. package/src/templates/default/app/i18n/ar-SA.ts +20 -0
  467. package/src/templates/default/app/i18n/de-DE.ts +20 -0
  468. package/src/templates/default/app/i18n/en-US.ts +20 -0
  469. package/src/templates/default/app/i18n/es-ES.ts +20 -0
  470. package/src/templates/default/app/i18n/fr-FR.ts +21 -0
  471. package/src/templates/default/app/i18n/hi-IN.ts +19 -0
  472. package/src/templates/default/app/i18n/ja-JP.ts +20 -0
  473. package/src/templates/default/app/i18n/ko-KR.ts +19 -0
  474. package/src/templates/default/app/i18n/pt-BR.ts +20 -0
  475. package/src/templates/default/app/i18n/zh-CN.ts +19 -0
  476. package/src/templates/default/app/i18n/zh-TW.ts +19 -0
  477. package/src/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
  478. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
  479. package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  480. package/src/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
  481. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  482. package/src/templates/workspace-core/AGENTS.md +1 -1
  483. package/src/templates/workspace-root/AGENTS.md +1 -1
  484. package/corpus/templates/analytics/server/handlers/github.ts +0 -200
  485. package/corpus/templates/analytics/server/handlers/pylon.ts +0 -43
  486. package/corpus/templates/analytics/server/lib/apollo.ts +0 -167
  487. package/corpus/templates/analytics/server/lib/commonroom.ts +0 -149
  488. package/corpus/templates/analytics/server/lib/github.ts +0 -660
  489. package/corpus/templates/analytics/server/lib/mixpanel.ts +0 -156
  490. package/corpus/templates/analytics/server/lib/posthog.ts +0 -194
  491. package/corpus/templates/analytics/server/lib/pylon.ts +0 -109
  492. package/corpus/templates/analytics/server/routes/api/github/graphql.post.ts +0 -1
  493. package/corpus/templates/analytics/server/routes/api/github/issue.get.ts +0 -1
  494. package/corpus/templates/analytics/server/routes/api/github/org-prs.get.ts +0 -1
  495. package/corpus/templates/analytics/server/routes/api/github/pr.get.ts +0 -1
  496. package/corpus/templates/analytics/server/routes/api/github/prs.get.ts +0 -1
  497. package/corpus/templates/analytics/server/routes/api/github/search.get.ts +0 -1
  498. package/corpus/templates/clips/actions/get-feature-flags.ts +0 -30
  499. package/corpus/templates/slides/actions/fetch-logos.ts +0 -90
  500. package/corpus/templates/slides/actions/image-search.ts +0 -64
  501. package/corpus/templates/slides/actions/import-github.ts +0 -182
  502. package/corpus/templates/slides/actions/logo-lookup.ts +0 -113
@@ -37,7 +37,6 @@ import React, {
37
37
 
38
38
  import type { ReasoningEffort } from "../shared/reasoning-effort.js";
39
39
  import {
40
- ACTIVE_RUN_STATE_EVENT,
41
40
  clearPendingTurnIfMatches,
42
41
  clearActiveRunIfMatches,
43
42
  getPendingTurn,
@@ -122,10 +121,12 @@ import {
122
121
  } from "./chat/runtime.js";
123
122
  import {
124
123
  ChatRunningContext,
124
+ ChatRunDurationContext,
125
125
  ApprovalContext,
126
126
  type ApprovalContextValue,
127
127
  ReconnectStreamMessage,
128
128
  } from "./chat/tool-call-display.js";
129
+ import { useAgentChatLifecycleTracking } from "./chat/use-agent-chat-lifecycle-tracking.js";
129
130
  import { useReconnectReaderOwner } from "./chat/use-reconnect-reader-owner.js";
130
131
  import {
131
132
  MessageScroller,
@@ -1611,6 +1612,29 @@ type QueuedMessage = {
1611
1612
  hideUserMessage?: boolean;
1612
1613
  };
1613
1614
 
1615
+ export function queuedMessageImageSources(
1616
+ message: Pick<QueuedMessage, "attachments" | "images">,
1617
+ ): string[] {
1618
+ const sources = (message.attachments ?? []).flatMap((attachment) =>
1619
+ attachment.content.flatMap((part) =>
1620
+ part.type === "image" &&
1621
+ "image" in part &&
1622
+ typeof part.image === "string" &&
1623
+ part.image.trim().length > 0
1624
+ ? [part.image]
1625
+ : [],
1626
+ ),
1627
+ );
1628
+
1629
+ for (const image of message.images ?? []) {
1630
+ if (image.trim().length > 0 && !sources.includes(image)) {
1631
+ sources.push(image);
1632
+ }
1633
+ }
1634
+
1635
+ return sources;
1636
+ }
1637
+
1614
1638
  function AssistantChatUserMessageItem() {
1615
1639
  const messageRuntime = useMessageRuntime();
1616
1640
  const message = messageRuntime.getState();
@@ -2191,6 +2215,7 @@ const AssistantChatInner = forwardRef<
2191
2215
  loadHistoryRepository,
2192
2216
  historyReloadKey,
2193
2217
  externalStreaming = false,
2218
+ agentChatSurface = "app",
2194
2219
  },
2195
2220
  ref,
2196
2221
  ) {
@@ -2573,24 +2598,12 @@ const AssistantChatInner = forwardRef<
2573
2598
  const [hasActiveServerRun, setHasActiveServerRun] = useState(() =>
2574
2599
  activeRunMatchesThread(getActiveRun(), threadId),
2575
2600
  );
2576
- useEffect(() => {
2577
- const syncActiveRun = (state = getActiveRun()) => {
2578
- setHasActiveServerRun(activeRunMatchesThread(state, threadId));
2579
- };
2580
- syncActiveRun();
2581
- const handler = (event: Event) => {
2582
- const state = (event as CustomEvent<{ state?: ActiveRunState | null }>)
2583
- .detail?.state;
2584
- syncActiveRun(state ?? null);
2585
- };
2586
- const storageHandler = () => syncActiveRun();
2587
- window.addEventListener(ACTIVE_RUN_STATE_EVENT, handler);
2588
- window.addEventListener("storage", storageHandler);
2589
- return () => {
2590
- window.removeEventListener(ACTIVE_RUN_STATE_EVENT, handler);
2591
- window.removeEventListener("storage", storageHandler);
2592
- };
2593
- }, [threadId]);
2601
+ const trackStoppedRun = useAgentChatLifecycleTracking({
2602
+ surface: agentChatSurface,
2603
+ threadId,
2604
+ tabId,
2605
+ onActiveRunChange: setHasActiveServerRun,
2606
+ });
2594
2607
  // Real running state drives submission/queue gating; UI running also covers
2595
2608
  // short auto-continuation gaps so the latest assistant message does not flash
2596
2609
  // into a done state while the agent is still working.
@@ -2603,6 +2616,25 @@ const AssistantChatInner = forwardRef<
2603
2616
  hasActiveServerRun,
2604
2617
  });
2605
2618
  const textStreaming = showRunningInUI || externalStreaming;
2619
+ const chatRunStartedAtRef = useRef<number | null>(null);
2620
+ const [lastChatRunDurationMs, setLastChatRunDurationMs] = useState<
2621
+ number | null
2622
+ >(null);
2623
+ useEffect(() => {
2624
+ if (showRunningInUI) {
2625
+ if (chatRunStartedAtRef.current == null) {
2626
+ chatRunStartedAtRef.current = Date.now();
2627
+ setLastChatRunDurationMs(null);
2628
+ }
2629
+ return;
2630
+ }
2631
+ if (chatRunStartedAtRef.current != null) {
2632
+ setLastChatRunDurationMs(
2633
+ Math.max(0, Date.now() - chatRunStartedAtRef.current),
2634
+ );
2635
+ chatRunStartedAtRef.current = null;
2636
+ }
2637
+ }, [showRunningInUI]);
2606
2638
  // A revealed activity label wins; otherwise keep recovery states calm and
2607
2639
  // product-facing. Reconnect is transport machinery, so normal replay reads as
2608
2640
  // ongoing work instead of exposing "Reconnecting" mid-chat.
@@ -4288,6 +4320,7 @@ const AssistantChatInner = forwardRef<
4288
4320
  at: Date.now(),
4289
4321
  ...(runIdToAbort ? { runId: runIdToAbort } : {}),
4290
4322
  };
4323
+ trackStoppedRun(runIdToAbort);
4291
4324
  setRunErrorInfo(null);
4292
4325
  setDismissedRunErrorKey(null);
4293
4326
  if (runIdToAbort) {
@@ -4351,6 +4384,7 @@ const AssistantChatInner = forwardRef<
4351
4384
  tabId,
4352
4385
  threadId,
4353
4386
  threadRuntime,
4387
+ trackStoppedRun,
4354
4388
  ],
4355
4389
  );
4356
4390
  // Keep the ref current so addToQueue can call it without a stale closure.
@@ -5021,619 +5055,630 @@ const AssistantChatInner = forwardRef<
5021
5055
  <CheckpointContext.Provider value={checkpointCtx}>
5022
5056
  <MessageActionsContext.Provider value={messageActionsCtx}>
5023
5057
  <ApprovalContext.Provider value={approvalCtx}>
5024
- <ChatRunningContext.Provider value={showRunningInUI}>
5025
- <TextStreamingContext.Provider value={textStreaming}>
5026
- <div
5027
- data-agent-empty-state={
5028
- centeredEmptyState
5029
- ? "centered"
5030
- : compactMissingKeyEmptyState
5031
- ? "compact-setup"
5032
- : undefined
5033
- }
5034
- className={cn(
5035
- "relative flex flex-1 flex-col h-full min-h-0 text-foreground",
5036
- className,
5037
- )}
5038
- onDragEnter={handleChatDragEnter}
5039
- onDragOver={handleChatDragOver}
5040
- onDragLeave={handleChatDragLeave}
5041
- onDropCapture={handleChatDropCapture}
5042
- onDrop={handleChatDrop}
5043
- >
5044
- {dropActive && (
5045
- <div
5046
- aria-hidden="true"
5047
- className="pointer-events-none absolute inset-0 z-50 flex items-center justify-center rounded-md border-2 border-dashed border-primary/70 bg-primary/5 backdrop-blur-[1px]"
5048
- >
5049
- <span className="rounded-md bg-background/90 px-3 py-1.5 text-xs font-medium text-foreground shadow-sm">
5050
- Drop to attach
5051
- </span>
5052
- </div>
5053
- )}
5054
- {showHeader && (
5055
- <div className="flex h-11 shrink-0 items-center justify-between border-b border-border px-4">
5056
- <span className="text-[13px] font-medium text-muted-foreground">
5057
- Agent
5058
- </span>
5059
- <div className="flex items-center gap-1">
5060
- {onSwitchToCli && (
5061
- <TooltipProvider delayDuration={200}>
5062
- <Tooltip>
5063
- <TooltipTrigger asChild>
5064
- <button
5065
- onClick={onSwitchToCli}
5066
- aria-label="Switch to CLI"
5067
- className="flex items-center gap-1 text-[12px] text-muted-foreground hover:text-foreground px-2 py-1 rounded-md hover:bg-accent"
5068
- >
5069
- <IconTerminal className="h-3.5 w-3.5" />
5070
- CLI
5071
- </button>
5072
- </TooltipTrigger>
5073
- <TooltipContent>Switch to CLI</TooltipContent>
5074
- </Tooltip>
5075
- </TooltipProvider>
5076
- )}
5077
- </div>
5078
- </div>
5079
- )}
5080
-
5081
- {/* Messages area */}
5082
- <MessageScrollerProvider
5083
- key={chatScrollResetKey}
5084
- autoScroll={false}
5058
+ <ChatRunDurationContext.Provider value={lastChatRunDurationMs}>
5059
+ <ChatRunningContext.Provider value={showRunningInUI}>
5060
+ <TextStreamingContext.Provider value={textStreaming}>
5061
+ <div
5062
+ data-agent-empty-state={
5063
+ centeredEmptyState
5064
+ ? "centered"
5065
+ : compactMissingKeyEmptyState
5066
+ ? "compact-setup"
5067
+ : undefined
5068
+ }
5069
+ className={cn(
5070
+ "relative flex flex-1 flex-col h-full min-h-0 text-foreground",
5071
+ className,
5072
+ )}
5073
+ onDragEnter={handleChatDragEnter}
5074
+ onDragOver={handleChatDragOver}
5075
+ onDragLeave={handleChatDragLeave}
5076
+ onDropCapture={handleChatDropCapture}
5077
+ onDrop={handleChatDrop}
5085
5078
  >
5086
- <MessageScroller className="agent-chat-scroll">
5087
- <MessageScrollerViewport ref={scrollRef}>
5088
- {authError ? (
5089
- <div className="flex flex-col items-center justify-center h-full px-4 gap-3">
5090
- <div className="flex h-10 w-10 items-center justify-center rounded-full bg-muted">
5091
- {authSessionAvailable ? (
5092
- <IconRefresh className="h-5 w-5 text-muted-foreground" />
5093
- ) : (
5094
- <IconMessage className="h-5 w-5 text-muted-foreground" />
5095
- )}
5096
- </div>
5097
- <div className="text-center max-w-[280px]">
5098
- <p className="text-sm font-medium text-foreground mb-1">
5099
- {authSessionAvailable
5100
- ? "Chat session needs refresh"
5101
- : authError.sessionExpired
5102
- ? "Session expired"
5103
- : "Authentication required"}
5104
- </p>
5105
- <p className="text-xs text-muted-foreground leading-relaxed">
5106
- {authSessionAvailable
5107
- ? "You're signed in, but this chat connection needs to reconnect."
5108
- : authError.sessionExpired
5109
- ? "Your session may have expired. Log out and log back in to reconnect."
5110
- : "You need to log in to use the agent."}
5111
- </p>
5112
- </div>
5113
- <div className="flex gap-2">
5114
- {!authError.sessionExpired &&
5115
- !authSessionAvailable && (
5079
+ {dropActive && (
5080
+ <div
5081
+ aria-hidden="true"
5082
+ className="pointer-events-none absolute inset-0 z-50 flex items-center justify-center rounded-md border-2 border-dashed border-primary/70 bg-primary/5 backdrop-blur-[1px]"
5083
+ >
5084
+ <span className="rounded-md bg-background/90 px-3 py-1.5 text-xs font-medium text-foreground shadow-sm">
5085
+ Drop to attach
5086
+ </span>
5087
+ </div>
5088
+ )}
5089
+ {showHeader && (
5090
+ <div className="flex h-11 shrink-0 items-center justify-between border-b border-border px-4">
5091
+ <span className="text-[13px] font-medium text-muted-foreground">
5092
+ Agent
5093
+ </span>
5094
+ <div className="flex items-center gap-1">
5095
+ {onSwitchToCli && (
5096
+ <TooltipProvider delayDuration={200}>
5097
+ <Tooltip>
5098
+ <TooltipTrigger asChild>
5116
5099
  <button
5117
- onClick={() => {
5118
- const ret =
5119
- window.location.pathname +
5120
- window.location.search;
5121
- window.location.href =
5122
- agentNativePath(
5123
- "/_agent-native/sign-in",
5124
- ) + `?return=${encodeURIComponent(ret)}`;
5125
- }}
5126
- className="text-xs text-background bg-foreground hover:opacity-90 px-3 py-1.5 rounded-md"
5100
+ onClick={onSwitchToCli}
5101
+ aria-label="Switch to CLI"
5102
+ className="flex items-center gap-1 text-[12px] text-muted-foreground hover:text-foreground px-2 py-1 rounded-md hover:bg-accent"
5127
5103
  >
5128
- Log in
5104
+ <IconTerminal className="h-3.5 w-3.5" />
5105
+ CLI
5129
5106
  </button>
5107
+ </TooltipTrigger>
5108
+ <TooltipContent>Switch to CLI</TooltipContent>
5109
+ </Tooltip>
5110
+ </TooltipProvider>
5111
+ )}
5112
+ </div>
5113
+ </div>
5114
+ )}
5115
+
5116
+ {/* Messages area */}
5117
+ <MessageScrollerProvider
5118
+ key={chatScrollResetKey}
5119
+ autoScroll={false}
5120
+ >
5121
+ <MessageScroller className="agent-chat-scroll">
5122
+ <MessageScrollerViewport ref={scrollRef}>
5123
+ {authError ? (
5124
+ <div className="flex flex-col items-center justify-center h-full px-4 gap-3">
5125
+ <div className="flex h-10 w-10 items-center justify-center rounded-full bg-muted">
5126
+ {authSessionAvailable ? (
5127
+ <IconRefresh className="h-5 w-5 text-muted-foreground" />
5128
+ ) : (
5129
+ <IconMessage className="h-5 w-5 text-muted-foreground" />
5130
5130
  )}
5131
- {authError.sessionExpired &&
5132
- !authSessionAvailable && (
5133
- <button
5134
- onClick={async () => {
5135
- try {
5136
- await fetch(
5131
+ </div>
5132
+ <div className="text-center max-w-[280px]">
5133
+ <p className="text-sm font-medium text-foreground mb-1">
5134
+ {authSessionAvailable
5135
+ ? "Chat session needs refresh"
5136
+ : authError.sessionExpired
5137
+ ? "Session expired"
5138
+ : "Authentication required"}
5139
+ </p>
5140
+ <p className="text-xs text-muted-foreground leading-relaxed">
5141
+ {authSessionAvailable
5142
+ ? "You're signed in, but this chat connection needs to reconnect."
5143
+ : authError.sessionExpired
5144
+ ? "Your session may have expired. Log out and log back in to reconnect."
5145
+ : "You need to log in to use the agent."}
5146
+ </p>
5147
+ </div>
5148
+ <div className="flex gap-2">
5149
+ {!authError.sessionExpired &&
5150
+ !authSessionAvailable && (
5151
+ <button
5152
+ onClick={() => {
5153
+ const ret =
5154
+ window.location.pathname +
5155
+ window.location.search;
5156
+ window.location.href =
5137
5157
  agentNativePath(
5138
- "/_agent-native/auth/logout",
5139
- ),
5140
- {
5141
- method: "POST",
5142
- },
5143
- );
5144
- } catch {}
5145
- window.location.reload();
5146
- }}
5147
- className="text-xs text-destructive hover:text-destructive/80 px-3 py-1.5 rounded-md border border-destructive/30 hover:bg-destructive/10"
5148
- >
5149
- Log out
5150
- </button>
5151
- )}
5152
- <button
5153
- onClick={() => {
5154
- setAuthError(null);
5155
- window.location.reload();
5156
- }}
5157
- className={
5158
- authSessionAvailable
5159
- ? "text-xs text-background bg-foreground hover:opacity-90 px-3 py-1.5 rounded-md"
5160
- : "text-xs text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md border border-border hover:bg-accent"
5161
- }
5162
- >
5163
- Refresh chat
5164
- </button>
5165
- </div>
5166
- </div>
5167
- ) : isRestoring && centeredRestoringState ? (
5168
- <div
5169
- className={cn(
5170
- "agent-empty-state",
5171
- emptyStateDisplay === "hidden"
5172
- ? "sr-only"
5173
- : "flex h-full flex-col items-center justify-center gap-3 px-4 py-16",
5174
- )}
5175
- aria-busy="true"
5176
- >
5177
- <IconMessage className="h-5 w-5 text-muted-foreground/60" />
5178
- <p className="sr-only">
5179
- {emptyStateText ?? "Loading chat..."}
5180
- </p>
5181
- </div>
5182
- ) : isRestoring ? (
5183
- <div className="flex flex-col gap-3 p-4">
5184
- <div className="flex justify-end">
5185
- <div className="h-8 w-32 rounded-lg bg-muted animate-pulse" />
5158
+ "/_agent-native/sign-in",
5159
+ ) +
5160
+ `?return=${encodeURIComponent(ret)}`;
5161
+ }}
5162
+ className="text-xs text-background bg-foreground hover:opacity-90 px-3 py-1.5 rounded-md"
5163
+ >
5164
+ Log in
5165
+ </button>
5166
+ )}
5167
+ {authError.sessionExpired &&
5168
+ !authSessionAvailable && (
5169
+ <button
5170
+ onClick={async () => {
5171
+ try {
5172
+ await fetch(
5173
+ agentNativePath(
5174
+ "/_agent-native/auth/logout",
5175
+ ),
5176
+ {
5177
+ method: "POST",
5178
+ },
5179
+ );
5180
+ } catch {}
5181
+ window.location.reload();
5182
+ }}
5183
+ className="text-xs text-destructive hover:text-destructive/80 px-3 py-1.5 rounded-md border border-destructive/30 hover:bg-destructive/10"
5184
+ >
5185
+ Log out
5186
+ </button>
5187
+ )}
5188
+ <button
5189
+ onClick={() => {
5190
+ setAuthError(null);
5191
+ window.location.reload();
5192
+ }}
5193
+ className={
5194
+ authSessionAvailable
5195
+ ? "text-xs text-background bg-foreground hover:opacity-90 px-3 py-1.5 rounded-md"
5196
+ : "text-xs text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md border border-border hover:bg-accent"
5197
+ }
5198
+ >
5199
+ Refresh chat
5200
+ </button>
5201
+ </div>
5186
5202
  </div>
5187
- <div className="flex flex-col gap-1.5">
5188
- <div className="h-4 w-48 rounded bg-muted animate-pulse" />
5189
- <div className="h-4 w-64 rounded bg-muted animate-pulse" />
5190
- <div className="h-4 w-40 rounded bg-muted animate-pulse" />
5203
+ ) : isRestoring && centeredRestoringState ? (
5204
+ <div
5205
+ className={cn(
5206
+ "agent-empty-state",
5207
+ emptyStateDisplay === "hidden"
5208
+ ? "sr-only"
5209
+ : "flex h-full flex-col items-center justify-center gap-3 px-4 py-16",
5210
+ )}
5211
+ aria-busy="true"
5212
+ >
5213
+ <IconMessage className="h-5 w-5 text-muted-foreground/60" />
5214
+ <p className="sr-only">
5215
+ {emptyStateText ?? "Loading chat..."}
5216
+ </p>
5191
5217
  </div>
5192
- </div>
5193
- ) : showEmptyState ? (
5194
- <div
5195
- className={cn(
5196
- "agent-empty-state",
5197
- emptyStateDisplay === "hidden"
5198
- ? "sr-only"
5199
- : "flex h-full flex-col items-center justify-center gap-3 px-4 py-16",
5200
- )}
5201
- >
5202
- <IconMessage className="h-5 w-5 text-muted-foreground/60" />
5203
- <p className="sr-only">
5204
- {emptyStateText ?? "How can I help you?"}
5205
- </p>
5206
- {emptyStateAddon}
5207
- {resolvedSuggestions &&
5208
- resolvedSuggestions.length > 0 ? (
5209
- <div className="flex w-full max-w-[280px] flex-col gap-1">
5210
- {resolvedSuggestions.map((suggestion) => (
5211
- <button
5212
- key={suggestion}
5213
- onClick={() => {
5214
- if (missingApiKey) {
5215
- requestMissingKeySetup();
5216
- return;
5217
- }
5218
- void addToQueue(suggestion);
5219
- }}
5220
- className="w-full px-2 py-1 text-center text-[13px] text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
5221
- >
5222
- {suggestion}
5223
- </button>
5224
- ))}
5218
+ ) : isRestoring ? (
5219
+ <div className="flex flex-col gap-3 p-4">
5220
+ <div className="flex justify-end">
5221
+ <div className="h-8 w-32 rounded-lg bg-muted animate-pulse" />
5225
5222
  </div>
5226
- ) : null}
5227
- {showInlineEmptyThreadFooterSlot ? (
5228
- <div className="agent-thread-footer-slot agent-thread-footer-slot--empty">
5229
- {resolvedThreadFooterSlot}
5223
+ <div className="flex flex-col gap-1.5">
5224
+ <div className="h-4 w-48 rounded bg-muted animate-pulse" />
5225
+ <div className="h-4 w-64 rounded bg-muted animate-pulse" />
5226
+ <div className="h-4 w-40 rounded bg-muted animate-pulse" />
5230
5227
  </div>
5231
- ) : null}
5232
- </div>
5233
- ) : (
5234
- <MessageScrollerContent className="agent-thread-content gap-4 px-4 py-4">
5235
- <AssistantMessageListErrorBoundary
5236
- resetKey={messageListResetKey}
5228
+ </div>
5229
+ ) : showEmptyState ? (
5230
+ <div
5231
+ className={cn(
5232
+ "agent-empty-state",
5233
+ emptyStateDisplay === "hidden"
5234
+ ? "sr-only"
5235
+ : "flex h-full flex-col items-center justify-center gap-3 px-4 py-16",
5236
+ )}
5237
5237
  >
5238
- <ThreadPrimitive.Messages
5239
- components={{
5240
- UserMessage: AssistantChatUserMessageItem,
5241
- AssistantMessage:
5242
- AssistantChatAssistantMessageItem,
5243
- }}
5244
- />
5245
- </AssistantMessageListErrorBoundary>
5246
- {visibleLoopLimit && !showRunningInUI && (
5247
- <MessageScrollerItem>
5248
- <LoopLimitContinueCard
5249
- info={visibleLoopLimit}
5250
- onContinue={() => {
5251
- setShowContinue(false);
5252
- setLoopLimitInfo(null);
5253
- addToQueue(
5254
- "Continue from where you left off.",
5255
- undefined,
5256
- undefined,
5257
- undefined,
5258
- undefined,
5259
- "queued",
5260
- "continue",
5261
- );
5262
- }}
5263
- />
5264
- </MessageScrollerItem>
5265
- )}
5266
- {shouldShowRunError && visibleRunError && (
5267
- <MessageScrollerItem>
5268
- <RunErrorRecoveryCard
5269
- info={visibleRunError}
5270
- onContinue={() => {
5271
- setRunErrorInfo(null);
5272
- addToQueue(
5273
- RECONNECT_NO_PROGRESS_CONTINUE_MESSAGE,
5274
- undefined,
5275
- undefined,
5276
- undefined,
5277
- undefined,
5278
- "queued",
5279
- "continue",
5280
- );
5281
- }}
5282
- onRetry={() => {
5283
- setRunErrorInfo(null);
5284
- addToQueue(
5285
- lastUserText
5286
- ? `Retry the previous request from a clean approach. Do not rerun the exact same failed tool input unless the failure was transient or the user explicitly asked for an exact rerun. If a provider query failed because of schema, syntax, or type mismatch, diagnose the error and adjust the query first.\n\nOriginal request:\n\n${lastUserText}`
5287
- : "Retry the previous request from a clean approach. Do not rerun the exact same failed tool input unless the failure was transient or the user explicitly asked for an exact rerun. If a provider query failed because of schema, syntax, or type mismatch, diagnose the error and adjust the query first.",
5288
- undefined,
5289
- undefined,
5290
- undefined,
5291
- undefined,
5292
- "queued",
5293
- "retry",
5294
- );
5295
- }}
5296
- onFork={onForkChat}
5297
- onDismiss={() => {
5298
- if (visibleRunErrorKey) {
5299
- setDismissedRunErrorKey(visibleRunErrorKey);
5300
- }
5301
- setRunErrorInfo(null);
5238
+ <IconMessage className="h-5 w-5 text-muted-foreground/60" />
5239
+ <p className="sr-only">
5240
+ {emptyStateText ?? "How can I help you?"}
5241
+ </p>
5242
+ {emptyStateAddon}
5243
+ {resolvedSuggestions &&
5244
+ resolvedSuggestions.length > 0 ? (
5245
+ <div className="flex w-full max-w-[280px] flex-col gap-1">
5246
+ {resolvedSuggestions.map((suggestion) => (
5247
+ <button
5248
+ key={suggestion}
5249
+ onClick={() => {
5250
+ if (missingApiKey) {
5251
+ requestMissingKeySetup();
5252
+ return;
5253
+ }
5254
+ void addToQueue(suggestion);
5255
+ }}
5256
+ className="w-full px-2 py-1 text-center text-[13px] text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
5257
+ >
5258
+ {suggestion}
5259
+ </button>
5260
+ ))}
5261
+ </div>
5262
+ ) : null}
5263
+ {showInlineEmptyThreadFooterSlot ? (
5264
+ <div className="agent-thread-footer-slot agent-thread-footer-slot--empty">
5265
+ {resolvedThreadFooterSlot}
5266
+ </div>
5267
+ ) : null}
5268
+ </div>
5269
+ ) : (
5270
+ <MessageScrollerContent className="agent-thread-content gap-4 px-4 py-4">
5271
+ <AssistantMessageListErrorBoundary
5272
+ resetKey={messageListResetKey}
5273
+ >
5274
+ <ThreadPrimitive.Messages
5275
+ components={{
5276
+ UserMessage: AssistantChatUserMessageItem,
5277
+ AssistantMessage:
5278
+ AssistantChatAssistantMessageItem,
5302
5279
  }}
5303
5280
  />
5304
- </MessageScrollerItem>
5305
- )}
5306
- {(isReconnecting ||
5307
- reconnectFrozen ||
5308
- adapterHandoffPending) &&
5309
- visibleReconnectContent.length > 0 && (
5281
+ </AssistantMessageListErrorBoundary>
5282
+ {visibleLoopLimit && !showRunningInUI && (
5310
5283
  <MessageScrollerItem>
5311
- <ReconnectStreamMessage
5312
- content={visibleReconnectContent}
5284
+ <LoopLimitContinueCard
5285
+ info={visibleLoopLimit}
5286
+ onContinue={() => {
5287
+ setShowContinue(false);
5288
+ setLoopLimitInfo(null);
5289
+ addToQueue(
5290
+ "Continue from where you left off.",
5291
+ undefined,
5292
+ undefined,
5293
+ undefined,
5294
+ undefined,
5295
+ "queued",
5296
+ "continue",
5297
+ );
5298
+ }}
5313
5299
  />
5314
5300
  </MessageScrollerItem>
5315
5301
  )}
5316
- {(isReconnecting ||
5317
- reconnectFrozen ||
5318
- adapterHandoffPending) &&
5319
- visibleReconnectContent.length === 0 &&
5320
- reconnectContent.length === 0 &&
5321
- reconnectActivityContent.length > 0 && (
5302
+ {shouldShowRunError && visibleRunError && (
5322
5303
  <MessageScrollerItem>
5323
- <ReconnectStreamMessage
5324
- content={reconnectActivityContent}
5304
+ <RunErrorRecoveryCard
5305
+ info={visibleRunError}
5306
+ onContinue={() => {
5307
+ setRunErrorInfo(null);
5308
+ addToQueue(
5309
+ RECONNECT_NO_PROGRESS_CONTINUE_MESSAGE,
5310
+ undefined,
5311
+ undefined,
5312
+ undefined,
5313
+ undefined,
5314
+ "queued",
5315
+ "continue",
5316
+ );
5317
+ }}
5318
+ onRetry={() => {
5319
+ setRunErrorInfo(null);
5320
+ addToQueue(
5321
+ lastUserText
5322
+ ? `Retry the previous request from a clean approach. Do not rerun the exact same failed tool input unless the failure was transient or the user explicitly asked for an exact rerun. If a provider query failed because of schema, syntax, or type mismatch, diagnose the error and adjust the query first.\n\nOriginal request:\n\n${lastUserText}`
5323
+ : "Retry the previous request from a clean approach. Do not rerun the exact same failed tool input unless the failure was transient or the user explicitly asked for an exact rerun. If a provider query failed because of schema, syntax, or type mismatch, diagnose the error and adjust the query first.",
5324
+ undefined,
5325
+ undefined,
5326
+ undefined,
5327
+ undefined,
5328
+ "queued",
5329
+ "retry",
5330
+ );
5331
+ }}
5332
+ onFork={onForkChat}
5333
+ onDismiss={() => {
5334
+ if (visibleRunErrorKey) {
5335
+ setDismissedRunErrorKey(
5336
+ visibleRunErrorKey,
5337
+ );
5338
+ }
5339
+ setRunErrorInfo(null);
5340
+ }}
5325
5341
  />
5326
5342
  </MessageScrollerItem>
5327
5343
  )}
5328
- {showGlobalRunningStatus && (
5329
- <MessageScrollerItem>
5330
- <RunningActivityStatus
5331
- label={runningStatusLabel}
5332
- />
5333
- </MessageScrollerItem>
5334
- )}
5335
- {queuedMessages
5336
- .filter((msg) => !msg.hideUserMessage)
5337
- .map((msg) => {
5338
- const displayText = displayableUserMessageText(
5339
- msg.text,
5340
- );
5341
- return (
5342
- <MessageScrollerItem
5343
- key={msg.id}
5344
- messageId={msg.id}
5345
- >
5346
- <div className="group flex items-start justify-end gap-1.5">
5347
- <button
5348
- type="button"
5349
- onClick={() =>
5350
- applyLocalQueuedMessages((prev) =>
5351
- prev.filter((m) => m.id !== msg.id),
5352
- )
5353
- }
5354
- aria-label="Remove from queue"
5355
- className="mt-1.5 flex h-5 w-5 items-center justify-center rounded-full border border-border bg-background text-muted-foreground opacity-0 shadow-sm transition-opacity hover:bg-accent hover:text-foreground focus-visible:opacity-100 group-hover:opacity-100"
5356
- >
5357
- <IconX className="h-3 w-3" />
5358
- </button>
5359
- <div className="max-w-[85%] rounded-lg bg-accent/50 px-3 py-2 text-sm leading-relaxed text-foreground/60 whitespace-pre-wrap break-words">
5360
- {displayText}
5361
- {msg.images && msg.images.length > 0 && (
5362
- <div className="flex flex-wrap gap-1.5 mt-1.5">
5363
- {msg.images.map((img, j) => (
5364
- <img
5365
- key={j}
5366
- src={img}
5367
- alt=""
5368
- className="h-12 w-12 rounded object-cover border border-border/50"
5369
- />
5370
- ))}
5371
- </div>
5372
- )}
5373
- </div>
5374
- </div>
5344
+ {(isReconnecting ||
5345
+ reconnectFrozen ||
5346
+ adapterHandoffPending) &&
5347
+ visibleReconnectContent.length > 0 && (
5348
+ <MessageScrollerItem>
5349
+ <ReconnectStreamMessage
5350
+ content={visibleReconnectContent}
5351
+ />
5375
5352
  </MessageScrollerItem>
5376
- );
5377
- })}
5378
- {resolvedThreadFooterSlot ? (
5379
- <MessageScrollerItem>
5380
- <div className="agent-thread-footer-slot">
5381
- {resolvedThreadFooterSlot}
5382
- </div>
5383
- </MessageScrollerItem>
5384
- ) : null}
5385
- </MessageScrollerContent>
5386
- )}
5387
- </MessageScrollerViewport>
5388
- {!authError &&
5389
- !isRestoring &&
5390
- !showEmptyState &&
5391
- showScrollToBottom ? (
5392
- <div className="shrink-0 flex justify-center -mb-1">
5393
- <button
5394
- type="button"
5395
- onClick={scrollToBottom}
5396
- className="flex h-7 w-7 items-center justify-center rounded-full border border-border bg-background shadow-sm hover:bg-accent"
5397
- aria-label="Scroll to bottom"
5398
- >
5399
- <IconChevronDown className="h-3.5 w-3.5 text-muted-foreground" />
5400
- </button>
5401
- </div>
5402
- ) : null}
5403
- </MessageScroller>
5404
- </MessageScrollerProvider>
5405
-
5406
- {showComposerSlot ? composerSlot : null}
5407
- {isActiveComposer && (
5408
- <McpConnectionSuggestion text={composerText} />
5409
- )}
5410
- {showCenteredEmptyThreadFooterSlot ? (
5411
- <div className="agent-thread-footer-slot agent-thread-footer-slot--centered-empty">
5412
- {resolvedThreadFooterSlot}
5413
- </div>
5414
- ) : null}
5415
- {guidedQuestions && guidedQuestions.length > 0 && (
5416
- <div className="shrink-0 px-3 pb-2">
5417
- <GuidedQuestionFlow
5418
- questions={guidedQuestions}
5419
- onSubmit={handleGuidedQuestionsSubmit}
5420
- onSkip={handleGuidedQuestionsSkip}
5421
- {...(guidedQuestionsTitle
5422
- ? { title: guidedQuestionsTitle }
5423
- : {})}
5424
- {...(guidedQuestionsDescription
5425
- ? { description: guidedQuestionsDescription }
5426
- : {})}
5427
- {...(guidedQuestionsSkipLabel
5428
- ? { skipLabel: guidedQuestionsSkipLabel }
5429
- : {})}
5430
- {...(guidedQuestionsSubmitLabel
5431
- ? { submitLabel: guidedQuestionsSubmitLabel }
5432
- : {})}
5433
- className="h-auto items-stretch justify-stretch bg-transparent"
5434
- />
5435
- </div>
5436
- )}
5437
- {/* Inline attachment / body-size error */}
5438
- {composerError && (
5439
- <div
5440
- role="alert"
5441
- className="shrink-0 mx-3 mb-1.5 flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive"
5442
- >
5443
- <IconAlertTriangle className="h-3.5 w-3.5 mt-0.5 shrink-0" />
5444
- <span className="flex-1 leading-snug">{composerError}</span>
5445
- <button
5446
- type="button"
5447
- aria-label="Dismiss error"
5448
- onClick={() => setComposerError(null)}
5449
- className="shrink-0 opacity-70 hover:opacity-100"
5353
+ )}
5354
+ {(isReconnecting ||
5355
+ reconnectFrozen ||
5356
+ adapterHandoffPending) &&
5357
+ visibleReconnectContent.length === 0 &&
5358
+ reconnectContent.length === 0 &&
5359
+ reconnectActivityContent.length > 0 && (
5360
+ <MessageScrollerItem>
5361
+ <ReconnectStreamMessage
5362
+ content={reconnectActivityContent}
5363
+ />
5364
+ </MessageScrollerItem>
5365
+ )}
5366
+ {showGlobalRunningStatus && (
5367
+ <MessageScrollerItem>
5368
+ <RunningActivityStatus
5369
+ label={runningStatusLabel}
5370
+ />
5371
+ </MessageScrollerItem>
5372
+ )}
5373
+ {queuedMessages
5374
+ .filter((msg) => !msg.hideUserMessage)
5375
+ .map((msg) => {
5376
+ const displayText = displayableUserMessageText(
5377
+ msg.text,
5378
+ );
5379
+ const imageSources =
5380
+ queuedMessageImageSources(msg);
5381
+ return (
5382
+ <MessageScrollerItem
5383
+ key={msg.id}
5384
+ messageId={msg.id}
5385
+ >
5386
+ <div className="group flex items-start justify-end gap-1.5">
5387
+ <button
5388
+ type="button"
5389
+ onClick={() =>
5390
+ applyLocalQueuedMessages((prev) =>
5391
+ prev.filter((m) => m.id !== msg.id),
5392
+ )
5393
+ }
5394
+ aria-label="Remove from queue"
5395
+ className="mt-1.5 flex h-5 w-5 items-center justify-center rounded-full border border-border bg-background text-muted-foreground opacity-0 shadow-sm transition-opacity hover:bg-accent hover:text-foreground focus-visible:opacity-100 group-hover:opacity-100"
5396
+ >
5397
+ <IconX className="h-3 w-3" />
5398
+ </button>
5399
+ <div className="max-w-[85%] rounded-lg bg-accent/50 px-3 py-2 text-sm leading-relaxed text-foreground/60 whitespace-pre-wrap break-words">
5400
+ {displayText}
5401
+ {imageSources.length > 0 && (
5402
+ <div className="flex flex-wrap gap-1.5 mt-1.5">
5403
+ {imageSources.map((img, j) => (
5404
+ <img
5405
+ key={j}
5406
+ src={img}
5407
+ alt=""
5408
+ className="h-12 w-12 rounded object-cover border border-border/50"
5409
+ />
5410
+ ))}
5411
+ </div>
5412
+ )}
5413
+ </div>
5414
+ </div>
5415
+ </MessageScrollerItem>
5416
+ );
5417
+ })}
5418
+ {resolvedThreadFooterSlot ? (
5419
+ <MessageScrollerItem>
5420
+ <div className="agent-thread-footer-slot">
5421
+ {resolvedThreadFooterSlot}
5422
+ </div>
5423
+ </MessageScrollerItem>
5424
+ ) : null}
5425
+ </MessageScrollerContent>
5426
+ )}
5427
+ </MessageScrollerViewport>
5428
+ {!authError &&
5429
+ !isRestoring &&
5430
+ !showEmptyState &&
5431
+ showScrollToBottom ? (
5432
+ <div className="shrink-0 flex justify-center -mb-1">
5433
+ <button
5434
+ type="button"
5435
+ onClick={scrollToBottom}
5436
+ className="flex h-7 w-7 items-center justify-center rounded-full border border-border bg-background shadow-sm hover:bg-accent"
5437
+ aria-label="Scroll to bottom"
5438
+ >
5439
+ <IconChevronDown className="h-3.5 w-3.5 text-muted-foreground" />
5440
+ </button>
5441
+ </div>
5442
+ ) : null}
5443
+ </MessageScroller>
5444
+ </MessageScrollerProvider>
5445
+
5446
+ {showComposerSlot ? composerSlot : null}
5447
+ {isActiveComposer && (
5448
+ <McpConnectionSuggestion text={composerText} />
5449
+ )}
5450
+ {showCenteredEmptyThreadFooterSlot ? (
5451
+ <div className="agent-thread-footer-slot agent-thread-footer-slot--centered-empty">
5452
+ {resolvedThreadFooterSlot}
5453
+ </div>
5454
+ ) : null}
5455
+ {guidedQuestions && guidedQuestions.length > 0 && (
5456
+ <div className="shrink-0 px-3 pb-2">
5457
+ <GuidedQuestionFlow
5458
+ questions={guidedQuestions}
5459
+ onSubmit={handleGuidedQuestionsSubmit}
5460
+ onSkip={handleGuidedQuestionsSkip}
5461
+ {...(guidedQuestionsTitle
5462
+ ? { title: guidedQuestionsTitle }
5463
+ : {})}
5464
+ {...(guidedQuestionsDescription
5465
+ ? { description: guidedQuestionsDescription }
5466
+ : {})}
5467
+ {...(guidedQuestionsSkipLabel
5468
+ ? { skipLabel: guidedQuestionsSkipLabel }
5469
+ : {})}
5470
+ {...(guidedQuestionsSubmitLabel
5471
+ ? { submitLabel: guidedQuestionsSubmitLabel }
5472
+ : {})}
5473
+ className="h-auto items-stretch justify-stretch bg-transparent"
5474
+ />
5475
+ </div>
5476
+ )}
5477
+ {/* Inline attachment / body-size error */}
5478
+ {composerError && (
5479
+ <div
5480
+ role="alert"
5481
+ className="shrink-0 mx-3 mb-1.5 flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive"
5450
5482
  >
5451
- <IconX className="h-3 w-3" />
5452
- </button>
5453
- </div>
5454
- )}
5455
- <div
5456
- className="agent-composer-stack"
5457
- data-agent-composer-adjacent-ui={
5458
- hasComposerAccessoryAboveStack ? "true" : undefined
5459
- }
5460
- >
5461
- <SelectionAttachedPill />
5462
- {showPlanModeCallout && (
5463
- <PlanModeCallout
5464
- canImplementPlan={canImplementPlan}
5465
- onImplementPlan={handleImplementPlan}
5466
- onSwitchToAct={handleSwitchToAct}
5467
- />
5483
+ <IconAlertTriangle className="h-3.5 w-3.5 mt-0.5 shrink-0" />
5484
+ <span className="flex-1 leading-snug">
5485
+ {composerError}
5486
+ </span>
5487
+ <button
5488
+ type="button"
5489
+ aria-label="Dismiss error"
5490
+ onClick={() => setComposerError(null)}
5491
+ className="shrink-0 opacity-70 hover:opacity-100"
5492
+ >
5493
+ <IconX className="h-3 w-3" />
5494
+ </button>
5495
+ </div>
5468
5496
  )}
5469
- {/* Input area */}
5470
- <Popover
5471
- open={showMissingKeySetup && missingKeySetupOpen}
5472
- onOpenChange={setMissingKeySetupOpen}
5497
+ <div
5498
+ className="agent-composer-stack"
5499
+ data-agent-composer-adjacent-ui={
5500
+ hasComposerAccessoryAboveStack ? "true" : undefined
5501
+ }
5473
5502
  >
5474
- <AgentComposerFrame
5475
- layoutVariant={composerLayoutVariant}
5476
- className={cn(
5477
- composerAreaClassName,
5478
- isComposerDisabled &&
5479
- !showMissingKeySetup &&
5480
- "opacity-70",
5481
- )}
5482
- rootClassName={cn(
5483
- showMissingKeySetup &&
5484
- "agent-composer-root--missing-key",
5485
- )}
5503
+ <SelectionAttachedPill />
5504
+ {showPlanModeCallout && (
5505
+ <PlanModeCallout
5506
+ canImplementPlan={canImplementPlan}
5507
+ onImplementPlan={handleImplementPlan}
5508
+ onSwitchToAct={handleSwitchToAct}
5509
+ />
5510
+ )}
5511
+ {/* Input area */}
5512
+ <Popover
5513
+ open={showMissingKeySetup && missingKeySetupOpen}
5514
+ onOpenChange={setMissingKeySetupOpen}
5486
5515
  >
5487
- {showMissingKeySetup ? (
5488
- <PopoverTrigger asChild>
5489
- <button
5490
- type="button"
5491
- className="agent-composer-missing-key-trigger"
5492
- aria-label="Connect AI to start chatting"
5493
- >
5494
- <span className="agent-composer-missing-key-copy">
5495
- <span className="agent-composer-missing-key-title">
5496
- {missingApiKeySetupLayout === "sidebar"
5497
- ? "Connect AI to chat"
5498
- : "Connect AI to start chatting"}
5499
- </span>
5500
- {missingApiKeySetupLayout !== "sidebar" ? (
5501
- <span className="agent-composer-missing-key-description">
5502
- Builder.io includes free credits, or use your
5503
- own API key.
5516
+ <AgentComposerFrame
5517
+ layoutVariant={composerLayoutVariant}
5518
+ className={cn(
5519
+ composerAreaClassName,
5520
+ isComposerDisabled &&
5521
+ !showMissingKeySetup &&
5522
+ "opacity-70",
5523
+ )}
5524
+ rootClassName={cn(
5525
+ showMissingKeySetup &&
5526
+ "agent-composer-root--missing-key",
5527
+ )}
5528
+ >
5529
+ {showMissingKeySetup ? (
5530
+ <PopoverTrigger asChild>
5531
+ <button
5532
+ type="button"
5533
+ className="agent-composer-missing-key-trigger"
5534
+ aria-label="Connect AI to start chatting"
5535
+ >
5536
+ <span className="agent-composer-missing-key-copy">
5537
+ <span className="agent-composer-missing-key-title">
5538
+ {missingApiKeySetupLayout === "sidebar"
5539
+ ? "Connect AI to chat"
5540
+ : "Connect AI to start chatting"}
5504
5541
  </span>
5505
- ) : null}
5506
- </span>
5507
- </button>
5508
- </PopoverTrigger>
5509
- ) : (
5510
- <>
5511
- <ComposerAttachmentPreviewStrip />
5512
- <TiptapComposer
5513
- focusRef={tiptapRef}
5514
- onTextChange={
5515
- isActiveComposer
5516
- ? handleComposerTextChange
5517
- : undefined
5518
- }
5519
- disabled={isComposerDisabled}
5520
- placeholder={
5521
- missingApiKey
5522
- ? "Connect AI to start chatting..."
5523
- : isProviderStatusChecking
5524
- ? t("agentPanel.checkingAiConnection")
5525
- : composerDisabled
5526
- ? (composerDisabledPlaceholder ??
5527
- "Open Desktop to use this chat.")
5528
- : isRunning
5529
- ? queuedMessages.length > 0
5530
- ? `${queuedMessages.length} queued — send a follow-up...`
5531
- : "Send a follow-up..."
5532
- : composerPlaceholder
5533
- }
5534
- onSubmit={
5535
- isRunning || composerContextItems.length > 0
5536
- ? (text, references, attachments, options) =>
5537
- void addToQueue(
5538
- text,
5539
- undefined,
5540
- references.length > 0
5541
- ? references
5542
- : undefined,
5543
- attachments,
5544
- undefined,
5545
- resolveAssistantChatSubmitIntent({
5546
- isRunning,
5547
- requestedIntent: options?.intent,
5548
- }),
5549
- undefined,
5550
- true,
5551
- )
5552
- : undefined
5553
- }
5554
- onSlashCommand={onSlashCommand}
5555
- execMode={execMode}
5556
- onExecModeChange={onExecModeChange}
5557
- planModeDisabled={planModeDisabled}
5558
- planModeDisabledReason={planModeDisabledReason}
5559
- selectedModel={selectedModel ?? defaultModel}
5560
- selectedEffort={selectedEffort}
5561
- availableModels={availableModels}
5562
- modelListLoading={modelListLoading}
5563
- onModelChange={onModelChange}
5564
- onEffortChange={onEffortChange}
5565
- imageModelMenu={imageModelMenu}
5566
- onConnectProvider={onConnectProvider}
5567
- onConnectLocalRuntime={onConnectLocalRuntime}
5568
- toolbarSlot={composerToolbarSlot}
5569
- contextItems={composerContextItems}
5570
- onRemoveContextItem={removeComposerContextItem}
5571
- plusMenuMode={plusMenuMode}
5572
- layoutVariant={composerLayoutVariant}
5573
- providerConnectStatusEnabled={
5574
- providerStatusChecksEnabled
5575
- }
5576
- voiceEnabled
5577
- draftScope={threadId || tabId}
5578
- interceptBuildRequestsForBuilder
5579
- onAttachmentError={setComposerError}
5580
- extraActionButton={
5581
- contextXRayEnabled ||
5582
- composerExtraActionButton ? (
5583
- <>
5584
- {contextXRayEnabled && (
5585
- <ContextMeter threadId={threadId} />
5586
- )}
5587
- {composerExtraActionButton}
5588
- </>
5589
- ) : undefined
5590
- }
5591
- stopButton={
5592
- showRunningInUI ? (
5593
- <Tooltip>
5594
- <TooltipTrigger asChild>
5595
- <button
5596
- type="button"
5597
- onClick={() => stopActiveRun()}
5598
- aria-label="Stop response"
5599
- data-agent-composer-slot="stop-button"
5600
- className="shrink-0 flex h-7 w-7 cursor-pointer items-center justify-center rounded-full bg-primary text-primary-foreground shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
5601
- >
5602
- <IconPlayerStopFilled className="h-3 w-3" />
5603
- </button>
5604
- </TooltipTrigger>
5605
- <TooltipContent>Stop response</TooltipContent>
5606
- </Tooltip>
5607
- ) : undefined
5608
- }
5542
+ {missingApiKeySetupLayout !== "sidebar" ? (
5543
+ <span className="agent-composer-missing-key-description">
5544
+ Builder.io includes free credits, or use
5545
+ your own API key.
5546
+ </span>
5547
+ ) : null}
5548
+ </span>
5549
+ </button>
5550
+ </PopoverTrigger>
5551
+ ) : (
5552
+ <>
5553
+ <ComposerAttachmentPreviewStrip />
5554
+ <TiptapComposer
5555
+ focusRef={tiptapRef}
5556
+ onTextChange={
5557
+ isActiveComposer
5558
+ ? handleComposerTextChange
5559
+ : undefined
5560
+ }
5561
+ disabled={isComposerDisabled}
5562
+ placeholder={
5563
+ missingApiKey
5564
+ ? "Connect AI to start chatting..."
5565
+ : isProviderStatusChecking
5566
+ ? t("agentPanel.checkingAiConnection")
5567
+ : composerDisabled
5568
+ ? (composerDisabledPlaceholder ??
5569
+ "Open Desktop to use this chat.")
5570
+ : isRunning
5571
+ ? queuedMessages.length > 0
5572
+ ? `${queuedMessages.length} queued — send a follow-up...`
5573
+ : "Send a follow-up..."
5574
+ : composerPlaceholder
5575
+ }
5576
+ onSubmit={
5577
+ isRunning || composerContextItems.length > 0
5578
+ ? (text, references, attachments, options) =>
5579
+ void addToQueue(
5580
+ text,
5581
+ undefined,
5582
+ references.length > 0
5583
+ ? references
5584
+ : undefined,
5585
+ attachments,
5586
+ undefined,
5587
+ resolveAssistantChatSubmitIntent({
5588
+ isRunning,
5589
+ requestedIntent: options?.intent,
5590
+ }),
5591
+ undefined,
5592
+ true,
5593
+ )
5594
+ : undefined
5595
+ }
5596
+ onSlashCommand={onSlashCommand}
5597
+ execMode={execMode}
5598
+ onExecModeChange={onExecModeChange}
5599
+ planModeDisabled={planModeDisabled}
5600
+ planModeDisabledReason={planModeDisabledReason}
5601
+ selectedModel={selectedModel ?? defaultModel}
5602
+ selectedEffort={selectedEffort}
5603
+ availableModels={availableModels}
5604
+ modelListLoading={modelListLoading}
5605
+ onModelChange={onModelChange}
5606
+ onEffortChange={onEffortChange}
5607
+ imageModelMenu={imageModelMenu}
5608
+ onConnectProvider={onConnectProvider}
5609
+ onConnectLocalRuntime={onConnectLocalRuntime}
5610
+ toolbarSlot={composerToolbarSlot}
5611
+ contextItems={composerContextItems}
5612
+ onRemoveContextItem={removeComposerContextItem}
5613
+ plusMenuMode={plusMenuMode}
5614
+ layoutVariant={composerLayoutVariant}
5615
+ providerConnectStatusEnabled={
5616
+ providerStatusChecksEnabled
5617
+ }
5618
+ voiceEnabled
5619
+ draftScope={threadId || tabId}
5620
+ interceptBuildRequestsForBuilder
5621
+ onAttachmentError={setComposerError}
5622
+ extraActionButton={
5623
+ contextXRayEnabled ||
5624
+ composerExtraActionButton ? (
5625
+ <>
5626
+ {contextXRayEnabled && (
5627
+ <ContextMeter threadId={threadId} />
5628
+ )}
5629
+ {composerExtraActionButton}
5630
+ </>
5631
+ ) : undefined
5632
+ }
5633
+ stopButton={
5634
+ showRunningInUI ? (
5635
+ <Tooltip>
5636
+ <TooltipTrigger asChild>
5637
+ <button
5638
+ type="button"
5639
+ onClick={() => stopActiveRun()}
5640
+ aria-label="Stop response"
5641
+ data-agent-composer-slot="stop-button"
5642
+ className="shrink-0 flex h-7 w-7 cursor-pointer items-center justify-center rounded-full bg-primary text-primary-foreground shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
5643
+ >
5644
+ <IconPlayerStopFilled className="h-3 w-3" />
5645
+ </button>
5646
+ </TooltipTrigger>
5647
+ <TooltipContent>
5648
+ Stop response
5649
+ </TooltipContent>
5650
+ </Tooltip>
5651
+ ) : undefined
5652
+ }
5653
+ />
5654
+ </>
5655
+ )}
5656
+ </AgentComposerFrame>
5657
+ {showMissingKeySetup ? (
5658
+ <PopoverContent
5659
+ side={
5660
+ missingApiKeySetupLayout === "sidebar"
5661
+ ? "top"
5662
+ : "bottom"
5663
+ }
5664
+ align="center"
5665
+ sideOffset={8}
5666
+ collisionPadding={12}
5667
+ data-agent-native-composer-popover="true"
5668
+ className="z-[260] box-border w-[min(calc(100vw-2rem),var(--radix-popover-content-available-width,26rem),26rem)] rounded-lg border-border p-3 shadow-lg"
5669
+ >
5670
+ <BuilderSetupContent
5671
+ onConnected={handleBuilderConnected}
5672
+ layout={missingApiKeySetupLayout}
5609
5673
  />
5610
- </>
5611
- )}
5612
- </AgentComposerFrame>
5613
- {showMissingKeySetup ? (
5614
- <PopoverContent
5615
- side={
5616
- missingApiKeySetupLayout === "sidebar"
5617
- ? "top"
5618
- : "bottom"
5619
- }
5620
- align="center"
5621
- sideOffset={8}
5622
- collisionPadding={12}
5623
- data-agent-native-composer-popover="true"
5624
- className="z-[260] box-border w-[min(calc(100vw-2rem),var(--radix-popover-content-available-width,26rem),26rem)] rounded-lg border-border p-3 shadow-lg"
5625
- >
5626
- <BuilderSetupContent
5627
- onConnected={handleBuilderConnected}
5628
- layout={missingApiKeySetupLayout}
5629
- />
5630
- </PopoverContent>
5631
- ) : null}
5632
- </Popover>
5674
+ </PopoverContent>
5675
+ ) : null}
5676
+ </Popover>
5677
+ </div>
5633
5678
  </div>
5634
- </div>
5635
- </TextStreamingContext.Provider>
5636
- </ChatRunningContext.Provider>
5679
+ </TextStreamingContext.Provider>
5680
+ </ChatRunningContext.Provider>
5681
+ </ChatRunDurationContext.Provider>
5637
5682
  </ApprovalContext.Provider>
5638
5683
  </MessageActionsContext.Provider>
5639
5684
  </CheckpointContext.Provider>