@agent-native/core 0.108.0 → 0.109.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +18 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/a2a/client.ts +140 -17
  5. package/corpus/core/src/a2a/handlers.ts +60 -0
  6. package/corpus/core/src/a2a/index.ts +6 -1
  7. package/corpus/core/src/a2a/invoke.ts +68 -1
  8. package/corpus/core/src/a2a/server.ts +13 -1
  9. package/corpus/core/src/a2a/types.ts +16 -0
  10. package/corpus/core/src/action.ts +3 -2
  11. package/corpus/core/src/agent/production-agent.ts +10 -4
  12. package/corpus/core/src/client/AssistantChat.tsx +648 -603
  13. package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -4
  14. package/corpus/core/src/client/agent-chat-adapter.ts +23 -37
  15. package/corpus/core/src/client/agent-sidebar-state.ts +4 -0
  16. package/corpus/core/src/client/analytics.ts +84 -0
  17. package/corpus/core/src/client/chat/message-components.tsx +94 -22
  18. package/corpus/core/src/client/chat/tool-call-display.tsx +170 -47
  19. package/corpus/core/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
  20. package/corpus/core/src/client/chat-thread-url.ts +11 -0
  21. package/corpus/core/src/client/error-capture.ts +12 -0
  22. package/corpus/core/src/client/extensions/ExtensionSlot.tsx +37 -1
  23. package/corpus/core/src/client/index.ts +2 -0
  24. package/corpus/core/src/client/route-chunk-recovery.ts +20 -8
  25. package/corpus/core/src/client/session-replay.ts +31 -0
  26. package/corpus/core/src/extensions/actions.ts +2 -14
  27. package/corpus/core/src/extensions/store.ts +1 -1
  28. package/corpus/core/src/localization/default-messages.ts +3 -0
  29. package/corpus/core/src/mcp/build-server.ts +2 -2
  30. package/corpus/core/src/progress/actions.ts +4 -2
  31. package/corpus/core/src/provider-api/index.ts +205 -105
  32. package/corpus/core/src/scripts/call-agent.ts +137 -17
  33. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +40 -0
  34. package/corpus/core/src/server/agent-chat-plugin.ts +31 -0
  35. package/corpus/core/src/styles/agent-conversation.css +7 -0
  36. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +20 -0
  37. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +20 -0
  38. package/corpus/core/src/templates/default/app/i18n/en-US.ts +20 -0
  39. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +20 -0
  40. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
  41. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +19 -0
  42. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +20 -0
  43. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +19 -0
  44. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +20 -0
  45. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +19 -0
  46. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
  47. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
  48. package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  49. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  50. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -10
  51. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +54 -23
  52. package/corpus/templates/analytics/.builder/skills/apollo/SKILL.md +19 -41
  53. package/corpus/templates/analytics/.builder/skills/commonroom/SKILL.md +20 -35
  54. package/corpus/templates/analytics/.builder/skills/github/SKILL.md +23 -67
  55. package/corpus/templates/analytics/.builder/skills/pylon/SKILL.md +25 -43
  56. package/corpus/templates/analytics/AGENTS.md +22 -13
  57. package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
  58. package/corpus/templates/analytics/actions/configure-gong-native-insights.ts +29 -0
  59. package/corpus/templates/analytics/actions/content-calendar-schema.ts +8 -4
  60. package/corpus/templates/analytics/actions/content-calendar.ts +12 -4
  61. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -1
  62. package/corpus/templates/analytics/actions/gong-calls.ts +113 -22
  63. package/corpus/templates/analytics/actions/gong-native-insights.ts +166 -0
  64. package/corpus/templates/analytics/actions/hubspot-deals.ts +190 -46
  65. package/corpus/templates/analytics/actions/pylon-issues.ts +123 -0
  66. package/corpus/templates/analytics/actions/slack-messages.ts +179 -27
  67. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +48 -152
  68. package/corpus/templates/analytics/app/components/ui/chart.tsx +1 -1
  69. package/corpus/templates/analytics/app/hooks/use-chart-tooltip-flip.ts +21 -6
  70. package/corpus/templates/analytics/app/i18n/zh-TW.ts +13 -0
  71. package/corpus/templates/analytics/app/i18n-data.ts +134 -0
  72. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +181 -30
  73. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +6 -0
  74. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +4 -3
  75. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-editors-can-add-shared-extensions-or-opt-into-per-.md +6 -0
  76. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extensions-show-a-loading-skeleton.md +6 -0
  77. package/corpus/templates/analytics/changelog/2026-07-17-errors-now-group-repeat-failures-consistently-and-keep-priva.md +6 -0
  78. package/corpus/templates/analytics/changelog/2026-07-17-gong-transcript-reviews-now-batch-bounded-call-windows-for-f.md +6 -0
  79. package/corpus/templates/analytics/changelog/2026-07-17-hubspot-deal-filters-now-run-in-hubspot-before-paging-result.md +6 -0
  80. package/corpus/templates/analytics/changelog/2026-07-17-notion-content-calendars-now-discover-the-matching-database-.md +6 -0
  81. package/corpus/templates/analytics/changelog/2026-07-17-pylon-dashboard-reads-now-use-the-paginated-issue-search-api.md +6 -0
  82. package/corpus/templates/analytics/changelog/2026-07-17-slack-reads-no-longer-join-channels-and-report-pagination-coverage.md +6 -0
  83. package/corpus/templates/analytics/server/handlers/notion.ts +14 -3
  84. package/corpus/templates/analytics/server/handlers/slack.ts +182 -29
  85. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -6
  86. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +6 -2
  87. package/corpus/templates/analytics/server/lib/error-capture.ts +75 -8
  88. package/corpus/templates/analytics/server/lib/gong-native-policy.ts +72 -0
  89. package/corpus/templates/analytics/server/lib/gong.ts +54 -66
  90. package/corpus/templates/analytics/server/lib/hubspot.ts +40 -3
  91. package/corpus/templates/analytics/server/lib/notion.ts +83 -8
  92. package/corpus/templates/analytics/server/lib/real-data-actions.ts +4 -0
  93. package/corpus/templates/analytics/server/lib/slack.ts +242 -90
  94. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -3
  95. package/corpus/templates/analytics/server/routes/api/pylon/accounts.get.ts +42 -1
  96. package/corpus/templates/analytics/server/routes/api/pylon/issues.get.ts +71 -1
  97. package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +44 -4
  98. package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +19 -1
  99. package/corpus/templates/clips/app/components/library/create-folder-dialog.tsx +123 -0
  100. package/corpus/templates/clips/app/components/library/library-grid.tsx +42 -4
  101. package/corpus/templates/clips/app/components/library/recording-card.tsx +30 -0
  102. package/corpus/templates/clips/app/entry.client.tsx +6 -1
  103. package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -1
  104. package/corpus/templates/clips/app/i18n/de-DE.ts +12 -1
  105. package/corpus/templates/clips/app/i18n/en-US.ts +12 -1
  106. package/corpus/templates/clips/app/i18n/es-ES.ts +11 -1
  107. package/corpus/templates/clips/app/i18n/fr-FR.ts +11 -1
  108. package/corpus/templates/clips/app/i18n/hi-IN.ts +10 -1
  109. package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -1
  110. package/corpus/templates/clips/app/i18n/ko-KR.ts +11 -1
  111. package/corpus/templates/clips/app/i18n/pt-BR.ts +11 -1
  112. package/corpus/templates/clips/app/i18n/zh-CN.ts +11 -1
  113. package/corpus/templates/clips/app/i18n/zh-TW.ts +11 -1
  114. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +72 -1
  115. package/corpus/templates/clips/changelog/2026-07-17-choose-which-workspace-receives-new-clips-recordings-and-des.md +6 -0
  116. package/corpus/templates/clips/changelog/2026-07-17-create-folders-directly-from-the-move-menu.md +6 -0
  117. package/corpus/templates/clips/changelog/2026-07-17-failed-desktop-uploads-now-offer-a-direct-way-to-reopen-clip.md +6 -0
  118. package/corpus/templates/clips/desktop/src/app.tsx +1 -1
  119. package/corpus/templates/content/app/entry.client.tsx +6 -1
  120. package/corpus/templates/dispatch/AGENTS.md +5 -0
  121. package/corpus/templates/dispatch/changelog/2026-07-17-apps-page-links-to-other-available-apps.md +6 -0
  122. package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +6 -0
  123. package/corpus/templates/mail/app/entry.client.tsx +6 -1
  124. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +11 -7
  125. package/corpus/templates/slides/.env.example +0 -1
  126. package/corpus/templates/slides/AGENTS.md +4 -0
  127. package/corpus/templates/slides/DEVELOPING.md +2 -2
  128. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
  129. package/corpus/templates/slides/actions/logo-config.ts +6 -7
  130. package/corpus/templates/slides/actions/search-images.ts +11 -39
  131. package/corpus/templates/slides/actions/search-logos.ts +5 -52
  132. package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +1 -1
  133. package/corpus/templates/slides/app/components/editor/LogoSearchPanel.tsx +16 -26
  134. package/corpus/templates/slides/app/entry.client.tsx +6 -1
  135. package/corpus/templates/slides/server/lib/media-search-providers.ts +216 -0
  136. package/corpus/templates/slides/server/register-secrets.ts +30 -0
  137. package/dist/a2a/client.d.ts +38 -1
  138. package/dist/a2a/client.d.ts.map +1 -1
  139. package/dist/a2a/client.js +81 -12
  140. package/dist/a2a/client.js.map +1 -1
  141. package/dist/a2a/handlers.d.ts.map +1 -1
  142. package/dist/a2a/handlers.js +47 -0
  143. package/dist/a2a/handlers.js.map +1 -1
  144. package/dist/a2a/index.d.ts +4 -4
  145. package/dist/a2a/index.d.ts.map +1 -1
  146. package/dist/a2a/index.js +2 -2
  147. package/dist/a2a/index.js.map +1 -1
  148. package/dist/a2a/invoke.d.ts +26 -2
  149. package/dist/a2a/invoke.d.ts.map +1 -1
  150. package/dist/a2a/invoke.js +30 -1
  151. package/dist/a2a/invoke.js.map +1 -1
  152. package/dist/a2a/server.d.ts.map +1 -1
  153. package/dist/a2a/server.js +14 -1
  154. package/dist/a2a/server.js.map +1 -1
  155. package/dist/a2a/types.d.ts +12 -0
  156. package/dist/a2a/types.d.ts.map +1 -1
  157. package/dist/a2a/types.js.map +1 -1
  158. package/dist/action.d.ts +3 -2
  159. package/dist/action.d.ts.map +1 -1
  160. package/dist/action.js.map +1 -1
  161. package/dist/agent/production-agent.d.ts +5 -0
  162. package/dist/agent/production-agent.d.ts.map +1 -1
  163. package/dist/agent/production-agent.js +5 -3
  164. package/dist/agent/production-agent.js.map +1 -1
  165. package/dist/client/AssistantChat.d.ts +14 -1
  166. package/dist/client/AssistantChat.d.ts.map +1 -1
  167. package/dist/client/AssistantChat.js +158 -136
  168. package/dist/client/AssistantChat.js.map +1 -1
  169. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  170. package/dist/client/MultiTabAssistantChat.js +27 -4
  171. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  172. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  173. package/dist/client/agent-chat-adapter.js +21 -39
  174. package/dist/client/agent-chat-adapter.js.map +1 -1
  175. package/dist/client/agent-sidebar-state.d.ts +1 -0
  176. package/dist/client/agent-sidebar-state.d.ts.map +1 -1
  177. package/dist/client/agent-sidebar-state.js +4 -0
  178. package/dist/client/agent-sidebar-state.js.map +1 -1
  179. package/dist/client/analytics.d.ts +14 -0
  180. package/dist/client/analytics.d.ts.map +1 -1
  181. package/dist/client/analytics.js +67 -0
  182. package/dist/client/analytics.js.map +1 -1
  183. package/dist/client/chat/message-components.d.ts +8 -0
  184. package/dist/client/chat/message-components.d.ts.map +1 -1
  185. package/dist/client/chat/message-components.js +62 -19
  186. package/dist/client/chat/message-components.js.map +1 -1
  187. package/dist/client/chat/tool-call-display.d.ts +6 -0
  188. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  189. package/dist/client/chat/tool-call-display.js +83 -14
  190. package/dist/client/chat/tool-call-display.js.map +1 -1
  191. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts +8 -0
  192. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts.map +1 -0
  193. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js +51 -0
  194. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js.map +1 -0
  195. package/dist/client/chat-thread-url.d.ts +2 -0
  196. package/dist/client/chat-thread-url.d.ts.map +1 -0
  197. package/dist/client/chat-thread-url.js +12 -0
  198. package/dist/client/chat-thread-url.js.map +1 -0
  199. package/dist/client/error-capture.d.ts.map +1 -1
  200. package/dist/client/error-capture.js +7 -0
  201. package/dist/client/error-capture.js.map +1 -1
  202. package/dist/client/extensions/ExtensionSlot.d.ts +3 -1
  203. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  204. package/dist/client/extensions/ExtensionSlot.js +28 -3
  205. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  206. package/dist/client/index.d.ts +1 -1
  207. package/dist/client/index.d.ts.map +1 -1
  208. package/dist/client/index.js +1 -1
  209. package/dist/client/index.js.map +1 -1
  210. package/dist/client/route-chunk-recovery.d.ts.map +1 -1
  211. package/dist/client/route-chunk-recovery.js +14 -9
  212. package/dist/client/route-chunk-recovery.js.map +1 -1
  213. package/dist/client/session-replay.d.ts +15 -0
  214. package/dist/client/session-replay.d.ts.map +1 -1
  215. package/dist/client/session-replay.js +20 -0
  216. package/dist/client/session-replay.js.map +1 -1
  217. package/dist/collab/routes.d.ts +1 -1
  218. package/dist/collab/struct-routes.d.ts +1 -1
  219. package/dist/extensions/actions.d.ts.map +1 -1
  220. package/dist/extensions/actions.js +2 -10
  221. package/dist/extensions/actions.js.map +1 -1
  222. package/dist/extensions/store.js +1 -1
  223. package/dist/extensions/store.js.map +1 -1
  224. package/dist/localization/default-messages.d.ts +3 -0
  225. package/dist/localization/default-messages.d.ts.map +1 -1
  226. package/dist/localization/default-messages.js +3 -0
  227. package/dist/localization/default-messages.js.map +1 -1
  228. package/dist/mcp/build-server.d.ts +2 -0
  229. package/dist/mcp/build-server.d.ts.map +1 -1
  230. package/dist/mcp/build-server.js +2 -2
  231. package/dist/mcp/build-server.js.map +1 -1
  232. package/dist/notifications/routes.d.ts +2 -2
  233. package/dist/observability/routes.d.ts +1 -1
  234. package/dist/progress/actions.d.ts.map +1 -1
  235. package/dist/progress/actions.js +3 -2
  236. package/dist/progress/actions.js.map +1 -1
  237. package/dist/progress/routes.d.ts +1 -1
  238. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  239. package/dist/provider-api/index.d.ts.map +1 -1
  240. package/dist/provider-api/index.js +91 -8
  241. package/dist/provider-api/index.js.map +1 -1
  242. package/dist/resources/handlers.d.ts +2 -2
  243. package/dist/scripts/call-agent.d.ts.map +1 -1
  244. package/dist/scripts/call-agent.js +107 -16
  245. package/dist/scripts/call-agent.js.map +1 -1
  246. package/dist/server/agent-chat/action-filters-a2a.d.ts +6 -0
  247. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  248. package/dist/server/agent-chat/action-filters-a2a.js +27 -0
  249. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  250. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  251. package/dist/server/agent-chat-plugin.js +27 -1
  252. package/dist/server/agent-chat-plugin.js.map +1 -1
  253. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  254. package/dist/server/transcribe-voice.d.ts +1 -1
  255. package/dist/styles/agent-conversation.css +7 -0
  256. package/dist/templates/default/app/i18n/ar-SA.ts +20 -0
  257. package/dist/templates/default/app/i18n/de-DE.ts +20 -0
  258. package/dist/templates/default/app/i18n/en-US.ts +20 -0
  259. package/dist/templates/default/app/i18n/es-ES.ts +20 -0
  260. package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
  261. package/dist/templates/default/app/i18n/hi-IN.ts +19 -0
  262. package/dist/templates/default/app/i18n/ja-JP.ts +20 -0
  263. package/dist/templates/default/app/i18n/ko-KR.ts +19 -0
  264. package/dist/templates/default/app/i18n/pt-BR.ts +20 -0
  265. package/dist/templates/default/app/i18n/zh-CN.ts +19 -0
  266. package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
  267. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
  268. package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  269. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  270. package/package.json +1 -1
  271. package/src/templates/default/app/i18n/ar-SA.ts +20 -0
  272. package/src/templates/default/app/i18n/de-DE.ts +20 -0
  273. package/src/templates/default/app/i18n/en-US.ts +20 -0
  274. package/src/templates/default/app/i18n/es-ES.ts +20 -0
  275. package/src/templates/default/app/i18n/fr-FR.ts +21 -0
  276. package/src/templates/default/app/i18n/hi-IN.ts +19 -0
  277. package/src/templates/default/app/i18n/ja-JP.ts +20 -0
  278. package/src/templates/default/app/i18n/ko-KR.ts +19 -0
  279. package/src/templates/default/app/i18n/pt-BR.ts +20 -0
  280. package/src/templates/default/app/i18n/zh-CN.ts +19 -0
  281. package/src/templates/default/app/i18n/zh-TW.ts +19 -0
  282. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
  283. package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  284. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  285. package/corpus/templates/analytics/server/handlers/github.ts +0 -200
  286. package/corpus/templates/analytics/server/handlers/pylon.ts +0 -43
  287. package/corpus/templates/analytics/server/lib/apollo.ts +0 -167
  288. package/corpus/templates/analytics/server/lib/commonroom.ts +0 -149
  289. package/corpus/templates/analytics/server/lib/github.ts +0 -660
  290. package/corpus/templates/analytics/server/lib/mixpanel.ts +0 -156
  291. package/corpus/templates/analytics/server/lib/posthog.ts +0 -194
  292. package/corpus/templates/analytics/server/lib/pylon.ts +0 -109
  293. package/corpus/templates/analytics/server/routes/api/github/graphql.post.ts +0 -1
  294. package/corpus/templates/analytics/server/routes/api/github/issue.get.ts +0 -1
  295. package/corpus/templates/analytics/server/routes/api/github/org-prs.get.ts +0 -1
  296. package/corpus/templates/analytics/server/routes/api/github/pr.get.ts +0 -1
  297. package/corpus/templates/analytics/server/routes/api/github/prs.get.ts +0 -1
  298. package/corpus/templates/analytics/server/routes/api/github/search.get.ts +0 -1
  299. package/corpus/templates/slides/actions/fetch-logos.ts +0 -90
  300. package/corpus/templates/slides/actions/image-search.ts +0 -64
  301. package/corpus/templates/slides/actions/import-github.ts +0 -182
  302. package/corpus/templates/slides/actions/logo-lookup.ts +0 -113
