@vellumai/assistant 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +273 -10
- package/Dockerfile +2 -3
- package/bun.lock +41 -49
- package/bunfig.toml +3 -0
- package/docs/architecture/memory.md +1 -1
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/stt-provider-onboarding.md +120 -0
- package/knip.json +12 -2
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +3 -3
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
- package/openapi.yaml +1111 -86
- package/package.json +40 -42
- package/scripts/generate-openapi.ts +0 -2
- package/scripts/test.sh +73 -18
- package/src/__tests__/acp-session.test.ts +43 -0
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop.test.ts +123 -0
- package/src/__tests__/anthropic-provider.test.ts +263 -10
- package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +1 -0
- package/src/__tests__/app-source-watcher.test.ts +37 -11
- package/src/__tests__/approval-routes-http.test.ts +178 -1
- 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 +240 -94
- package/src/__tests__/browser-manager.test.ts +40 -27
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/browser-skill-endstate.test.ts +31 -7
- package/src/__tests__/btw-routes.test.ts +7 -0
- package/src/__tests__/call-controller.test.ts +581 -20
- package/src/__tests__/catalog-files.test.ts +1000 -0
- package/src/__tests__/channel-approvals.test.ts +53 -0
- package/src/__tests__/channel-invite-transport.test.ts +2 -2
- package/src/__tests__/channel-readiness-routes.test.ts +16 -20
- package/src/__tests__/channel-readiness-service.test.ts +12 -7
- package/src/__tests__/checker.test.ts +157 -10
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/config-analysis.test.ts +100 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +1248 -224
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +43 -8
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
- package/src/__tests__/contact-store-user-file.test.ts +512 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-overflow-approval.test.ts +16 -1
- package/src/__tests__/context-window-manager.test.ts +88 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
- package/src/__tests__/conversation-agent-loop.test.ts +99 -3
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
- package/src/__tests__/conversation-attachments.test.ts +80 -4
- package/src/__tests__/conversation-confirmation-signals.test.ts +290 -0
- package/src/__tests__/conversation-error.test.ts +70 -0
- package/src/__tests__/conversation-fork-crud.test.ts +17 -0
- package/src/__tests__/conversation-history-web-search.test.ts +12 -4
- package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
- package/src/__tests__/conversation-inject-context.test.ts +103 -0
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +946 -62
- package/src/__tests__/conversation-routes-disk-view.test.ts +275 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +324 -46
- package/src/__tests__/conversation-skill-tools.test.ts +7 -4
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +89 -18
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-starter-routes.test.ts +126 -0
- package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
- package/src/__tests__/conversation-store.test.ts +195 -0
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -1
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +6 -3
- package/src/__tests__/credential-vault-unit.test.ts +383 -7
- package/src/__tests__/credential-vault.test.ts +152 -13
- package/src/__tests__/credentials-cli.test.ts +42 -18
- package/src/__tests__/cross-provider-web-search.test.ts +146 -35
- package/src/__tests__/date-context.test.ts +4 -4
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
- package/src/__tests__/email-html-renderer.test.ts +71 -0
- package/src/__tests__/email-invite-adapter.test.ts +36 -32
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
- package/src/__tests__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +222 -0
- package/src/__tests__/fixtures/mock-chrome-extension.ts +386 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +2 -0
- package/src/__tests__/gemini-provider.test.ts +66 -2
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
- package/src/__tests__/gmail-archive-gate.test.ts +246 -0
- package/src/__tests__/gmail-preferences.test.ts +117 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
- package/src/__tests__/headless-browser-interactions.test.ts +738 -359
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +528 -49
- package/src/__tests__/headless-browser-read-tools.test.ts +274 -100
- package/src/__tests__/headless-browser-snapshot.test.ts +250 -77
- package/src/__tests__/heartbeat-service.test.ts +70 -17
- package/src/__tests__/home-state-routes.test.ts +162 -0
- package/src/__tests__/host-bash-proxy.test.ts +145 -1
- package/src/__tests__/host-browser-e2e-cloud.test.ts +596 -0
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
- package/src/__tests__/host-browser-event-routes.test.ts +350 -0
- package/src/__tests__/host-browser-proxy.test.ts +444 -0
- package/src/__tests__/host-browser-routes.test.ts +198 -0
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +423 -0
- package/src/__tests__/host-cu-proxy.test.ts +166 -1
- package/src/__tests__/host-file-proxy.test.ts +185 -1
- package/src/__tests__/host-file-read-tool.test.ts +52 -0
- package/src/__tests__/host-proxy-interface.test.ts +165 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -11
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/integration-status.test.ts +6 -7
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
- package/src/__tests__/llm-context-normalization.test.ts +488 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/mcp-client-auth.test.ts +40 -4
- package/src/__tests__/mcp-health-check.test.ts +10 -3
- package/src/__tests__/media-stream-output.test.ts +555 -0
- package/src/__tests__/media-stream-parser.test.ts +374 -0
- package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
- package/src/__tests__/media-stream-stt-session.test.ts +588 -0
- package/src/__tests__/media-turn-detector.test.ts +440 -0
- package/src/__tests__/message-queue.test.ts +125 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
- package/src/__tests__/migration-export-http.test.ts +67 -8
- package/src/__tests__/migration-export-streaming.test.ts +66 -0
- package/src/__tests__/migration-import-commit-http.test.ts +109 -7
- package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +151 -0
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
- package/src/__tests__/oauth-apps-routes.test.ts +18 -12
- package/src/__tests__/oauth-cli.test.ts +709 -60
- package/src/__tests__/oauth-connect-orchestrator.test.ts +118 -24
- package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +147 -10
- package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
- package/src/__tests__/oauth-providers-routes.test.ts +52 -14
- package/src/__tests__/oauth-store.test.ts +1465 -176
- package/src/__tests__/oauth2-gateway-transport.test.ts +460 -26
- package/src/__tests__/onboarding-template-contract.test.ts +81 -70
- package/src/__tests__/openai-provider.test.ts +178 -2
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1105 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outlook-categories.test.ts +1 -1
- package/src/__tests__/outlook-client-automation.test.ts +1 -1
- package/src/__tests__/outlook-compose-tools.test.ts +1 -1
- package/src/__tests__/outlook-email-watcher.test.ts +1 -1
- package/src/__tests__/outlook-follow-up.test.ts +1 -1
- package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
- package/src/__tests__/outlook-trash.test.ts +1 -1
- package/src/__tests__/outlook-unsubscribe.test.ts +32 -3
- package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
- package/src/__tests__/permission-mode.test.ts +28 -56
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
- package/src/__tests__/platform-callback-registration.test.ts +19 -0
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +343 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +174 -0
- package/src/__tests__/proxy-approval-callback.test.ts +18 -0
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
- package/src/__tests__/relationship-state-contract.test.ts +175 -0
- package/src/__tests__/relay-server.test.ts +423 -5
- package/src/__tests__/require-fresh-approval.test.ts +40 -1
- package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
- package/src/__tests__/schedule-routes.test.ts +162 -0
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-detection-handler.test.ts +84 -0
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- package/src/__tests__/secret-scanner-executor.test.ts +4 -0
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +8 -1
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +49 -0
- package/src/__tests__/set-permission-mode.test.ts +13 -250
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +801 -0
- package/src/__tests__/skills-files-catalog-fallback.test.ts +738 -0
- package/src/__tests__/skills.test.ts +5 -2
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +576 -16
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/subagent-detail.test.ts +44 -2
- package/src/__tests__/subagent-disposal.test.ts +1 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
- package/src/__tests__/subagent-manager-notify.test.ts +1 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
- package/src/__tests__/subagent-tools.test.ts +1 -0
- package/src/__tests__/subagent-types.test.ts +1 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
- package/src/__tests__/system-prompt.test.ts +184 -27
- package/src/__tests__/task-scheduler.test.ts +32 -6
- package/src/__tests__/telegram-config.test.ts +10 -13
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +25 -5
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
- package/src/__tests__/tool-approval-handler.test.ts +73 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +33 -24
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
- package/src/__tests__/top-level-renderer.test.ts +73 -1
- package/src/__tests__/transport-hints-queue.test.ts +14 -29
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
- package/src/__tests__/tts-catalog-parity.test.ts +345 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
- package/src/__tests__/twilio-routes.test.ts +376 -0
- package/src/__tests__/unicode.test.ts +293 -0
- package/src/__tests__/update-bulletin-format.test.ts +59 -0
- package/src/__tests__/update-bulletin.test.ts +206 -5
- package/src/__tests__/usage-routes.test.ts +25 -4
- package/src/__tests__/user-reference.test.ts +46 -61
- package/src/__tests__/v2-consent-policy.test.ts +103 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
- package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
- package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
- package/src/__tests__/workspace-migration-meets.test.ts +244 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
- package/src/__tests__/workspace-policy.test.ts +2 -0
- package/src/acp/client-handler.ts +30 -4
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +55 -9
- package/src/approvals/guardian-request-resolvers.ts +21 -15
- 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-session/__tests__/manager.test.ts +297 -0
- package/src/browser-session/backends/cdp-inspect.ts +30 -0
- package/src/browser-session/backends/extension.ts +26 -0
- package/src/browser-session/backends/local.ts +24 -0
- package/src/browser-session/events.ts +164 -0
- package/src/browser-session/index.ts +27 -0
- package/src/browser-session/manager.ts +159 -0
- package/src/browser-session/types.ts +28 -0
- package/src/bundler/package-resolver.ts +4 -0
- package/src/calls/audio-store.ts +11 -5
- package/src/calls/call-controller.ts +226 -71
- package/src/calls/call-domain.ts +9 -0
- package/src/calls/call-speech-output.ts +190 -0
- package/src/calls/call-transport.ts +77 -0
- package/src/calls/media-stream-audio-transcode.ts +173 -0
- package/src/calls/media-stream-output.ts +660 -0
- package/src/calls/media-stream-parser.ts +300 -0
- package/src/calls/media-stream-protocol.ts +166 -0
- package/src/calls/media-stream-server.ts +592 -0
- package/src/calls/media-stream-stt-session.ts +460 -0
- package/src/calls/media-turn-detector.ts +230 -0
- package/src/calls/relay-server.ts +90 -75
- package/src/calls/resolve-call-tts-provider.ts +136 -0
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +161 -0
- package/src/calls/tts-text-sanitizer.ts +32 -16
- package/src/calls/twilio-routes.ts +281 -17
- package/src/calls/voice-quality.ts +78 -35
- package/src/calls/voice-session-bridge.ts +8 -1
- package/src/channels/__tests__/types.test.ts +134 -0
- package/src/channels/types.ts +69 -3
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
- package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
- package/src/cli/commands/__tests__/email-download.test.ts +16 -1
- package/src/cli/commands/__tests__/email-list.test.ts +22 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +37 -4
- package/src/cli/commands/__tests__/email-status.test.ts +5 -1
- package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/conversations.ts +77 -0
- package/src/cli/commands/credentials.ts +3 -4
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +273 -16
- package/src/cli/commands/mcp.ts +16 -4
- package/src/cli/commands/oauth/__tests__/connect.test.ts +56 -44
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
- package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
- package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +32 -33
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +330 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +117 -12
- package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
- package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
- package/src/cli/commands/oauth/apps.ts +7 -4
- package/src/cli/commands/oauth/connect.ts +6 -3
- package/src/cli/commands/oauth/disconnect.ts +1 -1
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +215 -36
- package/src/cli/commands/oauth/shared.ts +7 -6
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +254 -0
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
- package/src/cli/commands/platform/index.ts +107 -10
- package/src/cli/commands/usage.ts +10 -9
- package/src/cli/lib/daemon-credential-client.ts +4 -0
- package/src/cli/program.ts +30 -4
- package/src/config/__tests__/backup-schema.test.ts +134 -0
- package/src/config/assistant-feature-flags.ts +61 -62
- package/src/config/bundled-skills/app-builder/SKILL.md +26 -249
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +141 -0
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
- package/src/config/bundled-skills/browser/SKILL.md +30 -5
- package/src/config/bundled-skills/browser/TOOLS.json +123 -0
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
- package/src/config/bundled-skills/contacts/SKILL.md +5 -2
- package/src/config/bundled-skills/document/SKILL.md +4 -0
- package/src/config/bundled-skills/gmail/SKILL.md +54 -8
- package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
- package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/outlook/SKILL.md +9 -2
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
- package/src/config/bundled-skills/slack/SKILL.md +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +21 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
- package/src/config/bundled-skills/tasks/SKILL.md +5 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
- package/src/config/bundled-tool-registry.ts +8 -0
- package/src/config/env-registry.ts +38 -0
- package/src/config/env.ts +49 -4
- package/src/config/feature-flag-registry.json +85 -14
- package/src/config/loader.ts +82 -13
- package/src/config/sanitize-for-transfer.ts +47 -0
- package/src/config/schema.ts +81 -15
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +51 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -26
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +47 -7
- package/src/config/schemas/heartbeat.ts +27 -5
- package/src/config/schemas/host-browser.ts +112 -0
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/memory-retrieval.ts +103 -0
- package/src/config/schemas/security.ts +0 -6
- package/src/config/schemas/services.ts +52 -0
- package/src/config/schemas/stt.ts +59 -0
- package/src/config/schemas/tts.ts +230 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/skills.ts +4 -0
- package/src/config/types.ts +4 -1
- package/src/contacts/contact-store.ts +56 -11
- package/src/contacts/contacts-write.ts +38 -1
- package/src/context/post-turn-tool-result-truncation.ts +177 -0
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +61 -10
- package/src/credential-execution/approval-bridge.ts +49 -15
- package/src/credential-execution/executable-discovery.ts +12 -2
- package/src/credential-execution/process-manager.ts +33 -2
- package/src/credential-health/credential-health-service.ts +366 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +195 -0
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/app-source-watcher.ts +35 -0
- package/src/daemon/config-watcher.ts +99 -5
- package/src/daemon/context-overflow-approval.ts +5 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +23 -2
- package/src/daemon/conversation-agent-loop.ts +153 -42
- package/src/daemon/conversation-attachments.ts +40 -0
- package/src/daemon/conversation-error.ts +11 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +59 -9
- package/src/daemon/conversation-messaging.ts +37 -3
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +622 -13
- package/src/daemon/conversation-queue-manager.ts +24 -0
- package/src/daemon/conversation-runtime-assembly.ts +128 -36
- package/src/daemon/conversation-slash.ts +36 -0
- package/src/daemon/conversation-surfaces.ts +131 -40
- package/src/daemon/conversation-tool-setup.ts +99 -8
- package/src/daemon/conversation-usage.ts +7 -4
- package/src/daemon/conversation-workspace.ts +12 -0
- package/src/daemon/conversation.ts +292 -16
- package/src/daemon/date-context.ts +10 -10
- package/src/daemon/first-greeting.ts +3 -2
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +13 -141
- package/src/daemon/handlers/shared.ts +80 -0
- package/src/daemon/handlers/skills.ts +483 -44
- package/src/daemon/host-bash-proxy.ts +48 -13
- package/src/daemon/host-browser-proxy.ts +192 -0
- package/src/daemon/host-cu-proxy.ts +36 -11
- package/src/daemon/host-file-proxy.ts +57 -9
- package/src/daemon/lifecycle.ts +179 -28
- package/src/daemon/message-protocol.ts +13 -0
- package/src/daemon/message-types/conversations.ts +89 -14
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/host-browser.ts +100 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +19 -5
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +26 -0
- package/src/daemon/message-types/subagents.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/server.ts +439 -14
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +15 -0
- package/src/daemon/transport-hints.ts +5 -24
- package/src/email/html-renderer.ts +76 -0
- package/src/heartbeat/heartbeat-service.ts +93 -7
- package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
- package/src/home/__tests__/emit-feed-event.test.ts +169 -0
- package/src/home/__tests__/feed-scheduler.test.ts +194 -0
- package/src/home/__tests__/feed-types.test.ts +275 -0
- package/src/home/__tests__/feed-writer.test.ts +688 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
- package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
- package/src/home/__tests__/progress-formula.test.ts +213 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
- package/src/home/__tests__/rollup-producer.test.ts +398 -0
- package/src/home/assistant-feed-authoring.ts +124 -0
- package/src/home/emit-feed-event.ts +158 -0
- package/src/home/feed-scheduler.ts +247 -0
- package/src/home/feed-types.ts +181 -0
- package/src/home/feed-writer.ts +469 -0
- package/src/home/platform-gmail-digest.ts +163 -0
- package/src/home/progress-formula.ts +86 -0
- package/src/home/relationship-state-writer.ts +824 -0
- package/src/home/relationship-state.ts +143 -0
- package/src/home/rollup-producer.ts +384 -0
- package/src/hooks/runner.ts +7 -0
- package/src/inbound/platform-callback-registration.ts +30 -20
- package/src/inbound/public-ingress-urls.ts +12 -0
- package/src/instrument.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/cli-client.ts +151 -0
- package/src/ipc/cli-server.ts +234 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/index.ts +5 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/mcp/client.ts +59 -24
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
- package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/app-store.ts +31 -1
- package/src/memory/attachments-store.ts +70 -0
- package/src/memory/auto-analysis-enqueue.ts +127 -0
- package/src/memory/auto-analysis-guard.ts +27 -0
- package/src/memory/cleanup-schedule-state.ts +37 -0
- package/src/memory/conversation-analyze-job.ts +73 -0
- package/src/memory/conversation-crud.ts +122 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +34 -2
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/conversation-starters-cadence.ts +76 -0
- package/src/memory/conversation-title-service.ts +5 -2
- package/src/memory/db-init.ts +18 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/embedding-backend.test.ts +75 -0
- package/src/memory/embedding-backend.ts +131 -5
- package/src/memory/embedding-gemini.test.ts +54 -0
- package/src/memory/embedding-gemini.ts +20 -9
- package/src/memory/embedding-local.ts +176 -17
- package/src/memory/graph/consolidation.ts +10 -23
- package/src/memory/graph/conversation-graph-memory.ts +15 -0
- package/src/memory/graph/extraction-job.ts +15 -0
- package/src/memory/graph/extraction.test.ts +23 -0
- package/src/memory/graph/extraction.ts +8 -0
- package/src/memory/graph/retriever.ts +67 -40
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/store.test.ts +7 -3
- package/src/memory/graph/store.ts +47 -12
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/group-crud.ts +6 -1
- package/src/memory/indexer.ts +95 -16
- package/src/memory/job-handlers/cleanup.ts +11 -8
- package/src/memory/job-handlers/conversation-starters.ts +16 -10
- package/src/memory/jobs-store.ts +64 -4
- package/src/memory/jobs-worker.ts +22 -9
- package/src/memory/llm-usage-store.ts +137 -60
- package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
- package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
- package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
- package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
- package/src/memory/migrations/217-conversation-host-access.ts +40 -0
- package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
- package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
- package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
- package/src/memory/migrations/index.ts +12 -0
- package/src/memory/migrations/registry.ts +16 -0
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/oauth.ts +21 -13
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/client.ts +57 -6
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +143 -38
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/notifications/decision-engine.ts +3 -3
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/AGENTS.md +76 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +25 -19
- package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
- package/src/oauth/byo-connection.test.ts +26 -9
- package/src/oauth/byo-connection.ts +10 -8
- package/src/oauth/connect-orchestrator.ts +25 -21
- package/src/oauth/connect-types.ts +3 -3
- package/src/oauth/connection-resolver.test.ts +17 -4
- package/src/oauth/connection-resolver.ts +22 -18
- package/src/oauth/connection.ts +3 -1
- package/src/oauth/manual-token-connection.ts +13 -13
- package/src/oauth/oauth-store.ts +223 -100
- package/src/oauth/platform-connection.test.ts +101 -3
- package/src/oauth/platform-connection.ts +56 -35
- package/src/oauth/provider-serializer.ts +31 -5
- package/src/oauth/revoke.ts +76 -0
- package/src/oauth/seed-providers.ts +133 -87
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/checker.ts +16 -6
- package/src/permissions/defaults.ts +49 -1
- package/src/permissions/permission-mode.ts +4 -11
- package/src/permissions/prompter.ts +13 -1
- package/src/permissions/trust-store.ts +3 -3
- package/src/permissions/v2-consent-policy.ts +87 -0
- package/src/permissions/workspace-policy.ts +3 -0
- package/src/platform/client.test.ts +10 -0
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +126 -2
- package/src/prompts/system-prompt.ts +76 -38
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
- package/src/prompts/templates/BOOTSTRAP.md +59 -105
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/prompts/templates/UPDATES.md +12 -0
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-format.ts +26 -9
- package/src/prompts/update-bulletin.ts +34 -23
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/anthropic/client.ts +157 -60
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +9 -1
- package/src/providers/model-catalog.ts +6 -0
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +474 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +502 -0
- package/src/providers/openrouter/client.ts +101 -4
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +14 -3
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
- package/src/providers/speech-to-text/deepgram.test.ts +332 -0
- package/src/providers/speech-to-text/deepgram.ts +115 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
- package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
- package/src/providers/speech-to-text/google-gemini.ts +101 -0
- package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
- package/src/providers/speech-to-text/openai-whisper.ts +63 -33
- package/src/providers/speech-to-text/provider-catalog.ts +306 -0
- package/src/providers/speech-to-text/resolve.ts +386 -6
- package/src/providers/types.ts +10 -1
- package/src/runtime/AGENTS.md +65 -0
- package/src/runtime/__tests__/agent-wake.test.ts +831 -0
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
- package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
- package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
- package/src/runtime/agent-wake.ts +512 -0
- package/src/runtime/assistant-event-hub.ts +2 -2
- package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +48 -0
- package/src/runtime/auth/middleware.ts +98 -0
- package/src/runtime/auth/route-policy.ts +33 -9
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/capability-tokens.ts +414 -0
- package/src/runtime/channel-approvals.ts +18 -5
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-invite-transports/email.ts +14 -6
- package/src/runtime/channel-readiness-service.ts +12 -22
- package/src/runtime/chrome-extension-registry.ts +368 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
- package/src/runtime/guardian-decision-types.ts +7 -0
- package/src/runtime/http-server.ts +815 -75
- package/src/runtime/http-types.ts +6 -2
- package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +198 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/migration-transport.ts +7 -0
- package/src/runtime/migrations/migration-wizard.ts +23 -2
- package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
- package/src/runtime/migrations/vbundle-builder.ts +145 -38
- package/src/runtime/migrations/vbundle-import-analyzer.ts +96 -1
- package/src/runtime/migrations/vbundle-importer.ts +89 -5
- package/src/runtime/pending-interactions.ts +18 -13
- package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
- package/src/runtime/routes/app-management-routes.ts +12 -18
- package/src/runtime/routes/approval-routes.ts +90 -16
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/backup-routes.ts +519 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +556 -0
- package/src/runtime/routes/btw-routes.ts +8 -6
- package/src/runtime/routes/contact-routes.test.ts +298 -0
- package/src/runtime/routes/contact-routes.ts +132 -5
- package/src/runtime/routes/conversation-analysis-routes.ts +22 -141
- package/src/runtime/routes/conversation-management-routes.ts +223 -0
- package/src/runtime/routes/conversation-routes.ts +598 -103
- package/src/runtime/routes/conversation-starter-routes.ts +78 -16
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/guardian-action-routes.ts +24 -13
- package/src/runtime/routes/home-feed-routes.ts +334 -0
- package/src/runtime/routes/home-state-routes.ts +138 -0
- package/src/runtime/routes/host-browser-routes.ts +268 -0
- package/src/runtime/routes/host-file-routes.ts +9 -1
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +262 -33
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
- package/src/runtime/routes/integrations/slack/channel.ts +11 -3
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +303 -0
- package/src/runtime/routes/log-export-routes.ts +42 -22
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/memory-item-routes.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +122 -2
- package/src/runtime/routes/oauth-apps.ts +15 -17
- package/src/runtime/routes/oauth-providers.ts +4 -0
- package/src/runtime/routes/schedule-routes.ts +24 -11
- package/src/runtime/routes/settings-routes.ts +31 -102
- package/src/runtime/routes/skills-routes.ts +128 -9
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/subagents-routes.ts +14 -10
- package/src/runtime/routes/surface-action-routes.ts +41 -2
- package/src/runtime/routes/tts-routes.ts +108 -24
- package/src/runtime/routes/usage-routes.ts +38 -9
- package/src/runtime/routes/user-route-dispatcher.ts +50 -5
- package/src/runtime/routes/user-routes.ts +13 -1
- package/src/runtime/routes/work-items-routes.ts +8 -1
- package/src/runtime/routes/workspace-routes.test.ts +22 -0
- package/src/runtime/routes/workspace-routes.ts +8 -1
- package/src/runtime/routes/workspace-utils.ts +2 -0
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
- package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
- package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
- package/src/runtime/services/analyze-conversation.ts +344 -0
- package/src/runtime/services/analyze-deps-singleton.ts +32 -0
- package/src/runtime/services/auto-analysis-prompt.ts +55 -0
- package/src/runtime/skill-route-registry.ts +49 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +57 -5
- package/src/security/ces-credential-client.ts +20 -0
- package/src/security/ces-rpc-credential-backend.ts +17 -0
- package/src/security/credential-backend.ts +5 -0
- package/src/security/oauth2.ts +68 -29
- package/src/security/secure-keys.ts +143 -27
- package/src/security/token-manager.ts +31 -10
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-files.ts +554 -0
- package/src/skills/category-inference.ts +122 -0
- package/src/skills/clawhub-files.ts +213 -0
- package/src/skills/clawhub.ts +84 -23
- package/src/skills/skill-file-provider.ts +40 -0
- package/src/skills/skillssh-files.ts +395 -0
- package/src/skills/skillssh-registry.ts +4 -4
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +195 -0
- package/src/stt/stt-stream-session.ts +499 -0
- package/src/stt/types.ts +330 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +169 -40
- package/src/subagent/types.ts +19 -0
- package/src/tools/apps/executors.ts +11 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
- package/src/tools/browser/auth-detector.ts +43 -12
- package/src/tools/browser/browser-execution.ts +1787 -342
- package/src/tools/browser/browser-manager.ts +81 -12
- 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__/accessibility-snapshot.test.ts +318 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +1263 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +359 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1993 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
- package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +1007 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +744 -0
- package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +868 -0
- package/src/tools/browser/cdp-client/errors.ts +49 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +148 -0
- package/src/tools/browser/cdp-client/factory.ts +914 -0
- package/src/tools/browser/cdp-client/index.ts +28 -0
- package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
- package/src/tools/browser/cdp-client/types.ts +120 -0
- package/src/tools/credentials/vault.ts +35 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +1 -1
- package/src/tools/host-filesystem/read.ts +12 -15
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +21 -16
- package/src/tools/network/web-fetch.ts +5 -2
- package/src/tools/network/web-search.ts +5 -2
- package/src/tools/permission-checker.ts +77 -82
- package/src/tools/registry.ts +0 -2
- package/src/tools/secret-detection-handler.ts +34 -0
- package/src/tools/shared/filesystem/image-read.ts +61 -40
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +2 -0
- package/src/tools/skills/sandbox-runner.ts +3 -2
- package/src/tools/subagent/spawn.ts +47 -3
- package/src/tools/subagent/status.ts +2 -0
- package/src/tools/system/register.ts +2 -16
- package/src/tools/terminal/safe-env.ts +15 -0
- package/src/tools/terminal/shell.ts +36 -20
- package/src/tools/tool-approval-handler.ts +48 -2
- package/src/tools/tool-manifest.ts +21 -0
- package/src/tools/types.ts +19 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tts/__tests__/provider-adapters.test.ts +834 -0
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
- package/src/tts/__tests__/provider-catalog.test.ts +183 -0
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +201 -0
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +219 -0
- package/src/tts/providers/elevenlabs-provider.ts +211 -0
- package/src/tts/providers/fish-audio-provider.ts +183 -0
- package/src/tts/providers/index.ts +42 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +153 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/util/abort-reasons.ts +58 -0
- package/src/util/device-id.ts +32 -16
- package/src/util/errors.ts +9 -1
- package/src/util/platform.ts +63 -24
- package/src/util/pricing.ts +66 -3
- package/src/util/spawn.ts +1 -1
- package/src/util/truncate.ts +4 -2
- package/src/util/unicode.ts +201 -0
- package/src/version.ts +19 -24
- package/src/watcher/engine.ts +23 -0
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/migrations/003-seed-device-id.ts +9 -3
- package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
- package/src/workspace/migrations/029-seed-pkb.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +317 -0
- package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
- package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
- package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
- package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
- package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
- package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
- package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/top-level-renderer.ts +31 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/chrome-cdp.test.ts +0 -419
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/__tests__/permission-mode-sse.test.ts +0 -418
- package/src/__tests__/permission-mode-store.test.ts +0 -277
- package/src/browser-extension-relay/protocol.ts +0 -63
- package/src/browser-extension-relay/server.ts +0 -203
- package/src/cli/commands/browser-relay.ts +0 -536
- package/src/config/schemas/sandbox.ts +0 -14
- 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/permissions/permission-mode-store.ts +0 -180
- package/src/prompts/templates/USER.md +0 -13
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/tools/browser/chrome-cdp.ts +0 -239
- package/src/tools/system/set-permission-mode.ts +0 -103
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Gemini Live API streaming STT adapter.
|
|
3
|
+
*
|
|
4
|
+
* Opens a bidirectional streaming session against Gemini's Live API
|
|
5
|
+
* (`ai.live.connect`), forwards PCM audio frames from the caller, and
|
|
6
|
+
* normalizes the server's `inputAudioTranscription` events into the
|
|
7
|
+
* daemon's {@link SttStreamServerEvent} contract with stable partial/final
|
|
8
|
+
* semantics.
|
|
9
|
+
*
|
|
10
|
+
* Design notes:
|
|
11
|
+
* - Uses a long-lived WebSocket-backed session (not periodic REST polls).
|
|
12
|
+
* - The server emits transcription events natively via
|
|
13
|
+
* `serverContent.inputTranscription`; we do not diff responses ourselves.
|
|
14
|
+
* - Suppresses the model's text turn (`responseModalities: [TEXT]`,
|
|
15
|
+
* system instruction telling the model to stay silent) so we only pay
|
|
16
|
+
* for transcription work.
|
|
17
|
+
*
|
|
18
|
+
* Lifecycle:
|
|
19
|
+
* 1. {@link start} opens the Live session and resolves on `onopen`.
|
|
20
|
+
* 2. {@link sendAudio} forwards PCM chunks via `session.sendRealtimeInput`.
|
|
21
|
+
* 3. {@link stop} sends `audioStreamEnd: true` and waits for the server
|
|
22
|
+
* to flush any remaining transcription before closing.
|
|
23
|
+
* 4. The `onEvent` callback receives `partial`, `final`, `error`, and
|
|
24
|
+
* `closed` events throughout the session lifetime.
|
|
25
|
+
*
|
|
26
|
+
* Error handling mirrors {@link DeepgramRealtimeTranscriber}: close-code
|
|
27
|
+
* categorization (`auth` for 1008/4001, `rate-limit` for 1013,
|
|
28
|
+
* `provider-error` for everything else), a configurable inactivity
|
|
29
|
+
* timeout, and idempotent cleanup.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import type { LiveServerMessage, Session } from "@google/genai";
|
|
33
|
+
import { GoogleGenAI, Modality } from "@google/genai";
|
|
34
|
+
|
|
35
|
+
import type {
|
|
36
|
+
StreamingTranscriber,
|
|
37
|
+
SttStreamServerEvent,
|
|
38
|
+
} from "../../stt/types.js";
|
|
39
|
+
import { getLogger } from "../../util/logger.js";
|
|
40
|
+
|
|
41
|
+
const log = getLogger("google-gemini-live-stream");
|
|
42
|
+
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
// Constants
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Default Gemini Live-capable model. See the @google/genai SDK example at
|
|
49
|
+
* `@google/genai/dist/node/node.d.ts` (class `Live.connect`) — the Gemini
|
|
50
|
+
* Live API currently ships under the `gemini-live-2.5-flash-preview` id.
|
|
51
|
+
*/
|
|
52
|
+
const DEFAULT_MODEL = "gemini-live-2.5-flash-preview";
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Default timeout (ms) for the Live session handshake.
|
|
56
|
+
* If `onopen` does not fire within this window, start() rejects.
|
|
57
|
+
*/
|
|
58
|
+
const DEFAULT_CONNECT_TIMEOUT_MS = 10_000;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Default inactivity timeout (ms). If no message is received from Gemini
|
|
62
|
+
* for this duration after the session is open, the adapter closes with a
|
|
63
|
+
* timeout error. This guards against provider-side hangs.
|
|
64
|
+
*/
|
|
65
|
+
const DEFAULT_INACTIVITY_TIMEOUT_MS = 30_000;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Grace period (ms) after signaling `audioStreamEnd` before we force-close
|
|
69
|
+
* the Live session. Gives Gemini time to flush any remaining transcription.
|
|
70
|
+
*/
|
|
71
|
+
const CLOSE_GRACE_MS = 5_000;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* System instruction asking the model not to generate output. The Live API
|
|
75
|
+
* always attempts to respond; telling it to stay silent minimizes wasted
|
|
76
|
+
* tokens and avoids polluting our event stream with unwanted model turns.
|
|
77
|
+
*/
|
|
78
|
+
const SILENT_SYSTEM_INSTRUCTION =
|
|
79
|
+
"You are a silent transcription service. Do not respond to the user. Only transcribe the audio input.";
|
|
80
|
+
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// Options
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
export interface GoogleGeminiLiveStreamOptions {
|
|
86
|
+
/** Gemini Live model to use (default: "gemini-live-2.5-flash-preview"). */
|
|
87
|
+
model?: string;
|
|
88
|
+
/** Override the Google AI API base URL (useful for proxies or on-prem). */
|
|
89
|
+
baseUrl?: string;
|
|
90
|
+
/** Sample rate for raw PCM input; used when normalizing MIME types. */
|
|
91
|
+
pcmSampleRate?: number;
|
|
92
|
+
/** Connect timeout in milliseconds. Default: 10_000. */
|
|
93
|
+
connectTimeoutMs?: number;
|
|
94
|
+
/** Inactivity timeout in milliseconds. Default: 30_000. */
|
|
95
|
+
inactivityTimeoutMs?: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// Adapter implementation
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Google Gemini Live API streaming transcriber.
|
|
104
|
+
*
|
|
105
|
+
* Implements the daemon {@link StreamingTranscriber} contract on top of
|
|
106
|
+
* Gemini's bidirectional Live API with server-side input transcription.
|
|
107
|
+
*/
|
|
108
|
+
export class GoogleGeminiLiveStreamingTranscriber implements StreamingTranscriber {
|
|
109
|
+
readonly providerId = "google-gemini" as const;
|
|
110
|
+
readonly boundaryId = "daemon-streaming" as const;
|
|
111
|
+
|
|
112
|
+
private readonly client: GoogleGenAI;
|
|
113
|
+
private readonly model: string;
|
|
114
|
+
private readonly pcmSampleRate: number;
|
|
115
|
+
private readonly connectTimeoutMs: number;
|
|
116
|
+
private readonly inactivityTimeoutMs: number;
|
|
117
|
+
|
|
118
|
+
/** The live session, set during start(). */
|
|
119
|
+
private session: Session | null = null;
|
|
120
|
+
|
|
121
|
+
/** Callback for emitting events to the session orchestrator. */
|
|
122
|
+
private onEvent: ((event: SttStreamServerEvent) => void) | null = null;
|
|
123
|
+
|
|
124
|
+
/** Whether the session has been fully closed. */
|
|
125
|
+
private closed = false;
|
|
126
|
+
|
|
127
|
+
/** Whether stop() has been called. */
|
|
128
|
+
private stopping = false;
|
|
129
|
+
|
|
130
|
+
/** Inactivity timer handle. */
|
|
131
|
+
private inactivityTimer: ReturnType<typeof setTimeout> | null = null;
|
|
132
|
+
|
|
133
|
+
/** Close grace timer handle. */
|
|
134
|
+
private closeGraceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
135
|
+
|
|
136
|
+
/** Last partial transcript we emitted; used to dedupe repeats. */
|
|
137
|
+
private lastEmittedPartial = "";
|
|
138
|
+
|
|
139
|
+
/** Accumulated input transcription for the current turn. */
|
|
140
|
+
private currentTurnText = "";
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Whether we've already emitted a `final` event for the current turn
|
|
144
|
+
* via a completion signal (`turnComplete` / `generationComplete` /
|
|
145
|
+
* `inputTranscription.finished`). Reset when a new turn's text begins
|
|
146
|
+
* accumulating. Used by `flushFinalAndClose` to avoid emitting a
|
|
147
|
+
* trailing empty final when the provider closes normally after stop()
|
|
148
|
+
* has already flushed a final for the turn.
|
|
149
|
+
*/
|
|
150
|
+
private finalEmittedForCurrentTurn = false;
|
|
151
|
+
|
|
152
|
+
constructor(apiKey: string, options: GoogleGeminiLiveStreamOptions = {}) {
|
|
153
|
+
this.model = options.model ?? DEFAULT_MODEL;
|
|
154
|
+
this.pcmSampleRate = options.pcmSampleRate ?? 16_000;
|
|
155
|
+
this.connectTimeoutMs =
|
|
156
|
+
options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
157
|
+
this.inactivityTimeoutMs =
|
|
158
|
+
options.inactivityTimeoutMs ?? DEFAULT_INACTIVITY_TIMEOUT_MS;
|
|
159
|
+
|
|
160
|
+
this.client = options.baseUrl
|
|
161
|
+
? new GoogleGenAI({
|
|
162
|
+
apiKey,
|
|
163
|
+
httpOptions: { baseUrl: options.baseUrl },
|
|
164
|
+
})
|
|
165
|
+
: new GoogleGenAI({ apiKey });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ── StreamingTranscriber interface ──────────────────────────────────
|
|
169
|
+
|
|
170
|
+
async start(onEvent: (event: SttStreamServerEvent) => void): Promise<void> {
|
|
171
|
+
if (this.session || this.onEvent) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
"GoogleGeminiLiveStreamingTranscriber: start() called twice",
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
this.onEvent = onEvent;
|
|
177
|
+
this.closed = false;
|
|
178
|
+
this.stopping = false;
|
|
179
|
+
this.lastEmittedPartial = "";
|
|
180
|
+
this.currentTurnText = "";
|
|
181
|
+
this.finalEmittedForCurrentTurn = false;
|
|
182
|
+
|
|
183
|
+
log.info({ model: this.model }, "Opening Gemini Live session");
|
|
184
|
+
|
|
185
|
+
// Open is complete when BOTH the session handle is returned by the
|
|
186
|
+
// SDK AND `onopen` has fired. The real SDK's `live.connect()` awaits
|
|
187
|
+
// `onopen` internally before resolving with a Session; we track the
|
|
188
|
+
// two signals separately so the adapter stays correct across SDK
|
|
189
|
+
// ordering changes and matches the test mock (which returns the
|
|
190
|
+
// session synchronously and fires `onopen` on the next microtask).
|
|
191
|
+
let openFired = false;
|
|
192
|
+
let resolveOpen: (() => void) | null = null;
|
|
193
|
+
let rejectOpen: ((err: Error) => void) | null = null;
|
|
194
|
+
const openSignal = new Promise<void>((res, rej) => {
|
|
195
|
+
resolveOpen = res;
|
|
196
|
+
rejectOpen = rej;
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const finishOpen = (err?: Error): void => {
|
|
200
|
+
if (err) {
|
|
201
|
+
rejectOpen?.(err);
|
|
202
|
+
} else {
|
|
203
|
+
resolveOpen?.();
|
|
204
|
+
}
|
|
205
|
+
resolveOpen = null;
|
|
206
|
+
rejectOpen = null;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const connectPromise = this.client.live.connect({
|
|
210
|
+
model: this.model,
|
|
211
|
+
config: {
|
|
212
|
+
responseModalities: [Modality.TEXT],
|
|
213
|
+
inputAudioTranscription: {},
|
|
214
|
+
systemInstruction: SILENT_SYSTEM_INSTRUCTION,
|
|
215
|
+
},
|
|
216
|
+
callbacks: {
|
|
217
|
+
onopen: (): void => {
|
|
218
|
+
openFired = true;
|
|
219
|
+
finishOpen();
|
|
220
|
+
},
|
|
221
|
+
onmessage: (msg: LiveServerMessage): void => {
|
|
222
|
+
this.handleServerMessage(msg);
|
|
223
|
+
},
|
|
224
|
+
onerror: (ev: ErrorEvent): void => {
|
|
225
|
+
if (!openFired && !this.session) {
|
|
226
|
+
finishOpen(
|
|
227
|
+
new Error(`Gemini Live connect error: ${this.describeError(ev)}`),
|
|
228
|
+
);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
this.handleProviderError(ev);
|
|
232
|
+
},
|
|
233
|
+
onclose: (ev: CloseEvent): void => {
|
|
234
|
+
if (!openFired && !this.session) {
|
|
235
|
+
finishOpen(
|
|
236
|
+
new Error(
|
|
237
|
+
`Gemini Live session closed before open (code=${ev.code}, reason=${ev.reason})`,
|
|
238
|
+
),
|
|
239
|
+
);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
this.handleProviderClose(ev.code, ev.reason);
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// Capture the session as soon as the SDK returns it so subsequent
|
|
248
|
+
// methods have a handle. A failed connect (rejection) is surfaced
|
|
249
|
+
// below via the race path.
|
|
250
|
+
let timedOut = false;
|
|
251
|
+
connectPromise
|
|
252
|
+
.then((session) => {
|
|
253
|
+
if (timedOut) {
|
|
254
|
+
// Never assign a session after the start() timeout: if we did,
|
|
255
|
+
// `this.session` would persist past the failed start() and a
|
|
256
|
+
// retry would incorrectly trip the "start() called twice" guard.
|
|
257
|
+
try {
|
|
258
|
+
session.close();
|
|
259
|
+
} catch {
|
|
260
|
+
// best effort
|
|
261
|
+
}
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
this.session = session;
|
|
265
|
+
})
|
|
266
|
+
.catch(() => {
|
|
267
|
+
// Surfaced through the Promise.race below.
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Timeout race.
|
|
271
|
+
const timeoutPromise = new Promise<never>((_, rej) => {
|
|
272
|
+
const timer = setTimeout(() => {
|
|
273
|
+
timedOut = true;
|
|
274
|
+
log.warn("Gemini Live connect timeout");
|
|
275
|
+
rej(new Error("Gemini Live connect timeout"));
|
|
276
|
+
}, this.connectTimeoutMs);
|
|
277
|
+
// Clear the timer only once open has actually fired; a resolved
|
|
278
|
+
// `connectPromise` alone does not mean the session is open (the
|
|
279
|
+
// test mock returns the session synchronously and defers onopen).
|
|
280
|
+
openSignal.finally(() => clearTimeout(timer)).catch(() => {});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
// Wait for the SDK's connect() to resolve (giving us `this.session`)
|
|
285
|
+
// AND for `onopen` to have fired, or for either a timeout or
|
|
286
|
+
// connect error to fail the race.
|
|
287
|
+
await Promise.race([
|
|
288
|
+
Promise.all([connectPromise, openSignal]),
|
|
289
|
+
timeoutPromise,
|
|
290
|
+
]);
|
|
291
|
+
} catch (err) {
|
|
292
|
+
this.onEvent = null;
|
|
293
|
+
// The connectPromise may have already resolved with a session
|
|
294
|
+
// handle before the timeout fired — if so, the `.then()` above
|
|
295
|
+
// captured it on `this.session`. Close any such orphaned session
|
|
296
|
+
// here to prevent leaking a live WebSocket to the provider.
|
|
297
|
+
this.forceCloseSession();
|
|
298
|
+
throw err;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
this.resetInactivityTimer();
|
|
302
|
+
log.info("Gemini Live session opened");
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
sendAudio(audio: Buffer, mimeType: string): void {
|
|
306
|
+
if (this.closed || this.stopping) return;
|
|
307
|
+
|
|
308
|
+
const session = this.session;
|
|
309
|
+
if (!session) return;
|
|
310
|
+
|
|
311
|
+
const normalizedMimeType = this.normalizePcmMimeType(mimeType);
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
session.sendRealtimeInput({
|
|
315
|
+
audio: {
|
|
316
|
+
data: audio.toString("base64"),
|
|
317
|
+
mimeType: normalizedMimeType,
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
} catch (err) {
|
|
321
|
+
log.warn({ error: err }, "Failed to send audio to Gemini Live session");
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
stop(): void {
|
|
326
|
+
if (this.closed || this.stopping) return;
|
|
327
|
+
this.stopping = true;
|
|
328
|
+
|
|
329
|
+
log.info("Stopping Gemini Live session");
|
|
330
|
+
|
|
331
|
+
const session = this.session;
|
|
332
|
+
if (!session) {
|
|
333
|
+
this.emitClosedAndCleanup();
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Signal end-of-audio so Gemini flushes any pending transcription.
|
|
338
|
+
try {
|
|
339
|
+
session.sendRealtimeInput({ audioStreamEnd: true });
|
|
340
|
+
} catch (err) {
|
|
341
|
+
// If the send fails, force-close immediately.
|
|
342
|
+
log.warn({ error: err }, "Failed to send audioStreamEnd; forcing close");
|
|
343
|
+
this.flushFinalAndClose();
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Start a grace timer — if the provider doesn't close within the
|
|
348
|
+
// grace window, we force-close to prevent session leaks.
|
|
349
|
+
this.closeGraceTimer = setTimeout(() => {
|
|
350
|
+
log.warn("Gemini Live close grace timeout — forcing close");
|
|
351
|
+
this.flushFinalAndClose();
|
|
352
|
+
}, CLOSE_GRACE_MS);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ── Provider message handling ───────────────────────────────────────
|
|
356
|
+
|
|
357
|
+
private handleServerMessage(msg: LiveServerMessage): void {
|
|
358
|
+
if (this.closed) return;
|
|
359
|
+
|
|
360
|
+
this.resetInactivityTimer();
|
|
361
|
+
|
|
362
|
+
// Session-level setup/usage/goAway signals — log and proceed.
|
|
363
|
+
if (msg.setupComplete) {
|
|
364
|
+
log.debug("Gemini Live setupComplete received");
|
|
365
|
+
}
|
|
366
|
+
if (msg.usageMetadata) {
|
|
367
|
+
log.debug({ usage: msg.usageMetadata }, "Gemini Live usageMetadata");
|
|
368
|
+
}
|
|
369
|
+
if (msg.goAway) {
|
|
370
|
+
log.info(
|
|
371
|
+
{ timeLeft: msg.goAway.timeLeft },
|
|
372
|
+
"Gemini Live goAway received — treating as graceful close",
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const serverContent = msg.serverContent;
|
|
377
|
+
if (!serverContent) return;
|
|
378
|
+
|
|
379
|
+
// Append any new input transcription text to the current turn buffer.
|
|
380
|
+
// A new turn begins when we see text while the buffer is empty —
|
|
381
|
+
// reset the "final already emitted" flag so the next completion
|
|
382
|
+
// signal can emit again.
|
|
383
|
+
const transcriptionText = serverContent.inputTranscription?.text;
|
|
384
|
+
if (typeof transcriptionText === "string" && transcriptionText.length > 0) {
|
|
385
|
+
if (this.currentTurnText.length === 0) {
|
|
386
|
+
this.finalEmittedForCurrentTurn = false;
|
|
387
|
+
}
|
|
388
|
+
this.currentTurnText += transcriptionText;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Detect turn completion. Per the `@google/genai` SDK docs,
|
|
392
|
+
// `inputTranscription` is independent of the model's response turn,
|
|
393
|
+
// so we honor `Transcription.finished` as an additional completion
|
|
394
|
+
// signal alongside `turnComplete` / `generationComplete`.
|
|
395
|
+
const isComplete =
|
|
396
|
+
serverContent.inputTranscription?.finished === true ||
|
|
397
|
+
serverContent.generationComplete === true ||
|
|
398
|
+
serverContent.turnComplete === true;
|
|
399
|
+
|
|
400
|
+
if (isComplete) {
|
|
401
|
+
const finalText = this.currentTurnText;
|
|
402
|
+
this.currentTurnText = "";
|
|
403
|
+
this.lastEmittedPartial = "";
|
|
404
|
+
this.finalEmittedForCurrentTurn = true;
|
|
405
|
+
this.emitEvent({ type: "final", text: finalText });
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// During the stop() grace period we still accumulate text (above)
|
|
410
|
+
// so any flushed final is complete, but we suppress partials — the
|
|
411
|
+
// session orchestrator does not want interleaved partials between
|
|
412
|
+
// stop() and the final emission.
|
|
413
|
+
if (this.stopping) return;
|
|
414
|
+
|
|
415
|
+
// Otherwise emit a partial only if text has changed.
|
|
416
|
+
if (
|
|
417
|
+
this.currentTurnText.length > 0 &&
|
|
418
|
+
this.currentTurnText !== this.lastEmittedPartial
|
|
419
|
+
) {
|
|
420
|
+
this.lastEmittedPartial = this.currentTurnText;
|
|
421
|
+
this.emitEvent({ type: "partial", text: this.currentTurnText });
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// `modelTurn` content is ignored — we only care about input
|
|
425
|
+
// transcription, not the model's response.
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Handle provider-side session close.
|
|
430
|
+
*/
|
|
431
|
+
private handleProviderClose(code: number, reason: string): void {
|
|
432
|
+
if (this.closed) return;
|
|
433
|
+
|
|
434
|
+
// Normal close (1000) or going-away (1001) after stop() is expected.
|
|
435
|
+
if (this.stopping && (code === 1000 || code === 1001)) {
|
|
436
|
+
log.info({ code, reason }, "Gemini Live session closed normally");
|
|
437
|
+
this.flushFinalAndClose();
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
log.warn({ code, reason }, "Gemini Live session closed unexpectedly");
|
|
442
|
+
|
|
443
|
+
const category =
|
|
444
|
+
code === 1008 || code === 4001
|
|
445
|
+
? ("auth" as const)
|
|
446
|
+
: code === 1013
|
|
447
|
+
? ("rate-limit" as const)
|
|
448
|
+
: ("provider-error" as const);
|
|
449
|
+
|
|
450
|
+
this.emitEvent({
|
|
451
|
+
type: "error",
|
|
452
|
+
category,
|
|
453
|
+
message: `Gemini Live session closed (code=${code}, reason=${reason})`,
|
|
454
|
+
});
|
|
455
|
+
this.emitClosedAndCleanup();
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Handle provider-side error event.
|
|
460
|
+
*/
|
|
461
|
+
private handleProviderError(ev: unknown): void {
|
|
462
|
+
if (this.closed) return;
|
|
463
|
+
|
|
464
|
+
const message = this.describeError(ev);
|
|
465
|
+
log.error({ error: ev }, "Gemini Live session error");
|
|
466
|
+
|
|
467
|
+
this.emitEvent({
|
|
468
|
+
type: "error",
|
|
469
|
+
category: "provider-error",
|
|
470
|
+
message: `Gemini Live session error: ${message}`,
|
|
471
|
+
});
|
|
472
|
+
this.emitClosedAndCleanup();
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// ── Event emission & cleanup ────────────────────────────────────────
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Emit a server event to the session orchestrator. Swallows listener
|
|
479
|
+
* errors to prevent tearing down the adapter.
|
|
480
|
+
*
|
|
481
|
+
* Drops events after `closed` to preserve the streaming contract.
|
|
482
|
+
*/
|
|
483
|
+
private emitEvent(event: SttStreamServerEvent): void {
|
|
484
|
+
if (!this.onEvent) return;
|
|
485
|
+
if (this.closed && event.type !== "closed") return;
|
|
486
|
+
try {
|
|
487
|
+
this.onEvent(event);
|
|
488
|
+
} catch (err) {
|
|
489
|
+
log.warn({ error: err }, "Listener error in Gemini Live adapter");
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Flush any pending transcription as a final event, then close. Used
|
|
495
|
+
* when the provider closes normally after stop() or when the close
|
|
496
|
+
* grace timer fires.
|
|
497
|
+
*
|
|
498
|
+
* Avoids emitting a spurious empty-string final when the server
|
|
499
|
+
* already emitted a completion signal (`turnComplete` / `finished` /
|
|
500
|
+
* `generationComplete`) for the current turn before closing — that
|
|
501
|
+
* path already emitted the final and drained the accumulator. The
|
|
502
|
+
* stream contract callers (e.g. Meet's storage-writer) would write
|
|
503
|
+
* an empty transcript line on the extra final, so we suppress it.
|
|
504
|
+
*/
|
|
505
|
+
private flushFinalAndClose(): void {
|
|
506
|
+
if (this.closed) return;
|
|
507
|
+
const pending = this.currentTurnText;
|
|
508
|
+
const alreadyEmitted = this.finalEmittedForCurrentTurn;
|
|
509
|
+
this.currentTurnText = "";
|
|
510
|
+
this.lastEmittedPartial = "";
|
|
511
|
+
this.finalEmittedForCurrentTurn = false;
|
|
512
|
+
if (!(alreadyEmitted && pending.length === 0)) {
|
|
513
|
+
this.emitEvent({ type: "final", text: pending });
|
|
514
|
+
}
|
|
515
|
+
this.emitClosedAndCleanup();
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Emit a `closed` event and clean up all resources (timers, session).
|
|
520
|
+
* Idempotent — safe to call multiple times.
|
|
521
|
+
*/
|
|
522
|
+
private emitClosedAndCleanup(): void {
|
|
523
|
+
if (this.closed) return;
|
|
524
|
+
this.closed = true;
|
|
525
|
+
|
|
526
|
+
this.clearTimers();
|
|
527
|
+
this.forceCloseSession();
|
|
528
|
+
|
|
529
|
+
this.emitEvent({ type: "closed" });
|
|
530
|
+
this.onEvent = null;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Force-close the Live session without emitting events. Used during
|
|
535
|
+
* cleanup and timeout paths.
|
|
536
|
+
*/
|
|
537
|
+
private forceCloseSession(): void {
|
|
538
|
+
const session = this.session;
|
|
539
|
+
this.session = null;
|
|
540
|
+
if (!session) return;
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
session.close();
|
|
544
|
+
} catch {
|
|
545
|
+
// Best effort — already-closed sessions may throw.
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Clear all active timers.
|
|
551
|
+
*/
|
|
552
|
+
private clearTimers(): void {
|
|
553
|
+
if (this.inactivityTimer !== null) {
|
|
554
|
+
clearTimeout(this.inactivityTimer);
|
|
555
|
+
this.inactivityTimer = null;
|
|
556
|
+
}
|
|
557
|
+
if (this.closeGraceTimer !== null) {
|
|
558
|
+
clearTimeout(this.closeGraceTimer);
|
|
559
|
+
this.closeGraceTimer = null;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Reset the inactivity timer. Called on inbound provider messages to
|
|
565
|
+
* detect provider-side hangs. Not reset on outbound audio sends —
|
|
566
|
+
* continuous audio from the caller must not mask a silent provider.
|
|
567
|
+
*/
|
|
568
|
+
private resetInactivityTimer(): void {
|
|
569
|
+
if (this.closed || this.stopping) return;
|
|
570
|
+
|
|
571
|
+
if (this.inactivityTimer !== null) {
|
|
572
|
+
clearTimeout(this.inactivityTimer);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
this.inactivityTimer = setTimeout(() => {
|
|
576
|
+
if (this.closed) return;
|
|
577
|
+
|
|
578
|
+
log.warn("Gemini Live inactivity timeout");
|
|
579
|
+
this.emitEvent({
|
|
580
|
+
type: "error",
|
|
581
|
+
category: "timeout",
|
|
582
|
+
message: "Gemini Live session timed out due to inactivity",
|
|
583
|
+
});
|
|
584
|
+
this.emitClosedAndCleanup();
|
|
585
|
+
}, this.inactivityTimeoutMs);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Normalize generic PCM MIME types to include the sample-rate hint that
|
|
592
|
+
* Gemini Live requires. Passes non-PCM MIME types through unchanged.
|
|
593
|
+
*
|
|
594
|
+
* When the input lacks a `rate=` parameter, we append `;rate=<N>` to
|
|
595
|
+
* the original string rather than rebuilding from scratch, so
|
|
596
|
+
* auxiliary parameters (e.g. `encoding=linear16`) and the caller's
|
|
597
|
+
* original casing are preserved.
|
|
598
|
+
*/
|
|
599
|
+
private normalizePcmMimeType(mimeType: string): string {
|
|
600
|
+
const base = mimeType.split(";")[0].trim().toLowerCase();
|
|
601
|
+
if (base !== "audio/pcm") return mimeType;
|
|
602
|
+
// Preserve an explicit rate= parameter if the caller supplied one.
|
|
603
|
+
if (/rate\s*=\s*\d+/i.test(mimeType)) return mimeType;
|
|
604
|
+
return `${mimeType};rate=${this.pcmSampleRate}`;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Produce a human-readable message from an unknown error-like value.
|
|
609
|
+
*/
|
|
610
|
+
private describeError(ev: unknown): string {
|
|
611
|
+
if (ev instanceof Error) return ev.message;
|
|
612
|
+
if (typeof ev === "object" && ev !== null) {
|
|
613
|
+
if ("message" in ev) {
|
|
614
|
+
const m = (ev as { message: unknown }).message;
|
|
615
|
+
if (m !== undefined && m !== null) return String(m);
|
|
616
|
+
}
|
|
617
|
+
if ("error" in ev) {
|
|
618
|
+
const e = (ev as { error: unknown }).error;
|
|
619
|
+
if (e instanceof Error) return e.message;
|
|
620
|
+
if (e !== undefined && e !== null) return String(e);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
return "Gemini Live session error";
|
|
624
|
+
}
|
|
625
|
+
}
|