@vellumai/assistant 0.11.6 → 0.11.7-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/ARCHITECTURE.md +31 -19
- package/Dockerfile +1 -0
- package/docs/architecture/security.md +3 -3
- package/docs/flux-turn-detection-spike.md +8 -7
- package/docs/runbook-trusted-contacts.md +14 -0
- package/docs/stt-provider-onboarding.md +8 -4
- package/knip.json +1 -0
- package/node_modules/@vellumai/avatar-manifest/package.json +18 -0
- package/node_modules/@vellumai/avatar-manifest/src/__tests__/manifest.test.ts +173 -0
- package/node_modules/@vellumai/avatar-manifest/src/__tests__/read.test.ts +114 -0
- package/node_modules/@vellumai/avatar-manifest/src/index.ts +29 -0
- package/node_modules/@vellumai/avatar-manifest/src/layout.ts +18 -0
- package/node_modules/@vellumai/avatar-manifest/src/manifest.ts +156 -0
- package/node_modules/@vellumai/avatar-manifest/src/read.ts +109 -0
- package/node_modules/@vellumai/avatar-manifest/tsconfig.json +20 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/node_modules/@vellumai/ces-client/src/http-credentials.ts +161 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/shell.test.ts +56 -0
- package/node_modules/@vellumai/environments/src/shell.ts +65 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +32 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/inbound-event-kind.test.ts +82 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/plugin-admission-denied-contract.test.ts +56 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +18 -0
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +5 -11
- package/node_modules/@vellumai/gateway-client/src/channel-permission-contract.ts +3 -1
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +9 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-event-kind.ts +75 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +17 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +8 -0
- package/node_modules/@vellumai/gateway-client/src/plugin-admission-denied-contract.ts +47 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +11 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/openapi.yaml +419 -55
- package/package.json +4 -1
- package/scripts/sync-llm-catalog.ts +6 -0
- package/src/__tests__/approval-card-edit-inbound-handoff.test.ts +199 -0
- package/src/__tests__/approval-card-edit.test.ts +153 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +1 -1
- package/src/__tests__/available-skills.test.ts +54 -0
- package/src/__tests__/avatar-identity-sync.test.ts +5 -1
- package/src/__tests__/catalog-install-normalize.test.ts +9 -1
- package/src/__tests__/channel-policy.test.ts +1 -3
- package/src/__tests__/channel-readiness-discord.test.ts +9 -70
- package/src/__tests__/compactor-call-site-logging.test.ts +61 -0
- package/src/__tests__/config-loader-backfill.test.ts +69 -0
- package/src/__tests__/config-schema.test.ts +2 -3
- package/src/__tests__/conversation-agent-loop.test.ts +238 -0
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-error.test.ts +44 -0
- package/src/__tests__/conversation-evictor.test.ts +19 -0
- package/src/__tests__/conversation-fork-referential.test.ts +73 -63
- package/src/__tests__/conversation-fork-retrospective.test.ts +99 -74
- package/src/__tests__/conversation-runtime-assembly.test.ts +23 -0
- package/src/__tests__/conversation-slash.test.ts +9 -0
- package/src/__tests__/conversation-title-service.test.ts +97 -0
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +16 -0
- package/src/__tests__/credential-broker-server-use.test.ts +0 -218
- package/src/__tests__/credential-broker.test.ts +43 -420
- package/src/__tests__/credential-record-write-through.test.ts +78 -0
- package/src/__tests__/credential-routes.test.ts +17 -1
- package/src/__tests__/credential-security-invariants.test.ts +8 -9
- package/src/__tests__/default-profile-catalog-fallback.test.ts +289 -0
- package/src/__tests__/delete-propagation.test.ts +92 -2
- package/src/__tests__/discord-callback-round-trip.test.ts +93 -0
- package/src/__tests__/discord-channel-config.test.ts +237 -0
- package/src/__tests__/edit-propagation.test.ts +42 -2
- package/src/__tests__/evict-conversations-for-reload.test.ts +51 -1
- package/src/__tests__/fallback-breaker.test.ts +1335 -0
- package/src/__tests__/gateway-threshold-reader-mock.ts +6 -0
- package/src/__tests__/guardian-card-withdrawal.test.ts +30 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -2
- package/src/__tests__/image-conversion.test.ts +38 -4
- package/src/__tests__/install-skill-routing.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +4 -0
- package/src/__tests__/llm-resolver.test.ts +74 -0
- package/src/__tests__/llm-schema-fallback-profile.test.ts +359 -0
- package/src/__tests__/managed-fallback-dispatch.test.ts +430 -0
- package/src/__tests__/managed-profile-guard.test.ts +28 -0
- package/src/__tests__/managed-speech-defaults.test.ts +196 -1
- package/src/__tests__/mcp-cli.test.ts +23 -1
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +43 -34
- package/src/__tests__/media-stream-stt-session.test.ts +2 -0
- package/src/__tests__/notification-decision-fallback.test.ts +106 -0
- package/src/__tests__/notification-discord-adapter.test.ts +162 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +95 -0
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +6 -8
- package/src/__tests__/persist-unsendable-image.test.ts +3 -3
- package/src/__tests__/platform.test.ts +19 -1
- package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
- package/src/__tests__/provider-catalog-visibility.test.ts +17 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +8 -1
- package/src/__tests__/provider-usage-tracking.test.ts +56 -0
- package/src/__tests__/require-fresh-approval.test.ts +5 -2
- package/src/__tests__/retry-fallback-escalation.test.ts +1093 -0
- package/src/__tests__/schedule-retry.test.ts +183 -4
- package/src/__tests__/scheduler-reuse-conversation.test.ts +6 -6
- package/src/__tests__/secret-routes-platform-proxy.test.ts +55 -0
- package/src/__tests__/skill-load-tool.test.ts +34 -0
- package/src/__tests__/skill-tool-factory.test.ts +6 -1
- package/src/__tests__/skill-tool-manifest.test.ts +20 -0
- package/src/__tests__/skills.test.ts +25 -0
- package/src/__tests__/subagent-manager-notify.test.ts +38 -0
- package/src/__tests__/terminal-tools.test.ts +2 -0
- package/src/__tests__/tool-approval-handler.test.ts +146 -2
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +108 -2
- package/src/__tests__/tool-audit.test.ts +111 -40
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +228 -18
- package/src/__tests__/ui-shape-teaching.test.ts +1 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +6 -2
- package/src/__tests__/voice-config-update.test.ts +43 -0
- package/src/__tests__/workspace-migration-147-rename-colliding-backup-profile-names.test.ts +480 -0
- package/src/__tests__/workspace-migration-148-strip-unsupported-fallback-profiles.test.ts +167 -0
- package/src/__tests__/workspace-migration-149-repoint-backup-profile-selections.test.ts +144 -0
- package/src/agent/loop.ts +31 -2
- package/src/approvals/guardian-card-withdrawal.ts +22 -0
- package/src/avatar/__tests__/ensure-raster.test.ts +291 -0
- package/src/avatar/avatar-manifest.ts +48 -100
- package/src/avatar/avatar-store.ts +7 -7
- package/src/avatar/ensure-raster.ts +146 -0
- package/src/avatar/resvg-lazy.test.ts +0 -1
- package/src/avatar/traits-png-sync.ts +9 -10
- package/src/background-wake/wake-intent-hooks.test.ts +0 -1
- package/src/backup/__tests__/paths.test.ts +6 -2
- package/src/backup/paths.ts +6 -4
- package/src/bundler/app-compiler.ts +2 -2
- package/src/bundler/compiler-tools.test.ts +36 -0
- package/src/bundler/compiler-tools.ts +54 -18
- package/src/calls/__tests__/telephony-synthesis-language.test.ts +81 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +57 -0
- package/src/calls/media-stream-stt-session.ts +2 -1
- package/src/calls/telephony-synthesis-language.ts +13 -5
- package/src/calls/voice-session-bridge.ts +19 -4
- package/src/channels/config.ts +23 -12
- package/src/cli/AGENTS.md +3 -1
- package/src/cli/commands/backup.help.ts +10 -13
- package/src/cli/commands/contacts.help.ts +16 -4
- package/src/cli/commands/contacts.ts +5 -1
- package/src/cli/commands/credentials.help.ts +1 -1
- package/src/cli/commands/inference-providers.ts +18 -53
- package/src/cli/commands/mcp.help.ts +6 -5
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/memory/memory-retrospective.ts +1 -0
- package/src/cli/commands/stt.help.ts +2 -2
- package/src/config/__tests__/backup-schema.test.ts +1 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +83 -2
- package/src/config/__tests__/loader-sparse-array-cleanup.test.ts +1 -1
- package/src/config/__tests__/memory-retrospective-schema.test.ts +12 -15
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +9 -6
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +3 -1
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +16 -15
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +2 -1
- package/src/config/bundled-skills/settings/TOOLS.json +11 -5
- package/src/config/bundled-skills/settings/tools/open-system-settings.test.ts +85 -0
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +33 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +54 -3
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +1 -1
- package/src/config/default-profile-catalog.ts +195 -10
- package/src/config/default-profile-names.ts +41 -0
- package/src/config/feature-flag-registry.json +34 -2
- package/src/config/inference-profile-validation.ts +11 -2
- package/src/config/llm-resolver.ts +25 -0
- package/src/config/loader.ts +3 -0
- package/src/config/managed-speech-defaults.ts +160 -10
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/live-voice.test.ts +7 -6
- package/src/config/schemas/__tests__/stt.test.ts +94 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/channels.ts +32 -0
- package/src/config/schemas/live-voice.ts +13 -4
- package/src/config/schemas/llm.ts +263 -15
- package/src/config/schemas/mcp.ts +10 -2
- package/src/config/schemas/memory-retrospective.ts +1 -19
- package/src/config/schemas/services.ts +24 -0
- package/src/config/schemas/stt.ts +128 -5
- package/src/config/seed-inference-profiles.ts +32 -3
- package/src/config/skill-state.ts +5 -0
- package/src/config/skills.ts +21 -0
- package/src/contacts/notify-contacts-changed.ts +5 -2
- package/src/context/compactor.ts +74 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +138 -1
- package/src/daemon/config-watcher.ts +2 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +27 -0
- package/src/daemon/conversation-agent-loop.ts +86 -10
- package/src/daemon/conversation-error.ts +25 -0
- package/src/daemon/conversation-evictor.ts +2 -4
- package/src/daemon/conversation-runtime-assembly.ts +19 -7
- package/src/daemon/conversation-skill-tools.ts +5 -1
- package/src/daemon/conversation-slash.ts +2 -2
- package/src/daemon/conversation-store.ts +8 -1
- package/src/daemon/conversation-tool-setup.ts +37 -0
- package/src/daemon/conversation.ts +0 -4
- package/src/daemon/handlers/channel-config-result.ts +30 -0
- package/src/daemon/handlers/config-discord-channel.ts +301 -0
- package/src/daemon/handlers/config-ingress.ts +9 -0
- package/src/daemon/handlers/config-slack-channel.ts +13 -15
- package/src/daemon/handlers/config-telegram.ts +2 -5
- package/src/daemon/handlers/conversations.ts +0 -2
- package/src/daemon/handlers/skills.ts +25 -7
- package/src/daemon/lifecycle.ts +3 -1
- package/src/daemon/message-types/messages.ts +0 -2
- package/src/daemon/tool-setup-types.ts +5 -3
- package/src/daemon/trust-context-types.test.ts +33 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +58 -4
- package/src/live-voice/__tests__/live-voice-managed-speech-fallback.test.ts +8 -3
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +73 -11
- package/src/live-voice/__tests__/live-voice-session-preflight.test.ts +148 -2
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +64 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-text-turn.test.ts +391 -0
- package/src/live-voice/__tests__/protocol.test.ts +224 -0
- package/src/live-voice/live-voice-credential-preflight.ts +5 -1
- package/src/live-voice/live-voice-session-manager.ts +39 -2
- package/src/live-voice/live-voice-session.ts +224 -9
- package/src/live-voice/protocol.ts +187 -1
- package/src/messaging/providers/discord/api.ts +2 -1
- package/src/messaging/providers/discord/withdraw.ts +62 -0
- package/src/messaging/read-provider-metadata.ts +32 -0
- package/src/monitoring/__tests__/file-descriptors.test.ts +32 -0
- package/src/monitoring/__tests__/process-memory.test.ts +34 -1
- package/src/monitoring/db-integrity-sample.ts +1 -0
- package/src/monitoring/file-descriptors.ts +39 -6
- package/src/monitoring/process-memory.ts +37 -5
- package/src/monitoring/resource-sampler.ts +25 -8
- package/src/notifications/__tests__/activity-failed-dedupe.test.ts +161 -0
- package/src/notifications/__tests__/background-failure-signal.test.ts +107 -0
- package/src/notifications/__tests__/connected-channels.test.ts +12 -0
- package/src/notifications/__tests__/copy-composer.test.ts +83 -0
- package/src/notifications/__tests__/destination-resolver.test.ts +38 -0
- package/src/notifications/activity-failed-dedupe.ts +95 -0
- package/src/notifications/adapters/discord.ts +132 -0
- package/src/notifications/adapters/shared.ts +16 -0
- package/src/notifications/adapters/slack.ts +6 -1
- package/src/notifications/adapters/telegram.ts +5 -8
- package/src/notifications/approval-card-data.ts +94 -1
- package/src/notifications/background-failure-signal.ts +116 -0
- package/src/notifications/broadcaster.ts +3 -9
- package/src/notifications/copy-composer.ts +41 -8
- package/src/notifications/decision-engine.ts +55 -0
- package/src/notifications/destination-resolver.ts +45 -5
- package/src/notifications/emit-signal.ts +19 -5
- package/src/notifications/guardian-question-mode.ts +57 -0
- package/src/notifications/types.ts +2 -8
- package/src/oauth/__tests__/seed-providers-managed.test.ts +18 -0
- package/src/oauth/connect-orchestrator.ts +16 -0
- package/src/oauth/seed-providers.ts +262 -0
- package/src/permissions/checker.test.ts +21 -0
- package/src/permissions/checker.ts +6 -0
- package/src/permissions/gateway-threshold-reader.test.ts +184 -0
- package/src/permissions/gateway-threshold-reader.ts +144 -10
- package/src/permissions/prompter.ts +0 -6
- package/src/permissions/types.ts +5 -4
- package/src/persistence/__tests__/bulk-write-gate.test.ts +0 -38
- package/src/persistence/bulk-write-gate.ts +9 -10
- package/src/persistence/conversation-crud.ts +88 -134
- package/src/persistence/conversation-title-service.ts +43 -29
- package/src/persistence/embeddings/embedding-local.ts +14 -85
- package/src/persistence/embeddings/embedding-runtime-manager.ts +1 -0
- package/src/persistence/lifecycle-events-store.test.ts +50 -0
- package/src/persistence/lifecycle-events-store.ts +75 -5
- package/src/platform/platform-patch-queue.test.ts +368 -0
- package/src/platform/platform-patch-queue.ts +190 -0
- package/src/platform/sync-avatar.test.ts +527 -0
- package/src/platform/sync-avatar.ts +209 -0
- package/src/platform/sync-identity.test.ts +75 -0
- package/src/platform/sync-identity.ts +17 -110
- package/src/plugin-api/model-profiles.test.ts +2 -2
- package/src/plugin-api/model-profiles.ts +7 -7
- package/src/plugin-api/transcription-session.ts +1 -1
- package/src/plugins/defaults/compaction/window-manager.ts +4 -0
- package/src/plugins/defaults/image-recovery/recover.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +133 -34
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +21 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +13 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +31 -4
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +0 -11
- package/src/plugins/defaults/memory/memory-retrospective-fork-boundary.ts +27 -13
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +183 -113
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +13 -13
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +2 -2
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +1 -1
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +4 -2
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +9 -42
- package/src/plugins/defaults/memory/v2/rerank-local.ts +1 -0
- package/src/plugins/defaults/memory/worker.ts +7 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
- package/src/providers/__tests__/retry-callsite.test.ts +55 -0
- package/src/providers/__tests__/vellum-connection-routing.test.ts +21 -3
- package/src/providers/connection-resolution.ts +2 -17
- package/src/providers/fallback-breaker.ts +389 -0
- package/src/providers/inference/__tests__/adapter-factory-opencode.test.ts +92 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +16 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +12 -0
- package/src/providers/inference/adapter-factory.ts +246 -3
- package/src/providers/inference/auth.ts +15 -14
- package/src/providers/inference/chatgpt-subscription-auth.ts +70 -0
- package/src/providers/inference/chatgpt-subscription-credentials.ts +84 -0
- package/src/providers/inference/resolve-auth.ts +1 -1
- package/src/providers/media-resolve.ts +2 -3
- package/src/providers/model-catalog.ts +100 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +22 -0
- package/src/providers/openai/__tests__/chat-template-flatten.test.ts +198 -0
- package/src/providers/openai/api-error-normalization.ts +13 -0
- package/src/providers/openai/chat-completions-provider.ts +84 -0
- package/src/providers/opencode/client.test.ts +150 -0
- package/src/providers/opencode/client.ts +61 -0
- package/src/providers/platform-proxy/constants.ts +5 -0
- package/src/providers/provider-resolvability.ts +20 -0
- package/src/providers/provider-secret-catalog.ts +3 -2
- package/src/providers/retry.ts +956 -68
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +42 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +136 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +120 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +316 -12
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +83 -3
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +132 -4
- package/src/providers/speech-to-text/provider-catalog.ts +191 -3
- package/src/providers/speech-to-text/resolve.ts +132 -24
- package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +296 -0
- package/src/providers/types.ts +39 -0
- package/src/providers/usage-tracking.ts +12 -1
- package/src/providers/vellum/client.ts +29 -0
- package/src/providers/vellum-model-routing.test.ts +2 -0
- package/src/providers/vellum-model-routing.ts +3 -3
- package/src/runtime/AGENTS.md +1 -2
- package/src/runtime/__tests__/agent-wake.test.ts +105 -3
- package/src/runtime/__tests__/background-job-runner.test.ts +89 -3
- package/src/runtime/agent-wake.ts +44 -5
- package/src/runtime/background-job-runner.ts +68 -50
- package/src/runtime/channel-readiness-service.ts +0 -39
- package/src/runtime/http-server.ts +12 -4
- package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +18 -18
- package/src/runtime/routes/__tests__/backup-routes.test.ts +9 -5
- package/src/runtime/routes/__tests__/chatgpt-subscription-auth-routes.test.ts +372 -0
- package/src/runtime/routes/__tests__/contact-routes.test.ts +7 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +96 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +37 -0
- package/src/runtime/routes/__tests__/ingress-status-routes.test.ts +2 -1
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +87 -0
- package/src/runtime/routes/acp-claude-auth-routes.ts +25 -54
- package/src/runtime/routes/approval-routes.ts +0 -12
- package/src/runtime/routes/avatar-routes.ts +17 -30
- package/src/runtime/routes/backup-routes.ts +2 -2
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +296 -113
- package/src/runtime/routes/contact-prompt-routes.ts +65 -6
- package/src/runtime/routes/contact-routes.ts +20 -15
- package/src/runtime/routes/conversation-query-routes.ts +98 -10
- package/src/runtime/routes/conversation-routes.ts +2 -2
- package/src/runtime/routes/credential-routes.ts +2 -1
- package/src/runtime/routes/guardian-approval-interception.ts +12 -9
- package/src/runtime/routes/inbound-message-handler.ts +47 -48
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +18 -13
- package/src/runtime/routes/inbound-stages/admission-policy.ts +2 -2
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +20 -2
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +9 -8
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -1
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +2 -2
- package/src/runtime/routes/inference-profiles-routes.ts +12 -7
- package/src/runtime/routes/inference-provider-connection-routes.ts +2 -2
- package/src/runtime/routes/inference-send-routes.ts +2 -2
- package/src/runtime/routes/ingress-status-routes.ts +2 -2
- package/src/runtime/routes/integrations/discord.ts +119 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +2 -2
- package/src/runtime/routes/mcp-auth-routes.ts +12 -6
- package/src/runtime/routes/migration-routes.ts +3 -1
- package/src/runtime/routes/oauth-pending-flows.ts +136 -0
- package/src/runtime/routes/secret-routes.ts +7 -0
- package/src/runtime/routes/stt-routes.ts +38 -6
- package/src/runtime/routes/wake-conversation-routes.ts +8 -1
- package/src/runtime/routes/watch-routes.ts +9 -5
- package/src/runtime/sync/resource-sync-events.ts +2 -0
- package/src/runtime/trust-verdict-consumer.ts +3 -3
- package/src/schedule/__tests__/worker-feature-flags.test.ts +58 -0
- package/src/schedule/retry-policy.ts +8 -8
- package/src/schedule/run-script.ts +14 -23
- package/src/schedule/schedule-recovery.ts +0 -1
- package/src/schedule/scheduler.ts +89 -51
- package/src/schedule/worker.ts +57 -0
- package/src/security/__tests__/openai-device-auth.test.ts +355 -0
- package/src/security/ces-rpc-record-backend.ts +123 -0
- package/src/security/oauth2.ts +7 -0
- package/src/security/openai-device-auth.ts +364 -0
- package/src/security/secure-keys.ts +15 -0
- package/src/skills/available-skills.ts +10 -1
- package/src/skills/catalog-install.ts +19 -1
- package/src/skills/inline-command-runner.ts +6 -2
- package/src/skills/platform-compatibility.test.ts +49 -0
- package/src/skills/platform-compatibility.ts +65 -0
- package/src/skills/tool-manifest.ts +20 -0
- package/src/stt/__tests__/roles.test.ts +152 -0
- package/src/stt/daemon-batch-transcriber.ts +4 -1
- package/src/stt/roles.ts +180 -0
- package/src/stt/stt-stream-session.ts +3 -2
- package/src/stt/types.ts +33 -3
- package/src/subagent/manager.ts +12 -0
- package/src/telemetry/__tests__/live-voice-funnel.test.ts +34 -0
- package/src/telemetry/live-voice-funnel.ts +12 -2
- package/src/telemetry/telemetry-wire.generated.ts +6 -0
- package/src/telemetry/tool-audit.ts +83 -30
- package/src/telemetry/tool-executed-events-store.test.ts +0 -1
- package/src/telemetry/turn-outcome.ts +75 -4
- package/src/tools/client-os.ts +115 -0
- package/src/tools/computer-use/definitions.ts +11 -7
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -2
- package/src/tools/credentials/broker-types.ts +0 -71
- package/src/tools/credentials/broker.ts +6 -201
- package/src/tools/credentials/metadata-store.ts +65 -16
- package/src/tools/credentials/store.ts +2 -0
- package/src/tools/executor.ts +2 -8
- package/src/tools/host-shell.test.ts +75 -0
- package/src/tools/host-shell.ts +24 -0
- package/src/tools/host-terminal/host-shell.ts +15 -44
- package/src/tools/mcp/mcp-tool-factory.ts +44 -9
- package/src/tools/permission-checker.ts +73 -21
- package/src/tools/policy-context.ts +1 -0
- package/src/tools/shared/filesystem/image-read.ts +1 -1
- package/src/tools/skills/find-similar-skills.ts +10 -2
- package/src/tools/skills/load.ts +41 -6
- package/src/tools/skills/sandbox-runner.ts +8 -16
- package/src/tools/skills/skill-tool-factory.ts +1 -0
- package/src/tools/terminal/__tests__/safe-env.test.ts +64 -1
- package/src/tools/terminal/safe-env.ts +39 -9
- package/src/tools/terminal/shell.ts +12 -31
- package/src/tools/tool-approval-handler.ts +64 -10
- package/src/tools/tool-types.ts +10 -0
- package/src/tools/types.ts +19 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +4 -3
- package/src/tools/workflows/manage-workflows.ts +2 -2
- package/src/tools/workflows/run-workflow.test.ts +2 -1
- package/src/util/__tests__/file-use.test.ts +61 -0
- package/src/util/__tests__/process-table.test.ts +66 -0
- package/src/util/__tests__/process-tree.test.ts +46 -0
- package/src/util/errors.ts +1 -0
- package/src/util/file-use.ts +91 -0
- package/src/util/host-process.test.ts +17 -0
- package/src/util/host-process.ts +75 -0
- package/src/util/image-conversion.ts +39 -7
- package/src/util/platform.ts +32 -13
- package/src/util/process-table.ts +249 -0
- package/src/util/process-tree.ts +85 -129
- package/src/util/provider-error-patterns.ts +20 -0
- package/src/util/spawn.ts +9 -2
- package/src/watch/__tests__/watch-retro.test.ts +48 -1
- package/src/watch/watch-retro.ts +46 -4
- package/src/workspace/git-service.ts +4 -14
- package/src/workspace/migrations/147-rename-colliding-backup-profile-names.ts +360 -0
- package/src/workspace/migrations/148-strip-unsupported-fallback-profiles.ts +117 -0
- package/src/workspace/migrations/149-repoint-backup-profile-selections.ts +204 -0
- package/src/workspace/migrations/150-stt-flux-provider-to-model-family.ts +139 -0
- package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +160 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/permission-types.test.ts +0 -17
- package/src/channels/gateway-discord-admission.ts +0 -32
- package/src/persistence/fork-message-copy.ts +0 -239
- package/src/plugins/defaults/memory/__tests__/fork-message-copy.test.ts +0 -221
- package/src/security/__tests__/oauth2-device-code.test.ts +0 -431
- package/src/security/oauth2-device-code.ts +0 -312
|
@@ -20,7 +20,7 @@ import { z } from "zod";
|
|
|
20
20
|
|
|
21
21
|
import { validateInferenceProfileConfig } from "../../api/constants/profile-config-validation.js";
|
|
22
22
|
import {
|
|
23
|
-
|
|
23
|
+
getUserSelectableProfilesForProvider,
|
|
24
24
|
MANAGED_PROFILE_NAMES,
|
|
25
25
|
resolveDefaultProfileForProvider,
|
|
26
26
|
} from "../../config/default-profile-catalog.js";
|
|
@@ -436,8 +436,9 @@ function fragmentFromBody(
|
|
|
436
436
|
|
|
437
437
|
/**
|
|
438
438
|
* Enumerate every live reference to profile `name` in the raw `llm` config
|
|
439
|
-
* block: `activeProfile`, `advisorProfile`, each `callSites.<id>.profile`,
|
|
440
|
-
* every mix arm (`profiles.<mix>.mix[].profile`)
|
|
439
|
+
* block: `activeProfile`, `advisorProfile`, each `callSites.<id>.profile`,
|
|
440
|
+
* every mix arm (`profiles.<mix>.mix[].profile`), and every fallback pointer
|
|
441
|
+
* (`profiles.<p>.fallbackProfile`). Deleting a profile while any
|
|
441
442
|
* of these point at it would leave a dangling reference that `LLMSchema`'s
|
|
442
443
|
* superRefine rejects on the next load — silently resetting the user's chat
|
|
443
444
|
* model or call-site pins. The delete handler rejects instead.
|
|
@@ -467,13 +468,17 @@ export function collectProfileReferences(
|
|
|
467
468
|
const profiles = asPlainObject(llm.profiles);
|
|
468
469
|
if (profiles) {
|
|
469
470
|
for (const [profileName, profileEntry] of Object.entries(profiles)) {
|
|
470
|
-
const
|
|
471
|
+
const entry = asPlainObject(profileEntry);
|
|
472
|
+
const mix = entry?.mix;
|
|
471
473
|
if (
|
|
472
474
|
Array.isArray(mix) &&
|
|
473
475
|
mix.some((arm) => asPlainObject(arm)?.profile === name)
|
|
474
476
|
) {
|
|
475
477
|
refs.push(`llm.profiles.${profileName}.mix`);
|
|
476
478
|
}
|
|
479
|
+
if (entry?.fallbackProfile === name) {
|
|
480
|
+
refs.push(`llm.profiles.${profileName}.fallbackProfile`);
|
|
481
|
+
}
|
|
477
482
|
}
|
|
478
483
|
}
|
|
479
484
|
return refs;
|
|
@@ -514,7 +519,7 @@ function assertSaneMaxTokens(
|
|
|
514
519
|
|
|
515
520
|
async function handleListProfiles() {
|
|
516
521
|
const config = getConfigReadOnly();
|
|
517
|
-
const effective =
|
|
522
|
+
const effective = getUserSelectableProfilesForProvider(
|
|
518
523
|
config.llm.profiles,
|
|
519
524
|
config.llm.defaultProvider ?? null,
|
|
520
525
|
);
|
|
@@ -870,7 +875,7 @@ async function handleSetActiveProfile({ body = {} }: RouteHandlerArgs) {
|
|
|
870
875
|
// is rejected here instead of silently stripped on the next config load —
|
|
871
876
|
// which would reset the user's chat-model selection.
|
|
872
877
|
const config = getConfigReadOnly();
|
|
873
|
-
const effective =
|
|
878
|
+
const effective = getUserSelectableProfilesForProvider(
|
|
874
879
|
config.llm.profiles,
|
|
875
880
|
config.llm.defaultProvider ?? null,
|
|
876
881
|
);
|
|
@@ -1011,7 +1016,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
1011
1016
|
"404": { description: "Profile not found" },
|
|
1012
1017
|
"409": {
|
|
1013
1018
|
description:
|
|
1014
|
-
"Profile is still referenced by activeProfile, advisorProfile, a call site, a default-tier override,
|
|
1019
|
+
"Profile is still referenced by activeProfile, advisorProfile, a call site, a default-tier override, a mix arm, or another profile's fallbackProfile",
|
|
1015
1020
|
},
|
|
1016
1021
|
},
|
|
1017
1022
|
handler: handleDeleteProfile,
|
|
@@ -86,7 +86,7 @@ const savedConnectionResponseSchema = ProviderConnectionSchema.extend({
|
|
|
86
86
|
* Parse and validate `base_url` and `models` from the request body.
|
|
87
87
|
*
|
|
88
88
|
* `base_url` is only accepted for providers in
|
|
89
|
-
* `PROVIDERS_ALLOWING_CUSTOM_BASE_URL` (openai-compatible
|
|
89
|
+
* `PROVIDERS_ALLOWING_CUSTOM_BASE_URL` (openai-compatible, ollama, opencode).
|
|
90
90
|
* For all other providers, supplying `base_url` returns a 400. This prevents
|
|
91
91
|
* API-key exfiltration: an attacker cannot create an `anthropic` connection
|
|
92
92
|
* with a `base_url` pointing to their own server, which would redirect all
|
|
@@ -119,7 +119,7 @@ async function parseCustomProviderFields(
|
|
|
119
119
|
!PROVIDERS_ALLOWING_CUSTOM_BASE_URL.has(provider)
|
|
120
120
|
) {
|
|
121
121
|
throw new BadRequestError(
|
|
122
|
-
`base_url is only valid for openai-compatible and
|
|
122
|
+
`base_url is only valid for openai-compatible, ollama, and opencode providers. Remove base_url or use a provider that accepts a custom endpoint.`,
|
|
123
123
|
);
|
|
124
124
|
}
|
|
125
125
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { getUserSelectableProfilesForProvider } from "../../config/default-profile-catalog.js";
|
|
11
11
|
import type { ResolutionFallbackReason } from "../../config/llm-resolver.js";
|
|
12
12
|
import { selectWinningProfile } from "../../config/llm-resolver.js";
|
|
13
13
|
import { getConfigReadOnly } from "../../config/loader.js";
|
|
@@ -42,7 +42,7 @@ async function handleInferenceSend({ body = {} }: RouteHandlerArgs) {
|
|
|
42
42
|
// Validate --profile against the configured profile catalog.
|
|
43
43
|
if (profile !== undefined) {
|
|
44
44
|
const { llm } = getConfigReadOnly();
|
|
45
|
-
const profiles =
|
|
45
|
+
const profiles = getUserSelectableProfilesForProvider(
|
|
46
46
|
llm?.profiles,
|
|
47
47
|
llm?.defaultProvider ?? null,
|
|
48
48
|
);
|
|
@@ -24,9 +24,9 @@ import { z } from "zod";
|
|
|
24
24
|
import {
|
|
25
25
|
getIngressConfigResult,
|
|
26
26
|
isVelayManagedIngress,
|
|
27
|
-
loadLastTunnelRecord,
|
|
28
27
|
loadPairingTunnelRecord,
|
|
29
28
|
loadRecordedAssistantId,
|
|
29
|
+
loadRestartTunnelRecord,
|
|
30
30
|
} from "../../daemon/handlers/config-ingress.js";
|
|
31
31
|
import { probeTunnel } from "../../inbound/tunnel-probe.js";
|
|
32
32
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
@@ -100,7 +100,7 @@ async function handleIngressStatus(): Promise<IngressStatusResponse> {
|
|
|
100
100
|
if (isVelayManagedIngress() && !pairingTunnel) {
|
|
101
101
|
return { state: "unconfigured" };
|
|
102
102
|
}
|
|
103
|
-
const lastTunnel =
|
|
103
|
+
const lastTunnel = loadRestartTunnelRecord();
|
|
104
104
|
|
|
105
105
|
const publicBaseUrl =
|
|
106
106
|
pairingTunnel?.publicBaseUrl ?? config.publicBaseUrl.trim();
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route handlers for Discord channel configuration.
|
|
3
|
+
*
|
|
4
|
+
* GET /v1/integrations/discord/config: whether a bot token is stored
|
|
5
|
+
* POST /v1/integrations/discord/config: validate and store a bot token
|
|
6
|
+
* DELETE /v1/integrations/discord/config: clear it, disconnecting the bot
|
|
7
|
+
*
|
|
8
|
+
* The bot the assistant is reached through, not the user-scoped `discord`
|
|
9
|
+
* OAuth provider, which is a separate surface.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
clearDiscordChannelConfig,
|
|
16
|
+
DiscordChannelConfigResultSchema,
|
|
17
|
+
getDiscordChannelConfig,
|
|
18
|
+
setDiscordChannelConfig,
|
|
19
|
+
} from "../../../daemon/handlers/config-discord-channel.js";
|
|
20
|
+
import { ACTOR_PRINCIPALS } from "../../auth/route-policy.js";
|
|
21
|
+
import { BadRequestError, ServiceUnavailableError } from "../errors.js";
|
|
22
|
+
import { parseBody } from "../parse-body.js";
|
|
23
|
+
import type { RouteDefinition, RouteHandlerArgs } from "../types.js";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* One named schema for the connect body, parsed at the boundary and reused as
|
|
27
|
+
* the route's declaration. `requestBody` is a codegen signal, not a runtime
|
|
28
|
+
* check: the router hands the body straight to the handler, so a cast here
|
|
29
|
+
* would narrow nothing while a bot token flowed to secure storage.
|
|
30
|
+
*/
|
|
31
|
+
const SetDiscordConfigBodySchema = z.object({
|
|
32
|
+
botToken: z.string().min(1).describe("Discord bot token"),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Handlers
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
async function handleGetDiscordConfig() {
|
|
40
|
+
return getDiscordChannelConfig();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function handleSetDiscordConfig({ body = {} }: RouteHandlerArgs) {
|
|
44
|
+
const { botToken } = parseBody(SetDiscordConfigBodySchema, body);
|
|
45
|
+
const result = await setDiscordChannelConfig(botToken);
|
|
46
|
+
if (!result.success) {
|
|
47
|
+
throw new BadRequestError(
|
|
48
|
+
result.error ?? "Failed to set Discord channel config",
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function handleClearDiscordConfig() {
|
|
55
|
+
const result = await clearDiscordChannelConfig();
|
|
56
|
+
if (!result.success) {
|
|
57
|
+
// The token is still stored and the bot still connected; a 200 envelope
|
|
58
|
+
// here reads as a completed disconnect to every generated client.
|
|
59
|
+
throw new ServiceUnavailableError(
|
|
60
|
+
result.error ?? "Failed to clear Discord channel config",
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Routes
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
export const ROUTES: RouteDefinition[] = [
|
|
71
|
+
{
|
|
72
|
+
operationId: "integrations_discord_config_get",
|
|
73
|
+
endpoint: "integrations/discord/config",
|
|
74
|
+
method: "GET",
|
|
75
|
+
policy: {
|
|
76
|
+
requiredScopes: ["settings.read"],
|
|
77
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
78
|
+
},
|
|
79
|
+
summary: "Get Discord config",
|
|
80
|
+
description: "Check whether a Discord bot token is configured.",
|
|
81
|
+
tags: ["integrations"],
|
|
82
|
+
responseBody: DiscordChannelConfigResultSchema,
|
|
83
|
+
handler: () => handleGetDiscordConfig(),
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
operationId: "integrations_discord_config_post",
|
|
87
|
+
endpoint: "integrations/discord/config",
|
|
88
|
+
method: "POST",
|
|
89
|
+
policy: {
|
|
90
|
+
requiredScopes: ["settings.write"],
|
|
91
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
92
|
+
},
|
|
93
|
+
summary: "Set Discord config",
|
|
94
|
+
description:
|
|
95
|
+
"Validate a Discord bot token and store it. Storing it is what " +
|
|
96
|
+
"connects the bot: the gateway's Discord client is credential-gated " +
|
|
97
|
+
"and starts on the watcher's next tick.",
|
|
98
|
+
tags: ["integrations"],
|
|
99
|
+
handler: handleSetDiscordConfig,
|
|
100
|
+
requestBody: SetDiscordConfigBodySchema,
|
|
101
|
+
responseBody: DiscordChannelConfigResultSchema,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
operationId: "integrations_discord_config_delete",
|
|
105
|
+
endpoint: "integrations/discord/config",
|
|
106
|
+
method: "DELETE",
|
|
107
|
+
policy: {
|
|
108
|
+
requiredScopes: ["settings.write"],
|
|
109
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
110
|
+
},
|
|
111
|
+
summary: "Clear Discord config",
|
|
112
|
+
description:
|
|
113
|
+
"Clear the stored Discord bot token, which disconnects the bot on the " +
|
|
114
|
+
"gateway's next watcher tick. Room choices are left alone.",
|
|
115
|
+
tags: ["integrations"],
|
|
116
|
+
responseBody: DiscordChannelConfigResultSchema,
|
|
117
|
+
handler: () => handleClearDiscordConfig(),
|
|
118
|
+
},
|
|
119
|
+
];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
3
|
import { CALL_SITE_DEFAULTS } from "../../config/call-site-defaults.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getUserSelectableProfilesForProvider } from "../../config/default-profile-catalog.js";
|
|
5
5
|
import { resolveDefaultProfileKey } from "../../config/llm-resolver.js";
|
|
6
6
|
import { loadConfig } from "../../config/loader.js";
|
|
7
7
|
import {
|
|
@@ -66,7 +66,7 @@ export type LlmProfilesListResult = z.infer<
|
|
|
66
66
|
|
|
67
67
|
async function handleListProfiles(): Promise<LlmProfilesListResult> {
|
|
68
68
|
const { llm } = loadConfig();
|
|
69
|
-
const profiles =
|
|
69
|
+
const profiles = getUserSelectableProfilesForProvider(
|
|
70
70
|
llm?.profiles,
|
|
71
71
|
llm?.defaultProvider ?? null,
|
|
72
72
|
);
|
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
import { z } from "zod";
|
|
16
16
|
|
|
17
17
|
import { loadRawConfig, saveRawConfig } from "../../config/loader.js";
|
|
18
|
-
import
|
|
18
|
+
import {
|
|
19
|
+
DEFAULT_MCP_RISK_LEVEL,
|
|
20
|
+
type McpConfig,
|
|
21
|
+
type McpServerConfig,
|
|
22
|
+
} from "../../config/schemas/mcp.js";
|
|
19
23
|
import { estimateToolDefinitionTokens } from "../../context/token-estimator.js";
|
|
20
24
|
import { reloadMcpServers } from "../../daemon/mcp-reload-service.js";
|
|
21
25
|
import { McpClient } from "../../mcp/client.js";
|
|
@@ -312,7 +316,7 @@ async function handleMcpList(_args: {
|
|
|
312
316
|
status,
|
|
313
317
|
transport: safeTransport as McpServerEntry["transport"],
|
|
314
318
|
enabled,
|
|
315
|
-
defaultRiskLevel: config.defaultRiskLevel ??
|
|
319
|
+
defaultRiskLevel: config.defaultRiskLevel ?? DEFAULT_MCP_RISK_LEVEL,
|
|
316
320
|
hasOAuth,
|
|
317
321
|
hasStaticAuth,
|
|
318
322
|
authType,
|
|
@@ -551,10 +555,9 @@ async function handleMcpAdd({
|
|
|
551
555
|
const { name, transportType, url, command, args, risk, disabled, headers } =
|
|
552
556
|
parseBody(McpAddParams, body);
|
|
553
557
|
|
|
554
|
-
|
|
555
|
-
if (!["low", "medium", "high"].includes(riskLevel)) {
|
|
558
|
+
if (risk !== undefined && !["low", "medium", "high"].includes(risk)) {
|
|
556
559
|
throw new BadRequestError(
|
|
557
|
-
`Invalid risk level: ${
|
|
560
|
+
`Invalid risk level: ${risk}. Must be low, medium, or high`,
|
|
558
561
|
);
|
|
559
562
|
}
|
|
560
563
|
|
|
@@ -597,10 +600,13 @@ async function handleMcpAdd({
|
|
|
597
600
|
);
|
|
598
601
|
}
|
|
599
602
|
|
|
603
|
+
// Writing no `defaultRiskLevel` when the caller named none leaves the level
|
|
604
|
+
// to `McpServerConfigSchema`, so the entry tracks the shipped default
|
|
605
|
+
// instead of freezing whichever level was current on the day it was added.
|
|
600
606
|
serverMap[name] = {
|
|
601
607
|
transport,
|
|
602
608
|
enabled: !disabled,
|
|
603
|
-
defaultRiskLevel:
|
|
609
|
+
...(risk === undefined ? {} : { defaultRiskLevel: risk }),
|
|
604
610
|
};
|
|
605
611
|
|
|
606
612
|
// Store auth headers in credential store, not config
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
} from "../../security/secure-keys.js";
|
|
45
45
|
import {
|
|
46
46
|
getCredentialMetadata,
|
|
47
|
+
persistCredentialMetadata,
|
|
47
48
|
upsertCredentialMetadata,
|
|
48
49
|
} from "../../tools/credentials/metadata-store.js";
|
|
49
50
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -156,7 +157,8 @@ export async function reconcileVellumMetadataFromCes(warningSink: {
|
|
|
156
157
|
if (getCredentialMetadata("vellum", field)) {
|
|
157
158
|
continue;
|
|
158
159
|
}
|
|
159
|
-
upsertCredentialMetadata("vellum", field, {});
|
|
160
|
+
const metadata = upsertCredentialMetadata("vellum", field, {});
|
|
161
|
+
await persistCredentialMetadata(metadata);
|
|
160
162
|
log.info(
|
|
161
163
|
{ field },
|
|
162
164
|
"Reconciled vellum:* metadata entry from CES after import",
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory registry of in-flight OAuth flows, keyed by a state token.
|
|
3
|
+
*
|
|
4
|
+
* Browser-mediated OAuth finishes out of band: the daemon starts a flow, hands
|
|
5
|
+
* the client a state token, and completes the flow in the background (loopback
|
|
6
|
+
* capture, device-code poll) or on a later request (a pasted code). The client
|
|
7
|
+
* polls a status route with the state token to learn the outcome.
|
|
8
|
+
*
|
|
9
|
+
* Each caller creates its own registry so flows from different providers never
|
|
10
|
+
* share a key space. Entries expire after a TTL so the map cannot grow
|
|
11
|
+
* unbounded; call `cleanupExpired()` when starting a flow.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const DEFAULT_PENDING_FLOW_TTL_MS = 10 * 60 * 1000; // 10 minutes
|
|
15
|
+
|
|
16
|
+
export type PendingFlowStatus = "pending" | "connected" | "error";
|
|
17
|
+
|
|
18
|
+
/** Fields every tracked flow carries, whatever the provider or transport. */
|
|
19
|
+
export interface PendingFlowFields {
|
|
20
|
+
status: PendingFlowStatus;
|
|
21
|
+
/** Human-readable failure detail, set when `status` is `error`. */
|
|
22
|
+
error?: string;
|
|
23
|
+
/** Machine-readable failure code, when the provider supplies one. */
|
|
24
|
+
errorCode?: string;
|
|
25
|
+
createdAt: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** A tracked flow: the common fields plus whatever the caller stashed on it. */
|
|
29
|
+
export type PendingFlow<TExtra extends object> = PendingFlowFields & TExtra;
|
|
30
|
+
|
|
31
|
+
/** The subset of a flow that status routes report back to clients. */
|
|
32
|
+
export interface PendingFlowStatusReport {
|
|
33
|
+
status: PendingFlowStatus;
|
|
34
|
+
error?: string;
|
|
35
|
+
errorCode?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PendingFlowMarkOptions {
|
|
39
|
+
error?: string;
|
|
40
|
+
errorCode?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface PendingFlowRegistry<TExtra extends object> {
|
|
44
|
+
/** How long an entry lives before `cleanupExpired()` drops it. */
|
|
45
|
+
readonly ttlMs: number;
|
|
46
|
+
/** Track a new pending flow under `state` and return the stored entry. */
|
|
47
|
+
start(state: string, extra: TExtra): PendingFlow<TExtra>;
|
|
48
|
+
get(state: string): PendingFlow<TExtra> | undefined;
|
|
49
|
+
delete(state: string): void;
|
|
50
|
+
/** Update a tracked flow's status in place, if it still exists. */
|
|
51
|
+
mark(
|
|
52
|
+
state: string,
|
|
53
|
+
status: PendingFlowStatus,
|
|
54
|
+
options?: PendingFlowMarkOptions,
|
|
55
|
+
): void;
|
|
56
|
+
isExpired(flow: PendingFlowFields, now?: number): boolean;
|
|
57
|
+
/** Status view of a tracked flow, or `undefined` when there is no such flow. */
|
|
58
|
+
readStatus(state: string): PendingFlowStatusReport | undefined;
|
|
59
|
+
/** Drop entries older than the TTL. */
|
|
60
|
+
cleanupExpired(): void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface PendingFlowRegistryOptions {
|
|
64
|
+
ttlMs?: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function createPendingFlowRegistry<
|
|
68
|
+
TExtra extends object = Record<string, never>,
|
|
69
|
+
>(options: PendingFlowRegistryOptions = {}): PendingFlowRegistry<TExtra> {
|
|
70
|
+
const ttlMs = options.ttlMs ?? DEFAULT_PENDING_FLOW_TTL_MS;
|
|
71
|
+
const flows = new Map<string, PendingFlow<TExtra>>();
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
ttlMs,
|
|
75
|
+
|
|
76
|
+
start(state, extra) {
|
|
77
|
+
const flow = {
|
|
78
|
+
...extra,
|
|
79
|
+
status: "pending",
|
|
80
|
+
createdAt: Date.now(),
|
|
81
|
+
} as PendingFlow<TExtra>;
|
|
82
|
+
flows.set(state, flow);
|
|
83
|
+
return flow;
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
get(state) {
|
|
87
|
+
return flows.get(state);
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
delete(state) {
|
|
91
|
+
flows.delete(state);
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
mark(state, status, markOptions) {
|
|
95
|
+
const flow = flows.get(state);
|
|
96
|
+
if (!flow) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
flow.status = status;
|
|
100
|
+
if (markOptions?.error !== undefined) {
|
|
101
|
+
flow.error = markOptions.error;
|
|
102
|
+
}
|
|
103
|
+
if (markOptions?.errorCode !== undefined) {
|
|
104
|
+
flow.errorCode = markOptions.errorCode;
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
isExpired(flow, now = Date.now()) {
|
|
109
|
+
return now - flow.createdAt > ttlMs;
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
readStatus(state) {
|
|
113
|
+
const flow = flows.get(state);
|
|
114
|
+
if (!flow) {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
const report: PendingFlowStatusReport = { status: flow.status };
|
|
118
|
+
if (flow.error !== undefined) {
|
|
119
|
+
report.error = flow.error;
|
|
120
|
+
}
|
|
121
|
+
if (flow.errorCode !== undefined) {
|
|
122
|
+
report.errorCode = flow.errorCode;
|
|
123
|
+
}
|
|
124
|
+
return report;
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
cleanupExpired() {
|
|
128
|
+
const cutoff = Date.now() - ttlMs;
|
|
129
|
+
for (const [state, flow] of flows) {
|
|
130
|
+
if (flow.createdAt < cutoff) {
|
|
131
|
+
flows.delete(state);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
@@ -30,6 +30,8 @@ import {
|
|
|
30
30
|
scrubStoredCredentialFromTranscripts,
|
|
31
31
|
} from "../../daemon/credential-transcript-scrub.js";
|
|
32
32
|
import { syncManualTokenConnection } from "../../oauth/manual-token-connection.js";
|
|
33
|
+
import { syncAvatarToPlatform } from "../../platform/sync-avatar.js";
|
|
34
|
+
import { syncWorkspaceIdentityToPlatform } from "../../platform/sync-identity.js";
|
|
33
35
|
import { maybeReseedCapabilitiesAfterManagedCredential } from "../../plugins/defaults/memory/substrate/boot-maintenance.js";
|
|
34
36
|
import { validateAnthropicApiKey } from "../../providers/anthropic/client.js";
|
|
35
37
|
import { validateAtlasCloudApiKey } from "../../providers/atlascloud/client.js";
|
|
@@ -423,6 +425,11 @@ async function handleAddSecret({ body }: RouteHandlerArgs) {
|
|
|
423
425
|
// defaulting; the hook no-ops until the connection is complete.
|
|
424
426
|
// Detached — must not block the response.
|
|
425
427
|
void maybeDefaultSpeechToManaged();
|
|
428
|
+
// Same last-write-wins shape: the startup syncs no-op before live
|
|
429
|
+
// registration, so re-enqueue them here. Both dedup and no-op until
|
|
430
|
+
// the client and assistant id exist.
|
|
431
|
+
syncWorkspaceIdentityToPlatform();
|
|
432
|
+
syncAvatarToPlatform();
|
|
426
433
|
}
|
|
427
434
|
log.info({ service, field }, "Credential added via HTTP");
|
|
428
435
|
return { success: true, type, name };
|
|
@@ -13,9 +13,15 @@ import { extname, join } from "node:path";
|
|
|
13
13
|
|
|
14
14
|
import { z } from "zod";
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
baseModelFamilyFor,
|
|
18
|
+
listProviderEntries,
|
|
19
|
+
listProviderModelFamilies,
|
|
20
|
+
turnDetectionLanguagesFor,
|
|
21
|
+
} from "../../providers/speech-to-text/provider-catalog.js";
|
|
17
22
|
import { resolveBatchTranscriber } from "../../providers/speech-to-text/resolve.js";
|
|
18
23
|
import { normalizeSttError } from "../../stt/daemon-batch-transcriber.js";
|
|
24
|
+
import type { SttRole } from "../../stt/roles.js";
|
|
19
25
|
import type { BatchTranscriber, SttErrorCategory } from "../../stt/types.js";
|
|
20
26
|
import { SttError } from "../../stt/types.js";
|
|
21
27
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -232,10 +238,12 @@ const STT_ERROR_MAP: Record<SttErrorCategory, () => RouteError> = {
|
|
|
232
238
|
* surfaced verbatim. `null` means nothing is configured at all, and any other
|
|
233
239
|
* throw is an unexpected resolver failure.
|
|
234
240
|
*/
|
|
235
|
-
async function resolveBatchTranscriberOrUnavailable(
|
|
241
|
+
async function resolveBatchTranscriberOrUnavailable(
|
|
242
|
+
role: SttRole,
|
|
243
|
+
): Promise<BatchTranscriber> {
|
|
236
244
|
let transcriber: BatchTranscriber | null;
|
|
237
245
|
try {
|
|
238
|
-
transcriber = await resolveBatchTranscriber();
|
|
246
|
+
transcriber = await resolveBatchTranscriber({ role });
|
|
239
247
|
} catch (err) {
|
|
240
248
|
if (err instanceof SttError) {
|
|
241
249
|
throw new ServiceUnavailableError(err.message);
|
|
@@ -257,10 +265,30 @@ async function resolveBatchTranscriberOrUnavailable(): Promise<BatchTranscriber>
|
|
|
257
265
|
// ---------------------------------------------------------------------------
|
|
258
266
|
|
|
259
267
|
function handleListProviders() {
|
|
260
|
-
|
|
268
|
+
// Model-family rows share their parent's credential and are selected
|
|
269
|
+
// through `services.stt.providers.<id>.model`, so a provider picker must
|
|
270
|
+
// not offer them as separate providers.
|
|
271
|
+
const entries = listProviderEntries().filter(
|
|
272
|
+
(entry) => entry.variantOf === undefined,
|
|
273
|
+
);
|
|
261
274
|
const providers = entries.map((e) => ({
|
|
262
275
|
id: e.id,
|
|
263
276
|
displayName: e.displayName,
|
|
277
|
+
// The families selectable through `services.stt.providers.<id>.model`.
|
|
278
|
+
// Variant rows are filtered out above because a provider picker must not
|
|
279
|
+
// offer them as providers, which leaves this the only way a client can
|
|
280
|
+
// learn a family exists at all.
|
|
281
|
+
modelFamilies: listProviderModelFamilies(e.id),
|
|
282
|
+
// Which of those families the provider runs when none is named. Sent
|
|
283
|
+
// explicitly rather than left as "the first entry", so a client that
|
|
284
|
+
// needs to write the non-variant family is not depending on array order
|
|
285
|
+
// across the wire.
|
|
286
|
+
baseModelFamily: baseModelFamilyFor(e.id),
|
|
287
|
+
// The spoken languages this provider's turn-detecting family serves, when
|
|
288
|
+
// it has one. Reported rather than left for a client to know, so the
|
|
289
|
+
// roster lives in one place instead of being copied into every surface
|
|
290
|
+
// that has to decide whether to offer turn detection.
|
|
291
|
+
turnDetectionLanguages: turnDetectionLanguagesFor(e.id),
|
|
264
292
|
subtitle: e.subtitle,
|
|
265
293
|
setupMode: e.setupMode,
|
|
266
294
|
setupHint: e.setupHint,
|
|
@@ -317,7 +345,7 @@ async function handleTranscribe({ body }: RouteHandlerArgs) {
|
|
|
317
345
|
}
|
|
318
346
|
|
|
319
347
|
// -- Resolve transcriber --------------------------------------------------
|
|
320
|
-
const transcriber = await resolveBatchTranscriberOrUnavailable();
|
|
348
|
+
const transcriber = await resolveBatchTranscriberOrUnavailable("dictation");
|
|
321
349
|
|
|
322
350
|
// -- Transcribe with timeout ----------------------------------------------
|
|
323
351
|
const abortController = new AbortController();
|
|
@@ -375,7 +403,7 @@ async function handleTranscribeFile({ body }: RouteHandlerArgs) {
|
|
|
375
403
|
);
|
|
376
404
|
}
|
|
377
405
|
|
|
378
|
-
const transcriber = await resolveBatchTranscriberOrUnavailable();
|
|
406
|
+
const transcriber = await resolveBatchTranscriberOrUnavailable("batch");
|
|
379
407
|
|
|
380
408
|
const startTime = Date.now();
|
|
381
409
|
let wavPath: string | null = null;
|
|
@@ -449,6 +477,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
449
477
|
conversationStreamingMode: z.string().optional(),
|
|
450
478
|
// Optional on the wire so older generated clients keep validating.
|
|
451
479
|
languageSelection: z.enum(["manual", "auto"]).optional(),
|
|
480
|
+
// Optional on the wire so older generated clients keep validating.
|
|
481
|
+
modelFamilies: z.array(z.string()).optional(),
|
|
482
|
+
baseModelFamily: z.string().optional(),
|
|
483
|
+
turnDetectionLanguages: z.array(z.string()).optional(),
|
|
452
484
|
credentialsGuide: z.string().optional(),
|
|
453
485
|
}),
|
|
454
486
|
),
|
|
@@ -94,7 +94,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
94
94
|
? (getSchedule(scheduleId)?.inferenceProfile ?? null)
|
|
95
95
|
: null;
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
const result = await wakeAgentForOpportunity({
|
|
98
98
|
conversationId,
|
|
99
99
|
hint,
|
|
100
100
|
source,
|
|
@@ -108,6 +108,13 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
108
108
|
? { untrustedOutput: { content: externalContent, source: "webhook" } }
|
|
109
109
|
: {}),
|
|
110
110
|
});
|
|
111
|
+
// Pin the wire shape to the declared responseBody: WakeResult carries
|
|
112
|
+
// in-process diagnostics (exitReason) beyond this route's contract.
|
|
113
|
+
return {
|
|
114
|
+
invoked: result.invoked,
|
|
115
|
+
producedToolCalls: result.producedToolCalls,
|
|
116
|
+
...(result.reason !== undefined ? { reason: result.reason } : {}),
|
|
117
|
+
};
|
|
111
118
|
},
|
|
112
119
|
},
|
|
113
120
|
];
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
* deliberately not a second story: binary frames or base64 `audio` events in,
|
|
7
7
|
* a `{ type: "stop" }` text frame to flush, and a `StreamingTranscriber`
|
|
8
8
|
* resolved by `resolveStreamingTranscriber()` so provider selection,
|
|
9
|
-
* credentials, and language live in exactly one place.
|
|
9
|
+
* credentials, and language live in exactly one place. Watch is its own STT
|
|
10
|
+
* consumer there (`services.stt.roles.watch`, falling back to the global
|
|
11
|
+
* provider), because it shares dictation's transport without sharing its
|
|
12
|
+
* batch fallback.
|
|
10
13
|
*
|
|
11
14
|
* What differs is everything downstream of a transcript. Dictation hands its
|
|
12
15
|
* text back to the client; a watch session hands each final to
|
|
@@ -421,11 +424,12 @@ export class WatchStreamSession {
|
|
|
421
424
|
}
|
|
422
425
|
const { resolveStreamingTranscriber } =
|
|
423
426
|
await import("../../providers/speech-to-text/resolve.js");
|
|
424
|
-
return resolveStreamingTranscriber(
|
|
425
|
-
|
|
427
|
+
return resolveStreamingTranscriber({
|
|
428
|
+
role: "watch",
|
|
429
|
+
...(this.options.sampleRate !== undefined
|
|
426
430
|
? { sampleRate: this.options.sampleRate }
|
|
427
|
-
: {},
|
|
428
|
-
);
|
|
431
|
+
: {}),
|
|
432
|
+
});
|
|
429
433
|
}
|
|
430
434
|
|
|
431
435
|
/**
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
conversationMetadataSyncTag,
|
|
6
6
|
SYNC_TAGS,
|
|
7
7
|
} from "../../daemon/message-types/sync.js";
|
|
8
|
+
import { syncAvatarToPlatform } from "../../platform/sync-avatar.js";
|
|
8
9
|
import { getAvatarImagePath } from "../../util/platform.js";
|
|
9
10
|
import { broadcastMessage } from "../assistant-event-hub.js";
|
|
10
11
|
import { isStreamSeqStampingDisabled } from "../assistant-stream-state.js";
|
|
@@ -31,6 +32,7 @@ export function publishAvatarChanged(originClientId?: string): void {
|
|
|
31
32
|
avatarPath: getAvatarImagePath(),
|
|
32
33
|
});
|
|
33
34
|
void publishSyncInvalidation([SYNC_TAGS.assistantAvatar], originClientId);
|
|
35
|
+
syncAvatarToPlatform();
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
export function publishIdentityChanged(
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
*
|
|
5
5
|
* The gateway resolves a per-actor verdict from its ACL DB and stamps it onto
|
|
6
6
|
* inbound `sourceMetadata`. These pure mappers turn that verdict into the same
|
|
7
|
-
* {@link TrustContext} the local resolver would have produced
|
|
8
|
-
* only. INFO fields (notes, userFile, contactType
|
|
9
|
-
*
|
|
7
|
+
* {@link TrustContext} the local resolver would have produced: ACL + identity
|
|
8
|
+
* only. INFO fields (notes, userFile, contactType) are never carried on the
|
|
9
|
+
* wire; the consumer re-joins them locally by contactId.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import type { TrustVerdict } from "@vellumai/gateway-client";
|