@vellumai/assistant 0.12.1 → 0.12.2-staging.2
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/AGENTS.md +4 -0
- package/ARCHITECTURE.md +20 -21
- package/docs/architecture/turn-actor.md +15 -8
- package/docs/guardian-request-flow.md +16 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +13 -8
- package/node_modules/@vellumai/slack-text/src/label-resolution-entities.test.ts +95 -0
- package/openapi.yaml +360 -51
- package/package.json +3 -1
- package/scripts/smoke-desktop-window-theme.ts +186 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
- package/src/__tests__/anthropic-provider.test.ts +0 -63
- package/src/__tests__/app-compiler.test.ts +6 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
- package/src/__tests__/app-dir-path-guard.test.ts +1 -3
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +6 -7
- package/src/__tests__/assistant-event-hub.test.ts +44 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
- package/src/__tests__/computer-use-tools.test.ts +19 -7
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +28 -29
- package/src/__tests__/config-watcher.test.ts +23 -8
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +26 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
- package/src/__tests__/conversation-queue.test.ts +48 -207
- package/src/__tests__/conversation-retry-discard.test.ts +54 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +28 -0
- package/src/__tests__/conversation-skill-tools.test.ts +27 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
- package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-point-at-capability.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-title-service.test.ts +14 -10
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
- package/src/__tests__/credential-record-retire.test.ts +171 -1
- package/src/__tests__/credential-routes.test.ts +250 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/cu-unified-flow.test.ts +14 -4
- package/src/__tests__/document-sync-tags.test.ts +25 -0
- package/src/__tests__/drain-kick-guard.test.ts +0 -2
- package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/git-porcelain.test.ts +47 -0
- package/src/__tests__/heartbeat-service.test.ts +56 -40
- package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
- package/src/__tests__/host-bash-proxy.test.ts +26 -45
- package/src/__tests__/host-browser-proxy.test.ts +6 -17
- package/src/__tests__/host-cu-proxy.test.ts +596 -0
- package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
- package/src/__tests__/host-file-proxy.test.ts +11 -23
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
- package/src/__tests__/list-messages-camera-frame.test.ts +121 -0
- package/src/__tests__/llm-catalog-parity.test.ts +25 -0
- package/src/__tests__/mcp-auth-routes.test.ts +6 -9
- package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
- package/src/__tests__/mcp-health-check.test.ts +8 -11
- package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +355 -548
- package/src/__tests__/model-intents.test.ts +3 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
- package/src/__tests__/oauth-commands-routes.test.ts +168 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +22 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-provider.test.ts +1 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +8 -16
- package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +14 -0
- package/src/__tests__/qdrant-manager.test.ts +132 -0
- package/src/__tests__/resolve-app.test.ts +135 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +229 -6
- package/src/__tests__/script-proxy-certs.test.ts +35 -0
- package/src/__tests__/secret-routes-acp-guard.test.ts +59 -1
- package/src/__tests__/service-account-token.test.ts +247 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/source-fingerprint.test.ts +184 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +70 -3
- package/src/__tests__/subagent-tools.test.ts +3 -2
- package/src/__tests__/telephony-tts-guard.test.ts +38 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/ui-channel-variants.test.ts +1 -56
- package/src/__tests__/unicode.test.ts +13 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
- package/src/__tests__/workspace-git-service.test.ts +26 -0
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +257 -6
- package/src/acp/__tests__/acp-credentials.test.ts +13 -0
- package/src/acp/__tests__/agent-process.test.ts +258 -4
- package/src/acp/__tests__/auth-required.test.ts +96 -0
- package/src/acp/__tests__/claude-token-refresh.test.ts +257 -0
- package/src/acp/__tests__/client-handler.test.ts +90 -2
- package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +60 -1
- package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
- package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
- package/src/acp/__tests__/session-manager.test.ts +895 -4
- package/src/acp/acp-claude-oauth.ts +328 -14
- package/src/acp/acp-credentials.ts +19 -0
- package/src/acp/agent-process.test.ts +4 -1
- package/src/acp/agent-process.ts +96 -10
- package/src/acp/auth-required.ts +50 -1
- package/src/acp/auto-install.test.ts +9 -7
- package/src/acp/claude-token-refresh.ts +150 -0
- package/src/acp/client-handler.ts +16 -3
- package/src/acp/model-config.test.ts +166 -0
- package/src/acp/model-config.ts +138 -0
- package/src/acp/prepare-agent-env.ts +21 -6
- package/src/acp/resolve-agent.test.ts +220 -6
- package/src/acp/resolve-agent.ts +88 -23
- package/src/acp/session-manager.test.ts +196 -3
- package/src/acp/session-manager.ts +441 -18
- package/src/acp/types.ts +50 -5
- package/src/agent/loop.ts +1 -0
- package/src/api/events/acp-session-model-update.test.ts +88 -0
- package/src/api/events/acp-session-model-update.ts +46 -0
- package/src/api/events/app-files-changed.ts +4 -3
- package/src/api/events/notification-intent.ts +2 -0
- package/src/api/events/user-message-echo.ts +7 -1
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +1 -1
- package/src/apps/resolve-app.ts +81 -0
- package/src/apps/source-fingerprint.ts +266 -0
- package/src/avatar/identity-avatar.ts +7 -2
- package/src/bundler/app-compiler.ts +15 -0
- package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
- package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
- package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
- package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
- package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
- package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
- package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
- package/src/calls/__tests__/voice-control-protocol.test.ts +120 -25
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
- package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
- package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
- package/src/calls/__tests__/voice-session-bridge.test.ts +56 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
- package/src/calls/barge-in-guard.ts +118 -0
- package/src/calls/call-constants.ts +24 -4
- package/src/calls/call-controller.ts +499 -199
- package/src/calls/call-transport.ts +16 -0
- package/src/calls/media-stream-output.ts +32 -0
- package/src/calls/media-stream-server.ts +82 -30
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/{live-voice → calls}/progress-narration.ts +2 -2
- package/src/calls/resolve-call-tts-provider.ts +33 -2
- package/src/calls/tts-call-strategy.ts +9 -5
- package/src/calls/types.ts +2 -0
- package/src/calls/voice-control-protocol.ts +155 -21
- package/src/calls/voice-leg-coordinator.ts +189 -0
- package/src/calls/voice-progress-cadence.ts +423 -0
- package/src/calls/voice-session-bridge.ts +92 -72
- package/src/calls/voice-triage-escalate.ts +178 -59
- package/src/cli/commands/__tests__/apps.test.ts +245 -0
- package/src/cli/commands/__tests__/bash.test.ts +53 -0
- package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
- package/src/cli/commands/apps.help.ts +67 -13
- package/src/cli/commands/apps.ts +183 -0
- package/src/cli/commands/bash.help.ts +8 -13
- package/src/cli/commands/bash.ts +7 -25
- package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
- package/src/cli/commands/channels/index.help.ts +70 -2
- package/src/cli/commands/channels/index.ts +16 -3
- package/src/cli/commands/channels/send.ts +128 -0
- package/src/cli/commands/credentials.help.ts +6 -2
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/oauth/status.ts +5 -0
- package/src/cli/commands/roadmap.help.ts +5 -1
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +103 -90
- package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
- package/src/config/__tests__/platform-identity.test.ts +255 -0
- package/src/config/__tests__/platform-rehydration.test.ts +99 -9
- package/src/config/acp-agent-write.ts +43 -0
- package/src/config/acp-defaults.test.ts +13 -3
- package/src/config/acp-defaults.ts +23 -6
- package/src/config/acp-schema.test.ts +81 -0
- package/src/config/acp-schema.ts +30 -2
- package/src/config/bundled-skills/acp/SKILL.md +22 -14
- package/src/config/bundled-skills/acp/TOOLS.json +5 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +29 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +99 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -1
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -1
- package/src/config/bundled-skills/schedule/SKILL.md +3 -4
- package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +6 -2
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +33 -13
- package/src/config/loader.ts +2 -0
- package/src/config/memory-v3-gate.test.ts +31 -0
- package/src/config/memory-v3-gate.ts +20 -16
- package/src/config/platform-identity.ts +201 -0
- package/src/config/platform-rehydration.ts +11 -27
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
- package/src/config/schemas/__tests__/voice.test.ts +148 -0
- package/src/config/schemas/calls.ts +1 -28
- package/src/config/schemas/live-voice.ts +1 -173
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +10 -0
- package/src/config/schemas/services.ts +18 -0
- package/src/config/schemas/skills.ts +0 -14
- package/src/config/schemas/voice.ts +150 -0
- package/src/credential-execution/process-manager.test.ts +18 -19
- package/src/credential-health/credential-health-service.ts +11 -17
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
- package/src/daemon/app-change-notify.ts +45 -0
- package/src/daemon/config-watcher.ts +13 -194
- package/src/daemon/conversation-error.ts +3 -2
- package/src/daemon/conversation-media-retry.ts +2 -1
- package/src/daemon/conversation-process.ts +35 -64
- package/src/daemon/conversation-runtime-assembly.ts +20 -7
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +21 -10
- package/src/daemon/conversation-tool-setup.ts +45 -59
- package/src/daemon/conversation.ts +0 -3
- package/src/daemon/dictation-profile-store.ts +2 -1
- package/src/daemon/handlers/shared.ts +2 -1
- package/src/daemon/handlers/skills.ts +6 -3
- package/src/daemon/host-bash-proxy.ts +8 -12
- package/src/daemon/host-browser-proxy.ts +15 -1
- package/src/daemon/host-cu-proxy.ts +224 -19
- package/src/daemon/host-file-proxy.ts +8 -10
- package/src/daemon/host-proxy-preactivation.ts +2 -1
- package/src/daemon/host-transfer-proxy.ts +14 -18
- package/src/daemon/lifecycle.ts +0 -5
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/reaction-history-render.ts +2 -1
- package/src/daemon/shutdown-handlers.ts +1 -9
- package/src/daemon/skill-memory-refresh.ts +64 -0
- package/src/daemon/tool-side-effects.ts +7 -18
- package/src/desktop/__tests__/fake-desktop.ts +122 -0
- package/src/desktop/desktop-chrome-policy.test.ts +79 -0
- package/src/desktop/desktop-chrome-policy.ts +47 -0
- package/src/desktop/desktop-chrome-session.ts +37 -0
- package/src/desktop/desktop-dependencies.test.ts +102 -0
- package/src/desktop/desktop-dependencies.ts +308 -0
- package/src/desktop/desktop-feature.test.ts +18 -0
- package/src/desktop/desktop-feature.ts +19 -0
- package/src/desktop/desktop-panel-config.test.ts +135 -0
- package/src/desktop/desktop-panel-config.ts +149 -0
- package/src/desktop/desktop-session-manager.test.ts +730 -0
- package/src/desktop/desktop-session-manager.ts +850 -0
- package/src/desktop/desktop-stream-bridge.test.ts +395 -0
- package/src/desktop/desktop-stream-bridge.ts +214 -0
- package/src/desktop/desktop-wallpaper.test.ts +191 -0
- package/src/desktop/desktop-wallpaper.ts +113 -0
- package/src/desktop/desktop-window-drag.ts +177 -0
- package/src/desktop/desktop-window-manager-config.test.ts +230 -0
- package/src/desktop/desktop-window-manager-config.ts +238 -0
- package/src/desktop/desktop-window-theme.ts +170 -0
- package/src/heartbeat/heartbeat-service.ts +21 -3
- package/src/home/__tests__/feed-writer.test.ts +22 -0
- package/src/home/feed-writer.ts +11 -2
- package/src/hooks/types.ts +33 -0
- package/src/i18n/AGENTS.md +22 -0
- package/src/i18n/__tests__/i18n.test.ts +108 -0
- package/src/i18n/index.ts +16 -0
- package/src/i18n/locales.ts +93 -0
- package/src/i18n/messages.ts +61 -0
- package/src/i18n/title.ts +25 -0
- package/src/inbound/platform-callback-registration.ts +4 -5
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +121 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +8 -7
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +94 -15
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/live-voice/__tests__/protocol.test.ts +39 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/__tests__/session-controls.test.ts +79 -0
- package/src/live-voice/live-voice-photo.ts +25 -6
- package/src/live-voice/live-voice-session.ts +297 -699
- package/src/live-voice/protocol.ts +60 -2
- package/src/live-voice/session-controls.ts +111 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +29 -45
- package/src/mcp/spec-schema.ts +111 -0
- package/src/mcp/startup.ts +8 -4
- package/src/mcp/workspace-mcp-config.ts +188 -0
- package/src/messaging/provider.ts +10 -3
- package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
- package/src/messaging/providers/callback-routing.ts +18 -0
- package/src/messaging/providers/channel-transport.ts +56 -0
- package/src/messaging/providers/discord/transport.ts +17 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
- package/src/messaging/providers/slack/adapter.ts +7 -44
- package/src/messaging/providers/slack/transport.ts +16 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
- package/src/messaging/providers/telegram-bot/client.ts +0 -26
- package/src/messaging/providers/telegram-bot/transport.ts +20 -0
- package/src/messaging/providers/whatsapp/adapter.ts +1 -48
- package/src/messaging/providers/whatsapp/transport.ts +18 -0
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
- package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/assistant-reply-producer.ts +8 -3
- package/src/notifications/conversation-pairing.ts +36 -16
- package/src/notifications/delivered-post-record.ts +11 -1
- package/src/notifications/guardian-feed-projection.ts +125 -5
- package/src/notifications/home-feed-side-effect.ts +55 -7
- package/src/notifications/schedule-result-producer.ts +66 -22
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/seed-providers-managed.test.ts +149 -0
- package/src/oauth/byo-connection.test.ts +105 -0
- package/src/oauth/byo-connection.ts +36 -6
- package/src/oauth/connection-resolver.test.ts +100 -0
- package/src/oauth/connection-resolver.ts +120 -3
- package/src/oauth/provider-serializer.ts +9 -0
- package/src/oauth/scope-utils.ts +24 -0
- package/src/oauth/seed-providers.ts +314 -27
- package/src/outbound-proxy/certs.ts +3 -5
- package/src/permissions/checker.test.ts +11 -6
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +71 -63
- package/src/persistence/conversation-lineage.ts +12 -4
- package/src/persistence/conversation-queries.ts +2 -2
- package/src/persistence/conversation-title-placeholders.ts +23 -0
- package/src/persistence/conversation-title-service.ts +9 -26
- package/src/persistence/embeddings/qdrant-manager.ts +163 -18
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-cursor.ts +78 -0
- package/src/persistence/message-reads.ts +30 -0
- package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
- package/src/persistence/schema/memory-core.ts +5 -0
- package/src/platform/client.test.ts +4 -2
- package/src/platform/client.ts +2 -10
- package/src/plugin-api/constants.ts +2 -0
- package/src/plugin-api/index.ts +1 -0
- package/src/plugin-api/types.ts +2 -0
- package/src/plugins/defaults/index.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +5 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +3 -2
- package/src/plugins/defaults/memory/context-search/format.ts +3 -2
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +6 -3
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +3 -2
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -7
- package/src/plugins/defaults/memory/hooks/init.ts +10 -0
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
- package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
- package/src/plugins/defaults/memory/host-utils.ts +10 -0
- package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
- package/src/plugins/defaults/memory/startup.ts +28 -2
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
- package/src/plugins/defaults/memory/substrate/page-index.ts +6 -1
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
- package/src/plugins/defaults/memory/v2/reranker.ts +6 -1
- package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
- package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +30 -0
- package/src/plugins/defaults/memory/v3/card.ts +3 -2
- package/src/plugins/defaults/memory/v3/pool-select.ts +5 -3
- package/src/plugins/defaults/memory/v3/sections.ts +9 -3
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -2
- package/src/plugins/defaults/memory/worker.ts +6 -0
- package/src/plugins/mcp-servers.ts +15 -75
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/__tests__/retry-callsite.test.ts +41 -0
- package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
- package/src/providers/anthropic/client.ts +0 -47
- package/src/providers/gemini/client.ts +9 -23
- package/src/providers/gemini-thought-signature.test.ts +63 -0
- package/src/providers/gemini-thought-signature.ts +44 -0
- package/src/providers/inference/__tests__/endpoint-probe.test.ts +42 -3
- package/src/providers/inference/auth.ts +2 -3
- package/src/providers/inference/connection-availability.ts +27 -8
- package/src/providers/inference/endpoint-probe.ts +10 -1
- package/src/providers/inference/resolve-auth.ts +22 -4
- package/src/providers/inference/service-account-token.ts +248 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/model-intents.ts +10 -5
- package/src/providers/openai/__tests__/chat-completions-output-token-limit.test.ts +141 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
- package/src/providers/openai/chat-completions-provider.ts +212 -79
- package/src/providers/openai/codex-models.ts +0 -4
- package/src/providers/openai/google-thought-signature.ts +320 -0
- package/src/providers/opencode/client.test.ts +73 -4
- package/src/providers/opencode/client.ts +60 -3
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/outbound-request-sanitize.ts +96 -0
- package/src/providers/retry.ts +30 -19
- package/src/providers/unparseable-tool-args.ts +5 -1
- package/src/runtime/AGENTS.md +3 -1
- package/src/runtime/__tests__/channel-send.test.ts +443 -0
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
- package/src/runtime/__tests__/host-observe.test.ts +40 -1
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
- package/src/runtime/agent-wake.ts +2 -1
- package/src/runtime/assistant-event-hub.ts +21 -3
- package/src/runtime/auth/same-actor.ts +38 -3
- package/src/runtime/channel-send.ts +316 -0
- package/src/runtime/host-observe.ts +11 -1
- package/src/runtime/http-server.ts +160 -151
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +16 -5
- package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +275 -0
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
- package/src/runtime/routes/acp-claude-auth-routes.ts +11 -3
- package/src/runtime/routes/acp-routes.test.ts +15 -0
- package/src/runtime/routes/acp-routes.ts +72 -9
- package/src/runtime/routes/app-management-routes.ts +90 -2
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/channel-send-routes.ts +85 -0
- package/src/runtime/routes/conversation-list-routes.ts +14 -3
- package/src/runtime/routes/conversation-query-routes.ts +40 -0
- package/src/runtime/routes/conversation-routes.ts +16 -3
- package/src/runtime/routes/credential-routes.ts +20 -14
- package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
- package/src/runtime/routes/desktop-setup-routes.ts +35 -0
- package/src/runtime/routes/diagnostics-routes.ts +61 -4
- package/src/runtime/routes/events-routes.ts +4 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -0
- package/src/runtime/routes/index.ts +4 -2
- package/src/runtime/routes/log-export-routes.ts +2 -0
- package/src/runtime/routes/mcp-auth-routes.ts +39 -47
- package/src/runtime/routes/migration-routes.ts +6 -20
- package/src/runtime/routes/oauth-commands-routes.ts +50 -0
- package/src/runtime/routes/oauth-providers.ts +7 -0
- package/src/runtime/routes/platform-routes.ts +18 -15
- package/src/runtime/routes/workspace-routes.test.ts +55 -26
- package/src/runtime/routes/workspace-routes.ts +46 -63
- package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
- package/src/runtime/routes/workspace-tree-walk.ts +240 -0
- package/src/runtime/routes/workspace-utils.ts +17 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +16 -3
- package/src/runtime/sync/resource-sync-events.ts +2 -1
- package/src/schedule/run-script.ts +2 -1
- package/src/schedule/schedule-store.ts +9 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
- package/src/security/ces-http-record-backend.ts +120 -0
- package/src/security/ces-rpc-record-backend.ts +7 -0
- package/src/security/untrusted-content.ts +3 -1
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
- package/src/skills/workspace-skill-md-signature.ts +50 -0
- package/src/subagent/consult-context.ts +12 -25
- package/src/tools/__tests__/side-effect-abort-guard.test.ts +1 -0
- package/src/tools/acp/list-agents.test.ts +3 -1
- package/src/tools/acp/spawn.test.ts +146 -11
- package/src/tools/acp/spawn.ts +21 -3
- package/src/tools/acp/status.test.ts +94 -0
- package/src/tools/acp/status.ts +40 -3
- package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
- package/src/tools/browser/network-recorder.ts +2 -1
- package/src/tools/capability-offer.test.ts +22 -2
- package/src/tools/capability-offer.ts +16 -1
- package/src/tools/computer-use/definitions.ts +121 -2
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
- package/src/tools/credentials/metadata-store.ts +100 -0
- package/src/tools/filesystem/search.ts +2 -1
- package/src/tools/host-filesystem/edit.test.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +2 -1
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +2 -1
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +16 -0
- package/src/tools/host-terminal/host-shell.ts +4 -20
- package/src/tools/network/web-search.ts +6 -1
- package/src/tools/policy-context.ts +6 -7
- package/src/tools/skills/scaffold-managed.ts +61 -3
- package/src/tools/subagent/spawn.ts +5 -8
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
- package/src/tools/terminal/sanitized-bash.ts +105 -0
- package/src/tools/ui-surface/channel-variants.ts +10 -59
- package/src/tools/watch/watch-retro-report.ts +0 -8
- package/src/types/host-capabilities.ts +5 -3
- package/src/util/__tests__/language-subtag.test.ts +23 -1
- package/src/util/ca-bundle.ts +13 -0
- package/src/util/language-subtag.ts +16 -0
- package/src/util/platform.ts +8 -0
- package/src/util/unicode.ts +15 -1
- package/src/watch/watch-retro.ts +6 -8
- package/src/watch/watch-timeline.ts +2 -2
- package/src/workflows/run-manager.ts +2 -1
- package/src/workspace/git-porcelain.ts +66 -0
- package/src/workspace/git-service.ts +6 -55
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/app-source-watcher.test.ts +0 -218
- package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
- package/src/__tests__/speaker-identification.test.ts +0 -56
- package/src/calls/speaker-identification.ts +0 -233
- package/src/daemon/app-source-watcher.ts +0 -218
- package/src/messaging/providers/whatsapp/client.ts +0 -29
- package/src/runtime/routes/debug-bash-routes.ts +0 -173
- package/src/util/fs-watcher-error.ts +0 -36
- /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
|
@@ -30,6 +30,7 @@ const _LIVE_VOICE_SERVER_FRAME_TYPES = [
|
|
|
30
30
|
"tts_done",
|
|
31
31
|
"turn_cancelled",
|
|
32
32
|
"minimize_room",
|
|
33
|
+
"session_control",
|
|
33
34
|
"metrics",
|
|
34
35
|
"archived",
|
|
35
36
|
"error",
|
|
@@ -152,6 +153,40 @@ export interface LiveVoiceClientStartFrame {
|
|
|
152
153
|
* malformed value costs a chart facet and never the session.
|
|
153
154
|
*/
|
|
154
155
|
readonly entry?: string;
|
|
156
|
+
/**
|
|
157
|
+
* The session controls this client can carry out when a reply asks for one
|
|
158
|
+
* (see {@link LiveVoiceSessionControlServerFrame}). The session teaches the
|
|
159
|
+
* model only the controls listed here, so a client that cannot hang up or
|
|
160
|
+
* mute is never told it can.
|
|
161
|
+
*
|
|
162
|
+
* Absent means none: a client that predates the field would ignore the
|
|
163
|
+
* frame, and a spoken "okay, ending the call" that ends nothing is worse
|
|
164
|
+
* than the model not offering. Values this daemon does not know are dropped
|
|
165
|
+
* rather than rejected, so a newer client can list controls an older daemon
|
|
166
|
+
* has never heard of.
|
|
167
|
+
*/
|
|
168
|
+
readonly sessionControls?: readonly LiveVoiceSessionControl[];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const LIVE_VOICE_SESSION_CONTROLS = ["end", "mute"] as const;
|
|
172
|
+
|
|
173
|
+
/** A session control a client can carry out on the assistant's behalf. */
|
|
174
|
+
export type LiveVoiceSessionControl =
|
|
175
|
+
(typeof LIVE_VOICE_SESSION_CONTROLS)[number];
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* A start frame's `sessionControls`, reduced to the known values with
|
|
179
|
+
* duplicates removed; empty when the field is absent or not an array.
|
|
180
|
+
*/
|
|
181
|
+
export function parseLiveVoiceSessionControls(
|
|
182
|
+
value: unknown,
|
|
183
|
+
): LiveVoiceSessionControl[] {
|
|
184
|
+
if (!Array.isArray(value)) {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
return LIVE_VOICE_SESSION_CONTROLS.filter((control) =>
|
|
188
|
+
value.includes(control),
|
|
189
|
+
);
|
|
155
190
|
}
|
|
156
191
|
|
|
157
192
|
/**
|
|
@@ -586,6 +621,26 @@ export interface LiveVoiceMinimizeRoomServerFrame extends LiveVoiceServerFrameBa
|
|
|
586
621
|
readonly turnId: string;
|
|
587
622
|
}
|
|
588
623
|
|
|
624
|
+
/**
|
|
625
|
+
* A session control the just-completed reply asked for with a terminal marker
|
|
626
|
+
* (`[END_CALL]`, `[MUTE]`, `[MUTE:<seconds>]`). Sent only after the turn's TTS
|
|
627
|
+
* has fully drained, so the spoken acknowledgement is heard first, never for a
|
|
628
|
+
* turn the user barged in on, at most once per turn, and only for a control
|
|
629
|
+
* the client listed in the start frame's `sessionControls`.
|
|
630
|
+
*
|
|
631
|
+
* - `end`: end the session the way the client's own end control does.
|
|
632
|
+
* - `mute`: mute the microphone. With `durationMs`, unmute again once it
|
|
633
|
+
* elapses; without, stay muted until the user unmutes. The timer is the
|
|
634
|
+
* client's: a muted microphone sends silence, so the daemon cannot hear an
|
|
635
|
+
* "unmute".
|
|
636
|
+
*/
|
|
637
|
+
export interface LiveVoiceSessionControlServerFrame extends LiveVoiceServerFrameBase {
|
|
638
|
+
readonly type: "session_control";
|
|
639
|
+
readonly turnId: string;
|
|
640
|
+
readonly action: LiveVoiceSessionControl;
|
|
641
|
+
readonly durationMs?: number;
|
|
642
|
+
}
|
|
643
|
+
|
|
589
644
|
export interface LiveVoiceMetricsServerFrame extends LiveVoiceServerFrameBase {
|
|
590
645
|
readonly type: "metrics";
|
|
591
646
|
readonly event?: string;
|
|
@@ -627,8 +682,6 @@ export interface LiveVoiceMetricsServerFrame extends LiveVoiceServerFrameBase {
|
|
|
627
682
|
* condition as the two fields above.
|
|
628
683
|
*/
|
|
629
684
|
readonly endpointDecisionSource?: "front-door" | "provider";
|
|
630
|
-
/** Which floor-holding ack actually spoke during the turn, if any. */
|
|
631
|
-
readonly ackSpoken?: "first_delta" | "tool_use";
|
|
632
685
|
/**
|
|
633
686
|
* Spoken progress narrations during the turn. Present only when at least
|
|
634
687
|
* one progress update spoke (otherwise the field is absent, keeping frames
|
|
@@ -709,6 +762,7 @@ export type LiveVoiceServerFrame =
|
|
|
709
762
|
| LiveVoiceTtsDoneServerFrame
|
|
710
763
|
| LiveVoiceTurnCancelledServerFrame
|
|
711
764
|
| LiveVoiceMinimizeRoomServerFrame
|
|
765
|
+
| LiveVoiceSessionControlServerFrame
|
|
712
766
|
| LiveVoiceMetricsServerFrame
|
|
713
767
|
| LiveVoiceArchivedServerFrame
|
|
714
768
|
| LiveVoiceErrorServerFrame;
|
|
@@ -730,6 +784,7 @@ export type LiveVoiceServerFramePayload =
|
|
|
730
784
|
| WithoutSeq<LiveVoiceTtsDoneServerFrame>
|
|
731
785
|
| WithoutSeq<LiveVoiceTurnCancelledServerFrame>
|
|
732
786
|
| WithoutSeq<LiveVoiceMinimizeRoomServerFrame>
|
|
787
|
+
| WithoutSeq<LiveVoiceSessionControlServerFrame>
|
|
733
788
|
| WithoutSeq<LiveVoiceMetricsServerFrame>
|
|
734
789
|
| WithoutSeq<LiveVoiceArchivedServerFrame>
|
|
735
790
|
| WithoutSeq<LiveVoiceErrorServerFrame>;
|
|
@@ -1220,6 +1275,8 @@ function validateStartFrame(
|
|
|
1220
1275
|
const client = parseClientOs(value.client);
|
|
1221
1276
|
// Same policy for the same reason: a dimension, not a capability.
|
|
1222
1277
|
const entry = parseLiveVoiceEntry(value.entry);
|
|
1278
|
+
// Same policy again: an unknown control is a newer client, not a bad frame.
|
|
1279
|
+
const sessionControls = parseLiveVoiceSessionControls(value.sessionControls);
|
|
1223
1280
|
|
|
1224
1281
|
return {
|
|
1225
1282
|
ok: true,
|
|
@@ -1241,6 +1298,7 @@ function validateStartFrame(
|
|
|
1241
1298
|
? { bargeInMinSpeechMs: value.bargeInMinSpeechMs }
|
|
1242
1299
|
: {}),
|
|
1243
1300
|
...(value.textInput === true ? { textInput: true } : {}),
|
|
1301
|
+
...(sessionControls.length > 0 ? { sessionControls } : {}),
|
|
1244
1302
|
},
|
|
1245
1303
|
};
|
|
1246
1304
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
END_CALL_MARKER,
|
|
3
|
+
FEWER_UPDATES_MARKER,
|
|
4
|
+
MUTE_MARKER,
|
|
5
|
+
NORMAL_UPDATES_MARKER,
|
|
6
|
+
parseTerminalSessionControl,
|
|
7
|
+
type SessionControlRequest,
|
|
8
|
+
} from "../calls/voice-control-protocol.js";
|
|
9
|
+
import type { VoiceProgressConfig } from "../config/schemas/voice.js";
|
|
10
|
+
import type { LiveVoiceSessionControl } from "./protocol.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Spoken session controls: the user asks out loud to end the call, mute their
|
|
14
|
+
* microphone, or hear fewer progress updates, the reply acknowledges it and
|
|
15
|
+
* ends with a marker, and the session carries it out once that
|
|
16
|
+
* acknowledgement has been spoken.
|
|
17
|
+
*
|
|
18
|
+
* A marker rather than a tool, because these are the turns a front-door leg
|
|
19
|
+
* answers on its own: "okay, I'm gonna go" should not wait on an escalation to
|
|
20
|
+
* a stronger model before the call can end. The marker is judged by the
|
|
21
|
+
* model, never by matching the user's words, so "I'm all done with that
|
|
22
|
+
* email" does not hang up.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const CLIENT_CONTROL_LINES: Record<LiveVoiceSessionControl, string> = {
|
|
26
|
+
end: `- To end the call (for example "I'm all done" or "okay, I'm gonna go"), say a brief goodbye, then end your reply with ${END_CALL_MARKER}. Being done with a task is not the same as leaving the call; end only when they are leaving.`,
|
|
27
|
+
mute: `- To mute their microphone (for example "mute for 30 seconds" or "mute yourself, I need to take this"), confirm in a few words, then end your reply with [MUTE:<seconds>] when they gave a duration or ${MUTE_MARKER} when they did not. While muted you cannot hear them, so mention they can unmute from the call controls unless the mute is timed.`,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Always taught: narration is the session's own, so no client has to be able
|
|
31
|
+
// to carry it out.
|
|
32
|
+
const UPDATES_LINE = `- To hear fewer spoken progress updates while you work (for example "don't give me updates so often"), confirm that you will only check in now and then and will tell them when it is done, then end your reply with ${FEWER_UPDATES_MARKER}. If they later want regular updates back, confirm and end with ${NORMAL_UPDATES_MARKER}.`;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The control-prompt block that teaches the session controls: the ones the
|
|
36
|
+
* client declared plus the progress-update cadence. Every leg gets it,
|
|
37
|
+
* including the toolless front-door leg: these turns are its to answer.
|
|
38
|
+
*
|
|
39
|
+
* The no-other-markers rule is withheld from the front-door leg, whose
|
|
40
|
+
* routing rule teaches it leading verdict tokens and already confines
|
|
41
|
+
* everything else to speech.
|
|
42
|
+
*/
|
|
43
|
+
export function sessionControlTeaching(
|
|
44
|
+
controls: readonly LiveVoiceSessionControl[],
|
|
45
|
+
leg: { frontDoor?: boolean },
|
|
46
|
+
): string {
|
|
47
|
+
return [
|
|
48
|
+
"The user can also control this call by asking you. Only when they clearly ask:",
|
|
49
|
+
...controls.map((control) => CLIENT_CONTROL_LINES[control]),
|
|
50
|
+
UPDATES_LINE,
|
|
51
|
+
`The marker must be the very last thing in your reply. It is never spoken and does nothing anywhere else.${leg.frontDoor === true ? "" : " Never emit any other bracketed marker."}`,
|
|
52
|
+
].join("\n");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** A session control the client carries out, sent as a `session_control` frame. */
|
|
56
|
+
export type ClientSessionControlRequest = Exclude<
|
|
57
|
+
SessionControlRequest,
|
|
58
|
+
{ action: "updates" }
|
|
59
|
+
>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The control a completed leg's raw text asks for; null when there is none or
|
|
63
|
+
* when it is a client control the client did not declare. An undeclared
|
|
64
|
+
* control is dropped rather than sent: the client said it cannot carry it out.
|
|
65
|
+
* The update cadence always passes, since the session carries it out itself.
|
|
66
|
+
*/
|
|
67
|
+
export function requestedSessionControl(
|
|
68
|
+
rawText: string,
|
|
69
|
+
controls: readonly LiveVoiceSessionControl[],
|
|
70
|
+
): SessionControlRequest | null {
|
|
71
|
+
const request = parseTerminalSessionControl(rawText);
|
|
72
|
+
if (request === null) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
if (request.action === "updates") {
|
|
76
|
+
return request;
|
|
77
|
+
}
|
|
78
|
+
return controls.includes(request.action) ? request : null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Silence (ms) a session that asked for fewer updates waits through before a
|
|
83
|
+
* progress update. Long enough that a minute-long task runs without a word;
|
|
84
|
+
* short enough that a really long one still proves the call is alive.
|
|
85
|
+
*/
|
|
86
|
+
export const FEWER_UPDATES_INTERVAL_MS = 60_000;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The progress config a turn runs on under the session's update cadence.
|
|
90
|
+
*
|
|
91
|
+
* Fewer updates means no update for tool activity (a burst of ops or a long
|
|
92
|
+
* op finishing, each normally its own beat) and the silence tick stretched to
|
|
93
|
+
* {@link FEWER_UPDATES_INTERVAL_MS}, so the only thing that speaks is a long
|
|
94
|
+
* stretch of silence. Done is still said: the reply itself is the "it's done".
|
|
95
|
+
*/
|
|
96
|
+
export function progressConfigForCadence(
|
|
97
|
+
config: VoiceProgressConfig,
|
|
98
|
+
cadence: "fewer" | "normal",
|
|
99
|
+
): VoiceProgressConfig {
|
|
100
|
+
if (cadence === "normal") {
|
|
101
|
+
return config;
|
|
102
|
+
}
|
|
103
|
+
const intervalMs = Math.max(FEWER_UPDATES_INTERVAL_MS, config.maxSilenceMs);
|
|
104
|
+
return {
|
|
105
|
+
...config,
|
|
106
|
+
opsThreshold: Number.MAX_SAFE_INTEGER,
|
|
107
|
+
longOpMs: Number.MAX_SAFE_INTEGER,
|
|
108
|
+
idleIntervalMs: intervalMs,
|
|
109
|
+
maxSilenceMs: intervalMs,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* The properties worth pinning are the ones a refactor could quietly
|
|
5
5
|
* break, each of which fails silently rather than loudly:
|
|
6
6
|
*
|
|
7
|
-
* 1. Plugin servers reach the manager at all. Reading only
|
|
8
|
-
* leaves a plugin's tools missing with nothing logged.
|
|
7
|
+
* 1. Plugin servers reach the manager at all. Reading only the workspace
|
|
8
|
+
* `mcp.json` leaves a plugin's tools missing with nothing logged.
|
|
9
9
|
* 2. A workspace entry of the same id wins, so a plugin cannot redirect a
|
|
10
10
|
* server the user configured by hand.
|
|
11
11
|
* 3. Every server is attributed. `source` is what `McpClient` reads to
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { beforeEach, describe, expect, test } from "bun:test";
|
|
4
|
+
|
|
5
|
+
import { AGENT_PLUGINS_MCP_SCHEMA_URL } from "../spec-schema.js";
|
|
6
|
+
import {
|
|
7
|
+
loadWorkspaceMcpConfig,
|
|
8
|
+
overlayWorkspaceMcpForConfigRead,
|
|
9
|
+
readWorkspaceMcpFile,
|
|
10
|
+
saveWorkspaceMcpConfig,
|
|
11
|
+
} from "../workspace-mcp-config.js";
|
|
12
|
+
|
|
13
|
+
function mcpPath(): string {
|
|
14
|
+
return join(process.env.VELLUM_WORKSPACE_DIR!, "mcp.json");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe("workspace mcp.json", () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
mkdirSync(process.env.VELLUM_WORKSPACE_DIR!, { recursive: true });
|
|
20
|
+
rmSync(mcpPath(), { force: true });
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("missing file is an empty server map", () => {
|
|
24
|
+
expect(loadWorkspaceMcpConfig()).toEqual({ servers: {} });
|
|
25
|
+
expect(readWorkspaceMcpFile().fileState).toBe("missing");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("round-trips a spec document without wrapping transport", () => {
|
|
29
|
+
saveWorkspaceMcpConfig({
|
|
30
|
+
servers: {
|
|
31
|
+
remote: {
|
|
32
|
+
transport: {
|
|
33
|
+
type: "streamable-http",
|
|
34
|
+
url: "https://example.com/mcp",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
local: {
|
|
38
|
+
transport: {
|
|
39
|
+
type: "stdio",
|
|
40
|
+
command: "npx",
|
|
41
|
+
args: ["-y", "srv"],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(JSON.parse(readFileSync(mcpPath(), "utf8"))).toEqual({
|
|
48
|
+
$schema: AGENT_PLUGINS_MCP_SCHEMA_URL,
|
|
49
|
+
mcpServers: {
|
|
50
|
+
remote: {
|
|
51
|
+
type: "streamable-http",
|
|
52
|
+
url: "https://example.com/mcp",
|
|
53
|
+
},
|
|
54
|
+
local: {
|
|
55
|
+
type: "stdio",
|
|
56
|
+
command: "npx",
|
|
57
|
+
args: ["-y", "srv"],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
expect(loadWorkspaceMcpConfig()).toEqual({
|
|
62
|
+
servers: {
|
|
63
|
+
remote: {
|
|
64
|
+
transport: {
|
|
65
|
+
type: "streamable-http",
|
|
66
|
+
url: "https://example.com/mcp",
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
local: {
|
|
70
|
+
transport: {
|
|
71
|
+
type: "stdio",
|
|
72
|
+
command: "npx",
|
|
73
|
+
args: ["-y", "srv"],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("does not persist transport headers", () => {
|
|
81
|
+
saveWorkspaceMcpConfig({
|
|
82
|
+
servers: {
|
|
83
|
+
remote: {
|
|
84
|
+
transport: {
|
|
85
|
+
type: "streamable-http",
|
|
86
|
+
url: "https://example.com/mcp",
|
|
87
|
+
headers: { Authorization: "Bearer secret" },
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const onDisk = readFileSync(mcpPath(), "utf8");
|
|
94
|
+
expect(onDisk).not.toContain("secret");
|
|
95
|
+
expect(loadWorkspaceMcpConfig().servers.remote?.transport).toEqual({
|
|
96
|
+
type: "streamable-http",
|
|
97
|
+
url: "https://example.com/mcp",
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("invalid file does not throw on read and refuses a later write", () => {
|
|
102
|
+
mkdirSync(process.env.VELLUM_WORKSPACE_DIR!, { recursive: true });
|
|
103
|
+
writeFileSync(mcpPath(), "{ not json");
|
|
104
|
+
|
|
105
|
+
expect(loadWorkspaceMcpConfig()).toEqual({ servers: {} });
|
|
106
|
+
expect(readWorkspaceMcpFile().fileState).toBe("invalid");
|
|
107
|
+
expect(() => saveWorkspaceMcpConfig({ servers: {} })).toThrow(/invalid JSON/);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("overlay projects transport-only servers for config reads", () => {
|
|
111
|
+
saveWorkspaceMcpConfig({
|
|
112
|
+
servers: {
|
|
113
|
+
remote: {
|
|
114
|
+
transport: {
|
|
115
|
+
type: "streamable-http",
|
|
116
|
+
url: "https://example.com/mcp",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const config: Record<string, unknown> = { llm: { activeProfile: "balanced" } };
|
|
123
|
+
overlayWorkspaceMcpForConfigRead(config);
|
|
124
|
+
expect(config.mcp).toEqual({
|
|
125
|
+
servers: {
|
|
126
|
+
remote: {
|
|
127
|
+
transport: {
|
|
128
|
+
type: "streamable-http",
|
|
129
|
+
url: "https://example.com/mcp",
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The MCP configuration the daemon actually runs.
|
|
3
3
|
*
|
|
4
|
-
* Two sources contribute servers: the workspace `
|
|
4
|
+
* Two sources contribute servers: the workspace `mcp.json`, which the
|
|
5
5
|
* user owns, and each installed plugin's `mcp.json`, which its author
|
|
6
6
|
* owns. Both must reach the MCP manager, so every consumer that starts
|
|
7
|
-
* servers builds its config through here rather than reading
|
|
8
|
-
*
|
|
7
|
+
* servers builds its config through here rather than reading the
|
|
8
|
+
* workspace file directly — a path that only reads the workspace half
|
|
9
9
|
* leaves a plugin's tools silently missing.
|
|
10
10
|
*
|
|
11
11
|
* Every server comes out attributed with its {@link McpServerSource}, so
|
|
@@ -3,18 +3,21 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Follows the same pattern as mcp-oauth-provider.ts: headers are stored in
|
|
5
5
|
* the secure credential store (CES or encrypted file fallback) rather than
|
|
6
|
-
* in plaintext
|
|
6
|
+
* in plaintext mcp.json, keeping secrets out of workspace config files.
|
|
7
7
|
*
|
|
8
8
|
* Key format: mcp:{serverId}:headers — stores JSON-serialized Record<string, string>.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { loadRawConfig, saveRawConfig } from "../config/loader.js";
|
|
12
11
|
import {
|
|
13
12
|
deleteSecureKeyAsync,
|
|
14
13
|
getSecureKeyAsync,
|
|
15
14
|
setSecureKeyAsync,
|
|
16
15
|
} from "../security/secure-keys.js";
|
|
17
16
|
import { getLogger } from "../util/logger.js";
|
|
17
|
+
import {
|
|
18
|
+
loadWorkspaceMcpConfig,
|
|
19
|
+
saveWorkspaceMcpConfig,
|
|
20
|
+
} from "./workspace-mcp-config.js";
|
|
18
21
|
|
|
19
22
|
const log = getLogger("mcp-header-store");
|
|
20
23
|
|
|
@@ -73,64 +76,45 @@ export async function deleteMcpHeaders(serverId: string): Promise<boolean> {
|
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* Safe to call on every MCP reload — no-ops when no legacy headers remain.
|
|
79
|
+
* Move leftover plaintext headers from mcp.json into the credential store
|
|
80
|
+
* and rewrite the file without them. Safe to call on every MCP reload.
|
|
79
81
|
*/
|
|
80
82
|
export async function migrateLegacyMcpHeaders(): Promise<void> {
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
| undefined;
|
|
85
|
-
const servers = mcpConfig?.servers;
|
|
86
|
-
if (!servers) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
83
|
+
const config = loadWorkspaceMcpConfig();
|
|
84
|
+
const servers = config.servers;
|
|
85
|
+
let dirty = false;
|
|
89
86
|
|
|
90
|
-
let configDirty = false;
|
|
91
87
|
for (const [id, server] of Object.entries(servers)) {
|
|
92
|
-
const transport = server
|
|
93
|
-
if (
|
|
94
|
-
!transport ||
|
|
95
|
-
(transport.type !== "sse" && transport.type !== "streamable-http")
|
|
96
|
-
) {
|
|
88
|
+
const transport = server.transport;
|
|
89
|
+
if (transport.type !== "sse" && transport.type !== "streamable-http") {
|
|
97
90
|
continue;
|
|
98
91
|
}
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
| undefined;
|
|
102
|
-
if (!legacyHeaders || Object.keys(legacyHeaders).length === 0) {
|
|
92
|
+
const leftoverHeaders = transport.headers;
|
|
93
|
+
if (!leftoverHeaders || Object.keys(leftoverHeaders).length === 0) {
|
|
103
94
|
continue;
|
|
104
95
|
}
|
|
105
96
|
|
|
106
|
-
// Only migrate if credential store doesn't already have headers for
|
|
107
|
-
// this server (idempotent — safe to re-run after partial failure).
|
|
108
97
|
const existing = await getMcpHeaders(id);
|
|
109
|
-
if (existing) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
delete transport.headers;
|
|
119
|
-
configDirty = true;
|
|
98
|
+
if (!existing) {
|
|
99
|
+
const ok = await setMcpHeaders(id, leftoverHeaders);
|
|
100
|
+
if (!ok) {
|
|
101
|
+
log.warn(
|
|
102
|
+
{ serverId: id },
|
|
103
|
+
"Skipping leftover header migration: credential store write failed; will retry on next reload",
|
|
104
|
+
);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
120
107
|
log.info(
|
|
121
108
|
{ serverId: id },
|
|
122
|
-
"
|
|
123
|
-
);
|
|
124
|
-
} else {
|
|
125
|
-
log.warn(
|
|
126
|
-
{ serverId: id },
|
|
127
|
-
"Skipping legacy header migration — credential store write failed; will retry on next reload",
|
|
109
|
+
"Moved leftover MCP headers to credential store",
|
|
128
110
|
);
|
|
129
111
|
}
|
|
112
|
+
delete transport.headers;
|
|
113
|
+
dirty = true;
|
|
130
114
|
}
|
|
131
115
|
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
log.info("
|
|
116
|
+
if (dirty) {
|
|
117
|
+
saveWorkspaceMcpConfig(config);
|
|
118
|
+
log.info("mcp.json updated: leftover MCP headers removed after migration");
|
|
135
119
|
}
|
|
136
120
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Plugins 1.0.0 `mcp.json` wire schema and projections onto the
|
|
3
|
+
* assistant's in-memory `McpTransport` union.
|
|
4
|
+
*
|
|
5
|
+
* Workspace `/workspace/mcp.json` and each plugin's root `mcp.json` share
|
|
6
|
+
* this document shape. Origin (`workspace` vs `plugin`) is resolved from
|
|
7
|
+
* which file was read, never from a field in the file.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
12
|
+
import type { McpTransport } from "../config/schemas/mcp.js";
|
|
13
|
+
|
|
14
|
+
/** Canonical `$schema` value for an Agent Plugins 1.0.0 MCP document. */
|
|
15
|
+
export const AGENT_PLUGINS_MCP_SCHEMA_URL =
|
|
16
|
+
"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json";
|
|
17
|
+
|
|
18
|
+
const SpecStdioServerSchema = z.object({
|
|
19
|
+
type: z.literal("stdio"),
|
|
20
|
+
command: z.string().min(1),
|
|
21
|
+
args: z.array(z.string()).optional(),
|
|
22
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
23
|
+
cwd: z.string().optional(),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Remote MCP entry. Agent Plugins 1.0.0 requires `type` and names no
|
|
28
|
+
* default. MCP's current remote transport is Streamable HTTP, so this
|
|
29
|
+
* host fills omitted `type` and the Claude-style `http` alias as
|
|
30
|
+
* `streamable-http`. `sse` stays explicit.
|
|
31
|
+
*/
|
|
32
|
+
const SpecHttpServerSchema = z.object({
|
|
33
|
+
type: z
|
|
34
|
+
.union([
|
|
35
|
+
z.literal("streamable-http"),
|
|
36
|
+
z.literal("sse"),
|
|
37
|
+
z.literal("http").transform(() => "streamable-http" as const),
|
|
38
|
+
])
|
|
39
|
+
.default("streamable-http"),
|
|
40
|
+
url: z.string().min(1),
|
|
41
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export const SpecMcpServerSchema = z.union([
|
|
45
|
+
SpecStdioServerSchema,
|
|
46
|
+
SpecHttpServerSchema,
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
export const SpecMcpDocumentSchema = z.object({
|
|
50
|
+
$schema: z.string().optional(),
|
|
51
|
+
mcpServers: z.record(z.string(), z.unknown()),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export type SpecMcpServer = z.infer<typeof SpecMcpServerSchema>;
|
|
55
|
+
export type SpecMcpDocument = z.infer<typeof SpecMcpDocumentSchema>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Project one spec-shaped entry onto the assistant's transport union. The
|
|
59
|
+
* two vocabularies already agree on type names and required fields, so this
|
|
60
|
+
* is a field copy plus an optional expander for plugin path variables.
|
|
61
|
+
*/
|
|
62
|
+
export function projectSpecServerToTransport(
|
|
63
|
+
entry: SpecMcpServer,
|
|
64
|
+
expand?: (value: string) => string,
|
|
65
|
+
): McpTransport {
|
|
66
|
+
if (entry.type === "stdio") {
|
|
67
|
+
const map = expand ?? ((value: string) => value);
|
|
68
|
+
return {
|
|
69
|
+
type: "stdio",
|
|
70
|
+
command: entry.command,
|
|
71
|
+
args: (entry.args ?? []).map(map),
|
|
72
|
+
...(entry.env && {
|
|
73
|
+
env: Object.fromEntries(
|
|
74
|
+
Object.entries(entry.env).map(([key, value]) => [key, map(value)]),
|
|
75
|
+
),
|
|
76
|
+
}),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
type: entry.type,
|
|
81
|
+
url: entry.url,
|
|
82
|
+
...(entry.headers && { headers: entry.headers }),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Project an in-memory transport onto a spec server entry. Headers are
|
|
88
|
+
* omitted: workspace secrets live in the credential store, and a write
|
|
89
|
+
* must not copy them into `mcp.json`.
|
|
90
|
+
*/
|
|
91
|
+
export function projectTransportToSpecServer(
|
|
92
|
+
transport: McpTransport,
|
|
93
|
+
): Record<string, unknown> {
|
|
94
|
+
if (transport.type === "stdio") {
|
|
95
|
+
const entry: Record<string, unknown> = {
|
|
96
|
+
type: "stdio",
|
|
97
|
+
command: transport.command,
|
|
98
|
+
};
|
|
99
|
+
if (transport.args && transport.args.length > 0) {
|
|
100
|
+
entry.args = transport.args;
|
|
101
|
+
}
|
|
102
|
+
if (transport.env) {
|
|
103
|
+
entry.env = transport.env;
|
|
104
|
+
}
|
|
105
|
+
return entry;
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
type: transport.type,
|
|
109
|
+
url: transport.url,
|
|
110
|
+
};
|
|
111
|
+
}
|
package/src/mcp/startup.ts
CHANGED
|
@@ -13,13 +13,14 @@
|
|
|
13
13
|
* further process that starts hosting turns has one call to make.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import { invalidateConfigCache } from "../config/loader.js";
|
|
17
17
|
import type { McpConfig } from "../config/schemas/mcp.js";
|
|
18
18
|
import { createMcpToolsFromServer } from "../tools/mcp/mcp-tool-factory.js";
|
|
19
19
|
import { registerMcpTools, unregisterAllMcpTools } from "../tools/registry.js";
|
|
20
20
|
import { getLogger } from "../util/logger.js";
|
|
21
21
|
import { buildEffectiveMcpConfig } from "./effective-config.js";
|
|
22
22
|
import { getMcpServerManager, stopMcpServerManager } from "./manager.js";
|
|
23
|
+
import { loadWorkspaceMcpConfig } from "./workspace-mcp-config.js";
|
|
23
24
|
|
|
24
25
|
const log = getLogger("mcp-startup");
|
|
25
26
|
|
|
@@ -36,7 +37,8 @@ const log = getLogger("mcp-startup");
|
|
|
36
37
|
* is a startup step in processes whose other work must not be held hostage to
|
|
37
38
|
* a third-party server being up.
|
|
38
39
|
*
|
|
39
|
-
* @param workspaceMcpConfig The
|
|
40
|
+
* @param workspaceMcpConfig The projected workspace MCP config. Callers
|
|
41
|
+
* that omit it read `/workspace/mcp.json`.
|
|
40
42
|
* @returns The number of tools registered across all servers.
|
|
41
43
|
*/
|
|
42
44
|
export async function startConfiguredMcpServers(
|
|
@@ -44,7 +46,9 @@ export async function startConfiguredMcpServers(
|
|
|
44
46
|
): Promise<number> {
|
|
45
47
|
let registered = 0;
|
|
46
48
|
try {
|
|
47
|
-
const mcpConfig = buildEffectiveMcpConfig(
|
|
49
|
+
const mcpConfig = buildEffectiveMcpConfig(
|
|
50
|
+
workspaceMcpConfig ?? loadWorkspaceMcpConfig(),
|
|
51
|
+
);
|
|
48
52
|
if (Object.keys(mcpConfig.servers).length === 0) {
|
|
49
53
|
return 0;
|
|
50
54
|
}
|
|
@@ -97,5 +101,5 @@ export async function restartConfiguredMcpServers(): Promise<number> {
|
|
|
97
101
|
}
|
|
98
102
|
unregisterAllMcpTools();
|
|
99
103
|
invalidateConfigCache();
|
|
100
|
-
return startConfiguredMcpServers(
|
|
104
|
+
return startConfiguredMcpServers(loadWorkspaceMcpConfig());
|
|
101
105
|
}
|