@agent-native/core 0.169.1 → 0.171.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-native.eject.json +4 -1
- package/bin/agent-native.js +23 -5
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
- package/corpus/templates/analytics/app/i18n-data.ts +28 -0
- package/corpus/templates/analytics/app/pages/Agents.tsx +25 -1
- package/corpus/templates/analytics/app/routes/$.tsx +10 -0
- package/corpus/templates/analytics/app/routes.ts +3 -1
- package/corpus/templates/analytics/changelog/2026-08-22-fixed-the-agent-native-templates-first-party-dashboard-panel.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-22-org-admin-panels-no-longer-report-a-database-error-as-a-per.md +9 -0
- package/corpus/templates/analytics/changelog/2026-08-22-slack-requests-report-invalid-inputs.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-22-unknown-analytics-links-now-return-a-real-not-found-status.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +2 -1
- package/corpus/templates/analytics/docs/schemas/tracked-events.md +2 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +29 -7
- package/corpus/templates/analytics/server/handlers/slack.ts +59 -5
- package/corpus/templates/analytics/server/lib/db-admin-connections.ts +11 -6
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +132 -2
- package/corpus/templates/analytics/server/lib/slack.ts +4 -2
- package/corpus/templates/analytics/vitest.config.ts +6 -1
- package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/assets/app/routes/library.tsx +5 -3
- package/corpus/templates/assets/app/routes.ts +3 -1
- package/corpus/templates/assets/changelog/2026-08-22-library-page-loads-again-instead-of-crashing-on-open.md +6 -0
- package/corpus/templates/assets/vitest.config.ts +6 -1
- package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/brain/app/components/ui/pointer-lock.ts +1 -0
- package/corpus/templates/brain/app/routes/sources.tsx +8 -3
- package/corpus/templates/brain/changelog/2026-08-22-tuning-or-adding-a-source-no-longer-leaves-the-sources-page.md +6 -0
- package/corpus/templates/brain/vitest.config.ts +1 -0
- package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/calendar/actions/list-booking-links.ts +83 -4
- package/corpus/templates/calendar/actions/update-booking-link.ts +4 -3
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +11 -3
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +1 -1
- package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +103 -44
- package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +28 -24
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +9 -2
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +47 -58
- package/corpus/templates/calendar/app/hooks/use-booking-links.ts +5 -1
- package/corpus/templates/calendar/app/lib/event-layout.ts +52 -26
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +126 -98
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +1 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +88 -81
- package/corpus/templates/calendar/app/routes.ts +3 -1
- package/corpus/templates/calendar/changelog/2026-08-22-booking-link-visibility-respects-shared-access.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-clicking-an-out-of-office-event-s-marker-no-longer-creates-a.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-event-detail-views-now-show-your-calendar-timezone.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-google-calendar-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-overlapping-events-now-show-each-others-boundaries.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-public-booking-pages-now-offer-time-slots-from-the-host-s-we.md +6 -0
- package/corpus/templates/calendar/server/handlers/bookings.ts +5 -7
- package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
- package/corpus/templates/calendar/server/lib/google-calendar.ts +139 -14
- package/corpus/templates/calendar/server/onboarding.ts +85 -0
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/calendar/shared/api.ts +9 -1
- package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/chat/app/routes.ts +3 -1
- package/corpus/templates/chat/vitest.config.ts +8 -0
- package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/clips/actions/get-meeting.ts +9 -4
- package/corpus/templates/clips/actions/list-recordings.ts +16 -3
- package/corpus/templates/clips/actions/search-meetings.ts +1 -0
- package/corpus/templates/clips/actions/view-screen.ts +8 -1
- package/corpus/templates/clips/app/components/meetings/meeting-history-row.tsx +32 -1
- package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +29 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +5 -0
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +33 -4
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -0
- package/corpus/templates/clips/app/routes/access-request.approve.tsx +16 -9
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +17 -7
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +17 -7
- package/corpus/templates/clips/changelog/2026-08-21-camera-bubble-black-circle.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-22-screen-recordings-respect-the-microphone-toggle.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-22-the-recordings-library-no-longer-fails-right-after-server-start.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-23-the-agent-can-see-your-library-right-after-server-start.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +1 -2
- package/corpus/templates/clips/chrome-extension/src/native-transcription.ts +39 -7
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +21 -25
- package/corpus/templates/clips/desktop/src/app.tsx +53 -24
- package/corpus/templates/clips/desktop/src/lib/bubble-playback.ts +68 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +3 -0
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +72 -14
- package/corpus/templates/clips/desktop/src/lib/updater.ts +8 -3
- package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +162 -20
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +43 -6
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +150 -13
- package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +28 -3
- package/corpus/templates/clips/server/lib/emails.ts +17 -33
- package/corpus/templates/content/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +140 -15
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +12 -14
- package/corpus/templates/content/app/components/ui/pointer-lock.ts +1 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +18 -2
- package/corpus/templates/content/app/hooks/use-local-storage.ts +38 -22
- package/corpus/templates/content/app/i18n-data.ts +25 -0
- package/corpus/templates/content/app/routes.ts +3 -1
- package/corpus/templates/content/changelog/2026-08-22-code-blocks-inserted-from-the-slash-menu-no-longer-get-stuck.md +6 -0
- package/corpus/templates/content/changelog/2026-08-22-the-sidebar-page-tree-no-longer-flashes-empty-after-creating-a-page.md +6 -0
- package/corpus/templates/content/docs/solutions/2026-08-21-content-mermaid-rendering-shape.md +233 -0
- package/corpus/templates/content/server/plugins/agent-chat.ts +9 -2
- package/corpus/templates/content/vitest.config.ts +7 -1
- package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/design/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1383 -88
- package/corpus/templates/design/actions/generate-design.ts +98 -47
- package/corpus/templates/design/actions/get-design-system.ts +6 -1
- package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +146 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +70 -26
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +284 -136
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2057 -141
- package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +6 -2
- package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +4 -4
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +10 -1
- package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +19 -2
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -2
- package/corpus/templates/design/app/components/layout/Header.tsx +15 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +7 -2
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +11 -4
- package/corpus/templates/design/app/i18n-data.ts +1 -0
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +12 -0
- package/corpus/templates/design/app/lib/design-system-data.ts +68 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +77 -35
- package/corpus/templates/design/app/pages/DesignSystems.tsx +136 -42
- package/corpus/templates/design/app/pages/Index.tsx +2 -0
- package/corpus/templates/design/app/pages/Templates.tsx +0 -10
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +10 -0
- package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +50 -0
- package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +10 -8
- package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +6 -6
- package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +18 -7
- package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +4 -90
- package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +2 -1
- package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +4 -3
- package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +12 -2
- package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +9 -2
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +11 -1
- package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +11 -19
- package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +6 -6
- package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +12 -15
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -59
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +8 -0
- package/corpus/templates/design/app/pages/design-editor/types.ts +3 -3
- package/corpus/templates/design/app/routes.ts +3 -1
- package/corpus/templates/design/changelog/2026-08-20-canvas-edits-patch-the-frame-instead-of-rebuilding-it.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-draw-mode-needs-shift-y.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-eyedropper-shortcut.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-figma-style-alignment-guides-and-snapping.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-group-transforms-keep-the-selection.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-inspector-fields-keep-focus-on-enter.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-pen-alt-keeps-the-incoming-handle.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-pen-on-the-board-creates-one-vector.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-scale-a-multi-selection-from-the-group-handles.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-scale-resizes-text-with-the-object.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-selecting-another-object-keeps-the-scale-tool-armed.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-the-shape-tool-remembers-the-shape-you-picked.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-vectors-drawn-in-a-frame-land-where-you-drew-them.md +6 -0
- package/corpus/templates/design/changelog/2026-08-22-multi-screen-generation-no-longer-loses-a-saved-screens-layo.md +6 -0
- package/corpus/templates/design/changelog/2026-08-22-rename-and-search-fields-are-labeled-for-screen-readers.md +6 -0
- package/corpus/templates/design/package.json +2 -0
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +311 -0
- package/corpus/templates/design/shared/canvas-math.ts +612 -206
- package/corpus/templates/design/shared/pen-path.ts +37 -0
- package/corpus/templates/design/vitest.config.ts +7 -1
- package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/dispatch/actions/list-workspace-connections.ts +34 -3
- package/corpus/templates/dispatch/app/routes/integrations.tsx +55 -21
- package/corpus/templates/dispatch/app/routes.ts +3 -1
- package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/factory/.env.example +2 -7
- package/corpus/templates/factory/AGENTS.md +3 -0
- package/corpus/templates/factory/README.md +5 -3
- package/corpus/templates/factory/actions/create-factory.ts +16 -3
- package/corpus/templates/factory/actions/get-slack-feedback-context.ts +2 -0
- package/corpus/templates/factory/actions/get-triage-item.ts +2 -0
- package/corpus/templates/factory/actions/list-factory-audit.ts +116 -36
- package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
- package/corpus/templates/factory/actions/list-triage-items.ts +22 -19
- package/corpus/templates/factory/actions/run-factory-automation.ts +7 -3
- package/corpus/templates/factory/actions/save-factory-automation.ts +5 -2
- package/corpus/templates/factory/actions/save-triage-config.ts +2 -8
- package/corpus/templates/factory/actions/start-builder-for-item.ts +21 -0
- package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +229 -297
- package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +397 -247
- package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +33 -0
- package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +202 -162
- package/corpus/templates/factory/app/i18n/en-US.ts +32 -4
- package/corpus/templates/factory/app/routes/factory.tsx +84 -11
- package/corpus/templates/factory/app/routes.ts +3 -1
- package/corpus/templates/factory/changelog/2026-08-21-activity-runs-use-automation-display-names.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-create-and-settings-source-cards.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-keep-automations-visible-while-running.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-nested-factory-automations-can-poll.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-settings-sticky-unsaved-bar.md +6 -0
- package/corpus/templates/factory/server/connectors/credentials.ts +10 -5
- package/corpus/templates/factory/server/lib/factory-audit-report.ts +412 -0
- package/corpus/templates/factory/server/lib/factory-config-reconcile.ts +321 -0
- package/corpus/templates/factory/server/lib/factory-scope.ts +25 -2
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +13 -4
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +148 -4
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +4 -6
- package/corpus/templates/factory/vitest.config.ts +17 -2
- package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/forms/app/routes/_app.settings.tsx +4 -1
- package/corpus/templates/forms/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/forms/server/lib/public-form-ssr.ts +11 -1
- package/corpus/templates/forms/vitest.config.ts +1 -0
- package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/macros/app/routes.ts +3 -1
- package/corpus/templates/macros/vitest.config.ts +6 -1
- package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/mail/actions/manage-gmail-filters.ts +10 -2
- package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -37
- package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +14 -2
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +66 -36
- package/corpus/templates/mail/app/hooks/use-google-auth.ts +2 -0
- package/corpus/templates/mail/app/lib/google-oauth-setup.ts +17 -0
- package/corpus/templates/mail/app/pages/InboxPage.tsx +69 -9
- package/corpus/templates/mail/app/routes/$.tsx +9 -0
- package/corpus/templates/mail/app/routes/$view.$threadId.tsx +23 -1
- package/corpus/templates/mail/app/routes/$view.tsx +47 -1
- package/corpus/templates/mail/app/routes.ts +3 -1
- package/corpus/templates/mail/changelog/2026-08-22-gmail-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/mail/changelog/2026-08-22-gmail-filters-now-shows-the-real-error.md +6 -0
- package/corpus/templates/mail/changelog/2026-08-22-unknown-mail-urls-now-show-the-404-page.md +6 -0
- package/corpus/templates/mail/server/handlers/google-auth.ts +11 -2
- package/corpus/templates/mail/server/lib/google-auth.ts +92 -12
- package/corpus/templates/mail/server/onboarding.ts +66 -18
- package/corpus/templates/mail/vitest.config.ts +6 -1
- package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/plan/app/routes/settings.tsx +4 -1
- package/corpus/templates/plan/app/routes.ts +3 -1
- package/corpus/templates/plan/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/plan/netlify.toml +1 -1
- package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/slides/actions/patch-deck.ts +79 -10
- package/corpus/templates/slides/actions/update-slide.ts +11 -1
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +14 -4
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +10 -52
- package/corpus/templates/slides/app/components/editor/GoogleDocImportHint.tsx +8 -53
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +9 -75
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +8 -60
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +10 -2
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +19 -7
- package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +49 -36
- package/corpus/templates/slides/app/routes/access-request.approve.tsx +16 -9
- package/corpus/templates/slides/app/routes.ts +3 -1
- package/corpus/templates/slides/changelog/2026-08-22-already-uploaded-chat-images-are-no-longer-dropped.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-google-drive-and-slides-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-multi-slide-repairs-now-report-slides-that-still-overflow.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-update-slide-now-reports-which-batched-edit-was-skipped.md +6 -0
- package/corpus/templates/slides/server/handlers/google-docs-auth.ts +52 -1
- package/corpus/templates/slides/server/lib/chat-attachments.ts +29 -3
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +66 -16
- package/corpus/templates/slides/server/lib/slide-content-patch.ts +13 -2
- package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -2
- package/corpus/templates/slides/tsconfig.json +5 -0
- package/corpus/templates/slides/vitest.config.ts +6 -1
- package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/tasks/app/routes/settings.tsx +4 -1
- package/corpus/templates/tasks/app/routes.ts +3 -1
- package/corpus/templates/tasks/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/tasks/vitest.config.ts +7 -1
- package/dist/action.d.ts +91 -0
- package/dist/action.js +50 -0
- package/dist/agent/abort-reasons.d.ts +38 -0
- package/dist/agent/abort-reasons.js +49 -0
- package/dist/agent/engine/ai-sdk-engine.js +8 -5
- package/dist/agent/engine/anthropic-engine.js +7 -5
- package/dist/agent/engine/first-event-timeout.d.ts +42 -17
- package/dist/agent/engine/first-event-timeout.js +67 -25
- package/dist/agent/production-agent.d.ts +23 -0
- package/dist/agent/production-agent.js +107 -102
- package/dist/agent/run-loop-with-resume.d.ts +2 -28
- package/dist/agent/run-loop-with-resume.js +25 -40
- package/dist/agent/run-manager.js +5 -4
- package/dist/agent/run-store.d.ts +55 -0
- package/dist/agent/run-store.js +124 -1
- package/dist/agent/tool-search.js +2 -1
- package/dist/agent/types.d.ts +9 -4
- package/dist/app-config/auth.d.ts +1 -0
- package/dist/app-config/auth.js +7 -0
- package/dist/app-config/configuration-error.d.ts +11 -0
- package/dist/app-config/configuration-error.js +14 -0
- package/dist/app-config/index.d.ts +1 -0
- package/dist/app-config/index.js +1 -0
- package/dist/app-config/integrations.d.ts +1 -0
- package/dist/app-config/integrations.js +10 -0
- package/dist/app-config/plugins.d.ts +34 -0
- package/dist/app-config/plugins.js +39 -0
- package/dist/app-config/run-lifecycle-invariants.d.ts +18 -9
- package/dist/app-config/run-lifecycle-invariants.js +18 -25
- package/dist/app-config/schema.d.ts +17 -0
- package/dist/app-config/schema.js +2 -0
- package/dist/chat-threads/schema-migrations.js +20 -0
- package/dist/chat-threads/store.js +21 -4
- package/dist/cli/native-dependencies.d.ts +4 -0
- package/dist/cli/native-dependencies.js +15 -0
- package/dist/client/EnvironmentBadge.d.ts +1 -1
- package/dist/client/EnvironmentBadge.js +40 -5
- package/dist/client/MultiTabAssistantChat.d.ts +1 -1
- package/dist/client/MultiTabAssistantChat.js +35 -14
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat/index.js +1 -1
- package/dist/client/agent-page/use-jobs.d.ts +2 -1
- package/dist/client/agent-page/use-jobs.js +3 -5
- package/dist/client/agent-sidebar-state.js +3 -1
- package/dist/client/blocks/library/code-tabs.js +5 -0
- package/dist/client/blocks/library/code.js +1 -0
- package/dist/client/chat-first/apps-rail.js +2 -2
- package/dist/client/chat-model-groups.d.ts +12 -0
- package/dist/client/chat-model-groups.js +3 -2
- package/dist/client/integrations/GoogleProductLogo.d.ts +5 -0
- package/dist/client/integrations/GoogleProductLogo.js +45 -0
- package/dist/client/integrations/index.d.ts +2 -0
- package/dist/client/integrations/index.js +2 -0
- package/dist/client/integrations/workspace-provider-oauth.d.ts +8 -0
- package/dist/client/integrations/workspace-provider-oauth.js +13 -0
- package/dist/client/resources/mcp-integration-catalog.js +0 -29
- package/dist/client/settings/SettingsTabsPage.js +10 -6
- package/dist/client/sharing/ShareButton.js +11 -2
- package/dist/client/use-chat-models.d.ts +6 -0
- package/dist/client/use-chat-models.js +10 -0
- package/dist/client/use-db-sync.js +27 -9
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +111 -9
- package/dist/connections/catalog.js +86 -30
- package/dist/db/create-get-db.js +18 -0
- package/dist/db/ddl-guard.d.ts +0 -4
- package/dist/db/ddl-guard.js +46 -0
- package/dist/deploy/build.d.ts +19 -0
- package/dist/deploy/build.js +190 -16
- package/dist/deploy/function-bundle.d.ts +45 -0
- package/dist/deploy/function-bundle.js +337 -0
- package/dist/deploy/workspace-deploy.js +19 -1
- package/dist/eject/workspace-connections.js +4 -0
- package/dist/email-catalog/registry.d.ts +4 -0
- package/dist/email-catalog/registry.js +79 -14
- package/dist/extensions/content-patch.js +14 -2
- package/dist/integrations/plugin.d.ts +10 -0
- package/dist/integrations/plugin.js +40 -6
- package/dist/jobs/actions/run-automation-now.d.ts +2 -1
- package/dist/jobs/actions/run-automation-now.js +11 -5
- package/dist/jobs/frontmatter.js +53 -2
- package/dist/jobs/run-now.d.ts +11 -1
- package/dist/jobs/run-now.js +42 -7
- package/dist/jobs/scheduler.d.ts +1 -0
- package/dist/jobs/scheduler.js +2 -1
- package/dist/localization/core-messages/ar-SA.js +3 -0
- package/dist/localization/core-messages/de-DE.js +3 -0
- package/dist/localization/core-messages/en-US.d.ts +3 -0
- package/dist/localization/core-messages/en-US.js +3 -0
- package/dist/localization/core-messages/es-ES.js +3 -0
- package/dist/localization/core-messages/fr-FR.js +3 -0
- package/dist/localization/core-messages/hi-IN.js +3 -0
- package/dist/localization/core-messages/ja-JP.js +3 -0
- package/dist/localization/core-messages/ko-KR.js +3 -0
- package/dist/localization/core-messages/pt-BR.js +3 -0
- package/dist/localization/core-messages/zh-CN.js +3 -0
- package/dist/localization/core-messages/zh-TW.js +3 -0
- package/dist/localization/core-messages.d.ts +3 -0
- package/dist/localization/default-messages.d.ts +2 -5
- package/dist/localization/default-messages.js +2 -5
- package/dist/mcp/build-server.d.ts +9 -0
- package/dist/mcp/build-server.js +37 -8
- package/dist/mcp-client/oauth-client.d.ts +7 -0
- package/dist/mcp-client/oauth-client.js +12 -1
- package/dist/oauth-tokens/index.d.ts +1 -1
- package/dist/oauth-tokens/index.js +1 -1
- package/dist/oauth-tokens/lifecycle.d.ts +11 -0
- package/dist/oauth-tokens/lifecycle.js +17 -0
- package/dist/oauth-tokens/store.js +7 -0
- package/dist/observability/posthog-ai.d.ts +15 -1
- package/dist/observability/posthog-ai.js +24 -12
- package/dist/observability/traces.js +158 -28
- package/dist/onboarding/app-profile.js +2 -2
- package/dist/onboarding/plugin.js +10 -2
- package/dist/onboarding/types.d.ts +2 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +2 -2
- package/dist/provider-api/index.js +2 -0
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/resources/store.js +13 -4
- package/dist/scripts/agent-engines/list-agent-engines.js +29 -3
- package/dist/secrets/register-framework-secrets.js +1 -1
- package/dist/server/action-discovery.js +5 -0
- package/dist/server/agent-chat/action-filters-a2a.d.ts +27 -3
- package/dist/server/agent-chat/action-filters-a2a.js +48 -9
- package/dist/server/agent-chat-plugin.js +36 -9
- package/dist/server/agent-discovery.js +43 -20
- package/dist/server/auth.js +18 -16
- package/dist/server/beta-opt-out-html.js +45 -4
- package/dist/server/better-auth-instance.d.ts +2 -1
- package/dist/server/better-auth-instance.js +37 -7
- package/dist/server/builder-design-systems.d.ts +4 -1
- package/dist/server/builder-design-systems.js +87 -6
- package/dist/server/builder-oauth.d.ts +1 -7
- package/dist/server/builder-oauth.js +80 -163
- package/dist/server/core-routes-plugin.d.ts +29 -0
- package/dist/server/core-routes-plugin.js +100 -20
- package/dist/server/default-plugins.d.ts +18 -0
- package/dist/server/default-plugins.js +22 -0
- package/dist/server/edge.d.ts +1 -0
- package/dist/server/edge.js +1 -0
- package/dist/server/framework-request-handler.js +31 -3
- package/dist/server/google-oauth.d.ts +3 -0
- package/dist/server/google-oauth.js +3 -0
- package/dist/server/index.d.ts +4 -4
- package/dist/server/index.js +3 -3
- package/dist/server/onboarding-html.js +37 -3
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/workspace-provider-oauth.d.ts +6 -1
- package/dist/server/workspace-provider-oauth.js +72 -20
- package/dist/shared/agent-sidebar-url.d.ts +1 -0
- package/dist/shared/agent-sidebar-url.js +1 -0
- package/dist/shared/environment-lanes.d.ts +2 -0
- package/dist/shared/environment-lanes.js +3 -1
- package/dist/shared/index.d.ts +3 -1
- package/dist/shared/index.js +3 -1
- package/dist/shared/surface-visibility.d.ts +31 -0
- package/dist/shared/surface-visibility.js +57 -0
- package/dist/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/chat/app/routes.ts +3 -1
- package/dist/templates/chat/vitest.config.ts +8 -0
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/default/app/routes.ts +3 -1
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/tracking/registry.d.ts +11 -0
- package/dist/tracking/registry.js +5 -2
- package/dist/triggers/actions.js +10 -3
- package/dist/usage/store.js +23 -3
- package/dist/user-profile/actions/get-auth-methods.js +18 -5
- package/dist/vite/client.js +33 -7
- package/docs/content/actions-access-control.mdx +43 -4
- package/docs/content/actions-defining.mdx +16 -0
- package/docs/content/authentication.mdx +40 -21
- package/docs/content/environment-variables.mdx +1 -0
- package/docs/content/template-clips-capture-everywhere.mdx +29 -30
- package/docs/content/template-clips-developers.mdx +4 -4
- package/docs/content/template-clips.mdx +3 -1
- package/package.json +2 -2
- package/src/eject/workspace-connections.ts +4 -0
- package/src/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/chat/app/routes.ts +3 -1
- package/src/templates/chat/vitest.config.ts +8 -0
- package/src/templates/default/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/default/app/routes.ts +3 -1
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
|
@@ -311,9 +311,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
311
311
|
notes?: string | undefined;
|
|
312
312
|
scope?: "org" | "user" | undefined;
|
|
313
313
|
}, {
|
|
314
|
+
id?: undefined;
|
|
314
315
|
message?: undefined;
|
|
315
316
|
deleted?: undefined;
|
|
316
|
-
id?: undefined;
|
|
317
317
|
provider?: undefined;
|
|
318
318
|
providers: {
|
|
319
319
|
id: string;
|
|
@@ -329,10 +329,10 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
329
329
|
registered?: undefined;
|
|
330
330
|
label?: undefined;
|
|
331
331
|
} | {
|
|
332
|
+
id?: undefined;
|
|
332
333
|
message?: undefined;
|
|
333
334
|
deleted?: undefined;
|
|
334
335
|
count?: undefined;
|
|
335
|
-
id?: undefined;
|
|
336
336
|
providers?: undefined;
|
|
337
337
|
found: boolean;
|
|
338
338
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
@@ -436,6 +436,7 @@ const PROVIDER_CONFIGS = {
|
|
|
436
436
|
type: "oauth-bearer",
|
|
437
437
|
oauthProvider: "google",
|
|
438
438
|
tokenLabel: "Google OAuth token",
|
|
439
|
+
workspaceProvider: "gmail",
|
|
439
440
|
},
|
|
440
441
|
credentialKeys: ["GOOGLE_OAUTH_ACCOUNT"],
|
|
441
442
|
docsUrls: ["https://developers.google.com/gmail/api/reference/rest"],
|
|
@@ -587,6 +588,7 @@ const PROVIDER_CONFIGS = {
|
|
|
587
588
|
type: "oauth-bearer",
|
|
588
589
|
oauthProvider: "google",
|
|
589
590
|
tokenLabel: "Google OAuth token",
|
|
591
|
+
workspaceProvider: "google_calendar",
|
|
590
592
|
},
|
|
591
593
|
credentialKeys: ["GOOGLE_OAUTH_ACCOUNT"],
|
|
592
594
|
docsUrls: ["https://developers.google.com/calendar/api/v3/reference"],
|
|
@@ -51,8 +51,8 @@ export declare function handleDeleteResource(event: any): Promise<{
|
|
|
51
51
|
error: string;
|
|
52
52
|
ok?: undefined;
|
|
53
53
|
} | {
|
|
54
|
-
error?: undefined;
|
|
55
54
|
ok: boolean;
|
|
55
|
+
error?: undefined;
|
|
56
56
|
}>;
|
|
57
57
|
/** POST /_agent-native/resources/upload — upload a file as a resource */
|
|
58
58
|
export declare function handleUploadResource(event: any): Promise<import("./store.js").Resource | {
|
|
@@ -73,10 +73,10 @@ export declare function handleUploadResource(event: any): Promise<import("./stor
|
|
|
73
73
|
runId: string | null;
|
|
74
74
|
expiresAt: number | null;
|
|
75
75
|
metadata: string | null;
|
|
76
|
-
error?: undefined;
|
|
77
76
|
url: string;
|
|
78
77
|
provider: string;
|
|
79
78
|
storageSetupRequired?: undefined;
|
|
79
|
+
error?: undefined;
|
|
80
80
|
} | {
|
|
81
81
|
error: string;
|
|
82
82
|
storageSetupRequired: boolean;
|
package/dist/resources/store.js
CHANGED
|
@@ -359,15 +359,19 @@ function physicalWorkspaceResourceId(id) {
|
|
|
359
359
|
: null;
|
|
360
360
|
}
|
|
361
361
|
function rowToGrantedWorkspaceResource(row) {
|
|
362
|
+
const contentLoaded = Object.prototype.hasOwnProperty.call(row, "content");
|
|
362
363
|
const content = String(row.content ?? "");
|
|
363
364
|
const path = String(row.path ?? "");
|
|
365
|
+
const size = contentLoaded
|
|
366
|
+
? Buffer.byteLength(content, "utf8")
|
|
367
|
+
: Number(row.content_size ?? 0);
|
|
364
368
|
return {
|
|
365
369
|
id: syntheticWorkspaceResourceId(String(row.id)),
|
|
366
370
|
path,
|
|
367
371
|
owner: WORKSPACE_OWNER,
|
|
368
372
|
content,
|
|
369
373
|
mimeType: workspaceResourceMimeType(path),
|
|
370
|
-
size:
|
|
374
|
+
size: Number.isFinite(size) ? size : 0,
|
|
371
375
|
createdAt: Number(row.created_at ?? Date.now()),
|
|
372
376
|
updatedAt: Number(row.updated_at ?? Date.now()),
|
|
373
377
|
createdBy: "system",
|
|
@@ -480,7 +484,7 @@ function mergeResourceMetas(primary, inherited) {
|
|
|
480
484
|
}
|
|
481
485
|
return merged;
|
|
482
486
|
}
|
|
483
|
-
async function selectGrantedWorkspaceResourceRows(input) {
|
|
487
|
+
async function selectGrantedWorkspaceResourceRows(input, options = {}) {
|
|
484
488
|
const appId = currentWorkspaceAppId(input.workspaceAppId);
|
|
485
489
|
const { userEmail, orgId } = requestScopedResourceIdentity(input);
|
|
486
490
|
if (!appId || (!userEmail && !orgId))
|
|
@@ -507,6 +511,9 @@ async function selectGrantedWorkspaceResourceRows(input) {
|
|
|
507
511
|
conditions.push("wr.owner_email = ?", "wr.org_id IS NULL", "wg.owner_email = ?", "wg.org_id IS NULL");
|
|
508
512
|
args.push(userEmail, userEmail);
|
|
509
513
|
}
|
|
514
|
+
const contentSelect = options.includeContent === false
|
|
515
|
+
? `${isPostgres() ? "octet_length(wr.content)" : "length(CAST(wr.content AS BLOB))"} AS content_size`
|
|
516
|
+
: "wr.content";
|
|
510
517
|
const client = getDbExec();
|
|
511
518
|
const { rows } = await client.execute({
|
|
512
519
|
sql: `
|
|
@@ -516,7 +523,7 @@ async function selectGrantedWorkspaceResourceRows(input) {
|
|
|
516
523
|
wr.name,
|
|
517
524
|
wr.description,
|
|
518
525
|
wr.path,
|
|
519
|
-
|
|
526
|
+
${contentSelect},
|
|
520
527
|
wr.created_at,
|
|
521
528
|
wr.updated_at,
|
|
522
529
|
wg.id AS grant_id,
|
|
@@ -532,7 +539,9 @@ async function selectGrantedWorkspaceResourceRows(input) {
|
|
|
532
539
|
}
|
|
533
540
|
async function grantedWorkspaceResources(input) {
|
|
534
541
|
try {
|
|
535
|
-
const rows = await selectGrantedWorkspaceResourceRows(input
|
|
542
|
+
const rows = await selectGrantedWorkspaceResourceRows(input, {
|
|
543
|
+
includeContent: false,
|
|
544
|
+
});
|
|
536
545
|
return rows.map(rowToGrantedWorkspaceResource);
|
|
537
546
|
}
|
|
538
547
|
catch {
|
|
@@ -70,8 +70,29 @@ export async function run(args = {}) {
|
|
|
70
70
|
const currentModel = currentEntry && !envUnavailable
|
|
71
71
|
? normalizeModelForEngine(currentEntry, currentModelCandidate ?? currentEntry.defaultModel, { preserveCustomModels })
|
|
72
72
|
: (currentModelCandidate ?? DEFAULT_MODEL);
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
// Readiness has to be resolved here: `requiredEnvVars` alone cannot see
|
|
74
|
+
// vault-stored keys or the deploy-injected Builder gateway lane, so a client
|
|
75
|
+
// that re-derives it from env keys marks working engines unconfigured.
|
|
76
|
+
const engineEntries = await Promise.all(engines.map(async (e) => {
|
|
77
|
+
// Resolved per engine, not across the set: one provider whose credential
|
|
78
|
+
// store is momentarily unreadable must not reject the whole listing. The
|
|
79
|
+
// chat refresh catches that rejection and renders an empty catalog, so a
|
|
80
|
+
// single unrelated provider would make every engine unselectable — the
|
|
81
|
+
// exact symptom this readiness plumbing exists to fix.
|
|
82
|
+
//
|
|
83
|
+
// A read error is its own state, left as `configured: undefined` so the
|
|
84
|
+
// client falls back to its env heuristic. Folding it into `false` would
|
|
85
|
+
// claim the engine needs an API key when nobody actually knows.
|
|
86
|
+
let configured;
|
|
87
|
+
let configuredError;
|
|
88
|
+
try {
|
|
89
|
+
configured = await isStoredEngineUsableForRequest({ engine: e.name, model: e.defaultModel }, e);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
configuredError =
|
|
93
|
+
error instanceof Error ? error.message : String(error);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
75
96
|
name: e.name,
|
|
76
97
|
label: e.label,
|
|
77
98
|
description: e.description,
|
|
@@ -81,7 +102,12 @@ export async function run(args = {}) {
|
|
|
81
102
|
requiredEnvVars: e.requiredEnvVars,
|
|
82
103
|
installPackage: e.installPackage,
|
|
83
104
|
packageInstalled: isAgentEnginePackageInstalled(e),
|
|
84
|
-
|
|
105
|
+
configured,
|
|
106
|
+
configuredError,
|
|
107
|
+
};
|
|
108
|
+
}));
|
|
109
|
+
const result = {
|
|
110
|
+
engines: engineEntries,
|
|
85
111
|
current: envUnavailable
|
|
86
112
|
? null
|
|
87
113
|
: {
|
|
@@ -27,7 +27,7 @@ export function registerFrameworkSecrets() {
|
|
|
27
27
|
id: "google_drive",
|
|
28
28
|
credentialPrefix: "GOOGLE",
|
|
29
29
|
oauthProvider: "google",
|
|
30
|
-
label: "Google
|
|
30
|
+
label: "Google Workspace",
|
|
31
31
|
docsUrl: "https://developers.google.com/identity/protocols/oauth2/web-server",
|
|
32
32
|
},
|
|
33
33
|
{
|
|
@@ -163,6 +163,11 @@ function preserveActionFlags(entry) {
|
|
|
163
163
|
const out = {};
|
|
164
164
|
if (typeof entry.agentTool === "boolean")
|
|
165
165
|
out.agentTool = entry.agentTool;
|
|
166
|
+
if (typeof entry.mcpTool === "boolean")
|
|
167
|
+
out.mcpTool = entry.mcpTool;
|
|
168
|
+
if (typeof entry.deferLoading === "boolean") {
|
|
169
|
+
out.deferLoading = entry.deferLoading;
|
|
170
|
+
}
|
|
166
171
|
if (typeof entry.requiresAuth === "boolean") {
|
|
167
172
|
out.requiresAuth = entry.requiresAuth;
|
|
168
173
|
}
|
|
@@ -13,6 +13,18 @@ export declare function filterReadOnlyActions(actions: Record<string, ActionEntr
|
|
|
13
13
|
* list (in-app assistant, MCP, A2A, job/trigger runners) or actions prompt.
|
|
14
14
|
* Default-allow: only an explicit `false` is excluded. */
|
|
15
15
|
export declare function filterAgentTools(actions: Record<string, ActionEntry>): Record<string, ActionEntry>;
|
|
16
|
+
/**
|
|
17
|
+
* The MCP-only actions: `agentTool: false` paired with an explicit
|
|
18
|
+
* `mcpTool: true`.
|
|
19
|
+
*
|
|
20
|
+
* `filterAgentTools` drops these, which is right for every in-app surface and
|
|
21
|
+
* wrong for the two external ones. Rather than have the MCP and A2A mounts
|
|
22
|
+
* read the unfiltered registry — and re-derive which agent-hidden actions are
|
|
23
|
+
* safe to serve — the plugin re-merges exactly this set into those two mounts.
|
|
24
|
+
* A caller that wants "everything external" merges this with the agent surface;
|
|
25
|
+
* nobody has to remember which raw fields make an action MCP-only.
|
|
26
|
+
*/
|
|
27
|
+
export declare function filterMcpOnlyActions(actions: Record<string, ActionEntry>): Record<string, ActionEntry>;
|
|
16
28
|
export declare function filterPublicAgentActions(actions: Record<string, ActionEntry>): Record<string, ActionEntry>;
|
|
17
29
|
/**
|
|
18
30
|
* True when an action takes a free-form query or program as input — raw SQL, a
|
|
@@ -137,15 +149,27 @@ export declare function createA2AEngineToolSurface(availableTools: EngineTool[],
|
|
|
137
149
|
export declare function isSelectedA2AReceiver(selectedReceiverApp: string | undefined, appId: string | undefined): boolean;
|
|
138
150
|
export declare function buildSelectedA2AReceiverContext(appId: string): string;
|
|
139
151
|
/**
|
|
140
|
-
* The first-request tool catalog
|
|
141
|
-
*
|
|
152
|
+
* The first-request tool catalog, in precedence order:
|
|
153
|
+
*
|
|
154
|
+
* 1. An explicit `initialToolNames`, plus every action that declares
|
|
155
|
+
* `deferLoading: false`. The configured list stays authoritative — an
|
|
156
|
+
* action it names is never dropped by a `deferLoading: true` — so a
|
|
157
|
+
* template can annotate its actions before deleting the array, not after.
|
|
158
|
+
* 2. Otherwise, the actions that declared `deferLoading: false`, if any did.
|
|
159
|
+
* 3. Otherwise, the app's OWN actions, minus any marked `deferLoading: true`.
|
|
160
|
+
*
|
|
161
|
+
* Step 2 is what makes `deferLoading` a replacement for the array rather than
|
|
162
|
+
* a second copy of it: opting a few starter actions out of deferral on an app
|
|
163
|
+
* with no configured list defers everything else, instead of leaving the whole
|
|
164
|
+
* registry in and the annotation decorative.
|
|
142
165
|
*
|
|
143
166
|
* "Its own actions" excludes the framework kits. They arrive in this same
|
|
144
167
|
* registry through `autoDiscoverActions` -> `mergeCoreSharingActions`, so the
|
|
145
168
|
* plain `Object.keys` default promoted ~45 sharing/review/history/flag schemas
|
|
146
169
|
* into every app's first request whether or not the app had those surfaces. They
|
|
147
170
|
* remain in `availableTools` and are still found by `tool-search`; an app that
|
|
148
|
-
* wants one on turn one names it in
|
|
171
|
+
* wants one on turn one sets `deferLoading: false` or names it in
|
|
172
|
+
* `initialToolNames`.
|
|
149
173
|
*/
|
|
150
174
|
export declare function resolveInitialToolNames(templateActions: Record<string, ActionEntry>, configured?: string[]): string[];
|
|
151
175
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getHeader } from "h3";
|
|
2
2
|
import { appendA2AArtifactLinks, extractA2APersistedMutationReceipts, } from "../../a2a/artifact-response.js";
|
|
3
3
|
import { collectFinalResponseTextFromAgentEvents } from "../../a2a/response-text.js";
|
|
4
|
+
import { isActionExposedToExternalAgents } from "../../action.js";
|
|
4
5
|
import { resolveMainChatMaxOutputTokens } from "../../agent/engine/output-tokens.js";
|
|
5
6
|
import { filterInitialEngineTools, resolveAgentRequestReasoningEffort, } from "../../agent/production-agent.js";
|
|
6
7
|
import { runAgentLoopDirectWithSoftTimeout } from "../../agent/run-loop-with-resume.js";
|
|
@@ -25,6 +26,20 @@ export function filterReadOnlyActions(actions) {
|
|
|
25
26
|
export function filterAgentTools(actions) {
|
|
26
27
|
return Object.fromEntries(Object.entries(actions).filter(([, entry]) => entry.agentTool !== false));
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* The MCP-only actions: `agentTool: false` paired with an explicit
|
|
31
|
+
* `mcpTool: true`.
|
|
32
|
+
*
|
|
33
|
+
* `filterAgentTools` drops these, which is right for every in-app surface and
|
|
34
|
+
* wrong for the two external ones. Rather than have the MCP and A2A mounts
|
|
35
|
+
* read the unfiltered registry — and re-derive which agent-hidden actions are
|
|
36
|
+
* safe to serve — the plugin re-merges exactly this set into those two mounts.
|
|
37
|
+
* A caller that wants "everything external" merges this with the agent surface;
|
|
38
|
+
* nobody has to remember which raw fields make an action MCP-only.
|
|
39
|
+
*/
|
|
40
|
+
export function filterMcpOnlyActions(actions) {
|
|
41
|
+
return Object.fromEntries(Object.entries(actions).filter(([, entry]) => entry.agentTool === false && entry.mcpTool === true));
|
|
42
|
+
}
|
|
28
43
|
export function filterPublicAgentActions(actions) {
|
|
29
44
|
return Object.fromEntries(Object.entries(actions).filter(([, entry]) => {
|
|
30
45
|
const config = entry.publicAgent;
|
|
@@ -80,7 +95,10 @@ export function filterDirectA2AActions(actions, options) {
|
|
|
80
95
|
const autoReads = options.externalAgents?.authenticatedReads === "auto";
|
|
81
96
|
return Object.fromEntries(Object.entries(actions).filter(([name, entry]) => {
|
|
82
97
|
const exposure = entry.publicAgent;
|
|
83
|
-
|
|
98
|
+
// `mcpTool: true` is catalog membership declared beside the action; the
|
|
99
|
+
// exposure resolver below is the veto no config list can re-open.
|
|
100
|
+
const selected = entry.mcpTool === true ||
|
|
101
|
+
catalog.has(name) ||
|
|
84
102
|
(autoReads &&
|
|
85
103
|
isAuthenticatedReadAction(entry) &&
|
|
86
104
|
!isAutoReadExcludedActionName(name));
|
|
@@ -88,7 +106,7 @@ export function filterDirectA2AActions(actions, options) {
|
|
|
88
106
|
return (selected &&
|
|
89
107
|
rawQueryAllowed &&
|
|
90
108
|
!denied.has(name) &&
|
|
91
|
-
entry
|
|
109
|
+
isActionExposedToExternalAgents(entry) &&
|
|
92
110
|
entry.readOnly === true &&
|
|
93
111
|
exposure?.expose === true &&
|
|
94
112
|
exposure.readOnly === true &&
|
|
@@ -108,7 +126,7 @@ export function filterDelegatedA2ACapabilityActions(actions, options) {
|
|
|
108
126
|
return Object.fromEntries(Object.entries(actions).filter(([name, entry]) => {
|
|
109
127
|
const exposure = entry.publicAgent;
|
|
110
128
|
return (!denied.has(name) &&
|
|
111
|
-
entry
|
|
129
|
+
isActionExposedToExternalAgents(entry) &&
|
|
112
130
|
entry.readOnly !== true &&
|
|
113
131
|
exposure?.expose === true &&
|
|
114
132
|
exposure.readOnly === false &&
|
|
@@ -463,20 +481,41 @@ The caller already selected this app to own the current objective. Start with th
|
|
|
463
481
|
</selected-a2a-receiver>`;
|
|
464
482
|
}
|
|
465
483
|
/**
|
|
466
|
-
* The first-request tool catalog
|
|
467
|
-
*
|
|
484
|
+
* The first-request tool catalog, in precedence order:
|
|
485
|
+
*
|
|
486
|
+
* 1. An explicit `initialToolNames`, plus every action that declares
|
|
487
|
+
* `deferLoading: false`. The configured list stays authoritative — an
|
|
488
|
+
* action it names is never dropped by a `deferLoading: true` — so a
|
|
489
|
+
* template can annotate its actions before deleting the array, not after.
|
|
490
|
+
* 2. Otherwise, the actions that declared `deferLoading: false`, if any did.
|
|
491
|
+
* 3. Otherwise, the app's OWN actions, minus any marked `deferLoading: true`.
|
|
492
|
+
*
|
|
493
|
+
* Step 2 is what makes `deferLoading` a replacement for the array rather than
|
|
494
|
+
* a second copy of it: opting a few starter actions out of deferral on an app
|
|
495
|
+
* with no configured list defers everything else, instead of leaving the whole
|
|
496
|
+
* registry in and the annotation decorative.
|
|
468
497
|
*
|
|
469
498
|
* "Its own actions" excludes the framework kits. They arrive in this same
|
|
470
499
|
* registry through `autoDiscoverActions` -> `mergeCoreSharingActions`, so the
|
|
471
500
|
* plain `Object.keys` default promoted ~45 sharing/review/history/flag schemas
|
|
472
501
|
* into every app's first request whether or not the app had those surfaces. They
|
|
473
502
|
* remain in `availableTools` and are still found by `tool-search`; an app that
|
|
474
|
-
* wants one on turn one names it in
|
|
503
|
+
* wants one on turn one sets `deferLoading: false` or names it in
|
|
504
|
+
* `initialToolNames`.
|
|
475
505
|
*/
|
|
476
506
|
export function resolveInitialToolNames(templateActions, configured) {
|
|
507
|
+
const entries = Object.entries(templateActions);
|
|
508
|
+
// A framework-grouped action stays out of the DERIVED set, but an explicit
|
|
509
|
+
// `deferLoading: false` on one is a declaration, not a leak: it is the same
|
|
510
|
+
// opt-in `initialToolNames` already gave apps for these names.
|
|
511
|
+
const eager = entries
|
|
512
|
+
.filter(([, entry]) => entry.deferLoading === false)
|
|
513
|
+
.map(([name]) => name);
|
|
477
514
|
if (configured)
|
|
478
|
-
return configured;
|
|
479
|
-
|
|
480
|
-
|
|
515
|
+
return [...new Set([...configured, ...eager])];
|
|
516
|
+
if (eager.length > 0)
|
|
517
|
+
return eager;
|
|
518
|
+
return entries
|
|
519
|
+
.filter(([name, entry]) => !isFrameworkGroupedAction(name, entry) && entry.deferLoading !== true)
|
|
481
520
|
.map(([name]) => name);
|
|
482
521
|
}
|
|
@@ -6,6 +6,7 @@ import { appendA2AArtifactLinks, buildA2ARecoverableArtifactMessage, } from "../
|
|
|
6
6
|
import { hasConfiguredA2ASecret, isLoopbackAddress, isTrustedLocalRuntime, } from "../a2a/auth-policy.js";
|
|
7
7
|
import { sanitizeA2ACorrelationId, sanitizeA2ACorrelationMetadata, } from "../a2a/correlation.js";
|
|
8
8
|
import { createA2AApproval, updateTaskStatusMessage, } from "../a2a/task-store.js";
|
|
9
|
+
import { clientAbortReason } from "../agent/abort-reasons.js";
|
|
9
10
|
import { canUpdateAgentAppModelDefaultSettings, normalizeAgentAppModelDefaultAppId, readAgentAppModelDefaultSettings, resetAgentAppModelDefaultSettings, writeAgentAppModelDefaultSettings, } from "../agent/app-model-defaults.js";
|
|
10
11
|
import { DEFAULT_ANTHROPIC_MODEL } from "../agent/default-model.js";
|
|
11
12
|
import { AGENT_CHAT_BACKGROUND_RUN_FIELD, AGENT_CHAT_PROCESS_RUN_PATH, backgroundRunMarkerExpectsBackgroundRuntime, isInBackgroundFunctionRuntime, prepareProcessRunRequest, } from "../agent/durable-background.js";
|
|
@@ -14,7 +15,6 @@ import { SYSTEM_PROMPT_CACHE_SPLIT } from "../agent/engine/prompt-cache.js";
|
|
|
14
15
|
import { PROVIDER_TO_ENV } from "../agent/engine/provider-env-vars.js";
|
|
15
16
|
import { hostedHarnessSystemPrompt } from "../agent/harness/hosted.js";
|
|
16
17
|
import { createProductionAgentHandler, actionsToEngineTools, executeAgentToolCall, filterActionsByAllowedNames, normalizeAgentActionSurfaceResolution, readPersistedActionSurface, toolCallCacheKey, getActiveRunForThreadAsync, abortRunDurably, abortTurnDurably, subscribeToRun, } from "../agent/production-agent.js";
|
|
17
|
-
import { clientAbortReason } from "../agent/run-loop-with-resume.js";
|
|
18
18
|
import { callerHasRunAccess, callerHasThreadAccess, } from "../agent/run-ownership.js";
|
|
19
19
|
import { markTurnAborted, readBackgroundRunClaim } from "../agent/run-store.js";
|
|
20
20
|
import { buildCurrentTimeUserContext, buildRuntimeContextPrompt, } from "../agent/runtime-context.js";
|
|
@@ -33,6 +33,7 @@ import { filterFrameworkToolGroups, resolveFrameworkTools, } from "../framework-
|
|
|
33
33
|
import { verifyInternalToken, extractBearerToken, } from "../integrations/internal-token.js";
|
|
34
34
|
import { RECURRING_JOBS_SWEEP_PATH, RECURRING_JOBS_SWEEP_TOKEN_SUBJECT, } from "../jobs/scheduler-dispatch.js";
|
|
35
35
|
import { McpClientManager, mcpToolsToActionEntries, syncMcpActionEntries, mountMcpServersRoutes, mountMcpHubRoutes, buildMergedConfig, startMcpConfigRefresh, getHubStatus, isHubServeEnabled, } from "../mcp-client/index.js";
|
|
36
|
+
import { declaredMcpToolNames } from "../mcp/build-server.js";
|
|
36
37
|
import { setProgressPreListHook } from "../progress/store.js";
|
|
37
38
|
import { getSkillNameFromPath } from "../resources/metadata.js";
|
|
38
39
|
import { resourceList, resourceListAccessible, resourceGet, ensurePersonalDefaults, SHARED_OWNER, WORKSPACE_OWNER, } from "../resources/store.js";
|
|
@@ -113,7 +114,7 @@ import { buildSystemManifestSections, setContextXraySystemSections, } from "../a
|
|
|
113
114
|
// the ones that were already part of the public surface) so
|
|
114
115
|
// `createAgentChatPlugin` below stays a thinner orchestrator.
|
|
115
116
|
// ---------------------------------------------------------------------------
|
|
116
|
-
import { buildSelectedA2AReceiverContext, createA2AEngineToolSurface, DEFAULT_DELEGATED_MAX_ITERATIONS, DEFAULT_DELEGATED_MAX_RUN_INPUT_TOKENS, DEFAULT_DELEGATED_MAX_TOOL_RESULT_CHARS, filterAgentTools, filterPublicAgentActions, filterDirectA2AActions, filterReadOnlyActions, isSelectedA2AReceiver, resolveInitialToolNames, runA2AAgentLoop, runMCPAgentLoop, assembleA2AFinalResponse, buildPublicAgentA2ASkills, buildAuthenticatedAgentA2ASkills, resolveArtifactBaseUrl, } from "./agent-chat/action-filters-a2a.js";
|
|
117
|
+
import { buildSelectedA2AReceiverContext, createA2AEngineToolSurface, DEFAULT_DELEGATED_MAX_ITERATIONS, DEFAULT_DELEGATED_MAX_RUN_INPUT_TOKENS, DEFAULT_DELEGATED_MAX_TOOL_RESULT_CHARS, filterAgentTools, filterMcpOnlyActions, filterPublicAgentActions, filterDirectA2AActions, filterReadOnlyActions, isSelectedA2AReceiver, resolveInitialToolNames, runA2AAgentLoop, runMCPAgentLoop, assembleA2AFinalResponse, buildPublicAgentA2ASkills, buildAuthenticatedAgentA2ASkills, resolveArtifactBaseUrl, } from "./agent-chat/action-filters-a2a.js";
|
|
117
118
|
import { createBuilderBrowserTool, createTeamTools, } from "./agent-chat/browser-team-tools.js";
|
|
118
119
|
import { createDataWidgetActionEntries, createFrameworkContextEntry, createRefreshScreenEntry, createUrlTools, } from "./agent-chat/context-tools.js";
|
|
119
120
|
import { _agentChatPromptSectionsForTests, buildFrameworkPrompts, buildSchemaBlock, collectFiles, corpusToolNamesTaughtByPrompt, generateActionsPrompt, generateCorpusToolsPrompt, } from "./agent-chat/framework-prompts.js";
|
|
@@ -708,6 +709,17 @@ export function createAgentChatPlugin(options) {
|
|
|
708
709
|
// whatever `generateCorpusToolsPrompt` teaches by name for this request.
|
|
709
710
|
const templateInitialToolNames = resolveInitialToolNames(templateScripts, options?.initialToolNames);
|
|
710
711
|
const discoveredActions = filterFrameworkToolGroups(filterAgentTools(discoveredActionsAll), disabledFrameworkGroups);
|
|
712
|
+
// MCP-only actions: `agentTool: false` with an explicit `mcpTool: true`.
|
|
713
|
+
// `filterAgentTools` above just dropped them — correctly, since the app's
|
|
714
|
+
// own agent must not see them — so the external surfaces below re-merge
|
|
715
|
+
// this set instead of reading the unfiltered registries. Keep it OUT of
|
|
716
|
+
// `allScripts`, the chat/A2A/ask_app loops, and every prompt: an
|
|
717
|
+
// `ask_app` run is the app's own agent, which `agentTool: false` already
|
|
718
|
+
// answered. Only the direct MCP and A2A tool surfaces get these.
|
|
719
|
+
const mcpOnlyActions = filterFrameworkToolGroups(filterMcpOnlyActions({
|
|
720
|
+
...discoveredActionsAll,
|
|
721
|
+
...templateScriptsAll,
|
|
722
|
+
}), disabledFrameworkGroups);
|
|
711
723
|
// Per-request owner is read from the AsyncLocalStorage run context
|
|
712
724
|
// (populated by prepareRun). Module-scope `let` would race across
|
|
713
725
|
// concurrent requests on a long-lived Node process — overlapping
|
|
@@ -1146,6 +1158,14 @@ export function createAgentChatPlugin(options) {
|
|
|
1146
1158
|
...devRunCodeTool,
|
|
1147
1159
|
})
|
|
1148
1160
|
: undefined;
|
|
1161
|
+
// The surface external agents get: everything the app's agent has, plus
|
|
1162
|
+
// the MCP-only actions the agent filter removed. The agent sets win on a
|
|
1163
|
+
// name collision, which by construction cannot happen — an action is in
|
|
1164
|
+
// one set or the other, never both.
|
|
1165
|
+
const externalActions = { ...mcpOnlyActions, ...allScripts };
|
|
1166
|
+
const externalFullActions = mcpFullActions
|
|
1167
|
+
? { ...mcpOnlyActions, ...mcpFullActions }
|
|
1168
|
+
: undefined;
|
|
1149
1169
|
const { mountA2A } = await import("../a2a/server.js");
|
|
1150
1170
|
mountA2A(nitroApp, {
|
|
1151
1171
|
appId: options?.appId,
|
|
@@ -1153,13 +1173,13 @@ export function createAgentChatPlugin(options) {
|
|
|
1153
1173
|
? options.appId.charAt(0).toUpperCase() + options.appId.slice(1)
|
|
1154
1174
|
: "Agent",
|
|
1155
1175
|
description: `Agent-native ${options?.appId ?? "app"} agent`,
|
|
1156
|
-
skills: buildPublicAgentA2ASkills(
|
|
1157
|
-
authenticatedSkills: buildAuthenticatedAgentA2ASkills(
|
|
1176
|
+
skills: buildPublicAgentA2ASkills(externalActions),
|
|
1177
|
+
authenticatedSkills: buildAuthenticatedAgentA2ASkills(externalFullActions ?? externalActions, mcpOptions),
|
|
1158
1178
|
publicSkillsOnly: true,
|
|
1159
1179
|
streaming: true,
|
|
1160
1180
|
durableBackgroundRuns: options?.durableBackgroundRuns,
|
|
1161
1181
|
executeReadOnlyAction: async ({ action, input, invocationId }) => {
|
|
1162
|
-
const actions = filterDirectA2AActions(
|
|
1182
|
+
const actions = filterDirectA2AActions(externalFullActions ?? externalActions, mcpOptions);
|
|
1163
1183
|
const entry = actions[action];
|
|
1164
1184
|
if (!entry) {
|
|
1165
1185
|
return {
|
|
@@ -1188,7 +1208,7 @@ export function createAgentChatPlugin(options) {
|
|
|
1188
1208
|
},
|
|
1189
1209
|
executeApproval: async (approval) => {
|
|
1190
1210
|
const result = await executeAgentToolCall({
|
|
1191
|
-
actions:
|
|
1211
|
+
actions: externalFullActions ?? externalActions,
|
|
1192
1212
|
name: approval.tool,
|
|
1193
1213
|
input: approval.input,
|
|
1194
1214
|
callId: approval.callId,
|
|
@@ -1523,7 +1543,14 @@ export function createAgentChatPlugin(options) {
|
|
|
1523
1543
|
});
|
|
1524
1544
|
const a2aToolSurface = createA2AEngineToolSurface(actionsToEngineTools(a2aActions), effectiveInitialToolNames, {
|
|
1525
1545
|
receiverOwnsObjective,
|
|
1526
|
-
|
|
1546
|
+
// Same curated set the MCP mount serves: config names plus the
|
|
1547
|
+
// actions that declare `mcpTool: true` themselves.
|
|
1548
|
+
localCapabilityNames: [
|
|
1549
|
+
...new Set([
|
|
1550
|
+
...(mcpOptions.connectorCatalog ?? []),
|
|
1551
|
+
...declaredMcpToolNames(a2aActions),
|
|
1552
|
+
]),
|
|
1553
|
+
],
|
|
1527
1554
|
});
|
|
1528
1555
|
// Precise current time rides the user message (not the cached
|
|
1529
1556
|
// system-prompt prefix) — same pattern as the interactive handler.
|
|
@@ -1848,8 +1875,8 @@ export function createAgentChatPlugin(options) {
|
|
|
1848
1875
|
`Agent-native ${options?.appId ?? "app"} agent`,
|
|
1849
1876
|
websiteUrl: mcpOptions.websiteUrl,
|
|
1850
1877
|
icons: mcpOptions.icons,
|
|
1851
|
-
actions:
|
|
1852
|
-
productionActions:
|
|
1878
|
+
actions: externalActions,
|
|
1879
|
+
productionActions: externalFullActions,
|
|
1853
1880
|
...(mcpOptions.catalog ? { catalogMode: mcpOptions.catalog } : {}),
|
|
1854
1881
|
...(mcpOptions.builtinCrossAppTools !== undefined
|
|
1855
1882
|
? { builtinCrossAppTools: mcpOptions.builtinCrossAppTools }
|
|
@@ -40,6 +40,8 @@ export function normalizeAgentId(id) {
|
|
|
40
40
|
normalized === "asset") {
|
|
41
41
|
return "assets";
|
|
42
42
|
}
|
|
43
|
+
if (normalized === "videos")
|
|
44
|
+
return "clips";
|
|
43
45
|
return normalized;
|
|
44
46
|
}
|
|
45
47
|
const WORKSPACE_APPS_ENV_KEY = "AGENT_NATIVE_WORKSPACE_APPS_JSON";
|
|
@@ -67,8 +69,11 @@ export function parseWorkspaceAppMetadataSettings(raw) {
|
|
|
67
69
|
? record.apps
|
|
68
70
|
: {};
|
|
69
71
|
const apps = {};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
const canonicalIds = new Set();
|
|
73
|
+
for (const [rawId, value] of Object.entries(rawApps)) {
|
|
74
|
+
const id = rawId.trim();
|
|
75
|
+
const normalizedId = id ? normalizeAgentId(id) : "";
|
|
76
|
+
if (!normalizedId || !value || typeof value !== "object")
|
|
72
77
|
continue;
|
|
73
78
|
const item = value;
|
|
74
79
|
const override = {};
|
|
@@ -89,8 +94,14 @@ export function parseWorkspaceAppMetadataSettings(raw) {
|
|
|
89
94
|
override.updatedAt = updatedAt;
|
|
90
95
|
if (updatedBy)
|
|
91
96
|
override.updatedBy = updatedBy;
|
|
92
|
-
if (Object.keys(override).length > 0)
|
|
93
|
-
|
|
97
|
+
if (Object.keys(override).length > 0) {
|
|
98
|
+
const isCanonical = id.toLowerCase() === normalizedId;
|
|
99
|
+
if (isCanonical || !canonicalIds.has(normalizedId)) {
|
|
100
|
+
apps[normalizedId] = override;
|
|
101
|
+
}
|
|
102
|
+
if (isCanonical)
|
|
103
|
+
canonicalIds.add(normalizedId);
|
|
104
|
+
}
|
|
94
105
|
}
|
|
95
106
|
return { apps };
|
|
96
107
|
}
|
|
@@ -110,7 +121,7 @@ export async function writeWorkspaceAppMetadataOverride(input) {
|
|
|
110
121
|
const key = workspaceAppMetadataSettingsKey();
|
|
111
122
|
if (!key)
|
|
112
123
|
throw new Error("no authenticated user");
|
|
113
|
-
const appId = input.appId
|
|
124
|
+
const appId = normalizeAgentId(input.appId);
|
|
114
125
|
if (!appId)
|
|
115
126
|
throw new Error("appId is required");
|
|
116
127
|
const { getSetting, putSetting } = await import("../settings/index.js");
|
|
@@ -145,7 +156,7 @@ export async function writeWorkspaceAppMetadataOverride(input) {
|
|
|
145
156
|
return current;
|
|
146
157
|
}
|
|
147
158
|
export function applyWorkspaceAppMetadataOverride(app, settings) {
|
|
148
|
-
const override = settings.apps[app.id];
|
|
159
|
+
const override = settings.apps[normalizeAgentId(app.id)] ?? settings.apps[app.id];
|
|
149
160
|
if (!override)
|
|
150
161
|
return app;
|
|
151
162
|
const name = cleanOptionalText(override.name);
|
|
@@ -244,21 +255,20 @@ export async function discoverAgents(selfAppId, options) {
|
|
|
244
255
|
continue;
|
|
245
256
|
const manifestId = normalizeAgentId(manifest.id);
|
|
246
257
|
// If the resource override carries a localhost URL but we're running
|
|
247
|
-
// in
|
|
258
|
+
// in a hosted runtime (e.g. a stale dev-time seed got promoted to the prod
|
|
248
259
|
// DB), fall back to the matching built-in's prod URL instead of
|
|
249
260
|
// letting the override win — otherwise outbound `call-agent` fetches
|
|
250
261
|
// from a serverless function would target localhost and fail with
|
|
251
262
|
// "fetch failed" instantly. The override still wins for non-localhost
|
|
252
263
|
// URLs (the supported case for self-hosted custom agents).
|
|
253
264
|
let url = manifest.url;
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
if (isProduction &&
|
|
257
|
-
typeof url === "string" &&
|
|
258
|
-
/^https?:\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0)(:|\/|$)/.test(url)) {
|
|
265
|
+
const isHosted = isHostedRuntime();
|
|
266
|
+
if (isHosted && typeof url === "string" && isLoopbackUrl(url)) {
|
|
259
267
|
const builtin = agentsById.get(manifestId);
|
|
260
268
|
if (builtin?.url)
|
|
261
269
|
url = builtin.url;
|
|
270
|
+
else
|
|
271
|
+
continue;
|
|
262
272
|
}
|
|
263
273
|
const builtin = agentsById.get(manifestId);
|
|
264
274
|
if (options?.preferLocalUrls && builtin) {
|
|
@@ -327,10 +337,19 @@ function hostnameFromUrlLike(value) {
|
|
|
327
337
|
}
|
|
328
338
|
function isLoopbackUrl(value) {
|
|
329
339
|
const hostname = hostnameFromUrlLike(value);
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
340
|
+
if (!hostname)
|
|
341
|
+
return false;
|
|
342
|
+
const normalized = hostname.replace(/^\[|\]$/g, "");
|
|
343
|
+
if (normalized === "localhost" ||
|
|
344
|
+
normalized.startsWith("127.") ||
|
|
345
|
+
normalized === "0.0.0.0" ||
|
|
346
|
+
normalized === "::1") {
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
const mapped = normalized.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);
|
|
350
|
+
if (!mapped)
|
|
351
|
+
return false;
|
|
352
|
+
return Number.parseInt(mapped[1], 16) >>> 8 === 0x7f;
|
|
334
353
|
}
|
|
335
354
|
function hasPublicRuntimeUrl() {
|
|
336
355
|
// Intentionally omit generic `URL` / `DEPLOY_URL` here. Platforms that set
|
|
@@ -353,6 +372,8 @@ function hasPublicRuntimeUrl() {
|
|
|
353
372
|
});
|
|
354
373
|
}
|
|
355
374
|
function isHostedRuntime() {
|
|
375
|
+
if (process.env.NETLIFY_LOCAL === "true")
|
|
376
|
+
return false;
|
|
356
377
|
return (process.env.NODE_ENV === "production" ||
|
|
357
378
|
!!process.env.NETLIFY ||
|
|
358
379
|
!!process.env.AWS_LAMBDA_FUNCTION_NAME ||
|
|
@@ -412,7 +433,8 @@ function parseWorkspaceAppsManifest(parsed) {
|
|
|
412
433
|
if (!entry || typeof entry !== "object")
|
|
413
434
|
return null;
|
|
414
435
|
const e = entry;
|
|
415
|
-
const
|
|
436
|
+
const rawId = typeof e.id === "string" ? e.id.trim() : "";
|
|
437
|
+
const id = rawId ? normalizeAgentId(rawId) : "";
|
|
416
438
|
const pathValue = typeof e.path === "string" ? e.path.trim() : "";
|
|
417
439
|
if (!id || !pathValue.startsWith("/"))
|
|
418
440
|
return null;
|
|
@@ -498,11 +520,11 @@ function readWorkspaceAppsFromFilesystem() {
|
|
|
498
520
|
return null;
|
|
499
521
|
const routeAccess = workspaceAppRouteAccessFromPackageJson(pkg);
|
|
500
522
|
return {
|
|
501
|
-
id: entry.name,
|
|
523
|
+
id: normalizeAgentId(entry.name),
|
|
502
524
|
name: pkg.displayName || titleCase(entry.name),
|
|
503
525
|
description: pkg.description || "",
|
|
504
526
|
path: `/${entry.name}`,
|
|
505
|
-
isDispatch: entry.name === "dispatch",
|
|
527
|
+
isDispatch: normalizeAgentId(entry.name) === "dispatch",
|
|
506
528
|
audience: workspaceAppAudienceFromPackageJson(pkg) ??
|
|
507
529
|
DEFAULT_WORKSPACE_APP_AUDIENCE,
|
|
508
530
|
publicPaths: routeAccess.publicPaths ?? [],
|
|
@@ -550,8 +572,9 @@ async function discoverWorkspaceAgents(selfAppId, options) {
|
|
|
550
572
|
if (!workspaceApps)
|
|
551
573
|
return [];
|
|
552
574
|
const metadataSettings = await readWorkspaceAppMetadataSettings();
|
|
575
|
+
const normalizedSelfAppId = selfAppId ? normalizeAgentId(selfAppId) : "";
|
|
553
576
|
return workspaceApps
|
|
554
|
-
.filter((app) => app.id !==
|
|
577
|
+
.filter((app) => normalizeAgentId(app.id) !== normalizedSelfAppId)
|
|
555
578
|
.map((app) => {
|
|
556
579
|
const withOverride = applyWorkspaceAppMetadataOverride(app, metadataSettings);
|
|
557
580
|
const builtin = BUILTIN_AGENTS.find((agent) => agent.id === withOverride.id);
|