@agent-native/core 0.115.4 → 0.116.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 (408) hide show
  1. package/agent-native.eject.json +1 -0
  2. package/corpus/README.md +3 -3
  3. package/corpus/core/CHANGELOG.md +28 -0
  4. package/corpus/core/agent-native.eject.json +1 -0
  5. package/corpus/core/docs/AGENTS.md +1 -1
  6. package/corpus/core/docs/content/agent-mentions.mdx +2 -2
  7. package/corpus/core/docs/content/{workspace.mdx → agent-resources.mdx} +1 -7
  8. package/corpus/core/docs/content/agent-teams.mdx +4 -4
  9. package/corpus/core/docs/content/dispatch.mdx +10 -10
  10. package/corpus/core/docs/content/drop-in-agent.mdx +4 -4
  11. package/corpus/core/docs/content/external-agents.mdx +1 -1
  12. package/corpus/core/docs/content/frames.mdx +1 -1
  13. package/corpus/core/docs/content/integrations.mdx +13 -2
  14. package/corpus/core/docs/content/key-concepts.mdx +2 -2
  15. package/corpus/core/docs/content/mcp-clients.mdx +7 -1
  16. package/corpus/core/docs/content/multi-app-workspace.mdx +3 -3
  17. package/corpus/core/docs/content/real-time-collaboration.mdx +33 -15
  18. package/corpus/core/docs/content/recurring-jobs.mdx +7 -7
  19. package/corpus/core/docs/content/skills-guide.mdx +4 -4
  20. package/corpus/core/docs/content/template-brain.mdx +1 -1
  21. package/corpus/core/docs/content/toolkit-collaboration.mdx +1 -1
  22. package/corpus/core/docs/content/using-your-agent.mdx +1 -1
  23. package/corpus/core/docs/content/what-is-agent-native.mdx +4 -4
  24. package/corpus/core/docs/content/workspace-management.mdx +4 -4
  25. package/corpus/core/package.json +1 -1
  26. package/corpus/core/src/agent/production-agent.ts +13 -3
  27. package/corpus/core/src/cli/doctor.ts +6 -1
  28. package/corpus/core/src/client/AgentPanel.tsx +79 -41
  29. package/corpus/core/src/client/AssistantChat.tsx +71 -25
  30. package/corpus/core/src/client/FeedbackButton.tsx +33 -7
  31. package/corpus/core/src/client/MultiTabAssistantChat.tsx +6 -8
  32. package/corpus/core/src/client/agent-chat-adapter.ts +11 -2
  33. package/corpus/core/src/client/agent-page/AgentTabFrame.tsx +22 -3
  34. package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +34 -19
  35. package/corpus/core/src/client/chat/message-components.tsx +43 -16
  36. package/corpus/core/src/client/chat/tool-call-display.tsx +30 -18
  37. package/corpus/core/src/client/chat/tool-render-registry.tsx +2 -0
  38. package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +19 -2
  39. package/corpus/core/src/client/resources/ResourceTree.tsx +7 -10
  40. package/corpus/core/src/client/resources/ResourcesPanel.tsx +33 -70
  41. package/corpus/core/src/client/resources/mcp-connection-resume.ts +107 -0
  42. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +65 -12
  43. package/corpus/core/src/client/resources/mcp-integration-logos.ts +4 -0
  44. package/corpus/core/src/client/sse-event-processor.ts +50 -14
  45. package/corpus/core/src/client/use-db-sync.ts +16 -6
  46. package/corpus/core/src/connections/catalog.ts +7 -1
  47. package/corpus/core/src/eject/remote-mcp-presets.ts +37 -5
  48. package/corpus/core/src/guards/explicit-collab-access.ts +229 -0
  49. package/corpus/core/src/guards/index.ts +1 -0
  50. package/corpus/core/src/localization/default-messages.ts +54 -5
  51. package/corpus/core/src/mcp/connect-route.ts +34 -51
  52. package/corpus/core/src/provider-api/index.ts +1 -1
  53. package/corpus/core/src/server/collab-plugin.ts +137 -18
  54. package/corpus/core/src/server/index.ts +2 -0
  55. package/corpus/core/src/styles/agent-native.css +40 -0
  56. package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  57. package/corpus/core/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
  58. package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  59. package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  60. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  61. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
  62. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  63. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
  64. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  65. package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
  66. package/corpus/templates/analytics/AGENTS.md +7 -2
  67. package/corpus/templates/analytics/actions/export-dashboard-panel-to-google-sheet.ts +144 -0
  68. package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -88
  69. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +34 -37
  70. package/corpus/templates/analytics/app/global.css +0 -4
  71. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -7
  72. package/corpus/templates/analytics/app/i18n-data.ts +107 -0
  73. package/corpus/templates/analytics/app/lib/data-source-status.ts +9 -0
  74. package/corpus/templates/analytics/app/lib/sql-query.ts +1 -2
  75. package/corpus/templates/analytics/app/pages/Ask.tsx +2 -7
  76. package/corpus/templates/analytics/app/pages/DataSources.tsx +48 -0
  77. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +59 -0
  78. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -0
  79. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +3 -1
  80. package/corpus/templates/analytics/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
  81. package/corpus/templates/analytics/changelog/2026-07-22-daily-dashboard-email-query-batches.md +6 -0
  82. package/corpus/templates/analytics/changelog/2026-07-22-export-table-panels-directly-to-google-sheets.md +6 -0
  83. package/corpus/templates/analytics/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  84. package/corpus/templates/analytics/changelog/2026-07-22-recent-chats-can-expand-in-the-sidebar.md +6 -0
  85. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +8 -8
  86. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +31 -0
  87. package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +3 -5
  88. package/corpus/templates/analytics/server/lib/dashboard-report.ts +12 -0
  89. package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +3 -5
  90. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +150 -21
  91. package/corpus/templates/analytics/server/lib/google-sheets-export.ts +188 -0
  92. package/corpus/templates/analytics/server/lib/provider-api.ts +7 -2
  93. package/corpus/templates/analytics/server/plugins/collab.ts +6 -3
  94. package/corpus/templates/analytics/shared/sql-query-limits.ts +1 -0
  95. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  96. package/corpus/templates/assets/.agents/skills/real-time-collab/SKILL.md +35 -13
  97. package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
  98. package/corpus/templates/assets/app/components/layout/Layout.tsx +1 -1
  99. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +54 -62
  100. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +2 -6
  101. package/corpus/templates/assets/app/routes/_index.tsx +8 -5
  102. package/corpus/templates/assets/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  103. package/corpus/templates/assets/changelog/2026-07-22-recent-chats-expand-from-a-compact-list.md +6 -0
  104. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  105. package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
  106. package/corpus/templates/brain/actions/rotate-source-ingest-token.ts +77 -0
  107. package/corpus/templates/brain/app/components/layout/Layout.tsx +5 -1
  108. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +38 -51
  109. package/corpus/templates/brain/app/hooks/use-navigation-state.ts +2 -9
  110. package/corpus/templates/brain/app/i18n-data.ts +120 -0
  111. package/corpus/templates/brain/app/routes/sources.tsx +156 -5
  112. package/corpus/templates/brain/changelog/2026-07-22-chat-runs-always-end-with-an-answer.md +6 -0
  113. package/corpus/templates/brain/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
  114. package/corpus/templates/brain/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  115. package/corpus/templates/brain/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  116. package/corpus/templates/brain/changelog/2026-07-22-long-chat-titles-stay-inside-the-sidebar.md +6 -0
  117. package/corpus/templates/brain/changelog/2026-07-22-new-clips-and-webhook-sources-now-show-their-secure-connecti.md +6 -0
  118. package/corpus/templates/brain/jobs/emit-netlify-brain-queue-cron.ts +125 -0
  119. package/corpus/templates/brain/netlify.toml +5 -1
  120. package/corpus/templates/brain/scripts/configure-prod-clips-source.ts +50 -0
  121. package/corpus/templates/brain/server/lib/capture-sanitization.ts +64 -6
  122. package/corpus/templates/brain/server/plugins/agent-chat.ts +4 -0
  123. package/corpus/templates/brain/server/plugins/brain-jobs.ts +1 -0
  124. package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +55 -0
  125. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  126. package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
  127. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  128. package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  129. package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -0
  130. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +43 -67
  131. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +2 -7
  132. package/corpus/templates/chat/app/routes/_index.tsx +8 -5
  133. package/corpus/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  134. package/corpus/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  135. package/corpus/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
  136. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  137. package/corpus/templates/clips/AGENTS.md +9 -1
  138. package/corpus/templates/clips/actions/export-to-brain.ts +82 -6
  139. package/corpus/templates/clips/actions/request-transcript.ts +25 -14
  140. package/corpus/templates/clips/changelog/2026-07-22-clips-transcripts-now-retry-brain-export.md +5 -0
  141. package/corpus/templates/clips/changelog/2026-07-22-german-umlauts-and-other-non-ascii-characters-now-paste-corr.md +6 -0
  142. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +26 -3
  143. package/corpus/templates/clips/jobs/emit-netlify-brain-export-cron.ts +118 -0
  144. package/corpus/templates/clips/netlify.toml +4 -1
  145. package/corpus/templates/clips/scripts/configure-prod-brain-export.ts +92 -0
  146. package/corpus/templates/clips/server/jobs/brain-export.ts +182 -0
  147. package/corpus/templates/clips/server/lib/brain-export-state.ts +42 -0
  148. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +5 -1
  149. package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
  150. package/corpus/templates/clips/server/register-secrets.ts +42 -0
  151. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +10 -1
  152. package/corpus/templates/clips/server/routes/api/clips/brain-export/run.post.ts +45 -0
  153. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  154. package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
  155. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -1
  156. package/corpus/templates/content/server/plugins/collab.ts +1 -1
  157. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  158. package/corpus/templates/crm/actions/_crm-data-program-actions.ts +15 -0
  159. package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +2 -0
  160. package/corpus/templates/crm/actions/run.ts +2 -6
  161. package/corpus/templates/crm/actions/update-crm-record.ts +4 -2
  162. package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +6 -0
  163. package/corpus/templates/crm/changelog/2026-07-22-crm-field-validation-now-explains-which-fields-cannot-be-edi.md +6 -0
  164. package/corpus/templates/crm/changelog/2026-07-22-fixed-hubspot-contact-syncs-missing-records-updated-after-th.md +6 -0
  165. package/corpus/templates/crm/changelog/2026-07-22-fixed-pipeline-dashboard-panels-so-their-opportunity-data-lo.md +6 -0
  166. package/corpus/templates/crm/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  167. package/corpus/templates/crm/server/crm/hubspot-adapter.ts +4 -1
  168. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  169. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  170. package/corpus/templates/design/server/plugins/collab.ts +11 -8
  171. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  172. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  173. package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
  174. package/corpus/templates/forms/app/components/layout/Layout.tsx +1 -0
  175. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +1 -1
  176. package/corpus/templates/forms/app/hooks/use-navigation-state.ts +2 -9
  177. package/corpus/templates/forms/app/root.tsx +1 -6
  178. package/corpus/templates/forms/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  179. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  180. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  181. package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
  182. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
  183. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  184. package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
  185. package/corpus/templates/plan/app/components/layout/Layout.tsx +5 -1
  186. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +57 -72
  187. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +2 -9
  188. package/corpus/templates/plan/app/lib/create-plan-routing.ts +2 -2
  189. package/corpus/templates/plan/app/pages/PlanChatPage.tsx +0 -1
  190. package/corpus/templates/plan/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  191. package/corpus/templates/plan/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  192. package/corpus/templates/plan/changelog/2026-07-22-recent-chats-and-sidebar-controls-are-more-compact.md +6 -0
  193. package/corpus/templates/plan/server/plugins/collab.ts +5 -2
  194. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  195. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +1 -1
  196. package/corpus/templates/slides/server/plugins/collab.ts +11 -8
  197. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  198. package/corpus/templates/tasks/.agents/skills/real-time-sync/SKILL.md +1 -1
  199. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +5 -22
  200. package/corpus/templates/tasks/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  201. package/corpus/toolkit/CHANGELOG.md +7 -0
  202. package/corpus/toolkit/README.md +12 -3
  203. package/corpus/toolkit/package.json +1 -1
  204. package/corpus/toolkit/src/chat-history/ChatHistoryRail.tsx +89 -0
  205. package/corpus/toolkit/src/chat-history/index.ts +5 -0
  206. package/corpus/toolkit/src/chat-history.css +59 -0
  207. package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +106 -36
  208. package/corpus/toolkit/src/composer/VoiceButton.tsx +49 -0
  209. package/corpus/toolkit/src/composer/realtime-voice-audio-level.ts +2 -1
  210. package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +5 -3
  211. package/corpus/toolkit/src/styles.css +35 -0
  212. package/dist/agent/production-agent.d.ts.map +1 -1
  213. package/dist/agent/production-agent.js +13 -3
  214. package/dist/agent/production-agent.js.map +1 -1
  215. package/dist/cli/doctor.d.ts +1 -1
  216. package/dist/cli/doctor.d.ts.map +1 -1
  217. package/dist/cli/doctor.js +5 -2
  218. package/dist/cli/doctor.js.map +1 -1
  219. package/dist/client/AgentPanel.d.ts +1 -0
  220. package/dist/client/AgentPanel.d.ts.map +1 -1
  221. package/dist/client/AgentPanel.js +38 -18
  222. package/dist/client/AgentPanel.js.map +1 -1
  223. package/dist/client/AssistantChat.d.ts.map +1 -1
  224. package/dist/client/AssistantChat.js +55 -20
  225. package/dist/client/AssistantChat.js.map +1 -1
  226. package/dist/client/FeedbackButton.d.ts +4 -2
  227. package/dist/client/FeedbackButton.d.ts.map +1 -1
  228. package/dist/client/FeedbackButton.js +18 -2
  229. package/dist/client/FeedbackButton.js.map +1 -1
  230. package/dist/client/MultiTabAssistantChat.d.ts +1 -1
  231. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  232. package/dist/client/MultiTabAssistantChat.js +2 -3
  233. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  234. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  235. package/dist/client/agent-chat-adapter.js +11 -3
  236. package/dist/client/agent-chat-adapter.js.map +1 -1
  237. package/dist/client/agent-page/AgentTabFrame.d.ts +3 -1
  238. package/dist/client/agent-page/AgentTabFrame.d.ts.map +1 -1
  239. package/dist/client/agent-page/AgentTabFrame.js +3 -2
  240. package/dist/client/agent-page/AgentTabFrame.js.map +1 -1
  241. package/dist/client/agent-page/AgentTabsPage.d.ts +2 -0
  242. package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
  243. package/dist/client/agent-page/AgentTabsPage.js +26 -15
  244. package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
  245. package/dist/client/chat/message-components.d.ts +6 -1
  246. package/dist/client/chat/message-components.d.ts.map +1 -1
  247. package/dist/client/chat/message-components.js +17 -11
  248. package/dist/client/chat/message-components.js.map +1 -1
  249. package/dist/client/chat/tool-call-display.d.ts +11 -1
  250. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  251. package/dist/client/chat/tool-call-display.js +16 -17
  252. package/dist/client/chat/tool-call-display.js.map +1 -1
  253. package/dist/client/chat/tool-render-registry.d.ts +2 -0
  254. package/dist/client/chat/tool-render-registry.d.ts.map +1 -1
  255. package/dist/client/chat/tool-render-registry.js.map +1 -1
  256. package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
  257. package/dist/client/resources/McpConnectionSuggestion.js +15 -1
  258. package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
  259. package/dist/client/resources/ResourceTree.d.ts.map +1 -1
  260. package/dist/client/resources/ResourceTree.js +3 -3
  261. package/dist/client/resources/ResourceTree.js.map +1 -1
  262. package/dist/client/resources/ResourcesPanel.d.ts +1 -0
  263. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  264. package/dist/client/resources/ResourcesPanel.js +34 -20
  265. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  266. package/dist/client/resources/mcp-connection-resume.d.ts +11 -0
  267. package/dist/client/resources/mcp-connection-resume.d.ts.map +1 -0
  268. package/dist/client/resources/mcp-connection-resume.js +95 -0
  269. package/dist/client/resources/mcp-connection-resume.js.map +1 -0
  270. package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
  271. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  272. package/dist/client/resources/mcp-integration-catalog.js +63 -8
  273. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  274. package/dist/client/resources/mcp-integration-logos.d.ts.map +1 -1
  275. package/dist/client/resources/mcp-integration-logos.js +4 -0
  276. package/dist/client/resources/mcp-integration-logos.js.map +1 -1
  277. package/dist/client/sse-event-processor.d.ts +5 -0
  278. package/dist/client/sse-event-processor.d.ts.map +1 -1
  279. package/dist/client/sse-event-processor.js +39 -13
  280. package/dist/client/sse-event-processor.js.map +1 -1
  281. package/dist/client/use-db-sync.d.ts +3 -2
  282. package/dist/client/use-db-sync.d.ts.map +1 -1
  283. package/dist/client/use-db-sync.js +17 -6
  284. package/dist/client/use-db-sync.js.map +1 -1
  285. package/dist/collab/routes.d.ts +1 -1
  286. package/dist/connections/catalog.d.ts +1 -1
  287. package/dist/connections/catalog.d.ts.map +1 -1
  288. package/dist/connections/catalog.js +7 -1
  289. package/dist/connections/catalog.js.map +1 -1
  290. package/dist/eject/remote-mcp-presets.d.ts.map +1 -1
  291. package/dist/eject/remote-mcp-presets.js +33 -3
  292. package/dist/eject/remote-mcp-presets.js.map +1 -1
  293. package/dist/guards/explicit-collab-access.d.ts +8 -0
  294. package/dist/guards/explicit-collab-access.d.ts.map +1 -0
  295. package/dist/guards/explicit-collab-access.js +214 -0
  296. package/dist/guards/explicit-collab-access.js.map +1 -0
  297. package/dist/guards/index.d.ts +1 -0
  298. package/dist/guards/index.d.ts.map +1 -1
  299. package/dist/guards/index.js +1 -0
  300. package/dist/guards/index.js.map +1 -1
  301. package/dist/localization/default-messages.d.ts +43 -0
  302. package/dist/localization/default-messages.d.ts.map +1 -1
  303. package/dist/localization/default-messages.js +48 -5
  304. package/dist/localization/default-messages.js.map +1 -1
  305. package/dist/mcp/connect-route.d.ts.map +1 -1
  306. package/dist/mcp/connect-route.js +34 -48
  307. package/dist/mcp/connect-route.js.map +1 -1
  308. package/dist/notifications/routes.d.ts +3 -3
  309. package/dist/observability/routes.d.ts +1 -1
  310. package/dist/progress/routes.d.ts +1 -1
  311. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  312. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  313. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  314. package/dist/provider-api/index.js +1 -1
  315. package/dist/provider-api/index.js.map +1 -1
  316. package/dist/server/collab-plugin.d.ts +34 -3
  317. package/dist/server/collab-plugin.d.ts.map +1 -1
  318. package/dist/server/collab-plugin.js +65 -12
  319. package/dist/server/collab-plugin.js.map +1 -1
  320. package/dist/server/index.d.ts +1 -1
  321. package/dist/server/index.d.ts.map +1 -1
  322. package/dist/server/index.js.map +1 -1
  323. package/dist/styles/agent-native.css +40 -0
  324. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  325. package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  326. package/dist/templates/chat/app/components/layout/Layout.tsx +1 -0
  327. package/dist/templates/chat/app/components/layout/Sidebar.tsx +43 -67
  328. package/dist/templates/chat/app/hooks/use-navigation-state.ts +2 -7
  329. package/dist/templates/chat/app/routes/_index.tsx +8 -5
  330. package/dist/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  331. package/dist/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  332. package/dist/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
  333. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  334. package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
  335. package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  336. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  337. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  338. package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
  339. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  340. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
  341. package/docs/AGENTS.md +1 -1
  342. package/docs/content/agent-mentions.mdx +2 -2
  343. package/docs/content/{workspace.mdx → agent-resources.mdx} +1 -7
  344. package/docs/content/agent-teams.mdx +4 -4
  345. package/docs/content/dispatch.mdx +10 -10
  346. package/docs/content/drop-in-agent.mdx +4 -4
  347. package/docs/content/external-agents.mdx +1 -1
  348. package/docs/content/frames.mdx +1 -1
  349. package/docs/content/integrations.mdx +13 -2
  350. package/docs/content/key-concepts.mdx +2 -2
  351. package/docs/content/mcp-clients.mdx +7 -1
  352. package/docs/content/multi-app-workspace.mdx +3 -3
  353. package/docs/content/real-time-collaboration.mdx +33 -15
  354. package/docs/content/recurring-jobs.mdx +7 -7
  355. package/docs/content/skills-guide.mdx +4 -4
  356. package/docs/content/template-brain.mdx +1 -1
  357. package/docs/content/toolkit-collaboration.mdx +1 -1
  358. package/docs/content/using-your-agent.mdx +1 -1
  359. package/docs/content/what-is-agent-native.mdx +4 -4
  360. package/docs/content/workspace-management.mdx +4 -4
  361. package/package.json +3 -3
  362. package/src/agent/production-agent.ts +13 -3
  363. package/src/cli/doctor.ts +6 -1
  364. package/src/client/AgentPanel.tsx +79 -41
  365. package/src/client/AssistantChat.tsx +71 -25
  366. package/src/client/FeedbackButton.tsx +33 -7
  367. package/src/client/MultiTabAssistantChat.tsx +6 -8
  368. package/src/client/agent-chat-adapter.ts +11 -2
  369. package/src/client/agent-page/AgentTabFrame.tsx +22 -3
  370. package/src/client/agent-page/AgentTabsPage.tsx +34 -19
  371. package/src/client/chat/message-components.tsx +43 -16
  372. package/src/client/chat/tool-call-display.tsx +30 -18
  373. package/src/client/chat/tool-render-registry.tsx +2 -0
  374. package/src/client/resources/McpConnectionSuggestion.tsx +19 -2
  375. package/src/client/resources/ResourceTree.tsx +7 -10
  376. package/src/client/resources/ResourcesPanel.tsx +33 -70
  377. package/src/client/resources/mcp-connection-resume.ts +107 -0
  378. package/src/client/resources/mcp-integration-catalog.ts +65 -12
  379. package/src/client/resources/mcp-integration-logos.ts +4 -0
  380. package/src/client/sse-event-processor.ts +50 -14
  381. package/src/client/use-db-sync.ts +16 -6
  382. package/src/connections/catalog.ts +7 -1
  383. package/src/eject/remote-mcp-presets.ts +37 -5
  384. package/src/guards/explicit-collab-access.ts +229 -0
  385. package/src/guards/index.ts +1 -0
  386. package/src/localization/default-messages.ts +54 -5
  387. package/src/mcp/connect-route.ts +34 -51
  388. package/src/provider-api/index.ts +1 -1
  389. package/src/server/collab-plugin.ts +137 -18
  390. package/src/server/index.ts +2 -0
  391. package/src/styles/agent-native.css +40 -0
  392. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  393. package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  394. package/src/templates/chat/app/components/layout/Layout.tsx +1 -0
  395. package/src/templates/chat/app/components/layout/Sidebar.tsx +43 -67
  396. package/src/templates/chat/app/hooks/use-navigation-state.ts +2 -7
  397. package/src/templates/chat/app/routes/_index.tsx +8 -5
  398. package/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  399. package/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  400. package/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
  401. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  402. package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
  403. package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  404. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  405. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  406. package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
  407. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  408. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
