@agent-native/core 0.107.2 → 0.109.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (502) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +24 -0
  3. package/corpus/core/docs/content/actions.mdx +48 -0
  4. package/corpus/core/docs/content/locales/ar-SA/actions.mdx +38 -0
  5. package/corpus/core/docs/content/locales/de-DE/actions.mdx +38 -0
  6. package/corpus/core/docs/content/locales/es-ES/actions.mdx +38 -0
  7. package/corpus/core/docs/content/locales/fr-FR/actions.mdx +38 -0
  8. package/corpus/core/docs/content/locales/hi-IN/actions.mdx +38 -0
  9. package/corpus/core/docs/content/locales/ja-JP/actions.mdx +38 -0
  10. package/corpus/core/docs/content/locales/ko-KR/actions.mdx +38 -0
  11. package/corpus/core/docs/content/locales/pt-BR/actions.mdx +38 -0
  12. package/corpus/core/docs/content/locales/zh-CN/actions.mdx +38 -0
  13. package/corpus/core/docs/content/locales/zh-TW/actions.mdx +38 -0
  14. package/corpus/core/package.json +5 -1
  15. package/corpus/core/src/a2a/client.ts +140 -17
  16. package/corpus/core/src/a2a/handlers.ts +60 -0
  17. package/corpus/core/src/a2a/index.ts +6 -1
  18. package/corpus/core/src/a2a/invoke.ts +68 -1
  19. package/corpus/core/src/a2a/server.ts +13 -1
  20. package/corpus/core/src/a2a/types.ts +16 -0
  21. package/corpus/core/src/a2a-claims.ts +52 -0
  22. package/corpus/core/src/action.ts +7 -2
  23. package/corpus/core/src/agent/production-agent.ts +10 -4
  24. package/corpus/core/src/audit/record.ts +6 -0
  25. package/corpus/core/src/client/AssistantChat.tsx +648 -603
  26. package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -4
  27. package/corpus/core/src/client/agent-chat-adapter.ts +23 -37
  28. package/corpus/core/src/client/agent-sidebar-state.ts +4 -0
  29. package/corpus/core/src/client/analytics.ts +84 -0
  30. package/corpus/core/src/client/chat/message-components.tsx +94 -22
  31. package/corpus/core/src/client/chat/tool-call-display.tsx +170 -47
  32. package/corpus/core/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
  33. package/corpus/core/src/client/chat-thread-url.ts +11 -0
  34. package/corpus/core/src/client/error-capture.ts +12 -0
  35. package/corpus/core/src/client/extensions/ExtensionSlot.tsx +37 -1
  36. package/corpus/core/src/client/feature-flags/FeatureFlagsPanel.tsx +519 -0
  37. package/corpus/core/src/client/feature-flags/helpers.ts +77 -0
  38. package/corpus/core/src/client/feature-flags/index.ts +13 -0
  39. package/corpus/core/src/client/feature-flags/types.ts +29 -0
  40. package/corpus/core/src/client/feature-flags/use-feature-flag.ts +26 -0
  41. package/corpus/core/src/client/index.ts +13 -0
  42. package/corpus/core/src/client/route-chunk-recovery.ts +20 -8
  43. package/corpus/core/src/client/session-replay.ts +31 -0
  44. package/corpus/core/src/extensions/actions.ts +2 -14
  45. package/corpus/core/src/extensions/routes.ts +1 -1
  46. package/corpus/core/src/extensions/store.ts +1 -1
  47. package/corpus/core/src/feature-flags/a2a-action-route.ts +56 -0
  48. package/corpus/core/src/feature-flags/actions/get-feature-flags.ts +24 -0
  49. package/corpus/core/src/feature-flags/actions/list-feature-flags.ts +69 -0
  50. package/corpus/core/src/feature-flags/actions/set-feature-flag.ts +89 -0
  51. package/corpus/core/src/feature-flags/index.ts +21 -0
  52. package/corpus/core/src/feature-flags/permissions.ts +53 -0
  53. package/corpus/core/src/feature-flags/plugin.ts +44 -0
  54. package/corpus/core/src/feature-flags/registry.ts +96 -0
  55. package/corpus/core/src/feature-flags/store.ts +176 -0
  56. package/corpus/core/src/index.ts +15 -0
  57. package/corpus/core/src/localization/default-messages.ts +50 -0
  58. package/corpus/core/src/mcp/build-server.ts +2 -2
  59. package/corpus/core/src/progress/actions.ts +4 -2
  60. package/corpus/core/src/provider-api/index.ts +205 -105
  61. package/corpus/core/src/scripts/call-agent.ts +137 -17
  62. package/corpus/core/src/server/action-discovery.ts +12 -0
  63. package/corpus/core/src/server/action-routes.ts +47 -5
  64. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +40 -0
  65. package/corpus/core/src/server/agent-chat-plugin.ts +31 -0
  66. package/corpus/core/src/server/index.ts +1 -0
  67. package/corpus/core/src/settings/org-settings.ts +13 -0
  68. package/corpus/core/src/settings/store.ts +57 -0
  69. package/corpus/core/src/styles/agent-conversation.css +7 -0
  70. package/corpus/core/src/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
  71. package/corpus/core/src/templates/default/AGENTS.md +1 -0
  72. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +20 -0
  73. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +20 -0
  74. package/corpus/core/src/templates/default/app/i18n/en-US.ts +20 -0
  75. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +20 -0
  76. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
  77. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +19 -0
  78. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +20 -0
  79. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +19 -0
  80. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +20 -0
  81. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +19 -0
  82. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
  83. package/corpus/core/src/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
  84. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
  85. package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  86. package/corpus/core/src/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
  87. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  88. package/corpus/core/src/templates/workspace-core/AGENTS.md +1 -1
  89. package/corpus/core/src/templates/workspace-root/AGENTS.md +1 -1
  90. package/corpus/core/src/vite/action-types-plugin.ts +12 -0
  91. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -10
  92. package/corpus/templates/analytics/.agents/skills/feature-flags/SKILL.md +169 -0
  93. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +54 -23
  94. package/corpus/templates/analytics/.builder/skills/apollo/SKILL.md +19 -41
  95. package/corpus/templates/analytics/.builder/skills/commonroom/SKILL.md +20 -35
  96. package/corpus/templates/analytics/.builder/skills/github/SKILL.md +23 -67
  97. package/corpus/templates/analytics/.builder/skills/pylon/SKILL.md +25 -43
  98. package/corpus/templates/analytics/AGENTS.md +37 -16
  99. package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
  100. package/corpus/templates/analytics/actions/configure-gong-native-insights.ts +29 -0
  101. package/corpus/templates/analytics/actions/content-calendar-schema.ts +8 -4
  102. package/corpus/templates/analytics/actions/content-calendar.ts +12 -4
  103. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -1
  104. package/corpus/templates/analytics/actions/gong-calls.ts +113 -22
  105. package/corpus/templates/analytics/actions/gong-native-insights.ts +166 -0
  106. package/corpus/templates/analytics/actions/hubspot-deals.ts +190 -46
  107. package/corpus/templates/analytics/actions/list-workspace-feature-flags.ts +15 -0
  108. package/corpus/templates/analytics/actions/navigate.ts +2 -2
  109. package/corpus/templates/analytics/actions/pylon-issues.ts +123 -0
  110. package/corpus/templates/analytics/actions/set-workspace-feature-flag.ts +45 -0
  111. package/corpus/templates/analytics/actions/slack-messages.ts +179 -27
  112. package/corpus/templates/analytics/actions/view-screen.ts +13 -0
  113. package/corpus/templates/analytics/app/components/agents/FeatureFlagsFleetPanel.tsx +243 -0
  114. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +48 -152
  115. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +11 -3
  116. package/corpus/templates/analytics/app/components/ui/chart.tsx +1 -1
  117. package/corpus/templates/analytics/app/hooks/use-chart-tooltip-flip.ts +21 -6
  118. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +3 -1
  119. package/corpus/templates/analytics/app/i18n/zh-TW.ts +30 -0
  120. package/corpus/templates/analytics/app/i18n-data.ts +385 -0
  121. package/corpus/templates/analytics/app/pages/Agents.tsx +22 -2
  122. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +181 -30
  123. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +6 -0
  124. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +4 -3
  125. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-editors-can-add-shared-extensions-or-opt-into-per-.md +6 -0
  126. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extensions-show-a-loading-skeleton.md +6 -0
  127. package/corpus/templates/analytics/changelog/2026-07-17-errors-now-group-repeat-failures-consistently-and-keep-priva.md +6 -0
  128. package/corpus/templates/analytics/changelog/2026-07-17-gong-transcript-reviews-now-batch-bounded-call-windows-for-f.md +6 -0
  129. package/corpus/templates/analytics/changelog/2026-07-17-hubspot-deal-filters-now-run-in-hubspot-before-paging-result.md +6 -0
  130. package/corpus/templates/analytics/changelog/2026-07-17-manage-feature-flag-rollouts-across-your-organization-s-apps.md +6 -0
  131. package/corpus/templates/analytics/changelog/2026-07-17-notion-content-calendars-now-discover-the-matching-database-.md +6 -0
  132. package/corpus/templates/analytics/changelog/2026-07-17-pylon-dashboard-reads-now-use-the-paginated-issue-search-api.md +6 -0
  133. package/corpus/templates/analytics/changelog/2026-07-17-slack-reads-no-longer-join-channels-and-report-pagination-coverage.md +6 -0
  134. package/corpus/templates/analytics/server/handlers/notion.ts +14 -3
  135. package/corpus/templates/analytics/server/handlers/slack.ts +182 -29
  136. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -6
  137. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +6 -2
  138. package/corpus/templates/analytics/server/lib/db-admin-connections.ts +13 -5
  139. package/corpus/templates/analytics/server/lib/error-capture.ts +75 -8
  140. package/corpus/templates/analytics/server/lib/gong-native-policy.ts +72 -0
  141. package/corpus/templates/analytics/server/lib/gong.ts +54 -66
  142. package/corpus/templates/analytics/server/lib/hubspot.ts +40 -3
  143. package/corpus/templates/analytics/server/lib/notion.ts +83 -8
  144. package/corpus/templates/analytics/server/lib/real-data-actions.ts +4 -0
  145. package/corpus/templates/analytics/server/lib/slack.ts +242 -90
  146. package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +347 -0
  147. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -3
  148. package/corpus/templates/analytics/server/routes/api/pylon/accounts.get.ts +42 -1
  149. package/corpus/templates/analytics/server/routes/api/pylon/issues.get.ts +71 -1
  150. package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +44 -4
  151. package/corpus/templates/assets/.agents/skills/feature-flags/SKILL.md +169 -0
  152. package/corpus/templates/brain/.agents/skills/feature-flags/SKILL.md +169 -0
  153. package/corpus/templates/calendar/.agents/skills/feature-flags/SKILL.md +169 -0
  154. package/corpus/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
  155. package/corpus/templates/clips/.agents/skills/feature-flags/SKILL.md +169 -0
  156. package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +19 -1
  157. package/corpus/templates/clips/app/components/library/create-folder-dialog.tsx +123 -0
  158. package/corpus/templates/clips/app/components/library/library-grid.tsx +42 -4
  159. package/corpus/templates/clips/app/components/library/recording-card.tsx +30 -0
  160. package/corpus/templates/clips/app/entry.client.tsx +6 -1
  161. package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -1
  162. package/corpus/templates/clips/app/i18n/de-DE.ts +12 -1
  163. package/corpus/templates/clips/app/i18n/en-US.ts +12 -1
  164. package/corpus/templates/clips/app/i18n/es-ES.ts +11 -1
  165. package/corpus/templates/clips/app/i18n/fr-FR.ts +11 -1
  166. package/corpus/templates/clips/app/i18n/hi-IN.ts +10 -1
  167. package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -1
  168. package/corpus/templates/clips/app/i18n/ko-KR.ts +11 -1
  169. package/corpus/templates/clips/app/i18n/pt-BR.ts +11 -1
  170. package/corpus/templates/clips/app/i18n/zh-CN.ts +11 -1
  171. package/corpus/templates/clips/app/i18n/zh-TW.ts +11 -1
  172. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +72 -1
  173. package/corpus/templates/clips/changelog/2026-07-17-choose-which-workspace-receives-new-clips-recordings-and-des.md +6 -0
  174. package/corpus/templates/clips/changelog/2026-07-17-create-folders-directly-from-the-move-menu.md +6 -0
  175. package/corpus/templates/clips/changelog/2026-07-17-failed-desktop-uploads-now-offer-a-direct-way-to-reopen-clip.md +6 -0
  176. package/corpus/templates/clips/desktop/src/app.tsx +1 -1
  177. package/corpus/templates/clips/server/plugins/feature-flags.ts +11 -0
  178. package/corpus/templates/clips/shared/feature-flags.ts +30 -37
  179. package/corpus/templates/content/.agents/skills/feature-flags/SKILL.md +169 -0
  180. package/corpus/templates/content/app/entry.client.tsx +6 -1
  181. package/corpus/templates/design/.agents/skills/feature-flags/SKILL.md +169 -0
  182. package/corpus/templates/design/AGENTS.md +5 -3
  183. package/corpus/templates/design/actions/add-fusion-screens.ts +4 -6
  184. package/corpus/templates/design/actions/apply-fusion-edits.ts +4 -6
  185. package/corpus/templates/design/actions/create-fusion-app.ts +5 -4
  186. package/corpus/templates/design/actions/deploy-fusion-app.ts +4 -3
  187. package/corpus/templates/design/actions/get-fusion-deploy-status.ts +4 -6
  188. package/corpus/templates/design/actions/list-fusion-edits.ts +4 -3
  189. package/corpus/templates/design/actions/push-fusion-app.ts +4 -6
  190. package/corpus/templates/design/actions/queue-fusion-edit.ts +4 -3
  191. package/corpus/templates/design/actions/send-fusion-message.ts +4 -6
  192. package/corpus/templates/design/actions/sync-fusion-app.ts +4 -3
  193. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +1 -1
  194. package/corpus/templates/design/app/pages/Index.tsx +8 -6
  195. package/corpus/templates/design/server/plugins/feature-flags.ts +5 -0
  196. package/corpus/templates/design/shared/full-app.ts +10 -7
  197. package/corpus/templates/dispatch/.agents/skills/feature-flags/SKILL.md +169 -0
  198. package/corpus/templates/dispatch/AGENTS.md +5 -0
  199. package/corpus/templates/dispatch/changelog/2026-07-17-apps-page-links-to-other-available-apps.md +6 -0
  200. package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +6 -0
  201. package/corpus/templates/forms/.agents/skills/feature-flags/SKILL.md +169 -0
  202. package/corpus/templates/macros/.agents/skills/feature-flags/SKILL.md +169 -0
  203. package/corpus/templates/mail/.agents/skills/feature-flags/SKILL.md +169 -0
  204. package/corpus/templates/mail/app/entry.client.tsx +6 -1
  205. package/corpus/templates/plan/.agents/skills/feature-flags/SKILL.md +169 -0
  206. package/corpus/templates/slides/.agents/skills/feature-flags/SKILL.md +169 -0
  207. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +11 -7
  208. package/corpus/templates/slides/.env.example +0 -1
  209. package/corpus/templates/slides/AGENTS.md +4 -0
  210. package/corpus/templates/slides/DEVELOPING.md +2 -2
  211. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
  212. package/corpus/templates/slides/actions/logo-config.ts +6 -7
  213. package/corpus/templates/slides/actions/search-images.ts +11 -39
  214. package/corpus/templates/slides/actions/search-logos.ts +5 -52
  215. package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +1 -1
  216. package/corpus/templates/slides/app/components/editor/LogoSearchPanel.tsx +16 -26
  217. package/corpus/templates/slides/app/entry.client.tsx +6 -1
  218. package/corpus/templates/slides/server/lib/media-search-providers.ts +216 -0
  219. package/corpus/templates/slides/server/register-secrets.ts +30 -0
  220. package/corpus/templates/tasks/.agents/skills/feature-flags/SKILL.md +169 -0
  221. package/dist/a2a/client.d.ts +38 -1
  222. package/dist/a2a/client.d.ts.map +1 -1
  223. package/dist/a2a/client.js +81 -12
  224. package/dist/a2a/client.js.map +1 -1
  225. package/dist/a2a/handlers.d.ts.map +1 -1
  226. package/dist/a2a/handlers.js +47 -0
  227. package/dist/a2a/handlers.js.map +1 -1
  228. package/dist/a2a/index.d.ts +4 -4
  229. package/dist/a2a/index.d.ts.map +1 -1
  230. package/dist/a2a/index.js +2 -2
  231. package/dist/a2a/index.js.map +1 -1
  232. package/dist/a2a/invoke.d.ts +26 -2
  233. package/dist/a2a/invoke.d.ts.map +1 -1
  234. package/dist/a2a/invoke.js +30 -1
  235. package/dist/a2a/invoke.js.map +1 -1
  236. package/dist/a2a/server.d.ts.map +1 -1
  237. package/dist/a2a/server.js +14 -1
  238. package/dist/a2a/server.js.map +1 -1
  239. package/dist/a2a/types.d.ts +12 -0
  240. package/dist/a2a/types.d.ts.map +1 -1
  241. package/dist/a2a/types.js.map +1 -1
  242. package/dist/a2a-claims.d.ts +10 -0
  243. package/dist/a2a-claims.d.ts.map +1 -0
  244. package/dist/a2a-claims.js +41 -0
  245. package/dist/a2a-claims.js.map +1 -0
  246. package/dist/action.d.ts +7 -2
  247. package/dist/action.d.ts.map +1 -1
  248. package/dist/action.js.map +1 -1
  249. package/dist/agent/production-agent.d.ts +5 -0
  250. package/dist/agent/production-agent.d.ts.map +1 -1
  251. package/dist/agent/production-agent.js +5 -3
  252. package/dist/agent/production-agent.js.map +1 -1
  253. package/dist/audit/record.d.ts +3 -0
  254. package/dist/audit/record.d.ts.map +1 -1
  255. package/dist/audit/record.js +3 -0
  256. package/dist/audit/record.js.map +1 -1
  257. package/dist/client/AssistantChat.d.ts +14 -1
  258. package/dist/client/AssistantChat.d.ts.map +1 -1
  259. package/dist/client/AssistantChat.js +158 -136
  260. package/dist/client/AssistantChat.js.map +1 -1
  261. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  262. package/dist/client/MultiTabAssistantChat.js +27 -4
  263. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  264. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  265. package/dist/client/agent-chat-adapter.js +21 -39
  266. package/dist/client/agent-chat-adapter.js.map +1 -1
  267. package/dist/client/agent-sidebar-state.d.ts +1 -0
  268. package/dist/client/agent-sidebar-state.d.ts.map +1 -1
  269. package/dist/client/agent-sidebar-state.js +4 -0
  270. package/dist/client/agent-sidebar-state.js.map +1 -1
  271. package/dist/client/analytics.d.ts +14 -0
  272. package/dist/client/analytics.d.ts.map +1 -1
  273. package/dist/client/analytics.js +67 -0
  274. package/dist/client/analytics.js.map +1 -1
  275. package/dist/client/chat/message-components.d.ts +8 -0
  276. package/dist/client/chat/message-components.d.ts.map +1 -1
  277. package/dist/client/chat/message-components.js +62 -19
  278. package/dist/client/chat/message-components.js.map +1 -1
  279. package/dist/client/chat/tool-call-display.d.ts +6 -0
  280. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  281. package/dist/client/chat/tool-call-display.js +83 -14
  282. package/dist/client/chat/tool-call-display.js.map +1 -1
  283. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts +8 -0
  284. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts.map +1 -0
  285. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js +51 -0
  286. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js.map +1 -0
  287. package/dist/client/chat-thread-url.d.ts +2 -0
  288. package/dist/client/chat-thread-url.d.ts.map +1 -0
  289. package/dist/client/chat-thread-url.js +12 -0
  290. package/dist/client/chat-thread-url.js.map +1 -0
  291. package/dist/client/error-capture.d.ts.map +1 -1
  292. package/dist/client/error-capture.js +7 -0
  293. package/dist/client/error-capture.js.map +1 -1
  294. package/dist/client/extensions/ExtensionSlot.d.ts +3 -1
  295. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  296. package/dist/client/extensions/ExtensionSlot.js +28 -3
  297. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  298. package/dist/client/feature-flags/FeatureFlagsPanel.d.ts +10 -0
  299. package/dist/client/feature-flags/FeatureFlagsPanel.d.ts.map +1 -0
  300. package/dist/client/feature-flags/FeatureFlagsPanel.js +143 -0
  301. package/dist/client/feature-flags/FeatureFlagsPanel.js.map +1 -0
  302. package/dist/client/feature-flags/helpers.d.ts +16 -0
  303. package/dist/client/feature-flags/helpers.d.ts.map +1 -0
  304. package/dist/client/feature-flags/helpers.js +50 -0
  305. package/dist/client/feature-flags/helpers.js.map +1 -0
  306. package/dist/client/feature-flags/index.d.ts +5 -0
  307. package/dist/client/feature-flags/index.d.ts.map +1 -0
  308. package/dist/client/feature-flags/index.js +4 -0
  309. package/dist/client/feature-flags/index.js.map +1 -0
  310. package/dist/client/feature-flags/types.d.ts +27 -0
  311. package/dist/client/feature-flags/types.d.ts.map +1 -0
  312. package/dist/client/feature-flags/types.js +2 -0
  313. package/dist/client/feature-flags/types.js.map +1 -0
  314. package/dist/client/feature-flags/use-feature-flag.d.ts +8 -0
  315. package/dist/client/feature-flags/use-feature-flag.d.ts.map +1 -0
  316. package/dist/client/feature-flags/use-feature-flag.js +15 -0
  317. package/dist/client/feature-flags/use-feature-flag.js.map +1 -0
  318. package/dist/client/index.d.ts +2 -1
  319. package/dist/client/index.d.ts.map +1 -1
  320. package/dist/client/index.js +2 -1
  321. package/dist/client/index.js.map +1 -1
  322. package/dist/client/route-chunk-recovery.d.ts.map +1 -1
  323. package/dist/client/route-chunk-recovery.js +14 -9
  324. package/dist/client/route-chunk-recovery.js.map +1 -1
  325. package/dist/client/session-replay.d.ts +15 -0
  326. package/dist/client/session-replay.d.ts.map +1 -1
  327. package/dist/client/session-replay.js +20 -0
  328. package/dist/client/session-replay.js.map +1 -1
  329. package/dist/collab/struct-routes.d.ts +1 -1
  330. package/dist/extensions/actions.d.ts.map +1 -1
  331. package/dist/extensions/actions.js +2 -10
  332. package/dist/extensions/actions.js.map +1 -1
  333. package/dist/extensions/routes.d.ts.map +1 -1
  334. package/dist/extensions/routes.js +1 -1
  335. package/dist/extensions/routes.js.map +1 -1
  336. package/dist/extensions/store.js +1 -1
  337. package/dist/extensions/store.js.map +1 -1
  338. package/dist/feature-flags/a2a-action-route.d.ts +14 -0
  339. package/dist/feature-flags/a2a-action-route.d.ts.map +1 -0
  340. package/dist/feature-flags/a2a-action-route.js +50 -0
  341. package/dist/feature-flags/a2a-action-route.js.map +1 -0
  342. package/dist/feature-flags/actions/get-feature-flags.d.ts +3 -0
  343. package/dist/feature-flags/actions/get-feature-flags.d.ts.map +1 -0
  344. package/dist/feature-flags/actions/get-feature-flags.js +18 -0
  345. package/dist/feature-flags/actions/get-feature-flags.js.map +1 -0
  346. package/dist/feature-flags/actions/list-feature-flags.d.ts +28 -0
  347. package/dist/feature-flags/actions/list-feature-flags.d.ts.map +1 -0
  348. package/dist/feature-flags/actions/list-feature-flags.js +60 -0
  349. package/dist/feature-flags/actions/list-feature-flags.js.map +1 -0
  350. package/dist/feature-flags/actions/set-feature-flag.d.ts +26 -0
  351. package/dist/feature-flags/actions/set-feature-flag.d.ts.map +1 -0
  352. package/dist/feature-flags/actions/set-feature-flag.js +78 -0
  353. package/dist/feature-flags/actions/set-feature-flag.js.map +1 -0
  354. package/dist/feature-flags/index.d.ts +5 -0
  355. package/dist/feature-flags/index.d.ts.map +1 -0
  356. package/dist/feature-flags/index.js +5 -0
  357. package/dist/feature-flags/index.js.map +1 -0
  358. package/dist/feature-flags/permissions.d.ts +13 -0
  359. package/dist/feature-flags/permissions.d.ts.map +1 -0
  360. package/dist/feature-flags/permissions.js +37 -0
  361. package/dist/feature-flags/permissions.js.map +1 -0
  362. package/dist/feature-flags/plugin.d.ts +17 -0
  363. package/dist/feature-flags/plugin.d.ts.map +1 -0
  364. package/dist/feature-flags/plugin.js +29 -0
  365. package/dist/feature-flags/plugin.js.map +1 -0
  366. package/dist/feature-flags/registry.d.ts +23 -0
  367. package/dist/feature-flags/registry.d.ts.map +1 -0
  368. package/dist/feature-flags/registry.js +59 -0
  369. package/dist/feature-flags/registry.js.map +1 -0
  370. package/dist/feature-flags/store.d.ts +31 -0
  371. package/dist/feature-flags/store.d.ts.map +1 -0
  372. package/dist/feature-flags/store.js +124 -0
  373. package/dist/feature-flags/store.js.map +1 -0
  374. package/dist/index.d.ts +1 -0
  375. package/dist/index.d.ts.map +1 -1
  376. package/dist/index.js +1 -0
  377. package/dist/index.js.map +1 -1
  378. package/dist/localization/default-messages.d.ts +45 -0
  379. package/dist/localization/default-messages.d.ts.map +1 -1
  380. package/dist/localization/default-messages.js +45 -0
  381. package/dist/localization/default-messages.js.map +1 -1
  382. package/dist/mcp/build-server.d.ts +2 -0
  383. package/dist/mcp/build-server.d.ts.map +1 -1
  384. package/dist/mcp/build-server.js +2 -2
  385. package/dist/mcp/build-server.js.map +1 -1
  386. package/dist/notifications/routes.d.ts +2 -2
  387. package/dist/progress/actions.d.ts.map +1 -1
  388. package/dist/progress/actions.js +3 -2
  389. package/dist/progress/actions.js.map +1 -1
  390. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  391. package/dist/provider-api/index.d.ts.map +1 -1
  392. package/dist/provider-api/index.js +91 -8
  393. package/dist/provider-api/index.js.map +1 -1
  394. package/dist/resources/handlers.d.ts +3 -3
  395. package/dist/scripts/call-agent.d.ts.map +1 -1
  396. package/dist/scripts/call-agent.js +107 -16
  397. package/dist/scripts/call-agent.js.map +1 -1
  398. package/dist/server/action-discovery.d.ts.map +1 -1
  399. package/dist/server/action-discovery.js +12 -0
  400. package/dist/server/action-discovery.js.map +1 -1
  401. package/dist/server/action-routes.d.ts +3 -0
  402. package/dist/server/action-routes.d.ts.map +1 -1
  403. package/dist/server/action-routes.js +45 -5
  404. package/dist/server/action-routes.js.map +1 -1
  405. package/dist/server/agent-chat/action-filters-a2a.d.ts +6 -0
  406. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  407. package/dist/server/agent-chat/action-filters-a2a.js +27 -0
  408. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  409. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  410. package/dist/server/agent-chat-plugin.js +27 -1
  411. package/dist/server/agent-chat-plugin.js.map +1 -1
  412. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  413. package/dist/server/index.d.ts +1 -0
  414. package/dist/server/index.d.ts.map +1 -1
  415. package/dist/server/index.js +1 -0
  416. package/dist/server/index.js.map +1 -1
  417. package/dist/server/transcribe-voice.d.ts +1 -1
  418. package/dist/settings/org-settings.d.ts +2 -0
  419. package/dist/settings/org-settings.d.ts.map +1 -1
  420. package/dist/settings/org-settings.js +5 -1
  421. package/dist/settings/org-settings.js.map +1 -1
  422. package/dist/settings/store.d.ts +8 -0
  423. package/dist/settings/store.d.ts.map +1 -1
  424. package/dist/settings/store.js +48 -0
  425. package/dist/settings/store.js.map +1 -1
  426. package/dist/styles/agent-conversation.css +7 -0
  427. package/dist/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
  428. package/dist/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
  429. package/dist/templates/default/AGENTS.md +1 -0
  430. package/dist/templates/default/app/i18n/ar-SA.ts +20 -0
  431. package/dist/templates/default/app/i18n/de-DE.ts +20 -0
  432. package/dist/templates/default/app/i18n/en-US.ts +20 -0
  433. package/dist/templates/default/app/i18n/es-ES.ts +20 -0
  434. package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
  435. package/dist/templates/default/app/i18n/hi-IN.ts +19 -0
  436. package/dist/templates/default/app/i18n/ja-JP.ts +20 -0
  437. package/dist/templates/default/app/i18n/ko-KR.ts +19 -0
  438. package/dist/templates/default/app/i18n/pt-BR.ts +20 -0
  439. package/dist/templates/default/app/i18n/zh-CN.ts +19 -0
  440. package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
  441. package/dist/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
  442. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
  443. package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  444. package/dist/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
  445. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  446. package/dist/templates/workspace-core/AGENTS.md +1 -1
  447. package/dist/templates/workspace-root/AGENTS.md +1 -1
  448. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  449. package/dist/vite/action-types-plugin.js +12 -0
  450. package/dist/vite/action-types-plugin.js.map +1 -1
  451. package/docs/content/actions.mdx +48 -0
  452. package/docs/content/locales/ar-SA/actions.mdx +38 -0
  453. package/docs/content/locales/de-DE/actions.mdx +38 -0
  454. package/docs/content/locales/es-ES/actions.mdx +38 -0
  455. package/docs/content/locales/fr-FR/actions.mdx +38 -0
  456. package/docs/content/locales/hi-IN/actions.mdx +38 -0
  457. package/docs/content/locales/ja-JP/actions.mdx +38 -0
  458. package/docs/content/locales/ko-KR/actions.mdx +38 -0
  459. package/docs/content/locales/pt-BR/actions.mdx +38 -0
  460. package/docs/content/locales/zh-CN/actions.mdx +38 -0
  461. package/docs/content/locales/zh-TW/actions.mdx +38 -0
  462. package/package.json +5 -1
  463. package/src/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
  464. package/src/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
  465. package/src/templates/default/AGENTS.md +1 -0
  466. package/src/templates/default/app/i18n/ar-SA.ts +20 -0
  467. package/src/templates/default/app/i18n/de-DE.ts +20 -0
  468. package/src/templates/default/app/i18n/en-US.ts +20 -0
  469. package/src/templates/default/app/i18n/es-ES.ts +20 -0
  470. package/src/templates/default/app/i18n/fr-FR.ts +21 -0
  471. package/src/templates/default/app/i18n/hi-IN.ts +19 -0
  472. package/src/templates/default/app/i18n/ja-JP.ts +20 -0
  473. package/src/templates/default/app/i18n/ko-KR.ts +19 -0
  474. package/src/templates/default/app/i18n/pt-BR.ts +20 -0
  475. package/src/templates/default/app/i18n/zh-CN.ts +19 -0
  476. package/src/templates/default/app/i18n/zh-TW.ts +19 -0
  477. package/src/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
  478. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
  479. package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  480. package/src/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
  481. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  482. package/src/templates/workspace-core/AGENTS.md +1 -1
  483. package/src/templates/workspace-root/AGENTS.md +1 -1
  484. package/corpus/templates/analytics/server/handlers/github.ts +0 -200
  485. package/corpus/templates/analytics/server/handlers/pylon.ts +0 -43
  486. package/corpus/templates/analytics/server/lib/apollo.ts +0 -167
  487. package/corpus/templates/analytics/server/lib/commonroom.ts +0 -149
  488. package/corpus/templates/analytics/server/lib/github.ts +0 -660
  489. package/corpus/templates/analytics/server/lib/mixpanel.ts +0 -156
  490. package/corpus/templates/analytics/server/lib/posthog.ts +0 -194
  491. package/corpus/templates/analytics/server/lib/pylon.ts +0 -109
  492. package/corpus/templates/analytics/server/routes/api/github/graphql.post.ts +0 -1
  493. package/corpus/templates/analytics/server/routes/api/github/issue.get.ts +0 -1
  494. package/corpus/templates/analytics/server/routes/api/github/org-prs.get.ts +0 -1
  495. package/corpus/templates/analytics/server/routes/api/github/pr.get.ts +0 -1
  496. package/corpus/templates/analytics/server/routes/api/github/prs.get.ts +0 -1
  497. package/corpus/templates/analytics/server/routes/api/github/search.get.ts +0 -1
  498. package/corpus/templates/clips/actions/get-feature-flags.ts +0 -30
  499. package/corpus/templates/slides/actions/fetch-logos.ts +0 -90
  500. package/corpus/templates/slides/actions/image-search.ts +0 -64
  501. package/corpus/templates/slides/actions/import-github.ts +0 -182
  502. package/corpus/templates/slides/actions/logo-lookup.ts +0 -113
