@agent-native/core 0.108.0 → 0.109.1

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 (368) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +25 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/a2a/client.ts +162 -17
  5. package/corpus/core/src/a2a/correlation.ts +50 -0
  6. package/corpus/core/src/a2a/handlers.ts +200 -14
  7. package/corpus/core/src/a2a/index.ts +7 -1
  8. package/corpus/core/src/a2a/invoke.ts +77 -1
  9. package/corpus/core/src/a2a/server.ts +13 -1
  10. package/corpus/core/src/a2a/task-store.ts +146 -6
  11. package/corpus/core/src/a2a/types.ts +32 -0
  12. package/corpus/core/src/action.ts +5 -2
  13. package/corpus/core/src/agent/production-agent.ts +33 -4
  14. package/corpus/core/src/client/AssistantChat.tsx +648 -603
  15. package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -4
  16. package/corpus/core/src/client/agent-chat-adapter.ts +23 -37
  17. package/corpus/core/src/client/agent-sidebar-state.ts +4 -0
  18. package/corpus/core/src/client/analytics.ts +84 -0
  19. package/corpus/core/src/client/chat/message-components.tsx +94 -22
  20. package/corpus/core/src/client/chat/tool-call-display.tsx +170 -47
  21. package/corpus/core/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
  22. package/corpus/core/src/client/chat-thread-url.ts +11 -0
  23. package/corpus/core/src/client/error-capture.ts +12 -0
  24. package/corpus/core/src/client/extensions/ExtensionSlot.tsx +37 -1
  25. package/corpus/core/src/client/index.ts +2 -0
  26. package/corpus/core/src/client/route-chunk-recovery.ts +20 -8
  27. package/corpus/core/src/client/session-replay.ts +31 -0
  28. package/corpus/core/src/client/use-run-stuck-detection.ts +27 -1
  29. package/corpus/core/src/db/client.ts +55 -0
  30. package/corpus/core/src/extensions/actions.ts +2 -14
  31. package/corpus/core/src/extensions/store.ts +1 -1
  32. package/corpus/core/src/localization/default-messages.ts +3 -0
  33. package/corpus/core/src/mcp/build-server.ts +2 -2
  34. package/corpus/core/src/observability/traces.ts +172 -19
  35. package/corpus/core/src/progress/actions.ts +4 -2
  36. package/corpus/core/src/provider-api/index.ts +205 -105
  37. package/corpus/core/src/scripts/call-agent.ts +190 -19
  38. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +112 -25
  39. package/corpus/core/src/server/agent-chat-plugin.ts +136 -4
  40. package/corpus/core/src/styles/agent-conversation.css +7 -0
  41. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +20 -0
  42. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +20 -0
  43. package/corpus/core/src/templates/default/app/i18n/en-US.ts +20 -0
  44. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +20 -0
  45. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
  46. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +19 -0
  47. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +20 -0
  48. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +19 -0
  49. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +20 -0
  50. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +19 -0
  51. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
  52. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  53. package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  54. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  55. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  56. package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  57. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -10
  58. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +54 -23
  59. package/corpus/templates/analytics/.builder/skills/apollo/SKILL.md +19 -41
  60. package/corpus/templates/analytics/.builder/skills/commonroom/SKILL.md +20 -35
  61. package/corpus/templates/analytics/.builder/skills/github/SKILL.md +23 -67
  62. package/corpus/templates/analytics/.builder/skills/pylon/SKILL.md +25 -43
  63. package/corpus/templates/analytics/AGENTS.md +22 -13
  64. package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
  65. package/corpus/templates/analytics/actions/configure-gong-native-insights.ts +29 -0
  66. package/corpus/templates/analytics/actions/content-calendar-schema.ts +8 -4
  67. package/corpus/templates/analytics/actions/content-calendar.ts +12 -4
  68. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -1
  69. package/corpus/templates/analytics/actions/gong-calls.ts +113 -22
  70. package/corpus/templates/analytics/actions/gong-native-insights.ts +166 -0
  71. package/corpus/templates/analytics/actions/hubspot-deals.ts +190 -46
  72. package/corpus/templates/analytics/actions/pylon-issues.ts +123 -0
  73. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  74. package/corpus/templates/analytics/actions/slack-messages.ts +179 -27
  75. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +48 -152
  76. package/corpus/templates/analytics/app/components/ui/chart.tsx +1 -1
  77. package/corpus/templates/analytics/app/hooks/use-chart-tooltip-flip.ts +21 -6
  78. package/corpus/templates/analytics/app/i18n/zh-TW.ts +13 -0
  79. package/corpus/templates/analytics/app/i18n-data.ts +134 -0
  80. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +181 -30
  81. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +6 -0
  82. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +4 -3
  83. package/corpus/templates/analytics/changelog/2026-07-17-analytics-now-includes-a-default-alert-for-spikes-in-stuck-agent-chats.md +6 -0
  84. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-editors-can-add-shared-extensions-or-opt-into-per-.md +6 -0
  85. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extensions-show-a-loading-skeleton.md +6 -0
  86. package/corpus/templates/analytics/changelog/2026-07-17-errors-now-group-repeat-failures-consistently-and-keep-priva.md +6 -0
  87. package/corpus/templates/analytics/changelog/2026-07-17-gong-transcript-reviews-now-batch-bounded-call-windows-for-f.md +6 -0
  88. package/corpus/templates/analytics/changelog/2026-07-17-hubspot-deal-filters-now-run-in-hubspot-before-paging-result.md +6 -0
  89. package/corpus/templates/analytics/changelog/2026-07-17-notion-content-calendars-now-discover-the-matching-database-.md +6 -0
  90. package/corpus/templates/analytics/changelog/2026-07-17-pylon-dashboard-reads-now-use-the-paginated-issue-search-api.md +6 -0
  91. package/corpus/templates/analytics/changelog/2026-07-17-slack-reads-no-longer-join-channels-and-report-pagination-coverage.md +6 -0
  92. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +23 -14
  93. package/corpus/templates/analytics/docs/schemas/tracked-events.md +5 -1
  94. package/corpus/templates/analytics/server/handlers/notion.ts +14 -3
  95. package/corpus/templates/analytics/server/handlers/slack.ts +182 -29
  96. package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +3 -3
  97. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -6
  98. package/corpus/templates/analytics/server/lib/analytics-alerts.ts +209 -87
  99. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +6 -2
  100. package/corpus/templates/analytics/server/lib/error-capture.ts +75 -8
  101. package/corpus/templates/analytics/server/lib/gong-native-policy.ts +72 -0
  102. package/corpus/templates/analytics/server/lib/gong.ts +54 -66
  103. package/corpus/templates/analytics/server/lib/hubspot.ts +40 -3
  104. package/corpus/templates/analytics/server/lib/notion.ts +83 -8
  105. package/corpus/templates/analytics/server/lib/real-data-actions.ts +4 -0
  106. package/corpus/templates/analytics/server/lib/slack.ts +242 -90
  107. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -3
  108. package/corpus/templates/analytics/server/routes/api/pylon/accounts.get.ts +42 -1
  109. package/corpus/templates/analytics/server/routes/api/pylon/issues.get.ts +71 -1
  110. package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +44 -4
  111. package/corpus/templates/clips/actions/finalize-recording.ts +541 -62
  112. package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +19 -1
  113. package/corpus/templates/clips/app/components/library/create-folder-dialog.tsx +123 -0
  114. package/corpus/templates/clips/app/components/library/library-grid.tsx +42 -4
  115. package/corpus/templates/clips/app/components/library/recording-card.tsx +30 -0
  116. package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +17 -2
  117. package/corpus/templates/clips/app/components/player/video-player.tsx +14 -2
  118. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +2 -2
  119. package/corpus/templates/clips/app/entry.client.tsx +6 -1
  120. package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -1
  121. package/corpus/templates/clips/app/i18n/de-DE.ts +12 -1
  122. package/corpus/templates/clips/app/i18n/en-US.ts +12 -1
  123. package/corpus/templates/clips/app/i18n/es-ES.ts +11 -1
  124. package/corpus/templates/clips/app/i18n/fr-FR.ts +11 -1
  125. package/corpus/templates/clips/app/i18n/hi-IN.ts +10 -1
  126. package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -1
  127. package/corpus/templates/clips/app/i18n/ko-KR.ts +11 -1
  128. package/corpus/templates/clips/app/i18n/pt-BR.ts +11 -1
  129. package/corpus/templates/clips/app/i18n/zh-CN.ts +11 -1
  130. package/corpus/templates/clips/app/i18n/zh-TW.ts +11 -1
  131. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +72 -1
  132. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
  133. package/corpus/templates/clips/app/routes/record.tsx +3 -3
  134. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -3
  135. package/corpus/templates/clips/changelog/2026-07-17-choose-which-workspace-receives-new-clips-recordings-and-des.md +6 -0
  136. package/corpus/templates/clips/changelog/2026-07-17-clips-now-retries-storage-verification-in-the-background-ins.md +6 -0
  137. package/corpus/templates/clips/changelog/2026-07-17-create-folders-directly-from-the-move-menu.md +6 -0
  138. package/corpus/templates/clips/changelog/2026-07-17-failed-desktop-uploads-now-offer-a-direct-way-to-reopen-clip.md +6 -0
  139. package/corpus/templates/clips/changelog/2026-07-17-fixed-broken-thumbnail-icons-appearing-over-playable-clip-em.md +6 -0
  140. package/corpus/templates/clips/changelog/2026-07-17-playback-comments-stay-readable-at-faster-playback-speeds.md +6 -0
  141. package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +3 -0
  142. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +3 -3
  143. package/corpus/templates/clips/desktop/src/app.tsx +19 -7
  144. package/corpus/templates/clips/desktop/src/lib/recorder.ts +111 -13
  145. package/corpus/templates/clips/desktop/src/lib/upload-verification.ts +16 -7
  146. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -4
  147. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +32 -15
  148. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +45 -18
  149. package/corpus/templates/clips/server/jobs/media-verification.ts +130 -0
  150. package/corpus/templates/clips/server/lib/builder-media-compression.ts +15 -0
  151. package/corpus/templates/clips/server/lib/media-verification-state.ts +38 -0
  152. package/corpus/templates/clips/server/lib/player-thumbnail-url.ts +31 -0
  153. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +10 -3
  154. package/corpus/templates/clips/server/plugins/auth.ts +5 -5
  155. package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
  156. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +12 -2
  157. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +6 -1
  158. package/corpus/templates/clips/server/routes/api/thumbnail/[recordingId].get.ts +340 -0
  159. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +24 -7
  160. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +91 -7
  161. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +14 -0
  162. package/corpus/templates/clips/shared/finalize-recovery.ts +61 -2
  163. package/corpus/templates/clips/shared/share-meta.ts +1 -1
  164. package/corpus/templates/content/app/entry.client.tsx +6 -1
  165. package/corpus/templates/dispatch/AGENTS.md +5 -0
  166. package/corpus/templates/dispatch/changelog/2026-07-17-apps-page-links-to-other-available-apps.md +6 -0
  167. package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +6 -0
  168. package/corpus/templates/mail/app/entry.client.tsx +6 -1
  169. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +11 -7
  170. package/corpus/templates/slides/.env.example +0 -1
  171. package/corpus/templates/slides/AGENTS.md +4 -0
  172. package/corpus/templates/slides/DEVELOPING.md +2 -2
  173. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
  174. package/corpus/templates/slides/actions/logo-config.ts +6 -7
  175. package/corpus/templates/slides/actions/search-images.ts +11 -39
  176. package/corpus/templates/slides/actions/search-logos.ts +5 -52
  177. package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +1 -1
  178. package/corpus/templates/slides/app/components/editor/LogoSearchPanel.tsx +16 -26
  179. package/corpus/templates/slides/app/entry.client.tsx +6 -1
  180. package/corpus/templates/slides/server/lib/media-search-providers.ts +216 -0
  181. package/corpus/templates/slides/server/register-secrets.ts +30 -0
  182. package/dist/a2a/client.d.ts +47 -1
  183. package/dist/a2a/client.d.ts.map +1 -1
  184. package/dist/a2a/client.js +94 -12
  185. package/dist/a2a/client.js.map +1 -1
  186. package/dist/a2a/correlation.d.ts +10 -0
  187. package/dist/a2a/correlation.d.ts.map +1 -0
  188. package/dist/a2a/correlation.js +40 -0
  189. package/dist/a2a/correlation.js.map +1 -0
  190. package/dist/a2a/handlers.d.ts.map +1 -1
  191. package/dist/a2a/handlers.js +147 -15
  192. package/dist/a2a/handlers.js.map +1 -1
  193. package/dist/a2a/index.d.ts +4 -4
  194. package/dist/a2a/index.d.ts.map +1 -1
  195. package/dist/a2a/index.js +2 -2
  196. package/dist/a2a/index.js.map +1 -1
  197. package/dist/a2a/invoke.d.ts +29 -2
  198. package/dist/a2a/invoke.d.ts.map +1 -1
  199. package/dist/a2a/invoke.js +33 -1
  200. package/dist/a2a/invoke.js.map +1 -1
  201. package/dist/a2a/server.d.ts.map +1 -1
  202. package/dist/a2a/server.js +14 -1
  203. package/dist/a2a/server.js.map +1 -1
  204. package/dist/a2a/task-store.d.ts +12 -1
  205. package/dist/a2a/task-store.d.ts.map +1 -1
  206. package/dist/a2a/task-store.js +96 -6
  207. package/dist/a2a/task-store.js.map +1 -1
  208. package/dist/a2a/types.d.ts +27 -0
  209. package/dist/a2a/types.d.ts.map +1 -1
  210. package/dist/a2a/types.js.map +1 -1
  211. package/dist/action.d.ts +5 -2
  212. package/dist/action.d.ts.map +1 -1
  213. package/dist/action.js.map +1 -1
  214. package/dist/agent/production-agent.d.ts +14 -0
  215. package/dist/agent/production-agent.d.ts.map +1 -1
  216. package/dist/agent/production-agent.js +19 -3
  217. package/dist/agent/production-agent.js.map +1 -1
  218. package/dist/client/AssistantChat.d.ts +14 -1
  219. package/dist/client/AssistantChat.d.ts.map +1 -1
  220. package/dist/client/AssistantChat.js +158 -136
  221. package/dist/client/AssistantChat.js.map +1 -1
  222. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  223. package/dist/client/MultiTabAssistantChat.js +27 -4
  224. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  225. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  226. package/dist/client/agent-chat-adapter.js +21 -39
  227. package/dist/client/agent-chat-adapter.js.map +1 -1
  228. package/dist/client/agent-sidebar-state.d.ts +1 -0
  229. package/dist/client/agent-sidebar-state.d.ts.map +1 -1
  230. package/dist/client/agent-sidebar-state.js +4 -0
  231. package/dist/client/agent-sidebar-state.js.map +1 -1
  232. package/dist/client/analytics.d.ts +14 -0
  233. package/dist/client/analytics.d.ts.map +1 -1
  234. package/dist/client/analytics.js +67 -0
  235. package/dist/client/analytics.js.map +1 -1
  236. package/dist/client/chat/message-components.d.ts +8 -0
  237. package/dist/client/chat/message-components.d.ts.map +1 -1
  238. package/dist/client/chat/message-components.js +62 -19
  239. package/dist/client/chat/message-components.js.map +1 -1
  240. package/dist/client/chat/tool-call-display.d.ts +6 -0
  241. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  242. package/dist/client/chat/tool-call-display.js +83 -14
  243. package/dist/client/chat/tool-call-display.js.map +1 -1
  244. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts +8 -0
  245. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts.map +1 -0
  246. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js +51 -0
  247. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js.map +1 -0
  248. package/dist/client/chat-thread-url.d.ts +2 -0
  249. package/dist/client/chat-thread-url.d.ts.map +1 -0
  250. package/dist/client/chat-thread-url.js +12 -0
  251. package/dist/client/chat-thread-url.js.map +1 -0
  252. package/dist/client/error-capture.d.ts.map +1 -1
  253. package/dist/client/error-capture.js +7 -0
  254. package/dist/client/error-capture.js.map +1 -1
  255. package/dist/client/extensions/ExtensionSlot.d.ts +3 -1
  256. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  257. package/dist/client/extensions/ExtensionSlot.js +28 -3
  258. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  259. package/dist/client/index.d.ts +1 -1
  260. package/dist/client/index.d.ts.map +1 -1
  261. package/dist/client/index.js +1 -1
  262. package/dist/client/index.js.map +1 -1
  263. package/dist/client/route-chunk-recovery.d.ts.map +1 -1
  264. package/dist/client/route-chunk-recovery.js +14 -9
  265. package/dist/client/route-chunk-recovery.js.map +1 -1
  266. package/dist/client/session-replay.d.ts +15 -0
  267. package/dist/client/session-replay.d.ts.map +1 -1
  268. package/dist/client/session-replay.js +20 -0
  269. package/dist/client/session-replay.js.map +1 -1
  270. package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
  271. package/dist/client/use-run-stuck-detection.js +25 -1
  272. package/dist/client/use-run-stuck-detection.js.map +1 -1
  273. package/dist/db/client.d.ts +7 -0
  274. package/dist/db/client.d.ts.map +1 -1
  275. package/dist/db/client.js +33 -0
  276. package/dist/db/client.js.map +1 -1
  277. package/dist/extensions/actions.d.ts.map +1 -1
  278. package/dist/extensions/actions.js +2 -10
  279. package/dist/extensions/actions.js.map +1 -1
  280. package/dist/extensions/store.js +1 -1
  281. package/dist/extensions/store.js.map +1 -1
  282. package/dist/localization/default-messages.d.ts +3 -0
  283. package/dist/localization/default-messages.d.ts.map +1 -1
  284. package/dist/localization/default-messages.js +3 -0
  285. package/dist/localization/default-messages.js.map +1 -1
  286. package/dist/mcp/build-server.d.ts +2 -0
  287. package/dist/mcp/build-server.d.ts.map +1 -1
  288. package/dist/mcp/build-server.js +2 -2
  289. package/dist/mcp/build-server.js.map +1 -1
  290. package/dist/notifications/routes.d.ts +2 -2
  291. package/dist/observability/routes.d.ts +5 -5
  292. package/dist/observability/traces.d.ts +9 -0
  293. package/dist/observability/traces.d.ts.map +1 -1
  294. package/dist/observability/traces.js +137 -19
  295. package/dist/observability/traces.js.map +1 -1
  296. package/dist/progress/actions.d.ts.map +1 -1
  297. package/dist/progress/actions.js +3 -2
  298. package/dist/progress/actions.js.map +1 -1
  299. package/dist/progress/routes.d.ts +1 -1
  300. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  301. package/dist/provider-api/index.d.ts.map +1 -1
  302. package/dist/provider-api/index.js +91 -8
  303. package/dist/provider-api/index.js.map +1 -1
  304. package/dist/scripts/call-agent.d.ts.map +1 -1
  305. package/dist/scripts/call-agent.js +140 -17
  306. package/dist/scripts/call-agent.js.map +1 -1
  307. package/dist/secrets/routes.d.ts +9 -9
  308. package/dist/server/agent-chat/action-filters-a2a.d.ts +24 -2
  309. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  310. package/dist/server/agent-chat/action-filters-a2a.js +62 -7
  311. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  312. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  313. package/dist/server/agent-chat-plugin.js +118 -5
  314. package/dist/server/agent-chat-plugin.js.map +1 -1
  315. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  316. package/dist/server/transcribe-voice.d.ts +1 -1
  317. package/dist/styles/agent-conversation.css +7 -0
  318. package/dist/templates/default/app/i18n/ar-SA.ts +20 -0
  319. package/dist/templates/default/app/i18n/de-DE.ts +20 -0
  320. package/dist/templates/default/app/i18n/en-US.ts +20 -0
  321. package/dist/templates/default/app/i18n/es-ES.ts +20 -0
  322. package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
  323. package/dist/templates/default/app/i18n/hi-IN.ts +19 -0
  324. package/dist/templates/default/app/i18n/ja-JP.ts +20 -0
  325. package/dist/templates/default/app/i18n/ko-KR.ts +19 -0
  326. package/dist/templates/default/app/i18n/pt-BR.ts +20 -0
  327. package/dist/templates/default/app/i18n/zh-CN.ts +19 -0
  328. package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
  329. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  330. package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  331. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  332. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  333. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  334. package/package.json +1 -1
  335. package/src/templates/default/app/i18n/ar-SA.ts +20 -0
  336. package/src/templates/default/app/i18n/de-DE.ts +20 -0
  337. package/src/templates/default/app/i18n/en-US.ts +20 -0
  338. package/src/templates/default/app/i18n/es-ES.ts +20 -0
  339. package/src/templates/default/app/i18n/fr-FR.ts +21 -0
  340. package/src/templates/default/app/i18n/hi-IN.ts +19 -0
  341. package/src/templates/default/app/i18n/ja-JP.ts +20 -0
  342. package/src/templates/default/app/i18n/ko-KR.ts +19 -0
  343. package/src/templates/default/app/i18n/pt-BR.ts +20 -0
  344. package/src/templates/default/app/i18n/zh-CN.ts +19 -0
  345. package/src/templates/default/app/i18n/zh-TW.ts +19 -0
  346. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  347. package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  348. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  349. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  350. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  351. package/corpus/templates/analytics/server/handlers/github.ts +0 -200
  352. package/corpus/templates/analytics/server/handlers/pylon.ts +0 -43
  353. package/corpus/templates/analytics/server/lib/apollo.ts +0 -167
  354. package/corpus/templates/analytics/server/lib/commonroom.ts +0 -149
  355. package/corpus/templates/analytics/server/lib/github.ts +0 -660
  356. package/corpus/templates/analytics/server/lib/mixpanel.ts +0 -156
  357. package/corpus/templates/analytics/server/lib/posthog.ts +0 -194
  358. package/corpus/templates/analytics/server/lib/pylon.ts +0 -109
  359. package/corpus/templates/analytics/server/routes/api/github/graphql.post.ts +0 -1
  360. package/corpus/templates/analytics/server/routes/api/github/issue.get.ts +0 -1
  361. package/corpus/templates/analytics/server/routes/api/github/org-prs.get.ts +0 -1
  362. package/corpus/templates/analytics/server/routes/api/github/pr.get.ts +0 -1
  363. package/corpus/templates/analytics/server/routes/api/github/prs.get.ts +0 -1
  364. package/corpus/templates/analytics/server/routes/api/github/search.get.ts +0 -1
  365. package/corpus/templates/slides/actions/fetch-logos.ts +0 -90
  366. package/corpus/templates/slides/actions/image-search.ts +0 -64
  367. package/corpus/templates/slides/actions/import-github.ts +0 -182
  368. package/corpus/templates/slides/actions/logo-lookup.ts +0 -113
