@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
|
@@ -11,8 +11,12 @@ import {
|
|
|
11
11
|
parseVellumModel,
|
|
12
12
|
} from "../../providers/vellum-model-routing.js";
|
|
13
13
|
import {
|
|
14
|
+
BACKUP_PROFILE_KEYS,
|
|
14
15
|
DEFAULT_PROFILE_KEYS,
|
|
15
16
|
DEFAULT_PROFILE_PROVIDERS,
|
|
17
|
+
FALLBACK_PROFILE_BY_KEY,
|
|
18
|
+
isBackupProfileKey,
|
|
19
|
+
isDefaultProfileKey,
|
|
16
20
|
} from "../default-profile-names.js";
|
|
17
21
|
|
|
18
22
|
/**
|
|
@@ -51,12 +55,13 @@ export const KNOWN_LLM_PROVIDERS = [
|
|
|
51
55
|
"atlascloud",
|
|
52
56
|
"together",
|
|
53
57
|
"litellm",
|
|
58
|
+
"opencode",
|
|
54
59
|
"baseten",
|
|
55
60
|
"poolside",
|
|
56
|
-
// Routing identities
|
|
57
|
-
//
|
|
58
|
-
// subscription route to OpenAI.
|
|
59
|
-
//
|
|
61
|
+
// Routing identities: "vellum" = the platform-managed route (upstream
|
|
62
|
+
// derived from the model at dispatch) and the catalog owner of
|
|
63
|
+
// Vellum-hosted GPU models; "chatgpt" = the subscription route to OpenAI.
|
|
64
|
+
// Dispatch substitutes a concrete upstream before adapter lookup.
|
|
60
65
|
"vellum",
|
|
61
66
|
"chatgpt",
|
|
62
67
|
] as const;
|
|
@@ -82,7 +87,8 @@ export function unknownLlmProviderIssue(provider: string): string | null {
|
|
|
82
87
|
* connection can serve the shared BYOK templates (fixed base URL, and a
|
|
83
88
|
* non-empty catalog `defaultModel` for the intent fallback in
|
|
84
89
|
* `resolveModelIntent`). Deliberately narrower than `LLMProvider`: keyless
|
|
85
|
-
* (ollama) and endpoint-supplied (openai-compatible, litellm)
|
|
90
|
+
* (ollama) and endpoint-supplied (openai-compatible, litellm, opencode)
|
|
91
|
+
* providers have
|
|
86
92
|
* no code-resolvable default profile implementation.
|
|
87
93
|
*/
|
|
88
94
|
export const DEFAULT_PROVIDER_CHOICES: readonly LLMProvider[] = [
|
|
@@ -629,6 +635,13 @@ export const ProfileEntry = LLMConfigFragment.extend({
|
|
|
629
635
|
* may accompany `mix`.
|
|
630
636
|
*/
|
|
631
637
|
mix: MixSchema.optional(),
|
|
638
|
+
/**
|
|
639
|
+
* Code-owned backup profile for a Vellum-managed default profile. This is
|
|
640
|
+
* read-only metadata from the default-profile catalog. Config write paths
|
|
641
|
+
* reject user-authored values because custom and BYOK fallback routes are
|
|
642
|
+
* not supported.
|
|
643
|
+
*/
|
|
644
|
+
fallbackProfile: z.string().min(1).optional().meta({ readOnly: true }),
|
|
632
645
|
});
|
|
633
646
|
export type ProfileEntry = z.infer<typeof ProfileEntry>;
|
|
634
647
|
|
|
@@ -674,10 +687,210 @@ export type DefaultProviderConfig = z.infer<typeof DefaultProviderSchema>;
|
|
|
674
687
|
*/
|
|
675
688
|
const DefaultProviderField = DefaultProviderSchema.optional().catch(undefined);
|
|
676
689
|
|
|
690
|
+
/**
|
|
691
|
+
* Whether the managed backup profiles (`BACKUP_PROFILE_KEYS`) resolve under a
|
|
692
|
+
* given `llm.defaultProvider`.
|
|
693
|
+
*
|
|
694
|
+
* Backups are companions of the managed (`vellum`) column only: on a BYOK or
|
|
695
|
+
* ChatGPT default provider `defaultProfileBodyForProvider` returns `undefined`
|
|
696
|
+
* for them, because the install may hold no credential for the backup's
|
|
697
|
+
* upstream. So a reference to one is a target that can never resolve there,
|
|
698
|
+
* and the schema must reject it rather than preserve a selection the picker
|
|
699
|
+
* cannot show.
|
|
700
|
+
*
|
|
701
|
+
* Accepts an unknown value so the raw write paths (which validate on-disk
|
|
702
|
+
* shapes without a full parse) can share the rule. A missing or malformed
|
|
703
|
+
* value resolves to the managed column: `DefaultProviderField` catches an
|
|
704
|
+
* invalid value to `undefined`, and an install predating
|
|
705
|
+
* `llm.defaultProvider` is managed by definition.
|
|
706
|
+
*/
|
|
707
|
+
export function backupProfilesResolveUnderDefaultProvider(
|
|
708
|
+
defaultProvider: unknown,
|
|
709
|
+
): boolean {
|
|
710
|
+
const provider =
|
|
711
|
+
defaultProvider != null &&
|
|
712
|
+
typeof defaultProvider === "object" &&
|
|
713
|
+
!Array.isArray(defaultProvider)
|
|
714
|
+
? (defaultProvider as Record<string, unknown>).provider
|
|
715
|
+
: undefined;
|
|
716
|
+
return typeof provider !== "string" || provider === "vellum";
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Why a referenced profile name does not resolve, for the reference error
|
|
721
|
+
* messages. A backup key under a non-managed default provider gets its own
|
|
722
|
+
* reason: the name is real and code-defined, it just has no body outside the
|
|
723
|
+
* managed column, and "not defined in llm.profiles" would send the reader
|
|
724
|
+
* looking for a missing entry that was never supposed to exist.
|
|
725
|
+
*/
|
|
726
|
+
function unresolvableProfileReason(
|
|
727
|
+
name: string,
|
|
728
|
+
backupsResolve: boolean,
|
|
729
|
+
): string {
|
|
730
|
+
return !backupsResolve &&
|
|
731
|
+
(BACKUP_PROFILE_KEYS as readonly string[]).includes(name)
|
|
732
|
+
? "is a managed backup profile, which resolves only while llm.defaultProvider is the managed provider"
|
|
733
|
+
: "is not defined in llm.profiles";
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* The `llm.profiles` keys that are reference targets in their own right,
|
|
738
|
+
* given whether the managed backups resolve under the current
|
|
739
|
+
* `llm.defaultProvider`.
|
|
740
|
+
*
|
|
741
|
+
* Every on-disk key qualifies but one: a reserved backup name whose entry is
|
|
742
|
+
* a thin `source: "managed"` stub. The stub is not a profile, it is the
|
|
743
|
+
* workspace's slot for a code-owned one, and it can reach disk on a managed
|
|
744
|
+
* install through nothing more than a `config get` -> `config set` round-trip
|
|
745
|
+
* of the effective profile list (`normalizeManagedProfileWrites` reduces the
|
|
746
|
+
* echoed body to exactly that stub). Counting it as an ordinary raw key would
|
|
747
|
+
* let it launder a backup reference past the provider gate: after a switch to
|
|
748
|
+
* a BYOK or ChatGPT default provider the reference would keep validating
|
|
749
|
+
* while the code-owned body it stands for has resolved to nothing, leaving a
|
|
750
|
+
* selection that names a providerless stub.
|
|
751
|
+
*
|
|
752
|
+
* A genuinely user-owned entry under a backup name is the opposite case: it
|
|
753
|
+
* carries its own body, and with no code-owned body to lose on a non-managed
|
|
754
|
+
* column `resolveAgainstBody` resolves the workspace entry itself. So it
|
|
755
|
+
* stays a valid target on every column. The `source` test is the same one
|
|
756
|
+
* the resolver uses, which is what keeps the two in step.
|
|
757
|
+
*/
|
|
758
|
+
function referenceableProfileKeys(
|
|
759
|
+
profiles: Record<string, unknown> | undefined,
|
|
760
|
+
backupsResolve: boolean,
|
|
761
|
+
): string[] {
|
|
762
|
+
return Object.entries(profiles ?? {})
|
|
763
|
+
.filter(([name, value]) => {
|
|
764
|
+
if (backupsResolve || !isBackupProfileKey(name)) {
|
|
765
|
+
return true;
|
|
766
|
+
}
|
|
767
|
+
const entry =
|
|
768
|
+
value != null && typeof value === "object" && !Array.isArray(value)
|
|
769
|
+
? (value as Record<string, unknown>)
|
|
770
|
+
: null;
|
|
771
|
+
return entry != null && entry.source !== "managed";
|
|
772
|
+
})
|
|
773
|
+
.map(([name]) => name);
|
|
774
|
+
}
|
|
775
|
+
|
|
677
776
|
// ---------------------------------------------------------------------------
|
|
678
777
|
// Top-level LLM schema
|
|
679
778
|
// ---------------------------------------------------------------------------
|
|
680
779
|
|
|
780
|
+
/**
|
|
781
|
+
* Cross-profile integrity checks for `fallbackProfile` metadata. Only the
|
|
782
|
+
* exact code-owned mapping on managed default profiles is accepted. The
|
|
783
|
+
* referenced profile must exist, must not be a mix, and must not declare a
|
|
784
|
+
* fallback of its own.
|
|
785
|
+
*
|
|
786
|
+
* Shared by `LLMSchema.superRefine` (full-config load) and the config write
|
|
787
|
+
* paths (`commitConfigWrite`), which persist raw config without a
|
|
788
|
+
* full-schema parse. Accepts a raw or parsed `llm.profiles` record; entries
|
|
789
|
+
* are read defensively so the raw on-disk shape is safe to pass.
|
|
790
|
+
*
|
|
791
|
+
* `defaultProvider` is the sibling `llm.defaultProvider` value (raw or
|
|
792
|
+
* parsed): it decides whether the managed backups are valid targets, since
|
|
793
|
+
* they resolve on the managed column alone.
|
|
794
|
+
*/
|
|
795
|
+
export function collectFallbackProfileIssues(
|
|
796
|
+
profiles: Record<string, unknown> | undefined,
|
|
797
|
+
defaultProvider?: unknown,
|
|
798
|
+
): { profileName: string; message: string }[] {
|
|
799
|
+
const issues: { profileName: string; message: string }[] = [];
|
|
800
|
+
const entries = Object.entries(profiles ?? {});
|
|
801
|
+
const readEntry = (value: unknown): Record<string, unknown> | null =>
|
|
802
|
+
value != null && typeof value === "object" && !Array.isArray(value)
|
|
803
|
+
? (value as Record<string, unknown>)
|
|
804
|
+
: null;
|
|
805
|
+
// The always-available default profiles are code-defined
|
|
806
|
+
// (`default-profile-catalog.ts`) and resolve whether or not they are
|
|
807
|
+
// materialized in `llm.profiles`, so their names are always valid
|
|
808
|
+
// fallback targets (same rule as call-site `profile` references). The
|
|
809
|
+
// managed backups resolve the same way, but on the managed column only,
|
|
810
|
+
// so they are valid targets only under a managed `llm.defaultProvider`.
|
|
811
|
+
// A persisted managed stub for a backup name does not change that, see
|
|
812
|
+
// `referenceableProfileKeys`.
|
|
813
|
+
const backupsResolve =
|
|
814
|
+
backupProfilesResolveUnderDefaultProvider(defaultProvider);
|
|
815
|
+
const profileNames = new Set([
|
|
816
|
+
...referenceableProfileKeys(profiles, backupsResolve),
|
|
817
|
+
...DEFAULT_PROFILE_KEYS,
|
|
818
|
+
...(backupsResolve ? BACKUP_PROFILE_KEYS : []),
|
|
819
|
+
]);
|
|
820
|
+
const mixProfileNames = new Set(
|
|
821
|
+
entries
|
|
822
|
+
.filter(([, value]) => readEntry(value)?.mix != null)
|
|
823
|
+
.map(([name]) => name),
|
|
824
|
+
);
|
|
825
|
+
for (const [name, value] of entries) {
|
|
826
|
+
const entry = readEntry(value);
|
|
827
|
+
const fallback = entry?.fallbackProfile;
|
|
828
|
+
if (fallback == null) {
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
// Raw writes (e.g. `config set`) can carry a non-string value the field
|
|
832
|
+
// schema would reject on the next full parse; flag it here so it never
|
|
833
|
+
// reaches disk.
|
|
834
|
+
if (typeof fallback !== "string" || fallback.length === 0) {
|
|
835
|
+
issues.push({
|
|
836
|
+
profileName: name,
|
|
837
|
+
message: `Profile "${name}" declares a fallbackProfile that must be a non-empty string naming another profile.`,
|
|
838
|
+
});
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
const expectedFallback = isDefaultProfileKey(name)
|
|
842
|
+
? FALLBACK_PROFILE_BY_KEY[name]
|
|
843
|
+
: undefined;
|
|
844
|
+
if (entry?.source !== "managed" || fallback !== expectedFallback) {
|
|
845
|
+
issues.push({
|
|
846
|
+
profileName: name,
|
|
847
|
+
message: `Profile "${name}" cannot configure fallbackProfile. Automatic fallbacks are code-owned for Vellum-managed default profiles.`,
|
|
848
|
+
});
|
|
849
|
+
continue;
|
|
850
|
+
}
|
|
851
|
+
// (e) A mix carries no route of its own to fall back from.
|
|
852
|
+
if (entry?.mix != null) {
|
|
853
|
+
issues.push({
|
|
854
|
+
profileName: name,
|
|
855
|
+
message: `Mix profile "${name}" cannot also set "fallbackProfile"; a mix only references other profiles plus metadata.`,
|
|
856
|
+
});
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
859
|
+
// (b) No self-reference.
|
|
860
|
+
if (fallback === name) {
|
|
861
|
+
issues.push({
|
|
862
|
+
profileName: name,
|
|
863
|
+
message: `Profile "${name}" cannot declare itself as its fallbackProfile.`,
|
|
864
|
+
});
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
867
|
+
// (a) Referenced profile must exist.
|
|
868
|
+
if (!profileNames.has(fallback)) {
|
|
869
|
+
issues.push({
|
|
870
|
+
profileName: name,
|
|
871
|
+
message: `Profile "${name}" declares fallbackProfile "${fallback}" which ${unresolvableProfileReason(fallback, backupsResolve)}.`,
|
|
872
|
+
});
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
// (c) A fallback target must be a standard (non-mix) profile.
|
|
876
|
+
if (mixProfileNames.has(fallback)) {
|
|
877
|
+
issues.push({
|
|
878
|
+
profileName: name,
|
|
879
|
+
message: `Profile "${name}" declares fallbackProfile "${fallback}" which is a mix profile; a fallback must be a standard profile.`,
|
|
880
|
+
});
|
|
881
|
+
continue;
|
|
882
|
+
}
|
|
883
|
+
// (d) Single hop only: the target must not declare its own fallback.
|
|
884
|
+
if (readEntry(profiles?.[fallback])?.fallbackProfile != null) {
|
|
885
|
+
issues.push({
|
|
886
|
+
profileName: name,
|
|
887
|
+
message: `Profile "${name}" declares fallbackProfile "${fallback}" which sets its own fallbackProfile; fallback is a single hop, chains are not allowed.`,
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
return issues;
|
|
892
|
+
}
|
|
893
|
+
|
|
681
894
|
export const LLMSchema = z
|
|
682
895
|
.object({
|
|
683
896
|
profiles: z.record(z.string().min(1), ProfileEntry).default({}),
|
|
@@ -740,12 +953,29 @@ export const LLMSchema = z
|
|
|
740
953
|
// The always-available default profiles are code-defined
|
|
741
954
|
// (`default-profile-catalog.ts`) and resolve whether or not they are
|
|
742
955
|
// materialized in `llm.profiles`, so their names are always valid
|
|
743
|
-
// reference targets. The
|
|
744
|
-
//
|
|
745
|
-
//
|
|
956
|
+
// reference targets. The managed backups (`BACKUP_PROFILE_KEYS`) are
|
|
957
|
+
// code-defined on the same terms and are listed in the effective
|
|
958
|
+
// catalog, so a selection naming one (`activeProfile`, `advisorProfile`,
|
|
959
|
+
// a call-site pin) must survive the next load rather than being stripped
|
|
960
|
+
// back to a default. Backups are scoped to the managed column though, so
|
|
961
|
+
// they join the set only under a managed `llm.defaultProvider`: on a BYOK
|
|
962
|
+
// or ChatGPT default provider they have no body to resolve to, and
|
|
963
|
+
// keeping the reference would strand a selection the picker cannot show.
|
|
964
|
+
// The flag-gated `os-beta` is excluded: it resolves only while a
|
|
965
|
+
// workspace entry exists, so a reference to it is valid only when that
|
|
966
|
+
// entry is present in `config.profiles`. A backup name materialized as a
|
|
967
|
+
// thin managed stub does not re-enter the set on a non-managed column
|
|
968
|
+
// either, see `referenceableProfileKeys`.
|
|
969
|
+
const backupsResolve = backupProfilesResolveUnderDefaultProvider(
|
|
970
|
+
config.defaultProvider,
|
|
971
|
+
);
|
|
746
972
|
const profileNames = new Set([
|
|
747
|
-
...
|
|
973
|
+
...referenceableProfileKeys(
|
|
974
|
+
config.profiles as Record<string, unknown> | undefined,
|
|
975
|
+
backupsResolve,
|
|
976
|
+
),
|
|
748
977
|
...DEFAULT_PROFILE_KEYS,
|
|
978
|
+
...(backupsResolve ? BACKUP_PROFILE_KEYS : []),
|
|
749
979
|
]);
|
|
750
980
|
for (const [siteId, siteConfig] of Object.entries(config.callSites ?? {})) {
|
|
751
981
|
if (siteConfig?.profile == null) {
|
|
@@ -755,7 +985,7 @@ export const LLMSchema = z
|
|
|
755
985
|
ctx.addIssue({
|
|
756
986
|
code: "custom",
|
|
757
987
|
path: ["callSites", siteId, "profile"],
|
|
758
|
-
message: `Profile "${siteConfig.profile}" referenced by call site "${siteId}"
|
|
988
|
+
message: `Profile "${siteConfig.profile}" referenced by call site "${siteId}" ${unresolvableProfileReason(siteConfig.profile, backupsResolve)}`,
|
|
759
989
|
});
|
|
760
990
|
}
|
|
761
991
|
}
|
|
@@ -766,7 +996,7 @@ export const LLMSchema = z
|
|
|
766
996
|
ctx.addIssue({
|
|
767
997
|
code: "custom",
|
|
768
998
|
path: ["activeProfile"],
|
|
769
|
-
message: `Profile "${config.activeProfile}" referenced by llm.activeProfile
|
|
999
|
+
message: `Profile "${config.activeProfile}" referenced by llm.activeProfile ${unresolvableProfileReason(config.activeProfile, backupsResolve)}`,
|
|
770
1000
|
});
|
|
771
1001
|
}
|
|
772
1002
|
if (
|
|
@@ -776,18 +1006,20 @@ export const LLMSchema = z
|
|
|
776
1006
|
ctx.addIssue({
|
|
777
1007
|
code: "custom",
|
|
778
1008
|
path: ["advisorProfile"],
|
|
779
|
-
message: `Profile "${config.advisorProfile}" referenced by llm.advisorProfile
|
|
1009
|
+
message: `Profile "${config.advisorProfile}" referenced by llm.advisorProfile ${unresolvableProfileReason(config.advisorProfile, backupsResolve)}`,
|
|
780
1010
|
});
|
|
781
1011
|
}
|
|
782
1012
|
|
|
783
1013
|
// --- Mix profile validation --------------------------------------------
|
|
784
1014
|
// Config keys a mix profile must NOT also set (a mix only references other
|
|
785
1015
|
// profiles + metadata). Derived from the fragment shape plus the
|
|
786
|
-
// ProfileEntry-only `provider_connection`
|
|
787
|
-
//
|
|
1016
|
+
// ProfileEntry-only `provider_connection` and `fallbackProfile` (a mix
|
|
1017
|
+
// carries no config of its own, so it has no route to fall back from) so
|
|
1018
|
+
// it can't drift if a new config field is added to `LLMConfigFragment`.
|
|
788
1019
|
const MIX_DISALLOWED_CONFIG_KEYS = [
|
|
789
1020
|
...Object.keys(LLMConfigFragment.shape),
|
|
790
1021
|
"provider_connection",
|
|
1022
|
+
"fallbackProfile",
|
|
791
1023
|
];
|
|
792
1024
|
const mixProfileNames = new Set(
|
|
793
1025
|
Object.entries(config.profiles ?? {})
|
|
@@ -824,7 +1056,7 @@ export const LLMSchema = z
|
|
|
824
1056
|
ctx.addIssue({
|
|
825
1057
|
code: "custom",
|
|
826
1058
|
path: ["profiles", name, "mix", index, "profile"],
|
|
827
|
-
message: `Mix profile "${name}" references profile "${arm.profile}" which
|
|
1059
|
+
message: `Mix profile "${name}" references profile "${arm.profile}" which ${unresolvableProfileReason(arm.profile, backupsResolve)}.`,
|
|
828
1060
|
});
|
|
829
1061
|
continue;
|
|
830
1062
|
}
|
|
@@ -838,6 +1070,22 @@ export const LLMSchema = z
|
|
|
838
1070
|
}
|
|
839
1071
|
}
|
|
840
1072
|
}
|
|
1073
|
+
|
|
1074
|
+
// --- fallbackProfile validation ----------------------------------------
|
|
1075
|
+
// Cross-profile fallback rules live in `collectFallbackProfileIssues`
|
|
1076
|
+
// (shared with the config write paths). A mix profile setting
|
|
1077
|
+
// `fallbackProfile` is also rejected by the mix validation above
|
|
1078
|
+
// (MIX_DISALLOWED_CONFIG_KEYS).
|
|
1079
|
+
for (const issue of collectFallbackProfileIssues(
|
|
1080
|
+
config.profiles,
|
|
1081
|
+
config.defaultProvider,
|
|
1082
|
+
)) {
|
|
1083
|
+
ctx.addIssue({
|
|
1084
|
+
code: "custom",
|
|
1085
|
+
path: ["profiles", issue.profileName, "fallbackProfile"],
|
|
1086
|
+
message: issue.message,
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
841
1089
|
});
|
|
842
1090
|
|
|
843
1091
|
export type LLMConfig = z.infer<typeof LLMSchema>;
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Risk level an MCP server's tools start at when its config entry does not
|
|
5
|
+
* name one. Callers that write or display a server entry must reference this
|
|
6
|
+
* rather than repeating a literal, so the level stays code-owned: an entry
|
|
7
|
+
* that omits the field picks up whatever this constant says on every load.
|
|
8
|
+
*/
|
|
9
|
+
export const DEFAULT_MCP_RISK_LEVEL = "medium";
|
|
10
|
+
|
|
3
11
|
const McpStdioTransportSchema = z
|
|
4
12
|
.object({
|
|
5
13
|
type: z.literal("stdio"),
|
|
@@ -66,9 +74,9 @@ export const McpServerConfigSchema = z
|
|
|
66
74
|
.enum(["low", "medium", "high"], {
|
|
67
75
|
error: "mcp server defaultRiskLevel must be one of: low, medium, high",
|
|
68
76
|
})
|
|
69
|
-
.default(
|
|
77
|
+
.default(DEFAULT_MCP_RISK_LEVEL)
|
|
70
78
|
.describe(
|
|
71
|
-
"
|
|
79
|
+
"Risk level tools from this server start at (affects approval requirements). A tool's own MCP annotations move it one step from here: destructiveHint up, readOnlyHint down.",
|
|
72
80
|
),
|
|
73
81
|
maxTools: z
|
|
74
82
|
.number({ error: "mcp server maxTools must be a number" })
|
|
@@ -2,11 +2,6 @@ import { z } from "zod";
|
|
|
2
2
|
|
|
3
3
|
export const MemoryRetrospectiveConfigSchema = z
|
|
4
4
|
.object({
|
|
5
|
-
// This kill switch exists only because conversation forking is expensive:
|
|
6
|
-
// a fork full-copies the source conversation (messages + attachments), so
|
|
7
|
-
// on a large conversation the retrospective's write burst can lock the
|
|
8
|
-
// SQLite table against other writers. Until forking is referential, an
|
|
9
|
-
// operator needs a way to stop retrospectives without turning off memory.
|
|
10
5
|
enabled: z
|
|
11
6
|
.boolean({ error: "memory.retrospective.enabled must be a boolean" })
|
|
12
7
|
.default(true)
|
|
@@ -14,16 +9,6 @@ export const MemoryRetrospectiveConfigSchema = z
|
|
|
14
9
|
"Whether the memory-retrospective background pass runs. When false, no retrospective is enqueued by any trigger (interval, message count, pre-compaction, scheduled sweep), the scheduled sweep job stops being queued, and any row already queued completes as a no-op. The rest of the memory system (extraction, retrieval, embeddings, `<memory>` injection) is unaffected. Use `memory.enabled` to disable memory as a whole.",
|
|
15
10
|
),
|
|
16
11
|
|
|
17
|
-
forkStrategy: z
|
|
18
|
-
.enum(["cloning", "reference"], {
|
|
19
|
-
error:
|
|
20
|
-
"memory.retrospective.forkStrategy must be 'cloning' or 'reference'",
|
|
21
|
-
})
|
|
22
|
-
.default("cloning")
|
|
23
|
-
.describe(
|
|
24
|
-
"How a retrospective's fork of the source conversation is materialized. `cloning` (default) full-copies the source conversation's messages and attachments into the fork. `reference` makes the fork referential: it holds only its own messages and reads the source's through `fork_parent_message_id`, so a fork costs a single row instead of a full copy of the conversation.",
|
|
25
|
-
),
|
|
26
|
-
|
|
27
12
|
timeThresholdMs: z
|
|
28
13
|
.number({
|
|
29
14
|
error: "memory.retrospective.timeThresholdMs must be a number",
|
|
@@ -102,7 +87,7 @@ export const MemoryRetrospectiveConfigSchema = z
|
|
|
102
87
|
})
|
|
103
88
|
.default(false)
|
|
104
89
|
.describe(
|
|
105
|
-
"When false (default), superseded retrospective conversations are deleted once a newer run succeeds
|
|
90
|
+
"When false (default), superseded retrospective conversations are deleted once a newer run succeeds. The persisted remembered_log on memory_retrospective_state is the dedup baseline (the most recent run is scanned only as a fallback for state rows that predate the log column), so older runs are leftover review transcripts. Operators who want to retain the full run history set this to true; retained runs also skip the startup orphan sweep so they survive restarts.",
|
|
106
91
|
),
|
|
107
92
|
|
|
108
93
|
matchConversationProfile: z
|
|
@@ -130,6 +115,3 @@ export const MemoryRetrospectiveConfigSchema = z
|
|
|
130
115
|
export type MemoryRetrospectiveConfig = z.infer<
|
|
131
116
|
typeof MemoryRetrospectiveConfigSchema
|
|
132
117
|
>;
|
|
133
|
-
|
|
134
|
-
/** How a retrospective materializes its fork of the source conversation. */
|
|
135
|
-
export type MemoryForkStrategy = MemoryRetrospectiveConfig["forkStrategy"];
|
|
@@ -136,6 +136,21 @@ const HubspotOAuthServiceSchema = BaseServiceSchema.extend({
|
|
|
136
136
|
mode: ServiceModeSchema.default("your-own"),
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
+
const MondayOAuthServiceSchema = BaseServiceSchema.extend({
|
|
140
|
+
mode: ServiceModeSchema.default("your-own"),
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
export const EventbriteOAuthServiceSchema = BaseServiceSchema.extend({
|
|
144
|
+
mode: ServiceModeSchema.default("your-own"),
|
|
145
|
+
});
|
|
146
|
+
export type EventbriteOAuthService = z.infer<
|
|
147
|
+
typeof EventbriteOAuthServiceSchema
|
|
148
|
+
>;
|
|
149
|
+
|
|
150
|
+
const CalendlyOAuthServiceSchema = BaseServiceSchema.extend({
|
|
151
|
+
mode: ServiceModeSchema.default("your-own"),
|
|
152
|
+
});
|
|
153
|
+
|
|
139
154
|
export const ServicesSchema = z.object({
|
|
140
155
|
inference: InferenceServiceSchema.default(InferenceServiceSchema.parse({})),
|
|
141
156
|
"image-generation": ImageGenerationServiceSchema.default(
|
|
@@ -184,6 +199,15 @@ export const ServicesSchema = z.object({
|
|
|
184
199
|
"hubspot-oauth": HubspotOAuthServiceSchema.default(
|
|
185
200
|
HubspotOAuthServiceSchema.parse({}),
|
|
186
201
|
),
|
|
202
|
+
"monday-oauth": MondayOAuthServiceSchema.default(
|
|
203
|
+
MondayOAuthServiceSchema.parse({}),
|
|
204
|
+
),
|
|
205
|
+
"eventbrite-oauth": EventbriteOAuthServiceSchema.default(
|
|
206
|
+
EventbriteOAuthServiceSchema.parse({}),
|
|
207
|
+
),
|
|
208
|
+
"calendly-oauth": CalendlyOAuthServiceSchema.default(
|
|
209
|
+
CalendlyOAuthServiceSchema.parse({}),
|
|
210
|
+
),
|
|
187
211
|
});
|
|
188
212
|
export type Services = z.infer<typeof ServicesSchema>;
|
|
189
213
|
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
+
import { listProviderModelFamilies } from "../../providers/speech-to-text/provider-catalog.js";
|
|
4
|
+
import {
|
|
5
|
+
STT_ROLE_REQUIREMENTS,
|
|
6
|
+
STT_ROLES,
|
|
7
|
+
type SttRole,
|
|
8
|
+
sttRoleCapabilityGap,
|
|
9
|
+
} from "../../stt/roles.js";
|
|
10
|
+
import type { SttProviderId } from "../../stt/types.js";
|
|
11
|
+
|
|
3
12
|
/**
|
|
4
13
|
* Valid STT provider identifiers. New providers append here and register
|
|
5
14
|
* an adapter.
|
|
6
15
|
*/
|
|
7
16
|
export const VALID_STT_PROVIDERS = [
|
|
8
17
|
"deepgram",
|
|
9
|
-
"deepgram-flux",
|
|
10
18
|
"google-gemini",
|
|
11
19
|
"openai-whisper",
|
|
12
20
|
"xai",
|
|
@@ -38,12 +46,126 @@ const STT_PROVIDER_ALIASES: Record<
|
|
|
38
46
|
* The map only holds entries the user has explicitly configured — it is
|
|
39
47
|
* NOT required to enumerate every known provider.
|
|
40
48
|
*/
|
|
41
|
-
export const SttProvidersSchema = z
|
|
42
|
-
z.string(),
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
export const SttProvidersSchema = z
|
|
50
|
+
.record(z.string(), z.record(z.string(), z.unknown()).default({}))
|
|
51
|
+
.check((ctx) => {
|
|
52
|
+
// `model` is only meaningful for providers the catalog knows, and the map
|
|
53
|
+
// is deliberately open to ids it does not: entries for future providers
|
|
54
|
+
// must keep round-tripping untouched. So validate the key where it means
|
|
55
|
+
// something and leave the rest alone.
|
|
56
|
+
for (const [providerId, settings] of Object.entries(ctx.value)) {
|
|
57
|
+
const model = settings?.model;
|
|
58
|
+
if (model === undefined) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const families = listProviderModelFamilies(providerId as SttProviderId);
|
|
62
|
+
if (families.length === 0) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (typeof model !== "string" || !families.includes(model as never)) {
|
|
66
|
+
ctx.issues.push({
|
|
67
|
+
code: "custom",
|
|
68
|
+
path: [providerId, "model"],
|
|
69
|
+
message: `services.stt.providers.${providerId}.model must be one of: ${families.join(", ")}`,
|
|
70
|
+
input: model,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
45
75
|
export type SttProviders = z.infer<typeof SttProvidersSchema>;
|
|
46
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Per-consumer provider overrides: `services.stt.roles.<role>`.
|
|
79
|
+
*
|
|
80
|
+
* Sparse: an unset role falls back to `services.stt.provider`. Capability is
|
|
81
|
+
* per boundary while the base setting is global, so a provider that is right
|
|
82
|
+
* for live voice can be incapable of batch transcription. A role is how one
|
|
83
|
+
* consumer says which provider and model family it needs without moving the
|
|
84
|
+
* others onto it.
|
|
85
|
+
*
|
|
86
|
+
* Validation is fail-closed: a pair the provider cannot serve is rejected
|
|
87
|
+
* here rather than at dial time. Accepting it and falling back at resolve
|
|
88
|
+
* time is the silent substitution this config exists to make visible.
|
|
89
|
+
*/
|
|
90
|
+
export const SttRolesSchema = z
|
|
91
|
+
.partialRecord(
|
|
92
|
+
z.enum(STT_ROLES),
|
|
93
|
+
z.object({
|
|
94
|
+
provider: z
|
|
95
|
+
.preprocess(
|
|
96
|
+
(v) => {
|
|
97
|
+
if (typeof v !== "string") {
|
|
98
|
+
return v;
|
|
99
|
+
}
|
|
100
|
+
const k = v.trim().toLowerCase();
|
|
101
|
+
return STT_PROVIDER_ALIASES[k] ?? k;
|
|
102
|
+
},
|
|
103
|
+
z.enum(VALID_STT_PROVIDERS, {
|
|
104
|
+
error: `a services.stt.roles provider must be one of: ${VALID_STT_PROVIDERS.join(", ")}`,
|
|
105
|
+
}),
|
|
106
|
+
)
|
|
107
|
+
.describe("Provider this consumer uses"),
|
|
108
|
+
model: z
|
|
109
|
+
.string({ error: "a services.stt.roles model must be a string" })
|
|
110
|
+
.optional()
|
|
111
|
+
.describe(
|
|
112
|
+
"Model family this consumer uses. Omitted runs the provider's default family",
|
|
113
|
+
),
|
|
114
|
+
}),
|
|
115
|
+
)
|
|
116
|
+
.check((ctx) => {
|
|
117
|
+
for (const [role, selection] of Object.entries(ctx.value)) {
|
|
118
|
+
if (selection === undefined) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const families = listProviderModelFamilies(
|
|
122
|
+
selection.provider as SttProviderId,
|
|
123
|
+
);
|
|
124
|
+
if (
|
|
125
|
+
selection.model !== undefined &&
|
|
126
|
+
!families.includes(selection.model as never)
|
|
127
|
+
) {
|
|
128
|
+
ctx.issues.push({
|
|
129
|
+
code: "custom",
|
|
130
|
+
path: [role, "model"],
|
|
131
|
+
message:
|
|
132
|
+
families.length === 0
|
|
133
|
+
? `services.stt.roles.${role}: ${selection.provider} offers a single model, so model cannot be set`
|
|
134
|
+
: `services.stt.roles.${role}.model must be one of: ${families.join(", ")}`,
|
|
135
|
+
input: selection.model,
|
|
136
|
+
});
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const gap = sttRoleCapabilityGap(role as SttRole, selection);
|
|
140
|
+
if (gap !== null) {
|
|
141
|
+
ctx.issues.push({
|
|
142
|
+
code: "custom",
|
|
143
|
+
path: [role],
|
|
144
|
+
message: `services.stt.roles.${role} cannot be ${describeSelection(selection)}: ${gap}`,
|
|
145
|
+
input: selection,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
.describe(
|
|
151
|
+
`Per-consumer STT provider overrides (${STT_ROLES.join(", ")}). An unset role uses services.stt.provider`,
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
export type SttRoles = z.infer<typeof SttRolesSchema>;
|
|
155
|
+
|
|
156
|
+
/** How a role's selection reads in an error: "deepgram" or "deepgram/flux". */
|
|
157
|
+
function describeSelection(selection: {
|
|
158
|
+
provider: string;
|
|
159
|
+
model?: string | undefined;
|
|
160
|
+
}): string {
|
|
161
|
+
return selection.model === undefined
|
|
162
|
+
? `"${selection.provider}"`
|
|
163
|
+
: `"${selection.provider}" running ${selection.model}`;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Re-exported so config consumers need not reach into the stt module. */
|
|
167
|
+
export { STT_ROLE_REQUIREMENTS, STT_ROLES, type SttRole };
|
|
168
|
+
|
|
47
169
|
/**
|
|
48
170
|
* Canonical STT service configuration.
|
|
49
171
|
*
|
|
@@ -98,6 +220,7 @@ export const SttServiceSchema = z
|
|
|
98
220
|
"BCP-47 language code (e.g. 'en-US', 'hi') or 'multi' for code-switching across languages. Defaults to 'multi'; providers that detect natively ignore it",
|
|
99
221
|
),
|
|
100
222
|
providers: SttProvidersSchema.default({}),
|
|
223
|
+
roles: SttRolesSchema.default({}),
|
|
101
224
|
})
|
|
102
225
|
.describe(
|
|
103
226
|
"Speech-to-text service configuration -- provider selection, spoken language, and per-provider settings",
|