@agent-native/core 0.131.5 → 0.131.7
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 +3 -3
- package/corpus/core/CHANGELOG.md +70 -0
- package/corpus/core/docs/content/agent-native-toolkit.mdx +13 -6
- package/corpus/core/docs/content/cloneable-saas.mdx +5 -5
- package/corpus/core/docs/content/creating-templates.mdx +9 -0
- package/corpus/core/docs/content/deployment.mdx +18 -12
- package/corpus/core/docs/content/doctor.mdx +8 -1
- package/corpus/core/docs/content/drop-in-agent.mdx +1 -1
- package/corpus/core/docs/content/extensions.mdx +18 -18
- package/corpus/core/docs/content/faq.mdx +4 -4
- package/corpus/core/docs/content/key-concepts.mdx +30 -21
- package/corpus/core/docs/content/security.mdx +2 -2
- package/corpus/core/docs/content/template-brain-developers.mdx +4 -1
- package/corpus/core/docs/content/template-mail-developers.mdx +4 -1
- package/corpus/core/docs/content/what-is-agent-native.mdx +6 -6
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/client.ts +449 -66
- package/corpus/core/src/a2a/correlation.ts +31 -0
- package/corpus/core/src/a2a/invoke.ts +4 -2
- package/corpus/core/src/a2a/types.ts +4 -0
- package/corpus/core/src/action.ts +3 -0
- package/corpus/core/src/agent/action-continuation-guidance.ts +2 -1
- package/corpus/core/src/agent/engine/registry.ts +98 -6
- package/corpus/core/src/agent/production-agent.ts +151 -18
- package/corpus/core/src/agent/run-loop-with-resume.ts +190 -3
- package/corpus/core/src/agent/run-manager.ts +117 -41
- package/corpus/core/src/agent/thread-debug-history.ts +86 -0
- package/corpus/core/src/agent/types.ts +3 -1
- package/corpus/core/src/cli/create.ts +11 -1
- package/corpus/core/src/cli/templates-meta.ts +2 -2
- package/corpus/core/src/client/agent-chat-adapter.ts +91 -13
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +11 -9
- package/corpus/core/src/client/sse-event-processor.ts +17 -3
- package/corpus/core/src/db/client.ts +57 -17
- package/corpus/core/src/guards/no-env-credentials.ts +2 -0
- package/corpus/core/src/integrations/adapters/slack.ts +8 -3
- package/corpus/core/src/localization/default-messages.ts +44 -0
- package/corpus/core/src/observability/traces.ts +78 -5
- package/corpus/core/src/scripts/call-agent.ts +294 -11
- package/corpus/core/src/scripts/describe-workspace-apps.ts +2 -2
- package/corpus/core/src/secrets/crypto.ts +156 -35
- package/corpus/core/src/secrets/storage.ts +64 -26
- package/corpus/core/src/server/agent-capabilities.ts +1 -1
- package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +113 -7
- package/corpus/core/src/server/agent-chat/context-tools.ts +2 -0
- package/corpus/core/src/server/agent-chat/plugin-options.ts +34 -1
- package/corpus/core/src/server/agent-chat/prompt-resources.ts +1 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +91 -59
- package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +19 -7
- package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
- package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
- package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
- package/corpus/core/src/vite/client.ts +1 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +5 -4
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +6 -4
- package/corpus/templates/analytics/AGENTS.md +7 -4
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +4 -3
- package/corpus/templates/analytics/changelog/2026-07-30-delegated-analytics-questions-now-return-a-useful-current-me.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-30-scheduled-dashboard-emails-complete-every-panel-without-pool.md +6 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +28 -1
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +18 -11
- package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +4 -4
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +9 -5
- package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +6 -2
- package/corpus/templates/analytics/server/lib/dashboard-panel-source-resolver.ts +11 -4
- package/corpus/templates/analytics/server/lib/dashboard-report-render.ts +49 -31
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +16 -8
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +9 -3
- package/corpus/templates/analytics/server/lib/production-serverless-runtime.ts +11 -0
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +10 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -2
- package/corpus/templates/analytics/server/plugins/analytics-alert-jobs.ts +2 -1
- package/corpus/templates/analytics/server/plugins/dashboard-report-jobs.ts +2 -1
- package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +1 -12
- package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +54 -6
- package/corpus/templates/brain/.agents/skills/brain/SKILL.md +20 -9
- package/corpus/templates/brain/.agents/skills/ingestion-and-connectors/SKILL.md +33 -1
- package/corpus/templates/brain/AGENTS.md +3 -1
- package/corpus/templates/brain/README.md +4 -1
- package/corpus/templates/brain/actions/_schemas.ts +30 -8
- package/corpus/templates/brain/actions/ask-brain.ts +124 -14
- package/corpus/templates/brain/actions/create-source.ts +18 -2
- package/corpus/templates/brain/actions/enqueue-captures-distillation.ts +8 -123
- package/corpus/templates/brain/actions/enqueue-distillation.ts +6 -127
- package/corpus/templates/brain/actions/import-capture.ts +17 -5
- package/corpus/templates/brain/actions/import-transcript.ts +17 -5
- package/corpus/templates/brain/actions/update-source.ts +25 -5
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/brain/changelog/2026-07-30-blessed-resources-can-feed-cited-company-answers.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-30-the-left-sidebar-no-longer-shows-a-blank-organization-placeh.md +6 -0
- package/corpus/templates/brain/server/lib/brain.ts +49 -19
- package/corpus/templates/brain/server/lib/distillation-queue.ts +147 -0
- package/corpus/templates/brain/server/lib/source-policy.ts +264 -0
- package/corpus/templates/brain/server/plugins/agent-chat.ts +3 -2
- package/corpus/templates/brain/server/routes/api/_agent-native/brain/ingest.post.ts +116 -19
- package/corpus/templates/clips/app/components/meetings/google-oauth-identity-notice.tsx +51 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +3 -1
- package/corpus/templates/clips/changelog/2026-07-30-google-calendar-warning.md +6 -0
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +72 -8
- package/corpus/templates/content/changelog/2026-07-30-the-slash-command-hint-now-stays-on-only-the-active-empty-li.md +6 -0
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +506 -11
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +148 -17
- package/corpus/templates/design/app/components/design/canvas-interactions/design-canvas-interactions.ts +357 -0
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +7 -466
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +15 -311
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +19 -997
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +8 -1216
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +31 -38
- package/corpus/templates/design/package.json +0 -1
- package/corpus/templates/dispatch/AGENTS.md +8 -0
- package/corpus/templates/dispatch/DEVELOPING.md +29 -0
- package/corpus/templates/dispatch/actions/view-screen.ts +34 -2
- package/corpus/templates/dispatch/app/i18n-data.ts +457 -0
- package/corpus/templates/dispatch/changelog/2026-07-30-delegated-dispatch-work-continues-reliably-in-the-background.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-30-find-failed-runs-across-apps.md +6 -0
- package/corpus/templates/dispatch/netlify.toml +3 -0
- package/corpus/templates/plan/actions/get-visual-plan.ts +10 -6
- package/corpus/templates/plan/actions/patch-visual-plan-source.ts +117 -1
- package/corpus/templates/plan/actions/update-visual-plan.ts +56 -14
- package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -1
- package/corpus/templates/plan/changelog/2026-07-30-plan-agents-recover-with-targeted-writes.md +6 -0
- package/corpus/templates/plan/shared/plan-content.ts +35 -0
- package/corpus/templates/slides/.agents/skills/analytics-data-for-decks/SKILL.md +8 -12
- package/corpus/templates/slides/AGENTS.md +4 -4
- package/corpus/templates/slides/actions/create-deck.ts +1 -1
- package/corpus/templates/slides/actions/duplicate-deck.ts +19 -4
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +2 -10
- package/corpus/templates/slides/app/components/deck/MermaidRenderer.tsx +12 -1
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +30 -13
- package/corpus/templates/slides/app/components/editor/DeckEditorSkeleton.tsx +35 -0
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +63 -56
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +21 -76
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1110 -292
- package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +53 -0
- package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +235 -18
- package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +4 -1
- package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +11 -0
- package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +129 -0
- package/corpus/templates/slides/app/components/editor/selection-overlay-measurement.ts +70 -0
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +519 -65
- package/corpus/templates/slides/app/components/visual-editor/CanvasCommentPins.tsx +36 -426
- package/corpus/templates/slides/app/components/visual-editor/DrawOverlay.tsx +19 -458
- package/corpus/templates/slides/app/context/DeckContext.tsx +179 -72
- package/corpus/templates/slides/app/global.css +105 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +8 -0
- package/corpus/templates/slides/app/lib/deck-editor-loading.ts +26 -0
- package/corpus/templates/slides/app/lib/mermaid-blocks.ts +27 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +71 -38
- package/corpus/templates/slides/app/pages/Index.tsx +98 -41
- package/corpus/templates/slides/changelog/2026-07-30-deck-loading-no-longer-flashes-an-unavailable-message.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-duplicating-a-deck-from-the-deck-list-now-opens-the-copy-imm.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-layout-overflow-warning-is-readable-and-dismissible.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-new-decks-now-start-with-an-empty-slide-list-when-no-slides-.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-shared-canvas-annotations.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-slide-objects-can-be-moved-as-a-group-copied-and-pasted-with.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-slide-text-editing-and-object-controls-now-match-google-slides.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-style-panel-now-scrolls-with-speaker-notes-open-shows-the-sl.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-top-toolbar-controls-now-use-consistent-sizing-with-undo-and.md +6 -0
- package/corpus/templates/slides/netlify.toml +3 -1
- package/corpus/templates/slides/package.json +0 -1
- package/corpus/templates/slides/server/lib/chat-attachments.ts +18 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -0
- package/corpus/templates/slides/vite.config.ts +0 -1
- package/corpus/toolkit/CHANGELOG.md +13 -0
- package/corpus/toolkit/README.md +19 -0
- package/corpus/toolkit/agent-native.eject.json +38 -0
- package/corpus/toolkit/package.json +29 -1
- package/corpus/toolkit/src/canvas-annotations/CanvasCommentPins.tsx +861 -0
- package/corpus/toolkit/src/canvas-annotations/DrawOverlay.tsx +1233 -0
- package/corpus/toolkit/src/canvas-annotations/index.ts +15 -0
- package/corpus/toolkit/src/canvas-annotations/types.ts +14 -0
- package/corpus/toolkit/src/canvas-interactions/canvas-interactions.ts +933 -0
- package/corpus/toolkit/src/canvas-interactions/index.ts +67 -0
- package/corpus/toolkit/src/design-tweaks/scrub-input-utils.ts +311 -0
- package/corpus/toolkit/src/design-tweaks/scrub-input.tsx +491 -0
- package/corpus/toolkit/src/design-tweaks/visual-style-controls.tsx +26 -171
- package/corpus/toolkit/src/index.ts +1 -0
- package/dist/a2a/client.d.ts +23 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +309 -44
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/correlation.d.ts +1 -0
- package/dist/a2a/correlation.d.ts.map +1 -1
- package/dist/a2a/correlation.js +27 -0
- package/dist/a2a/correlation.js.map +1 -1
- package/dist/a2a/invoke.d.ts.map +1 -1
- package/dist/a2a/invoke.js +4 -2
- package/dist/a2a/invoke.js.map +1 -1
- package/dist/a2a/types.d.ts +4 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/action.d.ts +3 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js.map +1 -1
- package/dist/agent/action-continuation-guidance.d.ts.map +1 -1
- package/dist/agent/action-continuation-guidance.js +2 -1
- package/dist/agent/action-continuation-guidance.js.map +1 -1
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +82 -8
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/agent/production-agent.d.ts +40 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +113 -15
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts +21 -0
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +163 -4
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/agent/run-manager.d.ts +16 -9
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +93 -42
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/thread-debug-history.d.ts +10 -0
- package/dist/agent/thread-debug-history.d.ts.map +1 -0
- package/dist/agent/thread-debug-history.js +68 -0
- package/dist/agent/thread-debug-history.js.map +1 -0
- package/dist/agent/types.d.ts +3 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +6 -1
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/templates-meta.js +2 -2
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +76 -13
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +1 -1
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +12 -3
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +48 -17
- package/dist/db/client.js.map +1 -1
- package/dist/guards/no-env-credentials.d.ts.map +1 -1
- package/dist/guards/no-env-credentials.js +2 -0
- package/dist/guards/no-env-credentials.js.map +1 -1
- package/dist/integrations/adapters/slack.js +7 -3
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/localization/default-messages.d.ts +43 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +43 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/observability/traces.d.ts +3 -1
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +73 -4
- package/dist/observability/traces.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +13 -13
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +237 -12
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/scripts/describe-workspace-apps.js +2 -2
- package/dist/scripts/describe-workspace-apps.js.map +1 -1
- package/dist/secrets/crypto.d.ts +36 -21
- package/dist/secrets/crypto.d.ts.map +1 -1
- package/dist/secrets/crypto.js +134 -33
- package/dist/secrets/crypto.js.map +1 -1
- package/dist/secrets/storage.d.ts +6 -6
- package/dist/secrets/storage.d.ts.map +1 -1
- package/dist/secrets/storage.js +43 -26
- package/dist/secrets/storage.js.map +1 -1
- package/dist/server/agent-capabilities.js +1 -1
- package/dist/server/agent-capabilities.js.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.d.ts +17 -3
- package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +94 -3
- package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
- package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
- package/dist/server/agent-chat/context-tools.js +2 -0
- package/dist/server/agent-chat/context-tools.js.map +1 -1
- package/dist/server/agent-chat/plugin-options.d.ts +23 -0
- package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
- package/dist/server/agent-chat/plugin-options.js +4 -1
- package/dist/server/agent-chat/plugin-options.js.map +1 -1
- package/dist/server/agent-chat/prompt-resources.js +1 -1
- package/dist/server/agent-chat/prompt-resources.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +2 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +79 -56
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +19 -7
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
- package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +1 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/agent-native-toolkit.mdx +13 -6
- package/docs/content/cloneable-saas.mdx +5 -5
- package/docs/content/creating-templates.mdx +9 -0
- package/docs/content/deployment.mdx +18 -12
- package/docs/content/doctor.mdx +8 -1
- package/docs/content/drop-in-agent.mdx +1 -1
- package/docs/content/extensions.mdx +18 -18
- package/docs/content/faq.mdx +4 -4
- package/docs/content/key-concepts.mdx +30 -21
- package/docs/content/security.mdx +2 -2
- package/docs/content/template-brain-developers.mdx +4 -1
- package/docs/content/template-mail-developers.mdx +4 -1
- package/docs/content/what-is-agent-native.mdx +6 -6
- package/package.json +3 -3
- package/src/a2a/client.ts +449 -66
- package/src/a2a/correlation.ts +31 -0
- package/src/a2a/invoke.ts +4 -2
- package/src/a2a/types.ts +4 -0
- package/src/action.ts +3 -0
- package/src/agent/action-continuation-guidance.ts +2 -1
- package/src/agent/engine/registry.ts +98 -6
- package/src/agent/production-agent.ts +151 -18
- package/src/agent/run-loop-with-resume.ts +190 -3
- package/src/agent/run-manager.ts +117 -41
- package/src/agent/thread-debug-history.ts +86 -0
- package/src/agent/types.ts +3 -1
- package/src/cli/create.ts +11 -1
- package/src/cli/templates-meta.ts +2 -2
- package/src/client/agent-chat-adapter.ts +91 -13
- package/src/client/resources/McpIntegrationDialog.tsx +11 -9
- package/src/client/sse-event-processor.ts +17 -3
- package/src/db/client.ts +57 -17
- package/src/guards/no-env-credentials.ts +2 -0
- package/src/integrations/adapters/slack.ts +8 -3
- package/src/localization/default-messages.ts +44 -0
- package/src/observability/traces.ts +78 -5
- package/src/scripts/call-agent.ts +294 -11
- package/src/scripts/describe-workspace-apps.ts +2 -2
- package/src/secrets/crypto.ts +156 -35
- package/src/secrets/storage.ts +64 -26
- package/src/server/agent-capabilities.ts +1 -1
- package/src/server/agent-chat/action-filters-a2a.ts +113 -7
- package/src/server/agent-chat/context-tools.ts +2 -0
- package/src/server/agent-chat/plugin-options.ts +34 -1
- package/src/server/agent-chat/prompt-resources.ts +1 -1
- package/src/server/agent-chat-plugin.ts +91 -59
- package/src/templates/default/.agents/skills/secrets/SKILL.md +19 -7
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
- package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
- package/src/vite/client.ts +1 -0
package/dist/a2a/client.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import * as jose from "jose";
|
|
2
3
|
import { ssrfSafeFetch } from "../extensions/url-safety.js";
|
|
3
4
|
/**
|
|
@@ -46,6 +47,10 @@ function workspacePrivateOrigins() {
|
|
|
46
47
|
}
|
|
47
48
|
import { sanitizeA2ACorrelationMetadata } from "./correlation.js";
|
|
48
49
|
const DEFAULT_A2A_POLL_REQUEST_TIMEOUT_MS = 15_000;
|
|
50
|
+
const DEFAULT_A2A_DISCOVERY_TIMEOUT_MS = 3_000;
|
|
51
|
+
const MAX_A2A_RPC_ATTEMPTS = 3;
|
|
52
|
+
const A2A_RPC_RETRY_BASE_MS = 100;
|
|
53
|
+
export const MAX_A2A_CALLER_RESPONSE_CHARS = 32_768;
|
|
49
54
|
export class A2ATaskTimeoutError extends Error {
|
|
50
55
|
taskId;
|
|
51
56
|
lastTask;
|
|
@@ -61,6 +66,40 @@ export class A2ATaskTimeoutError extends Error {
|
|
|
61
66
|
this.timeoutMs = timeoutMs;
|
|
62
67
|
}
|
|
63
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Preserves a receiver's terminal protocol state across the text-oriented
|
|
71
|
+
* callAgent convenience boundary. Callers can distinguish a real answer from
|
|
72
|
+
* failure, cancellation, approval/input, and an invalid empty completion
|
|
73
|
+
* without parsing English prose.
|
|
74
|
+
*/
|
|
75
|
+
export class A2ATaskTerminalError extends Error {
|
|
76
|
+
taskId;
|
|
77
|
+
state;
|
|
78
|
+
responseText;
|
|
79
|
+
errorCode;
|
|
80
|
+
task;
|
|
81
|
+
constructor(task, state, responseText, errorCode = `a2a_task_${state.replace(/-/g, "_")}`) {
|
|
82
|
+
const detail = responseText.trim()
|
|
83
|
+
? `: ${boundA2ACallerResponseText(responseText).trim()}`
|
|
84
|
+
: "";
|
|
85
|
+
super(`A2A task ${task.id} ended ${state}${detail}`);
|
|
86
|
+
this.name = "A2ATaskTerminalError";
|
|
87
|
+
this.taskId = task.id;
|
|
88
|
+
this.state = state;
|
|
89
|
+
this.responseText = boundA2ACallerResponseText(responseText);
|
|
90
|
+
this.errorCode = errorCode;
|
|
91
|
+
this.task = task;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** Keep both the answer lead and artifact/source tail within caller context. */
|
|
95
|
+
export function boundA2ACallerResponseText(value) {
|
|
96
|
+
if (value.length <= MAX_A2A_CALLER_RESPONSE_CHARS)
|
|
97
|
+
return value;
|
|
98
|
+
const marker = "\n\n...[A2A response compacted at the caller boundary; use the receiving app or returned artifact links for full details]...\n\n";
|
|
99
|
+
const tailChars = 8_192;
|
|
100
|
+
const headChars = MAX_A2A_CALLER_RESPONSE_CHARS - tailChars - marker.length;
|
|
101
|
+
return value.slice(0, headChars) + marker + value.slice(-tailChars);
|
|
102
|
+
}
|
|
64
103
|
/**
|
|
65
104
|
* Sign a JWT for A2A cross-app identity verification.
|
|
66
105
|
*
|
|
@@ -167,35 +206,72 @@ export class A2AClient {
|
|
|
167
206
|
method,
|
|
168
207
|
params,
|
|
169
208
|
};
|
|
170
|
-
|
|
209
|
+
const discoveryTimeoutMs = resolveA2ADiscoveryTimeoutMs(options?.requestTimeoutMs ?? this.requestTimeoutMs, options?.deadlineMs);
|
|
210
|
+
await this.ensureEndpointCandidates(discoveryTimeoutMs);
|
|
171
211
|
let lastError = null;
|
|
172
212
|
for (const url of this.endpointCandidates) {
|
|
173
213
|
for (let i = 0; i < this.apiKeyAttempts.length; i++) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
214
|
+
const maxAttempts = isRetrySafeA2ARpc(method, params, this.apiKeyAttempts[i])
|
|
215
|
+
? MAX_A2A_RPC_ATTEMPTS
|
|
216
|
+
: 1;
|
|
217
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
218
|
+
const requestTimeoutMs = resolveA2ARequestTimeoutMs(options?.requestTimeoutMs ?? this.requestTimeoutMs, options?.deadlineMs);
|
|
219
|
+
if (requestTimeoutMs !== undefined && requestTimeoutMs <= 0) {
|
|
220
|
+
throw new Error("A2A request deadline exceeded");
|
|
221
|
+
}
|
|
222
|
+
console.log(`[A2A Client] POST ${url} method=${method} attempt=${attempt}/${maxAttempts}`);
|
|
223
|
+
const startTime = Date.now();
|
|
224
|
+
let res;
|
|
225
|
+
try {
|
|
226
|
+
res = await this.postJson(url, body, this.apiKeyAttempts[i], requestTimeoutMs);
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
lastError =
|
|
230
|
+
error instanceof Error ? error : new Error(String(error));
|
|
231
|
+
if (attempt < maxAttempts) {
|
|
232
|
+
await waitForA2ARetry(attempt, null, remainingA2ADeadlineMs(options?.deadlineMs));
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
console.log(`[A2A Client] Response: ${res.status} in ${Date.now() - startTime}ms`);
|
|
238
|
+
if (res.ok) {
|
|
239
|
+
const text = await res.text();
|
|
240
|
+
if (i < this.apiKeyAttempts.length - 1 &&
|
|
241
|
+
isA2AAuthRejectionResponse(res.status, text)) {
|
|
242
|
+
lastError = new Error(`A2A request failed (${res.status}): ${text}`);
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
const parsed = JSON.parse(text);
|
|
247
|
+
this.endpointCandidates = [url];
|
|
248
|
+
this.markApiKeySucceeded(this.apiKeyAttempts[i]);
|
|
249
|
+
return parsed;
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
lastError = new Error(`A2A response was not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
253
|
+
if (attempt < maxAttempts) {
|
|
254
|
+
await waitForA2ARetry(attempt, null, remainingA2ADeadlineMs(options?.deadlineMs));
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
179
260
|
const text = await res.text();
|
|
261
|
+
lastError = new Error(`A2A request failed (${res.status}): ${text}`);
|
|
180
262
|
if (i < this.apiKeyAttempts.length - 1 &&
|
|
181
263
|
isA2AAuthRejectionResponse(res.status, text)) {
|
|
182
|
-
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
if (isRetryableA2AStatus(res.status) && attempt < maxAttempts) {
|
|
267
|
+
await waitForA2ARetry(attempt, res.headers.get("retry-after"), remainingA2ADeadlineMs(options?.deadlineMs));
|
|
183
268
|
continue;
|
|
184
269
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const text = await res.text();
|
|
190
|
-
lastError = new Error(`A2A request failed (${res.status}): ${text}`);
|
|
191
|
-
if (i < this.apiKeyAttempts.length - 1 &&
|
|
192
|
-
isA2AAuthRejectionResponse(res.status, text)) {
|
|
193
|
-
continue;
|
|
194
|
-
}
|
|
195
|
-
if (!shouldTryNextEndpoint(res.status)) {
|
|
196
|
-
throw lastError;
|
|
270
|
+
if (!shouldTryNextEndpoint(res.status)) {
|
|
271
|
+
throw lastError;
|
|
272
|
+
}
|
|
273
|
+
break;
|
|
197
274
|
}
|
|
198
|
-
break;
|
|
199
275
|
}
|
|
200
276
|
}
|
|
201
277
|
throw lastError ?? new Error("No A2A endpoint candidates available");
|
|
@@ -219,11 +295,16 @@ export class A2AClient {
|
|
|
219
295
|
message,
|
|
220
296
|
contextId: opts?.contextId,
|
|
221
297
|
metadata: opts?.metadata,
|
|
222
|
-
...(opts?.idempotencyKey
|
|
298
|
+
...(opts?.idempotencyKey
|
|
299
|
+
? { idempotencyKey: opts.idempotencyKey }
|
|
300
|
+
: {}),
|
|
223
301
|
...(opts?.approvedActions?.length
|
|
224
302
|
? { approvedActions: opts.approvedActions }
|
|
225
303
|
: {}),
|
|
226
304
|
...(opts?.async ? { async: true } : {}),
|
|
305
|
+
}, {
|
|
306
|
+
requestTimeoutMs: opts?.requestTimeoutMs,
|
|
307
|
+
deadlineMs: opts?.deadlineMs,
|
|
227
308
|
});
|
|
228
309
|
if (response.error) {
|
|
229
310
|
throw new Error(`A2A error (${response.error.code}): ${response.error.message}`);
|
|
@@ -234,7 +315,10 @@ export class A2AClient {
|
|
|
234
315
|
* Poll for a task by id. Used in async mode after `send({ async: true })`.
|
|
235
316
|
*/
|
|
236
317
|
async getTask(taskId, opts) {
|
|
237
|
-
const response = await this.rpc("tasks/get", { id: taskId }, {
|
|
318
|
+
const response = await this.rpc("tasks/get", { id: taskId }, {
|
|
319
|
+
requestTimeoutMs: opts?.requestTimeoutMs,
|
|
320
|
+
deadlineMs: opts?.deadlineMs,
|
|
321
|
+
});
|
|
238
322
|
if (response.error) {
|
|
239
323
|
throw new Error(`A2A error (${response.error.code}): ${response.error.message}`);
|
|
240
324
|
}
|
|
@@ -267,6 +351,8 @@ export class A2AClient {
|
|
|
267
351
|
* receiving side and is checked via `tasks/get`.
|
|
268
352
|
*/
|
|
269
353
|
async sendAndWait(message, opts) {
|
|
354
|
+
const timeoutMs = opts?.timeoutMs ?? 5 * 60_000;
|
|
355
|
+
const deadlineMs = Date.now() + timeoutMs;
|
|
270
356
|
const submitted = await this.send(message, {
|
|
271
357
|
contextId: opts?.contextId,
|
|
272
358
|
metadata: opts?.metadata,
|
|
@@ -275,8 +361,10 @@ export class A2AClient {
|
|
|
275
361
|
? { approvedActions: opts.approvedActions }
|
|
276
362
|
: {}),
|
|
277
363
|
async: true,
|
|
364
|
+
requestTimeoutMs: Math.min(this.requestTimeoutMs ?? DEFAULT_A2A_POLL_REQUEST_TIMEOUT_MS, Math.max(1, deadlineMs - Date.now())),
|
|
365
|
+
deadlineMs,
|
|
278
366
|
});
|
|
279
|
-
return this.pollTask(submitted, opts);
|
|
367
|
+
return this.pollTask(submitted, { ...opts, timeoutMs, deadlineMs });
|
|
280
368
|
}
|
|
281
369
|
/**
|
|
282
370
|
* Continue waiting for an existing async task without submitting a second
|
|
@@ -284,9 +372,14 @@ export class A2AClient {
|
|
|
284
372
|
* task is still working.
|
|
285
373
|
*/
|
|
286
374
|
async waitForTask(taskId, opts) {
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
375
|
+
const timeoutMs = opts?.timeoutMs ?? 5 * 60_000;
|
|
376
|
+
const deadlineMs = Date.now() + timeoutMs;
|
|
377
|
+
const current = await this.getTask(taskId, {
|
|
378
|
+
requestTimeoutMs: Math.min(this.requestTimeoutMs ?? DEFAULT_A2A_POLL_REQUEST_TIMEOUT_MS, Math.max(1, deadlineMs - Date.now())),
|
|
379
|
+
deadlineMs,
|
|
380
|
+
});
|
|
381
|
+
safelyNotifyA2AUpdate(opts?.onUpdate, current);
|
|
382
|
+
return this.pollTask(current, { ...opts, timeoutMs, deadlineMs });
|
|
290
383
|
}
|
|
291
384
|
async pollTask(submitted, opts) {
|
|
292
385
|
const terminalStates = new Set([
|
|
@@ -299,7 +392,7 @@ export class A2AClient {
|
|
|
299
392
|
return submitted;
|
|
300
393
|
const timeoutMs = opts?.timeoutMs ?? 5 * 60_000;
|
|
301
394
|
const pollMs = opts?.pollIntervalMs ?? 2_000;
|
|
302
|
-
const deadline = Date.now() + timeoutMs;
|
|
395
|
+
const deadline = opts?.deadlineMs ?? Date.now() + timeoutMs;
|
|
303
396
|
let current = submitted;
|
|
304
397
|
while (Date.now() < deadline) {
|
|
305
398
|
const sleepMs = Math.min(pollMs, Math.max(0, deadline - Date.now()));
|
|
@@ -310,12 +403,17 @@ export class A2AClient {
|
|
|
310
403
|
try {
|
|
311
404
|
current = await this.getTask(submitted.id, {
|
|
312
405
|
requestTimeoutMs: Math.min(this.requestTimeoutMs ?? DEFAULT_A2A_POLL_REQUEST_TIMEOUT_MS, remainingMs),
|
|
406
|
+
deadlineMs: deadline,
|
|
313
407
|
});
|
|
314
|
-
opts?.onUpdate
|
|
408
|
+
safelyNotifyA2AUpdate(opts?.onUpdate, current);
|
|
315
409
|
}
|
|
316
|
-
catch {
|
|
317
|
-
//
|
|
318
|
-
|
|
410
|
+
catch (error) {
|
|
411
|
+
// Retry only transport/gateway interruptions. Authentication,
|
|
412
|
+
// task-not-found, invalid params, and other protocol failures are
|
|
413
|
+
// permanent for this poll and must surface immediately.
|
|
414
|
+
if (isRetryableA2APollError(error))
|
|
415
|
+
continue;
|
|
416
|
+
throw error;
|
|
319
417
|
}
|
|
320
418
|
if (terminalStates.has(current.status.state))
|
|
321
419
|
return current;
|
|
@@ -388,14 +486,14 @@ export class A2AClient {
|
|
|
388
486
|
}
|
|
389
487
|
}
|
|
390
488
|
}
|
|
391
|
-
async ensureEndpointCandidates() {
|
|
489
|
+
async ensureEndpointCandidates(timeoutMs) {
|
|
392
490
|
if (this.endpointResolved)
|
|
393
491
|
return;
|
|
394
492
|
this.endpointResolved = true;
|
|
395
493
|
const candidates = [];
|
|
396
494
|
addDefaultEndpointCandidates(candidates, this.baseUrl);
|
|
397
495
|
try {
|
|
398
|
-
const card = await this.getAgentCard();
|
|
496
|
+
const card = await this.getAgentCard({ timeoutMs });
|
|
399
497
|
const cardUrl = normalizeUrl(card.url, this.baseUrl);
|
|
400
498
|
if (cardUrl) {
|
|
401
499
|
const explicitEndpoint = splitExplicitA2AEndpoint(cardUrl);
|
|
@@ -478,6 +576,92 @@ function normalizeUrl(value, baseUrl) {
|
|
|
478
576
|
function shouldTryNextEndpoint(status) {
|
|
479
577
|
return status === 404 || status === 405;
|
|
480
578
|
}
|
|
579
|
+
function isRetrySafeA2ARpc(method, params, apiKey) {
|
|
580
|
+
if (method === "message/send") {
|
|
581
|
+
return (params.async === true &&
|
|
582
|
+
typeof params.idempotencyKey === "string" &&
|
|
583
|
+
params.idempotencyKey.trim().length > 0 &&
|
|
584
|
+
hasJwtSubject(apiKey));
|
|
585
|
+
}
|
|
586
|
+
return method === "tasks/get" || method === "actions/invoke";
|
|
587
|
+
}
|
|
588
|
+
function isRetryableA2AStatus(status) {
|
|
589
|
+
return (status === 408 ||
|
|
590
|
+
status === 425 ||
|
|
591
|
+
status === 429 ||
|
|
592
|
+
status === 500 ||
|
|
593
|
+
status === 502 ||
|
|
594
|
+
status === 503 ||
|
|
595
|
+
status === 504);
|
|
596
|
+
}
|
|
597
|
+
async function waitForA2ARetry(attempt, retryAfter = null, maxWaitMs) {
|
|
598
|
+
const retryAfterSeconds = retryAfter ? Number(retryAfter) : NaN;
|
|
599
|
+
const retryAfterMs = Number.isFinite(retryAfterSeconds)
|
|
600
|
+
? Math.max(0, Math.min(2_000, retryAfterSeconds * 1_000))
|
|
601
|
+
: 0;
|
|
602
|
+
const backoffMs = Math.max(retryAfterMs, Math.min(1_000, A2A_RPC_RETRY_BASE_MS * 2 ** (attempt - 1)));
|
|
603
|
+
const boundedWaitMs = maxWaitMs === undefined ? backoffMs : Math.min(backoffMs, maxWaitMs);
|
|
604
|
+
if (boundedWaitMs <= 0)
|
|
605
|
+
return;
|
|
606
|
+
await new Promise((resolve) => setTimeout(resolve, boundedWaitMs));
|
|
607
|
+
}
|
|
608
|
+
function remainingA2ADeadlineMs(deadlineMs) {
|
|
609
|
+
return deadlineMs === undefined
|
|
610
|
+
? undefined
|
|
611
|
+
: Math.max(0, deadlineMs - Date.now());
|
|
612
|
+
}
|
|
613
|
+
function resolveA2ARequestTimeoutMs(configuredMs, deadlineMs) {
|
|
614
|
+
const remainingMs = remainingA2ADeadlineMs(deadlineMs);
|
|
615
|
+
if (remainingMs === undefined)
|
|
616
|
+
return configuredMs;
|
|
617
|
+
return configuredMs === undefined
|
|
618
|
+
? remainingMs
|
|
619
|
+
: Math.min(configuredMs, remainingMs);
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Agent-card discovery is only a hint because first-party endpoints have
|
|
623
|
+
* conventional paths. Preserve most of a bounded call's deadline for the
|
|
624
|
+
* actual message instead of letting a cold or unavailable card consume it.
|
|
625
|
+
*/
|
|
626
|
+
function resolveA2ADiscoveryTimeoutMs(configuredMs, deadlineMs) {
|
|
627
|
+
const transportBudgetMs = resolveA2ARequestTimeoutMs(configuredMs, deadlineMs);
|
|
628
|
+
const remainingMs = remainingA2ADeadlineMs(deadlineMs);
|
|
629
|
+
const deadlineShareMs = remainingMs === undefined
|
|
630
|
+
? DEFAULT_A2A_DISCOVERY_TIMEOUT_MS
|
|
631
|
+
: Math.max(1, Math.floor(remainingMs / 4));
|
|
632
|
+
return Math.min(DEFAULT_A2A_DISCOVERY_TIMEOUT_MS, transportBudgetMs ?? DEFAULT_A2A_DISCOVERY_TIMEOUT_MS, deadlineShareMs);
|
|
633
|
+
}
|
|
634
|
+
function hasJwtSubject(apiKey) {
|
|
635
|
+
if (!apiKey)
|
|
636
|
+
return false;
|
|
637
|
+
const segments = apiKey.split(".");
|
|
638
|
+
if (segments.length !== 3)
|
|
639
|
+
return false;
|
|
640
|
+
try {
|
|
641
|
+
const payload = JSON.parse(Buffer.from(segments[1], "base64url").toString("utf8"));
|
|
642
|
+
return typeof payload.sub === "string" && payload.sub.trim().length > 0;
|
|
643
|
+
}
|
|
644
|
+
catch {
|
|
645
|
+
return false;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
function isRetryableA2APollError(error) {
|
|
649
|
+
const message = error instanceof Error ? error.message : String(error ?? "");
|
|
650
|
+
if (isA2AAuthRejection(error))
|
|
651
|
+
return false;
|
|
652
|
+
if (/A2A error \(-32\d+\)|A2A request failed \((?:400|403|404|405|409|422)\)/i.test(message)) {
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
655
|
+
return /(?:A2A request failed \((?:408|425|429|5\d\d)\)|fetch failed|network|socket|ECONN|ETIMEDOUT|timeout|deadline|aborted|invalid JSON)/i.test(message);
|
|
656
|
+
}
|
|
657
|
+
function safelyNotifyA2AUpdate(callback, task) {
|
|
658
|
+
try {
|
|
659
|
+
callback?.(task);
|
|
660
|
+
}
|
|
661
|
+
catch {
|
|
662
|
+
// Presentation/progress callbacks cannot alter task polling.
|
|
663
|
+
}
|
|
664
|
+
}
|
|
481
665
|
function unique(values) {
|
|
482
666
|
return Array.from(new Set(values));
|
|
483
667
|
}
|
|
@@ -521,6 +705,10 @@ export async function callAgent(url, text, opts) {
|
|
|
521
705
|
// detached promises that get killed on Netlify/Vercel. Callers that
|
|
522
706
|
// explicitly want a single-shot blocking POST can pass `async: false`.
|
|
523
707
|
const useAsync = opts?.async ?? true;
|
|
708
|
+
// A stable per-call key makes retrying a submission safe even when this
|
|
709
|
+
// invocation has no durable parent turn id. If the receiver committed the
|
|
710
|
+
// task but the response was lost, the retry reuses the task.
|
|
711
|
+
const effectiveIdempotencyKey = opts?.idempotencyKey ?? (opts?.taskId ? undefined : `auto:${randomUUID()}`);
|
|
524
712
|
const message = {
|
|
525
713
|
role: "user",
|
|
526
714
|
parts: [{ type: "text", text }],
|
|
@@ -546,7 +734,7 @@ export async function callAgent(url, text, opts) {
|
|
|
546
734
|
: await client.sendAndWait(message, {
|
|
547
735
|
contextId: opts?.contextId,
|
|
548
736
|
metadata,
|
|
549
|
-
idempotencyKey:
|
|
737
|
+
idempotencyKey: effectiveIdempotencyKey,
|
|
550
738
|
...(opts?.approvedActions?.length
|
|
551
739
|
? { approvedActions: opts.approvedActions }
|
|
552
740
|
: {}),
|
|
@@ -562,28 +750,47 @@ export async function callAgent(url, text, opts) {
|
|
|
562
750
|
task = await client.send(message, {
|
|
563
751
|
contextId: opts?.contextId,
|
|
564
752
|
metadata,
|
|
565
|
-
idempotencyKey:
|
|
753
|
+
idempotencyKey: effectiveIdempotencyKey,
|
|
566
754
|
...(opts?.approvedActions?.length
|
|
567
755
|
? { approvedActions: opts.approvedActions }
|
|
568
756
|
: {}),
|
|
569
757
|
});
|
|
570
758
|
}
|
|
571
|
-
//
|
|
759
|
+
// Preserve the receiver's typed terminal state. Failed, canceled, and
|
|
760
|
+
// input-required tasks are not successful text answers, even when the
|
|
761
|
+
// receiver attached a friendly explanatory message.
|
|
572
762
|
const responseMessage = task.status.message;
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
763
|
+
const responseText = responseMessage
|
|
764
|
+
? extractMessageText(responseMessage)
|
|
765
|
+
: "";
|
|
766
|
+
const state = task.status.state;
|
|
767
|
+
if (state === "failed" ||
|
|
768
|
+
state === "canceled" ||
|
|
769
|
+
state === "input-required") {
|
|
770
|
+
throw new A2ATaskTerminalError(task, state, responseText);
|
|
771
|
+
}
|
|
772
|
+
if (state !== "completed") {
|
|
773
|
+
throw new A2ATaskTerminalError(task, "failed", responseText || `Unexpected terminal state: ${state}`, "a2a_invalid_terminal_state");
|
|
774
|
+
}
|
|
775
|
+
if (responseText.trim()) {
|
|
776
|
+
if (responseText.length > MAX_A2A_CALLER_RESPONSE_CHARS) {
|
|
777
|
+
throw new A2ATaskTerminalError(task, "completed", responseText, "a2a_response_too_large");
|
|
778
|
+
}
|
|
779
|
+
return responseText;
|
|
578
780
|
}
|
|
579
|
-
|
|
781
|
+
const artifactSummary = verifiedArtifactSummary(task);
|
|
782
|
+
if (artifactSummary)
|
|
783
|
+
return artifactSummary;
|
|
784
|
+
throw new A2ATaskTerminalError(task, "completed", "Agent completed without a response or verified artifact.", "empty_agent_response");
|
|
580
785
|
}
|
|
581
786
|
catch (err) {
|
|
582
787
|
if (opts?.returnRecoverableArtifactsOnTimeout !== false &&
|
|
583
788
|
err instanceof A2ATaskTimeoutError) {
|
|
584
789
|
const recoverableText = extractRecoverableArtifactText(err.lastTask);
|
|
585
|
-
if (recoverableText
|
|
790
|
+
if (recoverableText &&
|
|
791
|
+
recoverableText.length <= MAX_A2A_CALLER_RESPONSE_CHARS) {
|
|
586
792
|
return recoverableText;
|
|
793
|
+
}
|
|
587
794
|
}
|
|
588
795
|
if (i < apiKeyAttempts.length - 1 && isA2AAuthRejection(err)) {
|
|
589
796
|
lastAuthError = err;
|
|
@@ -683,9 +890,67 @@ function extractRecoverableArtifactText(task) {
|
|
|
683
890
|
return extractMessageText(task.status.message);
|
|
684
891
|
}
|
|
685
892
|
function extractMessageText(message) {
|
|
686
|
-
return message.parts
|
|
893
|
+
return (Array.isArray(message.parts) ? message.parts : [])
|
|
687
894
|
.filter((p) => p.type === "text")
|
|
688
895
|
.map((p) => p.text)
|
|
689
896
|
.join("\n");
|
|
690
897
|
}
|
|
898
|
+
function verifiedArtifactSummary(task) {
|
|
899
|
+
const artifacts = Array.isArray(task.artifacts) ? task.artifacts : [];
|
|
900
|
+
if (artifacts.length === 0)
|
|
901
|
+
return "";
|
|
902
|
+
const summaries = artifacts
|
|
903
|
+
.map((artifact, artifactIndex) => {
|
|
904
|
+
const parts = Array.isArray(artifact?.parts) ? artifact.parts : [];
|
|
905
|
+
const usableParts = parts
|
|
906
|
+
.map((part) => summarizeVerifiedArtifactPart(part))
|
|
907
|
+
.filter((value) => !!value)
|
|
908
|
+
.slice(0, 5);
|
|
909
|
+
if (usableParts.length === 0)
|
|
910
|
+
return null;
|
|
911
|
+
const fallbackFileName = parts.find((part) => part.type === "file" && part.file.name?.trim());
|
|
912
|
+
const label = artifact?.name?.trim() ||
|
|
913
|
+
(fallbackFileName?.type === "file"
|
|
914
|
+
? fallbackFileName.file.name?.trim()
|
|
915
|
+
: "") ||
|
|
916
|
+
`Artifact ${artifactIndex + 1}`;
|
|
917
|
+
return `- ${label}\n${usableParts.map((part) => ` - ${part}`).join("\n")}`;
|
|
918
|
+
})
|
|
919
|
+
.filter((value) => !!value)
|
|
920
|
+
.slice(0, 20);
|
|
921
|
+
if (summaries.length === 0)
|
|
922
|
+
return "";
|
|
923
|
+
return boundA2ACallerResponseText(`The agent completed with ${summaries.length} verified artifact(s):\n` +
|
|
924
|
+
summaries.join("\n"));
|
|
925
|
+
}
|
|
926
|
+
function summarizeVerifiedArtifactPart(part) {
|
|
927
|
+
if (!part || typeof part !== "object")
|
|
928
|
+
return null;
|
|
929
|
+
const candidate = part;
|
|
930
|
+
if (candidate.type === "text" && typeof candidate.text === "string") {
|
|
931
|
+
const text = candidate.text.trim();
|
|
932
|
+
return text ? boundA2ACallerResponseText(text).slice(0, 2_000) : null;
|
|
933
|
+
}
|
|
934
|
+
if (candidate.type === "file") {
|
|
935
|
+
const file = candidate.file;
|
|
936
|
+
if (!file)
|
|
937
|
+
return null;
|
|
938
|
+
const uri = typeof file.uri === "string" ? file.uri.trim() : "";
|
|
939
|
+
const name = typeof file.name === "string" ? file.name.trim() : "";
|
|
940
|
+
const bytes = typeof file.bytes === "string" ? file.bytes : "";
|
|
941
|
+
if (uri)
|
|
942
|
+
return name ? `${name}: ${uri}` : uri;
|
|
943
|
+
if (bytes)
|
|
944
|
+
return name ? `${name} (inline file)` : "Inline file artifact";
|
|
945
|
+
return null;
|
|
946
|
+
}
|
|
947
|
+
if (candidate.type === "data") {
|
|
948
|
+
const data = candidate.data;
|
|
949
|
+
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
950
|
+
return null;
|
|
951
|
+
const serialized = JSON.stringify(data);
|
|
952
|
+
return serialized !== "{}" ? serialized.slice(0, 2_000) : null;
|
|
953
|
+
}
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
691
956
|
//# sourceMappingURL=client.js.map
|