@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.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +25 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/client.ts +162 -17
- package/corpus/core/src/a2a/correlation.ts +50 -0
- package/corpus/core/src/a2a/handlers.ts +200 -14
- package/corpus/core/src/a2a/index.ts +7 -1
- package/corpus/core/src/a2a/invoke.ts +77 -1
- package/corpus/core/src/a2a/server.ts +13 -1
- package/corpus/core/src/a2a/task-store.ts +146 -6
- package/corpus/core/src/a2a/types.ts +32 -0
- package/corpus/core/src/action.ts +5 -2
- package/corpus/core/src/agent/production-agent.ts +33 -4
- package/corpus/core/src/client/AssistantChat.tsx +648 -603
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -4
- package/corpus/core/src/client/agent-chat-adapter.ts +23 -37
- package/corpus/core/src/client/agent-sidebar-state.ts +4 -0
- package/corpus/core/src/client/analytics.ts +84 -0
- package/corpus/core/src/client/chat/message-components.tsx +94 -22
- package/corpus/core/src/client/chat/tool-call-display.tsx +170 -47
- package/corpus/core/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
- package/corpus/core/src/client/chat-thread-url.ts +11 -0
- package/corpus/core/src/client/error-capture.ts +12 -0
- package/corpus/core/src/client/extensions/ExtensionSlot.tsx +37 -1
- package/corpus/core/src/client/index.ts +2 -0
- package/corpus/core/src/client/route-chunk-recovery.ts +20 -8
- package/corpus/core/src/client/session-replay.ts +31 -0
- package/corpus/core/src/client/use-run-stuck-detection.ts +27 -1
- package/corpus/core/src/db/client.ts +55 -0
- package/corpus/core/src/extensions/actions.ts +2 -14
- package/corpus/core/src/extensions/store.ts +1 -1
- package/corpus/core/src/localization/default-messages.ts +3 -0
- package/corpus/core/src/mcp/build-server.ts +2 -2
- package/corpus/core/src/observability/traces.ts +172 -19
- package/corpus/core/src/progress/actions.ts +4 -2
- package/corpus/core/src/provider-api/index.ts +205 -105
- package/corpus/core/src/scripts/call-agent.ts +190 -19
- package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +112 -25
- package/corpus/core/src/server/agent-chat-plugin.ts +136 -4
- package/corpus/core/src/styles/agent-conversation.css +7 -0
- package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/de-DE.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/en-US.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/es-ES.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -10
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +54 -23
- package/corpus/templates/analytics/.builder/skills/apollo/SKILL.md +19 -41
- package/corpus/templates/analytics/.builder/skills/commonroom/SKILL.md +20 -35
- package/corpus/templates/analytics/.builder/skills/github/SKILL.md +23 -67
- package/corpus/templates/analytics/.builder/skills/pylon/SKILL.md +25 -43
- package/corpus/templates/analytics/AGENTS.md +22 -13
- package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
- package/corpus/templates/analytics/actions/configure-gong-native-insights.ts +29 -0
- package/corpus/templates/analytics/actions/content-calendar-schema.ts +8 -4
- package/corpus/templates/analytics/actions/content-calendar.ts +12 -4
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -1
- package/corpus/templates/analytics/actions/gong-calls.ts +113 -22
- package/corpus/templates/analytics/actions/gong-native-insights.ts +166 -0
- package/corpus/templates/analytics/actions/hubspot-deals.ts +190 -46
- package/corpus/templates/analytics/actions/pylon-issues.ts +123 -0
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
- package/corpus/templates/analytics/actions/slack-messages.ts +179 -27
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +48 -152
- package/corpus/templates/analytics/app/components/ui/chart.tsx +1 -1
- package/corpus/templates/analytics/app/hooks/use-chart-tooltip-flip.ts +21 -6
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +13 -0
- package/corpus/templates/analytics/app/i18n-data.ts +134 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +181 -30
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +6 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +4 -3
- package/corpus/templates/analytics/changelog/2026-07-17-analytics-now-includes-a-default-alert-for-spikes-in-stuck-agent-chats.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-dashboard-editors-can-add-shared-extensions-or-opt-into-per-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extensions-show-a-loading-skeleton.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-errors-now-group-repeat-failures-consistently-and-keep-priva.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-gong-transcript-reviews-now-batch-bounded-call-windows-for-f.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-hubspot-deal-filters-now-run-in-hubspot-before-paging-result.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-notion-content-calendars-now-discover-the-matching-database-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-pylon-dashboard-reads-now-use-the-paginated-issue-search-api.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-slack-reads-no-longer-join-channels-and-report-pagination-coverage.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +23 -14
- package/corpus/templates/analytics/docs/schemas/tracked-events.md +5 -1
- package/corpus/templates/analytics/server/handlers/notion.ts +14 -3
- package/corpus/templates/analytics/server/handlers/slack.ts +182 -29
- package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +3 -3
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -6
- package/corpus/templates/analytics/server/lib/analytics-alerts.ts +209 -87
- package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +6 -2
- package/corpus/templates/analytics/server/lib/error-capture.ts +75 -8
- package/corpus/templates/analytics/server/lib/gong-native-policy.ts +72 -0
- package/corpus/templates/analytics/server/lib/gong.ts +54 -66
- package/corpus/templates/analytics/server/lib/hubspot.ts +40 -3
- package/corpus/templates/analytics/server/lib/notion.ts +83 -8
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +4 -0
- package/corpus/templates/analytics/server/lib/slack.ts +242 -90
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -3
- package/corpus/templates/analytics/server/routes/api/pylon/accounts.get.ts +42 -1
- package/corpus/templates/analytics/server/routes/api/pylon/issues.get.ts +71 -1
- package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +44 -4
- package/corpus/templates/clips/actions/finalize-recording.ts +541 -62
- package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +19 -1
- package/corpus/templates/clips/app/components/library/create-folder-dialog.tsx +123 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +42 -4
- package/corpus/templates/clips/app/components/library/recording-card.tsx +30 -0
- package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +17 -2
- package/corpus/templates/clips/app/components/player/video-player.tsx +14 -2
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +2 -2
- package/corpus/templates/clips/app/entry.client.tsx +6 -1
- package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -1
- package/corpus/templates/clips/app/i18n/de-DE.ts +12 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +12 -1
- package/corpus/templates/clips/app/i18n/es-ES.ts +11 -1
- package/corpus/templates/clips/app/i18n/fr-FR.ts +11 -1
- package/corpus/templates/clips/app/i18n/hi-IN.ts +10 -1
- package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -1
- package/corpus/templates/clips/app/i18n/ko-KR.ts +11 -1
- package/corpus/templates/clips/app/i18n/pt-BR.ts +11 -1
- package/corpus/templates/clips/app/i18n/zh-CN.ts +11 -1
- package/corpus/templates/clips/app/i18n/zh-TW.ts +11 -1
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +72 -1
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
- package/corpus/templates/clips/app/routes/record.tsx +3 -3
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -3
- package/corpus/templates/clips/changelog/2026-07-17-choose-which-workspace-receives-new-clips-recordings-and-des.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-clips-now-retries-storage-verification-in-the-background-ins.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-create-folders-directly-from-the-move-menu.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-failed-desktop-uploads-now-offer-a-direct-way-to-reopen-clip.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-fixed-broken-thumbnail-icons-appearing-over-playable-clip-em.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-playback-comments-stay-readable-at-faster-playback-speeds.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +3 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +3 -3
- package/corpus/templates/clips/desktop/src/app.tsx +19 -7
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +111 -13
- package/corpus/templates/clips/desktop/src/lib/upload-verification.ts +16 -7
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -4
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +32 -15
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +45 -18
- package/corpus/templates/clips/server/jobs/media-verification.ts +130 -0
- package/corpus/templates/clips/server/lib/builder-media-compression.ts +15 -0
- package/corpus/templates/clips/server/lib/media-verification-state.ts +38 -0
- package/corpus/templates/clips/server/lib/player-thumbnail-url.ts +31 -0
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +10 -3
- package/corpus/templates/clips/server/plugins/auth.ts +5 -5
- package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +12 -2
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +6 -1
- package/corpus/templates/clips/server/routes/api/thumbnail/[recordingId].get.ts +340 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +24 -7
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +91 -7
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +14 -0
- package/corpus/templates/clips/shared/finalize-recovery.ts +61 -2
- package/corpus/templates/clips/shared/share-meta.ts +1 -1
- package/corpus/templates/content/app/entry.client.tsx +6 -1
- package/corpus/templates/dispatch/AGENTS.md +5 -0
- package/corpus/templates/dispatch/changelog/2026-07-17-apps-page-links-to-other-available-apps.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +6 -0
- package/corpus/templates/mail/app/entry.client.tsx +6 -1
- package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +11 -7
- package/corpus/templates/slides/.env.example +0 -1
- package/corpus/templates/slides/AGENTS.md +4 -0
- package/corpus/templates/slides/DEVELOPING.md +2 -2
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
- package/corpus/templates/slides/actions/logo-config.ts +6 -7
- package/corpus/templates/slides/actions/search-images.ts +11 -39
- package/corpus/templates/slides/actions/search-logos.ts +5 -52
- package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/LogoSearchPanel.tsx +16 -26
- package/corpus/templates/slides/app/entry.client.tsx +6 -1
- package/corpus/templates/slides/server/lib/media-search-providers.ts +216 -0
- package/corpus/templates/slides/server/register-secrets.ts +30 -0
- package/dist/a2a/client.d.ts +47 -1
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +94 -12
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/correlation.d.ts +10 -0
- package/dist/a2a/correlation.d.ts.map +1 -0
- package/dist/a2a/correlation.js +40 -0
- package/dist/a2a/correlation.js.map +1 -0
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +147 -15
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/index.d.ts +4 -4
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +2 -2
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/invoke.d.ts +29 -2
- package/dist/a2a/invoke.d.ts.map +1 -1
- package/dist/a2a/invoke.js +33 -1
- package/dist/a2a/invoke.js.map +1 -1
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +14 -1
- package/dist/a2a/server.js.map +1 -1
- package/dist/a2a/task-store.d.ts +12 -1
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +96 -6
- package/dist/a2a/task-store.js.map +1 -1
- package/dist/a2a/types.d.ts +27 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/action.d.ts +5 -2
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js.map +1 -1
- package/dist/agent/production-agent.d.ts +14 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +19 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +14 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +158 -136
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +27 -4
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +21 -39
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-sidebar-state.d.ts +1 -0
- package/dist/client/agent-sidebar-state.d.ts.map +1 -1
- package/dist/client/agent-sidebar-state.js +4 -0
- package/dist/client/agent-sidebar-state.js.map +1 -1
- package/dist/client/analytics.d.ts +14 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +67 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +8 -0
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +62 -19
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +6 -0
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +83 -14
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts +8 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts.map +1 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.js +51 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.js.map +1 -0
- package/dist/client/chat-thread-url.d.ts +2 -0
- package/dist/client/chat-thread-url.d.ts.map +1 -0
- package/dist/client/chat-thread-url.js +12 -0
- package/dist/client/chat-thread-url.js.map +1 -0
- package/dist/client/error-capture.d.ts.map +1 -1
- package/dist/client/error-capture.js +7 -0
- package/dist/client/error-capture.js.map +1 -1
- package/dist/client/extensions/ExtensionSlot.d.ts +3 -1
- package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionSlot.js +28 -3
- package/dist/client/extensions/ExtensionSlot.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/route-chunk-recovery.d.ts.map +1 -1
- package/dist/client/route-chunk-recovery.js +14 -9
- package/dist/client/route-chunk-recovery.js.map +1 -1
- package/dist/client/session-replay.d.ts +15 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +20 -0
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
- package/dist/client/use-run-stuck-detection.js +25 -1
- package/dist/client/use-run-stuck-detection.js.map +1 -1
- package/dist/db/client.d.ts +7 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +33 -0
- package/dist/db/client.js.map +1 -1
- package/dist/extensions/actions.d.ts.map +1 -1
- package/dist/extensions/actions.js +2 -10
- package/dist/extensions/actions.js.map +1 -1
- package/dist/extensions/store.js +1 -1
- package/dist/extensions/store.js.map +1 -1
- package/dist/localization/default-messages.d.ts +3 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +3 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/build-server.d.ts +2 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +2 -2
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +5 -5
- package/dist/observability/traces.d.ts +9 -0
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +137 -19
- package/dist/observability/traces.js.map +1 -1
- package/dist/progress/actions.d.ts.map +1 -1
- package/dist/progress/actions.js +3 -2
- package/dist/progress/actions.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +91 -8
- package/dist/provider-api/index.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +140 -17
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/action-filters-a2a.d.ts +24 -2
- package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +62 -7
- package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +118 -5
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/styles/agent-conversation.css +7 -0
- package/dist/templates/default/app/i18n/ar-SA.ts +20 -0
- package/dist/templates/default/app/i18n/de-DE.ts +20 -0
- package/dist/templates/default/app/i18n/en-US.ts +20 -0
- package/dist/templates/default/app/i18n/es-ES.ts +20 -0
- package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
- package/dist/templates/default/app/i18n/hi-IN.ts +19 -0
- package/dist/templates/default/app/i18n/ja-JP.ts +20 -0
- package/dist/templates/default/app/i18n/ko-KR.ts +19 -0
- package/dist/templates/default/app/i18n/pt-BR.ts +20 -0
- package/dist/templates/default/app/i18n/zh-CN.ts +19 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
- package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
- package/package.json +1 -1
- package/src/templates/default/app/i18n/ar-SA.ts +20 -0
- package/src/templates/default/app/i18n/de-DE.ts +20 -0
- package/src/templates/default/app/i18n/en-US.ts +20 -0
- package/src/templates/default/app/i18n/es-ES.ts +20 -0
- package/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/src/templates/default/app/i18n/hi-IN.ts +19 -0
- package/src/templates/default/app/i18n/ja-JP.ts +20 -0
- package/src/templates/default/app/i18n/ko-KR.ts +19 -0
- package/src/templates/default/app/i18n/pt-BR.ts +20 -0
- package/src/templates/default/app/i18n/zh-CN.ts +19 -0
- package/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
- package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
- package/corpus/templates/analytics/server/handlers/github.ts +0 -200
- package/corpus/templates/analytics/server/handlers/pylon.ts +0 -43
- package/corpus/templates/analytics/server/lib/apollo.ts +0 -167
- package/corpus/templates/analytics/server/lib/commonroom.ts +0 -149
- package/corpus/templates/analytics/server/lib/github.ts +0 -660
- package/corpus/templates/analytics/server/lib/mixpanel.ts +0 -156
- package/corpus/templates/analytics/server/lib/posthog.ts +0 -194
- package/corpus/templates/analytics/server/lib/pylon.ts +0 -109
- package/corpus/templates/analytics/server/routes/api/github/graphql.post.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/issue.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/org-prs.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/pr.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/prs.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/search.get.ts +0 -1
- package/corpus/templates/slides/actions/fetch-logos.ts +0 -90
- package/corpus/templates/slides/actions/image-search.ts +0 -64
- package/corpus/templates/slides/actions/import-github.ts +0 -182
- 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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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 { ...
|
|
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
|
|
945
|
-
const denied = authorizeTaskAccess(
|
|
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
|
|
1040
|
-
const denied = authorizeTaskAccess(
|
|
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 {
|
|
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
|
}
|