@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
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { writeAppState } from "@agent-native/core/application-state";
|
|
2
|
+
import { and, desc, eq, inArray } from "drizzle-orm";
|
|
3
|
+
|
|
4
|
+
import { getDb, schema } from "../db/index.js";
|
|
5
|
+
import {
|
|
6
|
+
nanoid,
|
|
7
|
+
nowIso,
|
|
8
|
+
parseJson,
|
|
9
|
+
readBrainAgentGuidance,
|
|
10
|
+
serializeDistillationQueue,
|
|
11
|
+
stableJson,
|
|
12
|
+
} from "./brain.js";
|
|
13
|
+
|
|
14
|
+
type CaptureRow = typeof schema.brainRawCaptures.$inferSelect;
|
|
15
|
+
type BrainAgentGuidance = Awaited<
|
|
16
|
+
ReturnType<typeof readBrainAgentGuidance>
|
|
17
|
+
>["guidance"];
|
|
18
|
+
|
|
19
|
+
async function writeDistillationRequest(values: {
|
|
20
|
+
captureId: string;
|
|
21
|
+
queueId: string;
|
|
22
|
+
sourceId: string;
|
|
23
|
+
requestedAt: string;
|
|
24
|
+
instructions?: string | null;
|
|
25
|
+
guidance: BrainAgentGuidance;
|
|
26
|
+
}) {
|
|
27
|
+
await writeAppState(`brain-distill-request-${values.captureId}`, {
|
|
28
|
+
kind: "distill-capture",
|
|
29
|
+
captureId: values.captureId,
|
|
30
|
+
queueId: values.queueId,
|
|
31
|
+
sourceId: values.sourceId,
|
|
32
|
+
requestedAt: values.requestedAt,
|
|
33
|
+
instructions: values.instructions ?? null,
|
|
34
|
+
guidance: values.guidance,
|
|
35
|
+
message:
|
|
36
|
+
`Distill Brain capture ${values.captureId} for ${values.guidance.identity.companyName ?? "this workspace"}. ` +
|
|
37
|
+
`Apply the Brain settings guidance in context. Use get-capture with ` +
|
|
38
|
+
`includeRawContent=true when you need exact quote validation, extract ` +
|
|
39
|
+
`only durable company knowledge with exact evidence quotes, ` +
|
|
40
|
+
`call write-knowledge for supported entries or proposals, then call ` +
|
|
41
|
+
`mark-capture-distilled when finished. If the capture is personal or ` +
|
|
42
|
+
`out of scope, call mark-capture-distilled with status ignored.`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function enqueueCaptureDistillation(values: {
|
|
47
|
+
capture: CaptureRow;
|
|
48
|
+
priority?: number;
|
|
49
|
+
instructions?: string;
|
|
50
|
+
payload?: Record<string, unknown>;
|
|
51
|
+
guidance?: BrainAgentGuidance;
|
|
52
|
+
}) {
|
|
53
|
+
const guidance = values.guidance ?? (await readBrainAgentGuidance()).guidance;
|
|
54
|
+
const db = getDb();
|
|
55
|
+
const now = nowIso();
|
|
56
|
+
const [existing] = await db
|
|
57
|
+
.select()
|
|
58
|
+
.from(schema.brainIngestQueue)
|
|
59
|
+
.where(
|
|
60
|
+
and(
|
|
61
|
+
eq(schema.brainIngestQueue.captureId, values.capture.id),
|
|
62
|
+
eq(schema.brainIngestQueue.operation, "distill"),
|
|
63
|
+
inArray(schema.brainIngestQueue.status, ["queued", "processing"]),
|
|
64
|
+
),
|
|
65
|
+
)
|
|
66
|
+
.orderBy(desc(schema.brainIngestQueue.updatedAt))
|
|
67
|
+
.limit(1);
|
|
68
|
+
|
|
69
|
+
if (existing) {
|
|
70
|
+
if (values.capture.status !== "distilling") {
|
|
71
|
+
await db
|
|
72
|
+
.update(schema.brainRawCaptures)
|
|
73
|
+
.set({ status: "distilling", updatedAt: now })
|
|
74
|
+
.where(eq(schema.brainRawCaptures.id, values.capture.id));
|
|
75
|
+
}
|
|
76
|
+
const payload = parseJson<Record<string, unknown>>(
|
|
77
|
+
existing.payloadJson,
|
|
78
|
+
{},
|
|
79
|
+
);
|
|
80
|
+
const existingInstructions =
|
|
81
|
+
typeof payload.instructions === "string"
|
|
82
|
+
? payload.instructions
|
|
83
|
+
: undefined;
|
|
84
|
+
await writeDistillationRequest({
|
|
85
|
+
captureId: values.capture.id,
|
|
86
|
+
queueId: existing.id,
|
|
87
|
+
sourceId: values.capture.sourceId,
|
|
88
|
+
requestedAt: now,
|
|
89
|
+
instructions: values.instructions ?? existingInstructions,
|
|
90
|
+
guidance,
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
queueItem: serializeDistillationQueue(existing),
|
|
94
|
+
existing: true,
|
|
95
|
+
guidance: guidance.distillation,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const id = nanoid();
|
|
100
|
+
const priority = values.priority ?? 50;
|
|
101
|
+
await db.insert(schema.brainIngestQueue).values({
|
|
102
|
+
id,
|
|
103
|
+
sourceId: values.capture.sourceId,
|
|
104
|
+
captureId: values.capture.id,
|
|
105
|
+
operation: "distill",
|
|
106
|
+
status: "queued",
|
|
107
|
+
priority,
|
|
108
|
+
attempts: 0,
|
|
109
|
+
payloadJson: stableJson({
|
|
110
|
+
...(values.payload ?? {}),
|
|
111
|
+
instructions: values.instructions,
|
|
112
|
+
}),
|
|
113
|
+
error: null,
|
|
114
|
+
runAfter: null,
|
|
115
|
+
createdAt: now,
|
|
116
|
+
updatedAt: now,
|
|
117
|
+
});
|
|
118
|
+
await db
|
|
119
|
+
.update(schema.brainRawCaptures)
|
|
120
|
+
.set({ status: "distilling", updatedAt: now })
|
|
121
|
+
.where(eq(schema.brainRawCaptures.id, values.capture.id));
|
|
122
|
+
await writeDistillationRequest({
|
|
123
|
+
captureId: values.capture.id,
|
|
124
|
+
queueId: id,
|
|
125
|
+
sourceId: values.capture.sourceId,
|
|
126
|
+
requestedAt: now,
|
|
127
|
+
instructions: values.instructions ?? null,
|
|
128
|
+
guidance,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
queueItem: {
|
|
133
|
+
id,
|
|
134
|
+
sourceId: values.capture.sourceId,
|
|
135
|
+
captureId: values.capture.id,
|
|
136
|
+
status: "queued" as const,
|
|
137
|
+
priority,
|
|
138
|
+
attempts: 0,
|
|
139
|
+
error: null,
|
|
140
|
+
runAfter: null,
|
|
141
|
+
createdAt: now,
|
|
142
|
+
updatedAt: now,
|
|
143
|
+
},
|
|
144
|
+
existing: false,
|
|
145
|
+
guidance: guidance.distillation,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { accessFilter } from "@agent-native/core/sharing";
|
|
2
|
+
import { and, inArray } from "drizzle-orm";
|
|
3
|
+
|
|
4
|
+
import { getDb, schema } from "../db/index.js";
|
|
5
|
+
import { parseJson } from "./brain.js";
|
|
6
|
+
|
|
7
|
+
export type SourceTrustTier = "blessed" | "standard" | "untrusted";
|
|
8
|
+
export type SourceConflictBehavior =
|
|
9
|
+
| "prefer-higher-authority"
|
|
10
|
+
| "surface-conflicts"
|
|
11
|
+
| "require-review";
|
|
12
|
+
|
|
13
|
+
export interface SourceAnswerPolicy {
|
|
14
|
+
trustTier: SourceTrustTier;
|
|
15
|
+
answerEligible: boolean;
|
|
16
|
+
authority: number;
|
|
17
|
+
freshnessWindowDays: number | null;
|
|
18
|
+
reviewRequired: boolean;
|
|
19
|
+
conflictBehavior: SourceConflictBehavior;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SourcePolicySnapshot extends SourceAnswerPolicy {
|
|
23
|
+
sourceId: string;
|
|
24
|
+
provider: string;
|
|
25
|
+
lastSyncedAt: string | null;
|
|
26
|
+
updatedAt: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface EvaluatedSourceAnswerPolicy extends SourceAnswerPolicy {
|
|
30
|
+
sourceIds: string[];
|
|
31
|
+
eligible: boolean;
|
|
32
|
+
freshness: "fresh" | "stale" | "not-configured";
|
|
33
|
+
exclusionReasons: Array<"answer-ineligible" | "stale" | "review-required">;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const DEFAULT_SOURCE_ANSWER_POLICY: SourceAnswerPolicy = {
|
|
37
|
+
trustTier: "standard",
|
|
38
|
+
answerEligible: true,
|
|
39
|
+
authority: 50,
|
|
40
|
+
freshnessWindowDays: null,
|
|
41
|
+
reviewRequired: false,
|
|
42
|
+
conflictBehavior: "prefer-higher-authority",
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
46
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function isTrustTier(value: unknown): value is SourceTrustTier {
|
|
50
|
+
return ["blessed", "standard", "untrusted"].includes(String(value));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isConflictBehavior(value: unknown): value is SourceConflictBehavior {
|
|
54
|
+
return [
|
|
55
|
+
"prefer-higher-authority",
|
|
56
|
+
"surface-conflicts",
|
|
57
|
+
"require-review",
|
|
58
|
+
].includes(String(value));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function boundedInteger(
|
|
62
|
+
value: unknown,
|
|
63
|
+
fallback: number,
|
|
64
|
+
min: number,
|
|
65
|
+
max: number,
|
|
66
|
+
) {
|
|
67
|
+
const parsed =
|
|
68
|
+
typeof value === "number"
|
|
69
|
+
? value
|
|
70
|
+
: typeof value === "string" && value.trim()
|
|
71
|
+
? Number(value)
|
|
72
|
+
: Number.NaN;
|
|
73
|
+
if (!Number.isFinite(parsed)) return fallback;
|
|
74
|
+
return Math.max(min, Math.min(max, Math.round(parsed)));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function normalizeSourceAnswerPolicy(
|
|
78
|
+
value: unknown,
|
|
79
|
+
base: SourceAnswerPolicy = DEFAULT_SOURCE_ANSWER_POLICY,
|
|
80
|
+
): SourceAnswerPolicy {
|
|
81
|
+
if (!isRecord(value)) return { ...base };
|
|
82
|
+
const trustTier = isTrustTier(value.trustTier)
|
|
83
|
+
? value.trustTier
|
|
84
|
+
: base.trustTier;
|
|
85
|
+
const tierChanged =
|
|
86
|
+
isTrustTier(value.trustTier) && trustTier !== base.trustTier;
|
|
87
|
+
const answerEligible =
|
|
88
|
+
typeof value.answerEligible === "boolean"
|
|
89
|
+
? value.answerEligible
|
|
90
|
+
: tierChanged
|
|
91
|
+
? trustTier !== "untrusted"
|
|
92
|
+
: base.answerEligible;
|
|
93
|
+
const reviewRequired =
|
|
94
|
+
typeof value.reviewRequired === "boolean"
|
|
95
|
+
? value.reviewRequired
|
|
96
|
+
: tierChanged
|
|
97
|
+
? trustTier === "untrusted"
|
|
98
|
+
: base.reviewRequired;
|
|
99
|
+
const freshnessWindowDays =
|
|
100
|
+
value.freshnessWindowDays === null
|
|
101
|
+
? null
|
|
102
|
+
: value.freshnessWindowDays === undefined
|
|
103
|
+
? base.freshnessWindowDays
|
|
104
|
+
: boundedInteger(value.freshnessWindowDays, 0, 0, 3650);
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
trustTier,
|
|
108
|
+
answerEligible,
|
|
109
|
+
authority: boundedInteger(value.authority, base.authority, 0, 100),
|
|
110
|
+
freshnessWindowDays,
|
|
111
|
+
reviewRequired,
|
|
112
|
+
conflictBehavior: isConflictBehavior(value.conflictBehavior)
|
|
113
|
+
? value.conflictBehavior
|
|
114
|
+
: base.conflictBehavior,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function sourceAnswerPolicyFromConfig(
|
|
119
|
+
config: Record<string, unknown>,
|
|
120
|
+
): SourceAnswerPolicy {
|
|
121
|
+
return normalizeSourceAnswerPolicy(config.answerPolicy);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function withSourceAnswerPolicy(
|
|
125
|
+
config: Record<string, unknown>,
|
|
126
|
+
input: unknown,
|
|
127
|
+
): Record<string, unknown> {
|
|
128
|
+
const current = sourceAnswerPolicyFromConfig(config);
|
|
129
|
+
return {
|
|
130
|
+
...config,
|
|
131
|
+
answerPolicy: normalizeSourceAnswerPolicy(input, current),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export async function loadAccessibleSourcePolicySnapshots(
|
|
136
|
+
sourceIds: string[],
|
|
137
|
+
): Promise<Map<string, SourcePolicySnapshot>> {
|
|
138
|
+
const ids = Array.from(new Set(sourceIds.filter(Boolean)));
|
|
139
|
+
if (!ids.length) return new Map();
|
|
140
|
+
const rows = await getDb()
|
|
141
|
+
.select()
|
|
142
|
+
.from(schema.brainSources)
|
|
143
|
+
.where(
|
|
144
|
+
and(
|
|
145
|
+
accessFilter(schema.brainSources, schema.brainSourceShares),
|
|
146
|
+
inArray(schema.brainSources.id, ids),
|
|
147
|
+
),
|
|
148
|
+
);
|
|
149
|
+
return new Map(
|
|
150
|
+
rows.map((row) => [
|
|
151
|
+
row.id,
|
|
152
|
+
{
|
|
153
|
+
sourceId: row.id,
|
|
154
|
+
provider: row.provider,
|
|
155
|
+
lastSyncedAt: row.lastSyncedAt,
|
|
156
|
+
updatedAt: row.updatedAt,
|
|
157
|
+
...sourceAnswerPolicyFromConfig(
|
|
158
|
+
parseJson<Record<string, unknown>>(row.configJson, {}),
|
|
159
|
+
),
|
|
160
|
+
},
|
|
161
|
+
]),
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const TRUST_RANK: Record<SourceTrustTier, number> = {
|
|
166
|
+
blessed: 3,
|
|
167
|
+
standard: 2,
|
|
168
|
+
untrusted: 1,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
function primaryPolicy(policies: SourcePolicySnapshot[]): SourceAnswerPolicy {
|
|
172
|
+
const [primary] = [...policies].sort(
|
|
173
|
+
(left, right) =>
|
|
174
|
+
TRUST_RANK[right.trustTier] - TRUST_RANK[left.trustTier] ||
|
|
175
|
+
right.authority - left.authority,
|
|
176
|
+
);
|
|
177
|
+
return primary ?? DEFAULT_SOURCE_ANSWER_POLICY;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function evaluateSourceAnswerPolicy(args: {
|
|
181
|
+
sourceIds: string[];
|
|
182
|
+
sourcePolicies: Map<string, SourcePolicySnapshot>;
|
|
183
|
+
contentUpdatedAt: string;
|
|
184
|
+
resultType: "knowledge" | "capture";
|
|
185
|
+
reviewed?: boolean;
|
|
186
|
+
now?: Date;
|
|
187
|
+
}): EvaluatedSourceAnswerPolicy {
|
|
188
|
+
const sourceIds = Array.from(new Set(args.sourceIds.filter(Boolean)));
|
|
189
|
+
const effectivePolicies = sourceIds.length
|
|
190
|
+
? sourceIds.map(
|
|
191
|
+
(id) =>
|
|
192
|
+
args.sourcePolicies.get(id) ?? {
|
|
193
|
+
sourceId: id,
|
|
194
|
+
provider: "legacy",
|
|
195
|
+
lastSyncedAt: null,
|
|
196
|
+
updatedAt: args.contentUpdatedAt,
|
|
197
|
+
...DEFAULT_SOURCE_ANSWER_POLICY,
|
|
198
|
+
},
|
|
199
|
+
)
|
|
200
|
+
: [
|
|
201
|
+
{
|
|
202
|
+
sourceId: "",
|
|
203
|
+
provider: "legacy",
|
|
204
|
+
lastSyncedAt: null,
|
|
205
|
+
updatedAt: args.contentUpdatedAt,
|
|
206
|
+
...DEFAULT_SOURCE_ANSWER_POLICY,
|
|
207
|
+
},
|
|
208
|
+
];
|
|
209
|
+
const primary = primaryPolicy(effectivePolicies);
|
|
210
|
+
const now = (args.now ?? new Date()).getTime();
|
|
211
|
+
const updatedAt = Date.parse(args.contentUpdatedAt);
|
|
212
|
+
const stale = effectivePolicies.some((policy) => {
|
|
213
|
+
if (policy.freshnessWindowDays === null) return false;
|
|
214
|
+
if (!Number.isFinite(updatedAt)) return true;
|
|
215
|
+
return now - updatedAt > policy.freshnessWindowDays * 24 * 60 * 60 * 1000;
|
|
216
|
+
});
|
|
217
|
+
const answerIneligible = effectivePolicies.some(
|
|
218
|
+
(policy) => !policy.answerEligible,
|
|
219
|
+
);
|
|
220
|
+
const missingRequiredReview =
|
|
221
|
+
!args.reviewed &&
|
|
222
|
+
effectivePolicies.some(
|
|
223
|
+
(policy) =>
|
|
224
|
+
policy.reviewRequired || policy.conflictBehavior === "require-review",
|
|
225
|
+
);
|
|
226
|
+
const exclusionReasons: EvaluatedSourceAnswerPolicy["exclusionReasons"] = [];
|
|
227
|
+
if (answerIneligible) exclusionReasons.push("answer-ineligible");
|
|
228
|
+
if (stale) exclusionReasons.push("stale");
|
|
229
|
+
if (missingRequiredReview) exclusionReasons.push("review-required");
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
...primary,
|
|
233
|
+
sourceIds,
|
|
234
|
+
reviewRequired: effectivePolicies.some((policy) => policy.reviewRequired),
|
|
235
|
+
freshnessWindowDays: effectivePolicies.reduce<number | null>(
|
|
236
|
+
(minimum, policy) => {
|
|
237
|
+
if (policy.freshnessWindowDays === null) return minimum;
|
|
238
|
+
return minimum === null
|
|
239
|
+
? policy.freshnessWindowDays
|
|
240
|
+
: Math.min(minimum, policy.freshnessWindowDays);
|
|
241
|
+
},
|
|
242
|
+
null,
|
|
243
|
+
),
|
|
244
|
+
eligible: exclusionReasons.length === 0,
|
|
245
|
+
freshness: effectivePolicies.every(
|
|
246
|
+
(policy) => policy.freshnessWindowDays === null,
|
|
247
|
+
)
|
|
248
|
+
? "not-configured"
|
|
249
|
+
: stale
|
|
250
|
+
? "stale"
|
|
251
|
+
: "fresh",
|
|
252
|
+
exclusionReasons,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function compareEvaluatedSourcePolicies(
|
|
257
|
+
left: EvaluatedSourceAnswerPolicy,
|
|
258
|
+
right: EvaluatedSourceAnswerPolicy,
|
|
259
|
+
) {
|
|
260
|
+
return (
|
|
261
|
+
TRUST_RANK[right.trustTier] - TRUST_RANK[left.trustTier] ||
|
|
262
|
+
right.authority - left.authority
|
|
263
|
+
);
|
|
264
|
+
}
|
|
@@ -48,15 +48,16 @@ export default createAgentChatPlugin({
|
|
|
48
48
|
codeExecution: { production: "sandboxed" },
|
|
49
49
|
systemPrompt: `You are the Brain institutional-knowledge agent.
|
|
50
50
|
|
|
51
|
-
Use actions as the source of truth. Import raw material with import-capture or import-transcript, queue distillation
|
|
51
|
+
Use actions as the source of truth. Import raw material with import-capture or import-transcript, which queue distillation by default, use enqueue-distillation to retry or explicitly queue an existing capture, and write durable knowledge with write-knowledge.
|
|
52
52
|
|
|
53
53
|
Important rules:
|
|
54
54
|
- Before answering, searching broadly, or distilling, call get-brain-settings when you do not already have current settings. Apply its guidance for assistant name, company name, tone, source policy, citation requirements, publish tier, pre-save capture sanitization, redaction, and distillation instructions.
|
|
55
55
|
- Evidence quotes must be exact substrings of a raw capture. Use get-capture with includeRawContent=true only when you need exact quote validation; normal capture reads are redacted by default.
|
|
56
56
|
- No vector database exists; search-knowledge uses SQL text matching.
|
|
57
57
|
- Source policy matters: strict means answer from reviewed knowledge only; balanced means raw captures are fallback context when reviewed knowledge is thin; exploratory means raw captures and sources may be surfaced as clearly labeled leads.
|
|
58
|
+
- Source answer policy is enforced separately from the workspace retrieval mode. For approved FAQs, docs, or other source-owner-published resources, create a generic source with policy.trustTier=blessed and choose answer eligibility, authority, freshness, review, and conflict behavior deliberately. Prefer blessed, higher-authority eligible sources in cited answers; never answer from stale or answer-ineligible sources.
|
|
58
59
|
- Company-tier knowledge may create a proposal instead of publishing immediately, depending on settings.
|
|
59
|
-
- Slack and Granola sources are configurable v1 connectors. Generic transcript import
|
|
60
|
+
- Slack and Granola sources are configurable v1 connectors. Generic capture and transcript import are always available.
|
|
60
61
|
- Source/read actions are convenience readers, not provider capability limits. Before any provider API request, call list-connection-providers and inspect the matching provider. If configured is not true, do not attempt the request; explain that the connection needs setup or repair and include setupLink. Jira is queried on demand through the provider API rather than indexed as a Brain source. For ad hoc provider analysis that needs an endpoint, filter, payload, pagination mode, or API version not modeled by a Brain action, call provider-api-catalog/provider-api-docs, then provider-api-request against the provider's real HTTP API. Use connectionId for a specific shared grant and accountId for a specific OAuth account.
|
|
61
62
|
- For broad searches, joins, classification, source-corpus counts, or absence claims across provider records, fetch every relevant page or an explicitly bounded cohort, stage/save large responses with stageAs/saveToFile/fetchAllPages, then use query-staged-dataset or run-code to reduce the corpus. Report source, filters, row counts, pagination, truncation, and gaps.`,
|
|
62
63
|
a2aMessageFallback: async ({ text }) => tryAnswerBrainA2AQuestion(text),
|
|
@@ -11,11 +11,21 @@ import {
|
|
|
11
11
|
BrainCaptureBlockedError,
|
|
12
12
|
createCapture,
|
|
13
13
|
parseJson,
|
|
14
|
+
retireUpstreamDeletedCapture,
|
|
14
15
|
serializeCapture,
|
|
15
16
|
sha256Hex,
|
|
16
17
|
} from "../../../../lib/brain.js";
|
|
18
|
+
import { enqueueCaptureDistillation } from "../../../../lib/distillation-queue.js";
|
|
17
19
|
import { resolveMeetingMemberEmails } from "../../../../lib/meeting-audience.js";
|
|
18
20
|
|
|
21
|
+
const captureKindSchema = z.enum([
|
|
22
|
+
"transcript",
|
|
23
|
+
"note",
|
|
24
|
+
"message",
|
|
25
|
+
"document",
|
|
26
|
+
"generic",
|
|
27
|
+
]);
|
|
28
|
+
|
|
19
29
|
const segmentSchema = z
|
|
20
30
|
.object({
|
|
21
31
|
startMs: z.coerce.number().int().min(0).optional(),
|
|
@@ -29,17 +39,40 @@ const rawCapturePayloadSchema = z
|
|
|
29
39
|
.object({
|
|
30
40
|
sourceKey: z.string().min(1),
|
|
31
41
|
externalId: z.string().min(1),
|
|
32
|
-
title: z.string().min(1),
|
|
42
|
+
title: z.string().min(1).optional(),
|
|
43
|
+
kind: captureKindSchema.optional(),
|
|
44
|
+
content: z.string().optional(),
|
|
33
45
|
participants: z.array(z.unknown()).default([]),
|
|
46
|
+
capturedAt: z.string().optional(),
|
|
34
47
|
occurredAt: z.string().optional(),
|
|
35
48
|
transcript: z.string().optional(),
|
|
36
49
|
segments: z.array(segmentSchema).optional(),
|
|
37
50
|
sourceUrl: z.string().url().optional(),
|
|
38
51
|
tags: z.array(z.string()).default([]),
|
|
52
|
+
metadata: z.record(z.string(), z.unknown()).default({}),
|
|
39
53
|
raw: z.unknown().optional(),
|
|
54
|
+
deleted: z.boolean().default(false),
|
|
40
55
|
})
|
|
41
|
-
.
|
|
42
|
-
|
|
56
|
+
.superRefine((payload, context) => {
|
|
57
|
+
if (payload.deleted) return;
|
|
58
|
+
if (!payload.title) {
|
|
59
|
+
context.addIssue({
|
|
60
|
+
code: "custom",
|
|
61
|
+
message: "Provide title",
|
|
62
|
+
path: ["title"],
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (
|
|
66
|
+
!payload.content?.trim() &&
|
|
67
|
+
!payload.transcript?.trim() &&
|
|
68
|
+
!payload.segments?.length
|
|
69
|
+
) {
|
|
70
|
+
context.addIssue({
|
|
71
|
+
code: "custom",
|
|
72
|
+
message: "Provide content, transcript, or segments",
|
|
73
|
+
path: ["content"],
|
|
74
|
+
});
|
|
75
|
+
}
|
|
43
76
|
});
|
|
44
77
|
|
|
45
78
|
function bearerToken(event: H3Event) {
|
|
@@ -50,6 +83,7 @@ function bearerToken(event: H3Event) {
|
|
|
50
83
|
}
|
|
51
84
|
|
|
52
85
|
function textFromPayload(payload: z.infer<typeof rawCapturePayloadSchema>) {
|
|
86
|
+
if (payload.content?.trim()) return payload.content.trim();
|
|
53
87
|
if (payload.transcript?.trim()) return payload.transcript.trim();
|
|
54
88
|
return (payload.segments ?? [])
|
|
55
89
|
.map((segment) => {
|
|
@@ -60,6 +94,33 @@ function textFromPayload(payload: z.infer<typeof rawCapturePayloadSchema>) {
|
|
|
60
94
|
.trim();
|
|
61
95
|
}
|
|
62
96
|
|
|
97
|
+
function kindFromPayload(payload: z.infer<typeof rawCapturePayloadSchema>) {
|
|
98
|
+
if (payload.kind) return payload.kind;
|
|
99
|
+
if (payload.transcript?.trim() || payload.segments?.length) {
|
|
100
|
+
return "transcript" as const;
|
|
101
|
+
}
|
|
102
|
+
return "generic" as const;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function metadataFromPayload(
|
|
106
|
+
payload: z.infer<typeof rawCapturePayloadSchema>,
|
|
107
|
+
kind: z.infer<typeof captureKindSchema>,
|
|
108
|
+
) {
|
|
109
|
+
const metadata = {
|
|
110
|
+
...payload.metadata,
|
|
111
|
+
sourceKey: payload.sourceKey,
|
|
112
|
+
sourceUrl: payload.sourceUrl,
|
|
113
|
+
tags: payload.tags,
|
|
114
|
+
};
|
|
115
|
+
if (kind !== "transcript") return metadata;
|
|
116
|
+
return {
|
|
117
|
+
...metadata,
|
|
118
|
+
participants: payload.participants,
|
|
119
|
+
segments: payload.segments ?? [],
|
|
120
|
+
raw: payload.raw,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
63
124
|
function sourceKeyConfigPattern(sourceKey: string) {
|
|
64
125
|
return `%"sourceKey":${JSON.stringify(sourceKey)}%`;
|
|
65
126
|
}
|
|
@@ -112,6 +173,22 @@ export default defineEventHandler(async (event) => {
|
|
|
112
173
|
orgId: source.orgId ?? undefined,
|
|
113
174
|
},
|
|
114
175
|
async () => {
|
|
176
|
+
if (payload.deleted) {
|
|
177
|
+
const retired = await retireUpstreamDeletedCapture({
|
|
178
|
+
sourceId: source.id,
|
|
179
|
+
externalId: payload.externalId,
|
|
180
|
+
provider: source.provider,
|
|
181
|
+
});
|
|
182
|
+
return {
|
|
183
|
+
ok: true,
|
|
184
|
+
sourceId: source.id,
|
|
185
|
+
capture: null,
|
|
186
|
+
deleted: true,
|
|
187
|
+
retired,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const kind = kindFromPayload(payload);
|
|
115
192
|
const memberEmails = resolveMeetingMemberEmails(
|
|
116
193
|
payload.participants,
|
|
117
194
|
source.ownerEmail,
|
|
@@ -121,23 +198,19 @@ export default defineEventHandler(async (event) => {
|
|
|
121
198
|
capture = await createCapture({
|
|
122
199
|
sourceId: source.id,
|
|
123
200
|
externalId: payload.externalId,
|
|
124
|
-
title: payload.title
|
|
125
|
-
kind
|
|
201
|
+
title: payload.title!,
|
|
202
|
+
kind,
|
|
126
203
|
content: textFromPayload(payload),
|
|
127
|
-
capturedAt: payload.occurredAt,
|
|
128
|
-
metadata:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
kind: "meeting",
|
|
138
|
-
memberEmails,
|
|
139
|
-
upstreamRefHash: payload.externalId,
|
|
140
|
-
},
|
|
204
|
+
capturedAt: payload.capturedAt ?? payload.occurredAt,
|
|
205
|
+
metadata: metadataFromPayload(payload, kind),
|
|
206
|
+
audience:
|
|
207
|
+
kind === "transcript"
|
|
208
|
+
? {
|
|
209
|
+
kind: "meeting",
|
|
210
|
+
memberEmails,
|
|
211
|
+
upstreamRefHash: payload.externalId,
|
|
212
|
+
}
|
|
213
|
+
: undefined,
|
|
141
214
|
});
|
|
142
215
|
} catch (error) {
|
|
143
216
|
if (!(error instanceof BrainCaptureBlockedError)) throw error;
|
|
@@ -149,10 +222,34 @@ export default defineEventHandler(async (event) => {
|
|
|
149
222
|
};
|
|
150
223
|
}
|
|
151
224
|
|
|
225
|
+
const distillation =
|
|
226
|
+
capture.status === "distilled" || capture.status === "ignored"
|
|
227
|
+
? null
|
|
228
|
+
: await enqueueCaptureDistillation({
|
|
229
|
+
capture,
|
|
230
|
+
priority: 50,
|
|
231
|
+
payload: {
|
|
232
|
+
sourceKey: payload.sourceKey,
|
|
233
|
+
externalId: payload.externalId,
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
|
|
152
237
|
return {
|
|
153
238
|
ok: true,
|
|
154
239
|
sourceId: source.id,
|
|
155
240
|
capture: serializeCapture(capture),
|
|
241
|
+
distillation: distillation
|
|
242
|
+
? {
|
|
243
|
+
queued: true,
|
|
244
|
+
queueId: distillation.queueItem.id,
|
|
245
|
+
existing: distillation.existing,
|
|
246
|
+
}
|
|
247
|
+
: {
|
|
248
|
+
queued: false,
|
|
249
|
+
queueId: null,
|
|
250
|
+
existing: false,
|
|
251
|
+
reason: `already-${capture.status}`,
|
|
252
|
+
},
|
|
156
253
|
};
|
|
157
254
|
},
|
|
158
255
|
);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
import { IconAlertTriangle, IconInfoCircle } from "@tabler/icons-react";
|
|
3
|
+
|
|
4
|
+
import { Button } from "@/components/ui/button";
|
|
5
|
+
import {
|
|
6
|
+
Popover,
|
|
7
|
+
PopoverContent,
|
|
8
|
+
PopoverTrigger,
|
|
9
|
+
} from "@/components/ui/popover";
|
|
10
|
+
import { cn } from "@/lib/utils";
|
|
11
|
+
|
|
12
|
+
export function GoogleOAuthIdentityNotice({
|
|
13
|
+
className,
|
|
14
|
+
}: {
|
|
15
|
+
className?: string;
|
|
16
|
+
}) {
|
|
17
|
+
const t = useT();
|
|
18
|
+
return (
|
|
19
|
+
<Popover>
|
|
20
|
+
<PopoverTrigger asChild>
|
|
21
|
+
<Button
|
|
22
|
+
type="button"
|
|
23
|
+
variant="ghost"
|
|
24
|
+
size="sm"
|
|
25
|
+
className={cn(
|
|
26
|
+
"h-auto gap-1 px-0 py-0 text-[11px] font-normal text-muted-foreground/70 hover:bg-transparent hover:text-muted-foreground",
|
|
27
|
+
className,
|
|
28
|
+
)}
|
|
29
|
+
>
|
|
30
|
+
<IconInfoCircle className="size-3" />
|
|
31
|
+
{t("meetingsRoute.googleMayShowWarning")}
|
|
32
|
+
</Button>
|
|
33
|
+
</PopoverTrigger>
|
|
34
|
+
<PopoverContent align="start" className="w-72 text-start">
|
|
35
|
+
<div className="flex items-start gap-2.5">
|
|
36
|
+
<div className="mt-0.5 flex size-6 shrink-0 items-center justify-center rounded-md bg-amber-500/15 text-amber-300">
|
|
37
|
+
<IconAlertTriangle className="size-3.5" />
|
|
38
|
+
</div>
|
|
39
|
+
<div className="space-y-1.5">
|
|
40
|
+
<p className="text-[13px] font-medium text-foreground">
|
|
41
|
+
{t("meetingsRoute.googleNotVerifiedTitle")}
|
|
42
|
+
</p>
|
|
43
|
+
<p className="text-xs leading-relaxed text-muted-foreground">
|
|
44
|
+
{t("meetingsRoute.googleWarningBeforeAdvanced")}
|
|
45
|
+
</p>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</PopoverContent>
|
|
49
|
+
</Popover>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -1498,6 +1498,10 @@ All notable user-facing changes to Clips are documented here. Open it any time f
|
|
|
1498
1498
|
calendarNeedsReconnect:
|
|
1499
1499
|
"Google Calendar needs to be reconnected to keep showing your upcoming meetings.",
|
|
1500
1500
|
connectGoogleCalendar: "Connect Google Calendar",
|
|
1501
|
+
googleMayShowWarning: "Review Google access",
|
|
1502
|
+
googleNotVerifiedTitle: "Verify the app before connecting",
|
|
1503
|
+
googleWarningBeforeAdvanced:
|
|
1504
|
+
"Confirm the app name and requested Calendar access match the Clips deployment you trust. If Google shows an unverified-app warning or the identity looks unfamiliar, stop and contact your workspace administrator.",
|
|
1501
1505
|
desktopReminder:
|
|
1502
1506
|
"Connect Google Calendar, keep Clips Desktop open, then click Start notes from the reminder or the menu bar when your meeting begins.",
|
|
1503
1507
|
getDesktopApp: "Get desktop app",
|