@agent-native/core 0.145.4 → 0.145.6
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 +1 -1
- package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +17 -1
- package/corpus/templates/analytics/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +22 -3
- package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/analytics/AGENTS.md +2 -1
- package/corpus/templates/analytics/actions/account-deep-dive.ts +83 -47
- package/corpus/templates/analytics/actions/create-dashboard-folder.ts +27 -0
- package/corpus/templates/analytics/actions/gong-calls.ts +3 -3
- package/corpus/templates/analytics/actions/list-dashboard-folders.ts +26 -0
- package/corpus/templates/analytics/actions/list-sql-dashboards.ts +1 -0
- package/corpus/templates/analytics/actions/set-dashboard-folder.ts +26 -0
- package/corpus/templates/analytics/app/components/ProviderCorpusJobNotifier.tsx +18 -3
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +6 -4
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +12 -2
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +35 -20
- package/corpus/templates/analytics/app/global.css +17 -0
- package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +29 -15
- package/corpus/templates/analytics/app/hooks/use-dashboard-views.ts +15 -3
- package/corpus/templates/analytics/app/i18n-data.ts +296 -0
- package/corpus/templates/analytics/app/lib/prefetch-keys.ts +23 -2
- package/corpus/templates/analytics/app/pages/DashboardOverview.tsx +642 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +66 -31
- package/corpus/templates/analytics/app/root.tsx +4 -0
- package/corpus/templates/analytics/app/routes/dashboards._index.tsx +5 -1
- package/corpus/templates/analytics/changelog/2026-08-07-added-a-dashboards-overview-with-personal-and-shared-folders.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-07-analytics-tracking-and-chat-startup-no-longer-emit-avoidable.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-07-dashboard-panels-now-load-custom-api-data-programs-reliably.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-07-gong-searches-conserve-api-quota-and-report-incomplete-coverage.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-07-searchable-dashboards-make-personal-and-shared-folders-easie.md +6 -0
- package/corpus/templates/analytics/netlify.toml +3 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +112 -0
- package/corpus/templates/analytics/server/db/index.ts +12 -0
- package/corpus/templates/analytics/server/db/schema.ts +14 -0
- package/corpus/templates/analytics/server/jobs/analytics-rollup-backfill.ts +4 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +1 -0
- package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +85 -15
- package/corpus/templates/analytics/server/lib/dashboard-folders-store.ts +168 -0
- package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +9 -4
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +116 -1
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +4 -8
- package/corpus/templates/analytics/server/lib/gong.ts +139 -78
- package/corpus/templates/analytics/server/plugins/db.ts +55 -15
- package/corpus/templates/analytics/server/plugins/session-replay-retention-jobs.ts +6 -2
- package/corpus/templates/analytics/server/routes/api/session-replay/retention.post.ts +65 -0
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/assets/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/brain/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/calendar/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/chat/.env.example +3 -0
- package/corpus/templates/chat/AGENTS.md +4 -0
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/clips/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +4 -0
- package/corpus/templates/clips/actions/request-transcript.ts +52 -3
- package/corpus/templates/clips/app/components/editor/editor-layout.tsx +8 -3
- package/corpus/templates/clips/app/components/editor/waveform.tsx +2 -1
- package/corpus/templates/clips/app/components/library/search-bar.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +3 -10
- package/corpus/templates/clips/app/global.css +9 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -0
- package/corpus/templates/clips/changelog/2026-08-07-screen-recordings-now-capture-tab-and-system-audio-even-when.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-07-transcription-now-retries-transient-cloud-failures-automatic.md +6 -0
- package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +10 -11
- package/corpus/templates/clips/server/db/schema.ts +7 -0
- package/corpus/templates/clips/server/plugins/db.ts +8 -0
- package/corpus/templates/clips/shared/recording-capture.ts +38 -0
- package/corpus/templates/clips/shared/transcript-failure.ts +89 -0
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/content/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/content/.env.example +9 -3
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -0
- package/corpus/templates/content/changelog/2026-08-07-collapsed-sidebar-utility-buttons-stay-anchored-at-the-botto.md +6 -0
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/design/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/design/actions/view-screen.ts +1 -0
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +14 -1
- package/corpus/templates/design/changelog/2026-08-07-cmd-c-now-copies-selected-text-in-the-agent-panel-instead-of.md +6 -0
- package/corpus/templates/design/changelog/2026-08-07-real-time-voice-can-now-read-the-current-selection-and-edit-.md +6 -0
- package/corpus/templates/design/server/lib/reprompt-action-guard.ts +7 -3
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/dispatch/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/factory/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/factory/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/factory/actions/babysit-agent-native-pull-request.ts +279 -0
- package/corpus/templates/factory/actions/get-factory-automation-health.ts +23 -4
- package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +1 -1
- package/corpus/templates/factory/app/routes/factory.tsx +21 -3
- package/corpus/templates/factory/changelog/2026-08-07-factory-can-keep-builder-bot-pull-requests-moving-by-request.md +6 -0
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +1 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +4 -1
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +81 -12
- package/corpus/templates/factory/server/triage/github-client.ts +31 -0
- package/corpus/templates/factory/server/triage/pr-babysit.ts +75 -1
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/forms/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/mail/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/plan/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +2 -1
- package/corpus/templates/plan/changelog/2026-08-07-inline-help-icons-now-stay-visually-balanced-with-nearby-tex.md +6 -0
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/slides/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/slides/.env.example +5 -0
- package/corpus/templates/slides/changelog/2026-08-07-fixed-generated-slides-briefly-disappearing-while-they-are-b.md +6 -0
- package/corpus/templates/slides/server/plugins/collab.ts +20 -8
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/tasks/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/tasks/.env.example +3 -0
- package/dist/agent/production-agent.js +24 -3
- package/dist/client/AgentPanel.d.ts +6 -0
- package/dist/client/AgentPanel.js +176 -30
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.js +4 -1
- package/dist/client/ConnectBuilderCard.js +6 -11
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/RuntimeConfigNotice.d.ts +1 -0
- package/dist/client/RuntimeConfigNotice.js +94 -0
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat/index.js +1 -1
- package/dist/client/agent-chat-adapter.js +85 -4
- package/dist/client/agent-page/AgentTabsPage.js +1 -1
- package/dist/client/agent-sidebar-state.d.ts +6 -0
- package/dist/client/agent-sidebar-state.js +25 -0
- package/dist/client/app-providers.js +2 -1
- package/dist/client/assistant-ui-recovery.js +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.js +1 -1
- package/dist/client/chat/markdown-renderer.d.ts +2 -1
- package/dist/client/chat/markdown-renderer.js +48 -2
- package/dist/client/chat/message-components.d.ts +6 -0
- package/dist/client/chat/message-components.js +182 -53
- package/dist/client/chat/tool-call-display.d.ts +16 -4
- package/dist/client/chat/tool-call-display.js +225 -18
- package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
- package/dist/client/frame-protocol.d.ts +4 -0
- package/dist/client/i18n.js +9 -0
- package/dist/client/integrations/IntegrationsPanel.js +2 -5
- package/dist/client/onboarding/FirstRunOnboarding.js +2 -3
- package/dist/client/org/TeamPage.js +49 -6
- package/dist/client/org/hooks.d.ts +7 -2
- package/dist/client/org/hooks.js +11 -4
- package/dist/client/resources/McpConnectionSuggestion.js +2 -3
- package/dist/client/resources/McpIntegrationDialog.js +2 -16
- package/dist/client/resources/McpIntegrationLogo.d.ts +11 -0
- package/dist/client/resources/McpIntegrationLogo.js +14 -0
- package/dist/client/resources/ResourceTree.js +1 -1
- package/dist/client/resources/mcp-integration-logos.d.ts +1 -0
- package/dist/client/resources/mcp-integration-logos.js +47 -18
- package/dist/client/settings/useBuilderStatus.js +6 -0
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/config.d.ts +26 -3
- package/dist/config.js +106 -14
- package/dist/db/ddl-guard.d.ts +15 -2
- package/dist/db/ddl-guard.js +53 -5
- package/dist/jobs/scheduler.js +7 -0
- package/dist/localization/default-messages.d.ts +17 -0
- package/dist/localization/default-messages.js +17 -0
- package/dist/mcp/oauth-client-metadata.js +5 -1
- package/dist/mcp/oauth-route.d.ts +5 -4
- package/dist/mcp/oauth-route.js +25 -9
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +9 -10
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/org/handlers.d.ts +1 -0
- package/dist/org/handlers.js +17 -2
- package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/corpus-jobs.d.ts +12 -2
- package/dist/provider-api/corpus-jobs.js +31 -1
- package/dist/provider-api/index.d.ts +2 -0
- package/dist/provider-api/index.js +7 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-chat/recurring-jobs-runtime.d.ts +1 -1
- package/dist/server/agent-chat/recurring-jobs-runtime.js +14 -2
- package/dist/server/agent-chat/script-entries.js +12 -1
- package/dist/server/agent-chat-plugin.js +2 -2
- package/dist/server/auth.d.ts +1 -0
- package/dist/server/auth.js +85 -1
- package/dist/server/better-auth-instance.d.ts +9 -0
- package/dist/server/better-auth-instance.js +25 -11
- package/dist/server/core-routes-plugin.d.ts +7 -0
- package/dist/server/core-routes-plugin.js +51 -5
- package/dist/server/create-server.js +23 -2
- package/dist/server/db-pressure.d.ts +38 -0
- package/dist/server/db-pressure.js +147 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/legacy-auth-migration.d.ts +10 -0
- package/dist/server/legacy-auth-migration.js +37 -0
- package/dist/server/onboarding-html.js +206 -2
- package/dist/server/poll.d.ts +26 -0
- package/dist/server/poll.js +108 -13
- package/dist/server/realtime-voice.d.ts +2 -1
- package/dist/server/realtime-voice.js +38 -56
- package/dist/server/short-lived-token.d.ts +43 -0
- package/dist/server/short-lived-token.js +74 -0
- package/dist/server/ssr-handler.js +4 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/shared/runtime-config.d.ts +44 -0
- package/dist/shared/runtime-config.js +284 -0
- package/dist/styles/agent-native.css +48 -1
- package/dist/templates/chat/.agents/skills/actions/SKILL.md +18 -0
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/dist/templates/chat/.env.example +3 -0
- package/dist/templates/chat/AGENTS.md +4 -0
- package/dist/templates/default/.agents/skills/actions/SKILL.md +18 -0
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/default/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +1 -0
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/dist/templates/default/AGENTS.md +6 -1
- package/dist/templates/default/app/i18n/ar-SA.ts +6 -0
- package/dist/templates/default/app/i18n/de-DE.ts +6 -0
- package/dist/templates/default/app/i18n/en-US.ts +6 -0
- package/dist/templates/default/app/i18n/es-ES.ts +6 -0
- package/dist/templates/default/app/i18n/fr-FR.ts +6 -0
- package/dist/templates/default/app/i18n/hi-IN.ts +6 -0
- package/dist/templates/default/app/i18n/ja-JP.ts +6 -0
- package/dist/templates/default/app/i18n/ko-KR.ts +6 -0
- package/dist/templates/default/app/i18n/pt-BR.ts +6 -0
- package/dist/templates/default/app/i18n/zh-CN.ts +6 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +6 -0
- package/dist/templates/headless/.agents/skills/actions/SKILL.md +18 -0
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +18 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +4 -0
- package/dist/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +8 -0
- package/dist/templates/workspace-core/AGENTS.md +7 -2
- package/dist/templates/workspace-root/AGENTS.md +5 -0
- package/dist/vite/client.d.ts +3 -3
- package/dist/vite/client.js +47 -1
- package/dist/vite/index.d.ts +1 -1
- package/docs/content/agent-native-config.mdx +240 -139
- package/docs/content/authentication.mdx +17 -0
- package/docs/content/deployment.mdx +19 -14
- package/docs/content/drop-in-agent.mdx +19 -2
- package/docs/content/environment-variables.mdx +63 -38
- package/docs/content/getting-started-actions.mdx +15 -6
- package/docs/content/getting-started-database.mdx +14 -10
- package/docs/content/getting-started-pages.mdx +32 -35
- package/docs/content/getting-started.mdx +7 -6
- package/package.json +2 -2
- package/src/templates/chat/.agents/skills/actions/SKILL.md +18 -0
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/src/templates/chat/.env.example +3 -0
- package/src/templates/chat/AGENTS.md +4 -0
- package/src/templates/default/.agents/skills/actions/SKILL.md +18 -0
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/default/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +1 -0
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/src/templates/default/AGENTS.md +6 -1
- package/src/templates/default/app/i18n/ar-SA.ts +6 -0
- package/src/templates/default/app/i18n/de-DE.ts +6 -0
- package/src/templates/default/app/i18n/en-US.ts +6 -0
- package/src/templates/default/app/i18n/es-ES.ts +6 -0
- package/src/templates/default/app/i18n/fr-FR.ts +6 -0
- package/src/templates/default/app/i18n/hi-IN.ts +6 -0
- package/src/templates/default/app/i18n/ja-JP.ts +6 -0
- package/src/templates/default/app/i18n/ko-KR.ts +6 -0
- package/src/templates/default/app/i18n/pt-BR.ts +6 -0
- package/src/templates/default/app/i18n/zh-CN.ts +6 -0
- package/src/templates/default/app/i18n/zh-TW.ts +6 -0
- package/src/templates/headless/.agents/skills/actions/SKILL.md +18 -0
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +18 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +4 -0
- package/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +8 -0
- package/src/templates/workspace-core/AGENTS.md +7 -2
- package/src/templates/workspace-root/AGENTS.md +5 -0
- package/corpus/templates/dispatch/app/routes/admin.apps.$appId.tsx +0 -1
- package/corpus/templates/dispatch/app/routes/admin.apps.tsx +0 -1
package/dist/server/poll.js
CHANGED
|
@@ -25,7 +25,7 @@ import { defineEventHandler, getQuery, setResponseStatus } from "h3";
|
|
|
25
25
|
import { ACTION_CHANGE_MARKER_KEY, parseActionChangeMarker, } from "../action-change-marker.js";
|
|
26
26
|
import { getAppStateEmitter } from "../application-state/emitter.js";
|
|
27
27
|
import { getDbExec, isPostgres } from "../db/client.js";
|
|
28
|
-
import { ensureIndexExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
28
|
+
import { ensureIndexExists, ensureIndexExistsConcurrently, ensureTableExists, } from "../db/ddl-guard.js";
|
|
29
29
|
import { EXTENSION_CHANGE_MARKER_KEY, parseExtensionChangeMarker, } from "../extensions/change-marker.js";
|
|
30
30
|
import { getSettingsEmitter } from "../settings/store.js";
|
|
31
31
|
import { getSession } from "./auth.js";
|
|
@@ -34,6 +34,21 @@ import { getSession } from "./auth.js";
|
|
|
34
34
|
const MAX_BUFFER = 200;
|
|
35
35
|
const DURABLE_READ_LIMIT = 1000;
|
|
36
36
|
const DURABLE_RETENTION_MS = 24 * 60 * 60 * 1000;
|
|
37
|
+
/**
|
|
38
|
+
* Rows per prune statement, and the ceiling on statements per prune call.
|
|
39
|
+
* The product (400k) leaves headroom over one app's documented production of
|
|
40
|
+
* ~1k events/sec over the five-minute throttle, so a healthy app catches up;
|
|
41
|
+
* the cap still bounds how long a single call can run.
|
|
42
|
+
*/
|
|
43
|
+
const DURABLE_PRUNE_BATCH = 10_000;
|
|
44
|
+
const DURABLE_PRUNE_MAX_BATCHES = 40;
|
|
45
|
+
/**
|
|
46
|
+
* How far back a cold-started process replays durable action markers.
|
|
47
|
+
* Covers the gap between a separate action process writing its marker and this
|
|
48
|
+
* process's first poll — seconds in practice. Anything older is history, and
|
|
49
|
+
* replaying history is what produced 1,169 sync events/sec on one app.
|
|
50
|
+
*/
|
|
51
|
+
const ACTION_MARKER_REPLAY_WINDOW_MS = 60_000;
|
|
37
52
|
const LEGACY_DB_CHECK_INTERVAL_MS = 1000;
|
|
38
53
|
export const DURABLE_LEGACY_DB_CHECK_INTERVAL_MS = 30_000;
|
|
39
54
|
export const POLL_CHANGE_EVENT = "poll-change";
|
|
@@ -243,6 +258,7 @@ export class AppSyncState {
|
|
|
243
258
|
pollEmitter = new EventEmitter();
|
|
244
259
|
syncEventsInitPromise;
|
|
245
260
|
lastDurablePrune = 0;
|
|
261
|
+
durablePruneFailures = 0;
|
|
246
262
|
/**
|
|
247
263
|
* Whether we've seeded `version` from the DB. In serverless (Netlify,
|
|
248
264
|
* Vercel, etc.) each invocation starts fresh — without seeding, `version`
|
|
@@ -388,6 +404,7 @@ export class AppSyncState {
|
|
|
388
404
|
await ensureIndexExists("sync_events_version_idx", "CREATE INDEX IF NOT EXISTS sync_events_version_idx ON sync_events (version)", guardOptions);
|
|
389
405
|
await ensureIndexExists("sync_events_owner_version_idx", "CREATE INDEX IF NOT EXISTS sync_events_owner_version_idx ON sync_events (owner, version)", guardOptions);
|
|
390
406
|
await ensureIndexExists("sync_events_org_version_idx", "CREATE INDEX IF NOT EXISTS sync_events_org_version_idx ON sync_events (org_id, version)", guardOptions);
|
|
407
|
+
await ensureIndexExistsConcurrently("sync_events_created_at_id_idx", "CREATE INDEX CONCURRENTLY IF NOT EXISTS sync_events_created_at_id_idx ON sync_events (created_at, id)", guardOptions);
|
|
391
408
|
if (this.dbAssignedVersions) {
|
|
392
409
|
await ensureTableExists("sync_version", "CREATE TABLE IF NOT EXISTS sync_version (id INT PRIMARY KEY, v BIGINT NOT NULL)", guardOptions);
|
|
393
410
|
// Seed at/above both the existing durable max and wall clock, so
|
|
@@ -401,6 +418,7 @@ export class AppSyncState {
|
|
|
401
418
|
"CREATE INDEX IF NOT EXISTS sync_events_version_idx ON sync_events (version)",
|
|
402
419
|
"CREATE INDEX IF NOT EXISTS sync_events_owner_version_idx ON sync_events (owner, version)",
|
|
403
420
|
"CREATE INDEX IF NOT EXISTS sync_events_org_version_idx ON sync_events (org_id, version)",
|
|
421
|
+
"CREATE INDEX IF NOT EXISTS sync_events_created_at_id_idx ON sync_events (created_at, id)",
|
|
404
422
|
]) {
|
|
405
423
|
try {
|
|
406
424
|
await client.execute(ddl);
|
|
@@ -417,17 +435,66 @@ export class AppSyncState {
|
|
|
417
435
|
}
|
|
418
436
|
return this.syncEventsInitPromise;
|
|
419
437
|
}
|
|
438
|
+
/**
|
|
439
|
+
* Drop events past the retention window, in bounded batches.
|
|
440
|
+
*
|
|
441
|
+
* Three things here are load-bearing, all of them learned from a 47 GB
|
|
442
|
+
* `sync_events` table on a live app:
|
|
443
|
+
*
|
|
444
|
+
* - Prune by `created_at`, the actual retention timestamp, with the
|
|
445
|
+
* additive `(created_at, id)` index created above. A version can move
|
|
446
|
+
* ahead of the clock under bursty writes, so it is not a retention
|
|
447
|
+
* timestamp and cannot define a 24-hour boundary safely.
|
|
448
|
+
* - Batch it. One statement deleting an unbounded slice is a long
|
|
449
|
+
* transaction, and a long transaction killed mid-flight by a serverless
|
|
450
|
+
* worker shutdown is what leaves connections `idle in transaction`
|
|
451
|
+
* holding locks — the shape of the 2026-08-06 outage.
|
|
452
|
+
* - `ORDER BY version` inside the subquery. Without it the planner
|
|
453
|
+
* prefers a sequential scan even with a LIMIT; with it, the existing
|
|
454
|
+
* `sync_events_version_idx` drives the batch and the delete is a
|
|
455
|
+
* bounded index range scan.
|
|
456
|
+
*
|
|
457
|
+
* The `lastDurablePrune` throttle below is per-process, so every serverless
|
|
458
|
+
* worker prunes on its first poll. That was survivable only once the work
|
|
459
|
+
* itself became bounded and indexed; if concurrency is still a problem,
|
|
460
|
+
* the next step is a `pg_try_advisory_xact_lock` so one worker prunes at a
|
|
461
|
+
* time. Deliberately not done yet — measure before adding a lock.
|
|
462
|
+
*/
|
|
420
463
|
async pruneDurableEvents(client) {
|
|
421
464
|
const now = Date.now();
|
|
422
465
|
if (now - this.lastDurablePrune < 5 * 60 * 1000)
|
|
423
466
|
return;
|
|
424
467
|
this.lastDurablePrune = now;
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
468
|
+
const cutoff = now - DURABLE_RETENTION_MS;
|
|
469
|
+
let deleted = 0;
|
|
470
|
+
try {
|
|
471
|
+
for (let batch = 0; batch < DURABLE_PRUNE_MAX_BATCHES; batch++) {
|
|
472
|
+
const result = await client.execute({
|
|
473
|
+
// `id IN (...)` rather than ctid/rowid: both are dialect-specific,
|
|
474
|
+
// and the primary key is indexed on every dialect we ship.
|
|
475
|
+
sql: `DELETE FROM sync_events WHERE id IN (
|
|
476
|
+
SELECT id FROM sync_events WHERE created_at < ?
|
|
477
|
+
ORDER BY created_at, id LIMIT ?
|
|
478
|
+
)`,
|
|
479
|
+
args: [cutoff, DURABLE_PRUNE_BATCH],
|
|
480
|
+
});
|
|
481
|
+
deleted += result.rowsAffected;
|
|
482
|
+
if (result.rowsAffected < DURABLE_PRUNE_BATCH)
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
this.durablePruneFailures = 0;
|
|
486
|
+
}
|
|
487
|
+
catch (err) {
|
|
488
|
+
// This used to be `.catch(() => {})`. A prune that silently never
|
|
489
|
+
// succeeded is indistinguishable from one that had nothing to do, which
|
|
490
|
+
// is how the table reached 47 GB without anyone finding out. Warn once
|
|
491
|
+
// per failure streak so a persistently broken prune is visible without
|
|
492
|
+
// repeating every five minutes.
|
|
493
|
+
this.durablePruneFailures++;
|
|
494
|
+
if (this.durablePruneFailures === 1) {
|
|
495
|
+
console.warn(`[agent-native] sync_events prune failed after deleting ${deleted} row(s); the table will grow until this succeeds:`, err instanceof Error ? err.message : String(err));
|
|
496
|
+
}
|
|
497
|
+
}
|
|
431
498
|
}
|
|
432
499
|
async persistSyncEvent(event, dedupeKey, presetId) {
|
|
433
500
|
if (!(await this.ensureSyncEventsTable()))
|
|
@@ -1025,7 +1092,17 @@ export class AppSyncState {
|
|
|
1025
1092
|
// Action markers are durable specifically so a web server can observe work
|
|
1026
1093
|
// performed by a separate action process. Do not baseline past an existing
|
|
1027
1094
|
// marker on cold start, or the first poll after the action will miss it.
|
|
1028
|
-
|
|
1095
|
+
//
|
|
1096
|
+
// Bounded to a replay window rather than rewound to 0. At 0 the filter
|
|
1097
|
+
// below (`updated_at > lastActionMarkerTs`) passes EVERY row, and the
|
|
1098
|
+
// marker table is one never-pruned row per identity that has ever run a
|
|
1099
|
+
// mutating action — so every cold start re-emitted the entire history.
|
|
1100
|
+
// On one production app that was 2,188 rows replayed ~32 times a minute:
|
|
1101
|
+
// 1,169 sync events/sec, none of it real traffic, against ~1.7/sec that
|
|
1102
|
+
// was. A `> 0` first-run guard like the sibling detectors use would be
|
|
1103
|
+
// wrong here — it would discard the cross-process wakeup this rewind
|
|
1104
|
+
// exists for. Bounding the window keeps that and drops the history.
|
|
1105
|
+
this.lastActionMarkerTs = Math.max(0, actionMarkerTs - ACTION_MARKER_REPLAY_WINDOW_MS);
|
|
1029
1106
|
this.replayActionMarkerOnce = actionMarkerTs > 0;
|
|
1030
1107
|
this.lastScreenRefreshTs = refreshTs;
|
|
1031
1108
|
this.lastScreenRefreshTsBySession.clear();
|
|
@@ -1151,14 +1228,25 @@ export class AppSyncState {
|
|
|
1151
1228
|
// serverless action invocations wake the web server's SSE/poll loop as a
|
|
1152
1229
|
// first-class source:"action" event rather than a generic app-state bump.
|
|
1153
1230
|
if (actionMarkerTs > this.lastActionMarkerTs) {
|
|
1231
|
+
// Bounded by the same watermark the filter below applies, so a cold
|
|
1232
|
+
// start reads its replay window instead of every marker ever written.
|
|
1154
1233
|
const actionMarkerResult = await db.execute({
|
|
1155
|
-
sql: "SELECT session_id, value, updated_at FROM application_state WHERE key = ? ORDER BY updated_at ASC",
|
|
1156
|
-
args: [ACTION_CHANGE_MARKER_KEY],
|
|
1234
|
+
sql: "SELECT session_id, value, updated_at FROM application_state WHERE key = ? AND updated_at > ? ORDER BY updated_at ASC",
|
|
1235
|
+
args: [ACTION_CHANGE_MARKER_KEY, this.lastActionMarkerTs],
|
|
1157
1236
|
});
|
|
1158
1237
|
const changedActionMarkers = actionMarkerResult.rows.filter((row) => timestampValue(row.updated_at) > this.lastActionMarkerTs);
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1238
|
+
for (const row of changedActionMarkers) {
|
|
1239
|
+
const target = parseActionChangeMarker(row.session_id, row.value);
|
|
1240
|
+
if (!target)
|
|
1241
|
+
continue;
|
|
1242
|
+
// Keyed on the ROW's own timestamp, not the table-wide max: every
|
|
1243
|
+
// process replaying the same marker must produce the same id so
|
|
1244
|
+
// `ON CONFLICT (id) DO NOTHING` collapses them. Keyed on the max,
|
|
1245
|
+
// two processes booting a moment apart hash the same row
|
|
1246
|
+
// differently and each writes its own copy. Matches the extension
|
|
1247
|
+
// marker path.
|
|
1248
|
+
this.recordActionChanges([target], `action|${timestampValue(row.updated_at)}`);
|
|
1249
|
+
}
|
|
1162
1250
|
this.lastActionMarkerTs = actionMarkerTs;
|
|
1163
1251
|
}
|
|
1164
1252
|
// Check for screen-refresh requests from the agent. The `refresh-screen`
|
|
@@ -1290,6 +1378,13 @@ export function getDefaultAppSyncState() {
|
|
|
1290
1378
|
if (!_defaultState) {
|
|
1291
1379
|
_defaultState = new AppSyncState({
|
|
1292
1380
|
dbAssignedVersions: hostedRealtimeTransportEnabled(),
|
|
1381
|
+
// Only the out-of-band detectors (action markers, extensions, app-state)
|
|
1382
|
+
// pass a dedupeKey, so this changes nothing for ordinary writes — they
|
|
1383
|
+
// keep unique ids. It exists so N processes detecting the SAME external
|
|
1384
|
+
// write collapse to one row via `ON CONFLICT (id) DO NOTHING`. Left off,
|
|
1385
|
+
// it never once executed in production: every dedupeKey threaded through
|
|
1386
|
+
// this file was inert, and each cold start wrote its own duplicate set.
|
|
1387
|
+
deterministicEventIds: true,
|
|
1293
1388
|
});
|
|
1294
1389
|
}
|
|
1295
1390
|
return _defaultState;
|
|
@@ -8,8 +8,9 @@ export declare const REALTIME_VOICE_MAX_TOOL_OUTPUT_CHARS = 16000;
|
|
|
8
8
|
export declare const REALTIME_VOICE_MAX_TOOLS = 32;
|
|
9
9
|
export declare const REALTIME_VOICE_MAX_TOOL_SCHEMA_BYTES = 32000;
|
|
10
10
|
export declare const REALTIME_VOICE_MAX_SESSION_BYTES = 64000;
|
|
11
|
+
/** Absolute, not sliding — a signed grant cannot be extended server-side, so
|
|
12
|
+
* this must outlast the provider's 60-minute maximum realtime session. */
|
|
11
13
|
export declare const REALTIME_VOICE_TOOL_GRANT_TTL_MS: number;
|
|
12
|
-
export declare const REALTIME_VOICE_MAX_TOOL_GRANT_SESSIONS = 256;
|
|
13
14
|
export declare const REALTIME_VOICE_CAPABILITY_HEADER = "X-Agent-Native-Realtime-Capability";
|
|
14
15
|
export interface RealtimeVoiceRequestContext {
|
|
15
16
|
event: H3Event;
|
|
@@ -9,6 +9,7 @@ import { getBuilderGatewayBaseUrl, resolveBuilderCredentials, resolveSecret, } f
|
|
|
9
9
|
import { getH3App } from "./framework-request-handler.js";
|
|
10
10
|
import { runWithRequestContext } from "./request-context.js";
|
|
11
11
|
import { isSameOriginRequest } from "./request-origin.js";
|
|
12
|
+
import { signRealtimeVoiceCapability, verifyRealtimeVoiceCapability, } from "./short-lived-token.js";
|
|
12
13
|
export const REALTIME_VOICE_SESSION_PATH = "/_agent-native/realtime-voice/session";
|
|
13
14
|
export const REALTIME_VOICE_TOOL_PATH = "/_agent-native/realtime-voice/tool";
|
|
14
15
|
export const REALTIME_VOICE_MAX_SDP_BYTES = 64 * 1024;
|
|
@@ -17,8 +18,9 @@ export const REALTIME_VOICE_MAX_TOOL_OUTPUT_CHARS = 16_000;
|
|
|
17
18
|
export const REALTIME_VOICE_MAX_TOOLS = 32;
|
|
18
19
|
export const REALTIME_VOICE_MAX_TOOL_SCHEMA_BYTES = 32_000;
|
|
19
20
|
export const REALTIME_VOICE_MAX_SESSION_BYTES = 64_000;
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
/** Absolute, not sliding — a signed grant cannot be extended server-side, so
|
|
22
|
+
* this must outlast the provider's 60-minute maximum realtime session. */
|
|
23
|
+
export const REALTIME_VOICE_TOOL_GRANT_TTL_MS = 75 * 60 * 1_000;
|
|
22
24
|
export const REALTIME_VOICE_CAPABILITY_HEADER = "X-Agent-Native-Realtime-Capability";
|
|
23
25
|
const OPENAI_REALTIME_CALLS_URL = "https://api.openai.com/v1/realtime/calls";
|
|
24
26
|
const DEFAULT_MODEL = "gpt-realtime-2.1";
|
|
@@ -207,56 +209,30 @@ function packRealtimeTools(session, eligibleTools) {
|
|
|
207
209
|
}
|
|
208
210
|
return packed;
|
|
209
211
|
}
|
|
210
|
-
function mintRealtimeToolCapability() {
|
|
211
|
-
return
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
while (capabilities.size > REALTIME_VOICE_MAX_TOOL_GRANT_SESSIONS) {
|
|
219
|
-
let oldestKey;
|
|
220
|
-
let oldestExpiry = Number.POSITIVE_INFINITY;
|
|
221
|
-
for (const [key, capability] of capabilities) {
|
|
222
|
-
if (capability.expiresAt < oldestExpiry) {
|
|
223
|
-
oldestKey = key;
|
|
224
|
-
oldestExpiry = capability.expiresAt;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
if (!oldestKey)
|
|
228
|
-
break;
|
|
229
|
-
capabilities.delete(oldestKey);
|
|
230
|
-
}
|
|
212
|
+
function mintRealtimeToolCapability(auth, capability) {
|
|
213
|
+
return signRealtimeVoiceCapability({
|
|
214
|
+
userEmail: auth.userEmail,
|
|
215
|
+
...(auth.orgId ? { orgId: auth.orgId } : {}),
|
|
216
|
+
...(auth.browserTabId ? { browserTabId: auth.browserTabId } : {}),
|
|
217
|
+
toolNames: [...capability.initialNames],
|
|
218
|
+
discoveredToolNames: [...capability.names],
|
|
219
|
+
}, REALTIME_VOICE_TOOL_GRANT_TTL_MS / 1_000);
|
|
231
220
|
}
|
|
232
|
-
function
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
capabilities.set(token, {
|
|
236
|
-
userEmail: auth.userEmail.trim().toLowerCase(),
|
|
221
|
+
function resolveRealtimeToolCapability(token, auth) {
|
|
222
|
+
const verified = verifyRealtimeVoiceCapability(token, {
|
|
223
|
+
userEmail: auth.userEmail,
|
|
237
224
|
...(auth.orgId ? { orgId: auth.orgId } : {}),
|
|
238
225
|
...(auth.browserTabId ? { browserTabId: auth.browserTabId } : {}),
|
|
239
|
-
expiresAt: Date.now() + REALTIME_VOICE_TOOL_GRANT_TTL_MS,
|
|
240
|
-
initialNames: new Set(initialNames),
|
|
241
|
-
names: new Set(),
|
|
242
226
|
});
|
|
243
|
-
|
|
244
|
-
return token;
|
|
245
|
-
}
|
|
246
|
-
function resolveRealtimeToolCapability(capabilities, token, auth) {
|
|
247
|
-
cleanRealtimeToolCapabilities(capabilities);
|
|
248
|
-
if (!token)
|
|
249
|
-
return null;
|
|
250
|
-
const capability = capabilities.get(token);
|
|
251
|
-
if (!capability)
|
|
252
|
-
return null;
|
|
253
|
-
if (capability.userEmail !== auth.userEmail.trim().toLowerCase() ||
|
|
254
|
-
capability.orgId !== auth.orgId ||
|
|
255
|
-
capability.browserTabId !== auth.browserTabId) {
|
|
227
|
+
if (!verified.ok)
|
|
256
228
|
return null;
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
229
|
+
return {
|
|
230
|
+
userEmail: verified.userEmail,
|
|
231
|
+
...(verified.orgId ? { orgId: verified.orgId } : {}),
|
|
232
|
+
...(verified.browserTabId ? { browserTabId: verified.browserTabId } : {}),
|
|
233
|
+
initialNames: new Set(verified.toolNames),
|
|
234
|
+
names: new Set(verified.discoveredToolNames),
|
|
235
|
+
};
|
|
260
236
|
}
|
|
261
237
|
function parseSuccessfulToolSearchNames(output) {
|
|
262
238
|
try {
|
|
@@ -302,7 +278,6 @@ function grantDiscoveredRealtimeTools(input) {
|
|
|
302
278
|
input.capability.names.add(tool.name);
|
|
303
279
|
expandedTools.push(tool);
|
|
304
280
|
}
|
|
305
|
-
input.capability.expiresAt = Date.now() + REALTIME_VOICE_TOOL_GRANT_TTL_MS;
|
|
306
281
|
return expandedTools;
|
|
307
282
|
}
|
|
308
283
|
function declaredBodyBytes(event) {
|
|
@@ -364,7 +339,7 @@ function invalidMethod(event) {
|
|
|
364
339
|
setResponseStatus(event, 405);
|
|
365
340
|
return { error: "Method not allowed" };
|
|
366
341
|
}
|
|
367
|
-
function createSessionHandler(tools,
|
|
342
|
+
function createSessionHandler(tools, options) {
|
|
368
343
|
return defineEventHandler(async (event) => {
|
|
369
344
|
if (getMethod(event) !== "POST")
|
|
370
345
|
return invalidMethod(event);
|
|
@@ -510,7 +485,10 @@ function createSessionHandler(tools, capabilities, options) {
|
|
|
510
485
|
}
|
|
511
486
|
setResponseStatus(event, upstream.status);
|
|
512
487
|
setResponseHeader(event, "Content-Type", "application/sdp");
|
|
513
|
-
setResponseHeader(event, REALTIME_VOICE_CAPABILITY_HEADER,
|
|
488
|
+
setResponseHeader(event, REALTIME_VOICE_CAPABILITY_HEADER, mintRealtimeToolCapability(auth, {
|
|
489
|
+
initialNames: new Set(packedTools.map((tool) => tool.name)),
|
|
490
|
+
names: new Set(),
|
|
491
|
+
}));
|
|
514
492
|
return answerSdp;
|
|
515
493
|
});
|
|
516
494
|
});
|
|
@@ -563,7 +541,7 @@ function normalizeExecutionResult(result) {
|
|
|
563
541
|
: {}),
|
|
564
542
|
};
|
|
565
543
|
}
|
|
566
|
-
function createToolHandler(toolsByName,
|
|
544
|
+
function createToolHandler(toolsByName, options) {
|
|
567
545
|
return defineEventHandler(async (event) => {
|
|
568
546
|
if (getMethod(event) !== "POST")
|
|
569
547
|
return invalidMethod(event);
|
|
@@ -577,7 +555,7 @@ function createToolHandler(toolsByName, capabilities, options) {
|
|
|
577
555
|
setResponseStatus(event, 401);
|
|
578
556
|
return { error: "Authentication required" };
|
|
579
557
|
}
|
|
580
|
-
const capability = resolveRealtimeToolCapability(
|
|
558
|
+
const capability = resolveRealtimeToolCapability(readSafeHeader(event, REALTIME_VOICE_CAPABILITY_HEADER), auth);
|
|
581
559
|
if (!capability) {
|
|
582
560
|
setResponseStatus(event, 403);
|
|
583
561
|
return { error: "Invalid or expired realtime voice capability" };
|
|
@@ -648,7 +626,12 @@ function createToolHandler(toolsByName, capabilities, options) {
|
|
|
648
626
|
return {
|
|
649
627
|
callId: request.callId,
|
|
650
628
|
...result,
|
|
651
|
-
...(expandedTools.length > 0
|
|
629
|
+
...(expandedTools.length > 0
|
|
630
|
+
? {
|
|
631
|
+
expandedTools,
|
|
632
|
+
capability: mintRealtimeToolCapability(auth, capability),
|
|
633
|
+
}
|
|
634
|
+
: {}),
|
|
652
635
|
};
|
|
653
636
|
}
|
|
654
637
|
catch (error) {
|
|
@@ -669,10 +652,9 @@ export function mountRealtimeVoiceRoutes(nitroApp, actions, options) {
|
|
|
669
652
|
}
|
|
670
653
|
const tools = buildRealtimeTools(actions);
|
|
671
654
|
const toolsByName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
672
|
-
const capabilities = new Map();
|
|
673
655
|
const app = getH3App(nitroApp);
|
|
674
|
-
app.use(REALTIME_VOICE_SESSION_PATH, createSessionHandler(tools,
|
|
675
|
-
app.use(REALTIME_VOICE_TOOL_PATH, createToolHandler(toolsByName,
|
|
656
|
+
app.use(REALTIME_VOICE_SESSION_PATH, createSessionHandler(tools, options));
|
|
657
|
+
app.use(REALTIME_VOICE_TOOL_PATH, createToolHandler(toolsByName, options));
|
|
676
658
|
return {
|
|
677
659
|
sessionPath: REALTIME_VOICE_SESSION_PATH,
|
|
678
660
|
toolPath: REALTIME_VOICE_TOOL_PATH,
|
|
@@ -121,6 +121,49 @@ export declare function verifyRealtimeSubscribeToken(token: string, expected: {
|
|
|
121
121
|
projectId: string;
|
|
122
122
|
key: string;
|
|
123
123
|
}): RealtimeVerifyResult;
|
|
124
|
+
/** Payload `typ` discriminator for realtime voice tool capabilities. */
|
|
125
|
+
export declare const REALTIME_VOICE_CAPABILITY_TOKEN_TYPE = "rt-voice-capability";
|
|
126
|
+
/** Inputs for {@link signRealtimeVoiceCapability}. */
|
|
127
|
+
export interface RealtimeVoiceCapabilityClaims {
|
|
128
|
+
/** Authenticated caller. Re-checked against the session on every tool call. */
|
|
129
|
+
userEmail: string;
|
|
130
|
+
orgId?: string;
|
|
131
|
+
/** Binds the capability to the tab that opened the session. */
|
|
132
|
+
browserTabId?: string;
|
|
133
|
+
/** Tool names packed into the session's opening manifest. */
|
|
134
|
+
toolNames: readonly string[];
|
|
135
|
+
/** Names added later by a successful `tool-search`, capped separately. */
|
|
136
|
+
discoveredToolNames?: readonly string[];
|
|
137
|
+
ttlSeconds?: number;
|
|
138
|
+
}
|
|
139
|
+
/** Result of {@link verifyRealtimeVoiceCapability}. */
|
|
140
|
+
export type RealtimeVoiceCapabilityVerifyResult = {
|
|
141
|
+
ok: true;
|
|
142
|
+
userEmail: string;
|
|
143
|
+
orgId?: string;
|
|
144
|
+
browserTabId?: string;
|
|
145
|
+
toolNames: string[];
|
|
146
|
+
discoveredToolNames: string[];
|
|
147
|
+
} | {
|
|
148
|
+
ok: false;
|
|
149
|
+
reason: string;
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Mint a capability authorising `claims.toolNames` for one realtime voice
|
|
153
|
+
* session. The token is a bounded manifest scope layered on top of the
|
|
154
|
+
* caller's session cookie — never a standalone credential.
|
|
155
|
+
*/
|
|
156
|
+
export declare function signRealtimeVoiceCapability(claims: RealtimeVoiceCapabilityClaims, ttlSecondsDefault: number): string;
|
|
157
|
+
/**
|
|
158
|
+
* Verify a realtime voice capability and confirm it was minted for exactly the
|
|
159
|
+
* identity now making the request. Identity mismatch is reported separately
|
|
160
|
+
* from a bad signature so callers can tell a replay from a stale tab.
|
|
161
|
+
*/
|
|
162
|
+
export declare function verifyRealtimeVoiceCapability(token: string | undefined, expected: {
|
|
163
|
+
userEmail: string;
|
|
164
|
+
orgId?: string;
|
|
165
|
+
browserTabId?: string;
|
|
166
|
+
}): RealtimeVoiceCapabilityVerifyResult;
|
|
124
167
|
/** Payload `typ` discriminator for gateway access-check tokens. */
|
|
125
168
|
export declare const GATEWAY_ACCESS_TOKEN_TYPE = "rt-access-check";
|
|
126
169
|
/** Inputs for {@link signGatewayAccessToken}. */
|
|
@@ -241,6 +241,80 @@ export function verifyRealtimeSubscribeToken(token, expected) {
|
|
|
241
241
|
absExp: claims.absExp,
|
|
242
242
|
};
|
|
243
243
|
}
|
|
244
|
+
// ── Realtime voice tool capabilities ─────────────────────────────────────────
|
|
245
|
+
// Signed, not stored: minting and spending are separate requests, and under a
|
|
246
|
+
// serverless preset they land on different instances.
|
|
247
|
+
/** Payload `typ` discriminator for realtime voice tool capabilities. */
|
|
248
|
+
export const REALTIME_VOICE_CAPABILITY_TOKEN_TYPE = "rt-voice-capability";
|
|
249
|
+
/**
|
|
250
|
+
* Mint a capability authorising `claims.toolNames` for one realtime voice
|
|
251
|
+
* session. The token is a bounded manifest scope layered on top of the
|
|
252
|
+
* caller's session cookie — never a standalone credential.
|
|
253
|
+
*/
|
|
254
|
+
export function signRealtimeVoiceCapability(claims, ttlSecondsDefault) {
|
|
255
|
+
const payload = {
|
|
256
|
+
typ: REALTIME_VOICE_CAPABILITY_TOKEN_TYPE,
|
|
257
|
+
userEmail: claims.userEmail.trim().toLowerCase(),
|
|
258
|
+
toolNames: [...claims.toolNames],
|
|
259
|
+
exp: Math.floor(Date.now() / 1000) + (claims.ttlSeconds ?? ttlSecondsDefault),
|
|
260
|
+
};
|
|
261
|
+
if (claims.orgId)
|
|
262
|
+
payload.orgId = claims.orgId;
|
|
263
|
+
if (claims.browserTabId)
|
|
264
|
+
payload.browserTabId = claims.browserTabId;
|
|
265
|
+
if (claims.discoveredToolNames?.length) {
|
|
266
|
+
payload.discovered = [...claims.discoveredToolNames];
|
|
267
|
+
}
|
|
268
|
+
const payloadStr = base64UrlEncode(JSON.stringify(payload));
|
|
269
|
+
return `${payloadStr}.${hmacB64(payloadStr, getSigningKey())}`;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Verify a realtime voice capability and confirm it was minted for exactly the
|
|
273
|
+
* identity now making the request. Identity mismatch is reported separately
|
|
274
|
+
* from a bad signature so callers can tell a replay from a stale tab.
|
|
275
|
+
*/
|
|
276
|
+
export function verifyRealtimeVoiceCapability(token, expected) {
|
|
277
|
+
if (typeof token !== "string" || !token.includes(".")) {
|
|
278
|
+
return { ok: false, reason: "malformed" };
|
|
279
|
+
}
|
|
280
|
+
const [payloadStr, sig] = token.split(".", 2);
|
|
281
|
+
if (!payloadStr || !sig)
|
|
282
|
+
return { ok: false, reason: "malformed" };
|
|
283
|
+
if (!timingSafeEqualB64(sig, hmacB64(payloadStr, getSigningKey()))) {
|
|
284
|
+
return { ok: false, reason: "bad_signature" };
|
|
285
|
+
}
|
|
286
|
+
let claims;
|
|
287
|
+
try {
|
|
288
|
+
claims = JSON.parse(base64UrlDecode(payloadStr).toString("utf8"));
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
return { ok: false, reason: "bad_payload" };
|
|
292
|
+
}
|
|
293
|
+
if (claims.typ !== REALTIME_VOICE_CAPABILITY_TOKEN_TYPE) {
|
|
294
|
+
return { ok: false, reason: "wrong_type" };
|
|
295
|
+
}
|
|
296
|
+
if (typeof claims.exp !== "number" || !Array.isArray(claims.toolNames)) {
|
|
297
|
+
return { ok: false, reason: "bad_payload" };
|
|
298
|
+
}
|
|
299
|
+
if (claims.exp * 1000 < Date.now())
|
|
300
|
+
return { ok: false, reason: "expired" };
|
|
301
|
+
if (claims.userEmail !== expected.userEmail.trim().toLowerCase() ||
|
|
302
|
+
claims.orgId !== expected.orgId ||
|
|
303
|
+
claims.browserTabId !== expected.browserTabId) {
|
|
304
|
+
return { ok: false, reason: "identity_mismatch" };
|
|
305
|
+
}
|
|
306
|
+
const stringsOnly = (value) => Array.isArray(value)
|
|
307
|
+
? value.filter((name) => typeof name === "string")
|
|
308
|
+
: [];
|
|
309
|
+
return {
|
|
310
|
+
ok: true,
|
|
311
|
+
userEmail: claims.userEmail,
|
|
312
|
+
orgId: claims.orgId,
|
|
313
|
+
browserTabId: claims.browserTabId,
|
|
314
|
+
toolNames: stringsOnly(claims.toolNames),
|
|
315
|
+
discoveredToolNames: stringsOnly(claims.discovered),
|
|
316
|
+
};
|
|
317
|
+
}
|
|
244
318
|
// ── Gateway access-check tokens ──────────────────────────────────────────────
|
|
245
319
|
//
|
|
246
320
|
// The hosted gateway has no access to an app's shareable-resource registry, so
|
|
@@ -18,7 +18,7 @@ import { defineEventHandler } from "h3";
|
|
|
18
18
|
*/
|
|
19
19
|
import { createRequestHandler } from "react-router";
|
|
20
20
|
import { isMcpPublicPath } from "../mcp/route-paths.js";
|
|
21
|
-
import { DEFAULT_SPECULATION_RULES_PATH, resolveSsrCacheHeaders, } from "../shared/cache-control.js";
|
|
21
|
+
import { DEFAULT_SPECULATION_RULES_PATH, resolveSsrCacheHeaders, resolveSsrCacheKeyHeaders, } from "../shared/cache-control.js";
|
|
22
22
|
import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, withAgentNativeSocialImageCacheBuster, } from "../shared/social-meta.js";
|
|
23
23
|
import { getAppBasePathFromViteEnv, stripAppBasePath as canonicalStripAppBasePath, } from "./app-base-path.js";
|
|
24
24
|
import { captureError } from "./capture-error.js";
|
|
@@ -225,6 +225,9 @@ function applyDefaultSsrCacheHeader(headers, status, pathname) {
|
|
|
225
225
|
for (const [name, value] of Object.entries(resolveSsrCacheHeaders())) {
|
|
226
226
|
headers.set(name, value);
|
|
227
227
|
}
|
|
228
|
+
for (const [name, value] of Object.entries(resolveSsrCacheKeyHeaders())) {
|
|
229
|
+
headers.set(name, value);
|
|
230
|
+
}
|
|
228
231
|
}
|
|
229
232
|
function applyDefaultSpeculationRulesHeader(headers, status, basePath) {
|
|
230
233
|
if (status < 200 || status >= 400)
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export { SIGN_IN_CONTINUATION_MAX_LENGTH, SIGN_IN_CONTINUATION_PARAM, SIGN_IN_EN
|
|
|
5
5
|
export { truncate } from "./truncate.js";
|
|
6
6
|
export { injectDocumentMarkup } from "./html-document.js";
|
|
7
7
|
export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
|
|
8
|
+
export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, type RuntimeConfigEnvironment, type RuntimeConfigIssue, type RuntimeConfigIssueCode, type RuntimeConfigIssueSeverity, type RuntimeConfigPhase, type RuntimeConfigReport, type RuntimeConfigRequirements, } from "./runtime-config.js";
|
|
8
9
|
export { llmConnectionTrackingProperties, normalizeLlmConnection, type LlmConnectionStatus, } from "./llm-connection.js";
|
|
9
10
|
export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, } from "./workspace-app-id.js";
|
|
10
11
|
export { DEFAULT_WORKSPACE_APP_AUDIENCE, WORKSPACE_APP_AUDIENCES, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromEnv, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromEnv, workspaceAppRouteAccessFromPackageJson, type WorkspaceAppRouteAccess, type WorkspaceAppRouteAccessFromConfig, type WorkspaceAppAudience, } from "./workspace-app-audience.js";
|
package/dist/shared/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export { SIGN_IN_CONTINUATION_MAX_LENGTH, SIGN_IN_CONTINUATION_PARAM, SIGN_IN_EN
|
|
|
5
5
|
export { truncate } from "./truncate.js";
|
|
6
6
|
export { injectDocumentMarkup } from "./html-document.js";
|
|
7
7
|
export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
|
|
8
|
+
export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, } from "./runtime-config.js";
|
|
8
9
|
export { llmConnectionTrackingProperties, normalizeLlmConnection, } from "./llm-connection.js";
|
|
9
10
|
export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, } from "./workspace-app-id.js";
|
|
10
11
|
export { DEFAULT_WORKSPACE_APP_AUDIENCE, WORKSPACE_APP_AUDIENCES, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromEnv, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromEnv, workspaceAppRouteAccessFromPackageJson, } from "./workspace-app-audience.js";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production configuration diagnostics.
|
|
3
|
+
*
|
|
4
|
+
* This module deliberately accepts an env-like record instead of reading
|
|
5
|
+
* process.env so the same rules can run during a Vite build, on the server,
|
|
6
|
+
* and in focused tests without ever exposing secret values to the browser.
|
|
7
|
+
*/
|
|
8
|
+
export type RuntimeConfigEnvironment = "development" | "production";
|
|
9
|
+
export type RuntimeConfigPhase = "build" | "runtime";
|
|
10
|
+
export type RuntimeConfigIssueSeverity = "warning" | "error";
|
|
11
|
+
export type RuntimeConfigIssueCode = "auth-disabled-in-production" | "missing-auth-secret" | "weak-auth-secret" | "missing-a2a-secret" | "weak-a2a-secret" | "invalid-auth-url" | "missing-database-url" | "local-database-in-production" | "missing-required-env";
|
|
12
|
+
export interface RuntimeConfigRequirements {
|
|
13
|
+
/** Whether the app's default or custom auth layer is expected to run. */
|
|
14
|
+
authEnabled?: boolean;
|
|
15
|
+
/** Whether the app needs a persistent database outside local development. */
|
|
16
|
+
databaseRequired?: boolean;
|
|
17
|
+
/** Additional non-secret keys the app declares as required. */
|
|
18
|
+
requiredEnv?: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
export interface RuntimeConfigIssue {
|
|
21
|
+
code: RuntimeConfigIssueCode;
|
|
22
|
+
severity: RuntimeConfigIssueSeverity;
|
|
23
|
+
title: string;
|
|
24
|
+
message: string;
|
|
25
|
+
envKeys: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface RuntimeConfigReport {
|
|
28
|
+
ok: boolean;
|
|
29
|
+
status: "ok" | "warning" | "error";
|
|
30
|
+
environment: RuntimeConfigEnvironment;
|
|
31
|
+
phase: RuntimeConfigPhase;
|
|
32
|
+
issues: RuntimeConfigIssue[];
|
|
33
|
+
prompt: string;
|
|
34
|
+
}
|
|
35
|
+
export interface RuntimeConfigReportOptions {
|
|
36
|
+
environment?: RuntimeConfigEnvironment;
|
|
37
|
+
phase?: RuntimeConfigPhase;
|
|
38
|
+
appName?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function runtimeConfigRequirementsFromSearchParams(searchParams: URLSearchParams): RuntimeConfigRequirements;
|
|
41
|
+
export declare function buildRuntimeConfigPrompt(report: Pick<RuntimeConfigReport, "environment" | "phase" | "issues">, appName?: string): string;
|
|
42
|
+
export declare function getRuntimeConfigReport(env: Record<string, string | undefined>, requirements?: RuntimeConfigRequirements, options?: RuntimeConfigReportOptions): RuntimeConfigReport;
|
|
43
|
+
export declare function formatRuntimeConfigReport(report: RuntimeConfigReport): string;
|
|
44
|
+
export declare function parseRuntimeConfigReport(value: unknown): RuntimeConfigReport | null;
|