@agent-native/core 0.121.2 → 0.122.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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +139 -0
- package/corpus/core/docs/content/actions.mdx +2 -2
- package/corpus/core/docs/content/agent-surfaces.mdx +1 -1
- package/corpus/core/docs/content/authentication.mdx +2 -0
- package/corpus/core/docs/content/deployment.mdx +36 -0
- package/corpus/core/docs/content/http-api.mdx +266 -0
- package/corpus/core/docs/content/syncing-template-changes.mdx +159 -0
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/a2a/activity.ts +38 -27
- package/corpus/core/src/agent/engine/builder-engine.ts +35 -4
- package/corpus/core/src/agent/run-manager.ts +20 -1
- package/corpus/core/src/agent/run-store.ts +4 -1
- package/corpus/core/src/agent/types.ts +28 -8
- package/corpus/core/src/chat-threads/store.ts +45 -0
- package/corpus/core/src/checkpoints/index.ts +2 -0
- package/corpus/core/src/checkpoints/route-match.ts +13 -0
- package/corpus/core/src/cli/create.ts +105 -17
- package/corpus/core/src/cli/index.ts +20 -0
- package/corpus/core/src/cli/template-baseline.ts +410 -0
- package/corpus/core/src/cli/template-sync.ts +1004 -0
- package/corpus/core/src/cli/templates-meta.ts +1 -0
- package/corpus/core/src/client/AssistantChat.tsx +38 -12
- package/corpus/core/src/client/NewWorkspaceAppFlow.tsx +75 -10
- package/corpus/core/src/client/chat/message-components.tsx +127 -66
- package/corpus/core/src/client/chat/tool-call-display.tsx +29 -5
- package/corpus/core/src/client/error-format.ts +18 -0
- package/corpus/core/src/client/org/OrgSwitcher.tsx +30 -8
- package/corpus/core/src/client/org/TeamPage.tsx +7 -6
- package/corpus/core/src/client/sse-event-processor.ts +3 -0
- package/corpus/core/src/data-widgets/index.ts +41 -0
- package/corpus/core/src/deploy/build.ts +11 -9
- package/corpus/core/src/integrations/webhook-handler.ts +63 -9
- package/corpus/core/src/org/auto-join-domain.ts +4 -3
- package/corpus/core/src/org/context.ts +108 -39
- package/corpus/core/src/org/index.ts +5 -0
- package/corpus/core/src/org/service-identity.ts +60 -0
- package/corpus/core/src/provider-api/index.ts +22 -1
- package/corpus/core/src/scripts/docs/search.ts +12 -1
- package/corpus/core/src/server/agent-chat/context-tools.ts +9 -4
- package/corpus/core/src/server/agent-chat/framework-prompts.ts +38 -66
- package/corpus/core/src/server/agent-chat-plugin.ts +17 -10
- package/corpus/core/src/server/agents-bundle.ts +84 -5
- package/corpus/core/src/server/auth.ts +4 -3
- package/corpus/core/src/server/builder-browser.ts +47 -19
- package/corpus/core/src/server/core-routes-plugin.ts +2 -2
- package/corpus/core/src/server/credential-provider.ts +209 -68
- package/corpus/core/src/server/index.ts +3 -0
- package/corpus/core/src/server/prompts/framework-core-compact.ts +6 -13
- package/corpus/core/src/server/prompts/framework-core.ts +9 -21
- package/corpus/core/src/server/prompts/index.ts +0 -1
- package/corpus/core/src/server/prompts/shared-rules.ts +19 -11
- package/corpus/core/src/server/ssr-handler.ts +13 -2
- package/corpus/core/src/settings/user-settings.ts +13 -1
- package/corpus/core/src/shared/cache-control.ts +141 -0
- package/corpus/core/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/core/src/templates/chat/_gitignore +1 -0
- package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
- package/corpus/core/src/vite/agents-bundle-plugin.ts +7 -6
- package/corpus/core/src/vite/client.ts +5 -0
- package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +4 -5
- package/corpus/templates/analytics/.agents/skills/admin-surfaces/SKILL.md +55 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +10 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/references/template-catalog-and-demo.md +62 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +85 -0
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +27 -2
- package/corpus/templates/analytics/.agents/skills/data-querying/references/inline-chart-embeds.md +139 -0
- package/corpus/templates/analytics/.agents/skills/monitoring/SKILL.md +77 -0
- package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/analytics/AGENTS.md +91 -563
- package/corpus/templates/analytics/_gitignore +1 -0
- package/corpus/templates/analytics/actions/bigquery.ts +12 -4
- package/corpus/templates/analytics/actions/generate-chart.ts +5 -5
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +30 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +3 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +1 -0
- package/corpus/templates/analytics/changelog/2026-07-24-analytics-finds-saved-dashboards-and-queries-far-more-reliab.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-24-notion-access-errors-now-explain-that-a-page-needs-sharing-w.md +6 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +7 -0
- package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +191 -30
- package/corpus/templates/analytics/server/lib/bigquery.ts +11 -1
- package/corpus/templates/analytics/server/lib/notion.ts +15 -4
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +10 -0
- package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/brain/_gitignore +1 -0
- package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/calendar/_gitignore +1 -0
- package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/chat/_gitignore +1 -0
- package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +34 -0
- package/corpus/templates/clips/AGENTS.md +5 -4
- package/corpus/templates/clips/_gitignore +1 -0
- package/corpus/templates/clips/actions/cleanup-transcript.ts +5 -0
- package/corpus/templates/clips/actions/get-recording-insights.ts +44 -8
- package/corpus/templates/clips/actions/get-recording-player-data.ts +39 -70
- package/corpus/templates/clips/actions/list-clip-views.ts +2 -4
- package/corpus/templates/clips/actions/list-recordings.ts +69 -19
- package/corpus/templates/clips/actions/list-viewers.ts +5 -2
- package/corpus/templates/clips/actions/regenerate-summary.ts +5 -1
- package/corpus/templates/clips/actions/request-transcript.ts +28 -1
- package/corpus/templates/clips/app/components/editor/stitch-manager.tsx +21 -1
- package/corpus/templates/clips/app/components/meetings/quick-ask-sidebar.tsx +14 -1
- package/corpus/templates/clips/app/components/player/insights-panel.tsx +8 -20
- package/corpus/templates/clips/app/components/player/recording-views-badge.tsx +335 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +13 -8
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +2 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +13 -2
- package/corpus/templates/clips/app/lib/capture-permissions.ts +110 -0
- package/corpus/templates/clips/app/lib/recording-link.ts +32 -0
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +27 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +46 -15
- package/corpus/templates/clips/app/routes/record.tsx +77 -31
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +42 -31
- package/corpus/templates/clips/changelog/2026-07-24-clip-pages-now-show-a-view-count-with-viewer-avatars-next-to.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-clip-summaries-read-like-a-description-you-d-write-yourself-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-clip-view-counts-now-separate-human-views-from-agent-views-s.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-clips-actions-can-now-be-called-by-org-service-tokens-so-ext.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-clips-no-longer-briefly-shows-a-dock-icon-while-launching.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-fixed-owner-and-editor-share-links-redirecting-to-the-record.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-meeting-and-note-recordings-now-start-as-a-compact-pill-on-t.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-new-clips-now-copy-a-shareable-link-instead-of-the-owner-onl.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-opening-a-share-link-as-the-clip-s-owner-now-goes-straight-t.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-permissions-and-rewind-controls-now-use-compact-consistent-h.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-quitting-the-desktop-app-no-longer-shows-a-false-macos-crash.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-screen-recording-permission-errors-now-name-the-exact-app-to.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-the-desktop-app-now-copies-a-new-clip-s-share-link-to-your-c.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-the-recording-toolbar-now-stays-above-other-apps-including-o.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-transcript-captions-now-use-real-speech-timings-instead-of-a.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-video-playback-no-longer-stutters-and-replays-the-last-momen.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +17 -1
- package/corpus/templates/clips/desktop/package.json +2 -0
- package/corpus/templates/clips/desktop/src/app.tsx +89 -0
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +9 -3
- package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +51 -0
- package/corpus/templates/clips/desktop/src/lib/native-notification.ts +44 -0
- package/corpus/templates/clips/desktop/src/lib/recording-link.ts +67 -0
- package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +35 -35
- package/corpus/templates/clips/desktop/src/overlays/live-transcript.tsx +3 -2
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +47 -46
- package/corpus/templates/clips/desktop/src/styles.css +127 -78
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +7 -0
- package/corpus/templates/clips/desktop/src-tauri/Info.plist +6 -0
- package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +1 -0
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +7 -3
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +4 -1
- package/corpus/templates/clips/desktop/src-tauri/src/main.rs +8 -0
- package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +21 -10
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +40 -0
- package/corpus/templates/clips/server/db/schema.ts +25 -0
- package/corpus/templates/clips/server/lib/agent-views.ts +145 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +7 -0
- package/corpus/templates/clips/server/lib/recording-share-grant.ts +79 -0
- package/corpus/templates/clips/server/lib/recordings.ts +51 -3
- package/corpus/templates/clips/server/plugins/db.ts +23 -0
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +49 -17
- package/corpus/templates/clips/shared/recording-link.ts +43 -0
- package/corpus/templates/clips/shared/share-attribution.ts +4 -0
- package/corpus/templates/clips/shared/share-dashboard-redirect.ts +42 -0
- package/corpus/templates/clips/shared/view-analytics.ts +26 -0
- package/corpus/templates/content/.agents/skills/content/SKILL.md +5 -0
- package/corpus/templates/content/.agents/skills/content/references/local-file-mode.md +135 -0
- package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +12 -0
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +238 -0
- package/corpus/templates/content/.agents/skills/document-editing/references/document-behavior.md +91 -0
- package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/content/AGENTS.md +62 -583
- package/corpus/templates/content/_gitignore +1 -0
- package/corpus/templates/design/.agents/skills/creative-context/SKILL.md +11 -0
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +50 -8
- package/corpus/templates/design/.agents/skills/design-generation/references/code-layers.md +81 -0
- package/corpus/templates/design/.agents/skills/design-generation/references/code-workspace.md +42 -0
- package/corpus/templates/design/.agents/skills/design-generation/references/editor-extensions.md +34 -0
- package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +4 -1
- package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +17 -0
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +8196 -0
- package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +265 -0
- package/corpus/templates/design/.generated/bridge/hit-test.generated.ts +642 -0
- package/corpus/templates/design/.generated/bridge/motion-preview.generated.ts +571 -0
- package/corpus/templates/design/.generated/bridge/nav.generated.ts +91 -0
- package/corpus/templates/design/.generated/bridge/sample.generated.ts +23 -0
- package/corpus/templates/design/.generated/bridge/shader-fill-preview.generated.ts +263 -0
- package/corpus/templates/design/.generated/bridge/shader-runtime.generated.ts +518 -0
- package/corpus/templates/design/.generated/bridge/tweak.generated.ts +20 -0
- package/corpus/templates/design/.generated/bridge/zoom.generated.ts +32 -0
- package/corpus/templates/design/AGENTS.md +88 -503
- package/corpus/templates/design/_gitignore +1 -0
- package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/dispatch/_gitignore +1 -0
- package/corpus/templates/dispatch/changelog/2026-07-24-signing-in-now-puts-you-in-your-companys-workspace.md +6 -0
- package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/forms/_gitignore +1 -0
- package/corpus/templates/forms/server/lib/public-form-ssr.ts +2 -2
- package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/macros/_gitignore +1 -0
- package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/mail/_gitignore +1 -0
- package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/plan/_gitignore +1 -0
- package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/slides/_gitignore +1 -0
- package/corpus/templates/slides/server/plugins/db.ts +4 -0
- package/corpus/templates/tasks/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/corpus/templates/tasks/AGENTS.md +1 -1
- package/corpus/templates/tasks/_gitignore +1 -0
- package/dist/a2a/activity.d.ts +4 -1
- package/dist/a2a/activity.d.ts.map +1 -1
- package/dist/a2a/activity.js +27 -16
- package/dist/a2a/activity.js.map +1 -1
- package/dist/agent/engine/builder-engine.d.ts +1 -0
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +31 -4
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +18 -1
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +1 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +2 -1
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/types.d.ts +12 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js +21 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/chat-threads/store.d.ts +10 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +41 -0
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/checkpoints/index.d.ts +1 -0
- package/dist/checkpoints/index.d.ts.map +1 -1
- package/dist/checkpoints/index.js +1 -0
- package/dist/checkpoints/index.js.map +1 -1
- package/dist/checkpoints/route-match.d.ts +8 -0
- package/dist/checkpoints/route-match.d.ts.map +1 -0
- package/dist/checkpoints/route-match.js +13 -0
- package/dist/checkpoints/route-match.js.map +1 -0
- package/dist/cli/create.d.ts +35 -4
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +69 -19
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.js +19 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/template-baseline.d.ts +54 -0
- package/dist/cli/template-baseline.d.ts.map +1 -0
- package/dist/cli/template-baseline.js +334 -0
- package/dist/cli/template-baseline.js.map +1 -0
- package/dist/cli/template-sync.d.ts +57 -0
- package/dist/cli/template-sync.d.ts.map +1 -0
- package/dist/cli/template-sync.js +787 -0
- package/dist/cli/template-sync.js.map +1 -0
- package/dist/cli/templates-meta.d.ts.map +1 -1
- package/dist/cli/templates-meta.js +1 -0
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +38 -10
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.js +32 -2
- package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +20 -0
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +81 -46
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +14 -6
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/error-format.d.ts.map +1 -1
- package/dist/client/error-format.js +13 -0
- package/dist/client/error-format.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts +8 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +3 -2
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +1 -1
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +3 -0
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/data-widgets/index.d.ts +3 -0
- package/dist/data-widgets/index.d.ts.map +1 -1
- package/dist/data-widgets/index.js +33 -0
- package/dist/data-widgets/index.js.map +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +11 -7
- package/dist/deploy/build.js.map +1 -1
- package/dist/eject/provider-api-definitions.d.ts +1 -0
- package/dist/eject/provider-api-definitions.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +46 -9
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/org/auto-join-domain.d.ts +3 -2
- package/dist/org/auto-join-domain.d.ts.map +1 -1
- package/dist/org/auto-join-domain.js +1 -1
- package/dist/org/auto-join-domain.js.map +1 -1
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/context.js +84 -28
- package/dist/org/context.js.map +1 -1
- package/dist/org/index.d.ts +1 -0
- package/dist/org/index.d.ts.map +1 -1
- package/dist/org/index.js +1 -0
- package/dist/org/index.js.map +1 -1
- package/dist/org/service-identity.d.ts +43 -0
- package/dist/org/service-identity.d.ts.map +1 -0
- package/dist/org/service-identity.js +34 -0
- package/dist/org/service-identity.js.map +1 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
- package/dist/provider-api/actions/provider-api.d.ts +13 -11
- package/dist/provider-api/actions/provider-api.d.ts.map +1 -1
- package/dist/provider-api/index.d.ts +4 -0
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +17 -1
- package/dist/provider-api/index.js.map +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/docs/search.d.ts.map +1 -1
- package/dist/scripts/docs/search.js +12 -1
- package/dist/scripts/docs/search.js.map +1 -1
- package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
- package/dist/server/agent-chat/context-tools.js +3 -3
- package/dist/server/agent-chat/context-tools.js.map +1 -1
- package/dist/server/agent-chat/framework-prompts.d.ts +8 -3
- package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -1
- package/dist/server/agent-chat/framework-prompts.js +33 -62
- package/dist/server/agent-chat/framework-prompts.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +16 -10
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agents-bundle.d.ts +18 -0
- package/dist/server/agents-bundle.d.ts.map +1 -1
- package/dist/server/agents-bundle.js +70 -4
- package/dist/server/agents-bundle.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +4 -3
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +43 -19
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.js +2 -2
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +38 -2
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +142 -64
- package/dist/server/credential-provider.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 +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/prompts/framework-core-compact.d.ts +1 -1
- package/dist/server/prompts/framework-core-compact.d.ts.map +1 -1
- package/dist/server/prompts/framework-core-compact.js +7 -13
- package/dist/server/prompts/framework-core-compact.js.map +1 -1
- package/dist/server/prompts/framework-core.d.ts +1 -1
- package/dist/server/prompts/framework-core.d.ts.map +1 -1
- package/dist/server/prompts/framework-core.js +10 -21
- package/dist/server/prompts/framework-core.js.map +1 -1
- package/dist/server/prompts/index.d.ts +1 -1
- package/dist/server/prompts/index.d.ts.map +1 -1
- package/dist/server/prompts/index.js +1 -1
- package/dist/server/prompts/index.js.map +1 -1
- package/dist/server/prompts/shared-rules.d.ts +16 -10
- package/dist/server/prompts/shared-rules.d.ts.map +1 -1
- package/dist/server/prompts/shared-rules.js +19 -10
- package/dist/server/prompts/shared-rules.js.map +1 -1
- package/dist/server/ssr-handler.d.ts +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +10 -3
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/settings/user-settings.d.ts.map +1 -1
- package/dist/settings/user-settings.js +13 -1
- package/dist/settings/user-settings.js.map +1 -1
- package/dist/shared/cache-control.d.ts +52 -0
- package/dist/shared/cache-control.d.ts.map +1 -1
- package/dist/shared/cache-control.js +107 -0
- package/dist/shared/cache-control.js.map +1 -1
- package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/dist/templates/chat/_gitignore +1 -0
- package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
- package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/dist/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
- package/dist/vite/agents-bundle-plugin.d.ts.map +1 -1
- package/dist/vite/agents-bundle-plugin.js +8 -7
- package/dist/vite/agents-bundle-plugin.js.map +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +2 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/actions.mdx +2 -2
- package/docs/content/agent-surfaces.mdx +1 -1
- package/docs/content/authentication.mdx +2 -0
- package/docs/content/deployment.mdx +36 -0
- package/docs/content/http-api.mdx +266 -0
- package/docs/content/syncing-template-changes.mdx +159 -0
- package/package.json +4 -3
- package/src/a2a/activity.ts +38 -27
- package/src/agent/engine/builder-engine.ts +35 -4
- package/src/agent/run-manager.ts +20 -1
- package/src/agent/run-store.ts +4 -1
- package/src/agent/types.ts +28 -8
- package/src/chat-threads/store.ts +45 -0
- package/src/checkpoints/index.ts +2 -0
- package/src/checkpoints/route-match.ts +13 -0
- package/src/cli/create.ts +105 -17
- package/src/cli/index.ts +20 -0
- package/src/cli/template-baseline.ts +410 -0
- package/src/cli/template-sync.ts +1004 -0
- package/src/cli/templates-meta.ts +1 -0
- package/src/client/AssistantChat.tsx +38 -12
- package/src/client/NewWorkspaceAppFlow.tsx +75 -10
- package/src/client/chat/message-components.tsx +127 -66
- package/src/client/chat/tool-call-display.tsx +29 -5
- package/src/client/error-format.ts +18 -0
- package/src/client/org/OrgSwitcher.tsx +30 -8
- package/src/client/org/TeamPage.tsx +7 -6
- package/src/client/sse-event-processor.ts +3 -0
- package/src/data-widgets/index.ts +41 -0
- package/src/deploy/build.ts +11 -9
- package/src/integrations/webhook-handler.ts +63 -9
- package/src/org/auto-join-domain.ts +4 -3
- package/src/org/context.ts +108 -39
- package/src/org/index.ts +5 -0
- package/src/org/service-identity.ts +60 -0
- package/src/provider-api/index.ts +22 -1
- package/src/scripts/docs/search.ts +12 -1
- package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +25 -36
- package/src/server/agent-chat/context-tools.ts +9 -4
- package/src/server/agent-chat/framework-prompts.ts +38 -66
- package/src/server/agent-chat-plugin.ts +17 -10
- package/src/server/agents-bundle.ts +84 -5
- package/src/server/auth.ts +4 -3
- package/src/server/builder-browser.ts +47 -19
- package/src/server/core-routes-plugin.ts +2 -2
- package/src/server/credential-provider.ts +209 -68
- package/src/server/index.ts +3 -0
- package/src/server/prompts/framework-core-compact.ts +6 -13
- package/src/server/prompts/framework-core.ts +9 -21
- package/src/server/prompts/index.ts +0 -1
- package/src/server/prompts/shared-rules.ts +19 -11
- package/src/server/ssr-handler.ts +13 -2
- package/src/settings/user-settings.ts +13 -1
- package/src/shared/cache-control.ts +141 -0
- package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/src/templates/chat/_gitignore +1 -0
- package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
- package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
- package/src/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
- package/src/vite/agents-bundle-plugin.ts +7 -6
- package/src/vite/client.ts +5 -0
|
@@ -625,6 +625,9 @@ function isAutoRecoverableError(ev: SSEEvent, errMsg: string): boolean {
|
|
|
625
625
|
code === "unauthorized" ||
|
|
626
626
|
code === "authentication_error" ||
|
|
627
627
|
code === "permission_error" ||
|
|
628
|
+
code === "builder_auth_error" ||
|
|
629
|
+
// The account cannot use this model; another POST picks the same one.
|
|
630
|
+
code === "builder_model_unauthorized" ||
|
|
628
631
|
code === "http_401" ||
|
|
629
632
|
code === "http_403" ||
|
|
630
633
|
code === "rate_limit_exceeded" ||
|
|
@@ -282,6 +282,47 @@ export function isDataWidgetResult(value: unknown): value is DataWidgetResult {
|
|
|
282
282
|
return normalizeDataWidgetResult(value) !== null;
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
export const DATA_WIDGET_MAX_ROWS = 50;
|
|
286
|
+
export const DATA_WIDGET_MAX_CHART_POINTS = 200;
|
|
287
|
+
|
|
288
|
+
// Widget rows arrive as tool-call arguments the model decodes token by token, so an
|
|
289
|
+
// uncapped table costs minutes of wall clock before anything renders. Clamp server-side
|
|
290
|
+
// rather than rejecting: the model has already paid for the tokens by the time we see them.
|
|
291
|
+
export function clampDataWidgetRows(
|
|
292
|
+
result: DataWidgetResult,
|
|
293
|
+
): DataWidgetResult {
|
|
294
|
+
const source = result as Partial<DataInsightsWidgetResult>;
|
|
295
|
+
const table = source.table;
|
|
296
|
+
const chartSeries = source.chartSeries;
|
|
297
|
+
|
|
298
|
+
const clampedTable =
|
|
299
|
+
table && table.rows.length > DATA_WIDGET_MAX_ROWS
|
|
300
|
+
? {
|
|
301
|
+
...table,
|
|
302
|
+
rows: table.rows.slice(0, DATA_WIDGET_MAX_ROWS),
|
|
303
|
+
totalRows: table.totalRows ?? table.rows.length,
|
|
304
|
+
sampledRows: DATA_WIDGET_MAX_ROWS,
|
|
305
|
+
truncated: true,
|
|
306
|
+
}
|
|
307
|
+
: table;
|
|
308
|
+
|
|
309
|
+
const clampedChart =
|
|
310
|
+
chartSeries && chartSeries.data.length > DATA_WIDGET_MAX_CHART_POINTS
|
|
311
|
+
? {
|
|
312
|
+
...chartSeries,
|
|
313
|
+
data: chartSeries.data.slice(0, DATA_WIDGET_MAX_CHART_POINTS),
|
|
314
|
+
sampled: true,
|
|
315
|
+
}
|
|
316
|
+
: chartSeries;
|
|
317
|
+
|
|
318
|
+
if (clampedTable === table && clampedChart === chartSeries) return result;
|
|
319
|
+
return {
|
|
320
|
+
...result,
|
|
321
|
+
...(clampedTable ? { table: clampedTable } : {}),
|
|
322
|
+
...(clampedChart ? { chartSeries: clampedChart } : {}),
|
|
323
|
+
} as DataWidgetResult;
|
|
324
|
+
}
|
|
325
|
+
|
|
285
326
|
const dataTableColumnSchema = z
|
|
286
327
|
.object({
|
|
287
328
|
key: z.string().min(1),
|
package/src/deploy/build.ts
CHANGED
|
@@ -36,10 +36,8 @@ import {
|
|
|
36
36
|
} from "../integrations/integration-durable-dispatch-config.js";
|
|
37
37
|
import { normalizeAppBasePath } from "../server/app-base-path.js";
|
|
38
38
|
import {
|
|
39
|
-
DEFAULT_SSR_CDN_CACHE_CONTROL,
|
|
40
|
-
DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL,
|
|
41
39
|
DEFAULT_SPECULATION_RULES_PATH,
|
|
42
|
-
|
|
40
|
+
resolveSsrCacheHeaders,
|
|
43
41
|
} from "../shared/cache-control.js";
|
|
44
42
|
import { mcpEmbedStaticAssetRouteRules } from "../shared/mcp-embed-headers.js";
|
|
45
43
|
import {
|
|
@@ -698,6 +696,9 @@ export function generateWorkerEntry(
|
|
|
698
696
|
options: GenerateWorkerEntryOptions = {},
|
|
699
697
|
): string {
|
|
700
698
|
const includeReactRouterSsr = options.includeReactRouterSsr ?? true;
|
|
699
|
+
// The worker ships as a static bundle with no access to runtime env, so the
|
|
700
|
+
// deployment-wide SSR cache policy is baked in from this build's env.
|
|
701
|
+
const ssrCacheHeaders = resolveSsrCacheHeaders();
|
|
701
702
|
const routeImports: string[] = [];
|
|
702
703
|
const routeRegistrations: string[] = [];
|
|
703
704
|
|
|
@@ -984,9 +985,10 @@ function injectHeadScript(html, script) {
|
|
|
984
985
|
return html.slice(0, headCloseIdx) + script + html.slice(headCloseIdx);
|
|
985
986
|
}
|
|
986
987
|
|
|
987
|
-
|
|
988
|
-
const
|
|
989
|
-
const
|
|
988
|
+
// Resolved from AGENT_NATIVE_SSR_CACHE at build time.
|
|
989
|
+
const SSR_CACHE_CONTROL = ${JSON.stringify(ssrCacheHeaders["cache-control"])};
|
|
990
|
+
const SSR_CDN_CACHE_CONTROL = ${JSON.stringify(ssrCacheHeaders["cdn-cache-control"])};
|
|
991
|
+
const SSR_NETLIFY_CDN_CACHE_CONTROL = ${JSON.stringify(ssrCacheHeaders["netlify-cdn-cache-control"])};
|
|
990
992
|
const DEFAULT_SPECULATION_RULES_PATH = ${JSON.stringify(DEFAULT_SPECULATION_RULES_PATH)};
|
|
991
993
|
const IMMUTABLE_ASSET_CACHE_CONTROL = ${JSON.stringify(IMMUTABLE_ASSET_CACHE_CONTROL)};
|
|
992
994
|
const IMMUTABLE_ASSET_PATHS = new Set(${JSON.stringify(
|
|
@@ -1084,13 +1086,13 @@ function applyDefaultSsrCacheHeader(headers, status, pathname) {
|
|
|
1084
1086
|
else headers.delete("vary");
|
|
1085
1087
|
}
|
|
1086
1088
|
|
|
1087
|
-
headers.set("cache-control",
|
|
1088
|
-
headers.set("cdn-cache-control",
|
|
1089
|
+
headers.set("cache-control", SSR_CACHE_CONTROL);
|
|
1090
|
+
headers.set("cdn-cache-control", SSR_CDN_CACHE_CONTROL);
|
|
1089
1091
|
// Netlify function responses are dynamic by default and can otherwise show
|
|
1090
1092
|
// Cache-Status fwd=bypass even with Cache-Control: public. Keep this
|
|
1091
1093
|
// Netlify-specific header so SSR HTML/.data are served from the shared
|
|
1092
1094
|
// durable CDN cache instead of stampeding origin — for every visitor.
|
|
1093
|
-
headers.set("netlify-cdn-cache-control",
|
|
1095
|
+
headers.set("netlify-cdn-cache-control", SSR_NETLIFY_CDN_CACHE_CONTROL);
|
|
1094
1096
|
}
|
|
1095
1097
|
|
|
1096
1098
|
function applyDefaultSpeculationRulesHeader(headers, status, basePath) {
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type A2AToolResultSummary,
|
|
9
9
|
} from "../a2a/artifact-response.js";
|
|
10
10
|
import { collectFinalResponseTextFromAgentEvents } from "../a2a/response-text.js";
|
|
11
|
+
import { isInBackgroundFunctionRuntime } from "../agent/durable-background.js";
|
|
11
12
|
import {
|
|
12
13
|
formatLlmCredentialErrorMessage,
|
|
13
14
|
isLlmCredentialError,
|
|
@@ -41,7 +42,11 @@ import {
|
|
|
41
42
|
threadDataToEngineMessages,
|
|
42
43
|
} from "../agent/thread-data-builder.js";
|
|
43
44
|
import { attachToolSearch } from "../agent/tool-search.js";
|
|
44
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
createThread,
|
|
47
|
+
getThread,
|
|
48
|
+
grantThreadUserShare,
|
|
49
|
+
} from "../chat-threads/store.js";
|
|
45
50
|
import { updateThreadData } from "../chat-threads/store.js";
|
|
46
51
|
import { isLocalDatabase } from "../db/client.js";
|
|
47
52
|
import { getOrgA2ASecret, resolveOrgIdForEmail } from "../org/context.js";
|
|
@@ -88,6 +93,20 @@ const DEFERRED_RESPONSE_DISPATCH_SETTLE_WAIT_MS = 1_500;
|
|
|
88
93
|
const DEFERRED_RESPONSE_MAX_HANDLER_MS = 2_500;
|
|
89
94
|
const EMPTY_INTEGRATION_RESPONSE_MESSAGE =
|
|
90
95
|
"The model finished without a visible answer. Try again, or open the thread in Dispatch to inspect the run.";
|
|
96
|
+
const CUTOFF_INTEGRATION_RESPONSE_MESSAGE =
|
|
97
|
+
"I ran out of time on this one before I could write up an answer — it needed more research than a single run allows. " +
|
|
98
|
+
"Open the thread in Dispatch to see what I gathered, or ask me again in smaller pieces (one source at a time works best).";
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* True when the run stopped at a continuation boundary rather than finishing:
|
|
102
|
+
* the run-manager's soft timeout emits `auto_continue` and aborts the loop, and
|
|
103
|
+
* the loop itself emits one when it hits an internal step budget. The run's
|
|
104
|
+
* status is still "completed", so without this check a cut-off research request
|
|
105
|
+
* is reported to the user as a model that answered with nothing.
|
|
106
|
+
*/
|
|
107
|
+
function endedAtContinuationBoundary(run: ActiveRun): boolean {
|
|
108
|
+
return run.events.some((runEvent) => runEvent.event.type === "auto_continue");
|
|
109
|
+
}
|
|
91
110
|
|
|
92
111
|
type ToolDoneEvent = {
|
|
93
112
|
type: "tool_done";
|
|
@@ -789,6 +808,29 @@ async function processIncomingMessage(
|
|
|
789
808
|
await releaseApplicableIntegrationBudgets(budgetReservations.reservations);
|
|
790
809
|
throw error;
|
|
791
810
|
}
|
|
811
|
+
|
|
812
|
+
// Channel conversations run as the integration service principal, so the
|
|
813
|
+
// thread is owned by `integration@<platform>` and not by the human who asked.
|
|
814
|
+
// The "Open thread" deep link we hand back would then 404 for them and the
|
|
815
|
+
// chat surface would silently render an empty new chat, so grant each
|
|
816
|
+
// verified participant an explicit share on the thread they are driving.
|
|
817
|
+
if (
|
|
818
|
+
incoming.senderVerified === true &&
|
|
819
|
+
incoming.senderEmail &&
|
|
820
|
+
incoming.senderEmail.trim().toLowerCase() !== ownerEmail.toLowerCase()
|
|
821
|
+
) {
|
|
822
|
+
await grantThreadUserShare(
|
|
823
|
+
threadId,
|
|
824
|
+
incoming.senderEmail,
|
|
825
|
+
"editor",
|
|
826
|
+
ownerEmail,
|
|
827
|
+
).catch((error) => {
|
|
828
|
+
console.warn(
|
|
829
|
+
`[integrations] Could not grant ${incoming.platform} sender access to thread ${threadId}:`,
|
|
830
|
+
error instanceof Error ? error.message : error,
|
|
831
|
+
);
|
|
832
|
+
});
|
|
833
|
+
}
|
|
792
834
|
const existingMessages: EngineMessage[] = [];
|
|
793
835
|
if (thread?.threadData) {
|
|
794
836
|
existingMessages.push(...threadDataToEngineMessages(thread.threadData));
|
|
@@ -1051,7 +1093,10 @@ async function processIncomingMessage(
|
|
|
1051
1093
|
"directly is the most reliable way to get an answer right now.";
|
|
1052
1094
|
} else {
|
|
1053
1095
|
responseText =
|
|
1054
|
-
verifiedMutationReceipt ??
|
|
1096
|
+
verifiedMutationReceipt ??
|
|
1097
|
+
(endedAtContinuationBoundary(completedRun)
|
|
1098
|
+
? CUTOFF_INTEGRATION_RESPONSE_MESSAGE
|
|
1099
|
+
: EMPTY_INTEGRATION_RESPONSE_MESSAGE);
|
|
1055
1100
|
}
|
|
1056
1101
|
}
|
|
1057
1102
|
if (approval?.type === "approval_required") {
|
|
@@ -1346,13 +1391,22 @@ async function processIncomingMessage(
|
|
|
1346
1391
|
resolve(outcome);
|
|
1347
1392
|
}
|
|
1348
1393
|
},
|
|
1349
|
-
//
|
|
1350
|
-
//
|
|
1351
|
-
//
|
|
1352
|
-
//
|
|
1353
|
-
//
|
|
1354
|
-
//
|
|
1355
|
-
|
|
1394
|
+
// Without the hosted soft timeout, a wedged model connection can outlive
|
|
1395
|
+
// the worker and leave Slack's native stream in "working" forever when
|
|
1396
|
+
// the host kills the process. Checkpoint at the safe boundary so
|
|
1397
|
+
// onComplete can always close the provider progress surface first.
|
|
1398
|
+
//
|
|
1399
|
+
// Which boundary that is depends on where this task is actually running:
|
|
1400
|
+
// when durable dispatch routes it to the emitted `-background` function
|
|
1401
|
+
// it has ~15min, and clamping it to the 40s foreground budget anyway cut
|
|
1402
|
+
// off every research-shaped request (multi-source sweeps, long tool
|
|
1403
|
+
// chains) with no visible answer. `isInBackgroundFunctionRuntime()` is
|
|
1404
|
+
// the runtime proof — never a config guess — so the wider ceiling is
|
|
1405
|
+
// taken only where the ~60s synchronous wall genuinely does not apply.
|
|
1406
|
+
{
|
|
1407
|
+
useHostedSoftTimeoutDefault: true,
|
|
1408
|
+
backgroundFunction: isInBackgroundFunctionRuntime(),
|
|
1409
|
+
},
|
|
1356
1410
|
);
|
|
1357
1411
|
});
|
|
1358
1412
|
}
|
|
@@ -14,9 +14,10 @@ export interface AutoJoinDomainOptions {
|
|
|
14
14
|
/**
|
|
15
15
|
* The signup hook should not clobber an org selected by an invite flow, but
|
|
16
16
|
* request-time org resolution may need to move an existing account from a
|
|
17
|
-
* personal workspace into its newly matched company org.
|
|
17
|
+
* personal workspace into its newly matched company org. `"never"` joins
|
|
18
|
+
* without touching `active-org-id` — the caller decides activation itself.
|
|
18
19
|
*/
|
|
19
|
-
activateJoinedOrg?: "if-missing" | "always";
|
|
20
|
+
activateJoinedOrg?: "if-missing" | "always" | "never";
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -96,7 +97,7 @@ export async function autoJoinDomainMatchingOrgs(
|
|
|
96
97
|
// one, unless the caller is request-time org resolution intentionally moving
|
|
97
98
|
// an existing account into its newly matched company org.
|
|
98
99
|
let activeOrgId: string | null = null;
|
|
99
|
-
if (joined[0]) {
|
|
100
|
+
if (joined[0] && options.activateJoinedOrg !== "never") {
|
|
100
101
|
try {
|
|
101
102
|
const existing = await getUserSetting(email, "active-org-id");
|
|
102
103
|
const hasActive = Boolean(existing?.orgId);
|
package/src/org/context.ts
CHANGED
|
@@ -20,12 +20,33 @@ function normalizeOrgRole(value: unknown): OrgRole | null {
|
|
|
20
20
|
: null;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
function emailDomainOf(email: string): string | null {
|
|
24
|
+
return email.split("@")[1]?.toLowerCase() || null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A workspace the user owns that nobody else has joined is a default/personal
|
|
29
|
+
* workspace whatever it happens to be named, so moving the user into their
|
|
30
|
+
* company org is safe. An org with other members is a team they deliberately
|
|
31
|
+
* belong to — join the domain org in the background but leave them there.
|
|
32
|
+
*/
|
|
33
|
+
async function isSoloOwnedWorkspace(
|
|
34
|
+
exec: ReturnType<typeof getDbExec>,
|
|
35
|
+
orgId: string,
|
|
36
|
+
memberships: MembershipRow[],
|
|
37
|
+
): Promise<boolean> {
|
|
38
|
+
const membership = memberships.find((m) => m.orgId === orgId);
|
|
39
|
+
if (!membership || membership.role !== "owner") return false;
|
|
40
|
+
try {
|
|
41
|
+
const { rows } = await exec.execute({
|
|
42
|
+
sql: `SELECT COUNT(*) AS "memberCount" FROM org_members WHERE org_id = ?`,
|
|
43
|
+
args: [orgId],
|
|
44
|
+
});
|
|
45
|
+
const row = rows[0] as any;
|
|
46
|
+
return Number(row?.memberCount ?? row?.membercount ?? 0) <= 1;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
29
50
|
}
|
|
30
51
|
|
|
31
52
|
function autoCreateDefaultOrgEnabled(): boolean {
|
|
@@ -61,7 +82,12 @@ export async function getOrgContext(event: H3Event): Promise<OrgContext> {
|
|
|
61
82
|
return (ctx.__anOrgContextCache ??= resolveOrgContextUncached(event));
|
|
62
83
|
}
|
|
63
84
|
|
|
64
|
-
type MembershipRow = {
|
|
85
|
+
type MembershipRow = {
|
|
86
|
+
orgId: string;
|
|
87
|
+
role: OrgRole;
|
|
88
|
+
orgName: string;
|
|
89
|
+
allowedDomain: string | null;
|
|
90
|
+
};
|
|
65
91
|
|
|
66
92
|
const MEMBERSHIPS_CACHE_KEY = "__anOrgMembershipsCache";
|
|
67
93
|
const ACTIVE_ORG_SETTING_CACHE_KEY = "__anActiveOrgSettingCache";
|
|
@@ -157,17 +183,26 @@ async function resolveOrgContextUncached(event: H3Event): Promise<OrgContext> {
|
|
|
157
183
|
return { email, orgId: null, orgName: null, role: null };
|
|
158
184
|
}
|
|
159
185
|
|
|
160
|
-
const shouldTryDomainAutoJoin =
|
|
161
|
-
memberships.length === 0 ||
|
|
162
|
-
(memberships.length === 1 &&
|
|
163
|
-
isLikelyPersonalWorkspace(memberships[0], email, session));
|
|
164
186
|
const activeOrgSetting = await loadActiveOrgSettingForEvent(event, email);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
187
|
+
const explicitPersonal = activeOrgSetting?.orgId === null;
|
|
188
|
+
|
|
189
|
+
const emailDomain = emailDomainOf(email);
|
|
190
|
+
// Membership in a domain-matched org is the only durable "already joined"
|
|
191
|
+
// signal. Recognizing the personal workspace by its *name* instead breaks the
|
|
192
|
+
// moment the provider display name or the workspace name changes, which
|
|
193
|
+
// strands an existing user in Personal with no way into their company org.
|
|
194
|
+
const shouldTryDomainAutoJoin =
|
|
195
|
+
!explicitPersonal &&
|
|
196
|
+
emailDomain !== null &&
|
|
197
|
+
!memberships.some((m) => m.allowedDomain?.toLowerCase() === emailDomain);
|
|
198
|
+
|
|
199
|
+
if (
|
|
200
|
+
!explicitPersonal &&
|
|
201
|
+
activeOrgSetting?.orgId &&
|
|
202
|
+
!shouldTryDomainAutoJoin
|
|
203
|
+
) {
|
|
169
204
|
const active = memberships.find((m) => m.orgId === activeOrgSetting.orgId);
|
|
170
|
-
if (active
|
|
205
|
+
if (active) {
|
|
171
206
|
return {
|
|
172
207
|
email,
|
|
173
208
|
orgId: active.orgId,
|
|
@@ -182,30 +217,63 @@ async function resolveOrgContextUncached(event: H3Event): Promise<OrgContext> {
|
|
|
182
217
|
: null;
|
|
183
218
|
|
|
184
219
|
if (shouldTryDomainAutoJoin) {
|
|
220
|
+
const membershipsBeforeJoin = memberships;
|
|
185
221
|
const joined = await autoJoinDomainMatchingOrgs(email, {
|
|
186
|
-
activateJoinedOrg: "
|
|
222
|
+
activateJoinedOrg: "never",
|
|
187
223
|
});
|
|
188
|
-
|
|
224
|
+
const joinedOrgId = joined.joined[0]?.orgId ?? null;
|
|
225
|
+
if (joinedOrgId) {
|
|
189
226
|
const refreshed = await loadMemberships(exec, email);
|
|
190
227
|
if (refreshed !== null) {
|
|
191
228
|
memberships = refreshed;
|
|
192
229
|
updateMembershipsForEvent(event, email, refreshed);
|
|
193
230
|
}
|
|
194
|
-
}
|
|
195
231
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
232
|
+
const currentOrgId =
|
|
233
|
+
activeOrgSetting?.orgId ??
|
|
234
|
+
sessionOrgId ??
|
|
235
|
+
membershipsBeforeJoin[0]?.orgId ??
|
|
236
|
+
null;
|
|
237
|
+
const shouldActivate =
|
|
238
|
+
!explicitPersonal &&
|
|
239
|
+
(currentOrgId === null ||
|
|
240
|
+
(await isSoloOwnedWorkspace(
|
|
241
|
+
exec,
|
|
242
|
+
currentOrgId,
|
|
243
|
+
membershipsBeforeJoin,
|
|
244
|
+
)));
|
|
245
|
+
|
|
246
|
+
if (shouldActivate) {
|
|
247
|
+
await putUserSetting(email, "active-org-id", { orgId: joinedOrgId });
|
|
248
|
+
const active = memberships.find((m) => m.orgId === joinedOrgId);
|
|
249
|
+
if (active) {
|
|
250
|
+
return {
|
|
251
|
+
email,
|
|
252
|
+
orgId: active.orgId,
|
|
253
|
+
orgName: active.orgName,
|
|
254
|
+
role: active.role,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
205
257
|
}
|
|
206
258
|
}
|
|
207
259
|
}
|
|
208
260
|
|
|
261
|
+
if (explicitPersonal) {
|
|
262
|
+
return { email, orgId: null, orgName: null, role: null };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (activeOrgSetting?.orgId) {
|
|
266
|
+
const active = memberships.find((m) => m.orgId === activeOrgSetting.orgId);
|
|
267
|
+
if (active) {
|
|
268
|
+
return {
|
|
269
|
+
email,
|
|
270
|
+
orgId: active.orgId,
|
|
271
|
+
orgName: active.orgName,
|
|
272
|
+
role: active.role,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
209
277
|
if (sessionOrgId) {
|
|
210
278
|
const active =
|
|
211
279
|
sessionMembership ?? memberships.find((m) => m.orgId === sessionOrgId);
|
|
@@ -247,24 +315,25 @@ async function resolveOrgContextUncached(event: H3Event): Promise<OrgContext> {
|
|
|
247
315
|
async function loadMemberships(
|
|
248
316
|
exec: ReturnType<typeof getDbExec>,
|
|
249
317
|
email: string,
|
|
250
|
-
): Promise<
|
|
251
|
-
orgId: string;
|
|
252
|
-
role: OrgRole;
|
|
253
|
-
orgName: string;
|
|
254
|
-
}> | null> {
|
|
318
|
+
): Promise<MembershipRow[] | null> {
|
|
255
319
|
try {
|
|
256
320
|
const { rows } = await exec.execute({
|
|
257
|
-
sql: `SELECT m.org_id AS "orgId", m.role AS role, o.name AS "orgName"
|
|
321
|
+
sql: `SELECT m.org_id AS "orgId", m.role AS role, o.name AS "orgName",
|
|
322
|
+
o.allowed_domain AS "allowedDomain"
|
|
258
323
|
FROM org_members m
|
|
259
324
|
INNER JOIN organizations o ON m.org_id = o.id
|
|
260
325
|
WHERE LOWER(m.email) = ?`,
|
|
261
326
|
args: [email.toLowerCase()],
|
|
262
327
|
});
|
|
263
|
-
return rows.map((r: any) =>
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
328
|
+
return rows.map((r: any) => {
|
|
329
|
+
const domain = r.allowedDomain ?? r.allowed_domain;
|
|
330
|
+
return {
|
|
331
|
+
orgId: String(r.orgId ?? r.org_id),
|
|
332
|
+
role: String(r.role) as OrgRole,
|
|
333
|
+
orgName: String(r.orgName ?? r.org_name),
|
|
334
|
+
allowedDomain: domain ? String(domain) : null,
|
|
335
|
+
};
|
|
336
|
+
});
|
|
268
337
|
} catch {
|
|
269
338
|
// Tables may not exist yet on first boot before migrations finish.
|
|
270
339
|
return null;
|
package/src/org/index.ts
CHANGED
|
@@ -28,6 +28,11 @@ export {
|
|
|
28
28
|
createOrganization,
|
|
29
29
|
} from "./context.js";
|
|
30
30
|
|
|
31
|
+
export {
|
|
32
|
+
implicitServiceOrgRole,
|
|
33
|
+
parseServiceIdentityEmail,
|
|
34
|
+
} from "./service-identity.js";
|
|
35
|
+
|
|
31
36
|
export { acceptPendingInvitationsForEmail } from "./accept-pending.js";
|
|
32
37
|
export type { AcceptPendingResult } from "./accept-pending.js";
|
|
33
38
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implicit org membership for synthetic service-token identities.
|
|
3
|
+
*
|
|
4
|
+
* Org service tokens authenticate as `svc-<name>@service.<orgId>` and are
|
|
5
|
+
* deliberately never inserted into `org_members` (see
|
|
6
|
+
* `mcp/actions/service-token-access.ts`), so any template that authorizes by
|
|
7
|
+
* looking up a physical membership row rejects them. The ownable/sharing layer
|
|
8
|
+
* already admits them via the signed `org_id` claim; this closes the gap for
|
|
9
|
+
* the role-lookup layer.
|
|
10
|
+
*
|
|
11
|
+
* Two constraints are load-bearing and must survive future edits:
|
|
12
|
+
*
|
|
13
|
+
* 1. The implicit role is always `member`, never admin or owner. Member-gated
|
|
14
|
+
* actions (create/read org data) work; admin-gated ones (invite/remove
|
|
15
|
+
* members, change roles, org settings, minting further service tokens) stay
|
|
16
|
+
* closed, so a leaked service token cannot escalate.
|
|
17
|
+
* 2. `requestOrgId` must independently agree with the target org. The email
|
|
18
|
+
* alone is not proof: a human account registered under a `@service.<orgId>`
|
|
19
|
+
* address would otherwise mint itself membership. A signed-in user's request
|
|
20
|
+
* org id is membership-derived through `getOrgContext`, so a non-member
|
|
21
|
+
* cannot present the target org id, while a service token carries it in its
|
|
22
|
+
* signed `org_id` claim.
|
|
23
|
+
*/
|
|
24
|
+
import type { OrgRole } from "./types.js";
|
|
25
|
+
|
|
26
|
+
const SERVICE_IDENTITY_PATTERN = /^svc-([a-z0-9-]+)@service\.(.+)$/;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Parse `svc-<name>@service.<orgId>` into its parts, or null when the address
|
|
30
|
+
* is not a service identity. Counterpart to `serviceIdentityEmail()` in
|
|
31
|
+
* `mcp/connect-store.ts`.
|
|
32
|
+
*/
|
|
33
|
+
export function parseServiceIdentityEmail(
|
|
34
|
+
email: string | null | undefined,
|
|
35
|
+
): { serviceName: string; orgId: string } | null {
|
|
36
|
+
const trimmed = email?.trim();
|
|
37
|
+
if (!trimmed) return null;
|
|
38
|
+
const match = SERVICE_IDENTITY_PATTERN.exec(trimmed.toLowerCase());
|
|
39
|
+
if (!match) return null;
|
|
40
|
+
const orgId = trimmed.slice(trimmed.length - match[2].length);
|
|
41
|
+
if (!orgId) return null;
|
|
42
|
+
return { serviceName: match[1], orgId };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the implicit org role for a service-token caller, or null when the
|
|
47
|
+
* caller is not a service identity acting for the org it was minted against.
|
|
48
|
+
*/
|
|
49
|
+
export function implicitServiceOrgRole(params: {
|
|
50
|
+
email: string | null | undefined;
|
|
51
|
+
orgId: string | null | undefined;
|
|
52
|
+
requestOrgId: string | null | undefined;
|
|
53
|
+
}): OrgRole | null {
|
|
54
|
+
const orgId = params.orgId?.trim();
|
|
55
|
+
if (!orgId) return null;
|
|
56
|
+
if (params.requestOrgId?.trim() !== orgId) return null;
|
|
57
|
+
const parsed = parseServiceIdentityEmail(params.email);
|
|
58
|
+
if (!parsed || parsed.orgId !== orgId) return null;
|
|
59
|
+
return "member";
|
|
60
|
+
}
|
|
@@ -396,6 +396,7 @@ export interface ProviderApiConfig {
|
|
|
396
396
|
placeholders?: readonly ProviderApiPlaceholder[];
|
|
397
397
|
examples?: readonly ProviderApiExample[];
|
|
398
398
|
notes?: readonly string[];
|
|
399
|
+
accessErrorGuidance?: string;
|
|
399
400
|
corpusRecipes?: readonly ProviderApiCorpusRecipe[];
|
|
400
401
|
templateUses?: readonly WorkspaceConnectionTemplateUse[];
|
|
401
402
|
}
|
|
@@ -1326,6 +1327,11 @@ const PROVIDER_CONFIGS: Record<ProviderApiId, ProviderApiConfig> = {
|
|
|
1326
1327
|
defaultHeaders: { "Notion-Version": "2026-03-11" },
|
|
1327
1328
|
templateUses: ["analytics", "brain", "content", "dispatch"],
|
|
1328
1329
|
examples: [{ label: "Search", method: "POST", path: "/search", body: {} }],
|
|
1330
|
+
notes: [
|
|
1331
|
+
"The name GET /users/me returns is the label whoever minted the token typed into Notion, so it often names an unrelated product or team. Call it the Notion-side integration label and never restate it as the workspace, app, or product the user is currently in.",
|
|
1332
|
+
],
|
|
1333
|
+
accessErrorGuidance:
|
|
1334
|
+
"Notion 401/403/404 on a specific page or database usually means that object was never shared with the integration, not that the id is wrong or the key is invalid. Fix: open the page or database in Notion, then ••• → Connections → add the integration. When naming the integration, describe it as the Notion-side integration label from GET /users/me and note that it may not match this app or workspace.",
|
|
1329
1335
|
corpusRecipes: [
|
|
1330
1336
|
{
|
|
1331
1337
|
label: "Search a Notion data source with complete cursor coverage",
|
|
@@ -1624,6 +1630,7 @@ export function listProviderApiCatalog(
|
|
|
1624
1630
|
defaultHeaders: config.defaultHeaders ?? {},
|
|
1625
1631
|
examples: config.examples ?? [],
|
|
1626
1632
|
notes: config.notes ?? [],
|
|
1633
|
+
accessErrorGuidance: config.accessErrorGuidance ?? null,
|
|
1627
1634
|
corpusRecipes: config.corpusRecipes ?? [],
|
|
1628
1635
|
templateUses: config.templateUses ?? [],
|
|
1629
1636
|
}));
|
|
@@ -1990,11 +1997,25 @@ export async function executeProviderApiRequest(
|
|
|
1990
1997
|
...(args.connectionId ? { connectionId: args.connectionId } : {}),
|
|
1991
1998
|
},
|
|
1992
1999
|
response,
|
|
1993
|
-
guidance:
|
|
2000
|
+
guidance: [
|
|
1994
2001
|
"This was a raw provider API request. Use provider docs/spec URLs to choose endpoints and include method/path/status plus relevant filters in the methodology. Prefer this escape hatch whenever canned actions are too narrow.",
|
|
2002
|
+
providerAccessErrorGuidance(config, response.status),
|
|
2003
|
+
]
|
|
2004
|
+
.filter(Boolean)
|
|
2005
|
+
.join(" "),
|
|
1995
2006
|
};
|
|
1996
2007
|
}
|
|
1997
2008
|
|
|
2009
|
+
const PROVIDER_ACCESS_ERROR_STATUSES = new Set([401, 403, 404]);
|
|
2010
|
+
|
|
2011
|
+
function providerAccessErrorGuidance(
|
|
2012
|
+
config: ProviderApiConfig,
|
|
2013
|
+
status: number,
|
|
2014
|
+
): string | null {
|
|
2015
|
+
if (!PROVIDER_ACCESS_ERROR_STATUSES.has(status)) return null;
|
|
2016
|
+
return config.accessErrorGuidance ?? null;
|
|
2017
|
+
}
|
|
2018
|
+
|
|
1998
2019
|
/**
|
|
1999
2020
|
* Resolve a provider OAuth token for a trusted server-side integration bridge
|
|
2000
2021
|
* such as a CRM adapter or Google Picker. Callers must keep the result out of
|
|
@@ -143,7 +143,7 @@ function slugifyDocId(value: string): string {
|
|
|
143
143
|
|
|
144
144
|
async function loadAgentBundleDocs(): Promise<DocFull[]> {
|
|
145
145
|
try {
|
|
146
|
-
const { loadAgentsBundle, getRuntimeSkills } =
|
|
146
|
+
const { loadAgentsBundle, getRuntimeSkills, skillSubfileDocsSlug } =
|
|
147
147
|
await import("../../server/agents-bundle.js");
|
|
148
148
|
const bundle = await loadAgentsBundle();
|
|
149
149
|
const docs: DocFull[] = [];
|
|
@@ -174,6 +174,17 @@ async function loadAgentBundleDocs(): Promise<DocFull[]> {
|
|
|
174
174
|
description: skill.meta.description,
|
|
175
175
|
body: skill.content,
|
|
176
176
|
});
|
|
177
|
+
// Progressive-disclosure sub-files (e.g. `references/*.md`) get their
|
|
178
|
+
// own searchable/readable doc so the "also contains" pointers the
|
|
179
|
+
// skill prompt block advertises actually resolve to something.
|
|
180
|
+
for (const [relPath, content] of Object.entries(skill.files)) {
|
|
181
|
+
docs.push({
|
|
182
|
+
slug: skillSubfileDocsSlug(skill.meta.name, relPath),
|
|
183
|
+
title: `Skill: ${skill.meta.name} — ${relPath}`,
|
|
184
|
+
description: `Reference file from the "${skill.meta.name}" skill (${relPath}).`,
|
|
185
|
+
body: content,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
177
188
|
}
|
|
178
189
|
return docs;
|
|
179
190
|
} catch {
|