@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
@@ -6,6 +6,7 @@ import {
6
6
  useRef,
7
7
  useLayoutEffect,
8
8
  useCallback,
9
+ useId,
9
10
  type ReactNode,
10
11
  } from "react";
11
12
  import ReactMarkdown from "react-markdown";
@@ -477,6 +478,8 @@ function AutoFitContent({
477
478
 
478
479
  /** Renders blank slide HTML content and applies white filter to logo images */
479
480
  function BlankSlideContent({ content }: { content: string }) {
481
+ const scopeId = `slide-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
482
+ const scopeSelector = `[data-slide-content-scope="${scopeId}"]`;
480
483
  // Memoize derived strings + the dangerouslySetInnerHTML object on `content` so
481
484
  // the prop value has a stable reference across re-renders. React 19 only checks
482
485
  // reference equality on `dangerouslySetInnerHTML` and unconditionally re-assigns
@@ -505,6 +508,7 @@ function BlankSlideContent({ content }: { content: string }) {
505
508
  return before + ' style="filter:brightness(0) invert(1);"' + close;
506
509
  },
507
510
  ),
511
+ { scopeSelector },
508
512
  );
509
513
 
510
514
  return {
@@ -516,7 +520,10 @@ function BlankSlideContent({ content }: { content: string }) {
516
520
 
517
521
  if (mermaidBlocks.length > 0) {
518
522
  return (
519
- <div className="slide-content text-white/90 w-full block h-full">
523
+ <div
524
+ className="slide-content text-white/90 w-full block h-full"
525
+ data-slide-content-scope={scopeId}
526
+ >
520
527
  <MermaidHtmlContent
521
528
  html={htmlWithPlaceholders}
522
529
  mermaidBlocks={mermaidBlocks}
@@ -528,6 +535,7 @@ function BlankSlideContent({ content }: { content: string }) {
528
535
  return (
529
536
  <div
530
537
  className="slide-content text-white/90 w-full block h-full"
538
+ data-slide-content-scope={scopeId}
531
539
  dangerouslySetInnerHTML={dangerousHtml}
532
540
  />
533
541
  );
@@ -143,7 +143,7 @@ export function Layout({ children }: LayoutProps) {
143
143
  }
144
144
  />
145
145
  </div>
146
- <div className="agent-layout-main-surface flex h-full flex-1 flex-col overflow-hidden">
146
+ <div className="agent-layout-main-surface flex h-full min-w-0 flex-1 flex-col overflow-hidden">
147
147
  {/* Mobile-only nav strip with hamburger — only when there's no page toolbar */}
148
148
  {!ownToolbar && (
149
149
  <div className="flex h-12 items-center border-b border-border px-4 md:hidden shrink-0">
@@ -1029,7 +1029,7 @@ export const defaultSlideContent: Record<SlideLayout, string> = {
1029
1029
  };
1030
1030
 
1031
1031
  export function DeckProvider({ children }: { children: ReactNode }) {
1032
- const { data: org } = useOrg();
1032
+ const { data: org, isLoading: orgLoading } = useOrg();
1033
1033
  const [decks, setDecks] = useState<Deck[]>([]);
1034
1034
  const [loading, setLoading] = useState(true);
1035
1035
  const [loadError, setLoadError] = useState(false);
@@ -1362,6 +1362,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1362
1362
  const requestId = ++deckBaselineRequestIdRef.current;
1363
1363
  const createSeqAtRequest = localCreateSeqRef.current;
1364
1364
  const requestedOpenDeckId = currentOpenDeckIdFromWindow();
1365
+ setLoading(true);
1365
1366
  const loaded = await fetchDecksForCurrentRoute();
1366
1367
  if (
1367
1368
  requestId !== deckBaselineRequestIdRef.current ||
@@ -1371,11 +1372,13 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1371
1372
  }
1372
1373
  if (loaded === null) {
1373
1374
  setLoadError(true);
1375
+ setLoading(false);
1374
1376
  return "failed";
1375
1377
  }
1376
1378
  lastExternalUpdateRef.current = Date.now();
1377
1379
  resetDeckBaseline(loaded, createSeqAtRequest);
1378
1380
  setLoadError(false);
1381
+ setLoading(false);
1379
1382
  return "loaded";
1380
1383
  }, [resetDeckBaseline]);
1381
1384
 
@@ -1385,6 +1388,10 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1385
1388
 
1386
1389
  // Load decks from API on mount
1387
1390
  useEffect(() => {
1391
+ // The deck query is scoped by the active organization on the server. Do
1392
+ // not turn the pre-scope empty response into the app's authoritative empty
1393
+ // state while the org query is still hydrating.
1394
+ if (orgLoading) return;
1388
1395
  const requestId = ++deckBaselineRequestIdRef.current;
1389
1396
  const createSeqAtRequest = localCreateSeqRef.current;
1390
1397
  const requestedOpenDeckId = currentOpenDeckIdFromWindow();
@@ -1405,7 +1412,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1405
1412
  setLoadError(loaded === null);
1406
1413
  setLoading(false);
1407
1414
  });
1408
- }, [resetDeckBaseline]);
1415
+ }, [orgLoading, resetDeckBaseline]);
1409
1416
 
1410
1417
  // Switching orgs re-scopes list-decks server-side but leaves this context's
1411
1418
  // in-memory list untouched, so the previous org's decks linger. Reload when
@@ -1413,6 +1420,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1413
1420
  // up on the mount fetch above.
1414
1421
  const lastOrgIdRef = useRef<string | null | undefined>(undefined);
1415
1422
  useEffect(() => {
1423
+ if (orgLoading) return;
1416
1424
  const orgId = org?.orgId ?? null;
1417
1425
  if (lastOrgIdRef.current === undefined) {
1418
1426
  lastOrgIdRef.current = orgId;
@@ -1421,7 +1429,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1421
1429
  if (lastOrgIdRef.current === orgId) return;
1422
1430
  lastOrgIdRef.current = orgId;
1423
1431
  void reloadDecks();
1424
- }, [org?.orgId, reloadDecks]);
1432
+ }, [org?.orgId, orgLoading, reloadDecks]);
1425
1433
 
1426
1434
  // Fallback polling for deck list + open-deck changes. SSE is the primary
1427
1435
  // path; this catches agent/db writes that bypass it without hammering idle
@@ -197,16 +197,40 @@ function sanitizeStyle(style: string): string {
197
197
  .join("; ");
198
198
  }
199
199
 
200
- function sanitizeStyleSheet(css: string): string {
200
+ function scopeCssSelector(selector: string, scopeSelector?: string): string {
201
+ const trimmed = selector.trim();
202
+ if (!scopeSelector || !trimmed || trimmed.startsWith("@")) return trimmed;
203
+
204
+ return trimmed
205
+ .split(",")
206
+ .map((part) => {
207
+ const item = part.trim();
208
+ if (!item) return "";
209
+ if (item === "*") return `${scopeSelector}, ${scopeSelector} *`;
210
+ if (/^(?:html|body|:root)\b/i.test(item)) {
211
+ return item.replace(/^(?:html|body|:root)\b/i, scopeSelector);
212
+ }
213
+ return `${scopeSelector} ${item}`;
214
+ })
215
+ .filter(Boolean)
216
+ .join(", ");
217
+ }
218
+
219
+ function sanitizeStyleSheet(css: string, scopeSelector?: string): string {
201
220
  return css
202
221
  .replace(/@import[^;]+;?/gi, "")
203
222
  .replace(/([^{}]+)\{([^{}]*)\}/g, (_match, selector, body) => {
204
223
  const safeBody = sanitizeStyle(String(body));
205
- return safeBody ? `${String(selector).trim()} { ${safeBody}; }` : "";
224
+ const safeSelector = scopeCssSelector(String(selector), scopeSelector);
225
+ return safeBody && safeSelector ? `${safeSelector} { ${safeBody}; }` : "";
206
226
  });
207
227
  }
208
228
 
209
- function cleanNode(node: Node, doc: Document): Node | null {
229
+ function cleanNode(
230
+ node: Node,
231
+ doc: Document,
232
+ scopeSelector?: string,
233
+ ): Node | null {
210
234
  if (node.nodeType === Node.TEXT_NODE) {
211
235
  return doc.createTextNode(node.textContent ?? "");
212
236
  }
@@ -218,7 +242,7 @@ function cleanNode(node: Node, doc: Document): Node | null {
218
242
  if (DROP_WITH_CHILDREN.has(tag)) return null;
219
243
 
220
244
  if (tag === "style") {
221
- const safeCss = sanitizeStyleSheet(el.textContent ?? "");
245
+ const safeCss = sanitizeStyleSheet(el.textContent ?? "", scopeSelector);
222
246
  if (!safeCss.trim()) return null;
223
247
  const out = doc.createElement("style");
224
248
  out.textContent = safeCss;
@@ -268,17 +292,17 @@ function cleanNode(node: Node, doc: Document): Node | null {
268
292
  }
269
293
 
270
294
  for (const child of Array.from(el.childNodes)) {
271
- const cleaned = cleanNode(child, doc);
295
+ const cleaned = cleanNode(child, doc, scopeSelector);
272
296
  if (cleaned) out.appendChild(cleaned);
273
297
  }
274
298
 
275
299
  return out;
276
300
  }
277
301
 
278
- function sanitizeHtmlString(html: string): string {
302
+ function sanitizeHtmlString(html: string, scopeSelector?: string): string {
279
303
  return html
280
304
  .replace(/<style\b[^>]*>([\s\S]*?)<\/style>/gi, (_match, css) => {
281
- const safeCss = sanitizeStyleSheet(String(css));
305
+ const safeCss = sanitizeStyleSheet(String(css), scopeSelector);
282
306
  return safeCss
283
307
  ? `<style>${safeCss.replace(/<\/style/gi, "<\\/style")}</style>`
284
308
  : "";
@@ -314,19 +338,23 @@ function sanitizeHtmlString(html: string): string {
314
338
  );
315
339
  }
316
340
 
317
- export function sanitizeSlideHtml(html: string): string {
341
+ export function sanitizeSlideHtml(
342
+ html: string,
343
+ options?: { scopeSelector?: string },
344
+ ): string {
345
+ const scopeSelector = options?.scopeSelector;
318
346
  if (typeof DOMParser === "undefined") {
319
- return sanitizeHtmlString(html);
347
+ return sanitizeHtmlString(html, scopeSelector);
320
348
  }
321
349
 
322
350
  const doc = new DOMParser().parseFromString(html, "text/html");
323
351
  const fragment = doc.createDocumentFragment();
324
352
  for (const style of Array.from(doc.head.querySelectorAll("style"))) {
325
- const cleaned = cleanNode(style, doc);
353
+ const cleaned = cleanNode(style, doc, scopeSelector);
326
354
  if (cleaned) fragment.appendChild(cleaned);
327
355
  }
328
356
  for (const child of Array.from(doc.body.childNodes)) {
329
- const cleaned = cleanNode(child, doc);
357
+ const cleaned = cleanNode(child, doc, scopeSelector);
330
358
  if (cleaned) fragment.appendChild(cleaned);
331
359
  }
332
360
 
@@ -597,7 +597,7 @@ export default function Index() {
597
597
  "Start a `manage-progress` run so progress appears in the app header. Add the first slide as soon as it is ready, then continue one slide at a time so the editor visibly fills in.",
598
598
  "After reading any requested or imported source material, but before adding the first slide, choose a concise, specific deck title from the user's request and source material. Call `patch-deck` with `deckId: \"" +
599
599
  deckId +
600
- '"` and `operations: [{ "op": "patch-deck-fields", "fields": { "title": "<generated title>" } }]`. Never leave a generated deck named "Untitled Deck" or another placeholder.',
600
+ '"` and `operations: [{ "op": "patch-deck-fields", "fields": { "title": "<generated title>" } }]`. Include only `title` in `fields`; omit all other optional fields. Never leave a generated deck named "Untitled Deck" or another placeholder.',
601
601
  "If the user asks for a standalone visual, diagram, hero, one-pager, poster, or a couple of visuals, create only the requested one/few polished visual slides. Do not pad the result into a full presentation.",
602
602
  "Add slides ONE AT A TIME using the `add-slide` action with --deckId=" +
603
603
  deckId +
@@ -746,7 +746,7 @@ export default function Index() {
746
746
  );
747
747
 
748
748
  return (
749
- <main className="flex-1 overflow-y-auto px-4 sm:px-6 py-6 sm:py-10">
749
+ <main className="min-w-0 flex-1 overflow-y-auto px-4 py-6 sm:px-6 sm:py-10">
750
750
  {loading ? (
751
751
  <>
752
752
  <div className="flex items-center justify-end mb-4">
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-30
4
+ ---
5
+
6
+ Slide previews keep their aspect ratio, isolate embedded styles, and remain usable at narrow widths
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-30
4
+ ---
5
+
6
+ Slides no longer lose decks while organization access is loading
@@ -1,5 +1,13 @@
1
1
  # @agent-native/toolkit
2
2
 
3
+ ## 0.12.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 89e5910: Memoize the composer runtime adapters context value so consumer effects stop
8
+ re-running on every provider render. The voice input preference was re-read from
9
+ app state, and the sidebar-state listener re-subscribed, once per render.
10
+
3
11
  ## 0.12.0
4
12
 
5
13
  ### Minor Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/toolkit",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Reusable app-building UI and helpers for Agent-Native apps.",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  createContext,
3
3
  useContext,
4
+ useMemo,
4
5
  type ComponentType,
5
6
  type ReactNode,
6
7
  } from "react";
@@ -251,18 +252,22 @@ export function ComposerRuntimeAdaptersProvider({
251
252
  adapters: ComposerRuntimeAdapters;
252
253
  children: ReactNode;
253
254
  }) {
255
+ // Consumers key effects off this value; a fresh identity per render re-runs
256
+ // every one of them (app-state reads, event subscriptions) on each render.
257
+ const value = useMemo(
258
+ () => ({
259
+ ...fallbackAdapters,
260
+ ...adapters,
261
+ models: { ...fallbackModels, ...adapters.models },
262
+ agentChat: { ...fallbackAdapters.agentChat, ...adapters.agentChat },
263
+ builder: { ...fallbackAdapters.builder, ...adapters.builder },
264
+ resources: { ...fallbackAdapters.resources, ...adapters.resources },
265
+ voice: { ...fallbackAdapters.voice, ...adapters.voice },
266
+ }),
267
+ [adapters],
268
+ );
254
269
  return (
255
- <ComposerRuntimeAdaptersContext.Provider
256
- value={{
257
- ...fallbackAdapters,
258
- ...adapters,
259
- models: { ...fallbackModels, ...adapters.models },
260
- agentChat: { ...fallbackAdapters.agentChat, ...adapters.agentChat },
261
- builder: { ...fallbackAdapters.builder, ...adapters.builder },
262
- resources: { ...fallbackAdapters.resources, ...adapters.resources },
263
- voice: { ...fallbackAdapters.voice, ...adapters.voice },
264
- }}
265
- >
270
+ <ComposerRuntimeAdaptersContext.Provider value={value}>
266
271
  {children}
267
272
  </ComposerRuntimeAdaptersContext.Provider>
268
273
  );
@@ -4,17 +4,33 @@ export declare const A2A_AGENT_ACTIVITY_KIND = "agent-native/agent-activity";
4
4
  export declare const A2A_AGENT_ACTIVITY_VERSION = 1;
5
5
  export declare const MAX_A2A_ACTIVITY_REASONING_CHARS = 32768;
6
6
  export declare const MAX_A2A_ACTIVITY_RESPONSE_CHARS = 32768;
7
- export declare const MAX_A2A_ACTIVITY_TOTAL_CHARS = 98304;
8
7
  export declare const MAX_A2A_ACTIVITY_REASONING_SEGMENTS = 128;
9
8
  export declare const MAX_A2A_ACTIVITY_TOOL_CALLS = 64;
10
9
  export declare const MAX_A2A_ACTIVITY_TOOL_NAME_CHARS = 96;
11
10
  export declare const MAX_A2A_ACTIVITY_TOOL_ID_CHARS = 128;
11
+ export declare const MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS = 1024;
12
+ export declare const MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS = 512;
13
+ /**
14
+ * Shared ceiling for every recorded tool input/result across the snapshot. The
15
+ * per-call caps alone allow 64 × 1536 chars, which would push a busy run past
16
+ * `MAX_A2A_ACTIVITY_TOTAL_CHARS` and make `parseA2AAgentActivityPart` reject
17
+ * the whole snapshot — trading missing arguments for a missing trace.
18
+ */
19
+ export declare const MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS = 16384;
20
+ export declare const MAX_A2A_ACTIVITY_TOTAL_CHARS: number;
12
21
  export type A2AAgentActivityPhase = "reasoning" | "tool" | "responding" | "complete" | "error";
13
22
  export type A2AAgentActivityToolStatus = "running" | "completed" | "failed";
14
23
  export interface A2AAgentActivityToolCall {
15
24
  name: string;
16
25
  id?: string;
17
26
  status: A2AAgentActivityToolStatus;
27
+ /**
28
+ * Redacted, size-capped JSON of the call's arguments. Absent when the call
29
+ * had none, or when the snapshot's shared payload budget was already spent.
30
+ */
31
+ input?: string;
32
+ /** Redacted, size-capped head of the tool result (`tool_done` only). */
33
+ result?: string;
18
34
  }
19
35
  export interface A2AAgentActivitySnapshot extends Record<string, unknown> {
20
36
  kind: typeof A2A_AGENT_ACTIVITY_KIND;
@@ -42,9 +58,11 @@ export interface A2AAgentActivityState {
42
58
  }
43
59
  export declare function createA2AAgentActivityState(startedAt?: number): A2AAgentActivityState;
44
60
  /**
45
- * Converts internal loop events into a bounded activity snapshot. It carries
46
- * only reasoning text already emitted to the local chat, never tool inputs or
47
- * results.
61
+ * Converts internal loop events into a bounded activity snapshot. Reasoning
62
+ * text is carried verbatim (it was already emitted to the local chat); tool
63
+ * arguments and results are carried only in redacted, size-capped form so the
64
+ * delegated run stays diagnosable without the snapshot becoming a secondary
65
+ * store of secrets or payloads.
48
66
  */
49
67
  export declare function applyA2AAgentActivityEvent(state: A2AAgentActivityState, event: AgentChatEvent, updatedAt?: number): A2AAgentActivityState;
50
68
  export declare function buildA2AAgentActivitySnapshot(state: A2AAgentActivityState): A2AAgentActivitySnapshot;
@@ -1 +1 @@
1
- {"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../src/a2a/activity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEjD,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AACrE,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAC5C,eAAO,MAAM,gCAAgC,QAAS,CAAC;AACvD,eAAO,MAAM,+BAA+B,QAAS,CAAC;AACtD,eAAO,MAAM,4BAA4B,QAAS,CAAC;AACnD,eAAO,MAAM,mCAAmC,MAAM,CAAC;AACvD,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAC9C,eAAO,MAAM,gCAAgC,KAAK,CAAC;AACnD,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD,MAAM,MAAM,qBAAqB,GAC7B,WAAW,GACX,MAAM,GACN,YAAY,GACZ,UAAU,GACV,OAAO,CAAC;AAEZ,MAAM,MAAM,0BAA0B,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE5E,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,0BAA0B,CAAC;CACpC;AAED,MAAM,WAAW,wBAAyB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACvE,IAAI,EAAE,OAAO,uBAAuB,CAAC;IACrC,OAAO,EAAE,OAAO,0BAA0B,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,qBAAqB,CAAC;IACnC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,wBAAwB,EAAE,CAAC;IACtC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,qBAAqB,CAAC;IACnC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,wBAAwB,EAAE,CAAC;IACtC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,2BAA2B,CACzC,SAAS,SAAa,GACrB,qBAAqB,CAUvB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,qBAAqB,EAC5B,KAAK,EAAE,cAAc,EACrB,SAAS,SAAa,GACrB,qBAAqB,CAkDvB;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,qBAAqB,GAC3B,wBAAwB,CAc1B;AAMD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,qBAAqB,GAC3B,QAAQ,CAEV;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,IAAI,GAAG,OAAO,GACnB,wBAAwB,GAAG,IAAI,CA2BjC"}
1
+ {"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../src/a2a/activity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEjD,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AACrE,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAC5C,eAAO,MAAM,gCAAgC,QAAS,CAAC;AACvD,eAAO,MAAM,+BAA+B,QAAS,CAAC;AACtD,eAAO,MAAM,mCAAmC,MAAM,CAAC;AACvD,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAC9C,eAAO,MAAM,gCAAgC,KAAK,CAAC;AACnD,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAClD,eAAO,MAAM,iCAAiC,OAAO,CAAC;AACtD,eAAO,MAAM,kCAAkC,MAAM,CAAC;AACtD;;;;;GAKG;AACH,eAAO,MAAM,mCAAmC,QAAS,CAAC;AAC1D,eAAO,MAAM,4BAA4B,QACK,CAAC;AAE/C,MAAM,MAAM,qBAAqB,GAC7B,WAAW,GACX,MAAM,GACN,YAAY,GACZ,UAAU,GACV,OAAO,CAAC;AAEZ,MAAM,MAAM,0BAA0B,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE5E,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,0BAA0B,CAAC;IACnC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAyB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACvE,IAAI,EAAE,OAAO,uBAAuB,CAAC;IACrC,OAAO,EAAE,OAAO,0BAA0B,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,qBAAqB,CAAC;IACnC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,wBAAwB,EAAE,CAAC;IACtC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,qBAAqB,CAAC;IACnC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,wBAAwB,EAAE,CAAC;IACtC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,2BAA2B,CACzC,SAAS,SAAa,GACrB,qBAAqB,CAUvB;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,qBAAqB,EAC5B,KAAK,EAAE,cAAc,EACrB,SAAS,SAAa,GACrB,qBAAqB,CA8DvB;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,qBAAqB,GAC3B,wBAAwB,CAc1B;AAMD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,qBAAqB,GAC3B,QAAQ,CAEV;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,IAAI,GAAG,OAAO,GACnB,wBAAwB,GAAG,IAAI,CA2BjC"}
@@ -1,13 +1,23 @@
1
1
  import { sanitizeToolErrorText } from "../agent/tool-error-redaction.js";
2
+ import { redactArgsToJson, redactTextToSummary } from "../audit/redact.js";
2
3
  export const A2A_AGENT_ACTIVITY_KIND = "agent-native/agent-activity";
3
4
  export const A2A_AGENT_ACTIVITY_VERSION = 1;
4
5
  export const MAX_A2A_ACTIVITY_REASONING_CHARS = 32_768;
5
6
  export const MAX_A2A_ACTIVITY_RESPONSE_CHARS = 32_768;
6
- export const MAX_A2A_ACTIVITY_TOTAL_CHARS = 98_304;
7
7
  export const MAX_A2A_ACTIVITY_REASONING_SEGMENTS = 128;
8
8
  export const MAX_A2A_ACTIVITY_TOOL_CALLS = 64;
9
9
  export const MAX_A2A_ACTIVITY_TOOL_NAME_CHARS = 96;
10
10
  export const MAX_A2A_ACTIVITY_TOOL_ID_CHARS = 128;
11
+ export const MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS = 1024;
12
+ export const MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS = 512;
13
+ /**
14
+ * Shared ceiling for every recorded tool input/result across the snapshot. The
15
+ * per-call caps alone allow 64 × 1536 chars, which would push a busy run past
16
+ * `MAX_A2A_ACTIVITY_TOTAL_CHARS` and make `parseA2AAgentActivityPart` reject
17
+ * the whole snapshot — trading missing arguments for a missing trace.
18
+ */
19
+ export const MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS = 16_384;
20
+ export const MAX_A2A_ACTIVITY_TOTAL_CHARS = 98_304 + MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS;
11
21
  export function createA2AAgentActivityState(startedAt = Date.now()) {
12
22
  return {
13
23
  sequence: 0,
@@ -20,9 +30,11 @@ export function createA2AAgentActivityState(startedAt = Date.now()) {
20
30
  };
21
31
  }
22
32
  /**
23
- * Converts internal loop events into a bounded activity snapshot. It carries
24
- * only reasoning text already emitted to the local chat, never tool inputs or
25
- * results.
33
+ * Converts internal loop events into a bounded activity snapshot. Reasoning
34
+ * text is carried verbatim (it was already emitted to the local chat); tool
35
+ * arguments and results are carried only in redacted, size-capped form so the
36
+ * delegated run stays diagnosable without the snapshot becoming a secondary
37
+ * store of secrets or payloads.
26
38
  */
27
39
  export function applyA2AAgentActivityEvent(state, event, updatedAt = Date.now()) {
28
40
  const next = { ...state, updatedAt: normalizeTimestamp(updatedAt) };
@@ -33,14 +45,19 @@ export function applyA2AAgentActivityEvent(state, event, updatedAt = Date.now())
33
45
  next.reasoning = appendBoundedSegment(next.reasoning, event.text, MAX_A2A_ACTIVITY_REASONING_CHARS, next.toolCalls.length);
34
46
  changed = true;
35
47
  break;
36
- case "tool_start":
48
+ case "tool_start": {
37
49
  next.activePhase = "tool";
38
- next.toolCalls = appendToolCall(next.toolCalls, toolFromEvent(event));
50
+ const input = captureToolInput(event.input, remainingPayloadBudget(next.toolCalls));
51
+ next.toolCalls = appendToolCall(next.toolCalls, {
52
+ ...toolFromEvent(event),
53
+ ...(input ? { input } : {}),
54
+ });
39
55
  changed = true;
40
56
  break;
57
+ }
41
58
  case "tool_done":
42
59
  next.activePhase = "tool";
43
- next.toolCalls = settleToolCall(next.toolCalls, toolFromEvent(event));
60
+ next.toolCalls = settleToolCall(next.toolCalls, toolFromEvent(event), event);
44
61
  changed = true;
45
62
  break;
46
63
  case "text":
@@ -123,6 +140,38 @@ function toolFromEvent(event) {
123
140
  : "completed",
124
141
  };
125
142
  }
143
+ function payloadChars(tool) {
144
+ return (tool.input?.length ?? 0) + (tool.result?.length ?? 0);
145
+ }
146
+ function remainingPayloadBudget(current, excludeIndex = -1) {
147
+ const used = current.reduce((total, tool, index) => index === excludeIndex ? total : total + payloadChars(tool), 0);
148
+ return Math.max(0, MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS - used);
149
+ }
150
+ /**
151
+ * Redacted, capped JSON of the arguments, or `undefined` when there is nothing
152
+ * to record or the shared budget cannot fit a whole (still-parseable) capture.
153
+ * A partial JSON string would be worse than none — the reader could not tell a
154
+ * clipped object from a different one.
155
+ */
156
+ function captureToolInput(input, budget) {
157
+ const cap = Math.min(MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS, budget);
158
+ if (cap < MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS / 8)
159
+ return undefined;
160
+ const json = redactArgsToJson(input, { maxJson: cap, maxString: 256 });
161
+ // JSON.stringify escapes control characters, so the result is already safe
162
+ // for the snapshot without a `sanitizeText` pass — which would rewrite
163
+ // `"token":"[redacted]"` into unparseable JSON.
164
+ if (!json || json === "{}" || json.length > cap)
165
+ return undefined;
166
+ return json;
167
+ }
168
+ function captureToolResult(result, budget) {
169
+ const cap = Math.min(MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS, budget);
170
+ if (!result || cap <= 0)
171
+ return undefined;
172
+ const summary = redactTextToSummary(result, cap);
173
+ return summary ? sanitizeText(summary, cap) || undefined : undefined;
174
+ }
126
175
  function appendBoundedSegment(current, addition, maxChars, precedingToolCount) {
127
176
  const used = current.reduce((total, text) => total + text.length, 0);
128
177
  if (used >= maxChars ||
@@ -148,15 +197,34 @@ function appendToolCall(current, tool) {
148
197
  ? [...current, tool]
149
198
  : current;
150
199
  }
151
- function settleToolCall(current, tool) {
200
+ function settleToolCall(current, tool, event) {
152
201
  for (let index = current.length - 1; index >= 0; index -= 1) {
153
202
  const existing = current[index];
154
203
  if ((tool.id && tool.id === existing.id) ||
155
204
  (!tool.id && tool.name === existing.name)) {
156
- return current.map((value, itemIndex) => itemIndex === index ? tool : value);
205
+ // The matching `tool_start` already paid for its input; reuse it rather
206
+ // than re-capturing (and re-charging) the same arguments.
207
+ let budget = remainingPayloadBudget(current, index);
208
+ const input = existing.input ?? captureToolInput(event.input, budget) ?? undefined;
209
+ budget -= input?.length ?? 0;
210
+ const result = captureToolResult(event.result, budget);
211
+ const settled = {
212
+ ...tool,
213
+ ...(input ? { input } : {}),
214
+ ...(result ? { result } : {}),
215
+ };
216
+ return current.map((value, itemIndex) => itemIndex === index ? settled : value);
157
217
  }
158
218
  }
159
- return appendToolCall(current, tool);
219
+ let budget = remainingPayloadBudget(current);
220
+ const input = captureToolInput(event.input, budget);
221
+ budget -= input?.length ?? 0;
222
+ const result = captureToolResult(event.result, budget);
223
+ return appendToolCall(current, {
224
+ ...tool,
225
+ ...(input ? { input } : {}),
226
+ ...(result ? { result } : {}),
227
+ });
160
228
  }
161
229
  function sanitizeText(value, maxChars) {
162
230
  return sanitizeToolErrorText(value)
@@ -200,10 +268,26 @@ function isSafeToolCall(value) {
200
268
  if (!isRecord(value) || !isSafeToolName(value.name))
201
269
  return false;
202
270
  return ((value.id === undefined || isSafeToolId(value.id)) &&
271
+ (value.input === undefined ||
272
+ isSafeCapturedText(value.input, MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS)) &&
273
+ (value.result === undefined ||
274
+ isSafeCapturedText(value.result, MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS)) &&
203
275
  (value.status === "running" ||
204
276
  value.status === "completed" ||
205
277
  value.status === "failed"));
206
278
  }
279
+ /**
280
+ * Captured input/result are producer-side redacted strings. Unlike reasoning
281
+ * text they are NOT re-sanitized on read: `sanitizeToolErrorText` rewrites
282
+ * `"token":"…"` into unparseable JSON, so a round-trip equality check would
283
+ * reject every legitimate capture. Bound the length and reject raw control
284
+ * characters instead.
285
+ */
286
+ function isSafeCapturedText(value, maxChars) {
287
+ return (typeof value === "string" &&
288
+ value.length <= maxChars &&
289
+ !/[\u0000-\u0008\u000b-\u001f\u007f]/.test(value));
290
+ }
207
291
  function isSafeText(value, maxChars) {
208
292
  return (typeof value === "string" &&
209
293
  value.length <= maxChars &&
@@ -234,7 +318,9 @@ function activityCharacterCount(data) {
234
318
  return total;
235
319
  return (total +
236
320
  (typeof tool.name === "string" ? tool.name.length : 0) +
237
- (typeof tool.id === "string" ? tool.id.length : 0));
321
+ (typeof tool.id === "string" ? tool.id.length : 0) +
322
+ (typeof tool.input === "string" ? tool.input.length : 0) +
323
+ (typeof tool.result === "string" ? tool.result.length : 0));
238
324
  }, 0)
239
325
  : 0;
240
326
  return reasoning + response + tools;