@@ -753,10 +753,15 @@ export function MultiTabAssistantChat({
753
753
  const [urlThreadId, setUrlThreadId] = useState<string | null>(() =>
754
754
  threadUrlSyncEnabled
755
755
  ? threadRouteControlsActiveThread
756
- ? (routeThreadId ?? null)
756
+ ? (routeThreadId ?? readUrlThreadId(threadUrlParamName))
757
757
  : readUrlThreadId(threadUrlParamName)
758
758
  : null,
759
759
  );
760
+ const [deepLinkedThreadId] = useState<string | null>(() =>
761
+ threadUrlSyncEnabled ? null : readUrlThreadId(DEFAULT_THREAD_URL_PARAM),
762
+ );
763
+ const [activeDeepLinkedThreadId, setActiveDeepLinkedThreadId] =
764
+ useState(deepLinkedThreadId);
760
765
  const urlThreadIdRef = useRef(urlThreadId);
761
766
  urlThreadIdRef.current = urlThreadId;
762
767
 
@@ -780,8 +785,28 @@ export function MultiTabAssistantChat({
780
785
 
781
786
  useEffect(() => {
782
787
  if (!threadUrlSyncEnabled || !threadRouteControlsActiveThread) return;
783
- setUrlThreadId(routeThreadId ?? null);
784
- }, [routeThreadId, threadRouteControlsActiveThread, threadUrlSyncEnabled]);
788
+ setUrlThreadId(routeThreadId ?? readUrlThreadId(threadUrlParamName));
789
+ }, [
790
+ routeThreadId,
791
+ threadRouteControlsActiveThread,
792
+ threadUrlParamName,
793
+ threadUrlSyncEnabled,
794
+ ]);
795
+
796
+ useEffect(() => {
797
+ if (threadUrlSyncEnabled) return;
798
+ const update = () =>
799
+ setActiveDeepLinkedThreadId(readUrlThreadId(DEFAULT_THREAD_URL_PARAM));
800
+ const uninstallHistoryPatch = installHistoryThreadUrlPatch();
801
+ update();
802
+ window.addEventListener("popstate", update);
803
+ window.addEventListener(THREAD_URL_CHANGED_EVENT, update);
804
+ return () => {
805
+ uninstallHistoryPatch();
806
+ window.removeEventListener("popstate", update);
807
+ window.removeEventListener(THREAD_URL_CHANGED_EVENT, update);
808
+ };
809
+ }, [threadUrlSyncEnabled]);
785
810
 
786
811
  const writeThreadUrl = useCallback(
787
812
  (threadId: string | null, options: { replace?: boolean } = {}): void => {
@@ -856,7 +881,9 @@ export function MultiTabAssistantChat({
856
881
  renameThread,
857
882
  } = useChatThreads(apiUrl, storageKey, null, {
858
883
  restoreActiveThread,
859
- routeThreadId: threadUrlSyncEnabled ? urlThreadId : undefined,
884
+ routeThreadId: threadUrlSyncEnabled
885
+ ? urlThreadId
886
+ : (activeDeepLinkedThreadId ?? undefined),
860
887
  });
861
888
 
862
889
  const switchThread = useCallback(
@@ -1875,6 +1875,10 @@ export function createAgentChatAdapter(
1875
1875
  }
1876
1876
  };
1877
1877
 
1878
+ const canAttachRun = (candidateRunId: string, candidateTurnId: string) =>
1879
+ attemptedRunIds.includes(candidateRunId) ||
1880
+ (candidateTurnId.length > 0 && candidateTurnId === turnId);
1881
+
1878
1882
  const preparingActionStateForRun = (
1879
1883
  id: string | null,
1880
1884
  ): PreparingActionState | undefined => {
@@ -2097,15 +2101,13 @@ export function createAgentChatAdapter(
2097
2101
  }
2098
2102
  const active = await activeRes.json();
2099
2103
  if (active?.active && active.runId) {
2100
- updateCurrentRunDispatchMode(active.dispatchMode);
2101
- const activeStatus =
2102
- typeof active.status === "string" ? active.status : "";
2104
+ const activeRunId = String(active.runId);
2103
2105
  const activeTurnId =
2104
2106
  typeof active.turnId === "string" ? active.turnId : "";
2105
- if (activeStatus !== "running" && activeTurnId !== turnId) {
2107
+ if (!canAttachRun(activeRunId, activeTurnId)) {
2106
2108
  return false;
2107
2109
  }
2108
- const activeRunId = String(active.runId);
2110
+ updateCurrentRunDispatchMode(active.dispatchMode);
2109
2111
  const previousRunId = runId;
2110
2112
  runId = activeRunId;
2111
2113
  if (!attemptedRunIds.includes(activeRunId)) {
@@ -2172,17 +2174,17 @@ export function createAgentChatAdapter(
2172
2174
  typeof active.dispatchMode === "string"
2173
2175
  ? active.dispatchMode
2174
2176
  : "";
2177
+ const activeTurnId =
2178
+ typeof active.turnId === "string" ? active.turnId : "";
2179
+ if (!canAttachRun(activeRunId, activeTurnId)) return false;
2175
2180
  updateCurrentRunDispatchMode(dispatchMode);
2176
2181
  if (activeRunId === interruptedRunId) {
2177
2182
  if (dispatchMode.startsWith("background")) continue;
2178
2183
  return false;
2179
2184
  }
2180
- const activeTurnId =
2181
- typeof active.turnId === "string" ? active.turnId : "";
2182
2185
  const activeStatus =
2183
2186
  typeof active.status === "string" ? active.status : "";
2184
2187
  if (!dispatchMode.startsWith("background")) return false;
2185
- if (activeTurnId && activeTurnId !== turnId) return false;
2186
2188
  if (activeStatus !== "running" && activeStatus !== "starting") {
2187
2189
  return false;
2188
2190
  }
@@ -2548,10 +2550,7 @@ export function createAgentChatAdapter(
2548
2550
  // Only follow runs belonging to THIS turn (server-chained
2549
2551
  // successors reuse the turnId) or runs we already attached to.
2550
2552
  const isOurRun =
2551
- activeRunId !== null &&
2552
- (attemptedRunIds.includes(activeRunId) ||
2553
- !activeTurnId ||
2554
- activeTurnId === turnId);
2553
+ activeRunId !== null && canAttachRun(activeRunId, activeTurnId);
2555
2554
 
2556
2555
  if (activeRunId && isOurRun) {
2557
2556
  lastSeenActive = active;
@@ -3100,12 +3099,19 @@ export function createAgentChatAdapter(
3100
3099
  // active run is one this adapter already consumed, reconnecting
3101
3100
  // to it replays the terminal auto_continue and exits instead of
3102
3101
  // posting the continuation. Wait for stale/previous active runs
3103
- // to clear and retry THIS prompt. A genuinely newer background
3104
- // run still falls through to the reconnect path below.
3105
- const shouldRetryConflictingActiveRun =
3102
+ // to clear and retry THIS prompt. An unknown run reported to an
3103
+ // internal continuation is only adoptable after /runs/active
3104
+ // proves it carries this turnId; a bare 409 run id is not
3105
+ // enough ownership evidence.
3106
+ if (
3106
3107
  activeRunId !== null &&
3107
- (!internalContinuationRequest ||
3108
- attemptedRunIds.includes(activeRunId));
3108
+ internalContinuationRequest &&
3109
+ !attemptedRunIds.includes(activeRunId)
3110
+ ) {
3111
+ const reconnected = yield* reconnectActiveRunForThread();
3112
+ if (reconnected) return;
3113
+ }
3114
+ const shouldRetryConflictingActiveRun = activeRunId !== null;
3109
3115
  if (shouldRetryConflictingActiveRun) {
3110
3116
  queuedConflictRetries += 1;
3111
3117
  if (queuedConflictRetries <= MAX_QUEUED_CONFLICT_RETRIES) {
@@ -3157,26 +3163,6 @@ export function createAgentChatAdapter(
3157
3163
  clearActiveRun();
3158
3164
  return;
3159
3165
  }
3160
- if (activeRunId) {
3161
- try {
3162
- const previousRunId = runId;
3163
- runId = activeRunId;
3164
- if (!attemptedRunIds.includes(runId)) {
3165
- attemptedRunIds.push(runId);
3166
- }
3167
- reconnectCursorForRun(activeRunId, previousRunId);
3168
- if (threadId) {
3169
- setActiveRun({ threadId, runId, lastSeq });
3170
- }
3171
- const reconnected = yield* reconnectCurrentRun();
3172
- if (reconnected) return;
3173
- await delay(1000, abortSignal);
3174
- if (abortSignal.aborted) return;
3175
- continue;
3176
- } catch {
3177
- // Fall through to the generic response handling below.
3178
- }
3179
- }
3180
3166
  }
3181
3167
 
3182
3168
  if (res.status === 401 || res.status === 403) {
@@ -2,6 +2,9 @@ import {
2
2
  AGENT_SIDEBAR_QUERY_PARAM,
3
3
  AGENT_SIDEBAR_QUERY_VALUE_CLOSED,
4
4
  } from "../shared/agent-sidebar-url.js";
5
+ import { hasChatThreadDeepLink } from "./chat-thread-url.js";
6
+
7
+ export { hasChatThreadDeepLink } from "./chat-thread-url.js";
5
8
 
6
9
  export const SIDEBAR_OPEN_KEY = "agent-native-sidebar-open";
7
10
  export const SIDEBAR_STATE_CHANGE_EVENT = "agent-panel:state-change";
@@ -139,6 +142,7 @@ export function getInitialAgentSidebarOpen(
139
142
  ): boolean {
140
143
  const urlOverride = getAgentSidebarUrlOpenOverride();
141
144
  if (urlOverride !== null) return urlOverride;
145
+ if (hasChatThreadDeepLink()) return true;
142
146
 
143
147
  // On mobile viewports the sidebar would cover most of the screen, so
144
148
  // always start closed regardless of any persisted desktop preference.
@@ -64,6 +64,10 @@ type PageviewTrackingState = {
64
64
  lastPageviewKey: string | null;
65
65
  };
66
66
 
67
+ type AgentChatTrackingState = {
68
+ seen: Map<string, number>;
69
+ };
70
+
67
71
  /**
68
72
  * First-party, Sentry-style error capture configuration. Pass `true`/`false`
69
73
  * to force on/off, or an options object to tune it. When omitted, error
@@ -173,6 +177,11 @@ export const AGENT_NATIVE_EXCEPTION_EVENT_NAME = "$exception";
173
177
  const PAGEVIEW_TRACKING_STATE_KEY = Symbol.for(
174
178
  "agent-native.client.pageviewTracking",
175
179
  );
180
+ const AGENT_CHAT_TRACKING_STATE_KEY = Symbol.for(
181
+ "agent-native.client.agentChatTracking",
182
+ );
183
+ const AGENT_CHAT_LIFECYCLE_DEDUPE_TTL_MS = 10 * 60 * 1_000;
184
+ const MAX_AGENT_CHAT_LIFECYCLE_DEDUPE_KEYS = 1_000;
176
185
 
177
186
  const LLM_CONNECTION_STORAGE_KEY = "agent-native.llm_connection_status";
178
187
  const LLM_CONNECTION_CACHE_TTL_MS = 5 * 60 * 1000;
@@ -1045,6 +1054,81 @@ function getPageviewTrackingState(): PageviewTrackingState {
1045
1054
  return g[PAGEVIEW_TRACKING_STATE_KEY];
1046
1055
  }
1047
1056
 
1057
+ function getAgentChatTrackingState(): AgentChatTrackingState {
1058
+ const g = globalThis as typeof globalThis & {
1059
+ [AGENT_CHAT_TRACKING_STATE_KEY]?: AgentChatTrackingState;
1060
+ };
1061
+ if (!g[AGENT_CHAT_TRACKING_STATE_KEY]) {
1062
+ g[AGENT_CHAT_TRACKING_STATE_KEY] = { seen: new Map() };
1063
+ }
1064
+ return g[AGENT_CHAT_TRACKING_STATE_KEY];
1065
+ }
1066
+
1067
+ export type AgentChatLifecycleEvent = {
1068
+ phase: "surface-mounted" | "run-observed" | "run-stopped";
1069
+ surface?: string;
1070
+ threadId?: string;
1071
+ runId?: string;
1072
+ tabId?: string;
1073
+ };
1074
+
1075
+ /**
1076
+ * Record a content-free, browser-session-linked chat lifecycle marker and add
1077
+ * the same marker to session replay when replay is configured. The bounded
1078
+ * global de-dupe survives React Strict Mode remounts without retaining keys
1079
+ * forever.
1080
+ */
1081
+ export function trackAgentChatLifecycle(input: AgentChatLifecycleEvent): void {
1082
+ if (typeof window === "undefined") return;
1083
+ const surface = input.surface?.trim() || "app";
1084
+ const dedupeKey = [
1085
+ input.phase,
1086
+ surface,
1087
+ input.threadId ?? "",
1088
+ input.runId ?? "",
1089
+ input.tabId ?? "",
1090
+ ].join(":");
1091
+ const state = getAgentChatTrackingState();
1092
+ const now = Date.now();
1093
+ for (const [key, seenAt] of state.seen) {
1094
+ if (now - seenAt >= AGENT_CHAT_LIFECYCLE_DEDUPE_TTL_MS) {
1095
+ state.seen.delete(key);
1096
+ }
1097
+ }
1098
+ if (state.seen.has(dedupeKey)) return;
1099
+ state.seen.set(dedupeKey, now);
1100
+ while (state.seen.size > MAX_AGENT_CHAT_LIFECYCLE_DEDUPE_KEYS) {
1101
+ const oldestKey = state.seen.keys().next().value;
1102
+ if (oldestKey === undefined) break;
1103
+ state.seen.delete(oldestKey);
1104
+ }
1105
+
1106
+ void (async () => {
1107
+ const replayResult =
1108
+ _sessionReplayOptions && _trackingContentCaptureEnabled
1109
+ ? await startConfiguredSessionReplay(_sessionReplayOptions)
1110
+ : null;
1111
+ const properties = {
1112
+ phase: input.phase,
1113
+ chat_surface: surface,
1114
+ ...(input.threadId ? { thread_id: input.threadId } : {}),
1115
+ ...(input.runId ? { run_id: input.runId } : {}),
1116
+ ...(input.tabId ? { chat_tab_id: input.tabId } : {}),
1117
+ replay_status: replayResult?.started
1118
+ ? "active"
1119
+ : (replayResult?.reason ?? "not-configured"),
1120
+ };
1121
+ trackEvent("agent_chat_lifecycle", properties);
1122
+ _sessionReplayModuleForCapture?.emitSessionReplayAgentChatEvent?.({
1123
+ phase: input.phase,
1124
+ surface,
1125
+ ...(input.threadId ? { threadId: input.threadId } : {}),
1126
+ ...(input.runId ? { runId: input.runId } : {}),
1127
+ ...(input.tabId ? { tabId: input.tabId } : {}),
1128
+ });
1129
+ })();
1130
+ }
1131
+
1048
1132
  export function configureTracking(options: ConfigureTrackingOptions): void {
1049
1133
  const publicKey = options.key || options.publicKey;
1050
1134
  if (publicKey) {
@@ -72,7 +72,10 @@ import {
72
72
  import {
73
73
  ToolCallFallback,
74
74
  FilesChangedSummary,
75
+ ASSISTANT_VISIBLE_TOOL_CALL_LIMIT,
75
76
  ChatRunningContext,
77
+ ChatRunDurationContext,
78
+ RanToolsSummary,
76
79
  ReasoningCell,
77
80
  WorkedForSummary,
78
81
  } from "./tool-call-display.js";
@@ -820,7 +823,7 @@ function assistantMessageStatusIsTerminal(message: {
820
823
  return statusType === "complete" || statusType === "incomplete";
821
824
  }
822
825
 
823
- function messageTextFromContent(content: unknown): string {
826
+ export function messageTextFromContent(content: unknown): string {
824
827
  if (typeof content === "string") return content;
825
828
  if (!Array.isArray(content)) return "";
826
829
  return content
@@ -829,14 +832,10 @@ function messageTextFromContent(content: unknown): string {
829
832
  const record = part as {
830
833
  type?: unknown;
831
834
  text?: unknown;
832
- result?: unknown;
833
835
  };
834
- const values: string[] = [];
835
- if (typeof record.text === "string") values.push(record.text);
836
- if (record.type === "tool-call" && typeof record.result === "string") {
837
- values.push(record.result);
838
- }
839
- return values;
836
+ return record.type === "text" && typeof record.text === "string"
837
+ ? [record.text]
838
+ : [];
840
839
  })
841
840
  .join("\n");
842
841
  }
@@ -874,10 +873,10 @@ export function shouldShowAssistantMessageFooter({
874
873
  hasUnresolvedTool?: boolean;
875
874
  }): boolean {
876
875
  if (!hasRenderableContent) return false;
877
- if (chatRunning) return false;
878
876
  if (!isLast) return true;
877
+ if (chatRunning) return false;
879
878
  if (hasUnresolvedTool) return false;
880
- return !chatRunning && statusIsTerminal;
879
+ return statusIsTerminal;
881
880
  }
882
881
 
883
882
  export function shouldShowAssistantWorkSummary({
@@ -954,16 +953,77 @@ export function isCollapsibleAssistantWorkPart(part: {
954
953
  );
955
954
  }
956
955
 
957
- function groupAssistantWorkParts(part: {
958
- type?: string;
959
- toolName?: string;
960
- }): ["group-work"] | null {
956
+ export function getAssistantToolSummaryInfo(
957
+ parts: readonly { type?: string; toolName?: string }[],
958
+ ): { startIndex: number; hiddenToolCount: number } {
959
+ const toolCallIndices = parts.reduce<number[]>((indices, part, index) => {
960
+ if (part.type === "tool-call" && isCollapsibleAssistantWorkPart(part)) {
961
+ indices.push(index);
962
+ }
963
+ return indices;
964
+ }, []);
965
+
966
+ if (toolCallIndices.length <= ASSISTANT_VISIBLE_TOOL_CALL_LIMIT) {
967
+ return { startIndex: -1, hiddenToolCount: 0 };
968
+ }
969
+
970
+ const startIndex =
971
+ toolCallIndices[
972
+ toolCallIndices.length - ASSISTANT_VISIBLE_TOOL_CALL_LIMIT
973
+ ]!;
974
+ return {
975
+ startIndex,
976
+ hiddenToolCount: toolCallIndices.length - ASSISTANT_VISIBLE_TOOL_CALL_LIMIT,
977
+ };
978
+ }
979
+
980
+ function groupAssistantWorkParts(
981
+ part: {
982
+ type?: string;
983
+ toolName?: string;
984
+ },
985
+ index: number,
986
+ parts: readonly { type?: string; toolName?: string }[],
987
+ ): ["group-work"] | ["group-work", "group-ran-tools"] | null {
961
988
  if (isCollapsibleAssistantWorkPart(part)) {
989
+ const { startIndex } = getAssistantToolSummaryInfo(parts);
990
+ if (isAssistantToolSummaryPart(parts, index, startIndex)) {
991
+ return ["group-work", "group-ran-tools"];
992
+ }
962
993
  return ["group-work"];
963
994
  }
964
995
  return null;
965
996
  }
966
997
 
998
+ function isAssistantToolSummaryPart(
999
+ parts: readonly { type?: string; toolName?: string }[],
1000
+ index: number,
1001
+ startIndex: number,
1002
+ ): boolean {
1003
+ if (startIndex < 0 || index >= startIndex) return false;
1004
+ if (!isCollapsibleAssistantWorkPart(parts[index]!)) return false;
1005
+
1006
+ let segmentStart = index;
1007
+ while (
1008
+ segmentStart > 0 &&
1009
+ isCollapsibleAssistantWorkPart(parts[segmentStart - 1]!)
1010
+ ) {
1011
+ segmentStart--;
1012
+ }
1013
+
1014
+ let segmentEnd = index + 1;
1015
+ while (
1016
+ segmentEnd < startIndex &&
1017
+ isCollapsibleAssistantWorkPart(parts[segmentEnd]!)
1018
+ ) {
1019
+ segmentEnd++;
1020
+ }
1021
+
1022
+ return parts
1023
+ .slice(segmentStart, segmentEnd)
1024
+ .some((candidate) => candidate.type === "tool-call");
1025
+ }
1026
+
967
1027
  export function AssistantMessage() {
968
1028
  const [restoreState, setRestoreState] = useState<
969
1029
  "idle" | "confirming" | "restoring"
@@ -971,6 +1031,7 @@ export function AssistantMessage() {
971
1031
  const messageRuntime = useMessageRuntime();
972
1032
  const thread = useThread();
973
1033
  const chatRunning = React.useContext(ChatRunningContext);
1034
+ const lastRunDurationMs = React.useContext(ChatRunDurationContext);
974
1035
  const msg = messageRuntime.getState();
975
1036
  const timestamp = formatMessageTimestamp(msg.createdAt);
976
1037
  const isLast =
@@ -1001,16 +1062,17 @@ export function AssistantMessage() {
1001
1062
  }
1002
1063
  return;
1003
1064
  }
1004
- if (
1005
- !chatRunning &&
1006
- isLast &&
1007
- runStartedAtRef.current != null &&
1008
- capturedDurationMs == null
1009
- ) {
1010
- setCapturedDurationMs(Date.now() - runStartedAtRef.current);
1065
+ if (!chatRunning && isLast && capturedDurationMs == null) {
1066
+ const durationMs =
1067
+ lastRunDurationMs ??
1068
+ (runStartedAtRef.current == null
1069
+ ? null
1070
+ : Date.now() - runStartedAtRef.current);
1071
+ if (durationMs == null) return;
1072
+ setCapturedDurationMs(durationMs);
1011
1073
  runStartedAtRef.current = null;
1012
1074
  }
1013
- }, [chatRunning, isLast, capturedDurationMs]);
1075
+ }, [chatRunning, isLast, capturedDurationMs, lastRunDurationMs]);
1014
1076
 
1015
1077
  // Animate collapse only when this message just finished running in-session.
1016
1078
  const wasRunningRef = useRef(false);
@@ -1124,6 +1186,16 @@ export function AssistantMessage() {
1124
1186
  </WorkedForSummary>
1125
1187
  );
1126
1188
  }
1189
+ case "group-ran-tools": {
1190
+ const toolCount = part.indices.filter(
1191
+ (index) => msgContent?.[index]?.type === "tool-call",
1192
+ ).length;
1193
+ return (
1194
+ <RanToolsSummary toolCount={toolCount}>
1195
+ {children}
1196
+ </RanToolsSummary>
1197
+ );
1198
+ }
1127
1199
  case "text":
1128
1200
  return <MarkdownText />;
1129
1201
  case "reasoning":