@agent-native/core 0.131.7 → 0.132.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 (320) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +123 -0
  3. package/corpus/core/docs/content/durable-background-runs.mdx +15 -6
  4. package/corpus/core/docs/design/durable-agent-runs.md +15 -11
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/a2a/activity.ts +127 -10
  7. package/corpus/core/src/a2a/index.ts +3 -0
  8. package/corpus/core/src/agent/durable-background.ts +38 -28
  9. package/corpus/core/src/agent/harness/background.ts +12 -2
  10. package/corpus/core/src/agent/production-agent.ts +18 -15
  11. package/corpus/core/src/agent/run-store.ts +45 -3
  12. package/corpus/core/src/application-state/handlers.ts +45 -0
  13. package/corpus/core/src/application-state/index.ts +3 -0
  14. package/corpus/core/src/application-state/store.ts +38 -34
  15. package/corpus/core/src/audit/redact.ts +104 -18
  16. package/corpus/core/src/cli/create.ts +115 -16
  17. package/corpus/core/src/client/AgentPanel.tsx +2 -7
  18. package/corpus/core/src/client/AssistantChat.tsx +10 -2
  19. package/corpus/core/src/client/MultiTabAssistantChat.tsx +3 -0
  20. package/corpus/core/src/client/RunStuckBanner.tsx +29 -6
  21. package/corpus/core/src/client/agent-chat.ts +4 -9
  22. package/corpus/core/src/client/application-state.ts +115 -12
  23. package/corpus/core/src/client/dynamic-suggestions.ts +4 -12
  24. package/corpus/core/src/client/frame-protocol.ts +5 -1
  25. package/corpus/core/src/client/guided-questions.tsx +12 -23
  26. package/corpus/core/src/db/client.ts +148 -28
  27. package/corpus/core/src/db/create-get-db.ts +39 -6
  28. package/corpus/core/src/db/runtime-diagnostics.ts +41 -6
  29. package/corpus/core/src/deploy/build.ts +26 -33
  30. package/corpus/core/src/feature-flags/store.ts +10 -5
  31. package/corpus/core/src/integrations/a2a-continuations-store.ts +11 -0
  32. package/corpus/core/src/integrations/config-store.ts +13 -0
  33. package/corpus/core/src/integrations/google-docs-poller.ts +26 -2
  34. package/corpus/core/src/mcp-client/routes.ts +33 -2
  35. package/corpus/core/src/onboarding/plugin.ts +31 -25
  36. package/corpus/core/src/org/accept-pending.ts +2 -0
  37. package/corpus/core/src/org/auto-join-domain.ts +2 -0
  38. package/corpus/core/src/org/context.ts +35 -10
  39. package/corpus/core/src/org/handlers.ts +6 -0
  40. package/corpus/core/src/org/request-org-cache.ts +71 -0
  41. package/corpus/core/src/resources/store.ts +10 -9
  42. package/corpus/core/src/scripts/runner.ts +6 -3
  43. package/corpus/core/src/secrets/storage.ts +97 -5
  44. package/corpus/core/src/server/action-change.ts +33 -0
  45. package/corpus/core/src/server/action-routes.ts +11 -9
  46. package/corpus/core/src/server/agent-teams.ts +10 -2
  47. package/corpus/core/src/server/better-auth-instance.ts +39 -12
  48. package/corpus/core/src/server/core-routes-plugin.ts +19 -2
  49. package/corpus/core/src/server/credential-provider.ts +57 -14
  50. package/corpus/core/src/server/http-response-telemetry.ts +1 -0
  51. package/corpus/core/src/server/poll.ts +95 -57
  52. package/corpus/core/src/server/voice-providers-status.ts +19 -4
  53. package/corpus/core/src/workspace-files/tool.ts +18 -11
  54. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -0
  55. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +1 -1
  56. package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +299 -0
  57. package/corpus/templates/analytics/actions/list-native-v2-dashboard-templates.ts +34 -0
  58. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +82 -0
  59. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +2 -2
  60. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +40 -34
  61. package/corpus/templates/analytics/app/hooks/use-user-pref.ts +3 -3
  62. package/corpus/templates/analytics/app/i18n-data.ts +40 -0
  63. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +18 -10
  64. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +14 -0
  65. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +1 -0
  66. package/corpus/templates/analytics/app/routes/chart.tsx +3 -0
  67. package/corpus/templates/analytics/changelog/2026-07-30-analytics-dashboards-now-expose-native-funnel-heatmap-callou.md +6 -0
  68. package/corpus/templates/analytics/changelog/2026-07-30-analytics-now-ships-reusable-native-v2-dashboard-manifests-w.md +6 -0
  69. package/corpus/templates/analytics/server/lib/dashboard-report-render.ts +81 -1
  70. package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +457 -0
  71. package/corpus/templates/analytics/server/lib/report-chart-svg.ts +73 -2
  72. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -1
  73. package/corpus/templates/analytics/shared/dashboard-funnel.ts +83 -0
  74. package/corpus/templates/clips/actions/generate-workflow.ts +6 -4
  75. package/corpus/templates/clips/actions/reconcile-workflow-generation.ts +257 -0
  76. package/corpus/templates/clips/app/hooks/use-auto-title.ts +166 -4
  77. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
  78. package/corpus/templates/clips/changelog/2026-07-27-stopped-agent-runs-no-longer-leave-generated-workflow-cards-.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-07-30-workflow-generation-now-stops-retrying-after-repeated-failur.md +6 -0
  80. package/corpus/templates/clips/shared/workflow.ts +5 -0
  81. package/corpus/templates/content/changelog/2026-07-30-long-running-delegated-requests-now-continue-reliably.md +6 -0
  82. package/corpus/templates/content/netlify.toml +3 -0
  83. package/corpus/templates/content/server/plugins/agent-chat.ts +1 -0
  84. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +2 -1
  85. package/corpus/templates/slides/actions/patch-deck.ts +25 -1
  86. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +17 -4
  87. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +9 -1
  88. package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
  89. package/corpus/templates/slides/app/context/DeckContext.tsx +11 -3
  90. package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +39 -11
  91. package/corpus/templates/slides/app/pages/Index.tsx +2 -2
  92. package/corpus/templates/slides/changelog/2026-07-30-slide-previews-keep-their-aspect-ratio-isolate-embedded-styl.md +6 -0
  93. package/corpus/templates/slides/changelog/2026-07-30-slides-no-longer-lose-decks-while-organization-access-is-loa.md +6 -0
  94. package/corpus/toolkit/CHANGELOG.md +8 -0
  95. package/corpus/toolkit/package.json +1 -1
  96. package/corpus/toolkit/src/composer/runtime-adapters.tsx +16 -11
  97. package/dist/a2a/activity.d.ts +22 -4
  98. package/dist/a2a/activity.d.ts.map +1 -1
  99. package/dist/a2a/activity.js +97 -11
  100. package/dist/a2a/activity.js.map +1 -1
  101. package/dist/a2a/index.d.ts +1 -1
  102. package/dist/a2a/index.d.ts.map +1 -1
  103. package/dist/a2a/index.js +1 -1
  104. package/dist/a2a/index.js.map +1 -1
  105. package/dist/agent/durable-background.d.ts +13 -8
  106. package/dist/agent/durable-background.d.ts.map +1 -1
  107. package/dist/agent/durable-background.js +36 -28
  108. package/dist/agent/durable-background.js.map +1 -1
  109. package/dist/agent/harness/background.d.ts.map +1 -1
  110. package/dist/agent/harness/background.js +12 -2
  111. package/dist/agent/harness/background.js.map +1 -1
  112. package/dist/agent/production-agent.d.ts.map +1 -1
  113. package/dist/agent/production-agent.js +18 -15
  114. package/dist/agent/production-agent.js.map +1 -1
  115. package/dist/agent/run-store.d.ts +2 -0
  116. package/dist/agent/run-store.d.ts.map +1 -1
  117. package/dist/agent/run-store.js +44 -3
  118. package/dist/agent/run-store.js.map +1 -1
  119. package/dist/application-state/handlers.d.ts +15 -0
  120. package/dist/application-state/handlers.d.ts.map +1 -1
  121. package/dist/application-state/handlers.js +42 -2
  122. package/dist/application-state/handlers.js.map +1 -1
  123. package/dist/application-state/index.d.ts +2 -2
  124. package/dist/application-state/index.d.ts.map +1 -1
  125. package/dist/application-state/index.js +2 -2
  126. package/dist/application-state/index.js.map +1 -1
  127. package/dist/application-state/store.d.ts +11 -0
  128. package/dist/application-state/store.d.ts.map +1 -1
  129. package/dist/application-state/store.js +37 -40
  130. package/dist/application-state/store.js.map +1 -1
  131. package/dist/audit/redact.d.ts +25 -2
  132. package/dist/audit/redact.d.ts.map +1 -1
  133. package/dist/audit/redact.js +85 -21
  134. package/dist/audit/redact.js.map +1 -1
  135. package/dist/cli/create.d.ts +8 -1
  136. package/dist/cli/create.d.ts.map +1 -1
  137. package/dist/cli/create.js +98 -16
  138. package/dist/cli/create.js.map +1 -1
  139. package/dist/client/AgentPanel.d.ts.map +1 -1
  140. package/dist/client/AgentPanel.js +2 -7
  141. package/dist/client/AgentPanel.js.map +1 -1
  142. package/dist/client/AssistantChat.d.ts.map +1 -1
  143. package/dist/client/AssistantChat.js +10 -2
  144. package/dist/client/AssistantChat.js.map +1 -1
  145. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  146. package/dist/client/MultiTabAssistantChat.js +1 -1
  147. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  148. package/dist/client/RunStuckBanner.d.ts +11 -1
  149. package/dist/client/RunStuckBanner.d.ts.map +1 -1
  150. package/dist/client/RunStuckBanner.js +20 -7
  151. package/dist/client/RunStuckBanner.js.map +1 -1
  152. package/dist/client/agent-chat.d.ts.map +1 -1
  153. package/dist/client/agent-chat.js +4 -6
  154. package/dist/client/agent-chat.js.map +1 -1
  155. package/dist/client/application-state.d.ts +11 -0
  156. package/dist/client/application-state.d.ts.map +1 -1
  157. package/dist/client/application-state.js +87 -9
  158. package/dist/client/application-state.js.map +1 -1
  159. package/dist/client/dynamic-suggestions.d.ts.map +1 -1
  160. package/dist/client/dynamic-suggestions.js +4 -13
  161. package/dist/client/dynamic-suggestions.js.map +1 -1
  162. package/dist/client/frame-protocol.d.ts +1 -0
  163. package/dist/client/frame-protocol.d.ts.map +1 -1
  164. package/dist/client/frame-protocol.js.map +1 -1
  165. package/dist/client/guided-questions.d.ts.map +1 -1
  166. package/dist/client/guided-questions.js +6 -22
  167. package/dist/client/guided-questions.js.map +1 -1
  168. package/dist/collab/awareness.d.ts +2 -2
  169. package/dist/collab/awareness.d.ts.map +1 -1
  170. package/dist/collab/routes.d.ts +1 -1
  171. package/dist/db/client.d.ts +57 -10
  172. package/dist/db/client.d.ts.map +1 -1
  173. package/dist/db/client.js +122 -31
  174. package/dist/db/client.js.map +1 -1
  175. package/dist/db/create-get-db.d.ts.map +1 -1
  176. package/dist/db/create-get-db.js +31 -7
  177. package/dist/db/create-get-db.js.map +1 -1
  178. package/dist/db/runtime-diagnostics.d.ts +1 -0
  179. package/dist/db/runtime-diagnostics.d.ts.map +1 -1
  180. package/dist/db/runtime-diagnostics.js +31 -6
  181. package/dist/db/runtime-diagnostics.js.map +1 -1
  182. package/dist/deploy/build.d.ts +5 -20
  183. package/dist/deploy/build.d.ts.map +1 -1
  184. package/dist/deploy/build.js +18 -30
  185. package/dist/deploy/build.js.map +1 -1
  186. package/dist/feature-flags/store.d.ts.map +1 -1
  187. package/dist/feature-flags/store.js +10 -5
  188. package/dist/feature-flags/store.js.map +1 -1
  189. package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
  190. package/dist/integrations/a2a-continuations-store.js +12 -0
  191. package/dist/integrations/a2a-continuations-store.js.map +1 -1
  192. package/dist/integrations/config-store.d.ts +1 -0
  193. package/dist/integrations/config-store.d.ts.map +1 -1
  194. package/dist/integrations/config-store.js +11 -0
  195. package/dist/integrations/config-store.js.map +1 -1
  196. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  197. package/dist/integrations/google-docs-poller.js +19 -2
  198. package/dist/integrations/google-docs-poller.js.map +1 -1
  199. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  200. package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
  201. package/dist/mcp-client/routes.d.ts.map +1 -1
  202. package/dist/mcp-client/routes.js +30 -2
  203. package/dist/mcp-client/routes.js.map +1 -1
  204. package/dist/notifications/routes.d.ts +6 -6
  205. package/dist/onboarding/plugin.d.ts.map +1 -1
  206. package/dist/onboarding/plugin.js +12 -8
  207. package/dist/onboarding/plugin.js.map +1 -1
  208. package/dist/org/accept-pending.d.ts.map +1 -1
  209. package/dist/org/accept-pending.js +2 -0
  210. package/dist/org/accept-pending.js.map +1 -1
  211. package/dist/org/auto-join-domain.d.ts.map +1 -1
  212. package/dist/org/auto-join-domain.js +2 -0
  213. package/dist/org/auto-join-domain.js.map +1 -1
  214. package/dist/org/context.d.ts.map +1 -1
  215. package/dist/org/context.js +29 -9
  216. package/dist/org/context.js.map +1 -1
  217. package/dist/org/handlers.d.ts.map +1 -1
  218. package/dist/org/handlers.js +5 -0
  219. package/dist/org/handlers.js.map +1 -1
  220. package/dist/org/request-org-cache.d.ts +16 -0
  221. package/dist/org/request-org-cache.d.ts.map +1 -0
  222. package/dist/org/request-org-cache.js +62 -0
  223. package/dist/org/request-org-cache.js.map +1 -0
  224. package/dist/progress/routes.d.ts +1 -1
  225. package/dist/resources/handlers.d.ts +1 -1
  226. package/dist/resources/store.d.ts.map +1 -1
  227. package/dist/resources/store.js +11 -9
  228. package/dist/resources/store.js.map +1 -1
  229. package/dist/scripts/runner.d.ts.map +1 -1
  230. package/dist/scripts/runner.js +3 -3
  231. package/dist/scripts/runner.js.map +1 -1
  232. package/dist/secrets/storage.d.ts.map +1 -1
  233. package/dist/secrets/storage.js +82 -5
  234. package/dist/secrets/storage.js.map +1 -1
  235. package/dist/server/action-change.d.ts +20 -0
  236. package/dist/server/action-change.d.ts.map +1 -1
  237. package/dist/server/action-change.js +29 -0
  238. package/dist/server/action-change.js.map +1 -1
  239. package/dist/server/action-routes.d.ts.map +1 -1
  240. package/dist/server/action-routes.js +7 -8
  241. package/dist/server/action-routes.js.map +1 -1
  242. package/dist/server/agent-teams.d.ts.map +1 -1
  243. package/dist/server/agent-teams.js +10 -2
  244. package/dist/server/agent-teams.js.map +1 -1
  245. package/dist/server/better-auth-instance.d.ts.map +1 -1
  246. package/dist/server/better-auth-instance.js +31 -14
  247. package/dist/server/better-auth-instance.js.map +1 -1
  248. package/dist/server/core-routes-plugin.d.ts +1 -0
  249. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  250. package/dist/server/core-routes-plugin.js +18 -4
  251. package/dist/server/core-routes-plugin.js.map +1 -1
  252. package/dist/server/credential-provider.d.ts +16 -0
  253. package/dist/server/credential-provider.d.ts.map +1 -1
  254. package/dist/server/credential-provider.js +49 -13
  255. package/dist/server/credential-provider.js.map +1 -1
  256. package/dist/server/http-response-telemetry.d.ts.map +1 -1
  257. package/dist/server/http-response-telemetry.js +1 -0
  258. package/dist/server/http-response-telemetry.js.map +1 -1
  259. package/dist/server/poll.d.ts +6 -0
  260. package/dist/server/poll.d.ts.map +1 -1
  261. package/dist/server/poll.js +84 -47
  262. package/dist/server/poll.js.map +1 -1
  263. package/dist/server/realtime-token.d.ts +1 -1
  264. package/dist/server/voice-providers-status.d.ts.map +1 -1
  265. package/dist/server/voice-providers-status.js +12 -3
  266. package/dist/server/voice-providers-status.js.map +1 -1
  267. package/dist/workspace-files/tool.d.ts.map +1 -1
  268. package/dist/workspace-files/tool.js +18 -11
  269. package/dist/workspace-files/tool.js.map +1 -1
  270. package/docs/content/durable-background-runs.mdx +15 -6
  271. package/docs/design/durable-agent-runs.md +15 -11
  272. package/package.json +3 -3
  273. package/src/a2a/activity.ts +127 -10
  274. package/src/a2a/index.ts +3 -0
  275. package/src/agent/durable-background.ts +38 -28
  276. package/src/agent/harness/background.ts +12 -2
  277. package/src/agent/production-agent.ts +18 -15
  278. package/src/agent/run-store.ts +45 -3
  279. package/src/application-state/handlers.ts +45 -0
  280. package/src/application-state/index.ts +3 -0
  281. package/src/application-state/store.ts +38 -34
  282. package/src/audit/redact.ts +104 -18
  283. package/src/cli/create.ts +115 -16
  284. package/src/client/AgentPanel.tsx +2 -7
  285. package/src/client/AssistantChat.tsx +10 -2
  286. package/src/client/MultiTabAssistantChat.tsx +3 -0
  287. package/src/client/RunStuckBanner.tsx +29 -6
  288. package/src/client/agent-chat.ts +4 -9
  289. package/src/client/application-state.ts +115 -12
  290. package/src/client/dynamic-suggestions.ts +4 -12
  291. package/src/client/frame-protocol.ts +5 -1
  292. package/src/client/guided-questions.tsx +12 -23
  293. package/src/db/client.ts +148 -28
  294. package/src/db/create-get-db.ts +39 -6
  295. package/src/db/runtime-diagnostics.ts +41 -6
  296. package/src/deploy/build.ts +26 -33
  297. package/src/feature-flags/store.ts +10 -5
  298. package/src/integrations/a2a-continuations-store.ts +11 -0
  299. package/src/integrations/config-store.ts +13 -0
  300. package/src/integrations/google-docs-poller.ts +26 -2
  301. package/src/mcp-client/routes.ts +33 -2
  302. package/src/onboarding/plugin.ts +31 -25
  303. package/src/org/accept-pending.ts +2 -0
  304. package/src/org/auto-join-domain.ts +2 -0
  305. package/src/org/context.ts +35 -10
  306. package/src/org/handlers.ts +6 -0
  307. package/src/org/request-org-cache.ts +71 -0
  308. package/src/resources/store.ts +10 -9
  309. package/src/scripts/runner.ts +6 -3
  310. package/src/secrets/storage.ts +97 -5
  311. package/src/server/action-change.ts +33 -0
  312. package/src/server/action-routes.ts +11 -9
  313. package/src/server/agent-teams.ts +10 -2
  314. package/src/server/better-auth-instance.ts +39 -12
  315. package/src/server/core-routes-plugin.ts +19 -2
  316. package/src/server/credential-provider.ts +57 -14
  317. package/src/server/http-response-telemetry.ts +1 -0
  318. package/src/server/poll.ts +95 -57
  319. package/src/server/voice-providers-status.ts +19 -4
  320. package/src/workspace-files/tool.ts +18 -11
