@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
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Backfill `services.tts.provider` and `services.tts.providers.*` from
|
|
8
|
+
* legacy config keys, then remove the legacy keys.
|
|
9
|
+
*
|
|
10
|
+
* Legacy keys consulted:
|
|
11
|
+
* - `calls.voice.ttsProvider` -> `services.tts.provider`
|
|
12
|
+
* - `elevenlabs.*` -> `services.tts.providers.elevenlabs.*`
|
|
13
|
+
* - `fishAudio.*` -> `services.tts.providers.fish-audio.*`
|
|
14
|
+
*
|
|
15
|
+
* In mixed legacy states, `calls.voice.ttsProvider` wins as the selected
|
|
16
|
+
* provider. Provider-specific values are copied from the legacy top-level
|
|
17
|
+
* sections into their canonical `services.tts.providers.*` locations.
|
|
18
|
+
*
|
|
19
|
+
* After copying, legacy fields are removed so no compatibility shim is
|
|
20
|
+
* required in the runtime resolver.
|
|
21
|
+
*
|
|
22
|
+
* Idempotent: re-running the migration on an already-migrated config
|
|
23
|
+
* produces no changes.
|
|
24
|
+
*/
|
|
25
|
+
export const ttsProviderUnificationMigration: WorkspaceMigration = {
|
|
26
|
+
id: "032-tts-provider-unification",
|
|
27
|
+
description:
|
|
28
|
+
"Backfill services.tts.provider and services.tts.providers.* from legacy TTS config keys, then remove legacy keys",
|
|
29
|
+
run(workspaceDir: string): void {
|
|
30
|
+
const configPath = join(workspaceDir, "config.json");
|
|
31
|
+
if (!existsSync(configPath)) return;
|
|
32
|
+
|
|
33
|
+
let config: Record<string, unknown>;
|
|
34
|
+
try {
|
|
35
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
36
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
37
|
+
config = raw as Record<string, unknown>;
|
|
38
|
+
} catch {
|
|
39
|
+
return; // Malformed config — skip
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Resolve legacy TTS provider from calls.voice.ttsProvider
|
|
43
|
+
const legacyProvider = resolveLegacyProvider(config);
|
|
44
|
+
|
|
45
|
+
// Resolve legacy provider-specific configs
|
|
46
|
+
const legacyElevenlabs = extractLegacyElevenlabs(config);
|
|
47
|
+
const legacyFishAudio = extractLegacyFishAudio(config);
|
|
48
|
+
|
|
49
|
+
// If no legacy data exists, nothing to migrate
|
|
50
|
+
if (!legacyProvider && !legacyElevenlabs && !legacyFishAudio) return;
|
|
51
|
+
|
|
52
|
+
// Ensure services.tts exists
|
|
53
|
+
const services = ensureObj(config, "services");
|
|
54
|
+
const tts = ensureObj(services, "tts");
|
|
55
|
+
|
|
56
|
+
// Set provider if not already explicitly set
|
|
57
|
+
if (!("provider" in tts) && legacyProvider) {
|
|
58
|
+
tts.provider = legacyProvider;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Set mode to your-own (always)
|
|
62
|
+
if (!("mode" in tts)) {
|
|
63
|
+
tts.mode = "your-own";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Backfill providers map
|
|
67
|
+
const providers = ensureObj(tts, "providers");
|
|
68
|
+
|
|
69
|
+
if (legacyElevenlabs) {
|
|
70
|
+
const elTarget = ensureObj(providers, "elevenlabs");
|
|
71
|
+
// Only copy keys that are not already present in canonical
|
|
72
|
+
for (const [key, value] of Object.entries(legacyElevenlabs)) {
|
|
73
|
+
if (!(key in elTarget)) {
|
|
74
|
+
elTarget[key] = value;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (legacyFishAudio) {
|
|
80
|
+
const faTarget = ensureObj(providers, "fish-audio");
|
|
81
|
+
for (const [key, value] of Object.entries(legacyFishAudio)) {
|
|
82
|
+
if (!(key in faTarget)) {
|
|
83
|
+
faTarget[key] = value;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Clean up legacy fields — canonical paths are now fully materialised.
|
|
89
|
+
// Remove calls.voice.ttsProvider (but preserve the rest of calls.voice)
|
|
90
|
+
removeLegacyTtsProvider(config);
|
|
91
|
+
// Remove top-level elevenlabs and fishAudio sections
|
|
92
|
+
delete config.elevenlabs;
|
|
93
|
+
delete config.fishAudio;
|
|
94
|
+
|
|
95
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
96
|
+
},
|
|
97
|
+
down(workspaceDir: string): void {
|
|
98
|
+
const configPath = join(workspaceDir, "config.json");
|
|
99
|
+
if (!existsSync(configPath)) return;
|
|
100
|
+
|
|
101
|
+
let config: Record<string, unknown>;
|
|
102
|
+
try {
|
|
103
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
104
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
105
|
+
config = raw as Record<string, unknown>;
|
|
106
|
+
} catch {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Restore legacy keys from canonical services.tts before removing it.
|
|
111
|
+
const services = config.services;
|
|
112
|
+
if (services && typeof services === "object" && !Array.isArray(services)) {
|
|
113
|
+
const servicesObj = services as Record<string, unknown>;
|
|
114
|
+
const tts = servicesObj.tts;
|
|
115
|
+
if (tts && typeof tts === "object" && !Array.isArray(tts)) {
|
|
116
|
+
const ttsObj = tts as Record<string, unknown>;
|
|
117
|
+
|
|
118
|
+
// Restore calls.voice.ttsProvider from services.tts.provider
|
|
119
|
+
const provider = ttsObj.provider;
|
|
120
|
+
if (typeof provider === "string") {
|
|
121
|
+
const calls = ensureObj(config, "calls");
|
|
122
|
+
const voice = ensureObj(calls, "voice");
|
|
123
|
+
voice.ttsProvider = provider;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Restore top-level elevenlabs and fishAudio from providers map
|
|
127
|
+
const providers = ttsObj.providers;
|
|
128
|
+
if (
|
|
129
|
+
providers &&
|
|
130
|
+
typeof providers === "object" &&
|
|
131
|
+
!Array.isArray(providers)
|
|
132
|
+
) {
|
|
133
|
+
const providersObj = providers as Record<string, unknown>;
|
|
134
|
+
|
|
135
|
+
const elConfig = providersObj.elevenlabs;
|
|
136
|
+
if (
|
|
137
|
+
elConfig &&
|
|
138
|
+
typeof elConfig === "object" &&
|
|
139
|
+
!Array.isArray(elConfig)
|
|
140
|
+
) {
|
|
141
|
+
config.elevenlabs = { ...(elConfig as Record<string, unknown>) };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const faConfig = providersObj["fish-audio"];
|
|
145
|
+
if (
|
|
146
|
+
faConfig &&
|
|
147
|
+
typeof faConfig === "object" &&
|
|
148
|
+
!Array.isArray(faConfig)
|
|
149
|
+
) {
|
|
150
|
+
config.fishAudio = { ...(faConfig as Record<string, unknown>) };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
delete servicesObj.tts;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// Helpers
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
function ensureObj(
|
|
167
|
+
parent: Record<string, unknown>,
|
|
168
|
+
key: string,
|
|
169
|
+
): Record<string, unknown> {
|
|
170
|
+
if (
|
|
171
|
+
!(key in parent) ||
|
|
172
|
+
parent[key] == null ||
|
|
173
|
+
typeof parent[key] !== "object" ||
|
|
174
|
+
Array.isArray(parent[key])
|
|
175
|
+
) {
|
|
176
|
+
parent[key] = {};
|
|
177
|
+
}
|
|
178
|
+
return parent[key] as Record<string, unknown>;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Extract legacy provider selection from calls.voice.ttsProvider. */
|
|
182
|
+
function resolveLegacyProvider(config: Record<string, unknown>): string | null {
|
|
183
|
+
const calls = config.calls;
|
|
184
|
+
if (!calls || typeof calls !== "object" || Array.isArray(calls)) return null;
|
|
185
|
+
const callsObj = calls as Record<string, unknown>;
|
|
186
|
+
|
|
187
|
+
const voice = callsObj.voice;
|
|
188
|
+
if (!voice || typeof voice !== "object" || Array.isArray(voice)) return null;
|
|
189
|
+
const voiceObj = voice as Record<string, unknown>;
|
|
190
|
+
|
|
191
|
+
const provider = voiceObj.ttsProvider;
|
|
192
|
+
return typeof provider === "string" ? provider : null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Remove calls.voice.ttsProvider from config while preserving other voice fields. */
|
|
196
|
+
function removeLegacyTtsProvider(config: Record<string, unknown>): void {
|
|
197
|
+
const calls = config.calls;
|
|
198
|
+
if (!calls || typeof calls !== "object" || Array.isArray(calls)) return;
|
|
199
|
+
const callsObj = calls as Record<string, unknown>;
|
|
200
|
+
|
|
201
|
+
const voice = callsObj.voice;
|
|
202
|
+
if (!voice || typeof voice !== "object" || Array.isArray(voice)) return;
|
|
203
|
+
const voiceObj = voice as Record<string, unknown>;
|
|
204
|
+
|
|
205
|
+
delete voiceObj.ttsProvider;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Extract legacy ElevenLabs config from top-level elevenlabs object. */
|
|
209
|
+
function extractLegacyElevenlabs(
|
|
210
|
+
config: Record<string, unknown>,
|
|
211
|
+
): Record<string, unknown> | null {
|
|
212
|
+
const el = config.elevenlabs;
|
|
213
|
+
if (!el || typeof el !== "object" || Array.isArray(el)) return null;
|
|
214
|
+
const obj = el as Record<string, unknown>;
|
|
215
|
+
// Only return if there are non-empty keys
|
|
216
|
+
return Object.keys(obj).length > 0 ? { ...obj } : null;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Extract legacy Fish Audio config from top-level fishAudio object. */
|
|
220
|
+
function extractLegacyFishAudio(
|
|
221
|
+
config: Record<string, unknown>,
|
|
222
|
+
): Record<string, unknown> | null {
|
|
223
|
+
const fa = config.fishAudio;
|
|
224
|
+
if (!fa || typeof fa !== "object" || Array.isArray(fa)) return null;
|
|
225
|
+
const obj = fa as Record<string, unknown>;
|
|
226
|
+
return Object.keys(obj).length > 0 ? { ...obj } : null;
|
|
227
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Materialize explicit `services.stt` configuration on disk.
|
|
8
|
+
*
|
|
9
|
+
* Prior to this migration the STT block was only populated at runtime via
|
|
10
|
+
* Zod `.default()` values in the schema. This meant existing workspaces had
|
|
11
|
+
* no `services.stt` in their `config.json` at all, making it invisible
|
|
12
|
+
* to users and tooling that inspects config on disk.
|
|
13
|
+
*
|
|
14
|
+
* This migration writes a canonical `services.stt` block when missing or
|
|
15
|
+
* partial, backfilling only structural fields:
|
|
16
|
+
*
|
|
17
|
+
* - `services.stt.mode` -> `"your-own"`
|
|
18
|
+
* - `services.stt.provider` -> `"deepgram"`
|
|
19
|
+
* - `services.stt.providers` -> `{}` (empty object — sparse map)
|
|
20
|
+
*
|
|
21
|
+
* It does NOT seed per-provider entries (`openai-whisper`, `deepgram`, etc.)
|
|
22
|
+
* — the providers map is sparse and only holds entries the user explicitly
|
|
23
|
+
* configures. Adding a new provider ID does not require a migration.
|
|
24
|
+
*
|
|
25
|
+
* It never clobbers user-defined STT values — only fills in what is missing.
|
|
26
|
+
*
|
|
27
|
+
* Idempotent: re-running the migration on an already-migrated config
|
|
28
|
+
* produces no changes.
|
|
29
|
+
*/
|
|
30
|
+
export const sttServiceExplicitConfigMigration: WorkspaceMigration = {
|
|
31
|
+
id: "033-stt-service-explicit-config",
|
|
32
|
+
description:
|
|
33
|
+
"Materialize explicit services.stt provider settings on disk (mode, provider, providers)",
|
|
34
|
+
run(workspaceDir: string): void {
|
|
35
|
+
const configPath = join(workspaceDir, "config.json");
|
|
36
|
+
if (!existsSync(configPath)) return;
|
|
37
|
+
|
|
38
|
+
let config: Record<string, unknown>;
|
|
39
|
+
try {
|
|
40
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
41
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
42
|
+
config = raw as Record<string, unknown>;
|
|
43
|
+
} catch {
|
|
44
|
+
return; // Malformed JSON — skip
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Ensure services.stt exists as an object
|
|
48
|
+
const services = ensureObj(config, "services");
|
|
49
|
+
const stt = ensureObj(services, "stt");
|
|
50
|
+
|
|
51
|
+
let changed = false;
|
|
52
|
+
|
|
53
|
+
// Backfill mode
|
|
54
|
+
if (!("mode" in stt)) {
|
|
55
|
+
stt.mode = "your-own";
|
|
56
|
+
changed = true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Backfill provider
|
|
60
|
+
if (!("provider" in stt)) {
|
|
61
|
+
stt.provider = "deepgram";
|
|
62
|
+
changed = true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Ensure providers map exists as an object (sparse — no per-provider seeding)
|
|
66
|
+
if (
|
|
67
|
+
!("providers" in stt) ||
|
|
68
|
+
stt.providers == null ||
|
|
69
|
+
typeof stt.providers !== "object" ||
|
|
70
|
+
Array.isArray(stt.providers)
|
|
71
|
+
) {
|
|
72
|
+
stt.providers = {};
|
|
73
|
+
changed = true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Only write when something actually changed
|
|
77
|
+
if (changed) {
|
|
78
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
down(workspaceDir: string): void {
|
|
82
|
+
const configPath = join(workspaceDir, "config.json");
|
|
83
|
+
if (!existsSync(configPath)) return;
|
|
84
|
+
|
|
85
|
+
let config: Record<string, unknown>;
|
|
86
|
+
try {
|
|
87
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
88
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
89
|
+
config = raw as Record<string, unknown>;
|
|
90
|
+
} catch {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Remove services.stt entirely.
|
|
95
|
+
const services = config.services;
|
|
96
|
+
if (services && typeof services === "object" && !Array.isArray(services)) {
|
|
97
|
+
const servicesObj = services as Record<string, unknown>;
|
|
98
|
+
delete servicesObj.stt;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Helpers (self-contained per migration AGENTS.md)
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
function ensureObj(
|
|
110
|
+
parent: Record<string, unknown>,
|
|
111
|
+
key: string,
|
|
112
|
+
): Record<string, unknown> {
|
|
113
|
+
if (
|
|
114
|
+
!(key in parent) ||
|
|
115
|
+
parent[key] == null ||
|
|
116
|
+
typeof parent[key] !== "object" ||
|
|
117
|
+
Array.isArray(parent[key])
|
|
118
|
+
) {
|
|
119
|
+
parent[key] = {};
|
|
120
|
+
}
|
|
121
|
+
return parent[key] as Record<string, unknown>;
|
|
122
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Remove `calls.voice.transcriptionProvider` (and `calls.voice.speechModel`)
|
|
8
|
+
* from persisted workspace configs, preserving user preferences by copying
|
|
9
|
+
* them to `services.stt.provider` before deletion.
|
|
10
|
+
*
|
|
11
|
+
* Migration 033 backfilled `services.stt.provider` to `"deepgram"`
|
|
12
|
+
* unconditionally. Users who had `calls.voice.transcriptionProvider: "Google"`
|
|
13
|
+
* were silently switched to Deepgram STT. This migration corrects that by
|
|
14
|
+
* reading the old value before removing it:
|
|
15
|
+
*
|
|
16
|
+
* - If `calls.voice.transcriptionProvider` is `"Google"` and
|
|
17
|
+
* `services.stt.provider` is still `"deepgram"` (the 033 default),
|
|
18
|
+
* set `services.stt.provider` to `"google-gemini"`.
|
|
19
|
+
* - If `calls.voice.transcriptionProvider` is `"Deepgram"` or missing,
|
|
20
|
+
* no change needed.
|
|
21
|
+
* - If `calls.voice.speechModel` was set and the provider is being
|
|
22
|
+
* corrected to `"google-gemini"`, clear the speechModel since
|
|
23
|
+
* Deepgram-specific models (e.g. "nova-3") are not valid for Google.
|
|
24
|
+
*
|
|
25
|
+
* After copying, the migration removes `calls.voice.transcriptionProvider`
|
|
26
|
+
* and `calls.voice.speechModel` from the persisted config.
|
|
27
|
+
*
|
|
28
|
+
* Idempotent: re-running the migration on an already-migrated config
|
|
29
|
+
* produces no changes.
|
|
30
|
+
*/
|
|
31
|
+
export const removeCallsVoiceTranscriptionProviderMigration: WorkspaceMigration =
|
|
32
|
+
{
|
|
33
|
+
id: "034-remove-calls-voice-transcription-provider",
|
|
34
|
+
description:
|
|
35
|
+
"Copy calls.voice.transcriptionProvider to services.stt.provider and remove legacy keys",
|
|
36
|
+
run(workspaceDir: string): void {
|
|
37
|
+
const configPath = join(workspaceDir, "config.json");
|
|
38
|
+
if (!existsSync(configPath)) return;
|
|
39
|
+
|
|
40
|
+
let config: Record<string, unknown>;
|
|
41
|
+
try {
|
|
42
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
43
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
44
|
+
config = raw as Record<string, unknown>;
|
|
45
|
+
} catch {
|
|
46
|
+
return; // Malformed JSON — skip
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let changed = false;
|
|
50
|
+
|
|
51
|
+
// ── Read legacy values ──────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
const calls = getObj(config, "calls");
|
|
54
|
+
const voice = calls ? getObj(calls, "voice") : null;
|
|
55
|
+
|
|
56
|
+
const legacyProvider =
|
|
57
|
+
voice && typeof voice.transcriptionProvider === "string"
|
|
58
|
+
? voice.transcriptionProvider
|
|
59
|
+
: null;
|
|
60
|
+
|
|
61
|
+
// ── Copy preference to services.stt.provider if needed ─────────────
|
|
62
|
+
|
|
63
|
+
if (legacyProvider === "Google") {
|
|
64
|
+
const services = getObj(config, "services");
|
|
65
|
+
const stt = services ? getObj(services, "stt") : null;
|
|
66
|
+
|
|
67
|
+
if (stt && typeof stt.provider === "string") {
|
|
68
|
+
// Only overwrite if services.stt looks like the untouched 033 default.
|
|
69
|
+
// Migration 033 backfilled { mode: "your-own", provider: "deepgram",
|
|
70
|
+
// providers: {} }. If the user later customized the section (changed
|
|
71
|
+
// mode, added provider-specific config, or set a different provider),
|
|
72
|
+
// we treat it as an intentional choice and leave it alone. Checking
|
|
73
|
+
// for extra keys beyond the 033 structural set avoids overriding a
|
|
74
|
+
// user who explicitly chose deepgram after 033 ran and then tweaked
|
|
75
|
+
// provider settings.
|
|
76
|
+
if (stt.provider === "deepgram" && looksLike033Default(stt)) {
|
|
77
|
+
stt.provider = "google-gemini";
|
|
78
|
+
changed = true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ── Remove legacy keys from calls.voice ────────────────────────────
|
|
84
|
+
|
|
85
|
+
if (voice) {
|
|
86
|
+
if ("transcriptionProvider" in voice) {
|
|
87
|
+
delete voice.transcriptionProvider;
|
|
88
|
+
changed = true;
|
|
89
|
+
}
|
|
90
|
+
if ("speechModel" in voice) {
|
|
91
|
+
delete voice.speechModel;
|
|
92
|
+
changed = true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Only write when something actually changed
|
|
97
|
+
if (changed) {
|
|
98
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
down(workspaceDir: string): void {
|
|
102
|
+
// The down migration restores `calls.voice.transcriptionProvider`
|
|
103
|
+
// from `services.stt.provider` where possible.
|
|
104
|
+
const configPath = join(workspaceDir, "config.json");
|
|
105
|
+
if (!existsSync(configPath)) return;
|
|
106
|
+
|
|
107
|
+
let config: Record<string, unknown>;
|
|
108
|
+
try {
|
|
109
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
110
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
111
|
+
config = raw as Record<string, unknown>;
|
|
112
|
+
} catch {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const services = getObj(config, "services");
|
|
117
|
+
const stt = services ? getObj(services, "stt") : null;
|
|
118
|
+
const sttProvider =
|
|
119
|
+
stt && typeof stt.provider === "string" ? stt.provider : null;
|
|
120
|
+
|
|
121
|
+
// Reverse-map canonical provider ID to legacy enum value
|
|
122
|
+
const legacyProvider = reverseMapProvider(sttProvider);
|
|
123
|
+
|
|
124
|
+
if (!legacyProvider) return;
|
|
125
|
+
|
|
126
|
+
const calls = ensureObj(config, "calls");
|
|
127
|
+
const voice = ensureObj(calls, "voice");
|
|
128
|
+
|
|
129
|
+
if (!("transcriptionProvider" in voice)) {
|
|
130
|
+
voice.transcriptionProvider = legacyProvider;
|
|
131
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
// Helpers (self-contained per migration AGENTS.md)
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Safely get a nested object value. Returns null if the key is missing
|
|
142
|
+
* or the value is not a plain object.
|
|
143
|
+
*/
|
|
144
|
+
function getObj(
|
|
145
|
+
parent: Record<string, unknown>,
|
|
146
|
+
key: string,
|
|
147
|
+
): Record<string, unknown> | null {
|
|
148
|
+
const val = parent[key];
|
|
149
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
150
|
+
return val as Record<string, unknown>;
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Ensure a nested key is an object. Creates it if missing or non-object.
|
|
157
|
+
*/
|
|
158
|
+
function ensureObj(
|
|
159
|
+
parent: Record<string, unknown>,
|
|
160
|
+
key: string,
|
|
161
|
+
): Record<string, unknown> {
|
|
162
|
+
if (
|
|
163
|
+
!(key in parent) ||
|
|
164
|
+
parent[key] == null ||
|
|
165
|
+
typeof parent[key] !== "object" ||
|
|
166
|
+
Array.isArray(parent[key])
|
|
167
|
+
) {
|
|
168
|
+
parent[key] = {};
|
|
169
|
+
}
|
|
170
|
+
return parent[key] as Record<string, unknown>;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Check whether `services.stt` contains only the structural keys that
|
|
175
|
+
* migration 033 backfilled (`mode`, `provider`, `providers`) with their
|
|
176
|
+
* default values. If any other key is present or if `mode`/`providers`
|
|
177
|
+
* differ from the 033 defaults, the user has actively configured this
|
|
178
|
+
* section and we should not override their provider choice.
|
|
179
|
+
*/
|
|
180
|
+
function looksLike033Default(stt: Record<string, unknown>): boolean {
|
|
181
|
+
const keys033 = new Set(["mode", "provider", "providers"]);
|
|
182
|
+
for (const key of Object.keys(stt)) {
|
|
183
|
+
if (!keys033.has(key)) return false;
|
|
184
|
+
}
|
|
185
|
+
// Verify the other structural values match the 033 defaults
|
|
186
|
+
if ("mode" in stt && stt.mode !== "your-own") return false;
|
|
187
|
+
if ("providers" in stt) {
|
|
188
|
+
const providers = stt.providers;
|
|
189
|
+
if (
|
|
190
|
+
!providers ||
|
|
191
|
+
typeof providers !== "object" ||
|
|
192
|
+
Array.isArray(providers) ||
|
|
193
|
+
Object.keys(providers as Record<string, unknown>).length > 0
|
|
194
|
+
) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Map canonical `services.stt.provider` ID back to legacy
|
|
203
|
+
* `calls.voice.transcriptionProvider` enum value for the down migration.
|
|
204
|
+
*/
|
|
205
|
+
function reverseMapProvider(sttProvider: string | null): string | null {
|
|
206
|
+
if (!sttProvider) return null;
|
|
207
|
+
switch (sttProvider) {
|
|
208
|
+
case "deepgram":
|
|
209
|
+
return "Deepgram";
|
|
210
|
+
case "google-gemini":
|
|
211
|
+
return "Google";
|
|
212
|
+
default:
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
// Inlined template snapshot so this migration is self-contained even if
|
|
7
|
+
// the bundled template file changes or moves in a future release.
|
|
8
|
+
const SLACK_CHANNEL_PERSONA_TEMPLATE = `_ Lines starting with _ are comments - they won't appear in the system prompt
|
|
9
|
+
_ This file shapes how you behave when responding in Slack. Edit it freely.
|
|
10
|
+
|
|
11
|
+
# Slack
|
|
12
|
+
|
|
13
|
+
## Delivery
|
|
14
|
+
|
|
15
|
+
Skip the research narration. In Slack, every message you send before your final answer posts as a separate visible message - not a live stream. "Let me look that up" and "Researching now..." just add noise. Use your tools, then deliver the result.
|
|
16
|
+
|
|
17
|
+
Your personality, warmth, humor, and opinions are welcome. Just don't narrate the process of finding the answer.
|
|
18
|
+
|
|
19
|
+
## Formatting
|
|
20
|
+
|
|
21
|
+
Never use markdown tables (pipe-delimited). Slack cannot render them. Use bullet points with bold labels instead.
|
|
22
|
+
|
|
23
|
+
When presenting information from web search, cite sources as inline hyperlinks woven into your text (e.g., "the round closed at $122B, [per CNBC](url)"). Don't dump a references list at the end.
|
|
24
|
+
|
|
25
|
+
## Long-form content
|
|
26
|
+
|
|
27
|
+
When your response would be long, dense, or highly structured (reports, teardowns, detailed analyses), use your judgment on whether to write it as an attached file vs posting inline. Consider what reads better in Slack - a wall of text with "See more" truncation often doesn't.
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
export const seedSlackChannelPersonaMigration: WorkspaceMigration = {
|
|
31
|
+
id: "035-seed-slack-channel-persona",
|
|
32
|
+
description: "Seed channels/slack.md persona template for Slack responses",
|
|
33
|
+
|
|
34
|
+
down(_workspaceDir: string): void {
|
|
35
|
+
// No-op: we don't delete user-editable files on rollback.
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
run(workspaceDir: string): void {
|
|
39
|
+
const channelsDir = join(workspaceDir, "channels");
|
|
40
|
+
mkdirSync(channelsDir, { recursive: true });
|
|
41
|
+
|
|
42
|
+
const slackPath = join(channelsDir, "slack.md");
|
|
43
|
+
if (existsSync(slackPath)) {
|
|
44
|
+
// Don't overwrite user customizations.
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
writeFileSync(slackPath, SLACK_CHANNEL_PERSONA_TEMPLATE, "utf-8");
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
// Original bar seeded by earlier versions of migration 029.
|
|
7
|
+
const ORIGINAL_BAR = `**Remember aggressively.** When you learn ANY fact — a preference, a name, a date, a habit, a plan, an opinion — call \`remember\` immediately. Don't filter, don't judge importance. Remembering too much costs nothing. Forgetting something that mattered costs trust.`;
|
|
8
|
+
|
|
9
|
+
// Target bar. Some installations were seeded with this text directly; this
|
|
10
|
+
// migration normalizes the ORIGINAL_BAR population to match.
|
|
11
|
+
const NEW_BAR = `**Remember aggressively.** Capture anything concrete about your user — preferences, names, dates, habits, plans, opinions, health details, commitments. Default to remembering; only skip obvious noise (small talk, hypotheticals). Don't judge importance — filing decides that later. Call \`remember\` immediately, multiple times per conversation. Remembering too much costs nothing. Forgetting something that mattered costs trust.`;
|
|
12
|
+
|
|
13
|
+
export const updatePkbIndexBarMigration: WorkspaceMigration = {
|
|
14
|
+
id: "036-update-pkb-index-bar",
|
|
15
|
+
description:
|
|
16
|
+
"Normalize pkb/INDEX.md 'Remember aggressively' bar across both variants previously seeded by migration 029",
|
|
17
|
+
|
|
18
|
+
down(_workspaceDir: string): void {
|
|
19
|
+
// No-op: don't revert user-editable file content on rollback.
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
run(workspaceDir: string): void {
|
|
23
|
+
const indexPath = join(workspaceDir, "pkb", "INDEX.md");
|
|
24
|
+
if (!existsSync(indexPath)) return;
|
|
25
|
+
|
|
26
|
+
const current = readFileSync(indexPath, "utf-8");
|
|
27
|
+
|
|
28
|
+
if (current.includes(NEW_BAR)) return;
|
|
29
|
+
|
|
30
|
+
if (current.includes(ORIGINAL_BAR)) {
|
|
31
|
+
const updated = current.replace(ORIGINAL_BAR, NEW_BAR);
|
|
32
|
+
writeFileSync(indexPath, updated, "utf-8");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// User-edited or unknown variant — leave alone.
|
|
36
|
+
},
|
|
37
|
+
};
|