@@ -0,0 +1,50 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import { writeFile } from "node:fs/promises";
3
+
4
+ import { getDbExec } from "@agent-native/core/db";
5
+
6
+ const tokenFile = process.env.BRAIN_CLIPS_TOKEN_FILE;
7
+ if (!tokenFile) throw new Error("BRAIN_CLIPS_TOKEN_FILE is required");
8
+
9
+ const db = getDbExec();
10
+ const { rows } = await db.execute({
11
+ sql: "SELECT id, source_key, config_json FROM brain_sources WHERE provider = ? AND title = ?",
12
+ args: ["clips", "Clips exports"],
13
+ });
14
+ if (rows.length !== 1) {
15
+ throw new Error(`Expected one Clips exports source, found ${rows.length}`);
16
+ }
17
+
18
+ const source = rows[0] as {
19
+ id: string;
20
+ source_key?: string | null;
21
+ config_json?: string | null;
22
+ };
23
+ const sourceKey = source.source_key?.trim() || "clips";
24
+ const token = `brain_${randomBytes(32).toString("base64url")}`;
25
+ const tokenHash = createHash("sha256").update(token).digest("hex");
26
+ const config = JSON.parse(source.config_json || "{}") as Record<
27
+ string,
28
+ unknown
29
+ >;
30
+ config.sourceKey = sourceKey;
31
+ config.ingestTokenHash = tokenHash;
32
+
33
+ await db.execute({
34
+ sql: "UPDATE brain_sources SET source_key = ?, ingest_token_hash = ?, config_json = ?, updated_at = ? WHERE id = ?",
35
+ args: [
36
+ sourceKey,
37
+ tokenHash,
38
+ JSON.stringify(config),
39
+ new Date().toISOString(),
40
+ source.id,
41
+ ],
42
+ });
43
+ await writeFile(tokenFile, token, {
44
+ encoding: "utf8",
45
+ flag: "wx",
46
+ mode: 0o600,
47
+ });
48
+ console.log(
49
+ JSON.stringify({ configured: true, sourceId: source.id, sourceKey }),
50
+ );
@@ -168,6 +168,10 @@ function preferredDeterministicSection(content: string): string {
168
168
  return content;
169
169
  }