@@ -40,6 +40,16 @@ export interface RunStuckBannerProps {
40
40
  * render; omit to keep the unconditional Retry/Cancel behavior.
41
41
  */
42
42
  hasInFlightWork?: () => boolean;
43
+ /**
44
+ * Returns true when this chat is actually waiting on a reply - typically
45
+ * backed by `chatHandle.isRunning()`. "Stuck" is a claim about THIS client,
46
+ * but the run row is the server's; a turn that finished normally can leave a
47
+ * row in `running` (terminal marking is best-effort, and the stale-run reaper
48
+ * runs later). Without this gate an idle, completed chat shows the warning
49
+ * and auto-retry re-prompts a thread the user considers done. Checked fresh
50
+ * on every render; omit to keep the unconditional behavior.
51
+ */
52
+ isAwaitingResponse?: () => boolean;
43
53
  /**
44
54
  * Called whenever the stuck state transitions. Useful for surfacing
45
55
  * observability events (Sentry, PostHog) at the call site.
@@ -60,5 +70,5 @@ export interface RunStuckBannerProps {
60
70
  /** Extra class on the outer container. */
61
71
  className?: string;
62
72
  }
63
- export declare function RunStuckBanner({ threadId, enabled, apiUrl, stuckThresholdMs, onRetry, onStuckStateChange, autoRetry, autoRetryOwnerId, hasInFlightWork, className, }: RunStuckBannerProps): import("react").JSX.Element | null;
73
+ export declare function RunStuckBanner({ threadId, enabled, apiUrl, stuckThresholdMs, onRetry, onStuckStateChange, autoRetry, autoRetryOwnerId, hasInFlightWork, isAwaitingResponse, className, }: RunStuckBannerProps): import("react").JSX.Element | null;
64
74
  //# sourceMappingURL=RunStuckBanner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RunStuckBanner.d.ts","sourceRoot":"","sources":["../../src/client/RunStuckBanner.tsx"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AAGtC;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC;IAChC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACpD;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2FD,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,OAAc,EACd,MAAM,EACN,gBAAgB,EAChB,OAAO,EACP,kBAAkB,EAClB,SAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,SAAS,GACV,EAAE,mBAAmB,sCAyPrB"}