@@ -3,6 +3,7 @@ import * as jose from "jose";
3
3
  import { ssrfSafeFetch } from "../extensions/url-safety.js";
4
4
  import type {
5
5
  A2AApprovedAction,
6
+ A2AReadOnlyActionResult,
6
7
  AgentCard,
7
8
  JsonRpcRequest,
8
9
  JsonRpcResponse,
@@ -188,9 +189,19 @@ export class A2AClient {
188
189
  );
189
190
 
190
191
  if (res.ok) {
192
+ const text = await res.text();
193
+ if (
194
+ i < this.apiKeyAttempts.length - 1 &&
195
+ isA2AAuthRejectionResponse(res.status, text)
196
+ ) {
197
+ lastError = new Error(
198
+ `A2A request failed (${res.status}): ${text}`,
199
+ );
200
+ continue;
201
+ }
191
202
  this.endpointCandidates = [url];
192
203
  this.markApiKeySucceeded(this.apiKeyAttempts[i]);
193
- return res.json() as Promise<JsonRpcResponse>;
204
+ return JSON.parse(text) as JsonRpcResponse;
194
205
  }
195
206
 
196
207
  const text = await res.text();
@@ -272,6 +283,24 @@ export class A2AClient {
272
283
  return response.result as Task;
273
284
  }
274
285
 
286
+ /**
287
+ * Execute one receiver-approved read-only action without starting the
288
+ * receiver's agent loop. The receiver still owns validation, credentials,
289
+ * request scoping, and the explicit action exposure decision.
290
+ */
291
+ async invokeAction(
292
+ action: string,
293
+ input: Record<string, unknown> = {},
294
+ ): Promise<A2AReadOnlyActionResult> {
295
+ const response = await this.rpc("actions/invoke", { action, input });
296
+ if (response.error) {
297
+ throw new Error(
298
+ `A2A error (${response.error.code}): ${response.error.message}`,
299
+ );
300
+ }
301
+ return response.result as A2AReadOnlyActionResult;
302
+ }
303
+
275
304
  /**
276
305
  * Send a message in async mode and poll until the task reaches a terminal
277
306
  * state. This is the recommended path on serverless hosts with short
@@ -304,6 +333,38 @@ export class A2AClient {
304
333
  async: true,
305
334
  });
306
335
 
336
+ return this.pollTask(submitted, opts);
337
+ }
338
+
339
+ /**
340
+ * Continue waiting for an existing async task without submitting a second
341
+ * message. Use this after a bounded caller-side wait expires but the remote
342
+ * task is still working.
343
+ */
344
+ async waitForTask(
345
+ taskId: string,
346
+ opts?: {
347
+ /** Total time to wait for completion. Default 5 min. */
348
+ timeoutMs?: number;
349
+ /** Poll interval. Default 2s. */
350
+ pollIntervalMs?: number;
351
+ /** Called with each successfully polled task. */
352
+ onUpdate?: (task: Task) => void;
353
+ },
354
+ ): Promise<Task> {
355
+ const current = await this.getTask(taskId);
356
+ opts?.onUpdate?.(current);
357
+ return this.pollTask(current, opts);
358
+ }
359
+
360
+ private async pollTask(
361
+ submitted: Task,
362
+ opts?: {
363
+ timeoutMs?: number;
364
+ pollIntervalMs?: number;
365
+ onUpdate?: (task: Task) => void;
366
+ },
367
+ ): Promise<Task> {
307
368
  const terminalStates = new Set([
308
369
  "completed",
309
370
  "failed",
@@ -532,6 +593,7 @@ function uniqueAuthTokens(
532
593
  function isA2AAuthRejectionResponse(status: number, text: string): boolean {
533
594
  return (
534
595
  status === 401 ||
596
+ /verified, audience-bound user identity/i.test(text) ||
535
597
  /A2A error \(-32001\): (?:Invalid or expired A2A token|Invalid API key|Authentication required)|Invalid or expired A2A token|Invalid API key|Authentication required/i.test(
536
598
  text,
537
599
  )
@@ -566,6 +628,11 @@ export async function callAgent(
566
628
  async?: boolean;
567
629
  /** Total time to wait for the polled task (default 5 min). */
568
630
  timeoutMs?: number;
631
+ /**
632
+ * Existing async task to keep polling. When set, no new message is sent.
633
+ * This prevents a caller-side timeout from duplicating downstream work.
634
+ */
635
+ taskId?: string;
569
636
  /** Poll interval for async calls. Primarily useful for tests/retries. */
570
637
  pollIntervalMs?: number;
571
638
  /**
@@ -615,17 +682,26 @@ export async function callAgent(
615
682
  });
616
683
  let task: Task;
617
684
  if (useAsync) {
618
- task = await client.sendAndWait(message, {
619
- contextId: opts?.contextId,
620
- metadata,
621
- ...(opts?.approvedActions?.length
622
- ? { approvedActions: opts.approvedActions }
623
- : {}),
624
- timeoutMs: opts?.timeoutMs,
625
- pollIntervalMs: opts?.pollIntervalMs,
626
- onUpdate: opts?.onUpdate,
627
- });
685
+ task = opts?.taskId
686
+ ? await client.waitForTask(opts.taskId, {
687
+ timeoutMs: opts.timeoutMs,
688
+ pollIntervalMs: opts.pollIntervalMs,
689
+ onUpdate: opts.onUpdate,
690
+ })
691
+ : await client.sendAndWait(message, {
692
+ contextId: opts?.contextId,
693
+ metadata,
694
+ ...(opts?.approvedActions?.length
695
+ ? { approvedActions: opts.approvedActions }
696
+ : {}),
697
+ timeoutMs: opts?.timeoutMs,
698
+ pollIntervalMs: opts?.pollIntervalMs,
699
+ onUpdate: opts?.onUpdate,
700
+ });
628
701
  } else {
702
+ if (opts?.taskId) {
703
+ throw new Error("Polling an existing A2A task requires async mode");
704
+ }
629
705
  task = await client.send(message, {
630
706
  contextId: opts?.contextId,
631
707
  metadata,
@@ -665,12 +741,52 @@ export async function callAgent(
665
741
  return "";
666
742
  }
667
743
 
668
- async function buildA2AApiKeyAttempts(opts?: {
669
- apiKey?: string;
670
- userEmail?: string;
671
- orgDomain?: string;
672
- orgSecret?: string;
673
- }): Promise<Array<string | undefined>> {
744
+ /**
745
+ * Invoke one receiver-approved read-only action with an audience-bound user
746
+ * token. Unlike conversational delegation, this never starts the receiver's
747
+ * model loop.
748
+ */
749
+ export async function callAction(
750
+ url: string,
751
+ action: string,
752
+ input: Record<string, unknown> = {},
753
+ opts?: {
754
+ apiKey?: string;
755
+ userEmail?: string;
756
+ orgDomain?: string;
757
+ orgSecret?: string;
758
+ requestTimeoutMs?: number;
759
+ },
760
+ ): Promise<A2AReadOnlyActionResult> {
761
+ const actionName = action.trim();
762
+ if (!actionName) throw new Error("A2A action name is required");
763
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
764
+ throw new Error("A2A action input must be an object");
765
+ }
766
+
767
+ const apiKeyAttempts = await buildA2AApiKeyAttempts(
768
+ opts,
769
+ normalizeA2AAudience(url),
770
+ );
771
+ const fallbackApiKeys = apiKeyAttempts
772
+ .slice(1)
773
+ .filter((token): token is string => token !== undefined);
774
+ const client = new A2AClient(url, apiKeyAttempts[0], {
775
+ fallbackApiKeys,
776
+ requestTimeoutMs: opts?.requestTimeoutMs,
777
+ });
778
+ return client.invokeAction(actionName, input);
779
+ }
780
+
781
+ async function buildA2AApiKeyAttempts(
782
+ opts?: {
783
+ apiKey?: string;
784
+ userEmail?: string;
785
+ orgDomain?: string;
786
+ orgSecret?: string;
787
+ },
788
+ audience?: string,
789
+ ): Promise<Array<string | undefined>> {
674
790
  const attempts: Array<string | undefined> = [];
675
791
  const add = (token: string | undefined) => {
676
792
  if (token === undefined || attempts.includes(token)) return;
@@ -685,6 +801,7 @@ async function buildA2AApiKeyAttempts(opts?: {
685
801
  add(
686
802
  await signA2AToken(opts.userEmail, opts.orgDomain, opts.orgSecret, {
687
803
  preferGlobalSecret: true,
804
+ audience,
688
805
  }),
689
806
  );
690
807
  } catch {
@@ -697,6 +814,7 @@ async function buildA2AApiKeyAttempts(opts?: {
697
814
  add(
698
815
  await signA2AToken(opts.userEmail, opts.orgDomain, opts.orgSecret, {
699
816
  preferGlobalSecret: false,
817
+ audience,
700
818
  }),
701
819
  );
702
820
  } catch {
@@ -709,6 +827,11 @@ async function buildA2AApiKeyAttempts(opts?: {
709
827
  return attempts;
710
828
  }
711
829
 
830
+ function normalizeA2AAudience(url: string): string {
831
+ const explicit = splitExplicitA2AEndpoint(url.replace(/\/$/, ""));
832
+ return (explicit?.baseUrl ?? url).replace(/\/$/, "");
833
+ }
834
+
712
835
  function isA2AAuthRejection(err: unknown): boolean {
713
836
  const message = err instanceof Error ? err.message : String(err ?? "");
714
837
  return /A2A request failed \(401\)|A2A error \(-32001\): (?:Invalid or expired A2A token|Invalid API key|Authentication required)|Invalid or expired A2A token|Invalid API key|Authentication required/i.test(
@@ -49,6 +49,8 @@ const A2A_QUEUED_DISPATCH_STUCK_AFTER_MS = 10_000;
49
49
  const A2A_PROCESSING_STUCK_AFTER_MS = 5 * 60 * 1000;
50
50
  const A2A_PROCESSING_HEARTBEAT_MS = 30_000;
51
51
  const MAX_A2A_APPROVED_ACTIONS = 10;
52
+ const MAX_A2A_DIRECT_ACTION_NAME_CHARS = 200;
53
+ const MAX_A2A_DIRECT_ACTION_INPUT_BYTES = 64 * 1024;
52
54
 
53
55
  function trustedApprovedActions(
54
56
  value: unknown,
@@ -1047,6 +1049,60 @@ async function handleCancel(
1047
1049
  return jsonRpcResult(0, sanitizeTaskForResponse(task));
1048
1050
  }
1049
1051
 
1052
+ async function handleInvokeReadOnlyAction(
1053
+ params: Record<string, unknown>,
1054
+ event: any,
1055
+ config: A2AConfig,
1056
+ ): Promise<JsonRpcResponse> {
1057
+ const action = typeof params.action === "string" ? params.action.trim() : "";
1058
+ const input = params.input ?? {};
1059
+
1060
+ if (!action) {
1061
+ return jsonRpcError(0, -32602, "Invalid params: action required");
1062
+ }
1063
+ if (action.length > MAX_A2A_DIRECT_ACTION_NAME_CHARS) {
1064
+ return jsonRpcError(0, -32602, "Invalid params: action is too long");
1065
+ }
1066
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
1067
+ return jsonRpcError(0, -32602, "Invalid params: input must be an object");
1068
+ }
1069
+ let inputBytes: number;
1070
+ try {
1071
+ inputBytes = Buffer.byteLength(JSON.stringify(input), "utf8");
1072
+ } catch {
1073
+ return jsonRpcError(0, -32602, "Invalid params: input must be JSON-safe");
1074
+ }
1075
+ if (inputBytes > MAX_A2A_DIRECT_ACTION_INPUT_BYTES) {
1076
+ return jsonRpcError(0, -32602, "Invalid params: input is too large");
1077
+ }
1078
+ if (
1079
+ !event?.context?.__a2aVerifiedEmail ||
1080
+ event?.context?.__a2aAudienceVerified !== true
1081
+ ) {
1082
+ return jsonRpcError(
1083
+ 0,
1084
+ -32001,
1085
+ "A verified, audience-bound user identity is required for direct action invocation",
1086
+ );
1087
+ }
1088
+ if (!config.executeReadOnlyAction) {
1089
+ return jsonRpcError(0, -32601, "Direct action invocation not supported");
1090
+ }
1091
+
1092
+ try {
1093
+ const result = await withA2ARequestContext(undefined, event, () =>
1094
+ config.executeReadOnlyAction!({
1095
+ action,
1096
+ input: input as Record<string, unknown>,
1097
+ }),
1098
+ );
1099
+ return jsonRpcResult(0, { action, ...result });
1100
+ } catch (error) {
1101
+ console.error(`[a2a] Direct action ${action} failed:`, error);
1102
+ return jsonRpcError(0, -32000, "Direct action invocation failed");
1103
+ }
1104
+ }
1105
+
1050
1106
  /**
1051
1107
  * H3-compatible JSON-RPC handler. Returns JSON directly (H3 serializes it).
1052
1108
  * Streaming is handled via H3's node response when needed.
@@ -1093,6 +1149,10 @@ export async function handleJsonRpcH3(
1093
1149
  const result = await handleCancel(params, event, config);
1094
1150
  return { ...result, id } as JsonRpcResponse;
1095
1151
  }
1152
+ case "actions/invoke": {
1153
+ const result = await handleInvokeReadOnlyAction(params, event, config);
1154
+ return { ...result, id } as JsonRpcResponse;
1155
+ }
1096
1156
  default:
1097
1157
  return jsonRpcError(id, -32601, `Method not found: ${body.method}`);
1098
1158
  }
@@ -4,11 +4,12 @@ export type { A2ATokenPayload } from "./server.js";
4
4
  export { generateAgentCard } from "./agent-card.js";
5
5
 
6
6
  // Client
7
- export { A2AClient, callAgent, signA2AToken } from "./client.js";
7
+ export { A2AClient, callAction, callAgent, signA2AToken } from "./client.js";
8
8
  export {
9
9
  AgentInvocationError,
10
10
  buildAgentInvocationPrompt,
11
11
  invokeAgent,
12
+ invokeAgentAction,
12
13
  looksLikeAgentUrl,
13
14
  resolveAgentInvocationTarget,
14
15
  } from "./invoke.js";
@@ -33,11 +34,15 @@ export type {
33
34
  Artifact,
34
35
  JsonRpcRequest,
35
36
  JsonRpcResponse,
37
+ A2AReadOnlyActionInvocation,
38
+ A2AReadOnlyActionResult,
36
39
  } from "./types.js";
37
40
  export type {
38
41
  AgentInvocationErrorCode,
42
+ AgentActionInvocationResult,
39
43
  AgentInvocationResult,
40
44
  AgentInvocationRuntime,
45
+ InvokeAgentActionOptions,
41
46
  InvokeAgentOptions,
42
47
  ResolveAgentInvocationTargetOptions,
43
48
  ResolvedAgentInvocationTarget,
@@ -3,11 +3,17 @@ import {
3
3
  findAgent as defaultFindAgent,
4
4
  type DiscoveredAgent,
5
5
  } from "../server/agent-discovery.js";
6
- import { callAgent as defaultCallAgent } from "./client.js";
6
+ import {
7
+ callAction as defaultCallAction,
8
+ callAgent as defaultCallAgent,
9
+ } from "./client.js";
10
+ import type { A2AReadOnlyActionResult } from "./types.js";
7
11
 
8
12
  export type AgentInvocationErrorCode =
9
13
  | "missing-target"
10
14
  | "missing-prompt"
15
+ | "missing-action"
16
+ | "invalid-input"
11
17
  | "invalid-url"
12
18
  | "self-call"
13
19
  | "not-found";
@@ -45,10 +51,17 @@ export interface AgentInvocationResult {
45
51
  responseText: string;
46
52
  }
47
53
 
54
+ export interface AgentActionInvocationResult {
55
+ target: ResolvedAgentInvocationTarget;
56
+ action: string;
57
+ result: A2AReadOnlyActionResult;
58
+ }
59
+
48
60
  export interface AgentInvocationRuntime {
49
61
  findAgent: typeof defaultFindAgent;
50
62
  discoverAgents: typeof defaultDiscoverAgents;
51
63
  callAgent: typeof defaultCallAgent;
64
+ callAction: typeof defaultCallAction;
52
65
  }
53
66
 
54
67
  export interface ResolveAgentInvocationTargetOptions {
@@ -72,6 +85,18 @@ export interface InvokeAgentOptions extends ResolveAgentInvocationTargetOptions
72
85
  runtime?: Partial<AgentInvocationRuntime>;
73
86
  }
74
87
 
88
+ export interface InvokeAgentActionOptions extends ResolveAgentInvocationTargetOptions {
89
+ target: string;
90
+ action: string;
91
+ input?: Record<string, unknown>;
92
+ apiKey?: string;
93
+ userEmail?: string;
94
+ orgDomain?: string;
95
+ orgSecret?: string;
96
+ requestTimeoutMs?: number;
97
+ runtime?: Partial<AgentInvocationRuntime>;
98
+ }
99
+
75
100
  /**
76
101
  * Resolve an A2A invocation target from a direct URL or from the connected app
77
102
  * registry. ID/name resolution deliberately uses the same discovery path as
@@ -181,6 +206,48 @@ export async function invokeAgent(
181
206
  };
182
207
  }
183
208
 
209
+ /**
210
+ * Resolve another app and execute one explicitly exposed read-only action on
211
+ * it. This is the fast A2A path for bounded data operations that do not need a
212
+ * second model to plan or synthesize.
213
+ */
214
+ export async function invokeAgentAction(
215
+ options: InvokeAgentActionOptions,
216
+ ): Promise<AgentActionInvocationResult> {
217
+ const action = options.action.trim();
218
+ if (!action) {
219
+ throw new AgentInvocationError(
220
+ "missing-action",
221
+ "Error: action is required",
222
+ { target: options.target },
223
+ );
224
+ }
225
+ const input = options.input ?? {};
226
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
227
+ throw new AgentInvocationError(
228
+ "invalid-input",
229
+ "Error: action input must be an object",
230
+ { target: options.target },
231
+ );
232
+ }
233
+
234
+ const target = await resolveAgentInvocationTarget(options.target, {
235
+ selfAppId: options.selfAppId,
236
+ selfUrl: options.selfUrl,
237
+ runtime: options.runtime,
238
+ });
239
+ const callAction = options.runtime?.callAction ?? defaultCallAction;
240
+ const result = await callAction(target.url, action, input, {
241
+ apiKey: options.apiKey,
242
+ userEmail: options.userEmail,
243
+ orgDomain: options.orgDomain,
244
+ orgSecret: options.orgSecret,
245
+ requestTimeoutMs: options.requestTimeoutMs,
246
+ });
247
+
248
+ return { target, action, result };
249
+ }
250
+
184
251
  export function buildAgentInvocationPrompt(
185
252
  prompt: string,
186
253
  agentUrl: string,
@@ -79,7 +79,7 @@ function expectedJwtAudience(event: any | undefined): string | undefined {
79
79
  process.env.URL ||
80
80
  process.env.DEPLOY_URL ||
81
81
  process.env.BETTER_AUTH_URL;
82
- if (fromEnv) return String(fromEnv);
82
+ if (fromEnv) return String(fromEnv).replace(/\/$/, "");
83
83
  // Best-effort: derive from the inbound request host. This is forgeable
84
84
  // (Host-header attack), but only useful as a hint when env-derived URL
85
85
  // is unset; the rest of the JWT verification still uses the secret.
@@ -440,6 +440,7 @@ export function mountA2A(
440
440
  const bearerToken = extractBearerToken(authHeader);
441
441
  let verifiedCallerEmail: string | null = null;
442
442
  let verifiedOrgDomain: string | null = null;
443
+ let verifiedAudienceBound = false;
443
444
  let legacyApiKeyAuthenticated = false;
444
445
  let bearerTokenRejectedByJwt = false;
445
446
 
@@ -456,6 +457,14 @@ export function mountA2A(
456
457
  const tokenPayload = await verifyA2AToken(bearerToken, event);
457
458
  verifiedCallerEmail = tokenPayload.email;
458
459
  verifiedOrgDomain = tokenPayload.orgDomain;
460
+ if (verifiedCallerEmail) {
461
+ try {
462
+ verifiedAudienceBound =
463
+ typeof jose.decodeJwt(bearerToken).aud !== "undefined";
464
+ } catch {
465
+ verifiedAudienceBound = false;
466
+ }
467
+ }
459
468
  bearerTokenRejectedByJwt = !verifiedCallerEmail;
460
469
  }
461
470
 
@@ -532,6 +541,9 @@ export function mountA2A(
532
541
  if (verifiedCallerEmail) {
533
542
  event.context.__a2aVerifiedEmail = verifiedCallerEmail;
534
543
  }
544
+ if (verifiedAudienceBound) {
545
+ event.context.__a2aAudienceVerified = true;
546
+ }
535
547
  if (verifiedOrgDomain) {
536
548
  event.context.__a2aOrgDomain = verifiedOrgDomain;
537
549
  }
@@ -164,6 +164,18 @@ export interface A2AApprovalExecution {
164
164
  callId: string;
165
165
  }
166
166
 
167
+ /** One explicitly exposed read-only app action invoked without an agent loop. */
168
+ export interface A2AReadOnlyActionInvocation {
169
+ action: string;
170
+ input: Record<string, unknown>;
171
+ }
172
+
173
+ export interface A2AReadOnlyActionResult {
174
+ action: string;
175
+ status: "completed" | "failed";
176
+ output: string;
177
+ }
178
+
167
179
  export type A2AHandler = (
168
180
  message: Message,
169
181
  context: A2AHandlerContext,
@@ -186,4 +198,8 @@ export interface A2AConfig {
186
198
  status: "completed" | "failed";
187
199
  output: string;
188
200
  }>;
201
+ /** Execute an explicitly exposed read-only action without starting a model. */
202
+ executeReadOnlyAction?: (
203
+ invocation: A2AReadOnlyActionInvocation,
204
+ ) => Promise<Pick<A2AReadOnlyActionResult, "status" | "output">>;
189
205
  }
@@ -0,0 +1,52 @@
1
+ import * as jose from "jose";
2
+
3
+ import { verifyA2AToken } from "./a2a/server.js";
4
+
5
+ export interface VerifiedA2AClaims {
6
+ email: string;
7
+ orgId: string;
8
+ jti: string;
9
+ issuer?: string;
10
+ scope: string[];
11
+ }
12
+
13
+ /** Typed opt-in claims check; legacy A2A verification remains unchanged. */
14
+ export async function verifyA2ATokenWithClaims(
15
+ token: string,
16
+ event?: any,
17
+ ): Promise<VerifiedA2AClaims | null> {
18
+ const identity = await verifyA2AToken(token, event);
19
+ if (!identity.email) return null;
20
+ try {
21
+ const raw = jose.decodeJwt(token);
22
+ const audiences = Array.isArray(raw.aud)
23
+ ? raw.aud.filter((value): value is string => typeof value === "string")
24
+ : typeof raw.aud === "string"
25
+ ? [raw.aud]
26
+ : [];
27
+ // Legacy A2A callers may omit `aud`, but privileged fleet-management
28
+ // delegation never may. verifyA2AToken already proves a declared audience
29
+ // matches this receiver; this opt-in claims layer makes its presence
30
+ // mandatory before exposing administrative scopes.
31
+ if (audiences.length === 0 || audiences.some((value) => !value.trim()))
32
+ return null;
33
+ const orgId = typeof raw.org_id === "string" ? raw.org_id.trim() : "";
34
+ const jti = typeof raw.jti === "string" ? raw.jti.trim() : "";
35
+ const scopes =
36
+ typeof raw.scope === "string"
37
+ ? raw.scope.split(/\s+/).filter(Boolean)
38
+ : [];
39
+ const issuer = typeof raw.iss === "string" ? raw.iss.trim() : "";
40
+ return orgId && jti
41
+ ? {
42
+ email: identity.email,
43
+ orgId,
44
+ jti,
45
+ ...(issuer ? { issuer } : {}),
46
+ scope: scopes,
47
+ }
48
+ : null;
49
+ } catch {
50
+ return null;
51
+ }
52
+ }
@@ -24,8 +24,9 @@ import type { ActionAuditConfig } from "./audit/types.js";
24
24
  * `callAction` (tagged with the `X-Request-Source` header).
25
25
  * - `"cli"` — `pnpm action <name>` (the CLI runner).
26
26
  * - `"mcp"` — an external agent over the MCP `tools/call` endpoint.
27
- * - `"a2a"` — a direct A2A action dispatch (currently unused: A2A runs through
28
- * the agent loop, so those calls are `"tool"`). Reserved for completeness.
27
+ * - `"a2a"` — a direct, explicitly exposed read-only A2A action dispatch.
28
+ * Natural-language A2A delegation still runs through the agent loop and its
29
+ * selected actions are attributed as `"tool"`.
29
30
  */
30
31
  export type ActionCaller = "tool" | "http" | "frontend" | "cli" | "mcp" | "a2a";
31
32
 
@@ -55,6 +56,10 @@ export interface ActionRunContext {
55
56
  orgId?: string | null;
56
57
  /** How this action was invoked. */
57
58
  caller: ActionCaller;
59
+ /** Verified network lineage for direct delegated action calls. */
60
+ networkProtocol?: "a2a" | "mcp" | "provider-api";
61
+ networkId?: string;
62
+ networkPeer?: string;
58
63
  /**
59
64
  * Attachments submitted with the current agent turn (pasted text blocks,
60
65
  * uploaded files, images), exactly as the server received them — with full,
@@ -8,7 +8,7 @@ import {
8
8
  } from "h3";
9
9
  import type { EventHandler as H3EventHandler } from "h3";
10
10
 
11
- import { isAgentActionStopError } from "../action.js";
11
+ import { isAgentActionStopError, type ActionCaller } from "../action.js";
12
12
  import { readAppState } from "../application-state/script-helpers.js";
13
13
  import { isReadOnlyShellCommand } from "../coding-tools/index.js";
14
14
  import { extensionIdFromPathname } from "../extensions/path.js";
@@ -2479,6 +2479,8 @@ export interface ExecuteAgentToolCallOptions {
2479
2479
  signal?: AbortSignal;
2480
2480
  ownerEmail?: string | null;
2481
2481
  orgId?: string | null;
2482
+ /** Audit/action attribution for this externally selected call. */
2483
+ caller?: ActionCaller;
2482
2484
  threadId?: string;
2483
2485
  turnId?: string;
2484
2486
  approvedToolCalls?: string[];
@@ -2573,6 +2575,7 @@ export async function executeAgentToolCall(
2573
2575
  signal,
2574
2576
  ownerEmail: options.ownerEmail,
2575
2577
  orgId: options.orgId,
2578
+ actionCaller: options.caller,
2576
2579
  executionMode: "act",
2577
2580
  maxIterations: 2,
2578
2581
  threadId: options.threadId,
@@ -3152,6 +3155,8 @@ export async function runAgentLoop(opts: {
3152
3155
  signal: AbortSignal;
3153
3156
  ownerEmail?: string | null;
3154
3157
  orgId?: string | null;
3158
+ /** Action invocation attribution. Defaults to the normal agent tool loop. */
3159
+ actionCaller?: ActionCaller;
3155
3160
  /**
3156
3161
  * Attachments submitted with this turn (pasted text, files, images), passed
3157
3162
  * through to each tool's `ActionRunContext.attachments` so actions can
@@ -4102,6 +4107,7 @@ export async function runAgentLoop(opts: {
4102
4107
  requestedActionStop ??= {
4103
4108
  message:
4104
4109
  `Stopped because ${toolCall.name} failed ${count} times with the same arguments and error. ` +
4110
+ `Last error: ${sanitizedResult} ` +
4105
4111
  "Fix the underlying issue or change the arguments before retrying.",
4106
4112
  errorCode: "repeated_identical_tool_error",
4107
4113
  };
@@ -4208,7 +4214,7 @@ export async function runAgentLoop(opts: {
4208
4214
  await actionEntry.needsApproval(toolCall.input, {
4209
4215
  userEmail: getRequestUserEmail(),
4210
4216
  orgId: getRequestOrgId() ?? null,
4211
- caller: "tool",
4217
+ caller: opts.actionCaller ?? "tool",
4212
4218
  }),
4213
4219
  )
4214
4220
  : actionEntry.needsApproval === true;
@@ -4242,7 +4248,7 @@ export async function runAgentLoop(opts: {
4242
4248
  args: toolCall.input,
4243
4249
  ctx: {
4244
4250
  actionName: toolCall.name,
4245
- caller: "tool",
4251
+ caller: opts.actionCaller ?? "tool",
4246
4252
  userEmail: getRequestUserEmail(),
4247
4253
  orgId: getRequestOrgId() ?? null,
4248
4254
  ...(opts.threadId ? { threadId: opts.threadId } : {}),
@@ -4638,7 +4644,7 @@ export async function runAgentLoop(opts: {
4638
4644
  send,
4639
4645
  userEmail: actionUserEmail ?? undefined,
4640
4646
  orgId: actionOrgId,
4641
- caller: "tool" as const,
4647
+ caller: opts.actionCaller ?? "tool",
4642
4648
  attachments: opts.attachments,
4643
4649
  signal,
4644
4650
  // Audit attribution: the action name + the agent thread/turn that
@@ -31,6 +31,9 @@ export interface AuditRunContextLike {
31
31
  orgId?: string | null;
32
32
  threadId?: string;
33
33
  turnId?: string;
34
+ networkProtocol?: "a2a" | "mcp" | "provider-api";
35
+ networkId?: string;
36
+ networkPeer?: string;
34
37
  }
35
38
 
36
39
  export interface RecordActionAuditInput {
@@ -134,6 +137,9 @@ export async function recordActionAudit(
134
137
  // otherwise to the actor (the common self-mutation case).
135
138
  ownerEmail: target?.ownerEmail ?? actorEmail,
136
139
  visibility: target?.visibility ?? "private",
140
+ networkProtocol: ctx?.networkProtocol ?? null,
141
+ networkId: ctx?.networkId ?? null,
142
+ networkPeer: ctx?.networkPeer ?? null,
137
143
  };
138
144
  const lineage = getIntegrationRequestContext()?.lineage;
139
145
  const integration = getIntegrationRequestContext();