@vellumai/assistant 0.6.3 → 0.6.5
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/.prettierignore +5 -0
- package/ARCHITECTURE.md +298 -39
- package/Dockerfile +14 -3
- package/README.md +3 -4
- package/bun.lock +13 -16
- package/docs/architecture/integrations.md +1 -20
- package/docs/architecture/security.md +16 -16
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/error-handling.md +111 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +121 -0
- package/knip.json +20 -3
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +5 -4
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
- package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
- package/node_modules/@vellumai/credential-storage/package.json +2 -2
- package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
- package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
- package/node_modules/@vellumai/egress-proxy/package.json +2 -2
- package/openapi.yaml +1094 -72
- package/package.json +9 -8
- package/scripts/generate-openapi.ts +50 -12
- package/scripts/test.sh +73 -18
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
- package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
- package/src/__tests__/agent-loop.test.ts +235 -1
- package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
- package/src/__tests__/anthropic-provider.test.ts +434 -12
- package/src/__tests__/approval-cascade.test.ts +31 -10
- package/src/__tests__/approval-routes-http.test.ts +134 -10
- package/src/__tests__/assistant-attachments.test.ts +44 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
- 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 +12 -1
- package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
- package/src/__tests__/browser-skill-endstate.test.ts +52 -159
- package/src/__tests__/btw-routes.test.ts +54 -1
- package/src/__tests__/call-controller.test.ts +582 -22
- package/src/__tests__/call-site-routing-provider.test.ts +214 -0
- package/src/__tests__/catalog-cache.test.ts +27 -4
- package/src/__tests__/catalog-files.test.ts +138 -0
- package/src/__tests__/channel-approval-routes.test.ts +4 -4
- 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__/channel-reply-delivery.test.ts +300 -2
- package/src/__tests__/checker.test.ts +576 -502
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/config-analysis.test.ts +83 -0
- package/src/__tests__/config-loader-backfill.test.ts +174 -0
- package/src/__tests__/config-loader-corrupt.test.ts +183 -0
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
- package/src/__tests__/config-schema-cmd.test.ts +11 -5
- package/src/__tests__/config-schema.test.ts +1458 -198
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +45 -10
- package/src/__tests__/contact-store-user-file.test.ts +511 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-token-estimator.test.ts +191 -1
- package/src/__tests__/context-window-manager.test.ts +618 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +32 -16
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +62 -17
- package/src/__tests__/conversation-agent-loop.test.ts +510 -84
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +165 -9
- package/src/__tests__/conversation-error.test.ts +102 -1
- package/src/__tests__/conversation-history-web-search.test.ts +17 -4
- package/src/__tests__/conversation-init.benchmark.test.ts +42 -1
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-lifecycle.test.ts +336 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +32 -16
- package/src/__tests__/conversation-process-callsite.test.ts +306 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +32 -16
- package/src/__tests__/conversation-queue.test.ts +932 -76
- package/src/__tests__/conversation-routes-disk-view.test.ts +299 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +2790 -55
- package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
- package/src/__tests__/conversation-skill-tools.test.ts +12 -143
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +120 -34
- package/src/__tests__/conversation-slash-unknown.test.ts +32 -16
- package/src/__tests__/conversation-speed-override.test.ts +30 -11
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -2
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-unread-route.test.ts +2 -2
- package/src/__tests__/conversation-usage.test.ts +3 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
- package/src/__tests__/conversation-workspace-injection.test.ts +45 -15
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +46 -16
- package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +8 -3
- package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
- package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
- package/src/__tests__/credential-vault-unit.test.ts +495 -3
- package/src/__tests__/credentials-cli.test.ts +32 -16
- package/src/__tests__/cross-provider-web-search.test.ts +230 -35
- package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
- package/src/__tests__/delete-propagation.test.ts +437 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/dm-backfill.test.ts +417 -0
- package/src/__tests__/dm-persistence.test.ts +227 -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__/edit-propagation.test.ts +280 -0
- 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__/ephemeral-permissions.test.ts +93 -3
- package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
- package/src/__tests__/estimator-calibration.test.ts +213 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +101 -15
- package/src/__tests__/file-write-tool.test.ts +151 -1
- package/src/__tests__/filing-service.test.ts +255 -0
- 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 -3
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/guardian-grant-minting.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +44 -1
- 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 +166 -32
- 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__/host-shell-tool.test.ts +124 -18
- package/src/__tests__/http-user-message-parity.test.ts +29 -1
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/intent-routing.test.ts +1 -40
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/llm-catalog-parity.test.ts +174 -0
- package/src/__tests__/llm-context-normalization.test.ts +609 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-resolver.test.ts +214 -0
- package/src/__tests__/llm-schema.test.ts +223 -0
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/managed-proxy-context.test.ts +6 -2
- 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__/messaging-skill-split.test.ts +3 -34
- 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-from-url.test.ts +684 -0
- 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 +10 -84
- package/src/__tests__/notification-decision-fallback.test.ts +0 -10
- package/src/__tests__/notification-decision-identity.test.ts +0 -9
- package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
- 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 +95 -7
- package/src/__tests__/oauth2-gateway-transport.test.ts +257 -9
- package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
- package/src/__tests__/onboarding-template-contract.test.ts +6 -13
- package/src/__tests__/openai-provider.test.ts +183 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1501 -0
- package/src/__tests__/openrouter-provider-only.test.ts +135 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
- package/src/__tests__/permission-mode.test.ts +16 -0
- package/src/__tests__/permission-types.test.ts +0 -1
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/pkb-autoinject.test.ts +37 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -1
- 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 +224 -3
- package/src/__tests__/profiler-routes.test.ts +1 -1
- package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
- package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
- package/src/__tests__/provider-error-scenarios.test.ts +135 -6
- package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
- package/src/__tests__/provider-registry-ollama.test.ts +1 -2
- package/src/__tests__/proxy-approval-callback.test.ts +0 -1
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/reaction-persistence.test.ts +560 -0
- 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 +424 -6
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
- package/src/__tests__/risk-classifier-parity.test.ts +230 -0
- package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-ingress-http.test.ts +28 -0
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
- package/src/__tests__/secret-scanner-executor.test.ts +5 -1
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +34 -2
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +80 -0
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/shell-parser-property.test.ts +13 -13
- package/src/__tests__/skill-cache-store.test.ts +182 -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 +19 -30
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +564 -1
- package/src/__tests__/slack-skill.test.ts +3 -8
- package/src/__tests__/starter-bundle.test.ts +35 -0
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
- package/src/__tests__/suggestion-routes.test.ts +160 -3
- package/src/__tests__/system-prompt.test.ts +126 -53
- package/src/__tests__/task-runner.test.ts +3 -1
- package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +26 -7
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +2 -49
- package/src/__tests__/thread-backfill.test.ts +941 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +10 -6
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +88 -113
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/trust-store.test.ts +442 -103
- 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-job.test.ts +389 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
- 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 +5 -22
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/voice-session-bridge.test.ts +39 -0
- package/src/__tests__/volume-security-guard.test.ts +3 -2
- package/src/__tests__/web-search-history.test.ts +337 -0
- 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-039-drop-legacy-llm-keys.test.ts +343 -0
- package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -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-migration-unify-llm-callsite-configs.test.ts +841 -0
- package/src/__tests__/workspace-policy.test.ts +1 -11
- package/src/acp/client-handler.ts +1 -2
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +251 -19
- package/src/avatar/resvg-lazy.test.ts +136 -0
- package/src/avatar/resvg-lazy.ts +82 -9
- package/src/avatar/traits-png-sync.ts +21 -1
- 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/browser/__tests__/operations.test.ts +163 -0
- package/src/browser/identifiers.ts +51 -0
- package/src/browser/operations.ts +660 -0
- package/src/browser/types.ts +81 -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/guardian-question-copy.ts +2 -2
- 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 +9 -1
- package/src/channels/types.ts +16 -0
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/attachment.test.ts +438 -0
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/browser.test.ts +554 -0
- package/src/cli/commands/__tests__/cache.test.ts +623 -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 +28 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +130 -5
- 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/__tests__/image-generation.test.ts +666 -0
- package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
- package/src/cli/commands/__tests__/task.test.ts +913 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
- package/src/cli/commands/__tests__/ui.test.ts +1215 -0
- package/src/cli/commands/__tests__/watchers.test.ts +716 -0
- package/src/cli/commands/attachment.ts +182 -0
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/browser.ts +350 -0
- package/src/cli/commands/cache.ts +341 -0
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/config.ts +6 -6
- package/src/cli/commands/conversations-import.ts +347 -0
- package/src/cli/commands/conversations.ts +90 -0
- package/src/cli/commands/credentials.ts +0 -1
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +308 -16
- package/src/cli/commands/image-generation.ts +300 -0
- package/src/cli/commands/inference.ts +200 -0
- package/src/cli/commands/memory.ts +127 -17
- 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 -10
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -2
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -1
- package/src/cli/commands/stt.ts +339 -0
- package/src/cli/commands/task.ts +795 -0
- package/src/cli/commands/trust.ts +50 -19
- package/src/cli/commands/tts.ts +273 -0
- package/src/cli/commands/ui.ts +670 -0
- package/src/cli/commands/watchers.ts +509 -0
- package/src/cli/lib/daemon-credential-client.ts +0 -19
- package/src/cli/program.ts +53 -8
- package/src/cli.ts +0 -37
- 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/contacts/SKILL.md +2 -2
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
- 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/services/reduce.ts +1 -1
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -2
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +28 -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/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 +0 -167
- package/src/config/env-registry.ts +24 -0
- package/src/config/env.ts +39 -10
- package/src/config/feature-flag-registry.json +63 -15
- package/src/config/llm-resolver.ts +128 -0
- package/src/config/loader.ts +220 -22
- package/src/config/raw-config-utils.ts +30 -2
- package/src/config/sanitize-for-transfer.ts +35 -0
- package/src/config/schema.ts +65 -51
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +32 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -30
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +49 -14
- package/src/config/schemas/heartbeat.ts +27 -10
- package/src/config/schemas/host-browser.ts +47 -1
- package/src/config/schemas/inference.ts +3 -23
- package/src/config/schemas/llm.ts +318 -0
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/memory-processing.ts +1 -9
- package/src/config/schemas/notifications.ts +4 -11
- package/src/config/schemas/platform.ts +3 -9
- package/src/config/schemas/security.ts +33 -0
- package/src/config/schemas/services.ts +53 -4
- package/src/config/schemas/stt.ts +60 -0
- package/src/config/schemas/tts.ts +283 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/schemas/workspace-git.ts +3 -40
- package/src/config/skills.ts +6 -2
- 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/__tests__/compact-prompt.test.ts +45 -0
- package/src/context/__tests__/microcompact.test.ts +805 -0
- package/src/context/estimator-calibration.ts +136 -0
- package/src/context/microcompact.ts +443 -0
- package/src/context/post-turn-tool-result-truncation.ts +3 -2
- package/src/context/prompts/compact.md +12 -0
- package/src/context/token-estimator.ts +61 -3
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +272 -35
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/executable-discovery.ts +23 -2
- package/src/credential-execution/process-manager.test.ts +109 -0
- package/src/credential-execution/process-manager.ts +96 -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/approval-generators.ts +29 -4
- package/src/daemon/assistant-attachments.ts +24 -13
- package/src/daemon/classifier.ts +2 -2
- package/src/daemon/config-watcher.ts +99 -6
- package/src/daemon/context-overflow-reducer.ts +4 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +85 -12
- package/src/daemon/conversation-agent-loop.ts +563 -104
- package/src/daemon/conversation-attachments.ts +2 -6
- package/src/daemon/conversation-error.ts +46 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +85 -11
- package/src/daemon/conversation-messaging.ts +110 -7
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +591 -23
- package/src/daemon/conversation-queue-manager.ts +27 -0
- package/src/daemon/conversation-runtime-assembly.ts +769 -28
- package/src/daemon/conversation-slash.ts +38 -2
- package/src/daemon/conversation-surfaces.ts +483 -5
- package/src/daemon/conversation-tool-setup.ts +35 -5
- package/src/daemon/conversation-usage.ts +8 -5
- package/src/daemon/conversation.ts +193 -47
- package/src/daemon/external-skills-bootstrap.ts +41 -0
- package/src/daemon/guardian-action-generators.ts +34 -14
- package/src/daemon/handlers/config-model.test.ts +86 -0
- package/src/daemon/handlers/config-model.ts +54 -12
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +13 -3
- package/src/daemon/handlers/shared.ts +51 -1
- package/src/daemon/handlers/skills.ts +323 -79
- package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
- package/src/daemon/host-browser-proxy.ts +2 -1
- package/src/daemon/lifecycle.ts +185 -26
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/conversations.ts +48 -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 +23 -1
- 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/message-types/trust.ts +0 -2
- package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
- package/src/daemon/pkb-context-tracker.test.ts +169 -0
- package/src/daemon/pkb-context-tracker.ts +125 -0
- package/src/daemon/pkb-reminder-builder.test.ts +70 -0
- package/src/daemon/pkb-reminder-builder.ts +31 -0
- package/src/daemon/providers-setup.ts +6 -0
- package/src/daemon/server.ts +463 -10
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +9 -9
- package/src/daemon/watch-handler.ts +4 -4
- package/src/daemon/web-search-history.ts +126 -0
- package/src/email/html-renderer.ts +76 -0
- package/src/events/domain-events.ts +0 -1
- package/src/filing/filing-service.ts +9 -10
- package/src/heartbeat/heartbeat-service.ts +156 -22
- 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 +222 -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 +442 -0
- package/src/home/assistant-feed-authoring.ts +128 -0
- package/src/home/emit-feed-event.ts +162 -0
- package/src/home/feed-scheduler.ts +263 -0
- package/src/home/feed-types.ts +235 -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 +413 -0
- package/src/home/suggested-prompts.ts +101 -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__/attachment-ipc.test.ts +213 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
- package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/__tests__/socket-path.test.ts +73 -0
- package/src/ipc/__tests__/task-ipc.test.ts +577 -0
- package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
- package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
- package/src/ipc/cli-client.ts +152 -0
- package/src/ipc/cli-server.ts +252 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/attachment.ts +114 -0
- package/src/ipc/routes/browser-context.ts +61 -0
- package/src/ipc/routes/browser.ts +96 -0
- package/src/ipc/routes/cache.ts +96 -0
- package/src/ipc/routes/index.ts +21 -0
- package/src/ipc/routes/task-queue.ts +226 -0
- package/src/ipc/routes/task.ts +173 -0
- package/src/ipc/routes/ui-request.ts +50 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/ipc/routes/watcher.ts +203 -0
- package/src/ipc/socket-path.ts +100 -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 +233 -0
- package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/admin.ts +18 -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 +74 -0
- package/src/memory/conversation-attention-store.ts +13 -6
- package/src/memory/conversation-crud.ts +199 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +65 -1
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/conversation-title-service.ts +7 -4
- package/src/memory/db-init.ts +8 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/embedding-backend.ts +1 -1
- package/src/memory/graph/compaction.ts +299 -0
- package/src/memory/graph/consolidation.ts +4 -4
- package/src/memory/graph/conversation-graph-memory.ts +104 -29
- package/src/memory/graph/extraction.test.ts +295 -2
- package/src/memory/graph/extraction.ts +181 -51
- package/src/memory/graph/graph-search.test.ts +92 -0
- package/src/memory/graph/graph-search.ts +4 -1
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.test.ts +459 -0
- package/src/memory/graph/retriever.ts +257 -66
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/store.ts +41 -0
- package/src/memory/graph/tool-handlers.ts +27 -0
- package/src/memory/graph/tools.ts +6 -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 +39 -30
- package/src/memory/job-handlers/summarization.ts +2 -2
- package/src/memory/job-utils.ts +7 -1
- package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
- package/src/memory/jobs/embed-pkb-file.ts +54 -0
- package/src/memory/jobs-store.ts +106 -5
- package/src/memory/jobs-worker.ts +26 -9
- package/src/memory/llm-usage-store.ts +92 -56
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
- 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/222-strip-placeholder-sentinels-from-messages.ts +82 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-index.test.ts +368 -0
- package/src/memory/pkb/pkb-index.ts +255 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
- package/src/memory/pkb/pkb-reconcile.ts +148 -0
- package/src/memory/pkb/pkb-search.test.ts +438 -0
- package/src/memory/pkb/pkb-search.ts +137 -0
- package/src/memory/pkb/types.ts +53 -0
- package/src/memory/qdrant-client.ts +122 -1
- 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/slack-thread-store.ts +37 -0
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/adapter.ts +6 -16
- package/src/messaging/providers/gmail/client.ts +79 -6
- package/src/messaging/providers/gmail/types.ts +7 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +155 -38
- package/src/messaging/providers/slack/backfill.test.ts +257 -0
- package/src/messaging/providers/slack/backfill.ts +101 -0
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
- package/src/messaging/providers/slack/message-metadata.ts +123 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
- package/src/messaging/providers/slack/render-transcript.ts +443 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/messaging/style-analyzer.ts +5 -2
- package/src/notifications/README.md +9 -5
- package/src/notifications/decision-engine.ts +6 -12
- package/src/notifications/preference-extractor.ts +2 -6
- 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 +10 -0
- package/src/oauth/platform-connection.test.ts +145 -0
- package/src/oauth/platform-connection.ts +62 -31
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/approval-policy.test.ts +948 -0
- package/src/permissions/approval-policy.ts +257 -0
- package/src/permissions/bash-risk-classifier.test.ts +1208 -0
- package/src/permissions/bash-risk-classifier.ts +707 -0
- package/src/permissions/checker.ts +218 -699
- package/src/permissions/command-registry.test.ts +535 -0
- package/src/permissions/command-registry.ts +825 -0
- package/src/permissions/defaults.ts +71 -75
- package/src/permissions/file-risk-classifier.test.ts +535 -0
- package/src/permissions/file-risk-classifier.ts +274 -0
- package/src/permissions/risk-types.ts +205 -0
- package/src/permissions/secret-prompter.ts +53 -2
- package/src/permissions/skill-risk-classifier.test.ts +311 -0
- package/src/permissions/skill-risk-classifier.ts +214 -0
- package/src/permissions/trust-client.ts +52 -25
- package/src/permissions/trust-store-interface.ts +1 -6
- package/src/permissions/trust-store.ts +164 -65
- package/src/permissions/types.ts +23 -14
- package/src/permissions/web-risk-classifier.test.ts +170 -0
- package/src/permissions/web-risk-classifier.ts +89 -0
- package/src/permissions/workspace-policy.ts +1 -13
- package/src/platform/client.test.ts +10 -0
- package/src/platform/client.ts +19 -1
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +127 -3
- package/src/prompts/system-prompt.ts +78 -38
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/SOUL.md +5 -3
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-job.ts +190 -0
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/__tests__/retry-callsite.test.ts +424 -0
- package/src/providers/anthropic/client.ts +335 -70
- package/src/providers/call-site-routing.ts +71 -0
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +74 -3
- package/src/providers/managed-proxy/constants.ts +2 -1
- package/src/providers/model-catalog.ts +502 -28
- package/src/providers/model-intents.ts +8 -8
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +530 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +579 -0
- package/src/providers/openrouter/client.ts +168 -4
- package/src/providers/provider-env-vars.ts +56 -0
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/provider-send-message.ts +22 -5
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/registry.ts +21 -10
- package/src/providers/retry.ts +185 -39
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +883 -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 +323 -0
- package/src/providers/speech-to-text/resolve.ts +393 -6
- package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
- package/src/providers/speech-to-text/xai-realtime.ts +796 -0
- package/src/providers/speech-to-text/xai.test.ts +155 -0
- package/src/providers/speech-to-text/xai.ts +97 -0
- package/src/providers/types.ts +102 -3
- package/src/runtime/AGENTS.md +45 -3
- package/src/runtime/__tests__/agent-wake.test.ts +872 -0
- package/src/runtime/__tests__/interactive-ui.test.ts +673 -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 +553 -0
- package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
- package/src/runtime/auth/route-policy.ts +34 -5
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +15 -3
- 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/channel-reply-delivery.ts +106 -2
- package/src/runtime/chrome-extension-registry.ts +38 -2
- package/src/runtime/decision-token.ts +116 -0
- package/src/runtime/gateway-client.ts +2 -2
- package/src/runtime/http-router.ts +32 -0
- package/src/runtime/http-server.ts +447 -11
- package/src/runtime/http-types.ts +29 -3
- package/src/runtime/interactive-ui.ts +362 -0
- package/src/runtime/invite-instruction-generator.ts +2 -2
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
- 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/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
- package/src/runtime/migrations/gcs-signed-url.ts +162 -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 +187 -8
- package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
- package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
- package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
- package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
- package/src/runtime/migrations/vbundle-validator.ts +15 -6
- 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 +618 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +247 -0
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -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/approval-prompt-ts-tracker.ts +58 -0
- package/src/runtime/routes/approval-routes.ts +12 -17
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/avatar-routes.ts +20 -4
- 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 +9 -10
- 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 +133 -0
- package/src/runtime/routes/conversation-routes.ts +487 -160
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +6 -4
- package/src/runtime/routes/events-routes.ts +16 -0
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/guardian-approval-interception.ts +33 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
- package/src/runtime/routes/home-feed-routes.ts +452 -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-message-handler.ts +912 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
- 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 +36 -6
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +325 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/migration-routes.ts +722 -91
- package/src/runtime/routes/settings-routes.ts +26 -7
- 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/trust-rules-routes.ts +30 -14
- 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.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +11 -3
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +426 -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 +340 -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 +71 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +58 -0
- package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
- package/src/security/__tests__/untrusted-content.test.ts +109 -0
- package/src/security/oauth2.ts +122 -37
- package/src/security/secure-keys.ts +32 -10
- package/src/security/token-manager.ts +35 -13
- package/src/security/untrusted-content.ts +102 -0
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-cache.ts +26 -7
- package/src/skills/catalog-files.ts +64 -2
- package/src/skills/catalog-install.ts +31 -3
- 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-cache-store.ts +97 -0
- 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 +468 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +228 -0
- package/src/stt/stt-stream-session.ts +506 -0
- package/src/stt/types.ts +334 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +79 -27
- package/src/tasks/ephemeral-permissions.ts +9 -4
- package/src/telemetry/usage-telemetry-reporter.ts +27 -5
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +166 -0
- package/src/tools/browser/browser-execution.ts +1208 -41
- 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 +205 -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/tool-policy.ts +39 -5
- package/src/tools/credentials/vault.ts +41 -7
- package/src/tools/executor.ts +4 -0
- package/src/tools/filesystem/write.ts +52 -0
- package/src/tools/host-terminal/host-shell.ts +45 -5
- package/src/tools/memory/register.test.ts +185 -0
- package/src/tools/memory/register.ts +3 -1
- package/src/tools/network/web-fetch.ts +25 -12
- package/src/tools/network/web-search.ts +20 -2
- package/src/tools/permission-checker.ts +36 -15
- package/src/tools/policy-context.ts +25 -8
- package/src/tools/registry.ts +55 -3
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +0 -9
- package/src/tools/skills/execute.ts +2 -2
- package/src/tools/skills/sandbox-runner.ts +6 -2
- package/src/tools/terminal/backends/native.ts +51 -2
- package/src/tools/terminal/safe-env.ts +11 -2
- package/src/tools/terminal/shell.ts +16 -4
- package/src/tools/tool-manifest.ts +6 -0
- package/src/tools/types.ts +29 -3
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tools/verification-control-plane-policy.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +1061 -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 +219 -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 +44 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/providers/xai-provider.ts +224 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +199 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/types/tar-stream.d.ts +66 -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/json.ts +17 -0
- package/src/util/platform.ts +56 -12
- package/src/util/pricing.ts +78 -5
- 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 +24 -1
- package/src/watcher/providers/google-calendar.ts +134 -8
- package/src/watcher/providers/outlook-calendar.ts +42 -2
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/git-service.ts +23 -4
- 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/038-unify-llm-callsite-configs.ts +516 -0
- package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
- package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
- package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
- package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/registry.ts +32 -0
- package/src/workspace/provider-commit-message-generator.ts +19 -38
- 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/__tests__/outlook-attachments.test.ts +0 -301
- package/src/__tests__/outlook-automation-tools.test.ts +0 -425
- package/src/__tests__/outlook-categories.test.ts +0 -212
- package/src/__tests__/outlook-compose-tools.test.ts +0 -325
- package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
- package/src/__tests__/outlook-follow-up.test.ts +0 -196
- package/src/__tests__/outlook-trash.test.ts +0 -77
- package/src/__tests__/outlook-unsubscribe.test.ts +0 -250
- package/src/__tests__/update-bulletin-format.test.ts +0 -122
- package/src/__tests__/update-bulletin-state.test.ts +0 -135
- package/src/__tests__/update-bulletin.test.ts +0 -277
- package/src/__tests__/update-template-contract.test.ts +0 -29
- package/src/cli/commands/browser-relay.ts +0 -466
- package/src/cli/commands/doctor.ts +0 -341
- package/src/config/bundled-skills/browser/SKILL.md +0 -63
- package/src/config/bundled-skills/browser/TOOLS.json +0 -393
- package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -32
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
- package/src/config/bundled-skills/gmail/SKILL.md +0 -175
- package/src/config/bundled-skills/gmail/TOOLS.json +0 -558
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -149
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -220
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -251
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
- package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
- package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
- package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/google-calendar/types.ts +0 -97
- package/src/config/bundled-skills/outlook/SKILL.md +0 -196
- package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
- package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
- package/src/config/bundled-skills/slack/SKILL.md +0 -107
- package/src/config/bundled-skills/tasks/SKILL.md +0 -37
- package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
- package/src/config/bundled-skills/tasks/icon.svg +0 -34
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
- package/src/config/bundled-skills/watcher/SKILL.md +0 -31
- package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
- 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/UPDATES.md +0 -38
- package/src/prompts/templates/USER.md +0 -13
- package/src/prompts/update-bulletin-format.ts +0 -68
- package/src/prompts/update-bulletin-state.ts +0 -58
- package/src/prompts/update-bulletin-template-path.ts +0 -13
- package/src/prompts/update-bulletin.ts +0 -128
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/runtime/routes/browser-cdp-routes.ts +0 -229
- package/src/shared/provider-env-vars.ts +0 -19
- package/src/tools/watcher/create.ts +0 -86
- package/src/tools/watcher/delete.ts +0 -36
- package/src/tools/watcher/digest.ts +0 -54
- package/src/tools/watcher/list.ts +0 -83
- package/src/tools/watcher/update.ts +0 -71
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xAI realtime streaming STT adapter.
|
|
3
|
+
*
|
|
4
|
+
* Opens a WebSocket session against xAI's live transcription endpoint
|
|
5
|
+
* (`wss://api.x.ai/v1/stt`), forwards PCM audio frames from the caller,
|
|
6
|
+
* and normalizes xAI's streaming response payloads (`transcript.partial`
|
|
7
|
+
* with `is_final`, `transcript.done`, `error`) into the daemon's
|
|
8
|
+
* {@link SttStreamServerEvent} contract with stable partial/final semantics.
|
|
9
|
+
*
|
|
10
|
+
* Lifecycle:
|
|
11
|
+
* 1. {@link start} opens the WebSocket and resolves once the connection
|
|
12
|
+
* is established.
|
|
13
|
+
* 2. {@link sendAudio} forwards audio chunks over the open socket with
|
|
14
|
+
* backpressure-safe bufferedAmount checks.
|
|
15
|
+
* 3. {@link stop} sends the xAI `{"type":"audio.done"}` JSON text frame
|
|
16
|
+
* and waits for the provider to flush any remaining finals before
|
|
17
|
+
* closing.
|
|
18
|
+
* 4. The `onEvent` callback receives `partial`, `final`, `error`, and
|
|
19
|
+
* `closed` events throughout the session lifetime.
|
|
20
|
+
*
|
|
21
|
+
* Error handling:
|
|
22
|
+
* - Provider WebSocket errors and unexpected closes are mapped to
|
|
23
|
+
* {@link SttStreamServerErrorEvent} with appropriate categories.
|
|
24
|
+
* - A configurable inactivity timeout fires a `closed` event if the
|
|
25
|
+
* provider stops sending data mid-session.
|
|
26
|
+
* - xAI `error` frames are surfaced without tearing down the session —
|
|
27
|
+
* per the protocol, the socket stays open after an error frame.
|
|
28
|
+
* - All timers and listeners are cleaned up on close to prevent leaks.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import type {
|
|
32
|
+
StreamingTranscriber,
|
|
33
|
+
SttStreamServerEvent,
|
|
34
|
+
} from "../../stt/types.js";
|
|
35
|
+
import { getLogger } from "../../util/logger.js";
|
|
36
|
+
|
|
37
|
+
const log = getLogger("xai-realtime");
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Constants
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
const DEFAULT_WS_URL = "wss://api.x.ai/v1/stt";
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Default timeout (ms) for the WebSocket connection handshake.
|
|
47
|
+
* If the socket does not reach OPEN within this window, start() rejects.
|
|
48
|
+
*/
|
|
49
|
+
const DEFAULT_CONNECT_TIMEOUT_MS = 10_000;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Default inactivity timeout (ms). If no message is received from xAI
|
|
53
|
+
* for this duration after the session is open, the adapter closes with
|
|
54
|
+
* a timeout error. This guards against provider-side hangs.
|
|
55
|
+
*/
|
|
56
|
+
const DEFAULT_INACTIVITY_TIMEOUT_MS = 30_000;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Maximum WebSocket bufferedAmount (bytes) before sendAudio applies
|
|
60
|
+
* backpressure by dropping frames. This prevents unbounded memory growth
|
|
61
|
+
* if the network or provider cannot keep up with the audio rate.
|
|
62
|
+
*/
|
|
63
|
+
const MAX_BUFFERED_AMOUNT = 1024 * 1024; // 1 MiB
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Grace period (ms) after sending the `audio.done` frame before we
|
|
67
|
+
* force-close the WebSocket. Gives xAI time to flush any remaining
|
|
68
|
+
* finals / `transcript.done`.
|
|
69
|
+
*/
|
|
70
|
+
const CLOSE_GRACE_MS = 5_000;
|
|
71
|
+
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Options
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
export interface XAIRealtimeOptions {
|
|
77
|
+
/** Audio sample rate in Hz (default: 16000). */
|
|
78
|
+
sampleRate?: number;
|
|
79
|
+
/** Audio encoding. Default: "pcm" (signed 16-bit LE). */
|
|
80
|
+
encoding?: "pcm" | "mulaw" | "alaw";
|
|
81
|
+
/** Enable interim (partial) results. Default: true. */
|
|
82
|
+
interimResults?: boolean;
|
|
83
|
+
/** BCP-47 language code (e.g. "en", "es"). Omitted by default. */
|
|
84
|
+
language?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Enable xAI speaker diarization. Default: false.
|
|
87
|
+
*
|
|
88
|
+
* When `true`, the adapter appends `diarize=true` to the xAI live URL
|
|
89
|
+
* so xAI attaches a `speaker` integer to each word. The adapter
|
|
90
|
+
* aggregates per-segment speakers (mode, with first-word tiebreaker)
|
|
91
|
+
* into a single `speakerLabel` emitted on `partial` / `final` events.
|
|
92
|
+
*/
|
|
93
|
+
diarize?: boolean;
|
|
94
|
+
/** Override the xAI WebSocket base URL (useful for proxies or testing). */
|
|
95
|
+
baseUrl?: string;
|
|
96
|
+
/** Connect timeout in milliseconds. Default: 10_000. */
|
|
97
|
+
connectTimeoutMs?: number;
|
|
98
|
+
/** Inactivity timeout in milliseconds. Default: 30_000. */
|
|
99
|
+
inactivityTimeoutMs?: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// xAI streaming response types (subset relevant to transcript events)
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* A single word within an xAI streaming transcript frame. When
|
|
108
|
+
* diarization is enabled, each word carries a numeric `speaker` tag
|
|
109
|
+
* identifying the detected speaker turn — stable within a session
|
|
110
|
+
* but opaque (xAI has no real-world identity).
|
|
111
|
+
*/
|
|
112
|
+
interface XAIStreamWord {
|
|
113
|
+
word?: string;
|
|
114
|
+
speaker?: number;
|
|
115
|
+
start?: number;
|
|
116
|
+
end?: number;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* An xAI streaming response frame.
|
|
121
|
+
*
|
|
122
|
+
* Frame types:
|
|
123
|
+
* - `transcript.created` — session ready signal (informational).
|
|
124
|
+
* - `transcript.partial` — interim or interim-final transcript.
|
|
125
|
+
* - `is_final: false` — interim transcript, may be revised.
|
|
126
|
+
* - `is_final: true` — committed transcript for this segment.
|
|
127
|
+
* - `transcript.done` — end-of-channel committed transcript.
|
|
128
|
+
* - `error` — provider-reported error (socket stays open).
|
|
129
|
+
*/
|
|
130
|
+
interface XAIStreamFrame {
|
|
131
|
+
type?: string;
|
|
132
|
+
is_final?: boolean;
|
|
133
|
+
speech_final?: boolean;
|
|
134
|
+
text?: string;
|
|
135
|
+
/** Per-word info when diarization is enabled. */
|
|
136
|
+
words?: XAIStreamWord[];
|
|
137
|
+
/** Present on `error` frames. */
|
|
138
|
+
message?: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
// Minimal WebSocket interface
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Minimal structural WebSocket interface so we can test without depending
|
|
147
|
+
* on Bun's global WebSocket type at the type level.
|
|
148
|
+
*/
|
|
149
|
+
interface WsLike {
|
|
150
|
+
readonly readyState: number;
|
|
151
|
+
readonly bufferedAmount: number;
|
|
152
|
+
send(data: string | ArrayBufferLike | ArrayBuffer | Uint8Array): void;
|
|
153
|
+
close(code?: number, reason?: string): void;
|
|
154
|
+
addEventListener(type: "open", listener: () => void): void;
|
|
155
|
+
addEventListener(
|
|
156
|
+
type: "close",
|
|
157
|
+
listener: (ev: { code: number; reason: string }) => void,
|
|
158
|
+
): void;
|
|
159
|
+
addEventListener(type: "error", listener: (ev: unknown) => void): void;
|
|
160
|
+
addEventListener(
|
|
161
|
+
type: "message",
|
|
162
|
+
listener: (ev: { data: unknown }) => void,
|
|
163
|
+
): void;
|
|
164
|
+
removeEventListener(type: string, listener: unknown): void;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const WS_OPEN = 1;
|
|
168
|
+
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// Adapter implementation
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* xAI realtime streaming transcriber.
|
|
175
|
+
*
|
|
176
|
+
* Implements the daemon {@link StreamingTranscriber} contract on top of
|
|
177
|
+
* xAI's live transcription WebSocket API (`wss://api.x.ai/v1/stt`).
|
|
178
|
+
*/
|
|
179
|
+
export class XAIRealtimeTranscriber implements StreamingTranscriber {
|
|
180
|
+
readonly providerId = "xai" as const;
|
|
181
|
+
readonly boundaryId = "daemon-streaming" as const;
|
|
182
|
+
|
|
183
|
+
private readonly apiKey: string;
|
|
184
|
+
private readonly sampleRate: number;
|
|
185
|
+
private readonly encoding: "pcm" | "mulaw" | "alaw";
|
|
186
|
+
private readonly interimResults: boolean;
|
|
187
|
+
private readonly language: string | undefined;
|
|
188
|
+
private readonly diarize: boolean;
|
|
189
|
+
private readonly baseUrl: string;
|
|
190
|
+
private readonly connectTimeoutMs: number;
|
|
191
|
+
private readonly inactivityTimeoutMs: number;
|
|
192
|
+
|
|
193
|
+
/** The live WebSocket connection, set during start(). */
|
|
194
|
+
private ws: WsLike | null = null;
|
|
195
|
+
|
|
196
|
+
/** Callback for emitting events to the session orchestrator. */
|
|
197
|
+
private onEvent: ((event: SttStreamServerEvent) => void) | null = null;
|
|
198
|
+
|
|
199
|
+
/** Whether the session has been fully closed. */
|
|
200
|
+
private closed = false;
|
|
201
|
+
|
|
202
|
+
/** Whether stop() has been called. */
|
|
203
|
+
private stopping = false;
|
|
204
|
+
|
|
205
|
+
/** Inactivity timer handle. */
|
|
206
|
+
private inactivityTimer: ReturnType<typeof setTimeout> | null = null;
|
|
207
|
+
|
|
208
|
+
/** Close grace timer handle. */
|
|
209
|
+
private closeGraceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
210
|
+
|
|
211
|
+
constructor(apiKey: string, options: XAIRealtimeOptions = {}) {
|
|
212
|
+
this.apiKey = apiKey;
|
|
213
|
+
this.sampleRate = options.sampleRate ?? 16_000;
|
|
214
|
+
this.encoding = options.encoding ?? "pcm";
|
|
215
|
+
this.interimResults = options.interimResults ?? true;
|
|
216
|
+
this.language = options.language;
|
|
217
|
+
this.diarize = options.diarize ?? false;
|
|
218
|
+
this.baseUrl = options.baseUrl ?? DEFAULT_WS_URL;
|
|
219
|
+
this.connectTimeoutMs =
|
|
220
|
+
options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
221
|
+
this.inactivityTimeoutMs =
|
|
222
|
+
options.inactivityTimeoutMs ?? DEFAULT_INACTIVITY_TIMEOUT_MS;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ── StreamingTranscriber interface ──────────────────────────────────
|
|
226
|
+
|
|
227
|
+
async start(onEvent: (event: SttStreamServerEvent) => void): Promise<void> {
|
|
228
|
+
if (this.ws) {
|
|
229
|
+
throw new Error("XAIRealtimeTranscriber: start() called twice");
|
|
230
|
+
}
|
|
231
|
+
this.onEvent = onEvent;
|
|
232
|
+
|
|
233
|
+
const url = this.buildWebSocketUrl();
|
|
234
|
+
log.info({ url }, "Opening xAI realtime session");
|
|
235
|
+
|
|
236
|
+
const ws = this.createWebSocket(url);
|
|
237
|
+
this.ws = ws;
|
|
238
|
+
|
|
239
|
+
// Attach the session-lifetime handlers (message, close, error)
|
|
240
|
+
// BEFORE awaiting the handshake. Gating on `settled` lets the
|
|
241
|
+
// handlers route to handshake-settle paths while the handshake is
|
|
242
|
+
// in flight, then to the normal session paths afterwards. This
|
|
243
|
+
// closes the narrow window in which a close/error/message could
|
|
244
|
+
// fire between WS open and the await resuming — with separate
|
|
245
|
+
// connect-phase vs session-phase listeners those events would
|
|
246
|
+
// otherwise have no handler attached.
|
|
247
|
+
//
|
|
248
|
+
// The xAI realtime protocol also requires waiting for
|
|
249
|
+
// `transcript.created` before the session is ready to accept
|
|
250
|
+
// audio. Resolving on WS `open` alone would mean early sendAudio()
|
|
251
|
+
// calls could be silently dropped by the provider, losing the
|
|
252
|
+
// first utterance. start() therefore defers resolution until
|
|
253
|
+
// either `transcript.created` arrives or the handshake budget
|
|
254
|
+
// expires.
|
|
255
|
+
await new Promise<void>((resolve, reject) => {
|
|
256
|
+
let settled = false;
|
|
257
|
+
|
|
258
|
+
const handshakeTimer = setTimeout(() => {
|
|
259
|
+
if (settled) return;
|
|
260
|
+
settled = true;
|
|
261
|
+
this.forceClose();
|
|
262
|
+
reject(new Error("xAI realtime connect timeout"));
|
|
263
|
+
}, this.connectTimeoutMs);
|
|
264
|
+
|
|
265
|
+
const settleResolve = () => {
|
|
266
|
+
if (settled) return;
|
|
267
|
+
settled = true;
|
|
268
|
+
clearTimeout(handshakeTimer);
|
|
269
|
+
resolve();
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const settleReject = (err: Error) => {
|
|
273
|
+
if (settled) return;
|
|
274
|
+
settled = true;
|
|
275
|
+
clearTimeout(handshakeTimer);
|
|
276
|
+
// Null out this.ws (via forceClose) so the instance can be
|
|
277
|
+
// reused for a retry. Without this, a subsequent start() call
|
|
278
|
+
// would throw "start() called twice" even though no session
|
|
279
|
+
// was ever established.
|
|
280
|
+
this.forceClose();
|
|
281
|
+
reject(err);
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
// `open` is informational — we wait for `transcript.created` to
|
|
285
|
+
// consider the handshake complete. The listener detaches itself
|
|
286
|
+
// after firing so the listener map settles at the shape
|
|
287
|
+
// session-lifetime handlers expect.
|
|
288
|
+
const onOpen = () => {
|
|
289
|
+
ws.removeEventListener("open", onOpen);
|
|
290
|
+
};
|
|
291
|
+
ws.addEventListener("open", onOpen);
|
|
292
|
+
|
|
293
|
+
ws.addEventListener("message", (ev: { data: unknown }) => {
|
|
294
|
+
if (!settled) {
|
|
295
|
+
if (tryParseHandshakeFrame(ev.data)?.type === "transcript.created") {
|
|
296
|
+
settleResolve();
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
// Any other pre-handshake frame flows through normal routing;
|
|
300
|
+
// per xAI protocol these shouldn't occur before
|
|
301
|
+
// `transcript.created` but we handle them conservatively.
|
|
302
|
+
this.handleProviderMessage(ev.data);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
this.handleProviderMessage(ev.data);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
ws.addEventListener("close", (ev: { code: number; reason: string }) => {
|
|
309
|
+
if (!settled) {
|
|
310
|
+
// 401 / 403 on connect arrive as WebSocket close codes 4001 /
|
|
311
|
+
// 4003 in most runtimes (or 1008 policy-violation in others).
|
|
312
|
+
// We surface the underlying code in the message — callers
|
|
313
|
+
// that need granular auth handling can branch on the
|
|
314
|
+
// rejection text.
|
|
315
|
+
settleReject(
|
|
316
|
+
new Error(
|
|
317
|
+
`xAI WebSocket closed before handshake (code=${ev.code}, reason=${ev.reason})`,
|
|
318
|
+
),
|
|
319
|
+
);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
this.handleProviderClose(ev.code, ev.reason);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
ws.addEventListener("error", (ev: unknown) => {
|
|
326
|
+
if (!settled) {
|
|
327
|
+
const msg =
|
|
328
|
+
ev instanceof Error
|
|
329
|
+
? ev.message
|
|
330
|
+
: typeof ev === "object" && ev !== null && "message" in ev
|
|
331
|
+
? String((ev as { message: unknown }).message)
|
|
332
|
+
: "WebSocket error during connect";
|
|
333
|
+
settleReject(new Error(`xAI realtime connect error: ${msg}`));
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
this.handleProviderError(ev);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
this.resetInactivityTimer();
|
|
341
|
+
|
|
342
|
+
log.info("xAI realtime session opened");
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
sendAudio(audio: Buffer, _mimeType: string): void {
|
|
346
|
+
if (this.closed || this.stopping) return;
|
|
347
|
+
|
|
348
|
+
const ws = this.ws;
|
|
349
|
+
if (!ws || ws.readyState !== WS_OPEN) return;
|
|
350
|
+
|
|
351
|
+
// Backpressure check — drop frames if the outbound buffer is too
|
|
352
|
+
// full to prevent unbounded memory growth.
|
|
353
|
+
if (ws.bufferedAmount > MAX_BUFFERED_AMOUNT) {
|
|
354
|
+
log.warn(
|
|
355
|
+
{ bufferedAmount: ws.bufferedAmount },
|
|
356
|
+
"xAI realtime backpressure: dropping audio frame",
|
|
357
|
+
);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// xAI's live endpoint accepts raw audio bytes on the WebSocket. We
|
|
362
|
+
// forward the caller's buffer as-is — no transcoding.
|
|
363
|
+
ws.send(new Uint8Array(audio));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
stop(): void {
|
|
367
|
+
if (this.closed || this.stopping) return;
|
|
368
|
+
this.stopping = true;
|
|
369
|
+
|
|
370
|
+
// Cancel the inactivity timer immediately. If it were left running,
|
|
371
|
+
// it could fire inside the CLOSE_GRACE window (waiting on xAI to
|
|
372
|
+
// flush finals after `audio.done`) and spuriously emit a
|
|
373
|
+
// `{type:"error", category:"timeout"}` event on an intentional stop.
|
|
374
|
+
// The inactivity callback also double-checks `this.stopping` as a
|
|
375
|
+
// safety net against any future code path that re-arms the timer
|
|
376
|
+
// after stop() runs.
|
|
377
|
+
if (this.inactivityTimer !== null) {
|
|
378
|
+
clearTimeout(this.inactivityTimer);
|
|
379
|
+
this.inactivityTimer = null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
log.info("Stopping xAI realtime session");
|
|
383
|
+
|
|
384
|
+
const ws = this.ws;
|
|
385
|
+
if (!ws || ws.readyState !== WS_OPEN) {
|
|
386
|
+
this.emitClosedAndCleanup();
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Send xAI's end-of-audio signal as a JSON text frame (NOT binary).
|
|
391
|
+
// The provider may flush remaining finals / emit `transcript.done`
|
|
392
|
+
// before closing.
|
|
393
|
+
try {
|
|
394
|
+
ws.send(JSON.stringify({ type: "audio.done" }));
|
|
395
|
+
} catch {
|
|
396
|
+
// If the send fails, force-close immediately.
|
|
397
|
+
this.emitClosedAndCleanup();
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Start a grace timer — if the provider doesn't close within the
|
|
402
|
+
// grace window, we force-close to prevent session leaks.
|
|
403
|
+
this.closeGraceTimer = setTimeout(() => {
|
|
404
|
+
log.warn("xAI realtime close grace timeout — forcing close");
|
|
405
|
+
this.emitClosedAndCleanup();
|
|
406
|
+
}, CLOSE_GRACE_MS);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// ── WebSocket lifecycle ─────────────────────────────────────────────
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Create a WebSocket instance. Factored out for test mockability.
|
|
413
|
+
*
|
|
414
|
+
* Passes the xAI API key via the `Authorization: Bearer <key>` header.
|
|
415
|
+
* Bun's WebSocket constructor supports a second `options` argument
|
|
416
|
+
* with custom headers, unlike the browser WebSocket API.
|
|
417
|
+
*/
|
|
418
|
+
private createWebSocket(url: string): WsLike {
|
|
419
|
+
const WebSocketCtor = (
|
|
420
|
+
globalThis as unknown as {
|
|
421
|
+
WebSocket: new (
|
|
422
|
+
url: string,
|
|
423
|
+
options?: { headers?: Record<string, string> },
|
|
424
|
+
) => WsLike;
|
|
425
|
+
}
|
|
426
|
+
).WebSocket;
|
|
427
|
+
if (typeof WebSocketCtor !== "function") {
|
|
428
|
+
throw new Error("global WebSocket is not available in this runtime");
|
|
429
|
+
}
|
|
430
|
+
return new WebSocketCtor(url, {
|
|
431
|
+
headers: {
|
|
432
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
433
|
+
},
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ── Provider message handling ───────────────────────────────────────
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Parse and normalize an xAI streaming response into daemon events.
|
|
441
|
+
*/
|
|
442
|
+
private handleProviderMessage(data: unknown): void {
|
|
443
|
+
if (this.closed) return;
|
|
444
|
+
|
|
445
|
+
this.resetInactivityTimer();
|
|
446
|
+
|
|
447
|
+
let raw: string;
|
|
448
|
+
if (typeof data === "string") {
|
|
449
|
+
raw = data;
|
|
450
|
+
} else if (data instanceof ArrayBuffer) {
|
|
451
|
+
raw = new TextDecoder().decode(data);
|
|
452
|
+
} else {
|
|
453
|
+
// Unexpected binary format — ignore.
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
let frame: XAIStreamFrame;
|
|
458
|
+
try {
|
|
459
|
+
frame = JSON.parse(raw) as XAIStreamFrame;
|
|
460
|
+
} catch {
|
|
461
|
+
log.debug("Dropped non-JSON xAI frame");
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (!frame || typeof frame !== "object") return;
|
|
466
|
+
|
|
467
|
+
switch (frame.type) {
|
|
468
|
+
case "transcript.created":
|
|
469
|
+
// Informational ready signal — no event emitted.
|
|
470
|
+
return;
|
|
471
|
+
|
|
472
|
+
case "transcript.partial":
|
|
473
|
+
this.handleTranscriptFrame(frame);
|
|
474
|
+
return;
|
|
475
|
+
|
|
476
|
+
case "transcript.done":
|
|
477
|
+
this.handleTranscriptDoneFrame(frame);
|
|
478
|
+
return;
|
|
479
|
+
|
|
480
|
+
case "error":
|
|
481
|
+
this.handleProviderErrorFrame(frame);
|
|
482
|
+
return;
|
|
483
|
+
|
|
484
|
+
default:
|
|
485
|
+
// Unknown frame types are informational — ignored.
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Normalize an xAI `transcript.partial` frame into partial or final
|
|
492
|
+
* events.
|
|
493
|
+
*
|
|
494
|
+
* xAI semantics:
|
|
495
|
+
* - `is_final: false` — interim transcript, may be revised.
|
|
496
|
+
* - `is_final: true` — committed transcript for this segment.
|
|
497
|
+
*
|
|
498
|
+
* When {@link XAIRealtimeOptions.diarize} is enabled, the frame also
|
|
499
|
+
* carries per-word speaker tags in `words[].speaker`. We derive a
|
|
500
|
+
* single per-chunk `speakerLabel` by picking the dominant speaker
|
|
501
|
+
* across the words — see {@link extractSpeakerLabel}.
|
|
502
|
+
*/
|
|
503
|
+
private handleTranscriptFrame(frame: XAIStreamFrame): void {
|
|
504
|
+
const text = typeof frame.text === "string" ? frame.text.trim() : "";
|
|
505
|
+
const speakerLabel = this.diarize
|
|
506
|
+
? extractSpeakerLabel(frame.words)
|
|
507
|
+
: undefined;
|
|
508
|
+
|
|
509
|
+
if (frame.is_final) {
|
|
510
|
+
this.emitEvent({
|
|
511
|
+
type: "final",
|
|
512
|
+
text,
|
|
513
|
+
...(speakerLabel !== undefined ? { speakerLabel } : {}),
|
|
514
|
+
});
|
|
515
|
+
} else if (this.interimResults) {
|
|
516
|
+
this.emitEvent({
|
|
517
|
+
type: "partial",
|
|
518
|
+
text,
|
|
519
|
+
...(speakerLabel !== undefined ? { speakerLabel } : {}),
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Normalize an xAI `transcript.done` frame into a final event. xAI
|
|
526
|
+
* emits one `transcript.done` per channel when multichannel is
|
|
527
|
+
* enabled; for single-channel sessions there is typically one per
|
|
528
|
+
* utterance boundary.
|
|
529
|
+
*/
|
|
530
|
+
private handleTranscriptDoneFrame(frame: XAIStreamFrame): void {
|
|
531
|
+
const text = typeof frame.text === "string" ? frame.text.trim() : "";
|
|
532
|
+
const speakerLabel = this.diarize
|
|
533
|
+
? extractSpeakerLabel(frame.words)
|
|
534
|
+
: undefined;
|
|
535
|
+
|
|
536
|
+
this.emitEvent({
|
|
537
|
+
type: "final",
|
|
538
|
+
text,
|
|
539
|
+
...(speakerLabel !== undefined ? { speakerLabel } : {}),
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Handle an xAI `error` frame. Per the xAI protocol the socket stays
|
|
545
|
+
* open after an error frame is emitted, so we surface the error to
|
|
546
|
+
* the caller but do NOT tear down the session.
|
|
547
|
+
*/
|
|
548
|
+
private handleProviderErrorFrame(frame: XAIStreamFrame): void {
|
|
549
|
+
const message =
|
|
550
|
+
typeof frame.message === "string" ? frame.message : "xAI error frame";
|
|
551
|
+
log.warn({ message }, "xAI realtime provider error frame");
|
|
552
|
+
this.emitEvent({
|
|
553
|
+
type: "error",
|
|
554
|
+
category: "provider-error",
|
|
555
|
+
message,
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Handle provider-side WebSocket close.
|
|
561
|
+
*/
|
|
562
|
+
private handleProviderClose(code: number, reason: string): void {
|
|
563
|
+
if (this.closed) return;
|
|
564
|
+
|
|
565
|
+
// Normal close (1000) or going-away (1001) after stop() is expected.
|
|
566
|
+
if (this.stopping && (code === 1000 || code === 1001)) {
|
|
567
|
+
log.info({ code, reason }, "xAI realtime session closed normally");
|
|
568
|
+
this.emitClosedAndCleanup();
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// Unexpected close — map to an error event.
|
|
573
|
+
log.warn({ code, reason }, "xAI realtime session closed unexpectedly");
|
|
574
|
+
|
|
575
|
+
const category =
|
|
576
|
+
code === 1008 || code === 4001 || code === 4003
|
|
577
|
+
? ("auth" as const)
|
|
578
|
+
: code === 1013
|
|
579
|
+
? ("rate-limit" as const)
|
|
580
|
+
: ("provider-error" as const);
|
|
581
|
+
|
|
582
|
+
this.emitEvent({
|
|
583
|
+
type: "error",
|
|
584
|
+
category,
|
|
585
|
+
message: `xAI WebSocket closed (code=${code}, reason=${reason})`,
|
|
586
|
+
});
|
|
587
|
+
this.emitClosedAndCleanup();
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Handle provider-side WebSocket error (transport-level failure).
|
|
592
|
+
*/
|
|
593
|
+
private handleProviderError(ev: unknown): void {
|
|
594
|
+
if (this.closed) return;
|
|
595
|
+
|
|
596
|
+
const message =
|
|
597
|
+
ev instanceof Error
|
|
598
|
+
? ev.message
|
|
599
|
+
: typeof ev === "object" && ev !== null && "message" in ev
|
|
600
|
+
? String((ev as { message: unknown }).message)
|
|
601
|
+
: "WebSocket error";
|
|
602
|
+
|
|
603
|
+
log.error({ error: ev }, "xAI realtime WebSocket error");
|
|
604
|
+
|
|
605
|
+
this.emitEvent({
|
|
606
|
+
type: "error",
|
|
607
|
+
category: "provider-error",
|
|
608
|
+
message: `xAI WebSocket error: ${message}`,
|
|
609
|
+
});
|
|
610
|
+
this.emitClosedAndCleanup();
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// ── Event emission & cleanup ────────────────────────────────────────
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Emit a server event to the session orchestrator. Swallows listener
|
|
617
|
+
* errors to prevent tearing down the adapter.
|
|
618
|
+
*/
|
|
619
|
+
private emitEvent(event: SttStreamServerEvent): void {
|
|
620
|
+
if (!this.onEvent) return;
|
|
621
|
+
try {
|
|
622
|
+
this.onEvent(event);
|
|
623
|
+
} catch (err) {
|
|
624
|
+
log.warn({ error: err }, "Listener error in xAI realtime adapter");
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Emit a `closed` event and clean up all resources (timers, WebSocket).
|
|
630
|
+
* Idempotent — safe to call multiple times.
|
|
631
|
+
*/
|
|
632
|
+
private emitClosedAndCleanup(): void {
|
|
633
|
+
if (this.closed) return;
|
|
634
|
+
this.closed = true;
|
|
635
|
+
|
|
636
|
+
this.clearTimers();
|
|
637
|
+
this.forceClose();
|
|
638
|
+
|
|
639
|
+
this.emitEvent({ type: "closed" });
|
|
640
|
+
this.onEvent = null;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Force-close the WebSocket without emitting events. Used during
|
|
645
|
+
* cleanup and timeout paths.
|
|
646
|
+
*/
|
|
647
|
+
private forceClose(): void {
|
|
648
|
+
const ws = this.ws;
|
|
649
|
+
this.ws = null;
|
|
650
|
+
if (!ws) return;
|
|
651
|
+
|
|
652
|
+
try {
|
|
653
|
+
ws.close();
|
|
654
|
+
} catch {
|
|
655
|
+
// Best effort — already closed sockets may throw.
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Clear all active timers.
|
|
661
|
+
*/
|
|
662
|
+
private clearTimers(): void {
|
|
663
|
+
if (this.inactivityTimer !== null) {
|
|
664
|
+
clearTimeout(this.inactivityTimer);
|
|
665
|
+
this.inactivityTimer = null;
|
|
666
|
+
}
|
|
667
|
+
if (this.closeGraceTimer !== null) {
|
|
668
|
+
clearTimeout(this.closeGraceTimer);
|
|
669
|
+
this.closeGraceTimer = null;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Reset the inactivity timer. Called on inbound provider messages to
|
|
675
|
+
* detect provider-side hangs. Not reset on outbound audio sends —
|
|
676
|
+
* continuous audio from the caller must not mask a silent provider.
|
|
677
|
+
*/
|
|
678
|
+
private resetInactivityTimer(): void {
|
|
679
|
+
if (this.closed || this.stopping) return;
|
|
680
|
+
|
|
681
|
+
if (this.inactivityTimer !== null) {
|
|
682
|
+
clearTimeout(this.inactivityTimer);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
this.inactivityTimer = setTimeout(() => {
|
|
686
|
+
// Belt-and-suspenders guard: stop() clears this timer before the
|
|
687
|
+
// CLOSE_GRACE window starts, but if a future refactor re-arms it
|
|
688
|
+
// or forgets to clear it, this check prevents the inactivity
|
|
689
|
+
// callback from emitting a timeout error during an intentional stop.
|
|
690
|
+
if (this.closed || this.stopping) return;
|
|
691
|
+
|
|
692
|
+
log.warn("xAI realtime inactivity timeout");
|
|
693
|
+
this.emitEvent({
|
|
694
|
+
type: "error",
|
|
695
|
+
category: "timeout",
|
|
696
|
+
message: "xAI realtime session timed out due to inactivity",
|
|
697
|
+
});
|
|
698
|
+
this.emitClosedAndCleanup();
|
|
699
|
+
}, this.inactivityTimeoutMs);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// ── URL construction ────────────────────────────────────────────────
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* Build the xAI live transcription WebSocket URL with query params.
|
|
706
|
+
*
|
|
707
|
+
* Audio format and feature flags are passed as query parameters.
|
|
708
|
+
* Authentication is handled separately via the `Authorization: Bearer`
|
|
709
|
+
* header in {@link createWebSocket}.
|
|
710
|
+
*/
|
|
711
|
+
private buildWebSocketUrl(): string {
|
|
712
|
+
const params = new URLSearchParams();
|
|
713
|
+
params.set("sample_rate", String(this.sampleRate));
|
|
714
|
+
params.set("encoding", this.encoding);
|
|
715
|
+
if (this.interimResults) {
|
|
716
|
+
params.set("interim_results", "true");
|
|
717
|
+
}
|
|
718
|
+
if (this.language) {
|
|
719
|
+
params.set("language", this.language);
|
|
720
|
+
}
|
|
721
|
+
if (this.diarize) {
|
|
722
|
+
params.set("diarize", "true");
|
|
723
|
+
}
|
|
724
|
+
return `${this.baseUrl}?${params.toString()}`;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// ---------------------------------------------------------------------------
|
|
729
|
+
// Helpers
|
|
730
|
+
// ---------------------------------------------------------------------------
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Best-effort parse of an inbound frame during the handshake window.
|
|
734
|
+
* Returns `undefined` on parse failure — callers fall back to normal
|
|
735
|
+
* message routing. Kept separate from {@link XAIRealtimeTranscriber}
|
|
736
|
+
* so the handshake gate doesn't drag in the full event-emission path.
|
|
737
|
+
*/
|
|
738
|
+
function tryParseHandshakeFrame(data: unknown): XAIStreamFrame | undefined {
|
|
739
|
+
let raw: string;
|
|
740
|
+
if (typeof data === "string") {
|
|
741
|
+
raw = data;
|
|
742
|
+
} else if (data instanceof ArrayBuffer) {
|
|
743
|
+
raw = new TextDecoder().decode(data);
|
|
744
|
+
} else {
|
|
745
|
+
return undefined;
|
|
746
|
+
}
|
|
747
|
+
try {
|
|
748
|
+
const frame = JSON.parse(raw) as XAIStreamFrame;
|
|
749
|
+
if (frame && typeof frame === "object") return frame;
|
|
750
|
+
} catch {
|
|
751
|
+
// fall through
|
|
752
|
+
}
|
|
753
|
+
return undefined;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* Derive a single `speakerLabel` for a diarized chunk.
|
|
758
|
+
*
|
|
759
|
+
* xAI attaches per-word speaker tags in the `words` array when
|
|
760
|
+
* `diarize=true`. We pick the most-frequent per-word speaker across
|
|
761
|
+
* the chunk; on ties we fall back to the first word's speaker so
|
|
762
|
+
* short segments where the endpointer didn't cleanly break between
|
|
763
|
+
* turns still attribute deterministically.
|
|
764
|
+
*
|
|
765
|
+
* Returns `undefined` when no speaker information is available — the
|
|
766
|
+
* resolver treats unlabeled chunks the same as a non-diarizing
|
|
767
|
+
* provider.
|
|
768
|
+
*
|
|
769
|
+
* The returned label is `String(speaker)` (e.g. `"0"`) to match the
|
|
770
|
+
* Deepgram adapter's output format, keeping consumer code
|
|
771
|
+
* provider-agnostic.
|
|
772
|
+
*/
|
|
773
|
+
function extractSpeakerLabel(
|
|
774
|
+
words: XAIStreamWord[] | undefined,
|
|
775
|
+
): string | undefined {
|
|
776
|
+
if (!Array.isArray(words) || words.length === 0) return undefined;
|
|
777
|
+
const counts = new Map<number, number>();
|
|
778
|
+
let firstSpeaker: number | undefined;
|
|
779
|
+
for (const word of words) {
|
|
780
|
+
if (typeof word.speaker !== "number") continue;
|
|
781
|
+
if (firstSpeaker === undefined) firstSpeaker = word.speaker;
|
|
782
|
+
counts.set(word.speaker, (counts.get(word.speaker) ?? 0) + 1);
|
|
783
|
+
}
|
|
784
|
+
if (counts.size === 0 || firstSpeaker === undefined) return undefined;
|
|
785
|
+
// Pick the most common speaker; on ties, prefer the first-word
|
|
786
|
+
// speaker.
|
|
787
|
+
let bestSpeaker = firstSpeaker;
|
|
788
|
+
let bestCount = counts.get(firstSpeaker) ?? 0;
|
|
789
|
+
for (const [speaker, count] of counts) {
|
|
790
|
+
if (count > bestCount) {
|
|
791
|
+
bestSpeaker = speaker;
|
|
792
|
+
bestCount = count;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
return String(bestSpeaker);
|
|
796
|
+
}
|