1
+ {"version":3,"file":"RunStuckBanner.d.ts","sourceRoot":"","sources":["../../src/client/RunStuckBanner.tsx"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AAGtC;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC;IAChC;;;;;;;;OAQG;IACH,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC;IACnC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACpD;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2FD,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,OAAc,EACd,MAAM,EACN,gBAAgB,EAChB,OAAO,EACP,kBAAkB,EAClB,SAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,SAAS,GACV,EAAE,mBAAmB,sCAqQrB"}
@@ -61,7 +61,7 @@ async function claimAutoRetryAttempt(threadId, runId, ownerId) {
61
61
  }
62
62
  return markAutoRetryClaim(key, ownerId);
63
63
  }
64
- export function RunStuckBanner({ threadId, enabled = true, apiUrl, stuckThresholdMs, onRetry, onStuckStateChange, autoRetry = false, autoRetryOwnerId, hasInFlightWork, className, }) {
64
+ export function RunStuckBanner({ threadId, enabled = true, apiUrl, stuckThresholdMs, onRetry, onStuckStateChange, autoRetry = false, autoRetryOwnerId, hasInFlightWork, isAwaitingResponse, className, }) {
65
65
  const state = useRunStuckDetection({
66
66
  threadId,
67
67
  enabled,
@@ -70,6 +70,11 @@ export function RunStuckBanner({ threadId, enabled = true, apiUrl, stuckThreshol
70
70
  });
71
71
  const abortRun = useAbortRun(apiUrl);
72
72
  const [busy, setBusy] = useState({ type: "none" });
73
+ // "An automatic attempt was made for this run" is a different fact from
74
+ // "the controls are locked while a request is in flight". Sharing one flag
75
+ // for both would force the buttons to stay disabled just to keep the
76
+ // message on screen.
77
+ const [autoRetriedRunId, setAutoRetriedRunId] = useState(null);
73
78
  const autoRetriedRunIdsRef = useRef(new Set());
74
79
  const generatedOwnerIdRef = useRef(null);
75
80
  if (!generatedOwnerIdRef.current) {
@@ -93,6 +98,7 @@ export function RunStuckBanner({ threadId, enabled = true, apiUrl, stuckThreshol
93
98
  // work is the failure we guard against, so we err toward "in flight" if
94
99
  // either signal says so.
95
100
  const inFlightWork = state.hasInFlightWork === true || (hasInFlightWork?.() ?? false);
101
+ const awaitingResponse = isAwaitingResponse?.() ?? true;
96
102
  // Server-continued runs are recovered by the SERVER (chained continuation
97
103
  // chunks + lost-handoff sweep); an automatic client abort would kill a live
98
104
  // server-chained run. Auto-retry is therefore disabled unconditionally for
@@ -145,6 +151,9 @@ export function RunStuckBanner({ threadId, enabled = true, apiUrl, stuckThreshol
145
151
  // A live tool/A2A call in flight — never auto-abort real work (see
146
152
  // `inFlightWork` comment above).
147
153
  inFlightWork ||
154
+ // Nothing is waiting on this run here; re-prompting would restart a
155
+ // thread the user already considers finished.
156
+ !awaitingResponse ||
148
157
  !state.isStuck ||
149
158
  !state.runId ||
150
159
  busy.type !== "none" ||
@@ -157,19 +166,21 @@ export function RunStuckBanner({ threadId, enabled = true, apiUrl, stuckThreshol
157
166
  if (!claimed)
158
167
  return;
159
168
  setBusy({ type: "retry", runId });
169
+ setAutoRetriedRunId(runId);
160
170
  trackEvent("agent_chat_stuck_auto_retry", {
161
171
  runId,
162
172
  threadId: threadId ?? null,
163
173
  stuckSinceMs: state.stuckSinceMs ?? null,
164
174
  });
165
175
  void abortRun(runId, "auto_stuck_retry").then((aborted) => {
166
- if (aborted) {
167
- onRetry?.(aborted);
168
- return;
169
- }
176
+ // Release the controls on both outcomes. If the abort does not move
177
+ // the row off `running`, polling may never observe a new run id. The
178
+ // automatic-attempt set still prevents re-entry.
170
179
  setBusy((current) => current.type !== "none" && current.runId === runId
171
180
  ? { type: "none" }
172
181
  : current);
182
+ if (aborted)
183
+ onRetry?.(aborted);
173
184
  });
174
185
  });
175
186
  }, [
@@ -185,6 +196,7 @@ export function RunStuckBanner({ threadId, enabled = true, apiUrl, stuckThreshol
185
196
  state.runId,
186
197
  state.stuckSinceMs,
187
198
  threadId,
199
+ awaitingResponse,
188
200
  ]);
189
201
  // A stale progress timestamp is not actionable while the server is still
190
202
  // heartbeating or an unresolved tool/A2A call is known to be running. Keep
@@ -193,7 +205,8 @@ export function RunStuckBanner({ threadId, enabled = true, apiUrl, stuckThreshol
193
205
  if (!state.isStuck ||
194
206
  !state.runId ||
195
207
  backgroundWorkerStillAlive ||
196
- inFlightWork) {
208
+ inFlightWork ||
209
+ !awaitingResponse) {
197
210
  return null;
198
211
  }
199
212
  const handleCancel = async () => {
@@ -231,7 +244,7 @@ export function RunStuckBanner({ threadId, enabled = true, apiUrl, stuckThreshol
231
244
  };
232
245
  const busyType = busy.type;
233
246
  const stuckSeconds = state.stuckSinceMs != null ? Math.floor(state.stuckSinceMs / 1000) : null;
234
- return (_jsxs("div", { role: "status", "aria-live": "polite", className: cn("mx-3 mt-2 flex items-start gap-2.5 rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2.5 text-xs text-foreground", className), children: [_jsx(IconAlertTriangle, { size: 16, className: "mt-0.5 shrink-0 text-amber-500", "aria-hidden": "true" }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [_jsxs("div", { className: "leading-snug", children: [_jsx("span", { className: "font-medium", children: "This chat looks stuck." }), " ", _jsxs("span", { className: "text-muted-foreground", children: ["No progress", stuckSeconds != null ? ` for ${stuckSeconds}s` : "", ". The agent may have hit a server timeout or lost its connection.", autoRetry && busyType === "retry"
247
+ return (_jsxs("div", { role: "status", "aria-live": "polite", className: cn("mx-3 mt-2 flex items-start gap-2.5 rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2.5 text-xs text-foreground", className), children: [_jsx(IconAlertTriangle, { size: 16, className: "mt-0.5 shrink-0 text-amber-500", "aria-hidden": "true" }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [_jsxs("div", { className: "leading-snug", children: [_jsx("span", { className: "font-medium", children: "This chat looks stuck." }), " ", _jsxs("span", { className: "text-muted-foreground", children: ["No progress", stuckSeconds != null ? ` for ${stuckSeconds}s` : "", ". The agent may have hit a server timeout or lost its connection.", autoRetry && autoRetriedRunId === state.runId
235
248
  ? " Retrying automatically now."
236
249
  : ""] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("button", { type: "button", onClick: handleRetry, disabled: busyType !== "none", className: "inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md bg-foreground px-2.5 text-[11px] font-medium text-background transition-colors hover:bg-foreground/90 disabled:cursor-not-allowed disabled:opacity-60", children: [busyType === "retry" ? (_jsx(IconLoader2, { size: 12, className: "animate-spin", "aria-hidden": "true" })) : null, "Retry"] }), _jsxs("button", { type: "button", onClick: handleCancel, disabled: busyType !== "none", className: "inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[11px] font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-60", children: [busyType === "cancel" ? (_jsx(IconLoader2, { size: 12, className: "animate-spin", "aria-hidden": "true" })) : null, "Cancel"] })] })] })] }));
237
250
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RunStuckBanner.js","sourceRoot":"","sources":["../../src/client/RunStuckBanner.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EACL,oBAAoB,EACpB,WAAW,GAEZ,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAgEhC,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAC9C,MAAM,oCAAoC,GAAG,MAAM,CAAC;AAYpD,SAAS,sBAAsB;IAC7B,MAAM,SAAS,GACb,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU;QACtE,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,IAAI,CAAC;IACX,OAAO,SAAS,EAAE,UAAU,EAAE,IAAI,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;AAC1E,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAgB,EAAE,KAAa;IACxD,OAAO,iCAAiC,QAAQ,IAAI,KAAK,EAAE,CAAC;AAC9D,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAoB;IACnD,OAAO,OAAO,CACZ,KAAK,CAAC,MAAM,KAAK,SAAS;QAC1B,KAAK,CAAC,YAAY,KAAK,uBAAuB;QAC9C,KAAK,CAAC,gBAAgB,IAAI,IAAI;QAC9B,KAAK,CAAC,gBAAgB,IAAI,CAAC;QAC3B,KAAK,CAAC,gBAAgB,GAAG,oCAAoC,CAC9D,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAW,EAAE,OAAe;IACtD,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAG9B,CAAC;YACF,MAAM,SAAS,GACb,OAAO,QAAQ,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YAClE,IAAI,SAAS,GAAG,GAAG,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO;gBAAE,OAAO,KAAK,CAAC;QACpE,CAAC;QACD,MAAM,CAAC,YAAY,CAAC,OAAO,CACzB,GAAG,EACH,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,GAAG,uBAAuB,EAAE,CAAC,CACtE,CAAC;QACF,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAEpE,CAAC;QACF,OAAO,SAAS,CAAC,OAAO,KAAK,OAAO,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;QACvE,oEAAoE;QACpE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,qBAAqB,CAClC,QAAmC,EACnC,KAAa,EACb,OAAe;IAEf,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,MAAM,GAAG,GAAG,iBAAiB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC/C,MAAM,KAAK,GACT,OAAO,SAAS,KAAK,WAAW;QAC9B,CAAC,CAAE,SAAsD,CAAC,KAAK;QAC/D,CAAC,CAAC,SAAS,CAAC;IAChB,IAAI,KAAK,EAAE,OAAO,EAAE,CAAC;QACnB,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,CAAC,OAAO,CACxB,GAAG,EACH,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,EACxC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAC5D,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAC7B,QAAQ,EACR,OAAO,GAAG,IAAI,EACd,MAAM,EACN,gBAAgB,EAChB,OAAO,EACP,kBAAkB,EAClB,SAAS,GAAG,KAAK,EACjB,gBAAgB,EAChB,eAAe,EACf,SAAS,GACW;IACpB,MAAM,KAAK,GAAG,oBAAoB,CAAC;QACjC,QAAQ;QACR,OAAO;QACP,gBAAgB;QAChB,MAAM;KACP,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAY,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9D,MAAM,oBAAoB,GAAG,MAAM,CAAc,IAAI,GAAG,EAAE,CAAC,CAAC;IAC5D,MAAM,mBAAmB,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IACxD,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC;QACjC,mBAAmB,CAAC,OAAO,GAAG,sBAAsB,EAAE,CAAC;IACzD,CAAC;IACD,MAAM,OAAO,GAAG,gBAAgB,IAAI,mBAAmB,CAAC,OAAO,CAAC;IAChE,MAAM,0BAA0B,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAClE,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,4EAA4E;IAC5E,uBAAuB;IACvB,2EAA2E;IAC3E,oEAAoE;IACpE,EAAE;IACF,wEAAwE;IACxE,sEAAsE;IACtE,2EAA2E;IAC3E,wEAAwE;IACxE,2EAA2E;IAC3E,wEAAwE;IACxE,yBAAyB;IACzB,MAAM,YAAY,GAChB,KAAK,CAAC,eAAe,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,IAAI,KAAK,CAAC,CAAC;IACnE,0EAA0E;IAC1E,4EAA4E;IAC5E,2EAA2E;IAC3E,4DAA4D;IAC5D,6EAA6E;IAC7E,6EAA6E;IAC7E,2EAA2E;IAC3E,wBAAwB;IACxB,MAAM,yBAAyB,GAC7B,KAAK,CAAC,YAAY,KAAK,uBAAuB;QAC9C,KAAK,CAAC,YAAY,EAAE,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IAExD,MAAM,eAAe,GAAG,MAAM,CAG3B,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC;QACrC,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK;YAAE,OAAO;QACzE,eAAe,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;QACzE,kBAAkB,EAAE,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACjC,UAAU,CAAC,2BAA2B,EAAE;gBACtC,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,QAAQ,EAAE,QAAQ,IAAI,IAAI;gBAC1B,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,IAAI;gBACxC,aAAa,EACX,KAAK,CAAC,YAAY,IAAI,IAAI;oBACxB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;oBACvC,CAAC,CAAC,IAAI;gBACV,SAAS,EAAE,KAAK,CAAC,MAAM;aACxB,CAAC,CAAC;QACL,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE1C,yEAAyE;IACzE,0EAA0E;IAC1E,gDAAgD;IAChD,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAClB,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,OAAO,CAAC;YAC5C,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;gBAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YACxD,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK;gBAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC1E,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAEhC,SAAS,CAAC,GAAG,EAAE;QACb,IACE,CAAC,SAAS;YACV,wEAAwE;YACxE,+CAA+C;YAC/C,yBAAyB;YACzB,0BAA0B;YAC1B,mEAAmE;YACnE,iCAAiC;YACjC,YAAY;YACZ,CAAC,KAAK,CAAC,OAAO;YACd,CAAC,KAAK,CAAC,KAAK;YACZ,IAAI,CAAC,IAAI,KAAK,MAAM;YACpB,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAC7C,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAC1B,KAAK,qBAAqB,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;YACpE,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO;gBAAE,OAAO;YACrB,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAClC,UAAU,CAAC,6BAA6B,EAAE;gBACxC,KAAK;gBACL,QAAQ,EAAE,QAAQ,IAAI,IAAI;gBAC1B,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,IAAI;aACzC,CAAC,CAAC;YACH,KAAK,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;gBACxD,IAAI,OAAO,EAAE,CAAC;oBACZ,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;oBACnB,OAAO;gBACT,CAAC;gBACD,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAClB,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK;oBAChD,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE;oBAClB,CAAC,CAAC,OAAO,CACZ,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,EAAE;QACD,QAAQ;QACR,SAAS;QACT,0BAA0B;QAC1B,IAAI;QACJ,YAAY;QACZ,yBAAyB;QACzB,OAAO;QACP,OAAO;QACP,KAAK,CAAC,OAAO;QACb,KAAK,CAAC,KAAK;QACX,KAAK,CAAC,YAAY;QAClB,QAAQ;KACT,CAAC,CAAC;IAEH,yEAAyE;IACzE,2EAA2E;IAC3E,0EAA0E;IAC1E,gEAAgE;IAChE,IACE,CAAC,KAAK,CAAC,OAAO;QACd,CAAC,KAAK,CAAC,KAAK;QACZ,0BAA0B;QAC1B,YAAY,EACZ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,KAAK,IAAI,EAAE;QAC9B,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAC1B,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QACnC,UAAU,CAAC,yBAAyB,EAAE;YACpC,KAAK;YACL,QAAQ,EAAE,QAAQ,IAAI,IAAI;YAC1B,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,IAAI;SACzC,CAAC,CAAC;QACH,MAAM,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC7C,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE;QAC7B,sEAAsE;QACtE,wEAAwE;QACxE,0EAA0E;QAC1E,IACE,CAAC,KAAK,CAAC,KAAK;YACZ,IAAI,CAAC,IAAI,KAAK,MAAM;YACpB,0BAA0B;YAC1B,YAAY,EACZ,CAAC;YACD,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAC1B,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAClC,UAAU,CAAC,wBAAwB,EAAE;YACnC,KAAK;YACL,QAAQ,EAAE,QAAQ,IAAI,IAAI;YAC1B,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,IAAI;SACzC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;QAC1D,IAAI,OAAO;YAAE,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;IAE3B,MAAM,YAAY,GAChB,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE5E,OAAO,CACL,eACE,IAAI,EAAC,QAAQ,eACH,QAAQ,EAClB,SAAS,EAAE,EAAE,CACX,8HAA8H,EAC9H,SAAS,CACV,aAED,KAAC,iBAAiB,IAChB,IAAI,EAAE,EAAE,EACR,SAAS,EAAC,gCAAgC,iBAC9B,MAAM,GAClB,EACF,eAAK,SAAS,EAAC,sCAAsC,aACnD,eAAK,SAAS,EAAC,cAAc,aAC3B,eAAM,SAAS,EAAC,aAAa,uCAA8B,EAAC,GAAG,EAC/D,gBAAM,SAAS,EAAC,uBAAuB,4BAEpC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,uEAEnD,SAAS,IAAI,QAAQ,KAAK,OAAO;wCAChC,CAAC,CAAC,8BAA8B;wCAChC,CAAC,CAAC,EAAE,IACD,IACH,EACN,eAAK,SAAS,EAAC,mCAAmC,aAChD,kBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,QAAQ,KAAK,MAAM,EAC7B,SAAS,EAAC,sNAAsN,aAE/N,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CACtB,KAAC,WAAW,IACV,IAAI,EAAE,EAAE,EACR,SAAS,EAAC,cAAc,iBACZ,MAAM,GAClB,CACH,CAAC,CAAC,CAAC,IAAI,aAED,EACT,kBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,QAAQ,KAAK,MAAM,EAC7B,SAAS,EAAC,oOAAoO,aAE7O,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CACvB,KAAC,WAAW,IACV,IAAI,EAAE,EAAE,EACR,SAAS,EAAC,cAAc,iBACZ,MAAM,GAClB,CACH,CAAC,CAAC,CAAC,IAAI,cAED,IACL,IACF,IACF,CACP,CAAC;AACJ,CAAC","sourcesContent":["import { IconAlertTriangle, IconLoader2 } from \"@tabler/icons-react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { trackEvent } from \"./analytics.js\";\nimport {\n useRunStuckDetection,\n useAbortRun,\n type RunStuckState,\n} from \"./use-run-stuck-detection.js\";\nimport { cn } from \"./utils.js\";\n\n/**\n * Surface a user-visible affordance when a chat run hasn't emitted any\n * events for an unusually long time. The adapter's silent reconnect logic\n * keeps trying in the background; this banner is the fallback when those\n * attempts haven't restored progress and the user is staring at a frozen\n * spinner.\n */\nexport interface RunStuckBannerProps {\n /** The thread to monitor. Pass null/undefined to disable. */\n threadId: string | null | undefined;\n /**\n * Set false to skip polling entirely — used when this banner is mounted\n * for a background tab kept alive via display:none. Only the active tab\n * should poll `/runs/active`. Defaults to true.\n */\n enabled?: boolean;\n /** API base path. Default `/_agent-native/agent-chat`. */\n apiUrl?: string;\n /**\n * Threshold above which an in-flight run is considered stuck.\n * Defaults to 90s (after the adapter's 75s no-progress reconnect\n * has had a chance to recover).\n */\n stuckThresholdMs?: number;\n /**\n * Called when the user clicks Retry. Implementations should re-prompt\n * the agent (typically via `chatHandle.sendMessage(...)`) — the banner\n * itself only handles aborting the prior run.\n */\n onRetry?: (runId: string) => void;\n /**\n * Returns true when the run has a tool call or sub-agent (A2A) call that\n * hasn't returned a result yet — typically backed by\n * `chatHandle.hasInFlightWork()`. \"No progress\" for a stretch of time does\n * not mean the run is dead: a long provider query or a cross-app `call\n * agent` can legitimately emit nothing for minutes. When this returns\n * true, the stuck warning is hidden — aborting would destroy real in-flight\n * work and re-execute the same long call from scratch. Checked fresh on every\n * render; omit to keep the unconditional Retry/Cancel behavior.\n */\n hasInFlightWork?: () => boolean;\n /**\n * Called whenever the stuck state transitions. Useful for surfacing\n * observability events (Sentry, PostHog) at the call site.\n */\n onStuckStateChange?: (state: RunStuckState) => void;\n /**\n * Automatically abort and retry once when the server reports a run is\n * alive but has stopped making real progress. Manual controls remain visible\n * as the fallback if the automatic recovery cannot clear the run.\n */\n autoRetry?: boolean;\n /**\n * Stable browser-tab/window id used to coordinate automatic retries across\n * multiple mounted chat views for the same thread. A local id is generated\n * when omitted.\n */\n autoRetryOwnerId?: string;\n /** Extra class on the outer container. */\n className?: string;\n}\n\nconst AUTO_RETRY_CLAIM_TTL_MS = 5 * 60 * 1000;\nconst BACKGROUND_WORKER_FRESH_HEARTBEAT_MS = 30_000;\n\ntype BusyState = { type: \"none\" } | { type: \"cancel\" | \"retry\"; runId: string };\n\ntype MaybeLockManager = {\n request<T>(\n name: string,\n options: { mode?: \"exclusive\" | \"shared\"; ifAvailable?: boolean },\n callback: (lock: unknown) => T | Promise<T>,\n ): Promise<T>;\n};\n\nfunction createAutoRetryOwnerId() {\n const cryptoApi =\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? crypto\n : null;\n return cryptoApi?.randomUUID() ?? `owner-${Math.random().toString(36)}`;\n}\n\nfunction autoRetryClaimKey(threadId: string, runId: string) {\n return `agent-native:stuck-auto-retry:${threadId}:${runId}`;\n}\n\nfunction isFreshBackgroundWorker(state: RunStuckState): boolean {\n return Boolean(\n state.status === \"running\" &&\n state.dispatchMode === \"background-processing\" &&\n state.heartbeatSinceMs != null &&\n state.heartbeatSinceMs >= 0 &&\n state.heartbeatSinceMs < BACKGROUND_WORKER_FRESH_HEARTBEAT_MS,\n );\n}\n\nfunction markAutoRetryClaim(key: string, ownerId: string) {\n if (typeof window === \"undefined\") return true;\n const now = Date.now();\n try {\n const raw = window.localStorage.getItem(key);\n if (raw) {\n const existing = JSON.parse(raw) as {\n ownerId?: unknown;\n expiresAt?: unknown;\n };\n const expiresAt =\n typeof existing.expiresAt === \"number\" ? existing.expiresAt : 0;\n if (expiresAt > now && existing.ownerId !== ownerId) return false;\n }\n window.localStorage.setItem(\n key,\n JSON.stringify({ ownerId, expiresAt: now + AUTO_RETRY_CLAIM_TTL_MS }),\n );\n const confirmed = JSON.parse(window.localStorage.getItem(key) ?? \"{}\") as {\n ownerId?: unknown;\n };\n return confirmed.ownerId === ownerId;\n } catch {\n // Private browsing or disabled storage: fall back to in-tab retry. The\n // server abort is idempotent, and manual controls remain available.\n return true;\n }\n}\n\nasync function claimAutoRetryAttempt(\n threadId: string | null | undefined,\n runId: string,\n ownerId: string,\n) {\n if (!threadId) return true;\n const key = autoRetryClaimKey(threadId, runId);\n const locks =\n typeof navigator !== \"undefined\"\n ? (navigator as Navigator & { locks?: MaybeLockManager }).locks\n : undefined;\n if (locks?.request) {\n try {\n return await locks.request(\n key,\n { mode: \"exclusive\", ifAvailable: true },\n (lock) => (lock ? markAutoRetryClaim(key, ownerId) : false),\n );\n } catch {\n return markAutoRetryClaim(key, ownerId);\n }\n }\n return markAutoRetryClaim(key, ownerId);\n}\n\nexport function RunStuckBanner({\n threadId,\n enabled = true,\n apiUrl,\n stuckThresholdMs,\n onRetry,\n onStuckStateChange,\n autoRetry = false,\n autoRetryOwnerId,\n hasInFlightWork,\n className,\n}: RunStuckBannerProps) {\n const state = useRunStuckDetection({\n threadId,\n enabled,\n stuckThresholdMs,\n apiUrl,\n });\n const abortRun = useAbortRun(apiUrl);\n const [busy, setBusy] = useState<BusyState>({ type: \"none\" });\n const autoRetriedRunIdsRef = useRef<Set<string>>(new Set());\n const generatedOwnerIdRef = useRef<string | null>(null);\n if (!generatedOwnerIdRef.current) {\n generatedOwnerIdRef.current = createAutoRetryOwnerId();\n }\n const ownerId = autoRetryOwnerId ?? generatedOwnerIdRef.current;\n const backgroundWorkerStillAlive = isFreshBackgroundWorker(state);\n // A live tool call or sub-agent (A2A) call means \"no progress\" is not the\n // same as \"dead\" — the process is genuinely still doing the user's work.\n // Retry aborts the run, so the stuck warning stays out of the way while real\n // work is in flight; see the `hasInFlightWork` prop doc comment. Re-checked\n // on every render (the\n // underlying source mutates in place as tool/agent-call events stream in),\n // which is why this is a function prop rather than a plain boolean.\n //\n // Two sources, combined disjunctively (either knowing = in flight): the\n // SERVER-authoritative `state.hasInFlightWork` from /runs/active (the\n // `in_flight_since` marker, correct even when the client's message list is\n // stale after a reconnect/reader-mode replay) and the client-side proxy\n // prop (unresolved tool-call parts in the local messages). Destroying live\n // work is the failure we guard against, so we err toward \"in flight\" if\n // either signal says so.\n const inFlightWork =\n state.hasInFlightWork === true || (hasInFlightWork?.() ?? false);\n // Server-continued runs are recovered by the SERVER (chained continuation\n // chunks + lost-handoff sweep); an automatic client abort would kill a live\n // server-chained run. Auto-retry is therefore disabled unconditionally for\n // these modes — not just a fresh-heartbeat worker — and the\n // localStorage/Web-Locks auto-retry claim below is never taken for them (the\n // adapter's follow loop is read-only, so multiple tabs need no retry dedup).\n // Only the manual banner remains, on the wider server-owned threshold from\n // useRunStuckDetection.\n const isServerContinuedDispatch =\n state.dispatchMode === \"foreground-self-chain\" ||\n state.dispatchMode?.startsWith(\"background\") === true;\n\n const lastReportedRef = useRef<{\n isStuck: boolean;\n runId: string | null;\n }>({ isStuck: false, runId: null });\n useEffect(() => {\n const last = lastReportedRef.current;\n if (last.isStuck === state.isStuck && last.runId === state.runId) return;\n lastReportedRef.current = { isStuck: state.isStuck, runId: state.runId };\n onStuckStateChange?.(state);\n if (state.isStuck && state.runId) {\n trackEvent(\"agent_chat_stuck_detected\", {\n runId: state.runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n stuckSinceSec:\n state.stuckSinceMs != null\n ? Math.floor(state.stuckSinceMs / 1000)\n : null,\n runStatus: state.status,\n });\n }\n }, [state, onStuckStateChange, threadId]);\n\n // Reset the busy spinner once the underlying run is no longer the one we\n // acted on. A recovery continuation can start quickly enough that polling\n // never observes an idle state between run ids.\n useEffect(() => {\n setBusy((current) => {\n if (current.type === \"none\") return current;\n if (state.status !== \"running\") return { type: \"none\" };\n if (state.runId && state.runId !== current.runId) return { type: \"none\" };\n return current;\n });\n }, [state.runId, state.status]);\n\n useEffect(() => {\n if (\n !autoRetry ||\n // Server owns recovery for these dispatch modes — never auto-abort (see\n // comment on isServerContinuedDispatch above).\n isServerContinuedDispatch ||\n backgroundWorkerStillAlive ||\n // A live tool/A2A call in flight — never auto-abort real work (see\n // `inFlightWork` comment above).\n inFlightWork ||\n !state.isStuck ||\n !state.runId ||\n busy.type !== \"none\" ||\n autoRetriedRunIdsRef.current.has(state.runId)\n ) {\n return;\n }\n\n const runId = state.runId;\n void claimAutoRetryAttempt(threadId, runId, ownerId).then((claimed) => {\n autoRetriedRunIdsRef.current.add(runId);\n if (!claimed) return;\n setBusy({ type: \"retry\", runId });\n trackEvent(\"agent_chat_stuck_auto_retry\", {\n runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n });\n void abortRun(runId, \"auto_stuck_retry\").then((aborted) => {\n if (aborted) {\n onRetry?.(aborted);\n return;\n }\n setBusy((current) =>\n current.type !== \"none\" && current.runId === runId\n ? { type: \"none\" }\n : current,\n );\n });\n });\n }, [\n abortRun,\n autoRetry,\n backgroundWorkerStillAlive,\n busy,\n inFlightWork,\n isServerContinuedDispatch,\n onRetry,\n ownerId,\n state.isStuck,\n state.runId,\n state.stuckSinceMs,\n threadId,\n ]);\n\n // A stale progress timestamp is not actionable while the server is still\n // heartbeating or an unresolved tool/A2A call is known to be running. Keep\n // those healthy long-running states in the chat's inline activity UI; the\n // warning is reserved for runs that may actually need recovery.\n if (\n !state.isStuck ||\n !state.runId ||\n backgroundWorkerStillAlive ||\n inFlightWork\n ) {\n return null;\n }\n\n const handleCancel = async () => {\n if (!state.runId || busy.type !== \"none\") return;\n const runId = state.runId;\n setBusy({ type: \"cancel\", runId });\n trackEvent(\"agent_chat_stuck_cancel\", {\n runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n });\n await abortRun(runId, \"user_stuck_cancel\");\n };\n\n const handleRetry = async () => {\n // Defense in depth: the banner is hidden while a background worker is\n // still heartbeating or work is explicitly in flight. Guard the handler\n // too so a render transition cannot abort a run the server says is alive.\n if (\n !state.runId ||\n busy.type !== \"none\" ||\n backgroundWorkerStillAlive ||\n inFlightWork\n ) {\n return;\n }\n const runId = state.runId;\n setBusy({ type: \"retry\", runId });\n trackEvent(\"agent_chat_stuck_retry\", {\n runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n });\n const aborted = await abortRun(runId, \"user_stuck_retry\");\n if (aborted) onRetry?.(aborted);\n };\n\n const busyType = busy.type;\n\n const stuckSeconds =\n state.stuckSinceMs != null ? Math.floor(state.stuckSinceMs / 1000) : null;\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"mx-3 mt-2 flex items-start gap-2.5 rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2.5 text-xs text-foreground\",\n className,\n )}\n >\n <IconAlertTriangle\n size={16}\n className=\"mt-0.5 shrink-0 text-amber-500\"\n aria-hidden=\"true\"\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <div className=\"leading-snug\">\n <span className=\"font-medium\">This chat looks stuck.</span>{\" \"}\n <span className=\"text-muted-foreground\">\n No progress\n {stuckSeconds != null ? ` for ${stuckSeconds}s` : \"\"}. The agent may\n have hit a server timeout or lost its connection.\n {autoRetry && busyType === \"retry\"\n ? \" Retrying automatically now.\"\n : \"\"}\n </span>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={handleRetry}\n disabled={busyType !== \"none\"}\n className=\"inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md bg-foreground px-2.5 text-[11px] font-medium text-background transition-colors hover:bg-foreground/90 disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {busyType === \"retry\" ? (\n <IconLoader2\n size={12}\n className=\"animate-spin\"\n aria-hidden=\"true\"\n />\n ) : null}\n Retry\n </button>\n <button\n type=\"button\"\n onClick={handleCancel}\n disabled={busyType !== \"none\"}\n className=\"inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[11px] font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {busyType === \"cancel\" ? (\n <IconLoader2\n size={12}\n className=\"animate-spin\"\n aria-hidden=\"true\"\n />\n ) : null}\n Cancel\n </button>\n </div>\n </div>\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"RunStuckBanner.js","sourceRoot":"","sources":["../../src/client/RunStuckBanner.tsx"],"names":[],"mappings":"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","sourcesContent":["import { IconAlertTriangle, IconLoader2 } from \"@tabler/icons-react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { trackEvent } from \"./analytics.js\";\nimport {\n useRunStuckDetection,\n useAbortRun,\n type RunStuckState,\n} from \"./use-run-stuck-detection.js\";\nimport { cn } from \"./utils.js\";\n\n/**\n * Surface a user-visible affordance when a chat run hasn't emitted any\n * events for an unusually long time. The adapter's silent reconnect logic\n * keeps trying in the background; this banner is the fallback when those\n * attempts haven't restored progress and the user is staring at a frozen\n * spinner.\n */\nexport interface RunStuckBannerProps {\n /** The thread to monitor. Pass null/undefined to disable. */\n threadId: string | null | undefined;\n /**\n * Set false to skip polling entirely — used when this banner is mounted\n * for a background tab kept alive via display:none. Only the active tab\n * should poll `/runs/active`. Defaults to true.\n */\n enabled?: boolean;\n /** API base path. Default `/_agent-native/agent-chat`. */\n apiUrl?: string;\n /**\n * Threshold above which an in-flight run is considered stuck.\n * Defaults to 90s (after the adapter's 75s no-progress reconnect\n * has had a chance to recover).\n */\n stuckThresholdMs?: number;\n /**\n * Called when the user clicks Retry. Implementations should re-prompt\n * the agent (typically via `chatHandle.sendMessage(...)`) — the banner\n * itself only handles aborting the prior run.\n */\n onRetry?: (runId: string) => void;\n /**\n * Returns true when the run has a tool call or sub-agent (A2A) call that\n * hasn't returned a result yet — typically backed by\n * `chatHandle.hasInFlightWork()`. \"No progress\" for a stretch of time does\n * not mean the run is dead: a long provider query or a cross-app `call\n * agent` can legitimately emit nothing for minutes. When this returns\n * true, the stuck warning is hidden — aborting would destroy real in-flight\n * work and re-execute the same long call from scratch. Checked fresh on every\n * render; omit to keep the unconditional Retry/Cancel behavior.\n */\n hasInFlightWork?: () => boolean;\n /**\n * Returns true when this chat is actually waiting on a reply - typically\n * backed by `chatHandle.isRunning()`. \"Stuck\" is a claim about THIS client,\n * but the run row is the server's; a turn that finished normally can leave a\n * row in `running` (terminal marking is best-effort, and the stale-run reaper\n * runs later). Without this gate an idle, completed chat shows the warning\n * and auto-retry re-prompts a thread the user considers done. Checked fresh\n * on every render; omit to keep the unconditional behavior.\n */\n isAwaitingResponse?: () => boolean;\n /**\n * Called whenever the stuck state transitions. Useful for surfacing\n * observability events (Sentry, PostHog) at the call site.\n */\n onStuckStateChange?: (state: RunStuckState) => void;\n /**\n * Automatically abort and retry once when the server reports a run is\n * alive but has stopped making real progress. Manual controls remain visible\n * as the fallback if the automatic recovery cannot clear the run.\n */\n autoRetry?: boolean;\n /**\n * Stable browser-tab/window id used to coordinate automatic retries across\n * multiple mounted chat views for the same thread. A local id is generated\n * when omitted.\n */\n autoRetryOwnerId?: string;\n /** Extra class on the outer container. */\n className?: string;\n}\n\nconst AUTO_RETRY_CLAIM_TTL_MS = 5 * 60 * 1000;\nconst BACKGROUND_WORKER_FRESH_HEARTBEAT_MS = 30_000;\n\ntype BusyState = { type: \"none\" } | { type: \"cancel\" | \"retry\"; runId: string };\n\ntype MaybeLockManager = {\n request<T>(\n name: string,\n options: { mode?: \"exclusive\" | \"shared\"; ifAvailable?: boolean },\n callback: (lock: unknown) => T | Promise<T>,\n ): Promise<T>;\n};\n\nfunction createAutoRetryOwnerId() {\n const cryptoApi =\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? crypto\n : null;\n return cryptoApi?.randomUUID() ?? `owner-${Math.random().toString(36)}`;\n}\n\nfunction autoRetryClaimKey(threadId: string, runId: string) {\n return `agent-native:stuck-auto-retry:${threadId}:${runId}`;\n}\n\nfunction isFreshBackgroundWorker(state: RunStuckState): boolean {\n return Boolean(\n state.status === \"running\" &&\n state.dispatchMode === \"background-processing\" &&\n state.heartbeatSinceMs != null &&\n state.heartbeatSinceMs >= 0 &&\n state.heartbeatSinceMs < BACKGROUND_WORKER_FRESH_HEARTBEAT_MS,\n );\n}\n\nfunction markAutoRetryClaim(key: string, ownerId: string) {\n if (typeof window === \"undefined\") return true;\n const now = Date.now();\n try {\n const raw = window.localStorage.getItem(key);\n if (raw) {\n const existing = JSON.parse(raw) as {\n ownerId?: unknown;\n expiresAt?: unknown;\n };\n const expiresAt =\n typeof existing.expiresAt === \"number\" ? existing.expiresAt : 0;\n if (expiresAt > now && existing.ownerId !== ownerId) return false;\n }\n window.localStorage.setItem(\n key,\n JSON.stringify({ ownerId, expiresAt: now + AUTO_RETRY_CLAIM_TTL_MS }),\n );\n const confirmed = JSON.parse(window.localStorage.getItem(key) ?? \"{}\") as {\n ownerId?: unknown;\n };\n return confirmed.ownerId === ownerId;\n } catch {\n // Private browsing or disabled storage: fall back to in-tab retry. The\n // server abort is idempotent, and manual controls remain available.\n return true;\n }\n}\n\nasync function claimAutoRetryAttempt(\n threadId: string | null | undefined,\n runId: string,\n ownerId: string,\n) {\n if (!threadId) return true;\n const key = autoRetryClaimKey(threadId, runId);\n const locks =\n typeof navigator !== \"undefined\"\n ? (navigator as Navigator & { locks?: MaybeLockManager }).locks\n : undefined;\n if (locks?.request) {\n try {\n return await locks.request(\n key,\n { mode: \"exclusive\", ifAvailable: true },\n (lock) => (lock ? markAutoRetryClaim(key, ownerId) : false),\n );\n } catch {\n return markAutoRetryClaim(key, ownerId);\n }\n }\n return markAutoRetryClaim(key, ownerId);\n}\n\nexport function RunStuckBanner({\n threadId,\n enabled = true,\n apiUrl,\n stuckThresholdMs,\n onRetry,\n onStuckStateChange,\n autoRetry = false,\n autoRetryOwnerId,\n hasInFlightWork,\n isAwaitingResponse,\n className,\n}: RunStuckBannerProps) {\n const state = useRunStuckDetection({\n threadId,\n enabled,\n stuckThresholdMs,\n apiUrl,\n });\n const abortRun = useAbortRun(apiUrl);\n const [busy, setBusy] = useState<BusyState>({ type: \"none\" });\n // \"An automatic attempt was made for this run\" is a different fact from\n // \"the controls are locked while a request is in flight\". Sharing one flag\n // for both would force the buttons to stay disabled just to keep the\n // message on screen.\n const [autoRetriedRunId, setAutoRetriedRunId] = useState<string | null>(null);\n const autoRetriedRunIdsRef = useRef<Set<string>>(new Set());\n const generatedOwnerIdRef = useRef<string | null>(null);\n if (!generatedOwnerIdRef.current) {\n generatedOwnerIdRef.current = createAutoRetryOwnerId();\n }\n const ownerId = autoRetryOwnerId ?? generatedOwnerIdRef.current;\n const backgroundWorkerStillAlive = isFreshBackgroundWorker(state);\n // A live tool call or sub-agent (A2A) call means \"no progress\" is not the\n // same as \"dead\" — the process is genuinely still doing the user's work.\n // Retry aborts the run, so the stuck warning stays out of the way while real\n // work is in flight; see the `hasInFlightWork` prop doc comment. Re-checked\n // on every render (the\n // underlying source mutates in place as tool/agent-call events stream in),\n // which is why this is a function prop rather than a plain boolean.\n //\n // Two sources, combined disjunctively (either knowing = in flight): the\n // SERVER-authoritative `state.hasInFlightWork` from /runs/active (the\n // `in_flight_since` marker, correct even when the client's message list is\n // stale after a reconnect/reader-mode replay) and the client-side proxy\n // prop (unresolved tool-call parts in the local messages). Destroying live\n // work is the failure we guard against, so we err toward \"in flight\" if\n // either signal says so.\n const inFlightWork =\n state.hasInFlightWork === true || (hasInFlightWork?.() ?? false);\n const awaitingResponse = isAwaitingResponse?.() ?? true;\n // Server-continued runs are recovered by the SERVER (chained continuation\n // chunks + lost-handoff sweep); an automatic client abort would kill a live\n // server-chained run. Auto-retry is therefore disabled unconditionally for\n // these modes — not just a fresh-heartbeat worker — and the\n // localStorage/Web-Locks auto-retry claim below is never taken for them (the\n // adapter's follow loop is read-only, so multiple tabs need no retry dedup).\n // Only the manual banner remains, on the wider server-owned threshold from\n // useRunStuckDetection.\n const isServerContinuedDispatch =\n state.dispatchMode === \"foreground-self-chain\" ||\n state.dispatchMode?.startsWith(\"background\") === true;\n\n const lastReportedRef = useRef<{\n isStuck: boolean;\n runId: string | null;\n }>({ isStuck: false, runId: null });\n useEffect(() => {\n const last = lastReportedRef.current;\n if (last.isStuck === state.isStuck && last.runId === state.runId) return;\n lastReportedRef.current = { isStuck: state.isStuck, runId: state.runId };\n onStuckStateChange?.(state);\n if (state.isStuck && state.runId) {\n trackEvent(\"agent_chat_stuck_detected\", {\n runId: state.runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n stuckSinceSec:\n state.stuckSinceMs != null\n ? Math.floor(state.stuckSinceMs / 1000)\n : null,\n runStatus: state.status,\n });\n }\n }, [state, onStuckStateChange, threadId]);\n\n // Reset the busy spinner once the underlying run is no longer the one we\n // acted on. A recovery continuation can start quickly enough that polling\n // never observes an idle state between run ids.\n useEffect(() => {\n setBusy((current) => {\n if (current.type === \"none\") return current;\n if (state.status !== \"running\") return { type: \"none\" };\n if (state.runId && state.runId !== current.runId) return { type: \"none\" };\n return current;\n });\n }, [state.runId, state.status]);\n\n useEffect(() => {\n if (\n !autoRetry ||\n // Server owns recovery for these dispatch modes — never auto-abort (see\n // comment on isServerContinuedDispatch above).\n isServerContinuedDispatch ||\n backgroundWorkerStillAlive ||\n // A live tool/A2A call in flight — never auto-abort real work (see\n // `inFlightWork` comment above).\n inFlightWork ||\n // Nothing is waiting on this run here; re-prompting would restart a\n // thread the user already considers finished.\n !awaitingResponse ||\n !state.isStuck ||\n !state.runId ||\n busy.type !== \"none\" ||\n autoRetriedRunIdsRef.current.has(state.runId)\n ) {\n return;\n }\n\n const runId = state.runId;\n void claimAutoRetryAttempt(threadId, runId, ownerId).then((claimed) => {\n autoRetriedRunIdsRef.current.add(runId);\n if (!claimed) return;\n setBusy({ type: \"retry\", runId });\n setAutoRetriedRunId(runId);\n trackEvent(\"agent_chat_stuck_auto_retry\", {\n runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n });\n void abortRun(runId, \"auto_stuck_retry\").then((aborted) => {\n // Release the controls on both outcomes. If the abort does not move\n // the row off `running`, polling may never observe a new run id. The\n // automatic-attempt set still prevents re-entry.\n setBusy((current) =>\n current.type !== \"none\" && current.runId === runId\n ? { type: \"none\" }\n : current,\n );\n if (aborted) onRetry?.(aborted);\n });\n });\n }, [\n abortRun,\n autoRetry,\n backgroundWorkerStillAlive,\n busy,\n inFlightWork,\n isServerContinuedDispatch,\n onRetry,\n ownerId,\n state.isStuck,\n state.runId,\n state.stuckSinceMs,\n threadId,\n awaitingResponse,\n ]);\n\n // A stale progress timestamp is not actionable while the server is still\n // heartbeating or an unresolved tool/A2A call is known to be running. Keep\n // those healthy long-running states in the chat's inline activity UI; the\n // warning is reserved for runs that may actually need recovery.\n if (\n !state.isStuck ||\n !state.runId ||\n backgroundWorkerStillAlive ||\n inFlightWork ||\n !awaitingResponse\n ) {\n return null;\n }\n\n const handleCancel = async () => {\n if (!state.runId || busy.type !== \"none\") return;\n const runId = state.runId;\n setBusy({ type: \"cancel\", runId });\n trackEvent(\"agent_chat_stuck_cancel\", {\n runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n });\n await abortRun(runId, \"user_stuck_cancel\");\n };\n\n const handleRetry = async () => {\n // Defense in depth: the banner is hidden while a background worker is\n // still heartbeating or work is explicitly in flight. Guard the handler\n // too so a render transition cannot abort a run the server says is alive.\n if (\n !state.runId ||\n busy.type !== \"none\" ||\n backgroundWorkerStillAlive ||\n inFlightWork\n ) {\n return;\n }\n const runId = state.runId;\n setBusy({ type: \"retry\", runId });\n trackEvent(\"agent_chat_stuck_retry\", {\n runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n });\n const aborted = await abortRun(runId, \"user_stuck_retry\");\n if (aborted) onRetry?.(aborted);\n };\n\n const busyType = busy.type;\n\n const stuckSeconds =\n state.stuckSinceMs != null ? Math.floor(state.stuckSinceMs / 1000) : null;\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"mx-3 mt-2 flex items-start gap-2.5 rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2.5 text-xs text-foreground\",\n className,\n )}\n >\n <IconAlertTriangle\n size={16}\n className=\"mt-0.5 shrink-0 text-amber-500\"\n aria-hidden=\"true\"\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <div className=\"leading-snug\">\n <span className=\"font-medium\">This chat looks stuck.</span>{\" \"}\n <span className=\"text-muted-foreground\">\n No progress\n {stuckSeconds != null ? ` for ${stuckSeconds}s` : \"\"}. The agent may\n have hit a server timeout or lost its connection.\n {autoRetry && autoRetriedRunId === state.runId\n ? \" Retrying automatically now.\"\n : \"\"}\n </span>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={handleRetry}\n disabled={busyType !== \"none\"}\n className=\"inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md bg-foreground px-2.5 text-[11px] font-medium text-background transition-colors hover:bg-foreground/90 disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {busyType === \"retry\" ? (\n <IconLoader2\n size={12}\n className=\"animate-spin\"\n aria-hidden=\"true\"\n />\n ) : null}\n Retry\n </button>\n <button\n type=\"button\"\n onClick={handleCancel}\n disabled={busyType !== \"none\"}\n className=\"inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[11px] font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {busyType === \"cancel\" ? (\n <IconLoader2\n size={12}\n className=\"animate-spin\"\n aria-hidden=\"true\"\n />\n ) : null}\n Cancel\n </button>\n </div>\n </div>\n </div>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"agent-chat.d.ts","sourceRoot":"","sources":["../../src/client/agent-chat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-chat.d.ts","sourceRoot":"","sources":["../../src/client/agent-chat.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@
7
7
  * stay inside the embedded app so its own AgentSidebar can receive them.
8
8
  */
9
9
  import { agentNativePath } from "./api-path.js";
10
+ import { readClientAppState } from "./application-state.js";
10
11
  import { isInBuilderFrame, isTrustedBuilderMessage, sendToBuilderChat, } from "./builder-frame.js";
11
12
  import { isEmbedAuthActive, isEmbedMcpChatBridgeActive, markEmbedMcpChatBridgeActive, readEmbedMcpChatBridgeFlagFromUrl, } from "./embed-auth.js";
12
13
  import { getFramePostMessageTargetOrigin, isTrustedFrameMessage, } from "./frame.js";
@@ -306,13 +307,10 @@ export async function refreshAgentChatContext() {
306
307
  return agentChatContextState;
307
308
  }
308
309
  try {
309
- const res = await fetch(agentNativePath(`/_agent-native/application-state/${AGENT_CHAT_CONTEXT_STATE_KEY}`));
310
- if (!res.ok || res.status === 204)
310
+ const raw = await readClientAppState(AGENT_CHAT_CONTEXT_STATE_KEY);
311
+ if (raw === null)
311
312
  return agentChatContextState;
312
- const text = await res.text();
313
- if (!text)
314
- return agentChatContextState;
315
- const state = normalizeAgentChatContextState(JSON.parse(text));
313
+ const state = normalizeAgentChatContextState(raw);
316
314
  if (!state)
317
315
  return agentChatContextState;
318
316
  return publishAgentChatContextItems(state.items, {