@vellumai/assistant 0.12.1-staging.1 → 0.12.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/AGENTS.md +0 -4
- package/ARCHITECTURE.md +12 -11
- package/docs/architecture/turn-actor.md +8 -15
- package/openapi.yaml +1 -291
- package/package.json +1 -1
- package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
- package/src/__tests__/app-compiler.test.ts +0 -6
- package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
- package/src/__tests__/app-dir-path-guard.test.ts +3 -1
- package/src/__tests__/app-source-watcher.test.ts +218 -0
- package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
- package/src/__tests__/computer-use-tools.test.ts +5 -17
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +29 -28
- package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
- package/src/__tests__/config-watcher.test.ts +8 -23
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +0 -26
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
- package/src/__tests__/conversation-queue.test.ts +207 -48
- package/src/__tests__/conversation-retry-discard.test.ts +1 -54
- package/src/__tests__/conversation-skill-tools.test.ts +0 -27
- package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
- package/src/__tests__/conversation-title-service.test.ts +10 -14
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
- package/src/__tests__/credential-record-retire.test.ts +1 -171
- package/src/__tests__/credential-routes.test.ts +3 -212
- package/src/__tests__/credential-security-invariants.test.ts +1 -2
- package/src/__tests__/cu-unified-flow.test.ts +2 -8
- package/src/__tests__/drain-kick-guard.test.ts +2 -0
- package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/host-bash-proxy.test.ts +45 -26
- package/src/__tests__/host-browser-proxy.test.ts +17 -6
- package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
- package/src/__tests__/host-file-proxy.test.ts +23 -11
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
- package/src/__tests__/llm-catalog-parity.test.ts +0 -25
- package/src/__tests__/mcp-auth-routes.test.ts +9 -6
- package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
- package/src/__tests__/mcp-health-check.test.ts +11 -8
- package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
- package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
- package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
- package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
- package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +548 -355
- package/src/__tests__/model-intents.test.ts +0 -3
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
- package/src/__tests__/script-proxy-certs.test.ts +0 -35
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/speaker-identification.test.ts +56 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
- package/src/__tests__/subagent-tools.test.ts +2 -3
- package/src/__tests__/telephony-tts-guard.test.ts +3 -38
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
- package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
- package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
- package/src/__tests__/workspace-git-service.test.ts +0 -26
- package/src/acp/__tests__/agent-process.test.ts +4 -258
- package/src/acp/__tests__/auth-required.test.ts +0 -96
- package/src/acp/__tests__/client-handler.test.ts +2 -90
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
- package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
- package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
- package/src/acp/__tests__/session-manager.test.ts +4 -895
- package/src/acp/agent-process.test.ts +1 -4
- package/src/acp/agent-process.ts +9 -94
- package/src/acp/auth-required.ts +1 -50
- package/src/acp/auto-install.test.ts +7 -9
- package/src/acp/client-handler.ts +3 -16
- package/src/acp/resolve-agent.test.ts +6 -220
- package/src/acp/resolve-agent.ts +23 -88
- package/src/acp/session-manager.test.ts +3 -196
- package/src/acp/session-manager.ts +18 -441
- package/src/acp/types.ts +5 -50
- package/src/api/events/app-files-changed.ts +3 -4
- package/src/api/index.ts +0 -6
- package/src/apps/app-store.ts +1 -1
- package/src/bundler/app-compiler.ts +0 -15
- package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
- package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
- package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
- package/src/calls/call-constants.ts +4 -24
- package/src/calls/call-controller.ts +199 -499
- package/src/calls/call-transport.ts +0 -16
- package/src/calls/media-stream-output.ts +0 -32
- package/src/calls/media-stream-server.ts +30 -82
- package/src/calls/media-stream-stt-session.ts +0 -15
- package/src/calls/resolve-call-tts-provider.ts +2 -33
- package/src/calls/speaker-identification.ts +233 -0
- package/src/calls/tts-call-strategy.ts +5 -9
- package/src/calls/types.ts +0 -2
- package/src/calls/voice-control-protocol.ts +21 -53
- package/src/calls/voice-session-bridge.ts +46 -59
- package/src/calls/voice-triage-escalate.ts +56 -175
- package/src/cli/commands/apps.help.ts +13 -67
- package/src/cli/commands/apps.ts +0 -183
- package/src/cli/commands/channels/index.help.ts +2 -70
- package/src/cli/commands/channels/index.ts +3 -16
- package/src/cli/commands/credentials.help.ts +2 -6
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/roadmap.help.ts +1 -5
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +90 -103
- package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
- package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
- package/src/config/__tests__/platform-rehydration.test.ts +0 -93
- package/src/config/acp-defaults.test.ts +3 -13
- package/src/config/acp-defaults.ts +6 -23
- package/src/config/acp-schema.ts +2 -30
- package/src/config/bundled-skills/acp/SKILL.md +14 -22
- package/src/config/bundled-skills/acp/TOOLS.json +1 -5
- package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +12 -8
- package/src/config/memory-v3-gate.test.ts +0 -31
- package/src/config/memory-v3-gate.ts +16 -20
- package/src/config/platform-rehydration.ts +21 -75
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
- package/src/config/schemas/calls.ts +28 -1
- package/src/config/schemas/live-voice.ts +173 -1
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +0 -10
- package/src/config/schemas/skills.ts +14 -0
- package/src/credential-execution/process-manager.test.ts +19 -18
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
- package/src/daemon/app-source-watcher.ts +218 -0
- package/src/daemon/config-watcher.ts +194 -13
- package/src/daemon/conversation-process.ts +64 -35
- package/src/daemon/conversation-skill-tools.ts +31 -13
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +8 -10
- package/src/daemon/conversation-tool-setup.ts +43 -37
- package/src/daemon/conversation.ts +3 -0
- package/src/daemon/host-bash-proxy.ts +12 -8
- package/src/daemon/host-browser-proxy.ts +1 -15
- package/src/daemon/host-file-proxy.ts +10 -8
- package/src/daemon/host-transfer-proxy.ts +18 -14
- package/src/daemon/lifecycle.ts +5 -0
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/shutdown-handlers.ts +9 -1
- package/src/daemon/skill-memory-refresh.ts +0 -64
- package/src/daemon/tool-side-effects.ts +18 -7
- package/src/hooks/types.ts +0 -33
- package/src/inbound/platform-callback-registration.ts +5 -4
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
- package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
- package/src/live-voice/live-voice-session.ts +693 -213
- package/src/{calls → live-voice}/progress-narration.ts +2 -2
- package/src/live-voice/protocol.ts +2 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +45 -29
- package/src/mcp/startup.ts +4 -8
- package/src/messaging/provider.ts +3 -10
- package/src/messaging/providers/callback-routing.ts +0 -18
- package/src/messaging/providers/channel-transport.ts +0 -56
- package/src/messaging/providers/discord/transport.ts +0 -17
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
- package/src/messaging/providers/slack/adapter.ts +44 -7
- package/src/messaging/providers/slack/transport.ts +0 -16
- package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
- package/src/messaging/providers/telegram-bot/client.ts +26 -0
- package/src/messaging/providers/telegram-bot/transport.ts +0 -20
- package/src/messaging/providers/whatsapp/adapter.ts +48 -1
- package/src/messaging/providers/whatsapp/client.ts +29 -0
- package/src/messaging/providers/whatsapp/transport.ts +0 -18
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
- package/src/notifications/assistant-reply-producer.ts +3 -8
- package/src/notifications/conversation-pairing.ts +16 -36
- package/src/notifications/delivered-post-record.ts +1 -11
- package/src/notifications/home-feed-side-effect.ts +7 -55
- package/src/outbound-proxy/certs.ts +5 -3
- package/src/permissions/checker.test.ts +6 -11
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +63 -71
- package/src/persistence/conversation-lineage.ts +4 -12
- package/src/persistence/conversation-title-service.ts +26 -9
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-reads.ts +0 -30
- package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
- package/src/persistence/schema/memory-core.ts +0 -5
- package/src/platform/client.test.ts +0 -2
- package/src/platform/client.ts +10 -2
- package/src/plugin-api/constants.ts +0 -2
- package/src/plugin-api/index.ts +0 -1
- package/src/plugin-api/types.ts +0 -2
- package/src/plugins/defaults/index.ts +0 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
- package/src/plugins/defaults/memory/hooks/init.ts +0 -10
- package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
- package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
- package/src/plugins/defaults/memory/startup.ts +1 -6
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
- package/src/plugins/defaults/memory/worker.ts +0 -6
- package/src/plugins/mcp-servers.ts +75 -15
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/gemini/client.ts +23 -9
- package/src/providers/model-catalog.ts +0 -34
- package/src/providers/model-intents.ts +5 -10
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
- package/src/providers/openai/chat-completions-provider.ts +78 -192
- package/src/providers/openai/codex-models.ts +4 -0
- package/src/runtime/AGENTS.md +0 -2
- package/src/runtime/auth/same-actor.ts +3 -38
- package/src/runtime/http-server.ts +151 -160
- package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
- package/src/runtime/routes/acp-routes.test.ts +0 -15
- package/src/runtime/routes/acp-routes.ts +9 -72
- package/src/runtime/routes/app-management-routes.ts +0 -73
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +3 -14
- package/src/runtime/routes/conversation-query-routes.ts +0 -40
- package/src/runtime/routes/credential-routes.ts +10 -19
- package/src/runtime/routes/diagnostics-routes.ts +3 -55
- package/src/runtime/routes/index.ts +0 -4
- package/src/runtime/routes/log-export-routes.ts +0 -2
- package/src/runtime/routes/mcp-auth-routes.ts +47 -39
- package/src/runtime/routes/migration-routes.ts +21 -8
- package/src/runtime/routes/platform-routes.ts +15 -18
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
- package/src/runtime/services/conversation-serializer.ts +3 -16
- package/src/runtime/sync/resource-sync-events.ts +1 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/ces-rpc-record-backend.ts +0 -7
- package/src/subagent/consult-context.ts +25 -12
- package/src/tools/acp/list-agents.test.ts +1 -3
- package/src/tools/acp/spawn.test.ts +11 -146
- package/src/tools/acp/spawn.ts +3 -21
- package/src/tools/acp/status.ts +3 -40
- package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
- package/src/tools/capability-offer.test.ts +2 -22
- package/src/tools/capability-offer.ts +1 -16
- package/src/tools/computer-use/definitions.ts +2 -4
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +0 -100
- package/src/tools/host-filesystem/edit.test.ts +1 -2
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +1 -2
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +1 -2
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +1 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +0 -16
- package/src/tools/host-terminal/host-shell.ts +20 -4
- package/src/tools/policy-context.ts +7 -6
- package/src/tools/subagent/spawn.ts +8 -5
- package/src/tools/watch/watch-retro-report.ts +8 -0
- package/src/util/__tests__/language-subtag.test.ts +1 -23
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/language-subtag.ts +0 -16
- package/src/util/platform.ts +0 -8
- package/src/workspace/git-service.ts +54 -5
- package/src/workspace/migrations/registry.ts +0 -6
- package/scripts/smoke-desktop-window-theme.ts +0 -186
- package/src/__tests__/git-porcelain.test.ts +0 -47
- package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
- package/src/__tests__/resolve-app.test.ts +0 -135
- package/src/__tests__/source-fingerprint.test.ts +0 -184
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
- package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
- package/src/acp/model-config.test.ts +0 -166
- package/src/acp/model-config.ts +0 -138
- package/src/api/events/acp-session-model-update.test.ts +0 -88
- package/src/api/events/acp-session-model-update.ts +0 -46
- package/src/apps/resolve-app.ts +0 -81
- package/src/apps/source-fingerprint.ts +0 -266
- package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
- package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
- package/src/calls/barge-in-guard.ts +0 -118
- package/src/calls/voice-leg-coordinator.ts +0 -189
- package/src/calls/voice-progress-cadence.ts +0 -423
- package/src/cli/commands/__tests__/apps.test.ts +0 -245
- package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
- package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
- package/src/cli/commands/channels/send.ts +0 -128
- package/src/config/__tests__/platform-identity.test.ts +0 -117
- package/src/config/acp-agent-write.ts +0 -43
- package/src/config/acp-schema.test.ts +0 -81
- package/src/config/platform-identity.ts +0 -144
- package/src/config/schemas/__tests__/voice.test.ts +0 -148
- package/src/config/schemas/voice.ts +0 -150
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
- package/src/daemon/app-change-notify.ts +0 -45
- package/src/desktop/__tests__/fake-desktop.ts +0 -119
- package/src/desktop/desktop-chrome-policy.test.ts +0 -71
- package/src/desktop/desktop-chrome-policy.ts +0 -42
- package/src/desktop/desktop-dependencies.test.ts +0 -102
- package/src/desktop/desktop-dependencies.ts +0 -306
- package/src/desktop/desktop-feature.test.ts +0 -18
- package/src/desktop/desktop-feature.ts +0 -19
- package/src/desktop/desktop-panel-config.test.ts +0 -135
- package/src/desktop/desktop-panel-config.ts +0 -149
- package/src/desktop/desktop-session-manager.test.ts +0 -627
- package/src/desktop/desktop-session-manager.ts +0 -814
- package/src/desktop/desktop-stream-bridge.test.ts +0 -395
- package/src/desktop/desktop-stream-bridge.ts +0 -214
- package/src/desktop/desktop-wallpaper.test.ts +0 -191
- package/src/desktop/desktop-wallpaper.ts +0 -113
- package/src/desktop/desktop-window-theme.ts +0 -170
- package/src/i18n/AGENTS.md +0 -22
- package/src/i18n/__tests__/i18n.test.ts +0 -108
- package/src/i18n/index.ts +0 -16
- package/src/i18n/locales.ts +0 -93
- package/src/i18n/messages.ts +0 -61
- package/src/i18n/title.ts +0 -25
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
- package/src/mcp/spec-schema.ts +0 -111
- package/src/mcp/workspace-mcp-config.ts +0 -188
- package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
- package/src/persistence/conversation-title-placeholders.ts +0 -23
- package/src/persistence/message-cursor.ts +0 -78
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
- package/src/providers/gemini-thought-signature.test.ts +0 -63
- package/src/providers/gemini-thought-signature.ts +0 -44
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
- package/src/providers/openai/google-thought-signature.ts +0 -320
- package/src/runtime/__tests__/channel-send.test.ts +0 -443
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
- package/src/runtime/channel-send.ts +0 -316
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
- package/src/runtime/routes/channel-send-routes.ts +0 -85
- package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
- package/src/runtime/routes/desktop-setup-routes.ts +0 -35
- package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
- package/src/security/ces-http-record-backend.ts +0 -120
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
- package/src/skills/workspace-skill-md-signature.ts +0 -50
- package/src/tools/acp/status.test.ts +0 -94
- package/src/util/ca-bundle.ts +0 -13
- package/src/workspace/git-porcelain.ts +0 -66
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
- /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
|
@@ -53,10 +53,7 @@ describe("screen_point_at", () => {
|
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
expect(result.isError).toBe(true);
|
|
56
|
-
expect(result.content).toContain(
|
|
57
|
-
"The Vellum desktop app is needed to view or control your screen",
|
|
58
|
-
);
|
|
59
|
-
expect(result.content).toContain("https://www.vellum.ai/downloads");
|
|
56
|
+
expect(result.content).toContain("connected desktop client");
|
|
60
57
|
});
|
|
61
58
|
|
|
62
59
|
/** Drawing on the user's screen is a side effect a stopped turn must not have. */
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"tools": [
|
|
4
4
|
{
|
|
5
5
|
"name": "scaffold_managed_skill",
|
|
6
|
-
"description": "Create or update a managed skill in {workspaceDir}/skills. The skill becomes available for skill_load when a valid top-level SKILL.md is written under the skill directory. Never persist a skill without explicit user consent. Before persisting, test the snippet: write to a temp file with bash and run with `bun run /tmp/vellum-eval/snippet.ts`. Iterate up to 3 attempts, then ask the user. Clean up temp files after. Do not use file_write for temp files outside the working directory.",
|
|
6
|
+
"description": "Create or update a managed skill in {workspaceDir}/skills. The skill becomes available for skill_load when a valid top-level SKILL.md is written under the skill directory. Never persist a skill without explicit user consent. Before persisting, test the snippet: write to a temp file with bash and run with `bun run /tmp/vellum-eval/snippet.ts`. Iterate up to 3 attempts, then ask the user. Clean up temp files after. Do not use file_write for temp files outside the working directory. After a skill is written, the next turn may run in a recreated conversation due to file-watcher eviction - continue normally.",
|
|
7
7
|
"category": "skills",
|
|
8
8
|
"risk": "high",
|
|
9
9
|
"input_schema": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
"name": "delete_managed_skill",
|
|
95
|
-
"description": "Delete a managed skill directory from {workspaceDir}/skills. Never delete a skill without explicit user confirmation.",
|
|
95
|
+
"description": "Delete a managed skill directory from {workspaceDir}/skills. Never delete a skill without explicit user confirmation. After deletion, the next turn may run in a recreated conversation due to file-watcher eviction - continue normally.",
|
|
96
96
|
"category": "skills",
|
|
97
97
|
"risk": "high",
|
|
98
98
|
"input_schema": {
|
|
@@ -137,7 +137,7 @@ const VELLUM_PROFILE_IMPLS: ProfileImpls = {
|
|
|
137
137
|
// The managed latency class, also what the live-voice front model runs on.
|
|
138
138
|
// Its leading tokens are the turn-taking verdict, so what this profile
|
|
139
139
|
// optimizes is the tail of time-to-first-token rather than the median: a
|
|
140
|
-
// verdict slower than `
|
|
140
|
+
// verdict slower than `liveVoice.frontModel.endpointDecisionTimeoutMs`
|
|
141
141
|
// trips the speculative fail-open commit in live-voice-session.ts, which
|
|
142
142
|
// is audible dead air.
|
|
143
143
|
//
|
package/src/config/env.ts
CHANGED
|
@@ -229,8 +229,8 @@ export function setPlatformAssistantId(value: string | undefined): void {
|
|
|
229
229
|
* Platform assistant ID — UUID of this assistant on the platform.
|
|
230
230
|
*
|
|
231
231
|
* Resolved from the in-memory override (populated by providers-setup
|
|
232
|
-
* rehydration
|
|
233
|
-
* platform pushes the value).
|
|
232
|
+
* rehydration from the credential store at daemon startup, or by
|
|
233
|
+
* secret-routes when the platform pushes the value).
|
|
234
234
|
*/
|
|
235
235
|
export function getPlatformAssistantId(): string {
|
|
236
236
|
return _platformAssistantIdOverride ?? "";
|
|
@@ -29,6 +29,18 @@
|
|
|
29
29
|
"description": "Enable user-hosted onboarding flow",
|
|
30
30
|
"defaultEnabled": false
|
|
31
31
|
},
|
|
32
|
+
{
|
|
33
|
+
"id": "proactive-tips",
|
|
34
|
+
"scope": "client",
|
|
35
|
+
"key": "proactive-tips",
|
|
36
|
+
"label": "Proactive Tips",
|
|
37
|
+
"description": "Gates the dismissible proactive tip card in the web sidebar. String-valued so future A/B arms can be added as new values.",
|
|
38
|
+
"defaultEnabled": "off",
|
|
39
|
+
"values": [
|
|
40
|
+
"off",
|
|
41
|
+
"on"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
32
44
|
{
|
|
33
45
|
"id": "vision-mode",
|
|
34
46
|
"scope": "client",
|
|
@@ -511,14 +523,6 @@
|
|
|
511
523
|
"label": "Send User Message Tool",
|
|
512
524
|
"description": "Route all user-facing assistant text through the send_user_message tool instead of streamed assistant text",
|
|
513
525
|
"defaultEnabled": false
|
|
514
|
-
},
|
|
515
|
-
{
|
|
516
|
-
"id": "assistant-desktop",
|
|
517
|
-
"scope": "assistant",
|
|
518
|
-
"key": "assistant-desktop",
|
|
519
|
-
"label": "Assistant Desktop",
|
|
520
|
-
"description": "Streams an interactive desktop from a containerized assistant pod to the web client over /v1/desktop/stream. Off: no desktop affordance is rendered. On: the chat header offers a desktop panel that views and controls the pod's display.",
|
|
521
|
-
"defaultEnabled": false
|
|
522
526
|
}
|
|
523
527
|
]
|
|
524
528
|
}
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
isMemoryV1Active,
|
|
7
7
|
isMemoryV2ExplicitlyDisabled,
|
|
8
8
|
isMemoryV3Live,
|
|
9
|
-
isSkillImprovementActive,
|
|
10
9
|
isV2InjectionEngineActive,
|
|
11
10
|
isV3TierActive,
|
|
12
11
|
usesConceptPageMemory,
|
|
@@ -56,16 +55,12 @@ function makeConfig(
|
|
|
56
55
|
enabled: TriState,
|
|
57
56
|
v2Enabled: TriState,
|
|
58
57
|
v3Live: TriState,
|
|
59
|
-
skillImprovement?: boolean,
|
|
60
58
|
): AssistantConfig {
|
|
61
59
|
return {
|
|
62
60
|
memory: {
|
|
63
61
|
...(enabled === undefined ? {} : { enabled }),
|
|
64
62
|
...(v2Enabled === undefined ? {} : { v2: { enabled: v2Enabled } }),
|
|
65
63
|
...(v3Live === undefined ? {} : { v3: { live: v3Live } }),
|
|
66
|
-
...(skillImprovement === undefined
|
|
67
|
-
? {}
|
|
68
|
-
: { retrospective: { skillImprovement } }),
|
|
69
64
|
},
|
|
70
65
|
} as AssistantConfig;
|
|
71
66
|
}
|
|
@@ -301,32 +296,6 @@ describe("v1-staleness guard is one condition", () => {
|
|
|
301
296
|
* proc-to-skills alias of `isMemoryV3Live` (which did not). One predicate now
|
|
302
297
|
* answers for both features.
|
|
303
298
|
*/
|
|
304
|
-
describe("skill improvement gate", () => {
|
|
305
|
-
test("defaults on for a live v3 tier", () => {
|
|
306
|
-
expect(isSkillImprovementActive(makeConfig(true, undefined, true))).toBe(
|
|
307
|
-
true,
|
|
308
|
-
);
|
|
309
|
-
expect(isSkillImprovementActive(makeConfig(undefined, undefined, true))).toBe(
|
|
310
|
-
true,
|
|
311
|
-
);
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
test("explicit opt-out disables skill improvement without disabling v3", () => {
|
|
315
|
-
const config = makeConfig(true, undefined, true, false);
|
|
316
|
-
|
|
317
|
-
expect(isV3TierActive(config)).toBe(true);
|
|
318
|
-
expect(isSkillImprovementActive(config)).toBe(false);
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
test("requires the live v3 tier even when explicitly enabled", () => {
|
|
322
|
-
const v2Config = makeConfig(true, true, false, true);
|
|
323
|
-
const memoryOffConfig = makeConfig(false, undefined, true, true);
|
|
324
|
-
|
|
325
|
-
expect(isSkillImprovementActive(v2Config)).toBe(false);
|
|
326
|
-
expect(isSkillImprovementActive(memoryOffConfig)).toBe(false);
|
|
327
|
-
});
|
|
328
|
-
});
|
|
329
|
-
|
|
330
299
|
describe("v3 tier is one condition", () => {
|
|
331
300
|
test("memory off suppresses the v3 tier even with memory.v3.live set", () => {
|
|
332
301
|
const config = makeConfig(false, undefined, true);
|
|
@@ -81,32 +81,28 @@ export function isMemoryV3Live(config: AssistantConfig): boolean {
|
|
|
81
81
|
* FEATURE asks this predicate; only the injection-suppression checks that must
|
|
82
82
|
* mirror the raw `memory.v3.live` key ask {@link isMemoryV3Live} directly.
|
|
83
83
|
*
|
|
84
|
-
* The
|
|
85
|
-
* (`supported`) and the cheap `graph_supported` bit on `GET /memory/stats`
|
|
86
|
-
* must agree with whether the graph can build from the v3 concept-page
|
|
87
|
-
* substrate.
|
|
84
|
+
* The two features gated on it, and why they must agree:
|
|
88
85
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
86
|
+
* - The memory concept graph — the single source of truth for both
|
|
87
|
+
* `GET /memory-graph` (`supported`) and the cheap `graph_supported` bit on
|
|
88
|
+
* `GET /memory/stats`, so the advertised capability and the actual build can
|
|
89
|
+
* never drift. The graph builds off the v3 concept-page substrate.
|
|
90
|
+
* - Procedural-memory-as-skills — the retrospective's skill-authoring step and
|
|
91
|
+
* its permission grant. Scoped to the v3 tier because skill retrieval rides
|
|
92
|
+
* the v3 lanes and the usage-prune stage lives in the v3 maintain job. That
|
|
93
|
+
* prune ships observe-first: with `memory.maintenance.skillPruneDays` at its
|
|
94
|
+
* default (`null`) it reports stale assistant-authored skills
|
|
95
|
+
* (`prunableSkills`) but deletes none — so a v3-tier assistant authors skills
|
|
96
|
+
* without an automatic retirement bound until a positive `skillPruneDays` is
|
|
97
|
+
* configured.
|
|
98
|
+
*
|
|
99
|
+
* Both write into memory on the user's behalf, so both honor the Memory
|
|
100
|
+
* opt-out identically: one predicate, one answer.
|
|
92
101
|
*/
|
|
93
102
|
export function isV3TierActive(config: AssistantConfig): boolean {
|
|
94
103
|
return isMemoryEnabled(config) && isMemoryV3Live(config);
|
|
95
104
|
}
|
|
96
105
|
|
|
97
|
-
/**
|
|
98
|
-
* Whether a retrospective may turn observed procedures into managed skills.
|
|
99
|
-
* This requires the v3 tier because skills are retrieved through its memory
|
|
100
|
-
* substrate, and it honors the retrospective-specific opt-out without
|
|
101
|
-
* disabling ordinary retrospective fact retention.
|
|
102
|
-
*/
|
|
103
|
-
export function isSkillImprovementActive(config: AssistantConfig): boolean {
|
|
104
|
-
return (
|
|
105
|
-
isV3TierActive(config) &&
|
|
106
|
-
config.memory?.retrospective?.skillImprovement !== false
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
106
|
/**
|
|
111
107
|
* Minimal structural view of the memory config the concept-page gate reads.
|
|
112
108
|
* Accepting the shape (rather than the full `MemoryConfig`) lets call sites
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Rehydrate the in-memory platform identity/URL overrides
|
|
2
|
+
* Rehydrate the in-memory platform identity/URL overrides from the credential
|
|
3
|
+
* store at process startup.
|
|
3
4
|
*
|
|
4
5
|
* These overrides (`setPlatformBaseUrl` and the platform ID setters in
|
|
5
6
|
* `config/env.ts`) are normally only populated at runtime by the secret-routes
|
|
@@ -9,10 +10,6 @@
|
|
|
9
10
|
* environment default (e.g. dev-platform) while the credential store holds the
|
|
10
11
|
* real production values, and requests are sent to the wrong environment.
|
|
11
12
|
*
|
|
12
|
-
* Bound platform ids come from `POST /v1/internal/assistants/validate/`,
|
|
13
|
-
* which trades the assistant API key for assistant/organization/user ids.
|
|
14
|
-
* If validate omits an id, that field is read from the credential store.
|
|
15
|
-
*
|
|
16
13
|
* Each field is best-effort: a credential-store read failure is logged and
|
|
17
14
|
* skipped so a single missing value never blocks startup.
|
|
18
15
|
*/
|
|
@@ -20,19 +17,11 @@ import { credentialKey } from "../security/credential-key.js";
|
|
|
20
17
|
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
21
18
|
import { getLogger } from "../util/logger.js";
|
|
22
19
|
import {
|
|
23
|
-
getPlatformAssistantId,
|
|
24
|
-
getPlatformBaseUrl,
|
|
25
|
-
getPlatformOrganizationId,
|
|
26
|
-
getPlatformUserId,
|
|
27
20
|
setPlatformAssistantId,
|
|
28
21
|
setPlatformBaseUrl,
|
|
29
22
|
setPlatformOrganizationId,
|
|
30
23
|
setPlatformUserId,
|
|
31
24
|
} from "./env.js";
|
|
32
|
-
import {
|
|
33
|
-
applyPlatformIdentityIds,
|
|
34
|
-
fetchPlatformIdentityIds,
|
|
35
|
-
} from "./platform-identity.js";
|
|
36
25
|
|
|
37
26
|
const log = getLogger("platform-rehydration");
|
|
38
27
|
|
|
@@ -56,75 +45,32 @@ async function rehydrateField(
|
|
|
56
45
|
}
|
|
57
46
|
}
|
|
58
47
|
|
|
59
|
-
async function readAssistantApiKey(): Promise<string> {
|
|
60
|
-
try {
|
|
61
|
-
const stored = (
|
|
62
|
-
await getSecureKeyAsync(credentialKey("vellum", "assistant_api_key"))
|
|
63
|
-
)?.trim();
|
|
64
|
-
if (stored) {
|
|
65
|
-
return stored;
|
|
66
|
-
}
|
|
67
|
-
} catch (err) {
|
|
68
|
-
log.warn(
|
|
69
|
-
{ error: err instanceof Error ? err.message : String(err) },
|
|
70
|
-
"Failed to read assistant API key from credential store (non-fatal)",
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
return process.env.ASSISTANT_API_KEY?.trim() ?? "";
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function rehydrateIdentityFromValidate(): Promise<boolean> {
|
|
77
|
-
const apiKey = await readAssistantApiKey();
|
|
78
|
-
if (!apiKey) {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
const baseUrl = getPlatformBaseUrl();
|
|
82
|
-
if (!baseUrl) {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
const ids = await fetchPlatformIdentityIds(baseUrl, apiKey);
|
|
86
|
-
if (!ids) {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
applyPlatformIdentityIds(ids);
|
|
90
|
-
log.info("Rehydrated platform identity from platform validate");
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
48
|
/**
|
|
95
49
|
* Rehydrate the platform base URL and the related platform IDs (assistant,
|
|
96
|
-
* organization, user)
|
|
50
|
+
* organization, user) from the credential store into their in-memory
|
|
51
|
+
* overrides. Safe to call more than once.
|
|
97
52
|
*/
|
|
98
53
|
export async function rehydratePlatformCredentials(): Promise<void> {
|
|
99
|
-
// Base URL first so managed proxy activation
|
|
100
|
-
// the
|
|
54
|
+
// Base URL first so managed proxy activation resolves the correct
|
|
55
|
+
// environment for the ID lookups and every request that follows.
|
|
101
56
|
await rehydrateField(
|
|
102
57
|
"platform_base_url",
|
|
103
58
|
setPlatformBaseUrl,
|
|
104
59
|
"platform base URL",
|
|
105
60
|
);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
if (!getPlatformUserId()) {
|
|
124
|
-
await rehydrateField(
|
|
125
|
-
"platform_user_id",
|
|
126
|
-
setPlatformUserId,
|
|
127
|
-
"platform user ID",
|
|
128
|
-
);
|
|
129
|
-
}
|
|
61
|
+
await rehydrateField(
|
|
62
|
+
"platform_assistant_id",
|
|
63
|
+
setPlatformAssistantId,
|
|
64
|
+
"platform assistant ID",
|
|
65
|
+
);
|
|
66
|
+
await rehydrateField(
|
|
67
|
+
"platform_organization_id",
|
|
68
|
+
setPlatformOrganizationId,
|
|
69
|
+
"platform organization ID",
|
|
70
|
+
);
|
|
71
|
+
await rehydrateField(
|
|
72
|
+
"platform_user_id",
|
|
73
|
+
setPlatformUserId,
|
|
74
|
+
"platform user ID",
|
|
75
|
+
);
|
|
130
76
|
}
|
package/src/config/schema.ts
CHANGED
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
AuditLogConfigSchema,
|
|
42
42
|
LogFileConfigSchema,
|
|
43
43
|
} from "./schemas/logging.js";
|
|
44
|
+
import { McpConfigSchema } from "./schemas/mcp.js";
|
|
44
45
|
import { MemoryConfigSchema } from "./schemas/memory.js";
|
|
45
46
|
import { MigrationsConfigSchema } from "./schemas/migrations.js";
|
|
46
47
|
import { MonitoringConfigSchema } from "./schemas/monitoring.js";
|
|
@@ -61,7 +62,6 @@ import {
|
|
|
61
62
|
} from "./schemas/timeouts.js";
|
|
62
63
|
import { ToolsConfigSchema } from "./schemas/tools.js";
|
|
63
64
|
import { UserRoutesConfigSchema } from "./schemas/user-routes.js";
|
|
64
|
-
import { VoiceConfigSchema } from "./schemas/voice.js";
|
|
65
65
|
import { WorkflowsConfigSchema } from "./schemas/workflows.js";
|
|
66
66
|
import { WorkspaceGitConfigSchema } from "./schemas/workspace-git.js";
|
|
67
67
|
|
|
@@ -108,6 +108,7 @@ export const AssistantConfigSchema = z.object({
|
|
|
108
108
|
),
|
|
109
109
|
journal: JournalConfigSchema.default(JournalConfigSchema.parse({})),
|
|
110
110
|
backup: BackupConfigSchema.default(BackupConfigSchema.parse({})),
|
|
111
|
+
mcp: McpConfigSchema.default(McpConfigSchema.parse({})),
|
|
111
112
|
acp: AcpConfigSchema.default(AcpConfigSchema.parse({})),
|
|
112
113
|
skills: SkillsConfigSchema.default(SkillsConfigSchema.parse({})),
|
|
113
114
|
workspaceGit: WorkspaceGitConfigSchema.default(
|
|
@@ -118,7 +119,6 @@ export const AssistantConfigSchema = z.object({
|
|
|
118
119
|
twilio: TwilioConfigSchema.default(TwilioConfigSchema.parse({})),
|
|
119
120
|
calls: CallsConfigSchema.default(CallsConfigSchema.parse({})),
|
|
120
121
|
liveVoice: LiveVoiceConfigSchema.default(LiveVoiceConfigSchema.parse({})),
|
|
121
|
-
voice: VoiceConfigSchema.default(VoiceConfigSchema.parse({})),
|
|
122
122
|
sight: SightConfigSchema.default(SightConfigSchema.parse({})),
|
|
123
123
|
whatsapp: WhatsAppConfigSchema.default(WhatsAppConfigSchema.parse({})),
|
|
124
124
|
telegram: TelegramConfigSchema.default(TelegramConfigSchema.parse({})),
|
|
@@ -3,9 +3,28 @@ import { describe, expect, test } from "bun:test";
|
|
|
3
3
|
import {
|
|
4
4
|
LiveVoiceConfigSchema,
|
|
5
5
|
LiveVoiceFluxConfigSchema,
|
|
6
|
+
LiveVoiceFrontModelConfigSchema,
|
|
6
7
|
LiveVoiceVadConfigSchema,
|
|
8
|
+
VALID_LIVE_VOICE_MODES,
|
|
7
9
|
} from "../live-voice.js";
|
|
8
10
|
|
|
11
|
+
const PROGRESS_DEFAULTS = {
|
|
12
|
+
enabled: true,
|
|
13
|
+
opsThreshold: 3,
|
|
14
|
+
idleIntervalMs: 5_000,
|
|
15
|
+
maxSilenceMs: 35_000,
|
|
16
|
+
longOpMs: 15_000,
|
|
17
|
+
minGapMs: 6_000,
|
|
18
|
+
generationTimeoutMs: 1_500,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const FRONT_MODEL_DEFAULTS = {
|
|
22
|
+
endpointDecisionTimeoutMs: 1200,
|
|
23
|
+
endpointExtensionMs: 1500,
|
|
24
|
+
endpointMaxExtensions: 2,
|
|
25
|
+
progress: PROGRESS_DEFAULTS,
|
|
26
|
+
};
|
|
27
|
+
|
|
9
28
|
// `eagerEotThreshold` is deliberately absent: it has no default, and leaving it
|
|
10
29
|
// unset is what keeps Deepgram from emitting speculative turn events. `model`
|
|
11
30
|
// is absent for a related reason: unset means the spoken language selects the
|
|
@@ -111,6 +130,117 @@ describe("LiveVoiceVadConfigSchema", () => {
|
|
|
111
130
|
});
|
|
112
131
|
});
|
|
113
132
|
|
|
133
|
+
describe("LiveVoiceFrontModelConfigSchema", () => {
|
|
134
|
+
test("empty object parses to defaults", () => {
|
|
135
|
+
const parsed = LiveVoiceFrontModelConfigSchema.parse({});
|
|
136
|
+
expect(parsed).toEqual(FRONT_MODEL_DEFAULTS);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("accepts overrides", () => {
|
|
140
|
+
const parsed = LiveVoiceFrontModelConfigSchema.parse({
|
|
141
|
+
endpointDecisionTimeoutMs: 400,
|
|
142
|
+
endpointMaxExtensions: 0,
|
|
143
|
+
});
|
|
144
|
+
expect(parsed.endpointDecisionTimeoutMs).toBe(400);
|
|
145
|
+
expect(parsed.endpointMaxExtensions).toBe(0);
|
|
146
|
+
// Unspecified fields still get defaults
|
|
147
|
+
expect(parsed.endpointExtensionMs).toBe(1500);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("strips retired generated-ack settings", () => {
|
|
151
|
+
const parsed = LiveVoiceFrontModelConfigSchema.parse({
|
|
152
|
+
ackFirstDeltaTimeoutMs: 2500,
|
|
153
|
+
ackGenerationTimeoutMs: 600,
|
|
154
|
+
});
|
|
155
|
+
expect(parsed).not.toHaveProperty("ackFirstDeltaTimeoutMs");
|
|
156
|
+
expect(parsed).not.toHaveProperty("ackGenerationTimeoutMs");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("rejects non-positive endpointDecisionTimeoutMs", () => {
|
|
160
|
+
const result = LiveVoiceFrontModelConfigSchema.safeParse({
|
|
161
|
+
endpointDecisionTimeoutMs: 0,
|
|
162
|
+
});
|
|
163
|
+
expect(result.success).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("rejects negative endpointMaxExtensions", () => {
|
|
167
|
+
const result = LiveVoiceFrontModelConfigSchema.safeParse({
|
|
168
|
+
endpointMaxExtensions: -1,
|
|
169
|
+
});
|
|
170
|
+
expect(result.success).toBe(false);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("absent progress namespace parses to full progress defaults", () => {
|
|
174
|
+
const parsed = LiveVoiceFrontModelConfigSchema.parse({});
|
|
175
|
+
expect(parsed.progress).toEqual(PROGRESS_DEFAULTS);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("partial progress overrides merge with defaults", () => {
|
|
179
|
+
const parsed = LiveVoiceFrontModelConfigSchema.parse({
|
|
180
|
+
progress: { enabled: false, opsThreshold: 5 },
|
|
181
|
+
});
|
|
182
|
+
expect(parsed.progress.enabled).toBe(false);
|
|
183
|
+
expect(parsed.progress.opsThreshold).toBe(5);
|
|
184
|
+
// Unspecified progress fields still get defaults
|
|
185
|
+
expect(parsed.progress.idleIntervalMs).toBe(5_000);
|
|
186
|
+
expect(parsed.progress.maxSilenceMs).toBe(35_000);
|
|
187
|
+
expect(parsed.progress.longOpMs).toBe(15_000);
|
|
188
|
+
expect(parsed.progress.minGapMs).toBe(6_000);
|
|
189
|
+
expect(parsed.progress.generationTimeoutMs).toBe(1_500);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("a stale maxPerTurn key is stripped, not rejected", () => {
|
|
193
|
+
// The cap was removed; configs written while it existed must still parse.
|
|
194
|
+
const parsed = LiveVoiceFrontModelConfigSchema.parse({
|
|
195
|
+
progress: { maxPerTurn: 3 },
|
|
196
|
+
});
|
|
197
|
+
expect("maxPerTurn" in parsed.progress).toBe(false);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test("rejects non-positive progress.opsThreshold", () => {
|
|
201
|
+
const result = LiveVoiceFrontModelConfigSchema.safeParse({
|
|
202
|
+
progress: { opsThreshold: 0 },
|
|
203
|
+
});
|
|
204
|
+
expect(result.success).toBe(false);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test("rejects a heartbeat ceiling shorter than the idle tick interval", () => {
|
|
208
|
+
// The heartbeat is only checked on the idle tick, so a shorter ceiling
|
|
209
|
+
// could be overshot by a full interval.
|
|
210
|
+
const result = LiveVoiceFrontModelConfigSchema.safeParse({
|
|
211
|
+
progress: { idleIntervalMs: 60_000, maxSilenceMs: 10_000 },
|
|
212
|
+
});
|
|
213
|
+
expect(result.success).toBe(false);
|
|
214
|
+
if (!result.success) {
|
|
215
|
+
const msgs = result.error.issues.map((issue) => issue.message);
|
|
216
|
+
expect(
|
|
217
|
+
msgs.some((msg) =>
|
|
218
|
+
msg.includes("liveVoice.frontModel.progress.maxSilenceMs"),
|
|
219
|
+
),
|
|
220
|
+
).toBe(true);
|
|
221
|
+
}
|
|
222
|
+
// The floor itself is allowed: the tick is exactly on the ceiling.
|
|
223
|
+
expect(
|
|
224
|
+
LiveVoiceFrontModelConfigSchema.safeParse({
|
|
225
|
+
progress: { idleIntervalMs: 60_000, maxSilenceMs: 60_000 },
|
|
226
|
+
}).success,
|
|
227
|
+
).toBe(true);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("rejects a non-boolean progress.enabled", () => {
|
|
231
|
+
const result = LiveVoiceFrontModelConfigSchema.safeParse({
|
|
232
|
+
progress: { enabled: "yes" },
|
|
233
|
+
});
|
|
234
|
+
expect(result.success).toBe(false);
|
|
235
|
+
if (!result.success) {
|
|
236
|
+
const msgs = result.error.issues.map((i) => i.message);
|
|
237
|
+
expect(
|
|
238
|
+
msgs.some((m) => m.includes("liveVoice.frontModel.progress.enabled")),
|
|
239
|
+
).toBe(true);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
114
244
|
describe("LiveVoiceFluxConfigSchema", () => {
|
|
115
245
|
test("empty object parses to defaults, with turn-end on", () => {
|
|
116
246
|
expect(LiveVoiceFluxConfigSchema.parse({})).toEqual(FLUX_DEFAULTS);
|
|
@@ -196,6 +326,7 @@ describe("LiveVoiceConfigSchema", () => {
|
|
|
196
326
|
test("empty object parses to defaults", () => {
|
|
197
327
|
const parsed = LiveVoiceConfigSchema.parse({});
|
|
198
328
|
expect(parsed).toEqual({
|
|
329
|
+
mode: "open-mic",
|
|
199
330
|
vad: {
|
|
200
331
|
speechEnergyThreshold: 800,
|
|
201
332
|
noiseFloorMargin: 3,
|
|
@@ -206,9 +337,11 @@ describe("LiveVoiceConfigSchema", () => {
|
|
|
206
337
|
echoEmaHalfLifeMs: 400,
|
|
207
338
|
echoDrainSlackMs: 300,
|
|
208
339
|
},
|
|
340
|
+
frontModel: FRONT_MODEL_DEFAULTS,
|
|
209
341
|
// Off by default: Flux turn detection is opt-in, so the front-door hold
|
|
210
342
|
// verdict keeps committing turns until it is enabled.
|
|
211
343
|
flux: FLUX_DEFAULTS,
|
|
344
|
+
maxSessionDurationSeconds: 1800,
|
|
212
345
|
// Off by default: voice turns carry only their transcript, no audio
|
|
213
346
|
// artifacts on the conversation messages (JARVIS-1283).
|
|
214
347
|
archiveAudio: false,
|
|
@@ -232,26 +365,43 @@ describe("LiveVoiceConfigSchema", () => {
|
|
|
232
365
|
|
|
233
366
|
test("accepts overrides", () => {
|
|
234
367
|
const parsed = LiveVoiceConfigSchema.parse({
|
|
368
|
+
mode: "ptt",
|
|
235
369
|
vad: { silenceThresholdMs: 900 },
|
|
370
|
+
frontModel: { endpointDecisionTimeoutMs: 300 },
|
|
236
371
|
flux: { turnEnd: { enabled: true } },
|
|
372
|
+
maxSessionDurationSeconds: 600,
|
|
237
373
|
});
|
|
374
|
+
expect(parsed.mode).toBe("ptt");
|
|
238
375
|
expect(parsed.vad.silenceThresholdMs).toBe(900);
|
|
239
376
|
// Unspecified vad fields still get defaults
|
|
240
377
|
expect(parsed.vad.speechEnergyThreshold).toBe(800);
|
|
241
378
|
expect(parsed.vad.maxTurnDurationMs).toBe(30_000);
|
|
379
|
+
// Partial frontModel overrides merge with defaults
|
|
380
|
+
expect(parsed.frontModel.endpointDecisionTimeoutMs).toBe(300);
|
|
381
|
+
expect(parsed.frontModel.endpointExtensionMs).toBe(1500);
|
|
242
382
|
// Partial flux overrides merge with defaults
|
|
243
383
|
expect(parsed.flux.turnEnd.enabled).toBe(true);
|
|
244
384
|
expect(parsed.flux.eotThreshold).toBe(0.7);
|
|
385
|
+
expect(parsed.maxSessionDurationSeconds).toBe(600);
|
|
245
386
|
});
|
|
246
387
|
|
|
247
|
-
test("
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
388
|
+
test("rejects invalid mode", () => {
|
|
389
|
+
const result = LiveVoiceConfigSchema.safeParse({ mode: "always-on" });
|
|
390
|
+
expect(result.success).toBe(false);
|
|
391
|
+
if (!result.success) {
|
|
392
|
+
const msgs = result.error.issues.map((i) => i.message);
|
|
393
|
+
expect(msgs.some((m) => m.includes("liveVoice.mode"))).toBe(true);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
test("rejects non-positive maxSessionDurationSeconds", () => {
|
|
398
|
+
const result = LiveVoiceConfigSchema.safeParse({
|
|
399
|
+
maxSessionDurationSeconds: -1,
|
|
253
400
|
});
|
|
254
|
-
expect(
|
|
255
|
-
|
|
401
|
+
expect(result.success).toBe(false);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
test("VALID_LIVE_VOICE_MODES lists ptt and open-mic", () => {
|
|
405
|
+
expect(VALID_LIVE_VOICE_MODES).toEqual(["ptt", "open-mic"]);
|
|
256
406
|
});
|
|
257
407
|
});
|
|
@@ -26,8 +26,32 @@ const CallsDisclosureConfigSchema = z
|
|
|
26
26
|
"Controls whether and how the assistant discloses its nature at the start of a phone call",
|
|
27
27
|
);
|
|
28
28
|
|
|
29
|
+
const CallsSafetyConfigSchema = z
|
|
30
|
+
.object({
|
|
31
|
+
denyCategories: z
|
|
32
|
+
.array(
|
|
33
|
+
z.string({
|
|
34
|
+
error: "calls.safety.denyCategories values must be strings",
|
|
35
|
+
}),
|
|
36
|
+
)
|
|
37
|
+
.default([])
|
|
38
|
+
.describe(
|
|
39
|
+
"Categories of calls that should be denied (e.g. for safety or compliance reasons)",
|
|
40
|
+
),
|
|
41
|
+
})
|
|
42
|
+
.describe("Safety guardrails for phone calls");
|
|
43
|
+
|
|
29
44
|
const CallsVoiceConfigSchema = z
|
|
30
45
|
.object({
|
|
46
|
+
interruptSensitivity: z
|
|
47
|
+
.enum(["low", "medium", "high"], {
|
|
48
|
+
error:
|
|
49
|
+
"calls.voice.interruptSensitivity must be one of: low, medium, high",
|
|
50
|
+
})
|
|
51
|
+
.default("low")
|
|
52
|
+
.describe(
|
|
53
|
+
"How aggressively the STT provider detects the start of caller speech — low reduces false interrupts from background noise",
|
|
54
|
+
),
|
|
31
55
|
telephonyStreaming: z
|
|
32
56
|
.boolean({
|
|
33
57
|
error: "calls.voice.telephonyStreaming must be a boolean",
|
|
@@ -203,6 +227,7 @@ export const CallsConfigSchema = z
|
|
|
203
227
|
disclosure: CallsDisclosureConfigSchema.default(
|
|
204
228
|
CallsDisclosureConfigSchema.parse({}),
|
|
205
229
|
),
|
|
230
|
+
safety: CallsSafetyConfigSchema.default(CallsSafetyConfigSchema.parse({})),
|
|
206
231
|
voice: CallsVoiceConfigSchema.default(CallsVoiceConfigSchema.parse({})),
|
|
207
232
|
callerIdentity: CallerIdentityConfigSchema.default(
|
|
208
233
|
CallerIdentityConfigSchema.parse({}),
|
|
@@ -211,4 +236,6 @@ export const CallsConfigSchema = z
|
|
|
211
236
|
CallsVerificationConfigSchema.parse({}),
|
|
212
237
|
),
|
|
213
238
|
})
|
|
214
|
-
.describe(
|
|
239
|
+
.describe(
|
|
240
|
+
"Phone call configuration — controls telephony, voice, safety, and call behavior",
|
|
241
|
+
);
|