@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
|
@@ -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
|
-
}
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Fork message-copy — off-event-loop bulk copy of a conversation's messages.
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
//
|
|
5
|
-
// The fork-based memory retrospective copies the visible tail of the source
|
|
6
|
-
// conversation's message rows (rows at-or-after the inherited compaction
|
|
7
|
-
// boundary) into a throwaway background conversation. Done in-process via
|
|
8
|
-
// `bun:sqlite` (synchronous), that copy is the single longest uninterruptible
|
|
9
|
-
// block on the daemon's event loop — on a multi-GB database it pegs the CPU
|
|
10
|
-
// for minutes, stalling `/healthz` and the gateway's IPC calls (see the
|
|
11
|
-
// runtime-freeze investigation).
|
|
12
|
-
//
|
|
13
|
-
// This module moves the message-row copy off the event loop via
|
|
14
|
-
// {@link runAsyncSqlite}, which runs the statements in a `sqlite3` CLI
|
|
15
|
-
// subprocess (its own connection; SQLite file-locking arbitrates with the
|
|
16
|
-
// in-process handle). The content/metadata never round-trip through JS — they
|
|
17
|
-
// are copied SELECT→INSERT inside SQLite — so there is no string-escaping
|
|
18
|
-
// hazard and the heavy bytes stay in the database.
|
|
19
|
-
//
|
|
20
|
-
// Two properties matter for correctness:
|
|
21
|
-
//
|
|
22
|
-
// 1. **Lock-friendly batching.** The main connection runs `busy_timeout=5000`
|
|
23
|
-
// (`db-connection.ts`). A single `INSERT … SELECT` over the whole history
|
|
24
|
-
// is one implicit transaction that holds the write lock for its full
|
|
25
|
-
// duration — a concurrent in-process write (a live user turn persisting a
|
|
26
|
-
// message) would then block up to 5 s and throw `SQLITE_BUSY`. So the copy
|
|
27
|
-
// is split into batches that each auto-commit, releasing the lock between
|
|
28
|
-
// batches so in-process writers slip in.
|
|
29
|
-
//
|
|
30
|
-
// 2. **`cloneForkMessageMetadata` parity.** The in-process fork stamps
|
|
31
|
-
// `forkSourceMessageId` onto each copied row's metadata. The SQL `CASE`
|
|
32
|
-
// below is a faithful translation of that helper's three branches
|
|
33
|
-
// (object → preserve-or-stamp; null/non-object/invalid → fresh object).
|
|
34
|
-
// `client_message_id` is intentionally NOT copied, matching the
|
|
35
|
-
// in-process fork (a forked row is not a client-submitted message).
|
|
36
|
-
|
|
37
|
-
import { setTimeout as sleep } from "node:timers/promises";
|
|
38
|
-
|
|
39
|
-
import { BULK_BATCH_TIMEOUT_MS, withBulkWriteGate } from "./bulk-write-gate.js";
|
|
40
|
-
import {
|
|
41
|
-
type AsyncSqliteBackend,
|
|
42
|
-
type AsyncSqliteResult,
|
|
43
|
-
runAsyncSqlite,
|
|
44
|
-
} from "./db-async-query.js";
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Default batch size for the chunked copy. Each batch is one `INSERT … SELECT`
|
|
48
|
-
* that auto-commits, so this bounds how long the subprocess holds the write
|
|
49
|
-
* lock before releasing it to in-process writers. Kept small so the worst-case
|
|
50
|
-
* wait for a contending foreground write is one short batch, even on a bloated
|
|
51
|
-
* database; per-batch statement overhead stays negligible against the row copy
|
|
52
|
-
* and fork latency doesn't matter (nobody waits on a background fork).
|
|
53
|
-
*/
|
|
54
|
-
export const DEFAULT_FORK_COPY_BATCH_SIZE = 50;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Pause inserted between batch subprocess calls. Without it the copy releases
|
|
58
|
-
* the write lock on each batch's auto-commit but greedily re-acquires it
|
|
59
|
-
* microseconds later, so a concurrent in-process writer (a live user turn
|
|
60
|
-
* persisting a message) can lose every race. A brief yield lets foreground
|
|
61
|
-
* writes reliably slip in between batches. The extra fork latency is free —
|
|
62
|
-
* nothing waits on a background fork — so we trade copy speed for foreground
|
|
63
|
-
* fairness.
|
|
64
|
-
*/
|
|
65
|
-
export const DEFAULT_FORK_COPY_INTER_BATCH_DELAY_MS = 25;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* A single source→fork message-id mapping. `oldId` is an existing source
|
|
69
|
-
* message id; `newId` is the freshly-generated id the fork row will carry.
|
|
70
|
-
* Generated by the caller (in JS) so the same map drives both this copy and
|
|
71
|
-
* the in-process attachment relink that follows.
|
|
72
|
-
*/
|
|
73
|
-
export interface ForkIdPair {
|
|
74
|
-
oldId: string;
|
|
75
|
-
newId: string;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export interface CopyForkMessagesOptions {
|
|
79
|
-
/** The fork conversation id every copied row is assigned to. */
|
|
80
|
-
forkConversationId: string;
|
|
81
|
-
/** Ordered source→fork id pairs for every message to copy. */
|
|
82
|
-
idPairs: readonly ForkIdPair[];
|
|
83
|
-
/** Override the per-batch row count (see {@link DEFAULT_FORK_COPY_BATCH_SIZE}). */
|
|
84
|
-
batchSize?: number;
|
|
85
|
-
/** Test-only passthrough to force the in-process backend. */
|
|
86
|
-
forceInProcess?: boolean;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Server-generated ids only ever use this charset. We interpolate ids (never
|
|
90
|
-
// message content) into the SQL script, so reject anything outside it as a
|
|
91
|
-
// defense-in-depth guard against a malformed id breaking out of the literal.
|
|
92
|
-
const SAFE_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
93
|
-
|
|
94
|
-
function assertSafeId(id: string): void {
|
|
95
|
-
if (!SAFE_ID.test(id)) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`fork message-copy: unsafe id literal: ${JSON.stringify(id)}`,
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* SQL translation of `cloneForkMessageMetadata`. `m` is the source `messages`
|
|
104
|
-
* row alias; the stamped value is the SOURCE message id (`m.id`), preserving an
|
|
105
|
-
* existing `forkSourceMessageId` when the metadata is already an object.
|
|
106
|
-
*/
|
|
107
|
-
const METADATA_CLONE_EXPR = `CASE
|
|
108
|
-
WHEN json_valid(m.metadata) AND json_type(m.metadata) = 'object'
|
|
109
|
-
THEN json_set(m.metadata, '$.forkSourceMessageId',
|
|
110
|
-
coalesce(json_extract(m.metadata, '$.forkSourceMessageId'), m.id))
|
|
111
|
-
ELSE json_object('forkSourceMessageId', m.id)
|
|
112
|
-
END`;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Build the multi-statement SQL script that copies the given id pairs into the
|
|
116
|
-
* fork conversation in lock-friendly batches. Exported for unit testing the
|
|
117
|
-
* generated SQL without spawning a subprocess.
|
|
118
|
-
*/
|
|
119
|
-
export function buildForkCopyScript(options: CopyForkMessagesOptions): string {
|
|
120
|
-
const { forkConversationId, idPairs } = options;
|
|
121
|
-
assertSafeId(forkConversationId);
|
|
122
|
-
const batchSize = Math.max(
|
|
123
|
-
1,
|
|
124
|
-
options.batchSize ?? DEFAULT_FORK_COPY_BATCH_SIZE,
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
const statements: string[] = [
|
|
128
|
-
// Connection-scoped staging table holding the current batch's id map. The
|
|
129
|
-
// unqualified `messages` reference in the SELECT resolves to the main DB.
|
|
130
|
-
`CREATE TEMP TABLE IF NOT EXISTS _fork_id_map (old_id TEXT PRIMARY KEY, new_id TEXT NOT NULL);`,
|
|
131
|
-
];
|
|
132
|
-
|
|
133
|
-
for (let i = 0; i < idPairs.length; i += batchSize) {
|
|
134
|
-
const batch = idPairs.slice(i, i + batchSize);
|
|
135
|
-
const values = batch
|
|
136
|
-
.map(({ oldId, newId }) => {
|
|
137
|
-
assertSafeId(oldId);
|
|
138
|
-
assertSafeId(newId);
|
|
139
|
-
return `('${oldId}','${newId}')`;
|
|
140
|
-
})
|
|
141
|
-
.join(",");
|
|
142
|
-
|
|
143
|
-
// Each batch auto-commits (no surrounding BEGIN), so the write lock is
|
|
144
|
-
// released between batches for in-process writers.
|
|
145
|
-
statements.push(`DELETE FROM _fork_id_map;`);
|
|
146
|
-
statements.push(
|
|
147
|
-
`INSERT INTO _fork_id_map (old_id, new_id) VALUES ${values};`,
|
|
148
|
-
);
|
|
149
|
-
statements.push(
|
|
150
|
-
`INSERT INTO messages (id, conversation_id, role, content, created_at, metadata)
|
|
151
|
-
SELECT map.new_id, '${forkConversationId}', m.role, m.content, m.created_at, ${METADATA_CLONE_EXPR}
|
|
152
|
-
FROM messages m JOIN _fork_id_map map ON map.old_id = m.id;`,
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Drop the staging table so the in-process fallback (which runs on the shared
|
|
157
|
-
// daemon connection) does not leave it lingering; harmless for the subprocess
|
|
158
|
-
// backend, whose connection is discarded on exit.
|
|
159
|
-
statements.push(`DROP TABLE IF EXISTS _fork_id_map;`);
|
|
160
|
-
|
|
161
|
-
return statements.join("\n");
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Copy the message rows for a fork off the event loop, in lock-friendly
|
|
166
|
-
* batches. Each batch runs as its own subprocess call with a brief yield in
|
|
167
|
-
* between (see {@link DEFAULT_FORK_COPY_INTER_BATCH_DELAY_MS}) so foreground
|
|
168
|
-
* writers reliably acquire the write lock between batches instead of losing
|
|
169
|
-
* every race to the copy's greedy lock re-acquisition. The whole batch stream
|
|
170
|
-
* runs under the process-wide {@link withBulkWriteGate} so two copies (or a
|
|
171
|
-
* copy and a batched delete) never convoy on the write lock — and the yields
|
|
172
|
-
* go to foreground writers, not a sibling bulk stream. Resolves once every
|
|
173
|
-
* batch has committed (or returns the failing batch's `ok: false` result on
|
|
174
|
-
* subprocess failure — the caller is responsible for cleaning up the
|
|
175
|
-
* partially-built fork).
|
|
176
|
-
*
|
|
177
|
-
* No-op (returns a synthetic ok result) when there is nothing to copy.
|
|
178
|
-
*/
|
|
179
|
-
export async function copyForkMessagesViaSubprocess(
|
|
180
|
-
options: CopyForkMessagesOptions,
|
|
181
|
-
): Promise<AsyncSqliteResult> {
|
|
182
|
-
if (options.idPairs.length === 0) {
|
|
183
|
-
return {
|
|
184
|
-
ok: true,
|
|
185
|
-
backend: "in-process-blocking",
|
|
186
|
-
error: null,
|
|
187
|
-
elapsedMs: 0,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return await withBulkWriteGate(
|
|
192
|
-
`fork-message-copy:${options.forkConversationId}`,
|
|
193
|
-
() => copyBatches(options),
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async function copyBatches(
|
|
198
|
-
options: CopyForkMessagesOptions,
|
|
199
|
-
): Promise<AsyncSqliteResult> {
|
|
200
|
-
const batchSize = Math.max(
|
|
201
|
-
1,
|
|
202
|
-
options.batchSize ?? DEFAULT_FORK_COPY_BATCH_SIZE,
|
|
203
|
-
);
|
|
204
|
-
const runOptions = options.forceInProcess
|
|
205
|
-
? { forceBackend: "in-process-blocking" as const }
|
|
206
|
-
: {};
|
|
207
|
-
|
|
208
|
-
let totalElapsedMs = 0;
|
|
209
|
-
let backend: AsyncSqliteBackend = "in-process-blocking";
|
|
210
|
-
|
|
211
|
-
for (let i = 0; i < options.idPairs.length; i += batchSize) {
|
|
212
|
-
const batch = options.idPairs.slice(i, i + batchSize);
|
|
213
|
-
// One subprocess call per batch. Each generated script is self-contained
|
|
214
|
-
// (it creates and drops its own staging table), so splitting execution
|
|
215
|
-
// across calls is safe — and it's what lets us yield between batches below.
|
|
216
|
-
const sql = buildForkCopyScript({
|
|
217
|
-
forkConversationId: options.forkConversationId,
|
|
218
|
-
idPairs: batch,
|
|
219
|
-
batchSize,
|
|
220
|
-
});
|
|
221
|
-
const result = await runAsyncSqlite(
|
|
222
|
-
sql,
|
|
223
|
-
`fork-message-copy:copy-batch:${options.forkConversationId}`,
|
|
224
|
-
{ ...runOptions, timeoutMs: BULK_BATCH_TIMEOUT_MS },
|
|
225
|
-
);
|
|
226
|
-
totalElapsedMs += result.elapsedMs;
|
|
227
|
-
backend = result.backend;
|
|
228
|
-
if (!result.ok) {
|
|
229
|
-
return { ...result, elapsedMs: totalElapsedMs };
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const isLastBatch = i + batchSize >= options.idPairs.length;
|
|
233
|
-
if (!isLastBatch) {
|
|
234
|
-
await sleep(DEFAULT_FORK_COPY_INTER_BATCH_DELAY_MS);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return { ok: true, backend, error: null, elapsedMs: totalElapsedMs };
|
|
239
|
-
}
|