@@ -1,3 +1,5 @@
1
+ import crypto from "node:crypto";
2
+
1
3
  import { setResponseHeader, setResponseStatus } from "h3";
2
4
 
3
5
  import {
@@ -7,18 +9,22 @@ import {
7
9
  isAgentChatDurableBackgroundEnabled,
8
10
  resolveAgentChatProcessRunDispatchPath,
9
11
  } from "../agent/durable-background.js";
12
+ import { trackingIdentityProperties } from "../observability/tracking-identity.js";
10
13
  import { withConfiguredAppBasePath } from "../server/app-base-path.js";
11
14
  import { getOrigin, isConfiguredAppOrigin } from "../server/google-oauth.js";
12
15
  import { fireInternalDispatch } from "../server/self-dispatch.js";
13
16
  import { agentChat } from "../shared/agent-chat.js";
17
+ import { track } from "../tracking/registry.js";
14
18
  import {
15
19
  hasConfiguredA2ASecret,
16
20
  isA2AProductionRuntime,
17
21
  } from "./auth-policy.js";
22
+ import { sanitizeA2ACorrelationMetadata } from "./correlation.js";
18
23
  import {
19
24
  createTask,
25
+ createOrReuseTask,
20
26
  getTask,
21
- getTaskOwner,
27
+ getTaskOwnership,
22
28
  updateTask,
23
29
  claimA2ATaskForProcessing,
24
30
  getA2ATaskDispatchState,
@@ -28,6 +34,8 @@ import {
28
34
  touchQueuedA2ATaskDispatch,
29
35
  touchProcessingA2ATask,
30
36
  pauseProcessingA2ATask,
37
+ MAX_A2A_IDEMPOTENCY_KEY_CHARS,
38
+ A2A_PERSONAL_OWNER_SCOPE,
31
39
  } from "./task-store.js";
32
40
  import type {
33
41
  A2AApprovedAction,
@@ -49,6 +57,9 @@ const A2A_QUEUED_DISPATCH_STUCK_AFTER_MS = 10_000;
49
57
  const A2A_PROCESSING_STUCK_AFTER_MS = 5 * 60 * 1000;
50
58
  const A2A_PROCESSING_HEARTBEAT_MS = 30_000;
51
59
  const MAX_A2A_APPROVED_ACTIONS = 10;
60
+ const MAX_A2A_DIRECT_ACTION_NAME_CHARS = 200;
61
+ const MAX_A2A_DIRECT_ACTION_INPUT_BYTES = 64 * 1024;
62
+ const A2A_READ_INVOKE_EVENT = "$a2a_read_invoke";
52
63
 
53
64
  function trustedApprovedActions(
54
65
  value: unknown,
@@ -578,6 +589,22 @@ async function runHandlerAndPersist(
578
589
  }
579
590
  }
580
591
 
592
+ function verifiedTaskOwner(event?: any): {
593
+ ownerEmail: string | null;
594
+ ownerScope: string | null;
595
+ } {
596
+ const ownerEmail =
597
+ (event?.context?.__a2aVerifiedEmail as string | undefined) ?? null;
598
+ return {
599
+ ownerEmail,
600
+ ownerScope: ownerEmail
601
+ ? ((event?.context?.__a2aOrgDomain as string | undefined)
602
+ ?.trim()
603
+ .toLowerCase() ?? A2A_PERSONAL_OWNER_SCOPE)
604
+ : null,
605
+ };
606
+ }
607
+
581
608
  async function handleSend(
582
609
  params: Record<string, unknown>,
583
610
  config: A2AConfig,
@@ -604,8 +631,31 @@ async function handleSend(
604
631
  // on every subsequent tasks/get and tasks/cancel call. Caller-supplied
605
632
  // metadata.userEmail is NEVER used for ownership; that would re-introduce
606
633
  // the IDOR class fixed here.
607
- const ownerEmailForTask =
608
- (event?.context?.__a2aVerifiedEmail as string | undefined) ?? null;
634
+ const { ownerEmail: ownerEmailForTask, ownerScope: ownerScopeForTask } =
635
+ verifiedTaskOwner(event);
636
+ let idempotencyKey: string | undefined;
637
+ if (ownerEmailForTask && params.idempotencyKey !== undefined) {
638
+ if (typeof params.idempotencyKey !== "string") {
639
+ return {
640
+ ...jsonRpcError(
641
+ 0,
642
+ -32602,
643
+ "Invalid params: idempotencyKey must be a string",
644
+ ),
645
+ _id: 0,
646
+ };
647
+ }
648
+ idempotencyKey = params.idempotencyKey.trim();
649
+ if (
650
+ !idempotencyKey ||
651
+ idempotencyKey.length > MAX_A2A_IDEMPOTENCY_KEY_CHARS
652
+ ) {
653
+ return {
654
+ ...jsonRpcError(0, -32602, "Invalid params: idempotencyKey is invalid"),
655
+ _id: 0,
656
+ };
657
+ }
658
+ }
609
659
 
610
660
  // Async mode: return the task immediately in `working` state, run the
611
661
  // handler in the background, and let the caller poll `tasks/get`. This is
@@ -618,6 +668,7 @@ async function handleSend(
618
668
  // production — see the additional gate below.
619
669
  const asyncMode =
620
670
  params.async === true || (event && event.context?.__a2aForceAsync === true);
671
+ if (!asyncMode) idempotencyKey = undefined;
621
672
 
622
673
  if (asyncMode) {
623
674
  // Refuse async mode entirely when no auth is configured in production.
@@ -665,12 +716,20 @@ async function handleSend(
665
716
  approvedActions: approvedActions ?? null,
666
717
  },
667
718
  };
668
- const task = await createTask(
719
+ const { task, reused } = await createOrReuseTask(
669
720
  message,
670
721
  contextId,
671
722
  taskMetadata,
672
723
  ownerEmailForTask,
724
+ ownerScopeForTask,
725
+ idempotencyKey,
673
726
  );
727
+ if (reused) {
728
+ return {
729
+ ...jsonRpcResult(0, sanitizeTaskForResponse(task)),
730
+ _id: 0,
731
+ };
732
+ }
674
733
  const working = await updateTask(task.id, { state: "working" });
675
734
 
676
735
  // Awaited, not fire-and-forget: this handler is about to return, and a
@@ -693,12 +752,20 @@ async function handleSend(
693
752
  }
694
753
 
695
754
  return withA2ARequestContext(metadata, event, async () => {
696
- const task = await createTask(
755
+ const { task, reused } = await createOrReuseTask(
697
756
  message,
698
757
  contextId,
699
758
  undefined,
700
759
  ownerEmailForTask,
760
+ ownerScopeForTask,
761
+ idempotencyKey,
701
762
  );
763
+ if (reused) {
764
+ return {
765
+ ...jsonRpcResult(0, sanitizeTaskForResponse(task)),
766
+ _id: 0,
767
+ };
768
+ }
702
769
  await updateTask(task.id, { state: "working" });
703
770
 
704
771
  const ctx = makeHandlerContext(
@@ -788,8 +855,8 @@ async function handleStream(
788
855
  const contextId = params.contextId as string | undefined;
789
856
  const metadata = params.metadata as Record<string, unknown> | undefined;
790
857
  const approvedActions = trustedApprovedActions(params.approvedActions, event);
791
- const ownerEmailForTask =
792
- (event?.context?.__a2aVerifiedEmail as string | undefined) ?? null;
858
+ const { ownerEmail: ownerEmailForTask, ownerScope: ownerScopeForTask } =
859
+ verifiedTaskOwner(event);
793
860
 
794
861
  await withA2ARequestContext(metadata, event, async () => {
795
862
  const task = await createTask(
@@ -797,6 +864,7 @@ async function handleStream(
797
864
  contextId,
798
865
  undefined,
799
866
  ownerEmailForTask,
867
+ ownerScopeForTask,
800
868
  );
801
869
 
802
870
  await updateTask(task.id, { state: "working" });
@@ -877,16 +945,23 @@ const SENSITIVE_METADATA_KEYS = new Set([
877
945
 
878
946
  function sanitizeTaskForResponse(task: any): any {
879
947
  if (!task || typeof task !== "object") return task;
880
- if (!task.metadata || typeof task.metadata !== "object") return task;
948
+ const {
949
+ ownerEmail: _ownerEmail,
950
+ ownerScope: _ownerScope,
951
+ ...publicTask
952
+ } = task;
953
+ if (!publicTask.metadata || typeof publicTask.metadata !== "object") {
954
+ return publicTask;
955
+ }
881
956
 
882
- const meta = task.metadata as Record<string, unknown>;
957
+ const meta = publicTask.metadata as Record<string, unknown>;
883
958
  const publicMeta: Record<string, unknown> = {};
884
959
  for (const [k, v] of Object.entries(meta)) {
885
960
  if (k === "__a2a_processor") continue;
886
961
  if (SENSITIVE_METADATA_KEYS.has(k)) continue;
887
962
  publicMeta[k] = v;
888
963
  }
889
- return { ...task, metadata: publicMeta };
964
+ return { ...publicTask, metadata: publicMeta };
890
965
  }
891
966
 
892
967
  /**
@@ -905,6 +980,7 @@ function sanitizeTaskForResponse(task: any): any {
905
980
  */
906
981
  function authorizeTaskAccess(
907
982
  taskOwnerEmail: string | null,
983
+ taskOwnerScope: string | null,
908
984
  event: any,
909
985
  config: A2AConfig,
910
986
  ): JsonRpcResponse | null {
@@ -926,6 +1002,15 @@ function authorizeTaskAccess(
926
1002
  if (verifiedEmail.toLowerCase() !== taskOwnerEmail.toLowerCase()) {
927
1003
  return jsonRpcError(0, -32001, "Task not found");
928
1004
  }
1005
+ if (taskOwnerScope) {
1006
+ const verifiedScope =
1007
+ (event?.context?.__a2aOrgDomain as string | undefined)
1008
+ ?.trim()
1009
+ .toLowerCase() ?? A2A_PERSONAL_OWNER_SCOPE;
1010
+ if (verifiedScope !== taskOwnerScope.toLowerCase()) {
1011
+ return jsonRpcError(0, -32001, "Task not found");
1012
+ }
1013
+ }
929
1014
  }
930
1015
  // Legacy row (no owner_email recorded). The route-level auth gate is the
931
1016
  // only thing protecting it — fall through and serve.
@@ -941,8 +1026,13 @@ async function handleGet(
941
1026
  if (!id) {
942
1027
  return jsonRpcError(0, -32602, "Invalid params: id required");
943
1028
  }
944
- const ownerEmail = await getTaskOwner(id);
945
- const denied = authorizeTaskAccess(ownerEmail, event, config);
1029
+ const ownership = await getTaskOwnership(id);
1030
+ const denied = authorizeTaskAccess(
1031
+ ownership.ownerEmail,
1032
+ ownership.ownerScope,
1033
+ event,
1034
+ config,
1035
+ );
946
1036
  if (denied) return denied;
947
1037
 
948
1038
  const task = await getTask(id);
@@ -1036,8 +1126,13 @@ async function handleCancel(
1036
1126
  if (!id) {
1037
1127
  return jsonRpcError(0, -32602, "Invalid params: id required");
1038
1128
  }
1039
- const ownerEmail = await getTaskOwner(id);
1040
- const denied = authorizeTaskAccess(ownerEmail, event, config);
1129
+ const ownership = await getTaskOwnership(id);
1130
+ const denied = authorizeTaskAccess(
1131
+ ownership.ownerEmail,
1132
+ ownership.ownerScope,
1133
+ event,
1134
+ config,
1135
+ );
1041
1136
  if (denied) return denied;
1042
1137
 
1043
1138
  const task = await updateTask(id, { state: "canceled" });
@@ -1047,6 +1142,93 @@ async function handleCancel(
1047
1142
  return jsonRpcResult(0, sanitizeTaskForResponse(task));
1048
1143
  }
1049
1144
 
1145
+ async function handleInvokeReadOnlyAction(
1146
+ params: Record<string, unknown>,
1147
+ event: any,
1148
+ config: A2AConfig,
1149
+ ): Promise<JsonRpcResponse> {
1150
+ const action = typeof params.action === "string" ? params.action.trim() : "";
1151
+ const input = params.input ?? {};
1152
+
1153
+ if (!action) {
1154
+ return jsonRpcError(0, -32602, "Invalid params: action required");
1155
+ }
1156
+ if (action.length > MAX_A2A_DIRECT_ACTION_NAME_CHARS) {
1157
+ return jsonRpcError(0, -32602, "Invalid params: action is too long");
1158
+ }
1159
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
1160
+ return jsonRpcError(0, -32602, "Invalid params: input must be an object");
1161
+ }
1162
+ let inputBytes: number;
1163
+ try {
1164
+ inputBytes = Buffer.byteLength(JSON.stringify(input), "utf8");
1165
+ } catch {
1166
+ return jsonRpcError(0, -32602, "Invalid params: input must be JSON-safe");
1167
+ }
1168
+ if (inputBytes > MAX_A2A_DIRECT_ACTION_INPUT_BYTES) {
1169
+ return jsonRpcError(0, -32602, "Invalid params: input is too large");
1170
+ }
1171
+ if (
1172
+ !event?.context?.__a2aVerifiedEmail ||
1173
+ event?.context?.__a2aAudienceVerified !== true
1174
+ ) {
1175
+ return jsonRpcError(
1176
+ 0,
1177
+ -32001,
1178
+ "A verified, audience-bound user identity is required for direct action invocation",
1179
+ );
1180
+ }
1181
+ if (!config.executeReadOnlyAction) {
1182
+ return jsonRpcError(0, -32601, "Direct action invocation not supported");
1183
+ }
1184
+
1185
+ const startedAt = Date.now();
1186
+ const correlation = sanitizeA2ACorrelationMetadata(params.metadata);
1187
+ const invocationId = crypto.randomUUID();
1188
+ const verifiedEmail = event.context.__a2aVerifiedEmail as string;
1189
+ const emitTracking = (status: "completed" | "failed") => {
1190
+ const identity = trackingIdentityProperties();
1191
+ track(
1192
+ A2A_READ_INVOKE_EVENT,
1193
+ {
1194
+ ...identity,
1195
+ action,
1196
+ receiver_app: config.appId ?? identity.app ?? config.name,
1197
+ caller_app: correlation.callerApp ?? "unknown",
1198
+ duration_ms: Math.max(0, Date.now() - startedAt),
1199
+ status,
1200
+ invocation_id: invocationId,
1201
+ ...(correlation.parentRunId
1202
+ ? { parent_run_id: correlation.parentRunId }
1203
+ : {}),
1204
+ ...(correlation.parentTurnId
1205
+ ? { parent_turn_id: correlation.parentTurnId }
1206
+ : {}),
1207
+ ...(correlation.invocationId
1208
+ ? { caller_invocation_id: correlation.invocationId }
1209
+ : {}),
1210
+ },
1211
+ { userId: verifiedEmail },
1212
+ );
1213
+ };
1214
+
1215
+ try {
1216
+ const result = await withA2ARequestContext(undefined, event, () =>
1217
+ config.executeReadOnlyAction!({
1218
+ action,
1219
+ input: input as Record<string, unknown>,
1220
+ invocationId,
1221
+ }),
1222
+ );
1223
+ emitTracking(result.status);
1224
+ return jsonRpcResult(0, { action, ...result });
1225
+ } catch (error) {
1226
+ emitTracking("failed");
1227
+ console.error(`[a2a] Direct action ${action} failed:`, error);
1228
+ return jsonRpcError(0, -32000, "Direct action invocation failed");
1229
+ }
1230
+ }
1231
+
1050
1232
  /**
1051
1233
  * H3-compatible JSON-RPC handler. Returns JSON directly (H3 serializes it).
1052
1234
  * Streaming is handled via H3's node response when needed.
@@ -1093,6 +1275,10 @@ export async function handleJsonRpcH3(
1093
1275
  const result = await handleCancel(params, event, config);
1094
1276
  return { ...result, id } as JsonRpcResponse;
1095
1277
  }
1278
+ case "actions/invoke": {
1279
+ const result = await handleInvokeReadOnlyAction(params, event, config);
1280
+ return { ...result, id } as JsonRpcResponse;
1281
+ }
1096
1282
  default:
1097
1283
  return jsonRpcError(id, -32601, `Method not found: ${body.method}`);
1098
1284
  }
@@ -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,16 @@ export type {
33
34
  Artifact,
34
35
  JsonRpcRequest,
35
36
  JsonRpcResponse,
37
+ A2ACorrelationMetadata,
38
+ A2AReadOnlyActionInvocation,
39
+ A2AReadOnlyActionResult,
36
40
  } from "./types.js";
37
41
  export type {
38
42
  AgentInvocationErrorCode,
43
+ AgentActionInvocationResult,
39
44
  AgentInvocationResult,
40
45
  AgentInvocationRuntime,
46
+ InvokeAgentActionOptions,
41
47
  InvokeAgentOptions,
42
48
  ResolveAgentInvocationTargetOptions,
43
49
  ResolvedAgentInvocationTarget,
@@ -3,11 +3,20 @@ 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 {
11
+ A2ACorrelationMetadata,
12
+ A2AReadOnlyActionResult,
13
+ } from "./types.js";
7
14
 
8
15
  export type AgentInvocationErrorCode =
9
16
  | "missing-target"
10
17
  | "missing-prompt"
18
+ | "missing-action"
19
+ | "invalid-input"
11
20
  | "invalid-url"
12
21
  | "self-call"
13
22
  | "not-found";
@@ -45,10 +54,17 @@ export interface AgentInvocationResult {
45
54
  responseText: string;
46
55
  }
47
56
 
57
+ export interface AgentActionInvocationResult {
58
+ target: ResolvedAgentInvocationTarget;
59
+ action: string;
60
+ result: A2AReadOnlyActionResult;
61
+ }
62
+
48
63
  export interface AgentInvocationRuntime {
49
64
  findAgent: typeof defaultFindAgent;
50
65
  discoverAgents: typeof defaultDiscoverAgents;
51
66
  callAgent: typeof defaultCallAgent;
67
+ callAction: typeof defaultCallAction;
52
68
  }
53
69
 
54
70
  export interface ResolveAgentInvocationTargetOptions {
@@ -69,6 +85,21 @@ export interface InvokeAgentOptions extends ResolveAgentInvocationTargetOptions
69
85
  timeoutMs?: number;
70
86
  pollIntervalMs?: number;
71
87
  includeInvocationHint?: boolean;
88
+ correlation?: A2ACorrelationMetadata;
89
+ idempotencyKey?: string;
90
+ runtime?: Partial<AgentInvocationRuntime>;
91
+ }
92
+
93
+ export interface InvokeAgentActionOptions extends ResolveAgentInvocationTargetOptions {
94
+ target: string;
95
+ action: string;
96
+ input?: Record<string, unknown>;
97
+ apiKey?: string;
98
+ userEmail?: string;
99
+ orgDomain?: string;
100
+ orgSecret?: string;
101
+ requestTimeoutMs?: number;
102
+ correlation?: A2ACorrelationMetadata;
72
103
  runtime?: Partial<AgentInvocationRuntime>;
73
104
  }
74
105
 
@@ -172,6 +203,8 @@ export async function invokeAgent(
172
203
  async: options.async,
173
204
  timeoutMs: options.timeoutMs,
174
205
  pollIntervalMs: options.pollIntervalMs,
206
+ correlation: options.correlation,
207
+ idempotencyKey: options.idempotencyKey,
175
208
  });
176
209
 
177
210
  return {
@@ -181,6 +214,49 @@ export async function invokeAgent(
181
214
  };
182
215
  }
183
216
 
217
+ /**
218
+ * Resolve another app and execute one explicitly exposed read-only action on
219
+ * it. This is the fast A2A path for bounded data operations that do not need a
220
+ * second model to plan or synthesize.
221
+ */
222
+ export async function invokeAgentAction(
223
+ options: InvokeAgentActionOptions,
224
+ ): Promise<AgentActionInvocationResult> {
225
+ const action = options.action.trim();
226
+ if (!action) {
227
+ throw new AgentInvocationError(
228
+ "missing-action",
229
+ "Error: action is required",
230
+ { target: options.target },
231
+ );
232
+ }
233
+ const input = options.input ?? {};
234
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
235
+ throw new AgentInvocationError(
236
+ "invalid-input",
237
+ "Error: action input must be an object",
238
+ { target: options.target },
239
+ );
240
+ }
241
+
242
+ const target = await resolveAgentInvocationTarget(options.target, {
243
+ selfAppId: options.selfAppId,
244
+ selfUrl: options.selfUrl,
245
+ runtime: options.runtime,
246
+ });
247
+ const callAction = options.runtime?.callAction ?? defaultCallAction;
248
+ const result = await callAction(target.url, action, input, {
249
+ apiKey: options.apiKey,
250
+ userEmail: options.userEmail,
251
+ orgDomain: options.orgDomain,
252
+ orgSecret: options.orgSecret,
253
+ requestTimeoutMs: options.requestTimeoutMs,
254
+ correlation: options.correlation,
255
+ });
256
+
257
+ return { target, action, result };
258
+ }
259
+
184
260
  export function buildAgentInvocationPrompt(
185
261
  prompt: string,
186
262
  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
  }