@agent-native/core 0.115.4 → 0.117.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-native.eject.json +1 -0
- package/corpus/README.md +3 -3
- package/corpus/core/CHANGELOG.md +43 -0
- package/corpus/core/agent-native.eject.json +1 -0
- package/corpus/core/docs/AGENTS.md +1 -1
- package/corpus/core/docs/content/agent-mentions.mdx +2 -2
- package/corpus/core/docs/content/{workspace.mdx → agent-resources.mdx} +1 -7
- package/corpus/core/docs/content/agent-teams.mdx +4 -4
- package/corpus/core/docs/content/dispatch.mdx +10 -10
- package/corpus/core/docs/content/drop-in-agent.mdx +4 -4
- package/corpus/core/docs/content/external-agents.mdx +1 -1
- package/corpus/core/docs/content/frames.mdx +1 -1
- package/corpus/core/docs/content/integrations.mdx +13 -2
- package/corpus/core/docs/content/key-concepts.mdx +2 -2
- package/corpus/core/docs/content/mcp-clients.mdx +7 -1
- package/corpus/core/docs/content/multi-app-workspace.mdx +3 -3
- package/corpus/core/docs/content/real-time-collaboration.mdx +33 -15
- package/corpus/core/docs/content/recurring-jobs.mdx +7 -7
- package/corpus/core/docs/content/skills-guide.mdx +4 -4
- package/corpus/core/docs/content/template-brain.mdx +1 -1
- package/corpus/core/docs/content/toolkit-collaboration.mdx +1 -1
- package/corpus/core/docs/content/using-your-agent.mdx +1 -1
- package/corpus/core/docs/content/what-is-agent-native.mdx +4 -4
- package/corpus/core/docs/content/workspace-management.mdx +4 -4
- package/corpus/core/package.json +4 -1
- package/corpus/core/src/agent/production-agent.ts +13 -3
- package/corpus/core/src/cli/doctor.ts +6 -1
- package/corpus/core/src/client/AgentPanel.tsx +79 -41
- package/corpus/core/src/client/AssistantChat.tsx +71 -25
- package/corpus/core/src/client/FeedbackButton.tsx +33 -7
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +6 -8
- package/corpus/core/src/client/agent-chat-adapter.ts +11 -2
- package/corpus/core/src/client/agent-page/AgentTabFrame.tsx +22 -3
- package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +34 -19
- package/corpus/core/src/client/analytics.ts +7 -0
- package/corpus/core/src/client/chat/message-components.tsx +43 -16
- package/corpus/core/src/client/chat/tool-call-display.tsx +30 -18
- package/corpus/core/src/client/chat/tool-render-registry.tsx +2 -0
- package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +19 -2
- package/corpus/core/src/client/resources/ResourceTree.tsx +7 -10
- package/corpus/core/src/client/resources/ResourcesPanel.tsx +33 -70
- package/corpus/core/src/client/resources/mcp-connection-resume.ts +107 -0
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +65 -12
- package/corpus/core/src/client/resources/mcp-integration-logos.ts +4 -0
- package/corpus/core/src/client/sse-event-processor.ts +50 -14
- package/corpus/core/src/client/use-db-sync.ts +370 -21
- package/corpus/core/src/collab/client.ts +26 -2
- package/corpus/core/src/connections/catalog.ts +7 -1
- package/corpus/core/src/db/ddl-guard.ts +49 -10
- package/corpus/core/src/deploy/build.ts +25 -2
- package/corpus/core/src/eject/remote-mcp-presets.ts +37 -5
- package/corpus/core/src/guards/explicit-collab-access.ts +229 -0
- package/corpus/core/src/guards/index.ts +1 -0
- package/corpus/core/src/localization/default-messages.ts +54 -5
- package/corpus/core/src/mcp/connect-route.ts +34 -51
- package/corpus/core/src/provider-api/index.ts +1 -1
- package/corpus/core/src/realtime-protocol.ts +92 -0
- package/corpus/core/src/server/collab-plugin.ts +137 -18
- package/corpus/core/src/server/core-routes-plugin.ts +7 -0
- package/corpus/core/src/server/index.ts +2 -0
- package/corpus/core/src/server/poll-events.ts +29 -8
- package/corpus/core/src/server/poll.ts +1123 -865
- package/corpus/core/src/server/realtime-token.ts +106 -0
- package/corpus/core/src/server/sentry-config.ts +40 -0
- package/corpus/core/src/server/short-lived-token.ts +156 -0
- package/corpus/core/src/server/sse.ts +15 -0
- package/corpus/core/src/server/ssr-handler.ts +9 -3
- package/corpus/core/src/styles/agent-native.css +40 -0
- package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/core/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/analytics/AGENTS.md +7 -2
- package/corpus/templates/analytics/actions/export-dashboard-panel-to-google-sheet.ts +144 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -88
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +34 -37
- package/corpus/templates/analytics/app/global.css +0 -4
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -7
- package/corpus/templates/analytics/app/i18n-data.ts +107 -0
- package/corpus/templates/analytics/app/lib/data-source-status.ts +9 -0
- package/corpus/templates/analytics/app/lib/sql-query.ts +1 -2
- package/corpus/templates/analytics/app/pages/Ask.tsx +2 -7
- package/corpus/templates/analytics/app/pages/DataSources.tsx +48 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +59 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +3 -1
- package/corpus/templates/analytics/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-daily-dashboard-email-query-batches.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-export-table-panels-directly-to-google-sheets.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-recent-chats-can-expand-in-the-sidebar.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +8 -8
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +31 -0
- package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +3 -5
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +12 -0
- package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +3 -5
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +150 -21
- package/corpus/templates/analytics/server/lib/google-sheets-export.ts +188 -0
- package/corpus/templates/analytics/server/lib/provider-api.ts +7 -2
- package/corpus/templates/analytics/server/plugins/collab.ts +6 -3
- package/corpus/templates/analytics/shared/sql-query-limits.ts +1 -0
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/assets/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/assets/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +54 -62
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +2 -6
- package/corpus/templates/assets/app/routes/_index.tsx +8 -5
- package/corpus/templates/assets/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-22-recent-chats-expand-from-a-compact-list.md +6 -0
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/brain/actions/rotate-source-ingest-token.ts +77 -0
- package/corpus/templates/brain/app/components/layout/Layout.tsx +5 -1
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +38 -51
- package/corpus/templates/brain/app/hooks/use-navigation-state.ts +2 -9
- package/corpus/templates/brain/app/i18n-data.ts +120 -0
- package/corpus/templates/brain/app/routes/sources.tsx +156 -5
- package/corpus/templates/brain/changelog/2026-07-22-chat-runs-always-end-with-an-answer.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-long-chat-titles-stay-inside-the-sidebar.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-new-clips-and-webhook-sources-now-show-their-secure-connecti.md +6 -0
- package/corpus/templates/brain/jobs/emit-netlify-brain-queue-cron.ts +125 -0
- package/corpus/templates/brain/netlify.toml +5 -1
- package/corpus/templates/brain/scripts/configure-prod-clips-source.ts +50 -0
- package/corpus/templates/brain/server/lib/capture-sanitization.ts +64 -6
- package/corpus/templates/brain/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/brain/server/plugins/brain-jobs.ts +1 -0
- package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +55 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +43 -67
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +2 -7
- package/corpus/templates/chat/app/routes/_index.tsx +8 -5
- package/corpus/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/clips/AGENTS.md +9 -1
- package/corpus/templates/clips/actions/export-to-brain.ts +82 -6
- package/corpus/templates/clips/actions/request-transcript.ts +25 -14
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +12 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
- package/corpus/templates/clips/changelog/2026-07-22-clips-transcripts-now-retry-brain-export.md +5 -0
- package/corpus/templates/clips/changelog/2026-07-22-german-umlauts-and-other-non-ascii-characters-now-paste-corr.md +6 -0
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +26 -3
- package/corpus/templates/clips/jobs/emit-netlify-brain-export-cron.ts +118 -0
- package/corpus/templates/clips/netlify.toml +4 -1
- package/corpus/templates/clips/scripts/configure-prod-brain-export.ts +92 -0
- package/corpus/templates/clips/server/jobs/brain-export.ts +182 -0
- package/corpus/templates/clips/server/lib/brain-export-state.ts +42 -0
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +5 -1
- package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
- package/corpus/templates/clips/server/register-secrets.ts +42 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +10 -1
- package/corpus/templates/clips/server/routes/api/clips/brain-export/run.post.ts +45 -0
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +566 -299
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +14 -0
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -1
- package/corpus/templates/content/app/i18n-data.ts +90 -0
- package/corpus/templates/content/server/plugins/collab.ts +1 -1
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/crm/actions/_crm-data-program-actions.ts +15 -0
- package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +2 -0
- package/corpus/templates/crm/actions/run.ts +2 -6
- package/corpus/templates/crm/actions/update-crm-record.ts +4 -2
- package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-crm-field-validation-now-explains-which-fields-cannot-be-edi.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-fixed-hubspot-contact-syncs-missing-records-updated-after-th.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-fixed-pipeline-dashboard-panels-so-their-opportunity-data-lo.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/crm/server/crm/hubspot-adapter.ts +4 -1
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/design/server/plugins/collab.ts +11 -8
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/forms/app/components/layout/Layout.tsx +1 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/forms/app/hooks/use-navigation-state.ts +2 -9
- package/corpus/templates/forms/app/root.tsx +1 -6
- package/corpus/templates/forms/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/plan/app/components/layout/Layout.tsx +5 -1
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +57 -72
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +2 -9
- package/corpus/templates/plan/app/lib/create-plan-routing.ts +2 -2
- package/corpus/templates/plan/app/pages/PlanChatPage.tsx +0 -1
- package/corpus/templates/plan/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-22-recent-chats-and-sidebar-controls-are-more-compact.md +6 -0
- package/corpus/templates/plan/server/plugins/collab.ts +5 -2
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/slides/server/plugins/collab.ts +11 -8
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/tasks/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +5 -22
- package/corpus/templates/tasks/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/toolkit/CHANGELOG.md +7 -0
- package/corpus/toolkit/README.md +12 -3
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/chat-history/ChatHistoryRail.tsx +89 -0
- package/corpus/toolkit/src/chat-history/index.ts +5 -0
- package/corpus/toolkit/src/chat-history.css +59 -0
- package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +106 -36
- package/corpus/toolkit/src/composer/VoiceButton.tsx +49 -0
- package/corpus/toolkit/src/composer/realtime-voice-audio-level.ts +2 -1
- package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +5 -3
- package/corpus/toolkit/src/styles.css +35 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +13 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/doctor.d.ts +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +5 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +1 -0
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +38 -18
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +55 -20
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/FeedbackButton.d.ts +4 -2
- package/dist/client/FeedbackButton.d.ts.map +1 -1
- package/dist/client/FeedbackButton.js +18 -2
- package/dist/client/FeedbackButton.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +2 -3
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +11 -3
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-page/AgentTabFrame.d.ts +3 -1
- package/dist/client/agent-page/AgentTabFrame.d.ts.map +1 -1
- package/dist/client/agent-page/AgentTabFrame.js +3 -2
- package/dist/client/agent-page/AgentTabFrame.js.map +1 -1
- package/dist/client/agent-page/AgentTabsPage.d.ts +2 -0
- package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
- package/dist/client/agent-page/AgentTabsPage.js +26 -15
- package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
- package/dist/client/analytics.d.ts +10 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +6 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +17 -11
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +11 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +16 -17
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/tool-render-registry.d.ts +2 -0
- package/dist/client/chat/tool-render-registry.d.ts.map +1 -1
- package/dist/client/chat/tool-render-registry.js.map +1 -1
- package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
- package/dist/client/resources/McpConnectionSuggestion.js +15 -1
- package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
- package/dist/client/resources/ResourceTree.d.ts.map +1 -1
- package/dist/client/resources/ResourceTree.js +3 -3
- package/dist/client/resources/ResourceTree.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts +1 -0
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +34 -20
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/client/resources/mcp-connection-resume.d.ts +11 -0
- package/dist/client/resources/mcp-connection-resume.d.ts.map +1 -0
- package/dist/client/resources/mcp-connection-resume.js +95 -0
- package/dist/client/resources/mcp-connection-resume.js.map +1 -0
- package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
- package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.js +63 -8
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/client/resources/mcp-integration-logos.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-logos.js +4 -0
- package/dist/client/resources/mcp-integration-logos.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +5 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +39 -13
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +4 -3
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +332 -21
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +26 -2
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +1 -1
- package/dist/connections/catalog.d.ts.map +1 -1
- package/dist/connections/catalog.js +7 -1
- package/dist/connections/catalog.js.map +1 -1
- package/dist/db/ddl-guard.d.ts +7 -2
- package/dist/db/ddl-guard.d.ts.map +1 -1
- package/dist/db/ddl-guard.js +21 -9
- package/dist/db/ddl-guard.js.map +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +25 -2
- package/dist/deploy/build.js.map +1 -1
- package/dist/eject/remote-mcp-presets.d.ts.map +1 -1
- package/dist/eject/remote-mcp-presets.js +33 -3
- package/dist/eject/remote-mcp-presets.js.map +1 -1
- package/dist/guards/explicit-collab-access.d.ts +8 -0
- package/dist/guards/explicit-collab-access.d.ts.map +1 -0
- package/dist/guards/explicit-collab-access.js +214 -0
- package/dist/guards/explicit-collab-access.js.map +1 -0
- package/dist/guards/index.d.ts +1 -0
- package/dist/guards/index.d.ts.map +1 -1
- package/dist/guards/index.js +1 -0
- package/dist/guards/index.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 +48 -5
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/connect-route.d.ts.map +1 -1
- package/dist/mcp/connect-route.js +34 -48
- package/dist/mcp/connect-route.js.map +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.js +1 -1
- package/dist/provider-api/index.js.map +1 -1
- package/dist/realtime-protocol.d.ts +40 -0
- package/dist/realtime-protocol.d.ts.map +1 -0
- package/dist/realtime-protocol.js +69 -0
- package/dist/realtime-protocol.js.map +1 -0
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/collab-plugin.d.ts +34 -3
- package/dist/server/collab-plugin.d.ts.map +1 -1
- package/dist/server/collab-plugin.js +65 -12
- package/dist/server/collab-plugin.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +3 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/poll-events.d.ts +7 -1
- package/dist/server/poll-events.d.ts.map +1 -1
- package/dist/server/poll-events.js +24 -7
- package/dist/server/poll-events.js.map +1 -1
- package/dist/server/poll.d.ts +223 -42
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +849 -737
- package/dist/server/poll.js.map +1 -1
- package/dist/server/realtime-token.d.ts +34 -0
- package/dist/server/realtime-token.d.ts.map +1 -0
- package/dist/server/realtime-token.js +85 -0
- package/dist/server/realtime-token.js.map +1 -0
- package/dist/server/sentry-config.d.ts +12 -0
- package/dist/server/sentry-config.d.ts.map +1 -1
- package/dist/server/sentry-config.js +34 -0
- package/dist/server/sentry-config.js.map +1 -1
- package/dist/server/short-lived-token.d.ts +46 -0
- package/dist/server/short-lived-token.d.ts.map +1 -1
- package/dist/server/short-lived-token.js +104 -0
- package/dist/server/short-lived-token.js.map +1 -1
- package/dist/server/sse.d.ts +1 -1
- package/dist/server/sse.d.ts.map +1 -1
- package/dist/server/sse.js +4 -0
- package/dist/server/sse.js.map +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +5 -3
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/styles/agent-native.css +40 -0
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/chat/app/components/layout/Layout.tsx +1 -0
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +43 -67
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +2 -7
- package/dist/templates/chat/app/routes/_index.tsx +8 -5
- package/dist/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/dist/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/dist/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
- package/docs/AGENTS.md +1 -1
- package/docs/content/agent-mentions.mdx +2 -2
- package/docs/content/{workspace.mdx → agent-resources.mdx} +1 -7
- package/docs/content/agent-teams.mdx +4 -4
- package/docs/content/dispatch.mdx +10 -10
- package/docs/content/drop-in-agent.mdx +4 -4
- package/docs/content/external-agents.mdx +1 -1
- package/docs/content/frames.mdx +1 -1
- package/docs/content/integrations.mdx +13 -2
- package/docs/content/key-concepts.mdx +2 -2
- package/docs/content/mcp-clients.mdx +7 -1
- package/docs/content/multi-app-workspace.mdx +3 -3
- package/docs/content/real-time-collaboration.mdx +33 -15
- package/docs/content/recurring-jobs.mdx +7 -7
- package/docs/content/skills-guide.mdx +4 -4
- package/docs/content/template-brain.mdx +1 -1
- package/docs/content/toolkit-collaboration.mdx +1 -1
- package/docs/content/using-your-agent.mdx +1 -1
- package/docs/content/what-is-agent-native.mdx +4 -4
- package/docs/content/workspace-management.mdx +4 -4
- package/package.json +6 -3
- package/src/agent/production-agent.ts +13 -3
- package/src/cli/doctor.ts +6 -1
- package/src/client/AgentPanel.tsx +79 -41
- package/src/client/AssistantChat.tsx +71 -25
- package/src/client/FeedbackButton.tsx +33 -7
- package/src/client/MultiTabAssistantChat.tsx +6 -8
- package/src/client/agent-chat-adapter.ts +11 -2
- package/src/client/agent-page/AgentTabFrame.tsx +22 -3
- package/src/client/agent-page/AgentTabsPage.tsx +34 -19
- package/src/client/analytics.ts +7 -0
- package/src/client/chat/message-components.tsx +43 -16
- package/src/client/chat/tool-call-display.tsx +30 -18
- package/src/client/chat/tool-render-registry.tsx +2 -0
- package/src/client/resources/McpConnectionSuggestion.tsx +19 -2
- package/src/client/resources/ResourceTree.tsx +7 -10
- package/src/client/resources/ResourcesPanel.tsx +33 -70
- package/src/client/resources/mcp-connection-resume.ts +107 -0
- package/src/client/resources/mcp-integration-catalog.ts +65 -12
- package/src/client/resources/mcp-integration-logos.ts +4 -0
- package/src/client/sse-event-processor.ts +50 -14
- package/src/client/use-db-sync.ts +370 -21
- package/src/collab/client.ts +26 -2
- package/src/connections/catalog.ts +7 -1
- package/src/db/ddl-guard.ts +49 -10
- package/src/deploy/build.ts +25 -2
- package/src/eject/remote-mcp-presets.ts +37 -5
- package/src/guards/explicit-collab-access.ts +229 -0
- package/src/guards/index.ts +1 -0
- package/src/localization/default-messages.ts +54 -5
- package/src/mcp/connect-route.ts +34 -51
- package/src/provider-api/index.ts +1 -1
- package/src/realtime-protocol.ts +92 -0
- package/src/server/collab-plugin.ts +137 -18
- package/src/server/core-routes-plugin.ts +7 -0
- package/src/server/index.ts +2 -0
- package/src/server/poll-events.ts +29 -8
- package/src/server/poll.ts +1123 -865
- package/src/server/realtime-token.ts +106 -0
- package/src/server/sentry-config.ts +40 -0
- package/src/server/short-lived-token.ts +156 -0
- package/src/server/sse.ts +15 -0
- package/src/server/ssr-handler.ts +9 -3
- package/src/styles/agent-native.css +40 -0
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/chat/app/components/layout/Layout.tsx +1 -0
- package/src/templates/chat/app/components/layout/Sidebar.tsx +43 -67
- package/src/templates/chat/app/hooks/use-navigation-state.ts +2 -7
- package/src/templates/chat/app/routes/_index.tsx +8 -5
- package/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
|
@@ -3,6 +3,14 @@ import {
|
|
|
3
3
|
useActionQuery,
|
|
4
4
|
} from "@agent-native/core/client/hooks";
|
|
5
5
|
import { useT } from "@agent-native/core/client/i18n";
|
|
6
|
+
import {
|
|
7
|
+
Dialog,
|
|
8
|
+
DialogContent,
|
|
9
|
+
DialogDescription,
|
|
10
|
+
DialogFooter,
|
|
11
|
+
DialogHeader,
|
|
12
|
+
DialogTitle,
|
|
13
|
+
} from "@agent-native/toolkit/ui/dialog";
|
|
6
14
|
import {
|
|
7
15
|
IconAlertTriangle,
|
|
8
16
|
IconArchive,
|
|
@@ -12,6 +20,7 @@ import {
|
|
|
12
20
|
IconCircleCheck,
|
|
13
21
|
IconCircleDashed,
|
|
14
22
|
IconClock,
|
|
23
|
+
IconCopy,
|
|
15
24
|
IconDatabaseImport,
|
|
16
25
|
IconDotsVertical,
|
|
17
26
|
IconExternalLink,
|
|
@@ -73,6 +82,7 @@ import {
|
|
|
73
82
|
type BrainCaptureReviewItem,
|
|
74
83
|
type EnqueueCapturesDistillationResponse,
|
|
75
84
|
type CapturesResponse,
|
|
85
|
+
type CreateSourceResponse,
|
|
76
86
|
type BrainSource,
|
|
77
87
|
type BrainWorkspaceConnectionGrantState,
|
|
78
88
|
type BrainWorkspaceConnectionStatus,
|
|
@@ -90,6 +100,10 @@ import {
|
|
|
90
100
|
sourceReviewRequired,
|
|
91
101
|
sourceType,
|
|
92
102
|
} from "@/lib/brain";
|
|
103
|
+
import {
|
|
104
|
+
createOneTimeIngestHandoff,
|
|
105
|
+
type OneTimeIngestHandoff,
|
|
106
|
+
} from "@/lib/ingest-handoff";
|
|
93
107
|
|
|
94
108
|
type Provider = "manual" | "generic" | "clips" | "slack" | "granola" | "github";
|
|
95
109
|
type CaptureStatusFilter = BrainCaptureReviewStatus | "all";
|
|
@@ -1499,16 +1513,25 @@ function SourceFact({ label, value }: { label: string; value: ReactNode }) {
|
|
|
1499
1513
|
);
|
|
1500
1514
|
}
|
|
1501
1515
|
|
|
1516
|
+
function ingestSourceKey(source: BrainSource) {
|
|
1517
|
+
const sourceKey = source.config?.sourceKey;
|
|
1518
|
+
return typeof sourceKey === "string" && sourceKey.trim()
|
|
1519
|
+
? sourceKey.trim()
|
|
1520
|
+
: null;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1502
1523
|
function SourceListItem({
|
|
1503
1524
|
source,
|
|
1504
1525
|
syncPending,
|
|
1505
1526
|
onReview,
|
|
1527
|
+
onRotateIngestToken,
|
|
1506
1528
|
onSync,
|
|
1507
1529
|
onTune,
|
|
1508
1530
|
}: {
|
|
1509
1531
|
source: BrainSource;
|
|
1510
1532
|
syncPending: boolean;
|
|
1511
1533
|
onReview: () => void;
|
|
1534
|
+
onRotateIngestToken?: () => void;
|
|
1512
1535
|
onSync: () => void;
|
|
1513
1536
|
onTune: () => void;
|
|
1514
1537
|
}) {
|
|
@@ -1602,6 +1625,12 @@ function SourceListItem({
|
|
|
1602
1625
|
<IconSettings2 className="size-4" />
|
|
1603
1626
|
{t("sources.tuneSource")}
|
|
1604
1627
|
</DropdownMenuItem>
|
|
1628
|
+
{onRotateIngestToken ? (
|
|
1629
|
+
<DropdownMenuItem onSelect={onRotateIngestToken}>
|
|
1630
|
+
<IconRefresh className="size-4" />
|
|
1631
|
+
{t("sources.rotateIngestToken")}
|
|
1632
|
+
</DropdownMenuItem>
|
|
1633
|
+
) : null}
|
|
1605
1634
|
</DropdownMenuContent>
|
|
1606
1635
|
</DropdownMenu>
|
|
1607
1636
|
</div>
|
|
@@ -1633,6 +1662,11 @@ export default function SourcesRoute() {
|
|
|
1633
1662
|
const type = params.get("type") ?? "all";
|
|
1634
1663
|
const [advancedOpen, setAdvancedOpen] = useState(false);
|
|
1635
1664
|
const [setupOpen, setSetupOpen] = useState(false);
|
|
1665
|
+
const [ingestHandoff, setIngestHandoff] =
|
|
1666
|
+
useState<OneTimeIngestHandoff | null>(null);
|
|
1667
|
+
const [copiedHandoffField, setCopiedHandoffField] = useState<string | null>(
|
|
1668
|
+
null,
|
|
1669
|
+
);
|
|
1636
1670
|
const [editingSource, setEditingSource] = useState<BrainSource | null>(null);
|
|
1637
1671
|
const [reviewSource, setReviewSource] = useState<BrainSource | null>(null);
|
|
1638
1672
|
const [captureStatus, setCaptureStatus] =
|
|
@@ -1672,7 +1706,7 @@ export default function SourcesRoute() {
|
|
|
1672
1706
|
}
|
|
1673
1707
|
>("update-source" as any);
|
|
1674
1708
|
const createSource = useActionMutation<
|
|
1675
|
-
|
|
1709
|
+
CreateSourceResponse,
|
|
1676
1710
|
{
|
|
1677
1711
|
title: string;
|
|
1678
1712
|
provider: Provider;
|
|
@@ -1681,6 +1715,10 @@ export default function SourcesRoute() {
|
|
|
1681
1715
|
sourceKey?: string;
|
|
1682
1716
|
}
|
|
1683
1717
|
>("create-source" as any);
|
|
1718
|
+
const rotateSourceIngestToken = useActionMutation<
|
|
1719
|
+
CreateSourceResponse,
|
|
1720
|
+
{ sourceId: string }
|
|
1721
|
+
>("rotate-source-ingest-token" as any);
|
|
1684
1722
|
const syncSource = useActionMutation<unknown, { sourceId: string }>(
|
|
1685
1723
|
"sync-source" as any,
|
|
1686
1724
|
);
|
|
@@ -1818,10 +1856,20 @@ export default function SourcesRoute() {
|
|
|
1818
1856
|
setForm((current) => ({ ...current, ...patch }));
|
|
1819
1857
|
}
|
|
1820
1858
|
|
|
1821
|
-
function
|
|
1859
|
+
function closeIngestHandoff() {
|
|
1860
|
+
setIngestHandoff(null);
|
|
1861
|
+
setCopiedHandoffField(null);
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
async function copyIngestHandoffValue(value: string, field: string) {
|
|
1865
|
+
await navigator.clipboard.writeText(value);
|
|
1866
|
+
setCopiedHandoffField(field);
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
async function submitSource() {
|
|
1822
1870
|
const config = buildConfig(form);
|
|
1823
1871
|
if (editingSource) {
|
|
1824
|
-
updateSource.
|
|
1872
|
+
await updateSource.mutateAsync({
|
|
1825
1873
|
id: editingSource.id,
|
|
1826
1874
|
title: form.title.trim() || defaultTitle(form.provider, t),
|
|
1827
1875
|
status:
|
|
@@ -1829,17 +1877,39 @@ export default function SourcesRoute() {
|
|
|
1829
1877
|
config,
|
|
1830
1878
|
});
|
|
1831
1879
|
} else {
|
|
1832
|
-
createSource.
|
|
1880
|
+
const result = await createSource.mutateAsync({
|
|
1833
1881
|
title: form.title.trim() || defaultTitle(form.provider, t),
|
|
1834
1882
|
provider: form.provider,
|
|
1835
1883
|
visibility: "org",
|
|
1836
1884
|
config,
|
|
1837
1885
|
sourceKey: form.sourceKey.trim() || undefined,
|
|
1838
1886
|
});
|
|
1887
|
+
const handoff = createOneTimeIngestHandoff({
|
|
1888
|
+
origin: window.location.origin,
|
|
1889
|
+
provider: form.provider,
|
|
1890
|
+
result,
|
|
1891
|
+
sourceKey: form.sourceKey,
|
|
1892
|
+
});
|
|
1893
|
+
if (handoff) setIngestHandoff(handoff);
|
|
1839
1894
|
}
|
|
1840
1895
|
setSetupOpen(false);
|
|
1841
1896
|
}
|
|
1842
1897
|
|
|
1898
|
+
async function rotateIngestToken(source: BrainSource) {
|
|
1899
|
+
const sourceKey = ingestSourceKey(source);
|
|
1900
|
+
if (!sourceKey) return;
|
|
1901
|
+
const result = await rotateSourceIngestToken.mutateAsync({
|
|
1902
|
+
sourceId: source.id,
|
|
1903
|
+
});
|
|
1904
|
+
const handoff = createOneTimeIngestHandoff({
|
|
1905
|
+
origin: window.location.origin,
|
|
1906
|
+
provider: source.provider ?? "",
|
|
1907
|
+
result,
|
|
1908
|
+
sourceKey,
|
|
1909
|
+
});
|
|
1910
|
+
if (handoff) setIngestHandoff(handoff);
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1843
1913
|
function toggleCaptureSelection(captureId: string, checked: boolean) {
|
|
1844
1914
|
setSelectedCaptureIds((current) => {
|
|
1845
1915
|
const next = new Set(current);
|
|
@@ -1909,8 +1979,17 @@ export default function SourcesRoute() {
|
|
|
1909
1979
|
<SourceListItem
|
|
1910
1980
|
key={source.id}
|
|
1911
1981
|
source={source}
|
|
1912
|
-
syncPending={
|
|
1982
|
+
syncPending={
|
|
1983
|
+
syncSource.isPending || rotateSourceIngestToken.isPending
|
|
1984
|
+
}
|
|
1913
1985
|
onReview={() => openCaptureReview(source)}
|
|
1986
|
+
onRotateIngestToken={
|
|
1987
|
+
(source.provider === "clips" ||
|
|
1988
|
+
source.provider === "generic") &&
|
|
1989
|
+
ingestSourceKey(source)
|
|
1990
|
+
? () => void rotateIngestToken(source)
|
|
1991
|
+
: undefined
|
|
1992
|
+
}
|
|
1914
1993
|
onSync={() => syncSource.mutate({ sourceId: source.id })}
|
|
1915
1994
|
onTune={() => openEdit(source)}
|
|
1916
1995
|
/>
|
|
@@ -1928,6 +2007,7 @@ export default function SourcesRoute() {
|
|
|
1928
2007
|
connectionProvidersQuery.isError ||
|
|
1929
2008
|
updateSource.isError ||
|
|
1930
2009
|
createSource.isError ||
|
|
2010
|
+
rotateSourceIngestToken.isError ||
|
|
1931
2011
|
syncSource.isError ||
|
|
1932
2012
|
syncDueSources.isError ||
|
|
1933
2013
|
enqueueCapturesDistillation.isError ? (
|
|
@@ -2302,6 +2382,77 @@ export default function SourcesRoute() {
|
|
|
2302
2382
|
</SheetContent>
|
|
2303
2383
|
</Sheet>
|
|
2304
2384
|
|
|
2385
|
+
<Dialog
|
|
2386
|
+
open={Boolean(ingestHandoff)}
|
|
2387
|
+
onOpenChange={(open) => {
|
|
2388
|
+
if (!open) closeIngestHandoff();
|
|
2389
|
+
}}
|
|
2390
|
+
>
|
|
2391
|
+
{ingestHandoff ? (
|
|
2392
|
+
<DialogContent className="max-w-xl gap-5">
|
|
2393
|
+
<DialogHeader>
|
|
2394
|
+
<DialogTitle>
|
|
2395
|
+
{t("sources.connectIngestSource", {
|
|
2396
|
+
source: ingestHandoff.source.title,
|
|
2397
|
+
})}
|
|
2398
|
+
</DialogTitle>
|
|
2399
|
+
<DialogDescription>
|
|
2400
|
+
{t("sources.ingestHandoffDescription")}
|
|
2401
|
+
</DialogDescription>
|
|
2402
|
+
</DialogHeader>
|
|
2403
|
+
|
|
2404
|
+
<div className="grid gap-4">
|
|
2405
|
+
{[
|
|
2406
|
+
[t("sources.endpoint"), ingestHandoff.endpoint, "endpoint"],
|
|
2407
|
+
[t("sources.sourceKey"), ingestHandoff.sourceKey, "source-key"],
|
|
2408
|
+
[
|
|
2409
|
+
t("sources.ingestToken"),
|
|
2410
|
+
ingestHandoff.ingestToken,
|
|
2411
|
+
"ingest-token",
|
|
2412
|
+
],
|
|
2413
|
+
].map(([label, value, field]) => (
|
|
2414
|
+
<div key={field} className="grid gap-2">
|
|
2415
|
+
<Label htmlFor={`ingest-handoff-${field}`}>{label}</Label>
|
|
2416
|
+
<div className="flex gap-2">
|
|
2417
|
+
<Input
|
|
2418
|
+
id={`ingest-handoff-${field}`}
|
|
2419
|
+
value={value}
|
|
2420
|
+
readOnly
|
|
2421
|
+
className="min-w-0 font-mono text-xs"
|
|
2422
|
+
/>
|
|
2423
|
+
<Button
|
|
2424
|
+
type="button"
|
|
2425
|
+
variant="outline"
|
|
2426
|
+
className="shrink-0"
|
|
2427
|
+
onClick={() => void copyIngestHandoffValue(value, field)}
|
|
2428
|
+
>
|
|
2429
|
+
{copiedHandoffField === field ? (
|
|
2430
|
+
<IconChecks className="size-4" />
|
|
2431
|
+
) : (
|
|
2432
|
+
<IconCopy className="size-4" />
|
|
2433
|
+
)}
|
|
2434
|
+
{copiedHandoffField === field
|
|
2435
|
+
? t("sources.copied")
|
|
2436
|
+
: t("sources.copy")}
|
|
2437
|
+
</Button>
|
|
2438
|
+
</div>
|
|
2439
|
+
</div>
|
|
2440
|
+
))}
|
|
2441
|
+
</div>
|
|
2442
|
+
|
|
2443
|
+
<div className="rounded-md border border-border bg-muted/25 p-3 text-sm leading-6 text-muted-foreground">
|
|
2444
|
+
{t("sources.ingestTokenSecurity")}
|
|
2445
|
+
</div>
|
|
2446
|
+
|
|
2447
|
+
<DialogFooter>
|
|
2448
|
+
<Button type="button" onClick={closeIngestHandoff}>
|
|
2449
|
+
{t("sources.ingestHandoffSaved")}
|
|
2450
|
+
</Button>
|
|
2451
|
+
</DialogFooter>
|
|
2452
|
+
</DialogContent>
|
|
2453
|
+
) : null}
|
|
2454
|
+
</Dialog>
|
|
2455
|
+
|
|
2305
2456
|
<Sheet open={setupOpen} onOpenChange={setSetupOpen}>
|
|
2306
2457
|
<SheetContent className="w-full overflow-y-auto sm:max-w-xl">
|
|
2307
2458
|
<SheetHeader>
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
|
|
3
|
+
import { randomBytes } from "node:crypto";
|
|
4
|
+
import { cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
+
const FUNCTIONS_DIR = path.join(ROOT, ".netlify", "functions-internal");
|
|
10
|
+
const SERVER_DIR = path.join(FUNCTIONS_DIR, "server");
|
|
11
|
+
export const SCHEDULED_NAME = "brain-queue-cron";
|
|
12
|
+
export const WORKER_NAME = "brain-queue-sweep-background";
|
|
13
|
+
export const ROUTE_PATH = "/api/brain/queue/run";
|
|
14
|
+
export const SCHEDULE = "* * * * *";
|
|
15
|
+
|
|
16
|
+
function ensureDir(dir: string) {
|
|
17
|
+
mkdirSync(dir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function scheduledTriggerSource(token: string) {
|
|
21
|
+
return `const WORKER_PATH = "/.netlify/functions/${WORKER_NAME}";
|
|
22
|
+
const CRON_TOKEN = ${JSON.stringify(token)};
|
|
23
|
+
|
|
24
|
+
function siteOrigin(request) {
|
|
25
|
+
return new URL(request.url).origin;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default async function handler(request) {
|
|
29
|
+
const response = await fetch(new URL(WORKER_PATH, siteOrigin(request)), {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: { "content-type": "application/json", "x-agent-native-brain-cron": CRON_TOKEN },
|
|
32
|
+
body: JSON.stringify({ scheduled: true }),
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok && response.status !== 202) {
|
|
35
|
+
console.error("[brain-queue-cron] Background sweep trigger failed:", response.status);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const config = {
|
|
40
|
+
name: "brain queue cron trigger",
|
|
41
|
+
generator: "agent-native brain build",
|
|
42
|
+
schedule: ${JSON.stringify(SCHEDULE)},
|
|
43
|
+
};
|
|
44
|
+
`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function backgroundWorkerSource(token: string) {
|
|
48
|
+
return `globalThis.__AGENT_NATIVE_BRAIN_SCHEDULED_RUNTIME__ = true;
|
|
49
|
+
const CRON_TOKEN = ${JSON.stringify(token)};
|
|
50
|
+
const ROUTE_PATH = ${JSON.stringify(ROUTE_PATH)};
|
|
51
|
+
let cachedHandler;
|
|
52
|
+
|
|
53
|
+
function timingSafeEquals(a, b) {
|
|
54
|
+
if (a.length !== b.length) return false;
|
|
55
|
+
let diff = 0;
|
|
56
|
+
for (let i = 0; i < a.length; i += 1) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
57
|
+
return diff === 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default async function handler(request, context) {
|
|
61
|
+
const token = request.headers.get("x-agent-native-brain-cron") || "";
|
|
62
|
+
if (!timingSafeEquals(token, CRON_TOKEN)) return new Response("Unauthorized", { status: 401 });
|
|
63
|
+
cachedHandler ??= (await import("./main.mjs")).default;
|
|
64
|
+
const url = new URL(request.url);
|
|
65
|
+
url.pathname = ROUTE_PATH;
|
|
66
|
+
url.search = "";
|
|
67
|
+
return cachedHandler(new Request(url, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: { "content-type": "application/json" },
|
|
70
|
+
body: JSON.stringify({ scheduled: true }),
|
|
71
|
+
}), context);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const config = {
|
|
75
|
+
name: "brain queue background sweep",
|
|
76
|
+
generator: "agent-native brain build",
|
|
77
|
+
background: true,
|
|
78
|
+
nodeBundler: "none",
|
|
79
|
+
includedFiles: ["**"],
|
|
80
|
+
preferStatic: false,
|
|
81
|
+
};
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function emitNetlifyBrainQueueCron(
|
|
86
|
+
options: {
|
|
87
|
+
functionsDir?: string;
|
|
88
|
+
serverDir?: string;
|
|
89
|
+
token?: string;
|
|
90
|
+
} = {},
|
|
91
|
+
) {
|
|
92
|
+
const functionsDir = options.functionsDir ?? FUNCTIONS_DIR;
|
|
93
|
+
const serverDir = options.serverDir ?? SERVER_DIR;
|
|
94
|
+
if (!existsSync(serverDir)) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
"Expected Nitro Netlify server output before emitting Brain cron functions.",
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
const token = options.token ?? randomBytes(32).toString("hex");
|
|
100
|
+
const scheduledDir = path.join(functionsDir, SCHEDULED_NAME);
|
|
101
|
+
const workerDir = path.join(functionsDir, WORKER_NAME);
|
|
102
|
+
rmSync(scheduledDir, { recursive: true, force: true });
|
|
103
|
+
rmSync(workerDir, { recursive: true, force: true });
|
|
104
|
+
ensureDir(scheduledDir);
|
|
105
|
+
cpSync(serverDir, workerDir, { recursive: true });
|
|
106
|
+
rmSync(path.join(workerDir, "server.mjs"), { force: true });
|
|
107
|
+
writeFileSync(
|
|
108
|
+
path.join(scheduledDir, `${SCHEDULED_NAME}.mjs`),
|
|
109
|
+
scheduledTriggerSource(token),
|
|
110
|
+
);
|
|
111
|
+
writeFileSync(
|
|
112
|
+
path.join(workerDir, `${WORKER_NAME}.mjs`),
|
|
113
|
+
backgroundWorkerSource(token),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (
|
|
118
|
+
process.argv[1] &&
|
|
119
|
+
path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)
|
|
120
|
+
) {
|
|
121
|
+
emitNetlifyBrainQueueCron();
|
|
122
|
+
console.log(
|
|
123
|
+
"[brain-queue-cron] Emitted scheduled queue sweep and background worker.",
|
|
124
|
+
);
|
|
125
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[build]
|
|
2
2
|
ignore = "node ./scripts/netlify-ignore-build.mjs brain"
|
|
3
|
-
command = "export DATABASE_URL=${NETLIFY_DATABASE_URL:-$DATABASE_URL} && pnpm install && NITRO_PRESET=netlify pnpm --filter brain build"
|
|
3
|
+
command = "export DATABASE_URL=${NETLIFY_DATABASE_URL:-$DATABASE_URL} && pnpm install && NITRO_PRESET=netlify pnpm --filter brain build && pnpm exec tsx templates/brain/jobs/emit-netlify-brain-queue-cron.ts"
|
|
4
4
|
publish = "templates/brain/dist"
|
|
5
5
|
functions = "templates/brain/.netlify/functions-internal"
|
|
6
6
|
|
|
@@ -15,3 +15,7 @@ NPM_CONFIG_PRODUCTION = "false"
|
|
|
15
15
|
# auto-continuation path can hand off before Netlify kills the function.
|
|
16
16
|
[functions."*"]
|
|
17
17
|
timeout = 75
|
|
18
|
+
|
|
19
|
+
[functions.brain-queue-sweep-background]
|
|
20
|
+
timeout = 900
|
|
21
|
+
memory = "2gb"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { writeFile } from "node:fs/promises";
|
|
3
|
+
|
|
4
|
+
import { getDbExec } from "@agent-native/core/db";
|
|
5
|
+
|
|
6
|
+
const tokenFile = process.env.BRAIN_CLIPS_TOKEN_FILE;
|
|
7
|
+
if (!tokenFile) throw new Error("BRAIN_CLIPS_TOKEN_FILE is required");
|
|
8
|
+
|
|
9
|
+
const db = getDbExec();
|
|
10
|
+
const { rows } = await db.execute({
|
|
11
|
+
sql: "SELECT id, source_key, config_json FROM brain_sources WHERE provider = ? AND title = ?",
|
|
12
|
+
args: ["clips", "Clips exports"],
|
|
13
|
+
});
|
|
14
|
+
if (rows.length !== 1) {
|
|
15
|
+
throw new Error(`Expected one Clips exports source, found ${rows.length}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const source = rows[0] as {
|
|
19
|
+
id: string;
|
|
20
|
+
source_key?: string | null;
|
|
21
|
+
config_json?: string | null;
|
|
22
|
+
};
|
|
23
|
+
const sourceKey = source.source_key?.trim() || "clips";
|
|
24
|
+
const token = `brain_${randomBytes(32).toString("base64url")}`;
|
|
25
|
+
const tokenHash = createHash("sha256").update(token).digest("hex");
|
|
26
|
+
const config = JSON.parse(source.config_json || "{}") as Record<
|
|
27
|
+
string,
|
|
28
|
+
unknown
|
|
29
|
+
>;
|
|
30
|
+
config.sourceKey = sourceKey;
|
|
31
|
+
config.ingestTokenHash = tokenHash;
|
|
32
|
+
|
|
33
|
+
await db.execute({
|
|
34
|
+
sql: "UPDATE brain_sources SET source_key = ?, ingest_token_hash = ?, config_json = ?, updated_at = ? WHERE id = ?",
|
|
35
|
+
args: [
|
|
36
|
+
sourceKey,
|
|
37
|
+
tokenHash,
|
|
38
|
+
JSON.stringify(config),
|
|
39
|
+
new Date().toISOString(),
|
|
40
|
+
source.id,
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
await writeFile(tokenFile, token, {
|
|
44
|
+
encoding: "utf8",
|
|
45
|
+
flag: "wx",
|
|
46
|
+
mode: 0o600,
|
|
47
|
+
});
|
|
48
|
+
console.log(
|
|
49
|
+
JSON.stringify({ configured: true, sourceId: source.id, sourceKey }),
|
|
50
|
+
);
|
|
@@ -168,6 +168,10 @@ function preferredDeterministicSection(content: string): string {
|
|
|
168
168
|
return content;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
function hasSummarySection(content: string): boolean {
|
|
172
|
+
return /(?:^|\n)\s*Summary\s*\n/i.test(content);
|
|
173
|
+
}
|
|
174
|
+
|
|
171
175
|
function looksLikeRawTranscriptLine(line: string): boolean {
|
|
172
176
|
return (
|
|
173
177
|
/^\[[^\]\n]{1,80}\]\s*/.test(line) ||
|
|
@@ -208,6 +212,35 @@ function deterministicSanitizeContent(
|
|
|
208
212
|
return retained.join("\n").slice(0, 80_000).trim();
|
|
209
213
|
}
|
|
210
214
|
|
|
215
|
+
function deterministicMeetingOutageFallback(
|
|
216
|
+
input: CaptureSanitizationInput,
|
|
217
|
+
decision: BrainSensitivityDecision,
|
|
218
|
+
capturedAt: string,
|
|
219
|
+
): string | null {
|
|
220
|
+
if (
|
|
221
|
+
decision.disposition !== "allowed" ||
|
|
222
|
+
input.kind !== "transcript" ||
|
|
223
|
+
!["granola", "clips"].includes(input.source.provider) ||
|
|
224
|
+
!shouldSanitizeCaptureBeforeStorage(input) ||
|
|
225
|
+
!hasSummarySection(decision.safeContent) ||
|
|
226
|
+
PERSONAL_SIGNAL.test(decision.safeContent) ||
|
|
227
|
+
RECRUITING_SIGNAL.test(decision.safeContent)
|
|
228
|
+
) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const content = deterministicSanitizeContent(
|
|
233
|
+
sanitizeSensitiveText(decision.safeContent),
|
|
234
|
+
{ dropTranscriptLines: true },
|
|
235
|
+
);
|
|
236
|
+
if (content === DEFAULT_SANITIZATION_OUTPUT) return null;
|
|
237
|
+
|
|
238
|
+
return fallbackSensitivityDecision(content, capturedAt).disposition ===
|
|
239
|
+
"allowed"
|
|
240
|
+
? content
|
|
241
|
+
: null;
|
|
242
|
+
}
|
|
243
|
+
|
|
211
244
|
function safeTranscriptTitle(input: CaptureSanitizationInput): string {
|
|
212
245
|
const date = input.capturedAt?.slice(0, 10);
|
|
213
246
|
const providerLabel =
|
|
@@ -506,7 +539,9 @@ export async function sanitizeCaptureForStorage(
|
|
|
506
539
|
deterministicQuarantineDecision(input.title, capturedAt) ??
|
|
507
540
|
(titleDecision.disposition === "allowed" ? null : titleDecision) ??
|
|
508
541
|
deterministicQuarantineDecision(input.content, capturedAt);
|
|
542
|
+
const sanitizationRequested = shouldSanitizeCaptureBeforeStorage(input);
|
|
509
543
|
let fallbackReason: string | undefined;
|
|
544
|
+
let classifierOutageFallback = false;
|
|
510
545
|
const classifierConfigured = Boolean(
|
|
511
546
|
stringSetting(input.settings.privacyClassifierModel) &&
|
|
512
547
|
stringSetting(input.settings.privacyClassifierEngine),
|
|
@@ -526,13 +561,35 @@ export async function sanitizeCaptureForStorage(
|
|
|
526
561
|
}
|
|
527
562
|
decision ??= fallbackSensitivityDecision(input.content, capturedAt);
|
|
528
563
|
if (classifierFailed) {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
564
|
+
const deterministicMeetingContent = deterministicMeetingOutageFallback(
|
|
565
|
+
input,
|
|
566
|
+
decision,
|
|
567
|
+
capturedAt,
|
|
568
|
+
);
|
|
569
|
+
if (deterministicMeetingContent) {
|
|
570
|
+
classifierOutageFallback = true;
|
|
571
|
+
decision = {
|
|
572
|
+
...decision,
|
|
573
|
+
safeContent: deterministicMeetingContent,
|
|
574
|
+
safeSegments: [
|
|
575
|
+
{
|
|
576
|
+
id: "deterministic-meeting-summary",
|
|
577
|
+
capturedAt,
|
|
578
|
+
text: deterministicMeetingContent,
|
|
579
|
+
reactionCount: 0,
|
|
580
|
+
},
|
|
581
|
+
],
|
|
582
|
+
confidenceBand: "deterministic",
|
|
583
|
+
classifier: "deterministic",
|
|
584
|
+
};
|
|
585
|
+
} else {
|
|
586
|
+
decision = {
|
|
587
|
+
...decision,
|
|
588
|
+
disposition: "quarantined",
|
|
589
|
+
confidenceBand: "uncertain",
|
|
590
|
+
};
|
|
591
|
+
}
|
|
534
592
|
}
|
|
535
|
-
const sanitizationRequested = shouldSanitizeCaptureBeforeStorage(input);
|
|
536
593
|
|
|
537
594
|
const sanitizedContent =
|
|
538
595
|
decision.disposition === "allowed"
|
|
@@ -575,6 +632,7 @@ export async function sanitizeCaptureForStorage(
|
|
|
575
632
|
? input.settings.privacyClassifierModel
|
|
576
633
|
: undefined,
|
|
577
634
|
fallbackReason,
|
|
635
|
+
classifierOutageFallback: classifierOutageFallback || undefined,
|
|
578
636
|
disposition: decision.disposition,
|
|
579
637
|
categories: decision.categories,
|
|
580
638
|
confidenceBand: decision.confidenceBand,
|
|
@@ -10,6 +10,8 @@ import { and, desc, like, or } from "drizzle-orm";
|
|
|
10
10
|
import actionsRegistry from "../../.generated/actions-registry.js";
|
|
11
11
|
import { tryAnswerBrainA2AQuestion } from "../lib/a2a-fallback.js";
|
|
12
12
|
|
|
13
|
+
const BRAIN_BACKGROUND_RUN_SOFT_TIMEOUT_MS = 13 * 60_000;
|
|
14
|
+
|
|
13
15
|
const INITIAL_TOOL_NAMES = [
|
|
14
16
|
"get-brain-settings",
|
|
15
17
|
"ask-brain",
|
|
@@ -39,6 +41,8 @@ export default createAgentChatPlugin({
|
|
|
39
41
|
appId: "brain",
|
|
40
42
|
actions: loadActionsFromStaticRegistry(actionsRegistry),
|
|
41
43
|
initialToolNames: INITIAL_TOOL_NAMES,
|
|
44
|
+
durableBackgroundRuns: true,
|
|
45
|
+
runSoftTimeoutMs: BRAIN_BACKGROUND_RUN_SOFT_TIMEOUT_MS,
|
|
42
46
|
resolveOrgId: async (event) => (await getOrgContext(event)).orgId,
|
|
43
47
|
codeExecution: { production: "sandboxed" },
|
|
44
48
|
systemPrompt: `You are the Brain institutional-knowledge agent.
|
|
@@ -2,6 +2,7 @@ import registerBrainDistillationQueueJob from "../jobs/distillation-queue.js";
|
|
|
2
2
|
import registerBrainSourceSyncJob from "../jobs/sync-sources.js";
|
|
3
3
|
|
|
4
4
|
export default () => {
|
|
5
|
+
if (process.env.NETLIFY === "true") return;
|
|
5
6
|
registerBrainSourceSyncJob();
|
|
6
7
|
registerBrainDistillationQueueJob();
|
|
7
8
|
};
|