@agent-native/core 0.95.0 → 0.96.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 (316) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +35 -0
  3. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +13 -0
  4. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +18 -0
  5. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +16 -0
  6. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +17 -0
  7. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +16 -0
  8. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +17 -0
  9. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +15 -0
  10. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +16 -0
  11. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +11 -0
  12. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +12 -0
  13. package/corpus/core/docs/content/template-design.mdx +16 -0
  14. package/corpus/core/package.json +4 -2
  15. package/corpus/core/src/a2a/client.ts +11 -1
  16. package/corpus/core/src/agent/production-agent.ts +107 -27
  17. package/corpus/core/src/agent/thread-data-builder.ts +48 -22
  18. package/corpus/core/src/chat-threads/store.ts +20 -1
  19. package/corpus/core/src/cli/code-agent-executor.ts +1 -0
  20. package/corpus/core/src/cli/code-agent-runs.ts +14 -0
  21. package/corpus/core/src/client/AgentPanel.tsx +32 -25
  22. package/corpus/core/src/client/AssistantChat.tsx +286 -45
  23. package/corpus/core/src/client/MultiTabAssistantChat.tsx +141 -90
  24. package/corpus/core/src/client/chat/ChatHistoryList.tsx +404 -0
  25. package/corpus/core/src/client/chat/index.ts +6 -0
  26. package/corpus/core/src/client/chat/tool-call-display.tsx +38 -4
  27. package/corpus/core/src/client/chat/use-reconnect-reader-owner.ts +28 -0
  28. package/corpus/core/src/client/code-agent-chat-adapter.ts +72 -4
  29. package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +52 -11
  30. package/corpus/core/src/client/composer/TiptapComposer.tsx +157 -20
  31. package/corpus/core/src/client/composer/VoiceButton.tsx +28 -0
  32. package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +5 -0
  33. package/corpus/core/src/client/conversation/code-agent-transcript.ts +4 -5
  34. package/corpus/core/src/client/guided-questions.tsx +11 -2
  35. package/corpus/core/src/client/index.ts +11 -0
  36. package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +6 -7
  37. package/corpus/core/src/client/sse-event-processor.ts +90 -21
  38. package/corpus/core/src/client/use-chat-threads.ts +10 -1
  39. package/corpus/core/src/client/voice-provider-status.ts +44 -0
  40. package/corpus/core/src/code-agents/transcript-normalizer.ts +76 -0
  41. package/corpus/core/src/connections/catalog.ts +2 -2
  42. package/corpus/core/src/deploy/build.ts +12 -8
  43. package/corpus/core/src/integrations/a2a-continuation-processor.ts +35 -5
  44. package/corpus/core/src/integrations/adapters/slack.ts +74 -21
  45. package/corpus/core/src/integrations/catalog.ts +2 -2
  46. package/corpus/core/src/integrations/webhook-handler.ts +14 -0
  47. package/corpus/core/src/localization/default-messages.ts +6 -0
  48. package/corpus/core/src/observability/hosted-model-experiment.ts +118 -0
  49. package/corpus/core/src/observability/routes.ts +17 -0
  50. package/corpus/core/src/observability/store.ts +4 -1
  51. package/corpus/core/src/observability/traces.ts +41 -2
  52. package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +19 -1
  53. package/corpus/core/src/scripts/call-agent.ts +53 -3
  54. package/corpus/core/src/scripts/chat/search-chats.ts +11 -8
  55. package/corpus/core/src/secrets/register-framework-secrets.ts +1 -1
  56. package/corpus/core/src/server/agent-chat-plugin.ts +41 -6
  57. package/corpus/core/src/server/auth.ts +1 -1
  58. package/corpus/core/src/server/core-routes-plugin.ts +15 -0
  59. package/corpus/core/src/server/credential-provider.ts +7 -3
  60. package/corpus/core/src/server/realtime-voice.ts +71 -24
  61. package/corpus/core/src/server/voice-providers-status.ts +4 -3
  62. package/corpus/core/src/shared/cache-control.ts +4 -4
  63. package/corpus/core/src/styles/agent-native.css +1 -0
  64. package/corpus/core/src/styles/chat-history-list.css +313 -0
  65. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
  66. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
  67. package/corpus/core/src/vite/client.ts +1 -0
  68. package/corpus/templates/analytics/AGENTS.md +7 -0
  69. package/corpus/templates/analytics/actions/bigquery.ts +26 -2
  70. package/corpus/templates/analytics/actions/data-source-status.ts +18 -0
  71. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +5 -4
  72. package/corpus/templates/analytics/app/global.css +10 -0
  73. package/corpus/templates/analytics/app/lib/data-sources.ts +5 -4
  74. package/corpus/templates/analytics/app/pages/Ask.tsx +25 -2
  75. package/corpus/templates/analytics/changelog/2026-07-10-analytics-answers-simple-time-bounded-metrics-without-unnece.md +6 -0
  76. package/corpus/templates/analytics/changelog/2026-07-10-analytics-chat-reliably-uses-connected-data-sources-across-s.md +6 -0
  77. package/corpus/templates/analytics/changelog/2026-07-10-chat-threads-now-stay-clear-of-top-actions-and-fade-smoothly.md +6 -0
  78. package/corpus/templates/analytics/changelog/2026-07-10-context-chips-can-now-be-selected-and-removed-one-at-a-time-.md +6 -0
  79. package/corpus/templates/analytics/changelog/2026-07-10-slack-token-setup-marked-legacy.md +6 -0
  80. package/corpus/templates/analytics/changelog/2026-07-10-the-ask-composer-no-longer-carries-dashboard-or-panel-contex.md +6 -0
  81. package/corpus/templates/analytics/changelog/2026-07-10-the-ask-section-stays-highlighted-while-its-chat-history-is-.md +6 -0
  82. package/corpus/templates/analytics/server/lib/bigquery.ts +90 -14
  83. package/corpus/templates/analytics/server/lib/credential-keys.ts +6 -2
  84. package/corpus/templates/analytics/server/plugins/agent-chat.ts +82 -7
  85. package/corpus/templates/brain/changelog/2026-07-10-slack-backfill-token-marked-legacy.md +6 -0
  86. package/corpus/templates/brain/server/register-secrets.ts +2 -2
  87. package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -1
  88. package/corpus/templates/clips/app/components/library/page-header.tsx +19 -3
  89. package/corpus/templates/clips/app/routes/_app.library._index.tsx +16 -12
  90. package/corpus/templates/clips/changelog/2026-07-10-new-recording-appears-once-when-the-library-sidebar-is-open.md +6 -0
  91. package/corpus/templates/clips/changelog/2026-07-10-slack-token-fallback-guidance.md +6 -0
  92. package/corpus/templates/clips/server/register-secrets.ts +1 -1
  93. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +0 -66
  94. package/corpus/templates/content/app/routes/_app.local-files.tsx +7 -47
  95. package/corpus/templates/content/changelog/2026-07-10-local-folders-now-wait-for-an-explicit-pull-before-content-r.md +6 -0
  96. package/corpus/templates/content/package.json +1 -1
  97. package/corpus/templates/design/actions/generate-design.ts +128 -31
  98. package/corpus/templates/design/actions/present-design-variants.ts +37 -9
  99. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +9 -3
  100. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +32 -10
  101. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +2 -2
  102. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +9 -1
  103. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +7 -5
  104. package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -0
  105. package/corpus/templates/design/app/global.css +10 -0
  106. package/corpus/templates/design/app/hooks/use-question-flow.ts +9 -2
  107. package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
  108. package/corpus/templates/design/app/i18n-data.ts +21 -11
  109. package/corpus/templates/design/changelog/2026-07-10-editor-panels-are-easier-to-distinguish-and-design-intake-qu.md +6 -0
  110. package/corpus/templates/design/changelog/2026-07-10-interact-mode-now-stays-on-the-full-canvas-matches-edit-visu.md +6 -0
  111. package/corpus/templates/design/changelog/2026-07-10-new-web-designs-open-at-desktop-size-and-adapt-across-mobile.md +6 -0
  112. package/corpus/templates/design/changelog/2026-07-10-tweaks-now-link-to-full-documentation.md +6 -0
  113. package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
  114. package/corpus/templates/mail/app/i18n/ar-SA.ts +3 -3
  115. package/corpus/templates/mail/app/i18n/de-DE.ts +3 -3
  116. package/corpus/templates/mail/app/i18n/en-US.ts +4 -3
  117. package/corpus/templates/mail/app/i18n/es-ES.ts +3 -3
  118. package/corpus/templates/mail/app/i18n/fr-FR.ts +3 -3
  119. package/corpus/templates/mail/app/i18n/hi-IN.ts +3 -3
  120. package/corpus/templates/mail/app/i18n/ja-JP.ts +3 -3
  121. package/corpus/templates/mail/app/i18n/ko-KR.ts +3 -3
  122. package/corpus/templates/mail/app/i18n/pt-BR.ts +3 -3
  123. package/corpus/templates/mail/app/i18n/zh-CN.ts +3 -3
  124. package/corpus/templates/mail/app/i18n/zh-TW.ts +3 -3
  125. package/corpus/templates/mail/changelog/2026-07-10-slack-intake-marked-legacy.md +6 -0
  126. package/corpus/templates/mail/server/lib/env-config.ts +5 -4
  127. package/corpus/templates/plan/package.json +1 -1
  128. package/dist/a2a/client.d.ts +7 -0
  129. package/dist/a2a/client.d.ts.map +1 -1
  130. package/dist/a2a/client.js +2 -1
  131. package/dist/a2a/client.js.map +1 -1
  132. package/dist/agent/production-agent.d.ts +6 -0
  133. package/dist/agent/production-agent.d.ts.map +1 -1
  134. package/dist/agent/production-agent.js +83 -26
  135. package/dist/agent/production-agent.js.map +1 -1
  136. package/dist/agent/thread-data-builder.d.ts +1 -0
  137. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  138. package/dist/agent/thread-data-builder.js +42 -23
  139. package/dist/agent/thread-data-builder.js.map +1 -1
  140. package/dist/chat-threads/store.d.ts +10 -0
  141. package/dist/chat-threads/store.d.ts.map +1 -1
  142. package/dist/chat-threads/store.js +6 -0
  143. package/dist/chat-threads/store.js.map +1 -1
  144. package/dist/cli/code-agent-executor.d.ts.map +1 -1
  145. package/dist/cli/code-agent-executor.js +1 -0
  146. package/dist/cli/code-agent-executor.js.map +1 -1
  147. package/dist/cli/code-agent-runs.d.ts +12 -0
  148. package/dist/cli/code-agent-runs.d.ts.map +1 -1
  149. package/dist/cli/code-agent-runs.js +1 -0
  150. package/dist/cli/code-agent-runs.js.map +1 -1
  151. package/dist/client/AgentPanel.d.ts.map +1 -1
  152. package/dist/client/AgentPanel.js +3 -3
  153. package/dist/client/AgentPanel.js.map +1 -1
  154. package/dist/client/AssistantChat.d.ts +14 -1
  155. package/dist/client/AssistantChat.d.ts.map +1 -1
  156. package/dist/client/AssistantChat.js +207 -32
  157. package/dist/client/AssistantChat.js.map +1 -1
  158. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  159. package/dist/client/MultiTabAssistantChat.js +83 -10
  160. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  161. package/dist/client/chat/ChatHistoryList.d.ts +88 -0
  162. package/dist/client/chat/ChatHistoryList.d.ts.map +1 -0
  163. package/dist/client/chat/ChatHistoryList.js +83 -0
  164. package/dist/client/chat/ChatHistoryList.js.map +1 -0
  165. package/dist/client/chat/index.d.ts +1 -0
  166. package/dist/client/chat/index.d.ts.map +1 -1
  167. package/dist/client/chat/index.js +1 -0
  168. package/dist/client/chat/index.js.map +1 -1
  169. package/dist/client/chat/tool-call-display.d.ts +13 -1
  170. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  171. package/dist/client/chat/tool-call-display.js +11 -3
  172. package/dist/client/chat/tool-call-display.js.map +1 -1
  173. package/dist/client/chat/use-reconnect-reader-owner.d.ts +11 -0
  174. package/dist/client/chat/use-reconnect-reader-owner.d.ts.map +1 -0
  175. package/dist/client/chat/use-reconnect-reader-owner.js +21 -0
  176. package/dist/client/chat/use-reconnect-reader-owner.js.map +1 -0
  177. package/dist/client/code-agent-chat-adapter.d.ts +17 -1
  178. package/dist/client/code-agent-chat-adapter.d.ts.map +1 -1
  179. package/dist/client/code-agent-chat-adapter.js +47 -3
  180. package/dist/client/code-agent-chat-adapter.js.map +1 -1
  181. package/dist/client/composer/RealtimeVoiceMode.d.ts +11 -1
  182. package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -1
  183. package/dist/client/composer/RealtimeVoiceMode.js +5 -3
  184. package/dist/client/composer/RealtimeVoiceMode.js.map +1 -1
  185. package/dist/client/composer/TiptapComposer.d.ts +25 -2
  186. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  187. package/dist/client/composer/TiptapComposer.js +96 -5
  188. package/dist/client/composer/TiptapComposer.js.map +1 -1
  189. package/dist/client/composer/VoiceButton.d.ts.map +1 -1
  190. package/dist/client/composer/VoiceButton.js +21 -1
  191. package/dist/client/composer/VoiceButton.js.map +1 -1
  192. package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -1
  193. package/dist/client/composer/useRealtimeVoiceMode.js +5 -0
  194. package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -1
  195. package/dist/client/conversation/code-agent-transcript.d.ts +2 -0
  196. package/dist/client/conversation/code-agent-transcript.d.ts.map +1 -1
  197. package/dist/client/conversation/code-agent-transcript.js +3 -5
  198. package/dist/client/conversation/code-agent-transcript.js.map +1 -1
  199. package/dist/client/guided-questions.d.ts.map +1 -1
  200. package/dist/client/guided-questions.js +7 -2
  201. package/dist/client/guided-questions.js.map +1 -1
  202. package/dist/client/index.d.ts +3 -1
  203. package/dist/client/index.d.ts.map +1 -1
  204. package/dist/client/index.js +3 -1
  205. package/dist/client/index.js.map +1 -1
  206. package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
  207. package/dist/client/integrations/IntegrationsPanel.js +5 -7
  208. package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
  209. package/dist/client/sse-event-processor.d.ts.map +1 -1
  210. package/dist/client/sse-event-processor.js +67 -20
  211. package/dist/client/sse-event-processor.js.map +1 -1
  212. package/dist/client/use-chat-threads.d.ts.map +1 -1
  213. package/dist/client/use-chat-threads.js +9 -1
  214. package/dist/client/use-chat-threads.js.map +1 -1
  215. package/dist/client/voice-provider-status.d.ts +10 -0
  216. package/dist/client/voice-provider-status.d.ts.map +1 -0
  217. package/dist/client/voice-provider-status.js +32 -0
  218. package/dist/client/voice-provider-status.js.map +1 -0
  219. package/dist/code-agents/transcript-normalizer.d.ts +29 -0
  220. package/dist/code-agents/transcript-normalizer.d.ts.map +1 -1
  221. package/dist/code-agents/transcript-normalizer.js +55 -0
  222. package/dist/code-agents/transcript-normalizer.js.map +1 -1
  223. package/dist/collab/struct-routes.d.ts +1 -1
  224. package/dist/connections/catalog.d.ts +2 -2
  225. package/dist/connections/catalog.js +2 -2
  226. package/dist/connections/catalog.js.map +1 -1
  227. package/dist/deploy/build.d.ts.map +1 -1
  228. package/dist/deploy/build.js +12 -8
  229. package/dist/deploy/build.js.map +1 -1
  230. package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
  231. package/dist/integrations/a2a-continuation-processor.js +25 -5
  232. package/dist/integrations/a2a-continuation-processor.js.map +1 -1
  233. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  234. package/dist/integrations/adapters/slack.js +55 -21
  235. package/dist/integrations/adapters/slack.js.map +1 -1
  236. package/dist/integrations/catalog.js +2 -2
  237. package/dist/integrations/catalog.js.map +1 -1
  238. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  239. package/dist/integrations/webhook-handler.js +11 -0
  240. package/dist/integrations/webhook-handler.js.map +1 -1
  241. package/dist/localization/default-messages.d.ts +5 -0
  242. package/dist/localization/default-messages.d.ts.map +1 -1
  243. package/dist/localization/default-messages.js +5 -0
  244. package/dist/localization/default-messages.js.map +1 -1
  245. package/dist/observability/hosted-model-experiment.d.ts +39 -0
  246. package/dist/observability/hosted-model-experiment.d.ts.map +1 -0
  247. package/dist/observability/hosted-model-experiment.js +90 -0
  248. package/dist/observability/hosted-model-experiment.js.map +1 -0
  249. package/dist/observability/routes.d.ts.map +1 -1
  250. package/dist/observability/routes.js +16 -0
  251. package/dist/observability/routes.js.map +1 -1
  252. package/dist/observability/store.d.ts.map +1 -1
  253. package/dist/observability/store.js +4 -1
  254. package/dist/observability/store.js.map +1 -1
  255. package/dist/observability/traces.d.ts +6 -0
  256. package/dist/observability/traces.d.ts.map +1 -1
  257. package/dist/observability/traces.js +28 -2
  258. package/dist/observability/traces.js.map +1 -1
  259. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  260. package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
  261. package/dist/scripts/agent-engines/list-agent-engines.js +19 -1
  262. package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
  263. package/dist/scripts/call-agent.d.ts.map +1 -1
  264. package/dist/scripts/call-agent.js +43 -3
  265. package/dist/scripts/call-agent.js.map +1 -1
  266. package/dist/scripts/chat/search-chats.d.ts +1 -1
  267. package/dist/scripts/chat/search-chats.d.ts.map +1 -1
  268. package/dist/scripts/chat/search-chats.js +11 -8
  269. package/dist/scripts/chat/search-chats.js.map +1 -1
  270. package/dist/secrets/register-framework-secrets.js +1 -1
  271. package/dist/secrets/register-framework-secrets.js.map +1 -1
  272. package/dist/server/agent-chat-plugin.d.ts +11 -0
  273. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  274. package/dist/server/agent-chat-plugin.js +27 -6
  275. package/dist/server/agent-chat-plugin.js.map +1 -1
  276. package/dist/server/auth.js +1 -1
  277. package/dist/server/auth.js.map +1 -1
  278. package/dist/server/core-routes-plugin.d.ts +3 -0
  279. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  280. package/dist/server/core-routes-plugin.js +13 -0
  281. package/dist/server/core-routes-plugin.js.map +1 -1
  282. package/dist/server/credential-provider.d.ts +5 -3
  283. package/dist/server/credential-provider.d.ts.map +1 -1
  284. package/dist/server/credential-provider.js +7 -3
  285. package/dist/server/credential-provider.js.map +1 -1
  286. package/dist/server/realtime-voice.d.ts.map +1 -1
  287. package/dist/server/realtime-voice.js +55 -21
  288. package/dist/server/realtime-voice.js.map +1 -1
  289. package/dist/server/voice-providers-status.d.ts.map +1 -1
  290. package/dist/server/voice-providers-status.js +2 -3
  291. package/dist/server/voice-providers-status.js.map +1 -1
  292. package/dist/shared/cache-control.d.ts +6 -6
  293. package/dist/shared/cache-control.d.ts.map +1 -1
  294. package/dist/shared/cache-control.js +3 -3
  295. package/dist/shared/cache-control.js.map +1 -1
  296. package/dist/styles/agent-native.css +1 -0
  297. package/dist/styles/chat-history-list.css +313 -0
  298. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
  299. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
  300. package/dist/vite/client.d.ts.map +1 -1
  301. package/dist/vite/client.js +1 -0
  302. package/dist/vite/client.js.map +1 -1
  303. package/docs/content/locales/ar-SA/template-design.mdx +13 -0
  304. package/docs/content/locales/de-DE/template-design.mdx +18 -0
  305. package/docs/content/locales/es-ES/template-design.mdx +16 -0
  306. package/docs/content/locales/fr-FR/template-design.mdx +17 -0
  307. package/docs/content/locales/hi-IN/template-design.mdx +16 -0
  308. package/docs/content/locales/ja-JP/template-design.mdx +17 -0
  309. package/docs/content/locales/ko-KR/template-design.mdx +15 -0
  310. package/docs/content/locales/pt-BR/template-design.mdx +16 -0
  311. package/docs/content/locales/zh-CN/template-design.mdx +11 -0
  312. package/docs/content/locales/zh-TW/template-design.mdx +12 -0
  313. package/docs/content/template-design.mdx +16 -0
  314. package/package.json +4 -2
  315. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
  316. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