170
170
 
171
+ function hasSummarySection(content: string): boolean {
172
+ return /(?:^|\n)\s*Summary\s*\n/i.test(content);
173
+ }
174
+
171
175
  function looksLikeRawTranscriptLine(line: string): boolean {
172
176
  return (
173
177
  /^\[[^\]\n]{1,80}\]\s*/.test(line) ||
@@ -208,6 +212,35 @@ function deterministicSanitizeContent(
208
212
  return retained.join("\n").slice(0, 80_000).trim();
209
213
  }
210
214
 
215
+ function deterministicMeetingOutageFallback(
216
+ input: CaptureSanitizationInput,
217
+ decision: BrainSensitivityDecision,
218
+ capturedAt: string,
219
+ ): string | null {
220
+ if (
221
+ decision.disposition !== "allowed" ||
222
+ input.kind !== "transcript" ||
223
+ !["granola", "clips"].includes(input.source.provider) ||
224
+ !shouldSanitizeCaptureBeforeStorage(input) ||
225
+ !hasSummarySection(decision.safeContent) ||
226
+ PERSONAL_SIGNAL.test(decision.safeContent) ||
227
+ RECRUITING_SIGNAL.test(decision.safeContent)
228
+ ) {
229
+ return null;
230
+ }
231
+
232
+ const content = deterministicSanitizeContent(
233
+ sanitizeSensitiveText(decision.safeContent),
234
+ { dropTranscriptLines: true },
235
+ );
236
+ if (content === DEFAULT_SANITIZATION_OUTPUT) return null;
237
+
238
+ return fallbackSensitivityDecision(content, capturedAt).disposition ===
239
+ "allowed"
240
+ ? content
241
+ : null;
242
+ }
243
+
211
244
  function safeTranscriptTitle(input: CaptureSanitizationInput): string {
212
245
  const date = input.capturedAt?.slice(0, 10);
213
246
  const providerLabel =
@@ -506,7 +539,9 @@ export async function sanitizeCaptureForStorage(
506
539
  deterministicQuarantineDecision(input.title, capturedAt) ??
507
540
  (titleDecision.disposition === "allowed" ? null : titleDecision) ??
508
541
  deterministicQuarantineDecision(input.content, capturedAt);
542
+ const sanitizationRequested = shouldSanitizeCaptureBeforeStorage(input);
509
543
  let fallbackReason: string | undefined;
544
+ let classifierOutageFallback = false;
510
545
  const classifierConfigured = Boolean(
511
546
  stringSetting(input.settings.privacyClassifierModel) &&
512
547
  stringSetting(input.settings.privacyClassifierEngine),
@@ -526,13 +561,35 @@ export async function sanitizeCaptureForStorage(
526
561
  }
527
562
  decision ??= fallbackSensitivityDecision(input.content, capturedAt);
528
563
  if (classifierFailed) {
529
- decision = {
530
- ...decision,
531
- disposition: "quarantined",
532
- confidenceBand: "uncertain",
533
- };
564
+ const deterministicMeetingContent = deterministicMeetingOutageFallback(
565
+ input,
566
+ decision,
567
+ capturedAt,
568
+ );
569
+ if (deterministicMeetingContent) {
570
+ classifierOutageFallback = true;
571
+ decision = {
572
+ ...decision,
573
+ safeContent: deterministicMeetingContent,
574
+ safeSegments: [
575
+ {
576
+ id: "deterministic-meeting-summary",
577
+ capturedAt,
578
+ text: deterministicMeetingContent,
579
+ reactionCount: 0,
580
+ },
581
+ ],
582
+ confidenceBand: "deterministic",
583
+ classifier: "deterministic",
584
+ };
585
+ } else {
586
+ decision = {
587
+ ...decision,
588
+ disposition: "quarantined",
589
+ confidenceBand: "uncertain",
590
+ };
591
+ }
534
592
  }
535
- const sanitizationRequested = shouldSanitizeCaptureBeforeStorage(input);
536
593
 
537
594
  const sanitizedContent =
538
595
  decision.disposition === "allowed"
@@ -575,6 +632,7 @@ export async function sanitizeCaptureForStorage(
575
632
  ? input.settings.privacyClassifierModel
576
633
  : undefined,
577
634
  fallbackReason,
635
+ classifierOutageFallback: classifierOutageFallback || undefined,
578
636
  disposition: decision.disposition,
579
637
  categories: decision.categories,
580
638
  confidenceBand: decision.confidenceBand,
@@ -10,6 +10,8 @@ import { and, desc, like, or } from "drizzle-orm";
10
10
  import actionsRegistry from "../../.generated/actions-registry.js";
11
11
  import { tryAnswerBrainA2AQuestion } from "../lib/a2a-fallback.js";
12
12
 
13
+ const BRAIN_BACKGROUND_RUN_SOFT_TIMEOUT_MS = 13 * 60_000;
14
+
13
15
  const INITIAL_TOOL_NAMES = [
14
16
  "get-brain-settings",
15
17
  "ask-brain",
@@ -39,6 +41,8 @@ export default createAgentChatPlugin({
39
41
  appId: "brain",
40
42
  actions: loadActionsFromStaticRegistry(actionsRegistry),
41
43
  initialToolNames: INITIAL_TOOL_NAMES,
44
+ durableBackgroundRuns: true,
45
+ runSoftTimeoutMs: BRAIN_BACKGROUND_RUN_SOFT_TIMEOUT_MS,
42
46
  resolveOrgId: async (event) => (await getOrgContext(event)).orgId,
43
47
  codeExecution: { production: "sandboxed" },
44
48
  systemPrompt: `You are the Brain institutional-knowledge agent.
@@ -2,6 +2,7 @@ import registerBrainDistillationQueueJob from "../jobs/distillation-queue.js";
2
2
  import registerBrainSourceSyncJob from "../jobs/sync-sources.js";
3
3
 
4
4
  export default () => {
5
+ if (process.env.NETLIFY === "true") return;
5
6
  registerBrainSourceSyncJob();
6
7
  registerBrainDistillationQueueJob();
7
8
  };
@@ -0,0 +1,55 @@
1
+ import { timingSafeEqual } from "node:crypto";
2
+
3
+ import { createError, defineEventHandler, getHeader } from "h3";
4
+
5
+ import { processBrainIngestQueueOnce } from "../../../../../jobs/process-ingest-queue.js";
6
+ import { syncDueBrainSourcesOnce } from "../../../../jobs/sync-sources.js";
7
+ import { expireSensitivityQuarantines } from "../../../../lib/brain.js";
8
+
9
+ declare global {
10
+ var __AGENT_NATIVE_BRAIN_SCHEDULED_RUNTIME__: boolean | undefined;
11
+ }
12
+
13
+ function productionLike() {
14
+ return (
15
+ process.env.NODE_ENV === "production" || process.env.NETLIFY === "true"
16
+ );
17
+ }
18
+
19
+ function scheduledFunctionRuntime() {
20
+ return globalThis.__AGENT_NATIVE_BRAIN_SCHEDULED_RUNTIME__ === true;
21
+ }
22
+
23
+ function headerMatchesSecret(header: string | undefined, secret: string) {
24
+ const expected = `Bearer ${secret}`;
25
+ const value = header?.trim() ?? "";
26
+ return (
27
+ value.length === expected.length &&
28
+ timingSafeEqual(Buffer.from(value), Buffer.from(expected))
29
+ );
30
+ }
31
+
32
+ export default defineEventHandler(async (event) => {
33
+ const secret = process.env.BRAIN_JOBS_SECRET?.trim(); // guard:allow-env-credential — deployment-level scheduler route secret
34
+ const scheduled = scheduledFunctionRuntime();
35
+ if (!secret && productionLike() && !scheduled) {
36
+ throw createError({
37
+ statusCode: 503,
38
+ statusMessage: "BRAIN_JOBS_SECRET is required",
39
+ });
40
+ }
41
+ if (
42
+ secret &&
43
+ !scheduled &&
44
+ !headerMatchesSecret(getHeader(event, "authorization"), secret)
45
+ ) {
46
+ throw createError({ statusCode: 401, statusMessage: "Unauthorized" });
47
+ }
48
+
49
+ const [sync, queue, expiredSensitivityQuarantines] = await Promise.all([
50
+ syncDueBrainSourcesOnce({ system: true, limit: 5 }),
51
+ processBrainIngestQueueOnce({ limit: 1, runDistillation: true }),
52
+ expireSensitivityQuarantines(),
53
+ ]);
54
+ return { ok: true, sync, queue, expiredSensitivityQuarantines };
55
+ });
@@ -85,7 +85,10 @@ in the moment of agent use.
85
85
  approval, generative UI, progress, and screen-state exposure.
86
86
  - **Chat history kit**: presentational chat lists and recent-chat rails belong
87
87
  in Toolkit; Core keeps thread persistence, agent execution, transport, and
88
- page-to-sidebar handoff. Apps inject routing, labels, and domain actions.
88
+ page-to-sidebar handoff. Use Toolkit's `ChatHistoryRail` for the standard
89
+ five-item sidebar preview and a footer row with New chat followed by an
90
+ ellipsis disclosure up to fifteen. Apps inject routing, labels, and domain
91
+ actions.
89
92
  - **Agent page kit**: the full-page `/agent` surface (`AgentTabsPage` from
90
93
  `@agent-native/core/client`) with Context, Files, Connections, Jobs, and
91
94
  Access tabs plus a Personal/Organization scope toggle. The canonical home
@@ -72,7 +72,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
72
72
  });
73
73
  ```
74
74
 
75
- `useDbSync` and every `subscribeSyncEvents` subscriber share one `EventSource` and one fallback poll loop per tab — this is how collaborative documents receive doc updates and cursor/awareness events.
75
+ `useDbSync` and every `subscribeSyncEvents` subscriber share one `EventSource` and one fallback poll loop per tab — this is how collaborative documents receive doc updates and cursor/awareness events. Hidden tabs keep that shared transport alive by default: SSE stays connected and active fallback polling relaxes to a 10-second floor (idle polling remains once per minute). Pass `pauseWhenHidden: true` only for a consumer that explicitly must stop all hidden-tab sync.
76
76
 
77
77
  ## Which sources to depend on
78
78
 
@@ -85,7 +85,10 @@ in the moment of agent use.
85
85
  approval, generative UI, progress, and screen-state exposure.
86
86
  - **Chat history kit**: presentational chat lists and recent-chat rails belong
87
87
  in Toolkit; Core keeps thread persistence, agent execution, transport, and
88
- page-to-sidebar handoff. Apps inject routing, labels, and domain actions.
88
+ page-to-sidebar handoff. Use Toolkit's `ChatHistoryRail` for the standard
89
+ five-item sidebar preview and a footer row with New chat followed by an
90
+ ellipsis disclosure up to fifteen. Apps inject routing, labels, and domain
91
+ actions.
89
92
  - **Agent page kit**: the full-page `/agent` surface (`AgentTabsPage` from
90
93
  `@agent-native/core/client`) with Context, Files, Connections, Jobs, and
91
94
  Access tabs plus a Personal/Organization scope toggle. The canonical home
@@ -72,7 +72,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
72
72
  });
73
73
  ```
74
74
 
75
- `useDbSync` and every `subscribeSyncEvents` subscriber share one `EventSource` and one fallback poll loop per tab — this is how collaborative documents receive doc updates and cursor/awareness events.
75
+ `useDbSync` and every `subscribeSyncEvents` subscriber share one `EventSource` and one fallback poll loop per tab — this is how collaborative documents receive doc updates and cursor/awareness events. Hidden tabs keep that shared transport alive by default: SSE stays connected and active fallback polling relaxes to a 10-second floor (idle polling remains once per minute). Pass `pauseWhenHidden: true` only for a consumer that explicitly must stop all hidden-tab sync.
76
76
 
77
77
  ## Which sources to depend on
78
78
 
@@ -60,6 +60,7 @@ export function Layout({ children }: LayoutProps) {
60
60
  useAgentChatHomeHandoffLinks({
61
61
  storageKey: "chat",
62
62
  isChatPath: (pathname) => pathname === "/" || pathname.startsWith("/chat/"),
63
+ requireActiveHandoff: false,
63
64
  });
64
65
 
65
66
  useEffect(() => {
@@ -9,7 +9,7 @@ import { useT } from "@agent-native/core/client/i18n";
9
9
  import { OrgSwitcher } from "@agent-native/core/client/org";
10
10
  import { FeedbackButton } from "@agent-native/core/client/ui";
11
11
  import {
12
- ChatHistoryList,
12
+ ChatHistoryRail,
13
13
  type ChatHistoryItem,
14
14
  } from "@agent-native/toolkit/chat-history";
15
15
  import {
@@ -17,7 +17,6 @@ import {
17
17
  IconLayoutSidebarLeftCollapse,
18
18
  IconLayoutSidebarLeftExpand,
19
19
  IconMessageCircle,
20
- IconPlus,
21
20
  IconSettings,
22
21
  } from "@tabler/icons-react";
23
22
  import { useEffect, useMemo } from "react";
@@ -104,6 +103,12 @@ function persistedActiveThreadId() {
104
103
  }
105
104
  }
106
105
 
106
+ function persistActiveThreadId(threadId: string) {
107
+ try {
108
+ localStorage.setItem(CHAT_ACTIVE_THREAD_KEY, threadId);
109
+ } catch {}
110
+ }
111
+
107
112
  function threadIdFromPath(pathname: string) {
108
113
  const match = pathname.match(/^\/chat\/([^/]+)/);
109
114
  if (!match) return null;
@@ -142,7 +147,7 @@ function ChatThreadsSection() {
142
147
  threads
143
148
  .filter((thread) => thread.messageCount > 0 && !thread.archivedAt)
144
149
  .sort(compareThreads)
145
- .slice(0, 12),
150
+ .slice(0, 15),
146
151
  [threads],
147
152
  );
148
153
  const displayedActiveThreadId =
@@ -184,6 +189,7 @@ function ChatThreadsSection() {
184
189
 
185
190
  function openThread(threadId: string, options?: { isNew?: boolean }) {
186
191
  switchThread(threadId);
192
+ persistActiveThreadId(threadId);
187
193
  navigateWithAgentChatViewTransition(
188
194
  navigate,
189
195
  options?.isNew ? "/" : chatThreadPath(threadId),
@@ -223,50 +229,35 @@ function ChatThreadsSection() {
223
229
 
224
230
  return (
225
231
  <div className="mt-2 border-s border-sidebar-border/70 ps-3">
226
- <div className="mb-1 flex h-7 items-center gap-2 pe-1">
227
- <div className="min-w-0 flex-1 text-xs font-medium text-sidebar-foreground/70">
228
- {t("chat.chats")}
229
- </div>
230
- <Tooltip>
231
- <TooltipTrigger asChild>
232
- <button
233
- type="button"
234
- onClick={handleNewChat}
235
- className="flex size-6 shrink-0 items-center justify-center rounded-md text-sidebar-foreground/65 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
236
- aria-label={t("chat.newChat")}
237
- >
238
- <IconPlus className="size-3.5" />
239
- </button>
240
- </TooltipTrigger>
241
- <TooltipContent>{t("chat.newChat")}</TooltipContent>
242
- </Tooltip>
243
- </div>
244
- {visibleThreads.length > 0 && (
245
- <ChatHistoryList
246
- items={chatItems}
247
- activeId={displayedActiveThreadId}
248
- onSelect={(threadId) => openThread(threadId)}
249
- renameMaxLength={160}
250
- onTogglePin={(threadId) => {
251
- const thread = visibleThreads.find((item) => item.id === threadId);
252
- if (thread) void pinThread(threadId, !thread.pinnedAt);
253
- }}
254
- onRename={handleRenameThread}
255
- onDelete={(threadId) => void handleArchiveThread(threadId)}
256
- labels={{
257
- options: (item) =>
258
- t("chat.optionsFor", { title: item.titleText ?? "" }),
259
- renameInput: (item) =>
260
- t("chat.renameThread", { title: item.titleText ?? "" }),
261
- rename: t("chat.renameChat"),
262
- pin: t("chat.pinChat"),
263
- unpin: t("chat.unpinChat"),
264
- delete: t("chat.archiveChat"),
265
- }}
266
- variant="rail"
267
- className="min-w-0"
268
- />
269
- )}
232
+ <ChatHistoryRail
233
+ items={chatItems}
234
+ activeId={displayedActiveThreadId}
235
+ onSelect={(threadId) => openThread(threadId)}
236
+ onNewChat={() => void handleNewChat()}
237
+ railLabels={{
238
+ newChat: t("chat.newChat"),
239
+ showMore: t("chat.chats"),
240
+ showLess: t("chat.chats"),
241
+ }}
242
+ renameMaxLength={160}
243
+ onTogglePin={(threadId) => {
244
+ const thread = visibleThreads.find((item) => item.id === threadId);
245
+ if (thread) void pinThread(threadId, !thread.pinnedAt);
246
+ }}
247
+ onRename={handleRenameThread}
248
+ onDelete={(threadId) => void handleArchiveThread(threadId)}
249
+ labels={{
250
+ options: (item) =>
251
+ t("chat.optionsFor", { title: item.titleText ?? "" }),
252
+ renameInput: (item) =>
253
+ t("chat.renameThread", { title: item.titleText ?? "" }),
254
+ rename: t("chat.renameChat"),
255
+ pin: t("chat.pinChat"),
256
+ unpin: t("chat.unpinChat"),
257
+ delete: t("chat.archiveChat"),
258
+ }}
259
+ className="min-w-0"
260
+ />
270
261
  </div>
271
262
  );
272
263
  }
@@ -445,28 +436,13 @@ export function Sidebar({
445
436
  />
446
437
  </div>
447
438
 
448
- <div
449
- className={cn(
450
- collapsed ? "flex justify-center px-1 py-1" : "px-3 py-2",
451
- )}
452
- >
453
- <FeedbackButton
454
- variant={collapsed ? "icon" : "sidebar"}
455
- side="right"
456
- align={collapsed ? "center" : "end"}
457
- />
458
- </div>
459
-
460
- {collapseButton ? (
461
- <div
462
- className={cn(
463
- collapsed
464
- ? "flex justify-center px-1 py-1"
465
- : "flex justify-end px-3 py-2",
466
- )}
467
- >
439
+ {!collapsed ? (
440
+ <div className="flex items-center justify-end gap-1 px-3 py-2">
441
+ <FeedbackButton className="min-w-0 flex-1" side="right" />
468
442
  {collapseButton}
469
443
  </div>
444
+ ) : collapseButton ? (
445
+ <div className="flex justify-center px-1 py-1">{collapseButton}</div>
470
446
  ) : null}
471
447
  </div>
472
448
  </aside>
@@ -1,7 +1,4 @@
1
- import {
2
- isAgentChatHomeHandoffActive,
3
- markAgentChatHomeHandoff,
4
- } from "@agent-native/core/client/agent-chat";
1
+ import { markAgentChatHomeHandoff } from "@agent-native/core/client/agent-chat";
5
2
  import { appBasePath, appPath } from "@agent-native/core/client/api-path";
6
3
  import { useAgentRouteState } from "@agent-native/core/client/navigation";
7
4
  import { useLocation } from "react-router";
@@ -34,9 +31,7 @@ export function useNavigationState() {
34
31
  isChatPath(location.pathname) &&
35
32
  !isChatPath(pathnameFromPath(path))
36
33
  ) {
37
- if (isAgentChatHomeHandoffActive("chat")) {
38
- markAgentChatHomeHandoff("chat");
39
- }
34
+ markAgentChatHomeHandoff("chat");
40
35
  }
41
36
  },
42
37
  });
@@ -36,6 +36,13 @@ export default function ChatRoute() {
36
36
  const { threadId } = useParams();
37
37
  const navigate = useNavigate();
38
38
  const t = useT();
39
+ const threadUrlSync = threadId
40
+ ? {
41
+ routeThreadId: threadId,
42
+ getPath: chatThreadPath,
43
+ navigate,
44
+ }
45
+ : undefined;
39
46
 
40
47
  useEffect(() => {
41
48
  function handleChatRunning(event: Event) {
@@ -56,11 +63,7 @@ export default function ChatRoute() {
56
63
  className="h-full"
57
64
  defaultMode="chat"
58
65
  storageKey="chat"
59
- threadUrlSync={{
60
- routeThreadId: threadId ?? null,
61
- getPath: chatThreadPath,
62
- navigate,
63
- }}
66
+ threadUrlSync={threadUrlSync}
64
67
  browserTabId={TAB_ID}
65
68
  showHeader={false}
66
69
  showTabBar={false}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-22
4
+ ---
5
+
6
+ The sidebar footer now keeps Feedback and the collapse control on one compact row.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-22
4
+ ---
5
+
6
+ Full-page chat keeps the active conversation when moving to and from the sidebar.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-22
4
+ ---
5
+
6
+ Recent chats now expand from a compact five-item list with New chat anchored at the bottom.
@@ -85,7 +85,10 @@ in the moment of agent use.
85
85
  approval, generative UI, progress, and screen-state exposure.
86
86
  - **Chat history kit**: presentational chat lists and recent-chat rails belong
87
87
  in Toolkit; Core keeps thread persistence, agent execution, transport, and
88
- page-to-sidebar handoff. Apps inject routing, labels, and domain actions.
88
+ page-to-sidebar handoff. Use Toolkit's `ChatHistoryRail` for the standard
89
+ five-item sidebar preview and a footer row with New chat followed by an
90
+ ellipsis disclosure up to fifteen. Apps inject routing, labels, and domain
91
+ actions.
89
92
  - **Agent page kit**: the full-page `/agent` surface (`AgentTabsPage` from
90
93
  `@agent-native/core/client`) with Context, Files, Connections, Jobs, and
91
94
  Access tabs plus a Personal/Organization scope toggle. The canonical home
@@ -69,7 +69,15 @@ ladder.
69
69
  current-user recordings with ready transcripts in the active organization
70
70
  and reports exported, quarantined, skipped, and failed counts. Both
71
71
  `BRAIN_INGEST_URL` and `BRAIN_INGEST_TOKEN` must be available as scoped Clips
72
- secrets.
72
+ secrets. Transcript completion persists a pending export before handing it to
73
+ the durable post-finalize worker; delivery receipts include the Brain capture
74
+ or sensitivity receipt id, while transient failures are swept and retried.
75
+ The sweep also discovers ready transcripts from the last seven days that
76
+ predate export-state tracking, in bounded batches, so recent recordings are
77
+ backfilled after the connection is configured.
78
+ Netlify builds emit a protected per-minute scheduled sweep because in-process
79
+ intervals are not durable there. Other serverless hosts must invoke
80
+ `runBrainExportSweepOnce` from their own scheduler.
73
81
  - The transcript embedded by `view-screen` is a bounded preview. If
74
82
  `previewTruncated` is true, it may end mid-sentence and does not show where
75
83
  transcription ended. Call `get-recording-player-data` before judging