@vellumai/assistant 0.11.6 → 0.11.7-staging.1
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/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/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/openapi.yaml +419 -55
- package/package.json +4 -1
- 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-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__/discord-callback-round-trip.test.ts +93 -0
- package/src/__tests__/discord-channel-config.test.ts +237 -0
- 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-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__/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-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 +20 -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 +6 -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 +18 -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 +259 -11
- 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-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 +213 -8
- 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/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/seed-providers.ts +261 -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 +85 -133
- 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__/retry-callsite.test.ts +55 -0
- 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 +231 -3
- package/src/providers/inference/auth.ts +1 -0
- 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 +75 -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/provider-resolvability.ts +20 -0
- 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/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 +21 -9
- 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/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/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/oauth2.ts +7 -0
- package/src/security/openai-device-auth.ts +364 -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/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/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
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace migration `149-repoint-backup-profile-selections`.
|
|
3
|
+
*
|
|
4
|
+
* Managed backup profiles are internal failover routes. Earlier builds let
|
|
5
|
+
* users select those names directly, so existing workspaces can retain them
|
|
6
|
+
* in active, advisor, call-site, mix, conversation, or schedule references.
|
|
7
|
+
* Repoint those direct selections to their corresponding primary profile
|
|
8
|
+
* before the user-facing catalog hides the backups. Automatic fallback
|
|
9
|
+
* metadata is preserved: a primary's `fallbackProfile` still names its
|
|
10
|
+
* internal backup route.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { Database } from "bun:sqlite";
|
|
16
|
+
|
|
17
|
+
import { FALLBACK_PROFILE_BY_KEY } from "../../config/default-profile-names.js";
|
|
18
|
+
import { getLogger } from "../../util/logger.js";
|
|
19
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
20
|
+
|
|
21
|
+
const log = getLogger(
|
|
22
|
+
"workspace-migration-149-repoint-backup-profile-selections",
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
/** Mapping of every managed backup to its direct-selectable primary. */
|
|
26
|
+
const BACKUP_TO_PRIMARY: Record<string, string> = Object.fromEntries(
|
|
27
|
+
Object.entries(FALLBACK_PROFILE_BY_KEY).map(([primary, backup]) => [
|
|
28
|
+
backup,
|
|
29
|
+
primary,
|
|
30
|
+
]),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const PROFILE_PIN_TABLES = ["conversations", "cron_jobs"] as const;
|
|
34
|
+
const DB_ATTEMPTS = 4;
|
|
35
|
+
const DB_RETRY_BASE_DELAY_MS = 50;
|
|
36
|
+
|
|
37
|
+
export const repointBackupProfileSelectionsMigration: WorkspaceMigration = {
|
|
38
|
+
id: "149-repoint-backup-profile-selections",
|
|
39
|
+
description:
|
|
40
|
+
"Repoint direct selections of managed backup profiles to their primaries",
|
|
41
|
+
retryFailedCheckpoint: true,
|
|
42
|
+
|
|
43
|
+
async run(workspaceDir: string): Promise<void> {
|
|
44
|
+
const configPath = join(workspaceDir, "config.json");
|
|
45
|
+
const config = readConfig(configPath);
|
|
46
|
+
const llm = config === null ? null : asObject(config.llm);
|
|
47
|
+
const configChanged = llm !== null && rewriteConfigReferences(llm);
|
|
48
|
+
|
|
49
|
+
// Rewrite database pins before config.json. If the database cannot be
|
|
50
|
+
// updated, leaving config untouched lets the next boot retry the same
|
|
51
|
+
// migration without stranding a direct selection.
|
|
52
|
+
await rewriteDbReferences(workspaceDir);
|
|
53
|
+
|
|
54
|
+
if (config !== null && configChanged) {
|
|
55
|
+
const tempPath = `${configPath}.tmp`;
|
|
56
|
+
writeFileSync(tempPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
57
|
+
renameSync(tempPath, configPath);
|
|
58
|
+
log.info("Repointed direct backup-profile selections to primaries");
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
down(_workspaceDir: string): void {
|
|
63
|
+
// Forward-only: restoring a backup selection would make it unreachable
|
|
64
|
+
// from the user-facing profile catalog.
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
function readConfig(path: string): Record<string, unknown> | null {
|
|
69
|
+
if (!existsSync(path)) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const parsed: unknown = JSON.parse(readFileSync(path, "utf-8"));
|
|
74
|
+
return isPlainObject(parsed) ? parsed : null;
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Rewrite config references that represent direct user profile choices. */
|
|
81
|
+
function rewriteConfigReferences(llm: Record<string, unknown>): boolean {
|
|
82
|
+
let changed = false;
|
|
83
|
+
|
|
84
|
+
for (const field of ["activeProfile", "advisorProfile"] as const) {
|
|
85
|
+
const current = llm[field];
|
|
86
|
+
const replacement = remapProfileName(current);
|
|
87
|
+
if (replacement !== current) {
|
|
88
|
+
llm[field] = replacement;
|
|
89
|
+
changed = true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const callSites = asObject(llm.callSites);
|
|
94
|
+
if (callSites !== null) {
|
|
95
|
+
for (const value of Object.values(callSites)) {
|
|
96
|
+
const site = asObject(value);
|
|
97
|
+
if (site === null) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const replacement = remapProfileName(site.profile);
|
|
101
|
+
if (replacement !== site.profile) {
|
|
102
|
+
site.profile = replacement;
|
|
103
|
+
changed = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const profiles = asObject(llm.profiles);
|
|
109
|
+
if (profiles === null) {
|
|
110
|
+
return changed;
|
|
111
|
+
}
|
|
112
|
+
for (const value of Object.values(profiles)) {
|
|
113
|
+
const entry = asObject(value);
|
|
114
|
+
if (entry === null || !Array.isArray(entry.mix)) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
for (const armValue of entry.mix as unknown[]) {
|
|
118
|
+
const arm = asObject(armValue);
|
|
119
|
+
if (arm === null) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const replacement = remapProfileName(arm.profile);
|
|
123
|
+
if (replacement !== arm.profile) {
|
|
124
|
+
arm.profile = replacement;
|
|
125
|
+
changed = true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return changed;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function remapProfileName(value: unknown): unknown {
|
|
134
|
+
if (typeof value !== "string") {
|
|
135
|
+
return value;
|
|
136
|
+
}
|
|
137
|
+
return BACKUP_TO_PRIMARY[value] ?? value;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Rewrite conversation and schedule pins, retrying transient DB contention. */
|
|
141
|
+
async function rewriteDbReferences(workspaceDir: string): Promise<void> {
|
|
142
|
+
const path = join(workspaceDir, "data", "db", "assistant.db");
|
|
143
|
+
if (!existsSync(path)) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
await withDbRetry(() => {
|
|
148
|
+
const db = new Database(path);
|
|
149
|
+
try {
|
|
150
|
+
for (const table of PROFILE_PIN_TABLES) {
|
|
151
|
+
if (!tableHasColumn(db, table, "inference_profile")) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
for (const [backup, primary] of Object.entries(BACKUP_TO_PRIMARY)) {
|
|
155
|
+
db.query(
|
|
156
|
+
`UPDATE ${table} SET inference_profile = ? WHERE inference_profile = ?`,
|
|
157
|
+
).run(primary, backup);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} finally {
|
|
161
|
+
db.close();
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function tableHasColumn(
|
|
167
|
+
db: Database,
|
|
168
|
+
table: (typeof PROFILE_PIN_TABLES)[number],
|
|
169
|
+
column: string,
|
|
170
|
+
): boolean {
|
|
171
|
+
const rows = db.query(`PRAGMA table_info(${table})`).all() as Array<{
|
|
172
|
+
name?: unknown;
|
|
173
|
+
}>;
|
|
174
|
+
return rows.some((row) => row.name === column);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function withDbRetry(attempt: () => void): Promise<void> {
|
|
178
|
+
for (let index = 0; ; index += 1) {
|
|
179
|
+
try {
|
|
180
|
+
attempt();
|
|
181
|
+
return;
|
|
182
|
+
} catch (err) {
|
|
183
|
+
if (index >= DB_ATTEMPTS - 1) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
`Could not repoint backup-profile selections after ${DB_ATTEMPTS} attempts`,
|
|
186
|
+
{ cause: err },
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
log.warn(
|
|
190
|
+
{ err, attempt: index },
|
|
191
|
+
"Could not repoint backup-profile selections; retrying",
|
|
192
|
+
);
|
|
193
|
+
await Bun.sleep(DB_RETRY_BASE_DELAY_MS * 2 ** index);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
199
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function asObject(value: unknown): Record<string, unknown> | null {
|
|
203
|
+
return isPlainObject(value) ? value : null;
|
|
204
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Fold the Flux provider ids back into their parent plus a model family.
|
|
8
|
+
*
|
|
9
|
+
* Flux shipped as its own `services.stt.provider` value, which made a model
|
|
10
|
+
* choice look like a provider choice. That cost an entry in the provider
|
|
11
|
+
* enum, a row in every settings picker, and a place in each
|
|
12
|
+
* managed-versus-BYOK predicate for a backend that shares its parent's
|
|
13
|
+
* credential and account. Model families now live where the rest of a
|
|
14
|
+
* provider's settings do:
|
|
15
|
+
*
|
|
16
|
+
* provider: "deepgram-flux" -> provider: "deepgram"
|
|
17
|
+
* providers.deepgram.model: "flux"
|
|
18
|
+
*
|
|
19
|
+
* The same rewrite applies to the managed pair. Any other provider value is
|
|
20
|
+
* left untouched, and an existing `providers.<parent>` entry keeps every key
|
|
21
|
+
* it already had.
|
|
22
|
+
*
|
|
23
|
+
* The same pass drops any `providers.<id>.model` a known provider cannot
|
|
24
|
+
* serve. That key was free-form before this change and read by nothing, so
|
|
25
|
+
* existing values carry no meaning, but the schema validates it now: leaving
|
|
26
|
+
* a stale one behind would fail the parse and drop the workspace onto the
|
|
27
|
+
* loader's salvage path, which resets the entire `services` section and takes
|
|
28
|
+
* unrelated STT and TTS settings with it.
|
|
29
|
+
*
|
|
30
|
+
* Idempotent: a config already naming a parent provider has nothing to
|
|
31
|
+
* rewrite, and a model key already naming a family it can serve is left
|
|
32
|
+
* alone.
|
|
33
|
+
*/
|
|
34
|
+
const FLUX_PROVIDER_PARENTS: Record<string, string> = {
|
|
35
|
+
"deepgram-flux": "deepgram",
|
|
36
|
+
"vellum-flux": "vellum",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The model families each provider served when this migration was written,
|
|
41
|
+
* inlined rather than read from the provider catalog.
|
|
42
|
+
*
|
|
43
|
+
* A published migration has to behave identically every time it runs, and it
|
|
44
|
+
* reruns on newly initialized workspaces and after an interrupted checkpoint.
|
|
45
|
+
* Reading the live catalog would let a later change to it alter what this
|
|
46
|
+
* migration deletes from configs it has already seen.
|
|
47
|
+
*/
|
|
48
|
+
const KNOWN_MODEL_FAMILIES: Record<string, readonly string[]> = {
|
|
49
|
+
deepgram: ["nova-3", "flux"],
|
|
50
|
+
vellum: ["nova-3", "flux"],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const sttFluxProviderToModelFamilyMigration: WorkspaceMigration = {
|
|
54
|
+
id: "150-stt-flux-provider-to-model-family",
|
|
55
|
+
description:
|
|
56
|
+
"Rewrite services.stt.provider Flux ids to the parent provider plus providers.<id>.model",
|
|
57
|
+
run(workspaceDir: string): void {
|
|
58
|
+
const configPath = join(workspaceDir, "config.json");
|
|
59
|
+
if (!existsSync(configPath)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let config: Record<string, unknown>;
|
|
64
|
+
try {
|
|
65
|
+
config = JSON.parse(readFileSync(configPath, "utf8")) as Record<
|
|
66
|
+
string,
|
|
67
|
+
unknown
|
|
68
|
+
>;
|
|
69
|
+
} catch {
|
|
70
|
+
// A config that does not parse is the loader's problem to report, not
|
|
71
|
+
// this migration's to guess at.
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const services = asRecord(config.services);
|
|
76
|
+
const stt = asRecord(services?.stt);
|
|
77
|
+
if (!stt || typeof stt.provider !== "string") {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const providers = asRecord(stt.providers) ?? {};
|
|
82
|
+
let changed = dropUnservableModels(providers);
|
|
83
|
+
|
|
84
|
+
const parent = FLUX_PROVIDER_PARENTS[stt.provider];
|
|
85
|
+
if (parent !== undefined) {
|
|
86
|
+
stt.provider = parent;
|
|
87
|
+
const parentSettings = asRecord(providers[parent]) ?? {};
|
|
88
|
+
parentSettings.model = "flux";
|
|
89
|
+
providers[parent] = parentSettings;
|
|
90
|
+
changed = true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!changed) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
stt.providers = providers;
|
|
98
|
+
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
down(_workspaceDir: string): void {
|
|
102
|
+
// Forward-only: the Flux provider ids are gone from the config enum, so
|
|
103
|
+
// restoring one would produce a config the schema rejects.
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Remove `model` values a provider known at the time of writing cannot serve.
|
|
109
|
+
* Entries for any other provider are left untouched: that map is deliberately
|
|
110
|
+
* open to ids from future builds, and the schema does not validate them
|
|
111
|
+
* either.
|
|
112
|
+
*/
|
|
113
|
+
function dropUnservableModels(providers: Record<string, unknown>): boolean {
|
|
114
|
+
let changed = false;
|
|
115
|
+
for (const [providerId, value] of Object.entries(providers)) {
|
|
116
|
+
const settings = asRecord(value);
|
|
117
|
+
if (!settings || settings.model === undefined) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const families = KNOWN_MODEL_FAMILIES[providerId];
|
|
121
|
+
if (families === undefined) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (
|
|
125
|
+
typeof settings.model !== "string" ||
|
|
126
|
+
!families.includes(settings.model)
|
|
127
|
+
) {
|
|
128
|
+
delete settings.model;
|
|
129
|
+
changed = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return changed;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function asRecord(value: unknown): Record<string, unknown> | null {
|
|
136
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
137
|
+
? (value as Record<string, unknown>)
|
|
138
|
+
: null;
|
|
139
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { describe, expect, test } from "bun:test";
|
|
5
|
+
|
|
6
|
+
import { sttFluxProviderToModelFamilyMigration } from "../150-stt-flux-provider-to-model-family.js";
|
|
7
|
+
import { WORKSPACE_MIGRATIONS } from "../registry.js";
|
|
8
|
+
|
|
9
|
+
function workspaceWith(config: unknown): string {
|
|
10
|
+
const dir = mkdtempSync(join(tmpdir(), "stt-flux-migration-"));
|
|
11
|
+
writeFileSync(join(dir, "config.json"), JSON.stringify(config, null, 2));
|
|
12
|
+
return dir;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function readConfig(dir: string): any {
|
|
16
|
+
return JSON.parse(readFileSync(join(dir, "config.json"), "utf8"));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe("150-stt-flux-provider-to-model-family", () => {
|
|
20
|
+
test("is registered as the newest migration", () => {
|
|
21
|
+
expect(sttFluxProviderToModelFamilyMigration.id).toBe(
|
|
22
|
+
"150-stt-flux-provider-to-model-family",
|
|
23
|
+
);
|
|
24
|
+
expect(WORKSPACE_MIGRATIONS.at(-1)?.id).toBe(
|
|
25
|
+
"150-stt-flux-provider-to-model-family",
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("rewrites a Flux provider id to its parent plus a model family", () => {
|
|
30
|
+
const dir = workspaceWith({
|
|
31
|
+
services: { stt: { provider: "deepgram-flux", providers: {} } },
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
sttFluxProviderToModelFamilyMigration.run(dir);
|
|
35
|
+
|
|
36
|
+
expect(readConfig(dir).services.stt).toEqual({
|
|
37
|
+
provider: "deepgram",
|
|
38
|
+
providers: { deepgram: { model: "flux" } },
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("rewrites the managed pair the same way", () => {
|
|
43
|
+
const dir = workspaceWith({
|
|
44
|
+
services: { stt: { provider: "vellum-flux", providers: {} } },
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
sttFluxProviderToModelFamilyMigration.run(dir);
|
|
48
|
+
|
|
49
|
+
expect(readConfig(dir).services.stt.provider).toBe("vellum");
|
|
50
|
+
expect(readConfig(dir).services.stt.providers.vellum.model).toBe("flux");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("keeps existing settings on the parent's entry", () => {
|
|
54
|
+
const dir = workspaceWith({
|
|
55
|
+
services: {
|
|
56
|
+
stt: {
|
|
57
|
+
provider: "deepgram-flux",
|
|
58
|
+
providers: { deepgram: { someExistingKey: 1 } },
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
sttFluxProviderToModelFamilyMigration.run(dir);
|
|
64
|
+
|
|
65
|
+
expect(readConfig(dir).services.stt.providers.deepgram).toEqual({
|
|
66
|
+
someExistingKey: 1,
|
|
67
|
+
model: "flux",
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("drops a model a known provider cannot serve", () => {
|
|
72
|
+
// That key was free-form and read by nothing before this change, so an
|
|
73
|
+
// existing value is meaningless -- but the schema validates it now, and
|
|
74
|
+
// leaving one behind drops the workspace onto the loader's salvage path,
|
|
75
|
+
// which resets the whole services section.
|
|
76
|
+
const dir = workspaceWith({
|
|
77
|
+
services: {
|
|
78
|
+
stt: {
|
|
79
|
+
provider: "deepgram",
|
|
80
|
+
providers: { deepgram: { model: "nova-2", keepMe: true } },
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
sttFluxProviderToModelFamilyMigration.run(dir);
|
|
86
|
+
|
|
87
|
+
expect(readConfig(dir).services.stt.providers.deepgram).toEqual({
|
|
88
|
+
keepMe: true,
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("keeps a model the provider can serve", () => {
|
|
93
|
+
const dir = workspaceWith({
|
|
94
|
+
services: {
|
|
95
|
+
stt: {
|
|
96
|
+
provider: "deepgram",
|
|
97
|
+
providers: { deepgram: { model: "flux" } },
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
sttFluxProviderToModelFamilyMigration.run(dir);
|
|
103
|
+
|
|
104
|
+
expect(readConfig(dir).services.stt.providers.deepgram.model).toBe("flux");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("leaves entries for providers the catalog does not know", () => {
|
|
108
|
+
// The map is deliberately open to ids from future builds, and the schema
|
|
109
|
+
// does not validate those either.
|
|
110
|
+
const before = {
|
|
111
|
+
services: {
|
|
112
|
+
stt: {
|
|
113
|
+
provider: "deepgram",
|
|
114
|
+
providers: { "future-provider": { model: "next-gen" } },
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
const dir = workspaceWith(before);
|
|
119
|
+
|
|
120
|
+
sttFluxProviderToModelFamilyMigration.run(dir);
|
|
121
|
+
|
|
122
|
+
expect(readConfig(dir)).toEqual(before);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("leaves a non-Flux provider untouched", () => {
|
|
126
|
+
const before = {
|
|
127
|
+
services: { stt: { provider: "deepgram", providers: {} } },
|
|
128
|
+
};
|
|
129
|
+
const dir = workspaceWith(before);
|
|
130
|
+
|
|
131
|
+
sttFluxProviderToModelFamilyMigration.run(dir);
|
|
132
|
+
|
|
133
|
+
expect(readConfig(dir)).toEqual(before);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("is idempotent", () => {
|
|
137
|
+
const dir = workspaceWith({
|
|
138
|
+
services: { stt: { provider: "deepgram-flux", providers: {} } },
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
sttFluxProviderToModelFamilyMigration.run(dir);
|
|
142
|
+
const once = readConfig(dir);
|
|
143
|
+
sttFluxProviderToModelFamilyMigration.run(dir);
|
|
144
|
+
|
|
145
|
+
expect(readConfig(dir)).toEqual(once);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("does nothing without a config file, or with an unparseable one", () => {
|
|
149
|
+
const empty = mkdtempSync(join(tmpdir(), "stt-flux-migration-"));
|
|
150
|
+
expect(() =>
|
|
151
|
+
sttFluxProviderToModelFamilyMigration.run(empty),
|
|
152
|
+
).not.toThrow();
|
|
153
|
+
|
|
154
|
+
const broken = mkdtempSync(join(tmpdir(), "stt-flux-migration-"));
|
|
155
|
+
writeFileSync(join(broken, "config.json"), "{not json");
|
|
156
|
+
expect(() =>
|
|
157
|
+
sttFluxProviderToModelFamilyMigration.run(broken),
|
|
158
|
+
).not.toThrow();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
@@ -144,6 +144,10 @@ import { repairDeprecatedCodexModelIdMigration } from "./143-repair-deprecated-c
|
|
|
144
144
|
import { convertStrandedSubscriptionOpenaiProfilesMigration } from "./144-convert-stranded-subscription-openai-profiles.js";
|
|
145
145
|
import { collapseProfileBindingsToEntriesMigration } from "./145-collapse-profile-bindings-to-entries.js";
|
|
146
146
|
import { repairRetiredFireworksDeepseekFlashModelIdMigration } from "./146-repair-retired-fireworks-deepseek-flash-model-id.js";
|
|
147
|
+
import { renameCollidingBackupProfileNamesMigration } from "./147-rename-colliding-backup-profile-names.js";
|
|
148
|
+
import { stripUnsupportedFallbackProfilesMigration } from "./148-strip-unsupported-fallback-profiles.js";
|
|
149
|
+
import { repointBackupProfileSelectionsMigration } from "./149-repoint-backup-profile-selections.js";
|
|
150
|
+
import { sttFluxProviderToModelFamilyMigration } from "./150-stt-flux-provider-to-model-family.js";
|
|
147
151
|
import { migrateToWorkspaceVolumeMigration } from "./migrate-to-workspace-volume.js";
|
|
148
152
|
import type { WorkspaceMigration } from "./types.js";
|
|
149
153
|
|
|
@@ -303,4 +307,8 @@ export const WORKSPACE_MIGRATIONS: WorkspaceMigration[] = [
|
|
|
303
307
|
convertStrandedSubscriptionOpenaiProfilesMigration,
|
|
304
308
|
collapseProfileBindingsToEntriesMigration,
|
|
305
309
|
repairRetiredFireworksDeepseekFlashModelIdMigration,
|
|
310
|
+
renameCollidingBackupProfileNamesMigration,
|
|
311
|
+
stripUnsupportedFallbackProfilesMigration,
|
|
312
|
+
repointBackupProfileSelectionsMigration,
|
|
313
|
+
sttFluxProviderToModelFamilyMigration,
|
|
306
314
|
];
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
|
|
3
|
-
import { isAllowDecision } from "../permissions/types.js";
|
|
4
|
-
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
// Tests
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
|
-
|
|
9
|
-
describe("isAllowDecision", () => {
|
|
10
|
-
test("returns true for 'allow'", () => {
|
|
11
|
-
expect(isAllowDecision("allow")).toBe(true);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test("returns false for 'deny'", () => {
|
|
15
|
-
expect(isAllowDecision("deny")).toBe(false);
|
|
16
|
-
});
|
|
17
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Daemon-side reader for how much Discord admits.
|
|
3
|
-
*
|
|
4
|
-
* The gateway owns the allow-list and the drop decision it feeds; the
|
|
5
|
-
* readiness surface that reports channel setup to the user lives here. This is
|
|
6
|
-
* the relay between them, and it exists for the same reason the socket-health
|
|
7
|
-
* relay does: the fact lives on one side of the boundary and is reported from
|
|
8
|
-
* the other.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
type DiscordAdmissionIpcResponse,
|
|
13
|
-
DiscordAdmissionIpcResponseSchema,
|
|
14
|
-
} from "@vellumai/gateway-client/gateway-ipc-contracts";
|
|
15
|
-
|
|
16
|
-
import { ipcCallPersistentValidated } from "../ipc/gateway-validated-call.js";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Ask the gateway how many channels Discord's allow-list admits.
|
|
20
|
-
*
|
|
21
|
-
* Throws on transport failure rather than reporting zero: an unreachable
|
|
22
|
-
* gateway is a fact about the gateway, and answering zero would tell an
|
|
23
|
-
* operator their allow-list is empty when nobody looked. Callers treat a throw
|
|
24
|
-
* as indeterminate.
|
|
25
|
-
*/
|
|
26
|
-
export async function readDiscordAdmission(): Promise<DiscordAdmissionIpcResponse> {
|
|
27
|
-
return ipcCallPersistentValidated(
|
|
28
|
-
"discord_admission",
|
|
29
|
-
{},
|
|
30
|
-
DiscordAdmissionIpcResponseSchema,
|
|
31
|
-
);
|
|
32
|
-
}
|