@@ -149,6 +149,16 @@
149
149
  background-color: hsl(var(--background)) !important;
150
150
  }
151
151
 
152
+ .analytics-chat-panel .agent-thread-content {
153
+ padding-top: 4.5rem;
154
+ }
155
+
156
+ .analytics-chat-panel
157
+ [data-agent-page-chat-scrolled]
158
+ [data-agent-page-chat-fade] {
159
+ opacity: 1;
160
+ }
161
+
152
162
  @media (max-width: 767px) {
153
163
  .analytics-chat-panel [data-agent-page-new-chat] {
154
164
  display: none;
@@ -748,14 +748,15 @@ export const dataSources: DataSource[] = [
748
748
  {
749
749
  id: "slack",
750
750
  name: "Slack",
751
- description: "Channel messages and workspace search",
751
+ description:
752
+ "Channel history and workspace search. Prefer a Slack workspace integration from Settings > Connections; a local bot token remains available as a legacy fallback.",
752
753
  category: "communication",
753
754
  icon: IconMessage,
754
755
  envKeys: ["SLACK_BOT_TOKEN"],
755
756
  docsUrl: "https://api.slack.com/methods",
756
757
  walkthroughSteps: [
757
758
  {
758
- title: "Create a Slack App",
759
+ title: "Create a Slack App for local fallback access",
759
760
  description:
760
761
  "Go to api.slack.com/apps, create a new app, and add OAuth scopes: channels:read, channels:history, search:read.",
761
762
  url: "https://api.slack.com/apps",
@@ -767,10 +768,10 @@ export const dataSources: DataSource[] = [
767
768
  'Under "OAuth & Permissions", install the app and copy the Bot User OAuth Token.',
768
769
  },
769
770
  {
770
- title: "Enter your Bot Token",
771
+ title: "Enter your local fallback Bot Token",
771
772
  description: 'Paste the Bot User OAuth Token (starts with "xoxb-").',
772
773
  inputKey: "SLACK_BOT_TOKEN",
773
- inputLabel: "Bot Token",
774
+ inputLabel: "Bot Token (legacy local fallback)",
774
775
  inputPlaceholder: "xoxb-...",
775
776
  inputType: "password",
776
777
  },
@@ -1,5 +1,9 @@
1
- import { AgentChatSurface, useT } from "@agent-native/core/client";
2
- import { useState } from "react";
1
+ import {
2
+ AgentChatSurface,
3
+ useAgentChatContext,
4
+ useT,
5
+ } from "@agent-native/core/client";
6
+ import { useEffect, useMemo, useState } from "react";
3
7
 
4
8
  import {
5
9
  ANALYTICS_CHAT_STORAGE_KEY,
@@ -7,9 +11,28 @@ import {
7
11
  } from "@/lib/chat-handoff";
8
12
  import { TAB_ID } from "@/lib/tab-id";
9
13
 
14
+ const DASHBOARD_CONTEXT_KEYS = new Set([
15
+ "analytics-selected-dashboard",
16
+ "analytics-selected-dashboard-panel",
17
+ ]);
18
+
10
19
  export default function AskPage() {
11
20
  const t = useT();
12
21
  const [restoreActiveThread] = useState(() => hasRecentAnalyticsChat());
22
+ const { items: chatContextItems, remove: removeChatContextItem } =
23
+ useAgentChatContext();
24
+ const staleDashboardContextKey = useMemo(
25
+ () =>
26
+ chatContextItems.find((item) => DASHBOARD_CONTEXT_KEYS.has(item.key))
27
+ ?.key ?? null,
28
+ [chatContextItems],
29
+ );
30
+
31
+ useEffect(() => {
32
+ if (staleDashboardContextKey) {
33
+ removeChatContextItem(staleDashboardContextKey);
34
+ }
35
+ }, [removeChatContextItem, staleDashboardContextKey]);
13
36
 
14
37
  return (
15
38
  <div className="analytics-ask-page flex h-full min-h-0 flex-col bg-background">
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-10
4
+ ---
5
+
6
+ Analytics answers simple time-bounded metrics without unnecessary follow-up queries.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-10
4
+ ---
5
+
6
+ Analytics chat reliably uses connected data sources across supported models
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-10
4
+ ---
5
+
6
+ Chat threads now stay clear of top actions and fade smoothly beneath them while scrolling.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-10
4
+ ---
5
+
6
+ Context chips can now be selected and removed one at a time with Backspace from the start of the Ask composer.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-10
4
+ ---
5
+
6
+ Slack data-source setup now favors workspace connections and identifies raw bot tokens as a legacy local fallback.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-10
4
+ ---
5
+
6
+ The Ask composer no longer carries dashboard or panel context after leaving a dashboard.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-10
4
+ ---
5
+
6
+ The Ask section stays highlighted while its chat history is expanded.
@@ -241,6 +241,15 @@ export interface QueryResult {
241
241
  cached?: boolean;
242
242
  }
243
243
 
244
+ export interface RunQueryOptions {
245
+ /**
246
+ * The current agent run's abort signal. This cancels in-flight BigQuery
247
+ * requests and, importantly, stops the one-second job polling wait without
248
+ * starting another request after the parent run has ended.
249
+ */
250
+ signal?: AbortSignal;
251
+ }
252
+
244
253
  interface BigQueryField {
245
254
  name: string;
246
255
  type: string;
@@ -265,6 +274,57 @@ interface BigQueryGetQueryResultsResponse {
265
274
  totalBytesProcessed?: string;
266
275
  }
267
276
 
277
+ function createAbortError(): Error {
278
+ if (typeof DOMException !== "undefined") {
279
+ return new DOMException("BigQuery query aborted", "AbortError");
280
+ }
281
+ const error = new Error("BigQuery query aborted");
282
+ error.name = "AbortError";
283
+ return error;
284
+ }
285
+
286
+ function throwIfAborted(signal?: AbortSignal): void {
287
+ if (signal?.aborted) throw createAbortError();
288
+ }
289
+
290
+ function waitForPollInterval(signal?: AbortSignal): Promise<void> {
291
+ throwIfAborted(signal);
292
+ return new Promise((resolve, reject) => {
293
+ const timeout = setTimeout(() => {
294
+ signal?.removeEventListener("abort", onAbort);
295
+ resolve();
296
+ }, 1000);
297
+ const onAbort = () => {
298
+ clearTimeout(timeout);
299
+ signal?.removeEventListener("abort", onAbort);
300
+ reject(createAbortError());
301
+ };
302
+ signal?.addEventListener("abort", onAbort, { once: true });
303
+ });
304
+ }
305
+
306
+ async function cancelQueryJob(
307
+ projectId: string,
308
+ jobId: string,
309
+ token: string,
310
+ ): Promise<void> {
311
+ try {
312
+ await fetch(
313
+ `https://bigquery.googleapis.com/bigquery/v2/projects/${projectId}/jobs/${jobId}/cancel`,
314
+ {
315
+ method: "POST",
316
+ headers: {
317
+ Authorization: `Bearer ${token}`,
318
+ "Content-Type": "application/json",
319
+ },
320
+ },
321
+ );
322
+ } catch {
323
+ // The caller is already aborting. Cancellation is best-effort and must not
324
+ // hide the original abort reason if BigQuery or the network is unavailable.
325
+ }
326
+ }
327
+
268
328
  /**
269
329
  * Convert BigQuery REST API row format to plain objects.
270
330
  * BigQuery returns rows as { f: [{ v: value }, ...] } arrays
@@ -361,7 +421,12 @@ export async function dryRunQuery(sql: string): Promise<string | null> {
361
421
  return `BigQuery validation failed (${res.status})`;
362
422
  }
363
423
 
364
- export async function runQuery(sql: string): Promise<QueryResult> {
424
+ export async function runQuery(
425
+ sql: string,
426
+ options: RunQueryOptions = {},
427
+ ): Promise<QueryResult> {
428
+ const { signal } = options;
429
+ throwIfAborted(signal);
365
430
  const { projectId, cacheScope, appEventsTable } = await getProjectInfo();
366
431
  const resolvedSql = await resolveTablePlaceholder(
367
432
  sql,
@@ -383,8 +448,10 @@ export async function runQuery(sql: string): Promise<QueryResult> {
383
448
  const token = await getAccessToken();
384
449
  const url = `https://bigquery.googleapis.com/bigquery/v2/projects/${projectId}/queries`;
385
450
 
451
+ throwIfAborted(signal);
386
452
  const res = await fetch(url, {
387
453
  method: "POST",
454
+ ...(signal ? { signal } : {}),
388
455
  headers: {
389
456
  Authorization: `Bearer ${token}`,
390
457
  "Content-Type": "application/json",
@@ -409,20 +476,29 @@ export async function runQuery(sql: string): Promise<QueryResult> {
409
476
  const resultsUrl = `https://bigquery.googleapis.com/bigquery/v2/projects/${projectId}/queries/${jobId}`;
410
477
 
411
478
  let attempts = 0;
412
- while (!data.jobComplete && attempts < 60) {
413
- await new Promise((resolve) => setTimeout(resolve, 1000));
414
- const pollRes = await fetch(resultsUrl, {
415
- headers: {
416
- Authorization: `Bearer ${token}`,
417
- "Content-Type": "application/json",
418
- },
419
- });
420
- if (!pollRes.ok) {
421
- const text = await pollRes.text();
422
- throw new Error(`BigQuery poll error ${pollRes.status}: ${text}`);
479
+ try {
480
+ while (!data.jobComplete && attempts < 60) {
481
+ await waitForPollInterval(signal);
482
+ throwIfAborted(signal);
483
+ const pollRes = await fetch(resultsUrl, {
484
+ ...(signal ? { signal } : {}),
485
+ headers: {
486
+ Authorization: `Bearer ${token}`,
487
+ "Content-Type": "application/json",
488
+ },
489
+ });
490
+ if (!pollRes.ok) {
491
+ const text = await pollRes.text();
492
+ throw new Error(`BigQuery poll error ${pollRes.status}: ${text}`);
493
+ }
494
+ data = (await pollRes.json()) as BigQueryGetQueryResultsResponse;
495
+ attempts++;
496
+ }
497
+ } catch (error) {
498
+ if (signal?.aborted) {
499
+ await cancelQueryJob(projectId, jobId, token);
423
500
  }
424
- data = (await pollRes.json()) as BigQueryGetQueryResultsResponse;
425
- attempts++;
501
+ throw error;
426
502
  }
427
503
 
428
504
  if (!data.jobComplete) {
@@ -107,10 +107,14 @@ export const credentialKeys: CredentialKeyConfig[] = [
107
107
  required: false,
108
108
  },
109
109
  // Slack
110
- { key: "SLACK_BOT_TOKEN", label: "Slack Bot Token", required: false },
110
+ {
111
+ key: "SLACK_BOT_TOKEN",
112
+ label: "Slack Bot Token (legacy local fallback)",
113
+ required: false,
114
+ },
111
115
  {
112
116
  key: "SLACK_BOT_TOKEN_2",
113
- label: "Slack Bot Token (secondary)",
117
+ label: "Slack Bot Token (legacy secondary fallback)",
114
118
  required: false,
115
119
  },
116
120
  // Notion
@@ -34,6 +34,18 @@ import {
34
34
  const DATA_DICT_PREFIX = "data-dict-";
35
35
  const ANALYTICS_BACKGROUND_RUN_SOFT_TIMEOUT_MS = 13 * 60_000;
36
36
 
37
+ export const SIMPLE_TIME_BOUNDED_METRIC_FAST_PATH_GUIDANCE =
38
+ "SIMPLE TIME-BOUNDED METRIC FAST PATH — When the data dictionary or a known canonical source identifies the metric, run one bounded aggregate. Once it returns a valid result, answer the explicit question immediately with the source, time window, row count, and only necessary caveats. Do not schema-discover, retry, enrich, cross-check, or add breakdowns after that successful result unless the query failed or the result conflicts with the known metric definition. This does not waive the real-data requirement: never answer from a guess, stale value, or unverified result. ";
39
+
40
+ export function analyticsSourceGuidanceOpening(): string {
41
+ return (
42
+ "<data-source-guidance>\n" +
43
+ "Apply real-data requirements only when presenting analytics results, source records, or derived metrics. Do not call data-source tools for workflow migration, recurring-job setup, UI/code fixes, settings help, conceptual planning, or other non-data tasks unless the user explicitly asks for data. " +
44
+ SIMPLE_TIME_BOUNDED_METRIC_FAST_PATH_GUIDANCE +
45
+ "SURFACE DIFFERENTIATION — You are the analytics assistant for definitions, deep-dive analysis, and action. For questions about what a metric, model, or table means, use the Data Dictionary and configured schema tools first. For trends, comparisons, anomalies, current data, or anything that requires querying live data, answer directly in chat with the relevant provider query, dashboard analysis, and inline charts when useful. "
46
+ );
47
+ }
48
+
37
49
  export {
38
50
  applyAnalyticsPlanModePolicy,
39
51
  INITIAL_TOOL_NAMES,
@@ -55,7 +67,61 @@ function latestUserText(
55
67
  return "";
56
68
  }
57
69
 
58
- function realDataFinalGuard(context: AgentLoopFinalResponseGuardContext) {
70
+ function configuredDataSourceLabels(
71
+ toolResults: AgentLoopFinalResponseGuardContext["toolResults"],
72
+ ): string[] {
73
+ const labels = new Set<string>();
74
+ for (const result of toolResults ?? []) {
75
+ const normalizedName = String(result.name ?? "")
76
+ .trim()
77
+ .toLowerCase()
78
+ .replace(/[\s_]+/g, "-");
79
+ if (normalizedName !== "data-source-status" || result.isError) continue;
80
+
81
+ let parsed: Record<string, unknown>;
82
+ try {
83
+ const value = JSON.parse(String(result.content ?? ""));
84
+ if (!value || typeof value !== "object" || Array.isArray(value)) continue;
85
+ parsed = value as Record<string, unknown>;
86
+ } catch {
87
+ continue;
88
+ }
89
+
90
+ const compactSources = Array.isArray(parsed.configuredDataSources)
91
+ ? parsed.configuredDataSources
92
+ : [];
93
+ for (const source of compactSources) {
94
+ if (!source || typeof source !== "object" || Array.isArray(source)) {
95
+ continue;
96
+ }
97
+ const record = source as Record<string, unknown>;
98
+ const label = record.label ?? record.provider;
99
+ if (typeof label === "string" && label.trim()) labels.add(label.trim());
100
+ }
101
+
102
+ // Backward compatibility for runs against deployments that predate the
103
+ // compact configuredDataSources summary.
104
+ const providers = Array.isArray(parsed.providers) ? parsed.providers : [];
105
+ for (const provider of providers) {
106
+ if (
107
+ !provider ||
108
+ typeof provider !== "object" ||
109
+ Array.isArray(provider)
110
+ ) {
111
+ continue;
112
+ }
113
+ const record = provider as Record<string, unknown>;
114
+ if (record.configured !== true) continue;
115
+ const label = record.label ?? record.provider;
116
+ if (typeof label === "string" && label.trim()) labels.add(label.trim());
117
+ }
118
+ }
119
+ return [...labels];
120
+ }
121
+
122
+ export function realDataFinalGuard(
123
+ context: AgentLoopFinalResponseGuardContext,
124
+ ) {
59
125
  if ((context as { executionMode?: string }).executionMode === "plan") {
60
126
  return null;
61
127
  }
@@ -125,11 +191,22 @@ function realDataFinalGuard(context: AgentLoopFinalResponseGuardContext) {
125
191
  };
126
192
  }
127
193
 
194
+ const configuredSources = configuredDataSourceLabels(context.toolResults);
195
+ const configuredSourceGuidance = configuredSources.length
196
+ ? ` \`data-source-status\` already confirmed these connected sources: ${configuredSources.join(", ")}. Do not claim that no sources are connected and do not ask the user to reconnect them. Immediately call the relevant query action for one of those sources.`
197
+ : "";
128
198
  return {
129
199
  retryMessage:
130
- "This looks like an analytics result request, but no real source query ran. If you are making data claims, run one relevant data-source action or connected provider MCP tool now and answer from that result. If the right response is a clarification, plan, or explicit unavailable/credentials-missing message with no metrics or source-record claims, finalize that directly instead.",
131
- fallbackMessage:
132
- "I can't provide a grounded analytics result yet because no real data-source query ran successfully. Tell me which source to use or connect the missing source, and I'll run it before giving numbers or source-record conclusions.",
200
+ "This looks like an analytics result request, but no real source query ran. If you are making data claims, run one relevant data-source action or connected provider MCP tool now and answer from that result." +
201
+ configuredSourceGuidance +
202
+ " If the right response is a clarification, plan, or explicit unavailable/credentials-missing message with no metrics or source-record claims, finalize that directly instead.",
203
+ fallbackMessage: configuredSources.length
204
+ ? `I found connected data sources (${configuredSources.join(", ")}), but the model still did not run a real source query. Please retry the request; you do not need to reconnect those sources.`
205
+ : "I can't provide a grounded analytics result yet because no real data-source query ran successfully. Tell me which source to use or connect the missing source, and I'll run it before giving numbers or source-record conclusions.",
206
+ // Some models use separate turns for status, schema discovery, and the
207
+ // actual query. One corrective turn was enough for Sonnet but caused Luna
208
+ // to hit the fallback before it reached the query.
209
+ maxRetries: 2,
133
210
  };
134
211
  }
135
212
 
@@ -159,9 +236,7 @@ export default createAgentChatPlugin({
159
236
  // The generic template can ship provider actions without every deployment
160
237
  // having credentials or workspace-specific schemas configured.
161
238
  const sourceGuidance =
162
- "<data-source-guidance>\n" +
163
- "Apply real-data requirements only when presenting analytics results, source records, or derived metrics. Do not call data-source tools for workflow migration, recurring-job setup, UI/code fixes, settings help, conceptual planning, or other non-data tasks unless the user explicitly asks for data. " +
164
- "SURFACE DIFFERENTIATION — You are the analytics assistant for definitions, deep-dive analysis, and action. For questions about what a metric, model, or table means, use the Data Dictionary and configured schema tools first. For trends, comparisons, anomalies, current data, or anything that requires querying live data, answer directly in chat with the relevant provider query, dashboard analysis, and inline charts when useful. " +
239
+ analyticsSourceGuidanceOpening() +
165
240
  "DASHBOARD CREATION RULE — You may create dashboards, analyses, SQL panels, or other resources only when the user explicitly asks you to (e.g. 'build me a dashboard for...', 'create a new analysis', 'add a chart for...'). Never create any resource proactively during research, trend analysis, or answering questions. If you think a dashboard would be useful, suggest it and wait for explicit confirmation before creating anything. Never add new items to the sidebar or modify existing dashboards without an explicit user directive. " +
166
241
  "DASHBOARD MUTATION RULE — For dashboard edits, default to `mutate-dashboard` with the typed `dashboard.*` script API so the main payload is a string and avoids native-array serialization traps. It can move panels by id, edit titles/SQL/config, insert, duplicate, remove, and patch dashboard fields in one atomic save. The script API is constrained: no variables/imports/loops/functions, only JSON-compatible arguments on documented dashboard methods. Do not count shifting `/panels/<index>` positions for ordinary dashboard edits unless the user specifically asks for low-level JSON-pointer operations. " +
167
242
  "DASHBOARD READ RULE — `get-sql-dashboard` is compact by default: use its `panels` summaries plus `layout.panelOrder`, `layout.firstPanelIds`, and `layout.groups[].rows[].rowNumber/panelIds` for orientation and verification. Pass `includeConfig: true` only when you truly need full panel SQL/config. " +
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-10
4
+ ---
5
+
6
+ Slack backfills now favor workspace connections while clearly marking raw bot tokens as a local fallback.
@@ -2,9 +2,9 @@ import { registerRequiredSecret } from "@agent-native/core/secrets";
2
2
 
3
3
  registerRequiredSecret({
4
4
  key: "SLACK_BOT_TOKEN",
5
- label: "Slack Bot Token",
5
+ label: "Slack Bot Token (local fallback)",
6
6
  description:
7
- "Optional Slack bot token for channel backfills. Brain only scans allow-listed channels and never enumerates DMs.",
7
+ "Optional local fallback for Brain channel backfills. Prefer a Slack workspace integration in Settings > Connections. Brain only scans allow-listed channels and never enumerates DMs.",
8
8
  docsUrl: "https://api.slack.com/authentication/token-types",
9
9
  scope: "workspace",
10
10
  kind: "api-key",
@@ -154,6 +154,9 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
154
154
  );
155
155
  const [headerSlot, setHeaderSlot] = useState<HTMLElement | null>(null);
156
156
  const showCollapsedSidebar = sidebarCollapsed && !isMobile;
157
+ const sidebarHasNewRecordingAction = isMobile
158
+ ? sidebarOpen
159
+ : !sidebarCollapsed;
157
160
 
158
161
  // Routes whose page renders its own h-12 toolbar. Layout still mounts Sidebar
159
162
  // + AgentSidebar, but skips its own header so there's no double-header.
@@ -603,7 +606,10 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
603
606
  </div>
604
607
  )}
605
608
  <main className="agent-native-app-main flex min-h-0 flex-1 flex-col overflow-y-auto">
606
- <PageHeaderSlotProvider slot={headerSlot}>
609
+ <PageHeaderSlotProvider
610
+ slot={headerSlot}
611
+ sidebarHasNewRecordingAction={sidebarHasNewRecordingAction}
612
+ >
607
613
  {children}
608
614
  </PageHeaderSlotProvider>
609
615
  </main>
@@ -7,24 +7,40 @@ import {
7
7
  } from "react";
8
8
  import { createPortal } from "react-dom";
9
9
 
10
- const PageHeaderSlotContext = createContext<HTMLElement | null>(null);
10
+ interface PageHeaderSlotContextValue {
11
+ slot: HTMLElement | null;
12
+ sidebarHasNewRecordingAction: boolean;
13
+ }
14
+
15
+ const PageHeaderSlotContext = createContext<PageHeaderSlotContextValue>({
16
+ slot: null,
17
+ sidebarHasNewRecordingAction: false,
18
+ });
11
19
 
12
20
  export function PageHeaderSlotProvider({
13
21
  slot,
22
+ sidebarHasNewRecordingAction,
14
23
  children,
15
24
  }: {
16
25
  slot: HTMLElement | null;
26
+ sidebarHasNewRecordingAction: boolean;
17
27
  children: ReactNode;
18
28
  }) {
19
29
  return (
20
- <PageHeaderSlotContext.Provider value={slot}>
30
+ <PageHeaderSlotContext.Provider
31
+ value={{ slot, sidebarHasNewRecordingAction }}
32
+ >
21
33
  {children}
22
34
  </PageHeaderSlotContext.Provider>
23
35
  );
24
36
  }
25
37
 
38
+ export function usePageHeaderLayout() {
39
+ return useContext(PageHeaderSlotContext);
40
+ }
41
+
26
42
  export function PageHeader({ children }: { children: ReactNode }) {
27
- const slot = useContext(PageHeaderSlotContext);
43
+ const { slot } = usePageHeaderLayout();
28
44
  const [ready, setReady] = useState(false);
29
45
  useEffect(() => setReady(true), []);
30
46
  if (!ready || !slot) return null;
@@ -4,6 +4,7 @@ import { IconPlayerRecord } from "@tabler/icons-react";
4
4
  import { NavLink } from "react-router";
5
5
 
6
6
  import { LibraryGrid } from "@/components/library/library-grid";
7
+ import { usePageHeaderLayout } from "@/components/library/page-header";
7
8
 
8
9
  const SEO_TITLE =
9
10
  "Agent-Native Clips - Open Source, agent-friendly Loom alternative";
@@ -24,24 +25,27 @@ export function meta() {
24
25
 
25
26
  export default function LibraryIndexRoute() {
26
27
  const t = useT();
28
+ const { sidebarHasNewRecordingAction } = usePageHeaderLayout();
27
29
  return (
28
30
  <LibraryGrid
29
31
  view="library"
30
32
  folderId={null}
31
33
  title="Library"
32
34
  extraActions={
33
- <Button
34
- className="gap-1.5 bg-primary text-primary-foreground shadow-sm hover:bg-primary/90"
35
- size="sm"
36
- asChild
37
- >
38
- <NavLink to="/record" aria-label={t("navigation.newRecording")}>
39
- <IconPlayerRecord className="h-4 w-4" />
40
- <span className="hidden sm:inline">
41
- {t("navigation.newRecording")}
42
- </span>
43
- </NavLink>
44
- </Button>
35
+ !sidebarHasNewRecordingAction && (
36
+ <Button
37
+ className="gap-1.5 bg-primary text-primary-foreground shadow-sm hover:bg-primary/90"
38
+ size="sm"
39
+ asChild
40
+ >
41
+ <NavLink to="/record" aria-label={t("navigation.newRecording")}>
42
+ <IconPlayerRecord className="h-4 w-4" />
43
+ <span className="hidden sm:inline">
44
+ {t("navigation.newRecording")}
45
+ </span>
46
+ </NavLink>
47
+ </Button>
48
+ )
45
49
  }
46
50
  />
47
51
  );
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-10
4
+ ---
5
+
6
+ New recording appears once when the library sidebar is open.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-10
4
+ ---
5
+
6
+ Slack setup now more clearly separates the legacy unfurl token fallback from workspace connections and messaging automations.
@@ -212,7 +212,7 @@ registerRequiredSecret({
212
212
  key: "SLACK_BOT_TOKEN",
213
213
  label: "Slack Bot Token (legacy)",
214
214
  description:
215
- "Legacy single-workspace bot token fallback for Clips link unfurls. New installs should use the Slack OAuth connect flow.",
215
+ "Legacy single-workspace bot token fallback for Clips link unfurls. New installs should use the Clips Slack workspace connection; new messaging automations should connect Slack in Settings > Messaging.",
216
216
  docsUrl: "https://api.slack.com/apps",
217
217
  scope: "workspace",
218
218
  kind: "api-key",