@vellumai/assistant 0.6.3 → 0.6.4
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 +273 -10
- package/Dockerfile +2 -3
- package/bun.lock +5 -13
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/stt-provider-onboarding.md +120 -0
- package/knip.json +12 -2
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +3 -3
- package/openapi.yaml +982 -72
- package/package.json +4 -6
- package/scripts/generate-openapi.ts +0 -1
- package/scripts/test.sh +73 -18
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop.test.ts +123 -0
- package/src/__tests__/anthropic-provider.test.ts +263 -10
- package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
- package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
- package/src/__tests__/browser-fill-credential.test.ts +11 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/browser-skill-endstate.test.ts +31 -7
- package/src/__tests__/btw-routes.test.ts +7 -0
- package/src/__tests__/call-controller.test.ts +581 -20
- package/src/__tests__/catalog-files.test.ts +138 -0
- package/src/__tests__/channel-invite-transport.test.ts +2 -2
- package/src/__tests__/channel-readiness-routes.test.ts +16 -20
- package/src/__tests__/channel-readiness-service.test.ts +12 -7
- package/src/__tests__/checker.test.ts +157 -10
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/config-analysis.test.ts +100 -0
- package/src/__tests__/config-schema.test.ts +1013 -66
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +43 -8
- package/src/__tests__/contact-store-user-file.test.ts +512 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-window-manager.test.ts +88 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +98 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +135 -0
- package/src/__tests__/conversation-error.test.ts +70 -0
- package/src/__tests__/conversation-history-web-search.test.ts +11 -4
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +901 -60
- package/src/__tests__/conversation-routes-disk-view.test.ts +270 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +55 -0
- package/src/__tests__/conversation-skill-tools.test.ts +7 -4
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +89 -18
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/credential-vault-unit.test.ts +379 -3
- package/src/__tests__/credentials-cli.test.ts +40 -16
- package/src/__tests__/cross-provider-web-search.test.ts +146 -35
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
- package/src/__tests__/email-html-renderer.test.ts +71 -0
- package/src/__tests__/email-invite-adapter.test.ts +36 -32
- package/src/__tests__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +75 -8
- package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +64 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
- package/src/__tests__/gmail-archive-gate.test.ts +246 -0
- package/src/__tests__/gmail-preferences.test.ts +117 -0
- package/src/__tests__/headless-browser-interactions.test.ts +43 -0
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +142 -5
- package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
- package/src/__tests__/heartbeat-service.test.ts +70 -17
- package/src/__tests__/home-state-routes.test.ts +162 -0
- package/src/__tests__/host-bash-proxy.test.ts +0 -5
- package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
- package/src/__tests__/host-cu-proxy.test.ts +0 -5
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/llm-context-normalization.test.ts +488 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/media-stream-output.test.ts +555 -0
- package/src/__tests__/media-stream-parser.test.ts +374 -0
- package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
- package/src/__tests__/media-stream-stt-session.test.ts +588 -0
- package/src/__tests__/media-turn-detector.test.ts +440 -0
- package/src/__tests__/message-queue.test.ts +125 -0
- package/src/__tests__/migration-export-http.test.ts +6 -6
- package/src/__tests__/migration-import-commit-http.test.ts +8 -6
- package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +151 -0
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +2 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
- package/src/__tests__/oauth-providers-routes.test.ts +2 -0
- package/src/__tests__/oauth-store.test.ts +85 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +249 -6
- package/src/__tests__/onboarding-template-contract.test.ts +6 -13
- package/src/__tests__/openai-provider.test.ts +176 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1105 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outlook-unsubscribe.test.ts +31 -2
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +174 -0
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
- package/src/__tests__/relationship-state-contract.test.ts +175 -0
- package/src/__tests__/relay-server.test.ts +423 -5
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-scanner-executor.test.ts +4 -0
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +5 -1
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +49 -0
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
- package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
- package/src/__tests__/skills.test.ts +5 -2
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +564 -1
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/system-prompt.test.ts +112 -26
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +18 -7
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +33 -24
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +345 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
- package/src/__tests__/twilio-routes.test.ts +376 -0
- package/src/__tests__/unicode.test.ts +293 -0
- package/src/__tests__/update-bulletin-format.test.ts +59 -0
- package/src/__tests__/update-bulletin.test.ts +206 -5
- package/src/__tests__/usage-routes.test.ts +25 -4
- package/src/__tests__/user-reference.test.ts +46 -61
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
- package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
- package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
- package/src/__tests__/workspace-migration-meets.test.ts +244 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
- package/src/__tests__/workspace-policy.test.ts +2 -0
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +43 -3
- package/src/backup/__tests__/backup-key.test.ts +152 -0
- package/src/backup/__tests__/backup-worker.test.ts +767 -0
- package/src/backup/__tests__/list-snapshots.test.ts +87 -0
- package/src/backup/__tests__/local-writer.test.ts +218 -0
- package/src/backup/__tests__/offsite-writer.test.ts +641 -0
- package/src/backup/__tests__/paths.test.ts +300 -0
- package/src/backup/__tests__/restore.test.ts +498 -0
- package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
- package/src/backup/__tests__/stream-crypt.test.ts +228 -0
- package/src/backup/backup-key.ts +137 -0
- package/src/backup/backup-worker.ts +459 -0
- package/src/backup/list-snapshots.ts +147 -0
- package/src/backup/local-writer.ts +133 -0
- package/src/backup/offsite-writer.ts +222 -0
- package/src/backup/paths.ts +226 -0
- package/src/backup/restore.ts +322 -0
- package/src/backup/snapshot-lock.ts +431 -0
- package/src/backup/stream-crypt.ts +263 -0
- package/src/bundler/package-resolver.ts +4 -0
- package/src/calls/audio-store.ts +11 -5
- package/src/calls/call-controller.ts +226 -71
- package/src/calls/call-domain.ts +9 -0
- package/src/calls/call-speech-output.ts +190 -0
- package/src/calls/call-transport.ts +77 -0
- package/src/calls/media-stream-audio-transcode.ts +173 -0
- package/src/calls/media-stream-output.ts +660 -0
- package/src/calls/media-stream-parser.ts +300 -0
- package/src/calls/media-stream-protocol.ts +166 -0
- package/src/calls/media-stream-server.ts +592 -0
- package/src/calls/media-stream-stt-session.ts +460 -0
- package/src/calls/media-turn-detector.ts +230 -0
- package/src/calls/relay-server.ts +90 -75
- package/src/calls/resolve-call-tts-provider.ts +136 -0
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +161 -0
- package/src/calls/tts-text-sanitizer.ts +32 -16
- package/src/calls/twilio-routes.ts +281 -17
- package/src/calls/voice-quality.ts +78 -35
- package/src/calls/voice-session-bridge.ts +8 -1
- package/src/channels/types.ts +16 -0
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
- package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
- package/src/cli/commands/__tests__/email-download.test.ts +16 -1
- package/src/cli/commands/__tests__/email-list.test.ts +22 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +37 -4
- package/src/cli/commands/__tests__/email-status.test.ts +5 -1
- package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/conversations.ts +77 -0
- package/src/cli/commands/credentials.ts +0 -1
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +255 -3
- package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +15 -0
- package/src/cli/commands/oauth/shared.ts +2 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -9
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
- package/src/cli/program.ts +30 -4
- package/src/config/__tests__/backup-schema.test.ts +134 -0
- package/src/config/assistant-feature-flags.ts +61 -62
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
- package/src/config/bundled-skills/browser/SKILL.md +30 -5
- package/src/config/bundled-skills/browser/TOOLS.json +123 -0
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
- package/src/config/bundled-skills/contacts/SKILL.md +2 -2
- package/src/config/bundled-skills/gmail/SKILL.md +53 -7
- package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
- package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/outlook/SKILL.md +2 -2
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
- package/src/config/bundled-skills/slack/SKILL.md +1 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
- package/src/config/bundled-tool-registry.ts +8 -0
- package/src/config/env-registry.ts +24 -0
- package/src/config/env.ts +34 -10
- package/src/config/feature-flag-registry.json +46 -14
- package/src/config/loader.ts +26 -12
- package/src/config/schema.ts +35 -10
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +51 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -26
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +47 -7
- package/src/config/schemas/heartbeat.ts +27 -5
- package/src/config/schemas/host-browser.ts +47 -1
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/services.ts +44 -0
- package/src/config/schemas/stt.ts +59 -0
- package/src/config/schemas/tts.ts +230 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/skills.ts +4 -0
- package/src/config/types.ts +4 -0
- package/src/contacts/contact-store.ts +56 -11
- package/src/contacts/contacts-write.ts +38 -1
- package/src/context/post-turn-tool-result-truncation.ts +3 -2
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +45 -12
- package/src/credential-execution/executable-discovery.ts +12 -2
- package/src/credential-execution/process-manager.ts +33 -2
- package/src/credential-health/credential-health-service.ts +366 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/config-watcher.ts +99 -5
- package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
- package/src/daemon/conversation-agent-loop.ts +101 -24
- package/src/daemon/conversation-error.ts +11 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +59 -9
- package/src/daemon/conversation-messaging.ts +37 -3
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +581 -19
- package/src/daemon/conversation-queue-manager.ts +24 -0
- package/src/daemon/conversation-runtime-assembly.ts +11 -1
- package/src/daemon/conversation-slash.ts +36 -0
- package/src/daemon/conversation-surfaces.ts +94 -4
- package/src/daemon/conversation-tool-setup.ts +25 -0
- package/src/daemon/conversation-usage.ts +7 -4
- package/src/daemon/conversation.ts +86 -28
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +4 -1
- package/src/daemon/handlers/shared.ts +22 -0
- package/src/daemon/handlers/skills.ts +321 -77
- package/src/daemon/host-browser-proxy.ts +2 -1
- package/src/daemon/lifecycle.ts +122 -25
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/conversations.ts +34 -1
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +14 -0
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +16 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/server.ts +347 -2
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +9 -0
- package/src/email/html-renderer.ts +76 -0
- package/src/heartbeat/heartbeat-service.ts +93 -7
- package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
- package/src/home/__tests__/emit-feed-event.test.ts +169 -0
- package/src/home/__tests__/feed-scheduler.test.ts +194 -0
- package/src/home/__tests__/feed-types.test.ts +275 -0
- package/src/home/__tests__/feed-writer.test.ts +688 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
- package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
- package/src/home/__tests__/progress-formula.test.ts +213 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
- package/src/home/__tests__/rollup-producer.test.ts +398 -0
- package/src/home/assistant-feed-authoring.ts +124 -0
- package/src/home/emit-feed-event.ts +158 -0
- package/src/home/feed-scheduler.ts +247 -0
- package/src/home/feed-types.ts +181 -0
- package/src/home/feed-writer.ts +469 -0
- package/src/home/platform-gmail-digest.ts +163 -0
- package/src/home/progress-formula.ts +86 -0
- package/src/home/relationship-state-writer.ts +824 -0
- package/src/home/relationship-state.ts +143 -0
- package/src/home/rollup-producer.ts +384 -0
- package/src/hooks/runner.ts +7 -0
- package/src/inbound/platform-callback-registration.ts +12 -3
- package/src/inbound/public-ingress-urls.ts +12 -0
- package/src/instrument.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/cli-client.ts +151 -0
- package/src/ipc/cli-server.ts +234 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/index.ts +5 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
- package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/app-store.ts +1 -1
- package/src/memory/attachments-store.ts +70 -0
- package/src/memory/auto-analysis-enqueue.ts +127 -0
- package/src/memory/auto-analysis-guard.ts +27 -0
- package/src/memory/cleanup-schedule-state.ts +37 -0
- package/src/memory/conversation-analyze-job.ts +73 -0
- package/src/memory/conversation-crud.ts +99 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +34 -2
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/db-init.ts +6 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/graph/conversation-graph-memory.ts +15 -0
- package/src/memory/graph/extraction.test.ts +23 -0
- package/src/memory/graph/extraction.ts +8 -0
- package/src/memory/graph/retriever.ts +27 -18
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/group-crud.ts +6 -1
- package/src/memory/indexer.ts +95 -16
- package/src/memory/job-handlers/cleanup.ts +11 -8
- package/src/memory/job-handlers/conversation-starters.ts +16 -10
- package/src/memory/jobs-store.ts +64 -4
- package/src/memory/jobs-worker.ts +22 -9
- package/src/memory/llm-usage-store.ts +92 -56
- package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
- package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/oauth.ts +3 -0
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/client.ts +57 -6
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +143 -38
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/notifications/decision-engine.ts +3 -3
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
- package/src/oauth/byo-connection.test.ts +18 -1
- package/src/oauth/byo-connection.ts +3 -1
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.ts +6 -2
- package/src/oauth/connection.ts +2 -0
- package/src/oauth/oauth-store.ts +9 -0
- package/src/oauth/platform-connection.test.ts +98 -0
- package/src/oauth/platform-connection.ts +52 -31
- package/src/oauth/seed-providers.ts +7 -0
- package/src/permissions/checker.ts +16 -6
- package/src/permissions/defaults.ts +49 -1
- package/src/permissions/trust-store.ts +3 -3
- package/src/permissions/workspace-policy.ts +3 -0
- package/src/platform/client.test.ts +10 -0
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +126 -2
- package/src/prompts/system-prompt.ts +59 -18
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/prompts/templates/UPDATES.md +12 -0
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-format.ts +26 -9
- package/src/prompts/update-bulletin.ts +34 -23
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/anthropic/client.ts +157 -61
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +9 -1
- package/src/providers/model-catalog.ts +6 -0
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +474 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +502 -0
- package/src/providers/openrouter/client.ts +101 -4
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +14 -3
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
- package/src/providers/speech-to-text/deepgram.test.ts +332 -0
- package/src/providers/speech-to-text/deepgram.ts +115 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
- package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
- package/src/providers/speech-to-text/google-gemini.ts +101 -0
- package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
- package/src/providers/speech-to-text/openai-whisper.ts +63 -33
- package/src/providers/speech-to-text/provider-catalog.ts +306 -0
- package/src/providers/speech-to-text/resolve.ts +386 -6
- package/src/providers/types.ts +9 -0
- package/src/runtime/AGENTS.md +43 -1
- package/src/runtime/__tests__/agent-wake.test.ts +831 -0
- package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
- package/src/runtime/agent-wake.ts +512 -0
- package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
- package/src/runtime/auth/route-policy.ts +30 -5
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/capability-tokens.ts +10 -10
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-invite-transports/email.ts +14 -6
- package/src/runtime/channel-readiness-service.ts +12 -22
- package/src/runtime/chrome-extension-registry.ts +38 -2
- package/src/runtime/http-server.ts +395 -10
- package/src/runtime/http-types.ts +6 -2
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/migration-transport.ts +1 -0
- package/src/runtime/migrations/migration-wizard.ts +1 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
- package/src/runtime/migrations/vbundle-importer.ts +34 -0
- package/src/runtime/pending-interactions.ts +0 -11
- package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
- package/src/runtime/routes/app-management-routes.ts +12 -18
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/backup-routes.ts +519 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
- package/src/runtime/routes/btw-routes.ts +8 -6
- package/src/runtime/routes/contact-routes.test.ts +298 -0
- package/src/runtime/routes/contact-routes.ts +132 -5
- package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
- package/src/runtime/routes/conversation-management-routes.ts +115 -0
- package/src/runtime/routes/conversation-routes.ts +367 -146
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/home-feed-routes.ts +334 -0
- package/src/runtime/routes/home-state-routes.ts +138 -0
- package/src/runtime/routes/host-browser-routes.ts +3 -14
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +3 -17
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
- package/src/runtime/routes/integrations/slack/channel.ts +11 -3
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +303 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/migration-routes.ts +40 -5
- package/src/runtime/routes/settings-routes.ts +22 -5
- package/src/runtime/routes/skills-routes.ts +76 -7
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/surface-action-routes.ts +41 -2
- package/src/runtime/routes/tts-routes.ts +108 -24
- package/src/runtime/routes/usage-routes.ts +30 -2
- package/src/runtime/routes/user-route-dispatcher.ts +50 -5
- package/src/runtime/routes/user-routes.ts +13 -1
- package/src/runtime/routes/work-items-routes.ts +8 -1
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
- package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
- package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
- package/src/runtime/services/analyze-conversation.ts +344 -0
- package/src/runtime/services/analyze-deps-singleton.ts +32 -0
- package/src/runtime/services/auto-analysis-prompt.ts +55 -0
- package/src/runtime/skill-route-registry.ts +49 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +50 -0
- package/src/security/oauth2.ts +26 -4
- package/src/security/secure-keys.ts +25 -2
- package/src/security/token-manager.ts +8 -0
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-files.ts +64 -2
- package/src/skills/category-inference.ts +122 -0
- package/src/skills/clawhub-files.ts +213 -0
- package/src/skills/clawhub.ts +84 -23
- package/src/skills/skill-file-provider.ts +40 -0
- package/src/skills/skillssh-files.ts +395 -0
- package/src/skills/skillssh-registry.ts +4 -4
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +195 -0
- package/src/stt/stt-stream-session.ts +499 -0
- package/src/stt/types.ts +330 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +38 -14
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
- package/src/tools/browser/browser-execution.ts +1163 -23
- package/src/tools/browser/browser-manager.ts +45 -0
- package/src/tools/browser/browser-mode-constants.ts +12 -0
- package/src/tools/browser/browser-mode.ts +92 -0
- package/src/tools/browser/browser-status-constants.ts +33 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +183 -17
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
- package/src/tools/browser/cdp-client/errors.ts +15 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
- package/src/tools/browser/cdp-client/factory.ts +797 -87
- package/src/tools/browser/cdp-client/index.ts +16 -2
- package/src/tools/browser/cdp-client/types.ts +68 -0
- package/src/tools/credentials/vault.ts +35 -6
- package/src/tools/network/web-fetch.ts +5 -2
- package/src/tools/network/web-search.ts +5 -2
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +2 -0
- package/src/tools/skills/sandbox-runner.ts +3 -2
- package/src/tools/terminal/safe-env.ts +10 -2
- package/src/tools/terminal/shell.ts +15 -4
- package/src/tools/tool-manifest.ts +21 -0
- package/src/tools/types.ts +17 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tts/__tests__/provider-adapters.test.ts +834 -0
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
- package/src/tts/__tests__/provider-catalog.test.ts +183 -0
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +201 -0
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +219 -0
- package/src/tts/providers/elevenlabs-provider.ts +211 -0
- package/src/tts/providers/fish-audio-provider.ts +183 -0
- package/src/tts/providers/index.ts +42 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +153 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/util/abort-reasons.ts +58 -0
- package/src/util/device-id.ts +32 -16
- package/src/util/errors.ts +9 -1
- package/src/util/platform.ts +54 -10
- package/src/util/pricing.ts +66 -3
- package/src/util/spawn.ts +1 -1
- package/src/util/truncate.ts +4 -2
- package/src/util/unicode.ts +201 -0
- package/src/version.ts +19 -24
- package/src/watcher/engine.ts +23 -0
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/migrations/003-seed-device-id.ts +9 -3
- package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
- package/src/workspace/migrations/029-seed-pkb.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +317 -0
- package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
- package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
- package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
- package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
- package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
- package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
- package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/top-level-renderer.ts +13 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/cli/commands/browser-relay.ts +0 -466
- package/src/email/guardrails.ts +0 -221
- package/src/email/provider.ts +0 -117
- package/src/email/providers/agentmail.ts +0 -361
- package/src/email/providers/index.ts +0 -65
- package/src/email/service.ts +0 -384
- package/src/email/types.ts +0 -126
- package/src/prompts/templates/USER.md +0 -13
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/runtime/routes/browser-cdp-routes.ts +0 -229
|
@@ -79,7 +79,7 @@ const {
|
|
|
79
79
|
} = await import("../prompts/system-prompt.js");
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
* Extract just the workspace-file content (IDENTITY.md, SOUL.md,
|
|
82
|
+
* Extract just the workspace-file content (IDENTITY.md, SOUL.md,
|
|
83
83
|
* BOOTSTRAP.md) from the full system prompt, stripping all static
|
|
84
84
|
* instruction sections, configuration, and skills catalog.
|
|
85
85
|
*
|
|
@@ -123,6 +123,7 @@ describe("buildSystemPrompt", () => {
|
|
|
123
123
|
"BOOTSTRAP.md",
|
|
124
124
|
"UPDATES.md",
|
|
125
125
|
"skills",
|
|
126
|
+
"users",
|
|
126
127
|
]) {
|
|
127
128
|
const p = join(TEST_DIR, name);
|
|
128
129
|
if (existsSync(p)) rmSync(p, { recursive: true, force: true });
|
|
@@ -249,31 +250,80 @@ describe("buildSystemPrompt", () => {
|
|
|
249
250
|
expect(result).not.toContain("incident-response");
|
|
250
251
|
});
|
|
251
252
|
|
|
252
|
-
test("
|
|
253
|
-
|
|
254
|
-
|
|
253
|
+
test("builds prompt without error when USER.md does not exist on disk", () => {
|
|
254
|
+
// Persona content now flows through options.userPersona (resolved via
|
|
255
|
+
// resolveGuardianPersona upstream). buildSystemPrompt must never read
|
|
256
|
+
// USER.md from disk — verify it returns a well-formed prompt when the
|
|
257
|
+
// file is absent.
|
|
258
|
+
writeFileSync(join(TEST_DIR, "IDENTITY.md"), "Identity");
|
|
259
|
+
writeFileSync(join(TEST_DIR, "SOUL.md"), "Soul");
|
|
255
260
|
const result = buildSystemPrompt();
|
|
256
|
-
expect(basePrompt(result)).toBe("
|
|
261
|
+
expect(basePrompt(result)).toBe("Identity\n\nSoul");
|
|
257
262
|
});
|
|
258
263
|
|
|
259
|
-
test("
|
|
264
|
+
test("does not read USER.md content from disk even when the file is present", () => {
|
|
265
|
+
// USER.md has been removed from PROMPT_FILES and the fallback read
|
|
266
|
+
// path. A stale file on disk must not leak into the prompt.
|
|
260
267
|
writeFileSync(join(TEST_DIR, "IDENTITY.md"), "Identity");
|
|
261
|
-
writeFileSync(
|
|
262
|
-
|
|
268
|
+
writeFileSync(
|
|
269
|
+
join(TEST_DIR, "USER.md"),
|
|
270
|
+
"stale user content that should be ignored",
|
|
271
|
+
);
|
|
263
272
|
const result = buildSystemPrompt();
|
|
264
|
-
expect(
|
|
273
|
+
expect(result).not.toContain("stale user content");
|
|
274
|
+
expect(basePrompt(result)).toBe("Identity");
|
|
265
275
|
});
|
|
266
276
|
|
|
267
|
-
test("
|
|
268
|
-
writeFileSync(join(TEST_DIR, "
|
|
269
|
-
|
|
270
|
-
|
|
277
|
+
test("uses options.userPersona instead of USER.md", () => {
|
|
278
|
+
writeFileSync(join(TEST_DIR, "IDENTITY.md"), "Identity");
|
|
279
|
+
writeFileSync(join(TEST_DIR, "SOUL.md"), "Soul");
|
|
280
|
+
const result = buildSystemPrompt({
|
|
281
|
+
userPersona: "# User persona\n\nName: Alice",
|
|
282
|
+
});
|
|
283
|
+
expect(basePrompt(result)).toBe(
|
|
284
|
+
"Identity\n\nSoul\n\n# User persona\n\nName: Alice",
|
|
285
|
+
);
|
|
271
286
|
});
|
|
272
287
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
288
|
+
describe("BOOTSTRAP.md user persona placeholder", () => {
|
|
289
|
+
test("substitutes {{USER_PERSONA_FILE}} with users/<slug>.md when userSlug is provided", () => {
|
|
290
|
+
writeFileSync(
|
|
291
|
+
join(TEST_DIR, "BOOTSTRAP.md"),
|
|
292
|
+
"# First run\n\nSave facts to users/{{USER_PERSONA_FILE}} immediately.",
|
|
293
|
+
);
|
|
294
|
+
const result = buildSystemPrompt({ userSlug: "alice" });
|
|
295
|
+
expect(result).toContain("users/alice.md");
|
|
296
|
+
expect(result).not.toContain("{{USER_PERSONA_FILE}}");
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
test("falls back to users/default.md when userSlug is omitted", () => {
|
|
300
|
+
writeFileSync(
|
|
301
|
+
join(TEST_DIR, "BOOTSTRAP.md"),
|
|
302
|
+
"# First run\n\nSave facts to users/{{USER_PERSONA_FILE}} immediately.",
|
|
303
|
+
);
|
|
304
|
+
const result = buildSystemPrompt();
|
|
305
|
+
expect(result).toContain("users/default.md");
|
|
306
|
+
expect(result).not.toContain("{{USER_PERSONA_FILE}}");
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
test("substitutes the unmodified bundled BOOTSTRAP.md template", () => {
|
|
310
|
+
// Copy the real bundled BOOTSTRAP.md into the test workspace so we
|
|
311
|
+
// verify substitution against the actual template the daemon ships.
|
|
312
|
+
const bundled = readFileSync(
|
|
313
|
+
join(
|
|
314
|
+
import.meta.dirname,
|
|
315
|
+
"..",
|
|
316
|
+
"prompts",
|
|
317
|
+
"templates",
|
|
318
|
+
"BOOTSTRAP.md",
|
|
319
|
+
),
|
|
320
|
+
"utf-8",
|
|
321
|
+
);
|
|
322
|
+
writeFileSync(join(TEST_DIR, "BOOTSTRAP.md"), bundled);
|
|
323
|
+
const result = buildSystemPrompt({ userSlug: "alice" });
|
|
324
|
+
expect(result).toContain("users/alice.md");
|
|
325
|
+
expect(result).not.toContain("{{USER_PERSONA_FILE}}");
|
|
326
|
+
});
|
|
277
327
|
});
|
|
278
328
|
|
|
279
329
|
describe("app-builder tool ownership guidance", () => {
|
|
@@ -541,17 +591,20 @@ describe("ensurePromptFiles", () => {
|
|
|
541
591
|
"SOUL.md",
|
|
542
592
|
"USER.md",
|
|
543
593
|
"BOOTSTRAP.md",
|
|
594
|
+
"BOOTSTRAP-REFERENCE.md",
|
|
595
|
+
"HEARTBEAT.md",
|
|
544
596
|
"conversations",
|
|
597
|
+
"users",
|
|
545
598
|
]) {
|
|
546
599
|
const p = join(TEST_DIR, name);
|
|
547
600
|
if (existsSync(p)) rmSync(p, { recursive: true, force: true });
|
|
548
601
|
}
|
|
549
602
|
});
|
|
550
603
|
|
|
551
|
-
test("creates
|
|
604
|
+
test("creates SOUL.md and IDENTITY.md from templates when none exist", () => {
|
|
552
605
|
ensurePromptFiles();
|
|
553
606
|
|
|
554
|
-
for (const file of ["SOUL.md", "IDENTITY.md"
|
|
607
|
+
for (const file of ["SOUL.md", "IDENTITY.md"]) {
|
|
555
608
|
const dest = join(TEST_DIR, file);
|
|
556
609
|
expect(existsSync(dest)).toBe(true);
|
|
557
610
|
const content = readFileSync(dest, "utf-8");
|
|
@@ -559,6 +612,24 @@ describe("ensurePromptFiles", () => {
|
|
|
559
612
|
}
|
|
560
613
|
});
|
|
561
614
|
|
|
615
|
+
test("does not seed USER.md", () => {
|
|
616
|
+
// USER.md is no longer part of the seeded prompt files — persona
|
|
617
|
+
// content lives in users/<slug>.md and is resolved via the guardian
|
|
618
|
+
// persona path.
|
|
619
|
+
ensurePromptFiles();
|
|
620
|
+
|
|
621
|
+
expect(existsSync(join(TEST_DIR, "USER.md"))).toBe(false);
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
test("seeds users/default.md persona template", () => {
|
|
625
|
+
ensurePromptFiles();
|
|
626
|
+
|
|
627
|
+
const defaultPersonaPath = join(TEST_DIR, "users", "default.md");
|
|
628
|
+
expect(existsSync(defaultPersonaPath)).toBe(true);
|
|
629
|
+
const content = readFileSync(defaultPersonaPath, "utf-8");
|
|
630
|
+
expect(content.length).toBeGreaterThan(0);
|
|
631
|
+
});
|
|
632
|
+
|
|
562
633
|
test("does not overwrite existing files", () => {
|
|
563
634
|
const customContent = "My custom identity";
|
|
564
635
|
writeFileSync(join(TEST_DIR, "IDENTITY.md"), customContent);
|
|
@@ -568,9 +639,8 @@ describe("ensurePromptFiles", () => {
|
|
|
568
639
|
const content = readFileSync(join(TEST_DIR, "IDENTITY.md"), "utf-8");
|
|
569
640
|
expect(content).toBe(customContent);
|
|
570
641
|
|
|
571
|
-
//
|
|
642
|
+
// The other seeded file should be created
|
|
572
643
|
expect(existsSync(join(TEST_DIR, "SOUL.md"))).toBe(true);
|
|
573
|
-
expect(existsSync(join(TEST_DIR, "USER.md"))).toBe(true);
|
|
574
644
|
});
|
|
575
645
|
|
|
576
646
|
test("handles missing template gracefully (warn, no crash)", () => {
|
|
@@ -595,7 +665,6 @@ describe("ensurePromptFiles", () => {
|
|
|
595
665
|
// BOOTSTRAP.md was deleted by the user.
|
|
596
666
|
writeFileSync(join(TEST_DIR, "IDENTITY.md"), "My identity");
|
|
597
667
|
writeFileSync(join(TEST_DIR, "SOUL.md"), "My soul");
|
|
598
|
-
writeFileSync(join(TEST_DIR, "USER.md"), "My user");
|
|
599
668
|
|
|
600
669
|
ensurePromptFiles();
|
|
601
670
|
|
|
@@ -613,11 +682,25 @@ describe("ensurePromptFiles", () => {
|
|
|
613
682
|
expect(existsSync(bootstrapPath)).toBe(false);
|
|
614
683
|
});
|
|
615
684
|
|
|
685
|
+
test("does not treat a workspace with populated users/ as a first run", () => {
|
|
686
|
+
// Upgraded workspaces may have dropped USER.md but still carry a
|
|
687
|
+
// populated users/ directory. Presence of users/<slug>.md signals an
|
|
688
|
+
// existing install, so BOOTSTRAP.md must not be re-seeded even when
|
|
689
|
+
// SOUL.md and IDENTITY.md are absent (they will be freshly seeded from
|
|
690
|
+
// templates, but onboarding should not re-trigger).
|
|
691
|
+
mkdirSync(join(TEST_DIR, "users"), { recursive: true });
|
|
692
|
+
writeFileSync(join(TEST_DIR, "users", "sidd.md"), "# Sidd persona");
|
|
693
|
+
|
|
694
|
+
ensurePromptFiles();
|
|
695
|
+
|
|
696
|
+
const bootstrapPath = join(TEST_DIR, "BOOTSTRAP.md");
|
|
697
|
+
expect(existsSync(bootstrapPath)).toBe(false);
|
|
698
|
+
});
|
|
699
|
+
|
|
616
700
|
test("auto-deletes stale BOOTSTRAP.md when prior conversations exist", () => {
|
|
617
701
|
// Simulate a non-first-run workspace: core files + BOOTSTRAP.md still present
|
|
618
702
|
writeFileSync(join(TEST_DIR, "IDENTITY.md"), "My identity");
|
|
619
703
|
writeFileSync(join(TEST_DIR, "SOUL.md"), "My soul");
|
|
620
|
-
writeFileSync(join(TEST_DIR, "USER.md"), "My user");
|
|
621
704
|
writeFileSync(join(TEST_DIR, "BOOTSTRAP.md"), "# Stale bootstrap");
|
|
622
705
|
|
|
623
706
|
// Create a conversations directory with at least one entry
|
|
@@ -630,15 +713,18 @@ describe("ensurePromptFiles", () => {
|
|
|
630
713
|
expect(existsSync(join(TEST_DIR, "BOOTSTRAP.md"))).toBe(false);
|
|
631
714
|
});
|
|
632
715
|
|
|
633
|
-
test("
|
|
634
|
-
//
|
|
716
|
+
test("does not seed BOOTSTRAP.md when conversations exist even if core files are missing", () => {
|
|
717
|
+
// An upgraded workspace might have dropped SOUL.md/IDENTITY.md (they
|
|
718
|
+
// will be re-seeded from templates) but still carries prior
|
|
719
|
+
// conversations. Existing conversation history signals a non-fresh
|
|
720
|
+
// install, so onboarding must not re-trigger.
|
|
635
721
|
const convDir = join(TEST_DIR, "conversations");
|
|
636
722
|
mkdirSync(convDir, { recursive: true });
|
|
637
723
|
writeFileSync(join(convDir, "conv-001.json"), "{}");
|
|
638
724
|
|
|
639
725
|
ensurePromptFiles();
|
|
640
726
|
|
|
641
|
-
expect(existsSync(join(TEST_DIR, "BOOTSTRAP.md"))).toBe(
|
|
727
|
+
expect(existsSync(join(TEST_DIR, "BOOTSTRAP.md"))).toBe(false);
|
|
642
728
|
});
|
|
643
729
|
|
|
644
730
|
test("keeps BOOTSTRAP.md when no conversations exist yet", () => {
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Mocks — must be declared before any subject imports
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
// -- Logger mock ----------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
mock.module("../util/logger.js", () => ({
|
|
10
|
+
getLogger: () =>
|
|
11
|
+
new Proxy({} as Record<string, unknown>, {
|
|
12
|
+
get: () => () => {},
|
|
13
|
+
}),
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
// -- Config mock ----------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
let mockConfig: Record<string, unknown> = {};
|
|
19
|
+
|
|
20
|
+
mock.module("../config/loader.js", () => ({
|
|
21
|
+
getConfig: () => mockConfig,
|
|
22
|
+
loadConfig: () => mockConfig,
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Subject import (after mocks)
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
import {
|
|
30
|
+
type ConversationRelayNativeStrategy,
|
|
31
|
+
type MediaStreamCustomStrategy,
|
|
32
|
+
resolveTelephonySttRouting,
|
|
33
|
+
} from "../calls/telephony-stt-routing.js";
|
|
34
|
+
import {
|
|
35
|
+
getProviderEntry,
|
|
36
|
+
listProviderEntries,
|
|
37
|
+
} from "../providers/speech-to-text/provider-catalog.js";
|
|
38
|
+
import type { SttProviderId } from "../stt/types.js";
|
|
39
|
+
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Helpers
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
function buildConfig(overrides: {
|
|
45
|
+
provider?: string;
|
|
46
|
+
}): Record<string, unknown> {
|
|
47
|
+
return {
|
|
48
|
+
services: {
|
|
49
|
+
stt: {
|
|
50
|
+
mode: "your-own",
|
|
51
|
+
provider: overrides.provider ?? "deepgram",
|
|
52
|
+
providers: {},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Tests — Provider-to-strategy mapping (catalog-driven)
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
describe("resolveTelephonySttRouting", () => {
|
|
63
|
+
beforeEach(() => {
|
|
64
|
+
mockConfig = buildConfig({});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// -----------------------------------------------------------------------
|
|
68
|
+
// Deepgram → conversation-relay-native (from catalog)
|
|
69
|
+
// -----------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
describe("deepgram", () => {
|
|
72
|
+
test("resolves to conversation-relay-native with Deepgram transcriptionProvider", () => {
|
|
73
|
+
mockConfig = buildConfig({ provider: "deepgram" });
|
|
74
|
+
|
|
75
|
+
const result = resolveTelephonySttRouting();
|
|
76
|
+
|
|
77
|
+
expect(result.status).toBe("resolved");
|
|
78
|
+
if (result.status !== "resolved") return;
|
|
79
|
+
|
|
80
|
+
expect(result.strategy.strategy).toBe("conversation-relay-native");
|
|
81
|
+
const strategy = result.strategy as ConversationRelayNativeStrategy;
|
|
82
|
+
expect(strategy.providerId).toBe("deepgram");
|
|
83
|
+
expect(strategy.transcriptionProvider).toBe("Deepgram");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("defaults speechModel to nova-3", () => {
|
|
87
|
+
mockConfig = buildConfig({ provider: "deepgram" });
|
|
88
|
+
|
|
89
|
+
const result = resolveTelephonySttRouting();
|
|
90
|
+
|
|
91
|
+
expect(result.status).toBe("resolved");
|
|
92
|
+
if (result.status !== "resolved") return;
|
|
93
|
+
|
|
94
|
+
const strategy = result.strategy as ConversationRelayNativeStrategy;
|
|
95
|
+
expect(strategy.speechModel).toBe("nova-3");
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("speechModel matches catalog telephonyRouting.twilioNativeMapping.defaultSpeechModel", () => {
|
|
99
|
+
mockConfig = buildConfig({ provider: "deepgram" });
|
|
100
|
+
const entry = getProviderEntry("deepgram");
|
|
101
|
+
|
|
102
|
+
const result = resolveTelephonySttRouting();
|
|
103
|
+
|
|
104
|
+
expect(result.status).toBe("resolved");
|
|
105
|
+
if (result.status !== "resolved") return;
|
|
106
|
+
|
|
107
|
+
const strategy = result.strategy as ConversationRelayNativeStrategy;
|
|
108
|
+
expect(strategy.speechModel).toBe(
|
|
109
|
+
entry?.telephonyRouting.twilioNativeMapping?.defaultSpeechModel,
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// -----------------------------------------------------------------------
|
|
115
|
+
// Google Gemini → conversation-relay-native (from catalog)
|
|
116
|
+
// -----------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
describe("google-gemini", () => {
|
|
119
|
+
test("resolves to conversation-relay-native with Google transcriptionProvider", () => {
|
|
120
|
+
mockConfig = buildConfig({ provider: "google-gemini" });
|
|
121
|
+
|
|
122
|
+
const result = resolveTelephonySttRouting();
|
|
123
|
+
|
|
124
|
+
expect(result.status).toBe("resolved");
|
|
125
|
+
if (result.status !== "resolved") return;
|
|
126
|
+
|
|
127
|
+
expect(result.strategy.strategy).toBe("conversation-relay-native");
|
|
128
|
+
const strategy = result.strategy as ConversationRelayNativeStrategy;
|
|
129
|
+
expect(strategy.providerId).toBe("google-gemini");
|
|
130
|
+
expect(strategy.transcriptionProvider).toBe("Google");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("leaves speechModel undefined (uses provider default)", () => {
|
|
134
|
+
mockConfig = buildConfig({ provider: "google-gemini" });
|
|
135
|
+
|
|
136
|
+
const result = resolveTelephonySttRouting();
|
|
137
|
+
|
|
138
|
+
expect(result.status).toBe("resolved");
|
|
139
|
+
if (result.status !== "resolved") return;
|
|
140
|
+
|
|
141
|
+
const strategy = result.strategy as ConversationRelayNativeStrategy;
|
|
142
|
+
expect(strategy.speechModel).toBeUndefined();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("speechModel matches catalog telephonyRouting.twilioNativeMapping.defaultSpeechModel", () => {
|
|
146
|
+
mockConfig = buildConfig({ provider: "google-gemini" });
|
|
147
|
+
const entry = getProviderEntry("google-gemini");
|
|
148
|
+
|
|
149
|
+
const result = resolveTelephonySttRouting();
|
|
150
|
+
|
|
151
|
+
expect(result.status).toBe("resolved");
|
|
152
|
+
if (result.status !== "resolved") return;
|
|
153
|
+
|
|
154
|
+
const strategy = result.strategy as ConversationRelayNativeStrategy;
|
|
155
|
+
expect(strategy.speechModel).toBe(
|
|
156
|
+
entry?.telephonyRouting.twilioNativeMapping?.defaultSpeechModel,
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// -----------------------------------------------------------------------
|
|
162
|
+
// OpenAI Whisper → media-stream-custom (from catalog)
|
|
163
|
+
// -----------------------------------------------------------------------
|
|
164
|
+
|
|
165
|
+
describe("openai-whisper", () => {
|
|
166
|
+
test("resolves to media-stream-custom strategy", () => {
|
|
167
|
+
mockConfig = buildConfig({ provider: "openai-whisper" });
|
|
168
|
+
|
|
169
|
+
const result = resolveTelephonySttRouting();
|
|
170
|
+
|
|
171
|
+
expect(result.status).toBe("resolved");
|
|
172
|
+
if (result.status !== "resolved") return;
|
|
173
|
+
|
|
174
|
+
expect(result.strategy.strategy).toBe("media-stream-custom");
|
|
175
|
+
const strategy = result.strategy as MediaStreamCustomStrategy;
|
|
176
|
+
expect(strategy.providerId).toBe("openai-whisper");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("media-stream-custom strategy does not include speechModel", () => {
|
|
180
|
+
mockConfig = buildConfig({ provider: "openai-whisper" });
|
|
181
|
+
|
|
182
|
+
const result = resolveTelephonySttRouting();
|
|
183
|
+
|
|
184
|
+
expect(result.status).toBe("resolved");
|
|
185
|
+
if (result.status !== "resolved") return;
|
|
186
|
+
|
|
187
|
+
// media-stream-custom has no speechModel property
|
|
188
|
+
expect(result.strategy.strategy).toBe("media-stream-custom");
|
|
189
|
+
expect("speechModel" in result.strategy).toBe(false);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// -----------------------------------------------------------------------
|
|
194
|
+
// Unknown / malformed provider handling
|
|
195
|
+
// -----------------------------------------------------------------------
|
|
196
|
+
|
|
197
|
+
describe("unknown provider handling", () => {
|
|
198
|
+
test("returns unknown-provider for a provider not in the catalog", () => {
|
|
199
|
+
mockConfig = buildConfig({ provider: "nonexistent-provider" as string });
|
|
200
|
+
|
|
201
|
+
const result = resolveTelephonySttRouting();
|
|
202
|
+
|
|
203
|
+
expect(result.status).toBe("unknown-provider");
|
|
204
|
+
if (result.status !== "unknown-provider") return;
|
|
205
|
+
|
|
206
|
+
expect(result.providerId).toBe("nonexistent-provider");
|
|
207
|
+
expect(result.reason).toContain("nonexistent-provider");
|
|
208
|
+
expect(result.reason).toContain("not in the provider catalog");
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("returns unknown-provider for empty-string provider", () => {
|
|
212
|
+
mockConfig = buildConfig({ provider: "" as string });
|
|
213
|
+
|
|
214
|
+
const result = resolveTelephonySttRouting();
|
|
215
|
+
|
|
216
|
+
expect(result.status).toBe("unknown-provider");
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// -----------------------------------------------------------------------
|
|
221
|
+
// Strategy discrimination correctness
|
|
222
|
+
// -----------------------------------------------------------------------
|
|
223
|
+
|
|
224
|
+
describe("strategy discrimination", () => {
|
|
225
|
+
test("conversation-relay-native strategies always have transcriptionProvider", () => {
|
|
226
|
+
for (const provider of ["deepgram", "google-gemini"]) {
|
|
227
|
+
mockConfig = buildConfig({ provider });
|
|
228
|
+
|
|
229
|
+
const result = resolveTelephonySttRouting();
|
|
230
|
+
expect(result.status).toBe("resolved");
|
|
231
|
+
if (result.status !== "resolved") return;
|
|
232
|
+
|
|
233
|
+
expect(result.strategy.strategy).toBe("conversation-relay-native");
|
|
234
|
+
const strategy = result.strategy as ConversationRelayNativeStrategy;
|
|
235
|
+
expect(strategy.transcriptionProvider).toBeDefined();
|
|
236
|
+
expect(strategy.transcriptionProvider.length).toBeGreaterThan(0);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test("media-stream-custom strategies never have transcriptionProvider", () => {
|
|
241
|
+
mockConfig = buildConfig({ provider: "openai-whisper" });
|
|
242
|
+
|
|
243
|
+
const result = resolveTelephonySttRouting();
|
|
244
|
+
expect(result.status).toBe("resolved");
|
|
245
|
+
if (result.status !== "resolved") return;
|
|
246
|
+
|
|
247
|
+
expect(result.strategy.strategy).toBe("media-stream-custom");
|
|
248
|
+
expect("transcriptionProvider" in result.strategy).toBe(false);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test("all resolved strategies include the original providerId", () => {
|
|
252
|
+
const providers: SttProviderId[] = [
|
|
253
|
+
"deepgram",
|
|
254
|
+
"google-gemini",
|
|
255
|
+
"openai-whisper",
|
|
256
|
+
];
|
|
257
|
+
for (const provider of providers) {
|
|
258
|
+
mockConfig = buildConfig({ provider });
|
|
259
|
+
|
|
260
|
+
const result = resolveTelephonySttRouting();
|
|
261
|
+
expect(result.status).toBe("resolved");
|
|
262
|
+
if (result.status !== "resolved") return;
|
|
263
|
+
|
|
264
|
+
expect(result.strategy.providerId).toBe(provider);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// -----------------------------------------------------------------------
|
|
270
|
+
// Catalog-driven mapping verification
|
|
271
|
+
// -----------------------------------------------------------------------
|
|
272
|
+
|
|
273
|
+
describe("catalog-driven mapping", () => {
|
|
274
|
+
test("every catalog entry with conversation-relay-native routing resolves to that strategy", () => {
|
|
275
|
+
const nativeEntries = listProviderEntries().filter(
|
|
276
|
+
(e) => e.telephonyRouting.strategyKind === "conversation-relay-native",
|
|
277
|
+
);
|
|
278
|
+
expect(nativeEntries.length).toBeGreaterThan(0);
|
|
279
|
+
|
|
280
|
+
for (const entry of nativeEntries) {
|
|
281
|
+
mockConfig = buildConfig({ provider: entry.id });
|
|
282
|
+
|
|
283
|
+
const result = resolveTelephonySttRouting();
|
|
284
|
+
expect(result.status).toBe("resolved");
|
|
285
|
+
if (result.status !== "resolved") return;
|
|
286
|
+
|
|
287
|
+
expect(result.strategy.strategy).toBe("conversation-relay-native");
|
|
288
|
+
const strategy = result.strategy as ConversationRelayNativeStrategy;
|
|
289
|
+
expect(strategy.transcriptionProvider).toBe(
|
|
290
|
+
entry.telephonyRouting.twilioNativeMapping!.provider,
|
|
291
|
+
);
|
|
292
|
+
expect(strategy.speechModel).toBe(
|
|
293
|
+
entry.telephonyRouting.twilioNativeMapping!.defaultSpeechModel,
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test("every catalog entry with media-stream-custom routing resolves to that strategy", () => {
|
|
299
|
+
const customEntries = listProviderEntries().filter(
|
|
300
|
+
(e) => e.telephonyRouting.strategyKind === "media-stream-custom",
|
|
301
|
+
);
|
|
302
|
+
expect(customEntries.length).toBeGreaterThan(0);
|
|
303
|
+
|
|
304
|
+
for (const entry of customEntries) {
|
|
305
|
+
mockConfig = buildConfig({ provider: entry.id });
|
|
306
|
+
|
|
307
|
+
const result = resolveTelephonySttRouting();
|
|
308
|
+
expect(result.status).toBe("resolved");
|
|
309
|
+
if (result.status !== "resolved") return;
|
|
310
|
+
|
|
311
|
+
expect(result.strategy.strategy).toBe("media-stream-custom");
|
|
312
|
+
expect(result.strategy.providerId).toBe(entry.id);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test("routing module contains no hardcoded provider-to-Twilio map", async () => {
|
|
317
|
+
// Read the source file and verify the hardcoded map was removed.
|
|
318
|
+
// This is a structural assertion: the catalog is the sole source of truth.
|
|
319
|
+
const sourceFile = Bun.file(
|
|
320
|
+
new URL("../calls/telephony-stt-routing.ts", import.meta.url).pathname,
|
|
321
|
+
);
|
|
322
|
+
const source = await sourceFile.text();
|
|
323
|
+
|
|
324
|
+
expect(source).not.toContain("TWILIO_NATIVE_PROVIDER_MAP");
|
|
325
|
+
expect(source).not.toContain("new Map<SttProviderId");
|
|
326
|
+
expect(source).not.toContain("DEEPGRAM_DEFAULT_SPEECH_MODEL");
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
});
|
|
@@ -450,8 +450,10 @@ describe("buildSanitizedEnv", () => {
|
|
|
450
450
|
delete process.env.LC_ALL;
|
|
451
451
|
|
|
452
452
|
const env = buildSanitizedEnv();
|
|
453
|
-
|
|
454
|
-
|
|
453
|
+
const expectedLocale =
|
|
454
|
+
process.platform === "darwin" ? "en_US.UTF-8" : "C.UTF-8";
|
|
455
|
+
expect(env.LANG).toBe(expectedLocale);
|
|
456
|
+
expect(env.LC_ALL).toBe(expectedLocale);
|
|
455
457
|
});
|
|
456
458
|
|
|
457
459
|
test("injects INTERNAL_GATEWAY_BASE_URL from gateway config", () => {
|
|
@@ -530,12 +532,21 @@ describe("Native sandbox backend", () => {
|
|
|
530
532
|
expect(result.sandboxed).toBe(true);
|
|
531
533
|
});
|
|
532
534
|
|
|
533
|
-
test("
|
|
535
|
+
test("escapes working dir with SBPL metacharacters", () => {
|
|
536
|
+
// SBPL metacharacters (", (, ), ;, \) are backslash-escaped inside the
|
|
537
|
+
// profile string rather than rejected, so wrap() should succeed.
|
|
534
538
|
const backend = new NativeBackend();
|
|
535
|
-
expect(
|
|
536
|
-
expect(
|
|
537
|
-
expect(
|
|
538
|
-
expect(
|
|
539
|
+
expect(backend.wrap("echo hi", '/tmp/foo"bar').sandboxed).toBe(true);
|
|
540
|
+
expect(backend.wrap("echo hi", "/tmp/foo(bar").sandboxed).toBe(true);
|
|
541
|
+
expect(backend.wrap("echo hi", "/tmp/foo;bar").sandboxed).toBe(true);
|
|
542
|
+
expect(backend.wrap("echo hi", "/tmp/foo\\bar").sandboxed).toBe(true);
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
test("rejects working dir with newline characters", () => {
|
|
546
|
+
// Newlines/CRs cannot appear in real paths and would break the profile.
|
|
547
|
+
const backend = new NativeBackend();
|
|
548
|
+
expect(() => backend.wrap("echo hi", "/tmp/foo\nbar")).toThrow(ToolError);
|
|
549
|
+
expect(() => backend.wrap("echo hi", "/tmp/foo\rbar")).toThrow(ToolError);
|
|
539
550
|
});
|
|
540
551
|
|
|
541
552
|
test("accepts working dir with safe special characters", () => {
|
|
@@ -16,7 +16,9 @@ import { tmpdir } from "node:os";
|
|
|
16
16
|
import { join } from "node:path";
|
|
17
17
|
import { afterAll } from "bun:test";
|
|
18
18
|
|
|
19
|
+
import { installGatewayIpcMock } from "../__tests__/mock-gateway-ipc.js";
|
|
19
20
|
import { resetDb } from "../memory/db-connection.js";
|
|
21
|
+
import { _setStorePath } from "../security/encrypted-store.js";
|
|
20
22
|
|
|
21
23
|
const testDir = realpathSync(
|
|
22
24
|
mkdtempSync(join(tmpdir(), "vellum-test-workspace-")),
|
|
@@ -25,6 +27,22 @@ process.env.VELLUM_WORKSPACE_DIR = testDir;
|
|
|
25
27
|
process.env.VELLUM_PLATFORM_URL = "https://test-platform.vellum.ai";
|
|
26
28
|
process.exitCode = 0;
|
|
27
29
|
|
|
30
|
+
// Isolate the encrypted credential store per test file. Without this,
|
|
31
|
+
// parallel test processes all read/write the same ~/.vellum/protected/keys.enc,
|
|
32
|
+
// causing races when one file deletes a key while another sets it.
|
|
33
|
+
_setStorePath(join(testDir, "keys.enc"));
|
|
34
|
+
|
|
35
|
+
// Mock gateway IPC so no test accidentally connects to a real gateway socket.
|
|
36
|
+
// Tests that need to control IPC responses use mockGatewayIpc() / resetMockGatewayIpc().
|
|
37
|
+
installGatewayIpcMock();
|
|
38
|
+
|
|
39
|
+
// Force-close any DB connection inherited from the parent process (e.g. when
|
|
40
|
+
// the test runner is spawned by the running assistant via a pre-push hook).
|
|
41
|
+
// Without this, the db singleton in db-connection.ts may still point at the
|
|
42
|
+
// real ~/.vellum/workspace database, and test cleanup (DELETE FROM …) would
|
|
43
|
+
// wipe production data — contacts, channels, credentials, etc.
|
|
44
|
+
resetDb();
|
|
45
|
+
|
|
28
46
|
// Prevent tests from routing credential writes through the real CES
|
|
29
47
|
// (Credential Execution Service). Without this, setSecureKeyAsync() in
|
|
30
48
|
// containerized environments writes to the live credential store.
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { Message } from "../../providers/types.js";
|
|
2
2
|
|
|
3
|
-
/** The
|
|
3
|
+
/** The browser tool names provided by the browser skill. */
|
|
4
4
|
export const BROWSER_TOOL_NAMES = [
|
|
5
5
|
"browser_navigate",
|
|
6
6
|
"browser_snapshot",
|
|
7
7
|
"browser_screenshot",
|
|
8
8
|
"browser_close",
|
|
9
|
+
"browser_attach",
|
|
10
|
+
"browser_detach",
|
|
9
11
|
"browser_click",
|
|
10
12
|
"browser_type",
|
|
11
13
|
"browser_press_key",
|
|
@@ -16,6 +18,7 @@ export const BROWSER_TOOL_NAMES = [
|
|
|
16
18
|
"browser_extract",
|
|
17
19
|
"browser_wait_for_download",
|
|
18
20
|
"browser_fill_credential",
|
|
21
|
+
"browser_status",
|
|
19
22
|
] as const;
|
|
20
23
|
|
|
21
24
|
/** Number of browser tools provided by the skill. */
|