@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
|
@@ -11,14 +11,13 @@ import {
|
|
|
11
11
|
createAssistantMessage,
|
|
12
12
|
createUserMessage,
|
|
13
13
|
} from "../agent/message-types.js";
|
|
14
|
-
import type {
|
|
15
|
-
TurnChannelContext,
|
|
16
|
-
TurnInterfaceContext,
|
|
17
|
-
} from "../channels/types.js";
|
|
18
14
|
import {
|
|
15
|
+
canServiceRegistryBrowser,
|
|
19
16
|
parseChannelId,
|
|
20
17
|
parseInterfaceId,
|
|
21
18
|
supportsHostProxy,
|
|
19
|
+
type TurnChannelContext,
|
|
20
|
+
type TurnInterfaceContext,
|
|
22
21
|
} from "../channels/types.js";
|
|
23
22
|
import { getConfig } from "../config/loader.js";
|
|
24
23
|
import type { ContextWindowResult } from "../context/window-manager.js";
|
|
@@ -34,19 +33,28 @@ import { createPreference } from "../notifications/preferences-store.js";
|
|
|
34
33
|
import type { Message } from "../providers/types.js";
|
|
35
34
|
import { routeGuardianReply } from "../runtime/guardian-reply-router.js";
|
|
36
35
|
import { getLogger } from "../util/logger.js";
|
|
37
|
-
import
|
|
38
|
-
import type {
|
|
36
|
+
import { persistQueuedMessageBody } from "./conversation-messaging.js";
|
|
37
|
+
import type {
|
|
38
|
+
MessageQueue,
|
|
39
|
+
QueuedMessage,
|
|
40
|
+
QueueDrainReason,
|
|
41
|
+
} from "./conversation-queue-manager.js";
|
|
39
42
|
import type {
|
|
40
43
|
ChannelCapabilities,
|
|
41
44
|
TrustContext,
|
|
42
45
|
} from "./conversation-runtime-assembly.js";
|
|
43
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
classifySlash,
|
|
48
|
+
resolveSlash,
|
|
49
|
+
type SlashContext,
|
|
50
|
+
} from "./conversation-slash.js";
|
|
44
51
|
import { getModelInfo } from "./handlers/config-model.js";
|
|
45
52
|
import type {
|
|
46
53
|
ServerMessage,
|
|
47
54
|
UsageStats,
|
|
48
55
|
UserMessageAttachment,
|
|
49
56
|
} from "./message-protocol.js";
|
|
57
|
+
import type { ConversationTransportMetadata } from "./message-types/conversations.js";
|
|
50
58
|
import type { TraceEmitter } from "./trace-emitter.js";
|
|
51
59
|
import { buildTransportHints } from "./transport-hints.js";
|
|
52
60
|
import { resolveVerificationSessionIntent } from "./verification-session-intent.js";
|
|
@@ -93,6 +101,12 @@ export interface ProcessConversationContext {
|
|
|
93
101
|
currentRequestId?: string;
|
|
94
102
|
readonly queue: MessageQueue;
|
|
95
103
|
readonly traceEmitter: TraceEmitter;
|
|
104
|
+
/**
|
|
105
|
+
* Set of requestIds created by surface-action responses. Used to
|
|
106
|
+
* distinguish surface-action turns from regular user turns (e.g. for
|
|
107
|
+
* stale-surface auto-dismiss guards and batched-drain exclusion).
|
|
108
|
+
*/
|
|
109
|
+
readonly surfaceActionRequestIds: Set<string>;
|
|
96
110
|
currentActiveSurfaceId?: string;
|
|
97
111
|
currentPage?: string;
|
|
98
112
|
/** Cumulative token usage stats for the conversation. */
|
|
@@ -134,8 +148,26 @@ export interface ProcessConversationContext {
|
|
|
134
148
|
setTurnInterfaceContext(ctx: TurnInterfaceContext): void;
|
|
135
149
|
/** Mark host proxies as unavailable so tool execution uses local fallback. */
|
|
136
150
|
clearProxyAvailability(): void;
|
|
137
|
-
/**
|
|
138
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Restore host proxy availability based on whether a real client is connected.
|
|
153
|
+
* When `skipBrowser` is true, the browser proxy is left untouched — use this
|
|
154
|
+
* when `restoreBrowserProxyAvailability()` will handle the browser proxy
|
|
155
|
+
* separately with the correct registry-routed sender.
|
|
156
|
+
*/
|
|
157
|
+
restoreProxyAvailability(options?: { skipBrowser?: boolean }): void;
|
|
158
|
+
/** Restore only the host browser proxy (used by chrome-extension and macOS+extension drains). */
|
|
159
|
+
restoreBrowserProxyAvailability(): void;
|
|
160
|
+
/**
|
|
161
|
+
* Registry-routed sender override for the host browser proxy. When set,
|
|
162
|
+
* `restoreBrowserProxyAvailability()` uses this function instead of
|
|
163
|
+
* `sendToClient`. Set by the POST /messages handler when the guardian
|
|
164
|
+
* has an active extension connection (regardless of interface).
|
|
165
|
+
*/
|
|
166
|
+
hostBrowserSenderOverride?: (msg: ServerMessage) => void;
|
|
167
|
+
/** Replace or clear the conversation's host browser proxy. */
|
|
168
|
+
setHostBrowserProxy(
|
|
169
|
+
proxy: import("./host-browser-proxy.js").HostBrowserProxy | undefined,
|
|
170
|
+
): void;
|
|
139
171
|
emitActivityState(
|
|
140
172
|
phase:
|
|
141
173
|
| "idle"
|
|
@@ -164,6 +196,13 @@ export interface ProcessConversationContext {
|
|
|
164
196
|
forceCompact(): Promise<ContextWindowResult>;
|
|
165
197
|
/** Set transport-derived hints for the conversation. */
|
|
166
198
|
setTransportHints(hints: string[] | undefined): void;
|
|
199
|
+
/**
|
|
200
|
+
* Apply client-reported host env (home dir, username) from transport
|
|
201
|
+
* metadata, gating on `supportsHostProxy` so non-host-proxy interfaces
|
|
202
|
+
* clear any stale values. Shared between the create/reuse path in
|
|
203
|
+
* `DaemonServer.applyTransportMetadata` and the queue-drain path below.
|
|
204
|
+
*/
|
|
205
|
+
applyHostEnvFromTransport(transport: ConversationTransportMetadata): void;
|
|
167
206
|
}
|
|
168
207
|
|
|
169
208
|
function resolveQueuedTurnContext(
|
|
@@ -228,6 +267,82 @@ function buildSlashContext(
|
|
|
228
267
|
};
|
|
229
268
|
}
|
|
230
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Walk the head of the queue and return the longest contiguous run of
|
|
272
|
+
* passthrough messages (non-slash, non-verification-intent) that share the
|
|
273
|
+
* same `userMessageInterface`. Returns `[]` when the head is itself a slash
|
|
274
|
+
* command or verification-intent direct-setup — in that case `drainQueue`
|
|
275
|
+
* pops the head via `queue.shift()` and the single-message path handles it.
|
|
276
|
+
*
|
|
277
|
+
* The builder uses `peek` for lookahead and only calls `shiftN(matched)` once
|
|
278
|
+
* a contiguous passthrough run is identified. This keeps byte-budget
|
|
279
|
+
* accounting centralized in `MessageQueue` rather than mutating mid-walk.
|
|
280
|
+
*/
|
|
281
|
+
async function buildPassthroughBatch(
|
|
282
|
+
conversation: ProcessConversationContext,
|
|
283
|
+
): Promise<QueuedMessage[]> {
|
|
284
|
+
const head = conversation.queue.peek(0);
|
|
285
|
+
if (head === undefined) return [];
|
|
286
|
+
|
|
287
|
+
const headInterface = resolveQueuedTurnInterfaceContext(
|
|
288
|
+
head,
|
|
289
|
+
conversation.getTurnInterfaceContext(),
|
|
290
|
+
);
|
|
291
|
+
// Pure classifier — no side effects. `resolveSlash` runs /pair's side
|
|
292
|
+
// effects (pairing registration, QR PNG write); if we called it here the
|
|
293
|
+
// real drain would invoke those again and the second call would fail with
|
|
294
|
+
// "active pairing already in progress".
|
|
295
|
+
if (classifySlash(head.content) !== "passthrough") return [];
|
|
296
|
+
if (resolveVerificationSessionIntent(head.content).kind === "direct_setup") {
|
|
297
|
+
// Verification intents stay on the single-message path so their per-turn
|
|
298
|
+
// skill preactivation isn't leaked into batched tail messages.
|
|
299
|
+
return [];
|
|
300
|
+
}
|
|
301
|
+
// Surface-action messages rely on per-message `activeSurfaceId` and
|
|
302
|
+
// `surfaceActionRequestIds` semantics that last-wins batching would
|
|
303
|
+
// corrupt (e.g. erasing the head's surface context when the last tail is
|
|
304
|
+
// a regular text message). Keep them on the single-message path.
|
|
305
|
+
if (
|
|
306
|
+
head.activeSurfaceId !== undefined ||
|
|
307
|
+
conversation.surfaceActionRequestIds.has(head.requestId)
|
|
308
|
+
) {
|
|
309
|
+
return [];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
let i = 1;
|
|
313
|
+
for (;;) {
|
|
314
|
+
const candidate = conversation.queue.peek(i);
|
|
315
|
+
if (candidate === undefined) break;
|
|
316
|
+
const candIf = resolveQueuedTurnInterfaceContext(
|
|
317
|
+
candidate,
|
|
318
|
+
conversation.getTurnInterfaceContext(),
|
|
319
|
+
);
|
|
320
|
+
// Treat an undefined interface as distinct from a defined one so we don't
|
|
321
|
+
// silently batch cross-interface messages whose env/transport would
|
|
322
|
+
// otherwise diverge.
|
|
323
|
+
if (candIf?.userMessageInterface !== headInterface?.userMessageInterface)
|
|
324
|
+
break;
|
|
325
|
+
if (classifySlash(candidate.content) !== "passthrough") break;
|
|
326
|
+
if (
|
|
327
|
+
resolveVerificationSessionIntent(candidate.content).kind ===
|
|
328
|
+
"direct_setup"
|
|
329
|
+
)
|
|
330
|
+
break;
|
|
331
|
+
// Stop at the first surface-action tail; it will drain via the single-
|
|
332
|
+
// message path so its per-message surface context is preserved.
|
|
333
|
+
if (
|
|
334
|
+
candidate.activeSurfaceId !== undefined ||
|
|
335
|
+
conversation.surfaceActionRequestIds.has(candidate.requestId)
|
|
336
|
+
) {
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
i++;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const matched = i;
|
|
343
|
+
return conversation.queue.shiftN(matched);
|
|
344
|
+
}
|
|
345
|
+
|
|
231
346
|
// ── drainQueue ───────────────────────────────────────────────────────
|
|
232
347
|
|
|
233
348
|
/**
|
|
@@ -244,9 +359,26 @@ export async function drainQueue(
|
|
|
244
359
|
conversation: ProcessConversationContext,
|
|
245
360
|
reason: QueueDrainReason = "loop_complete",
|
|
246
361
|
): Promise<void> {
|
|
247
|
-
const
|
|
248
|
-
if (
|
|
362
|
+
const batch = await buildPassthroughBatch(conversation);
|
|
363
|
+
if (batch.length === 0) {
|
|
364
|
+
// Head is a slash / verification intent / empty queue. If the queue has
|
|
365
|
+
// an item the builder rejected, pop it and hand it to the single-message
|
|
366
|
+
// path — which owns slash / compact / verification-intent behavior.
|
|
367
|
+
const next = conversation.queue.shift();
|
|
368
|
+
if (!next) return;
|
|
369
|
+
return drainSingleMessage(conversation, next, reason);
|
|
370
|
+
}
|
|
371
|
+
if (batch.length === 1) {
|
|
372
|
+
return drainSingleMessage(conversation, batch[0], reason);
|
|
373
|
+
}
|
|
374
|
+
return drainBatch(conversation, batch, reason);
|
|
375
|
+
}
|
|
249
376
|
|
|
377
|
+
async function drainSingleMessage(
|
|
378
|
+
conversation: ProcessConversationContext,
|
|
379
|
+
next: QueuedMessage,
|
|
380
|
+
reason: QueueDrainReason,
|
|
381
|
+
): Promise<void> {
|
|
250
382
|
// Reset per-turn preactivation so a prior iteration (e.g. an unknown-slash
|
|
251
383
|
// from a desktop source that skips runAgentLoop) can't leak CU preactivation
|
|
252
384
|
// into the next queued message.
|
|
@@ -304,6 +436,10 @@ export async function drainQueue(
|
|
|
304
436
|
// environment context for internal turns.
|
|
305
437
|
if (next.transport) {
|
|
306
438
|
conversation.setTransportHints(buildTransportHints(next.transport));
|
|
439
|
+
// Route client-reported host env through the same capability-gated
|
|
440
|
+
// setter used by DaemonServer.applyTransportMetadata so create/reuse
|
|
441
|
+
// and queue-drain stay in sync without duplicating the gate logic.
|
|
442
|
+
conversation.applyHostEnvFromTransport(next.transport);
|
|
307
443
|
}
|
|
308
444
|
|
|
309
445
|
// Non-interactive queued messages (channel requests) must not execute tools
|
|
@@ -311,17 +447,74 @@ export async function drainQueue(
|
|
|
311
447
|
// returns false and tool execution falls back to local.
|
|
312
448
|
if (next.isInteractive === false) {
|
|
313
449
|
conversation.clearProxyAvailability();
|
|
450
|
+
// chrome-extension is non-interactive (no SSE prompter UI) but DOES have
|
|
451
|
+
// a connected client that can service host_browser_request events. The
|
|
452
|
+
// unconditional clear above turned its hostBrowserProxy off; restore it
|
|
453
|
+
// here so the queued turn can still drive the browser via CDP.
|
|
454
|
+
const drainInterfaceCtx =
|
|
455
|
+
queuedInterfaceCtx ?? conversation.getTurnInterfaceContext();
|
|
456
|
+
const drainInterface = drainInterfaceCtx?.userMessageInterface;
|
|
457
|
+
if (
|
|
458
|
+
drainInterface &&
|
|
459
|
+
!supportsHostProxy(drainInterface) &&
|
|
460
|
+
supportsHostProxy(drainInterface, "host_browser")
|
|
461
|
+
) {
|
|
462
|
+
conversation.restoreBrowserProxyAvailability();
|
|
463
|
+
}
|
|
314
464
|
} else {
|
|
315
465
|
// Restore proxy availability only for desktop-originating turns (macos)
|
|
316
466
|
// in case a prior non-interactive drain disabled it. Non-desktop interactive
|
|
317
|
-
// interfaces (CLI, Vellum) should not re-enable desktop host proxies.
|
|
467
|
+
// interfaces (CLI, Vellum) should not re-enable desktop host proxies. The
|
|
468
|
+
// chrome-extension interface only supports host_browser, not the desktop
|
|
469
|
+
// proxies or computer-use, so it is excluded by the no-arg form of
|
|
470
|
+
// supportsHostProxy (which returns false for chrome-extension).
|
|
318
471
|
const interfaceCtx =
|
|
319
472
|
queuedInterfaceCtx ?? conversation.getTurnInterfaceContext();
|
|
320
473
|
const sourceInterface = interfaceCtx?.userMessageInterface;
|
|
321
474
|
if (sourceInterface && supportsHostProxy(sourceInterface)) {
|
|
322
|
-
|
|
475
|
+
// When hostBrowserSenderOverride is set, skip the browser proxy here
|
|
476
|
+
// — restoreBrowserProxyAvailability() below will handle it with the
|
|
477
|
+
// correct registry-routed sender instead of the SSE hub emitter.
|
|
478
|
+
conversation.restoreProxyAvailability(
|
|
479
|
+
conversation.hostBrowserSenderOverride
|
|
480
|
+
? { skipBrowser: true }
|
|
481
|
+
: undefined,
|
|
482
|
+
);
|
|
323
483
|
conversation.addPreactivatedSkillId("computer-use");
|
|
324
484
|
}
|
|
485
|
+
// Tear down a stale hostBrowserProxy inherited from a prior turn on a
|
|
486
|
+
// different interface (e.g. chrome-extension installed one, then a CLI
|
|
487
|
+
// turn drains). Without this, restoreProxyAvailability() above would
|
|
488
|
+
// re-enable the proxy and getCdpClient() would route browser tools
|
|
489
|
+
// through host_browser_request and hang waiting for a client that this
|
|
490
|
+
// turn's interface can't service.
|
|
491
|
+
//
|
|
492
|
+
// Skip teardown only when BOTH conditions hold:
|
|
493
|
+
// 1. `hostBrowserSenderOverride` is set (live registry-routed sender)
|
|
494
|
+
// 2. The current turn's interface can service host_browser frames
|
|
495
|
+
// (chrome-extension or macOS).
|
|
496
|
+
// Without the interface check, queued turns from CLI/iOS/Vellum would
|
|
497
|
+
// inherit a stale override left by a prior extension-connected turn
|
|
498
|
+
// and keep the proxy alive, causing cross-interface misrouting.
|
|
499
|
+
const currentTurnCanServiceBrowser =
|
|
500
|
+
!!sourceInterface && canServiceRegistryBrowser(sourceInterface);
|
|
501
|
+
if (
|
|
502
|
+
sourceInterface &&
|
|
503
|
+
!supportsHostProxy(sourceInterface, "host_browser") &&
|
|
504
|
+
!(conversation.hostBrowserSenderOverride && currentTurnCanServiceBrowser)
|
|
505
|
+
) {
|
|
506
|
+
conversation.setHostBrowserProxy(undefined);
|
|
507
|
+
}
|
|
508
|
+
// When a macOS turn has a registry-routed sender override (active
|
|
509
|
+
// extension connection), restore the browser proxy so host_browser
|
|
510
|
+
// tools route through the extension rather than cdp-inspect/local.
|
|
511
|
+
if (
|
|
512
|
+
sourceInterface &&
|
|
513
|
+
supportsHostProxy(sourceInterface) &&
|
|
514
|
+
conversation.hostBrowserSenderOverride
|
|
515
|
+
) {
|
|
516
|
+
conversation.restoreBrowserProxyAvailability();
|
|
517
|
+
}
|
|
325
518
|
}
|
|
326
519
|
|
|
327
520
|
// Snapshot persona context at turn start so later tool turns can't pick up
|
|
@@ -597,6 +790,16 @@ export async function drainQueue(
|
|
|
597
790
|
return;
|
|
598
791
|
}
|
|
599
792
|
|
|
793
|
+
// Broadcast the user message to all hub subscribers so passive devices
|
|
794
|
+
// see the user turn before the assistant reply starts streaming.
|
|
795
|
+
next.onEvent({
|
|
796
|
+
type: "user_message_echo",
|
|
797
|
+
text: resolvedContent,
|
|
798
|
+
conversationId: conversation.conversationId,
|
|
799
|
+
messageId: userMessageId,
|
|
800
|
+
requestId: next.requestId,
|
|
801
|
+
});
|
|
802
|
+
|
|
600
803
|
// Set the active surface for the dequeued message so runAgentLoop can inject context
|
|
601
804
|
conversation.currentActiveSurfaceId = next.activeSurfaceId;
|
|
602
805
|
conversation.currentPage = next.currentPage;
|
|
@@ -668,6 +871,412 @@ export async function drainQueue(
|
|
|
668
871
|
});
|
|
669
872
|
}
|
|
670
873
|
|
|
874
|
+
// Drives a batched turn where multiple queued passthrough messages share one
|
|
875
|
+
// runAgentLoop run. Per-message dequeue events and DB persistence are
|
|
876
|
+
// preserved; the agent reply fans out to every batched client.
|
|
877
|
+
async function drainBatch(
|
|
878
|
+
conversation: ProcessConversationContext,
|
|
879
|
+
batch: QueuedMessage[],
|
|
880
|
+
reason: QueueDrainReason,
|
|
881
|
+
): Promise<void> {
|
|
882
|
+
// Head-wins: the batch-builder guarantees identical userMessageInterface
|
|
883
|
+
// across the batch; channel/transport divergence is accepted with the head's
|
|
884
|
+
// environment.
|
|
885
|
+
const head = batch[0];
|
|
886
|
+
|
|
887
|
+
// Reset per-turn preactivation so a prior iteration can't leak CU
|
|
888
|
+
// preactivation into this batched turn.
|
|
889
|
+
conversation.preactivatedSkillIds = undefined;
|
|
890
|
+
|
|
891
|
+
log.info(
|
|
892
|
+
{
|
|
893
|
+
conversationId: conversation.conversationId,
|
|
894
|
+
requestId: head.requestId,
|
|
895
|
+
reason,
|
|
896
|
+
batchSize: batch.length,
|
|
897
|
+
},
|
|
898
|
+
"Dequeuing batched messages",
|
|
899
|
+
);
|
|
900
|
+
|
|
901
|
+
const queuedTurnCtx = resolveQueuedTurnContext(
|
|
902
|
+
head,
|
|
903
|
+
conversation.getTurnChannelContext(),
|
|
904
|
+
);
|
|
905
|
+
if (queuedTurnCtx) {
|
|
906
|
+
conversation.setTurnChannelContext(queuedTurnCtx);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
const queuedInterfaceCtx = resolveQueuedTurnInterfaceContext(
|
|
910
|
+
head,
|
|
911
|
+
conversation.getTurnInterfaceContext(),
|
|
912
|
+
);
|
|
913
|
+
if (queuedInterfaceCtx) {
|
|
914
|
+
conversation.setTurnInterfaceContext(queuedInterfaceCtx);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// Apply transport hints from the head message so this batched turn uses
|
|
918
|
+
// the head's transport metadata. Tail transport divergence is accepted
|
|
919
|
+
// per the head-wins contract.
|
|
920
|
+
if (head.transport) {
|
|
921
|
+
conversation.setTransportHints(buildTransportHints(head.transport));
|
|
922
|
+
conversation.applyHostEnvFromTransport(head.transport);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// Non-interactive queued messages (channel requests) must not execute tools
|
|
926
|
+
// via the desktop host proxy. Clear proxy availability so isAvailable()
|
|
927
|
+
// returns false and tool execution falls back to local. Mirrors the
|
|
928
|
+
// single-message path exactly — sourced from `head`.
|
|
929
|
+
if (head.isInteractive === false) {
|
|
930
|
+
conversation.clearProxyAvailability();
|
|
931
|
+
const drainInterfaceCtx =
|
|
932
|
+
queuedInterfaceCtx ?? conversation.getTurnInterfaceContext();
|
|
933
|
+
const drainInterface = drainInterfaceCtx?.userMessageInterface;
|
|
934
|
+
if (
|
|
935
|
+
drainInterface &&
|
|
936
|
+
!supportsHostProxy(drainInterface) &&
|
|
937
|
+
supportsHostProxy(drainInterface, "host_browser")
|
|
938
|
+
) {
|
|
939
|
+
conversation.restoreBrowserProxyAvailability();
|
|
940
|
+
}
|
|
941
|
+
} else {
|
|
942
|
+
const interfaceCtx =
|
|
943
|
+
queuedInterfaceCtx ?? conversation.getTurnInterfaceContext();
|
|
944
|
+
const sourceInterface = interfaceCtx?.userMessageInterface;
|
|
945
|
+
if (sourceInterface && supportsHostProxy(sourceInterface)) {
|
|
946
|
+
conversation.restoreProxyAvailability(
|
|
947
|
+
conversation.hostBrowserSenderOverride
|
|
948
|
+
? { skipBrowser: true }
|
|
949
|
+
: undefined,
|
|
950
|
+
);
|
|
951
|
+
conversation.addPreactivatedSkillId("computer-use");
|
|
952
|
+
}
|
|
953
|
+
const currentTurnCanServiceBrowser =
|
|
954
|
+
!!sourceInterface && canServiceRegistryBrowser(sourceInterface);
|
|
955
|
+
if (
|
|
956
|
+
sourceInterface &&
|
|
957
|
+
!supportsHostProxy(sourceInterface, "host_browser") &&
|
|
958
|
+
!(conversation.hostBrowserSenderOverride && currentTurnCanServiceBrowser)
|
|
959
|
+
) {
|
|
960
|
+
conversation.setHostBrowserProxy(undefined);
|
|
961
|
+
}
|
|
962
|
+
if (
|
|
963
|
+
sourceInterface &&
|
|
964
|
+
supportsHostProxy(sourceInterface) &&
|
|
965
|
+
conversation.hostBrowserSenderOverride
|
|
966
|
+
) {
|
|
967
|
+
conversation.restoreBrowserProxyAvailability();
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// Snapshot persona context at turn start so later tool turns can't pick up
|
|
972
|
+
// a different actor's context if a concurrent request mutates the live fields.
|
|
973
|
+
conversation.currentTurnTrustContext = conversation.trustContext;
|
|
974
|
+
conversation.currentTurnChannelCapabilities =
|
|
975
|
+
conversation.channelCapabilities;
|
|
976
|
+
|
|
977
|
+
// Single activity-state transition for the batched turn. Per-message
|
|
978
|
+
// emissions would publish N "thinking" phase transitions to every
|
|
979
|
+
// connected SSE client (via activityVersion increments), whipsawing the
|
|
980
|
+
// client-side thinking indicator. The single-message path emits exactly
|
|
981
|
+
// one such event per turn; match it here.
|
|
982
|
+
conversation.emitActivityState(
|
|
983
|
+
"thinking",
|
|
984
|
+
"message_dequeued",
|
|
985
|
+
"assistant_turn",
|
|
986
|
+
head.requestId,
|
|
987
|
+
);
|
|
988
|
+
|
|
989
|
+
// Per-message dequeue events and persistence loop. Track the last
|
|
990
|
+
// SUCCESSFUL persist separately from the batch tail — a failed tail
|
|
991
|
+
// must not corrupt the requestId/surface context that `runAgentLoop`
|
|
992
|
+
// will tag `message_complete` / `generation_cancelled` with.
|
|
993
|
+
let lastSuccessfulRequestId: string | undefined;
|
|
994
|
+
let lastSuccessfulActiveSurfaceId: string | undefined;
|
|
995
|
+
let lastSuccessfulCurrentPage: string | undefined;
|
|
996
|
+
let lastSuccessfulContent: string | undefined;
|
|
997
|
+
let lastUserMessageId: string | undefined;
|
|
998
|
+
// Members whose persist succeeded. `fanOutOnEvent` below must only
|
|
999
|
+
// broadcast agent-loop events to these — clients whose persist failed
|
|
1000
|
+
// already received an error event and must not also receive the
|
|
1001
|
+
// assistant's streaming response for a turn that isn't theirs.
|
|
1002
|
+
const successfulBatch: QueuedMessage[] = [];
|
|
1003
|
+
for (let i = 0; i < batch.length; i++) {
|
|
1004
|
+
const qm = batch[i];
|
|
1005
|
+
qm.onEvent({
|
|
1006
|
+
type: "message_dequeued",
|
|
1007
|
+
conversationId: conversation.conversationId,
|
|
1008
|
+
requestId: qm.requestId,
|
|
1009
|
+
});
|
|
1010
|
+
conversation.traceEmitter.emit(
|
|
1011
|
+
"request_dequeued",
|
|
1012
|
+
"Message dequeued (batched)",
|
|
1013
|
+
{
|
|
1014
|
+
requestId: qm.requestId,
|
|
1015
|
+
status: "info",
|
|
1016
|
+
attributes: { reason, batchIndex: i, batchSize: batch.length },
|
|
1017
|
+
},
|
|
1018
|
+
);
|
|
1019
|
+
|
|
1020
|
+
const qmSlash = await resolveSlash(
|
|
1021
|
+
qm.content,
|
|
1022
|
+
buildSlashContext(conversation),
|
|
1023
|
+
);
|
|
1024
|
+
if (qmSlash.kind !== "passthrough") {
|
|
1025
|
+
// Defensive recovery. `buildPassthroughBatch` should make this
|
|
1026
|
+
// unreachable, but if it ever fires we must avoid stranding
|
|
1027
|
+
// per-turn state and dropping the batch tails that have already
|
|
1028
|
+
// been shifted out of the queue. Log, emit an error to the
|
|
1029
|
+
// affected client, and either recover-and-drain (head case) or
|
|
1030
|
+
// skip the tail (tail case) so the rest of the batch still runs.
|
|
1031
|
+
const invariantMessage =
|
|
1032
|
+
"Internal error: batch drain invariant violated (non-passthrough message in batch)";
|
|
1033
|
+
log.error(
|
|
1034
|
+
{
|
|
1035
|
+
conversationId: conversation.conversationId,
|
|
1036
|
+
requestId: qm.requestId,
|
|
1037
|
+
batchIndex: i,
|
|
1038
|
+
batchSize: batch.length,
|
|
1039
|
+
slashKind: qmSlash.kind,
|
|
1040
|
+
},
|
|
1041
|
+
"drainBatch invariant violated — non-passthrough message found in batch",
|
|
1042
|
+
);
|
|
1043
|
+
conversation.traceEmitter.emit("request_error", invariantMessage, {
|
|
1044
|
+
requestId: qm.requestId,
|
|
1045
|
+
status: "error",
|
|
1046
|
+
attributes: { reason: "batch_invariant_violation" },
|
|
1047
|
+
});
|
|
1048
|
+
qm.onEvent({ type: "error", message: invariantMessage });
|
|
1049
|
+
if (i === 0) {
|
|
1050
|
+
// Head invariant fired — no in-flight turn yet (the check runs
|
|
1051
|
+
// before persistUserMessage, so the head was never persisted).
|
|
1052
|
+
// Clear per-turn state and recursively drain the remaining tails,
|
|
1053
|
+
// which were already shifted out of the queue by
|
|
1054
|
+
// buildPassthroughBatch and would otherwise be stranded. Mirrors
|
|
1055
|
+
// the head persist-failure recovery below.
|
|
1056
|
+
conversation.processing = false;
|
|
1057
|
+
conversation.abortController = null;
|
|
1058
|
+
conversation.currentRequestId = undefined;
|
|
1059
|
+
conversation.preactivatedSkillIds = undefined;
|
|
1060
|
+
const remaining = batch.slice(1);
|
|
1061
|
+
if (remaining.length >= 2) {
|
|
1062
|
+
await drainBatch(conversation, remaining, reason);
|
|
1063
|
+
} else if (remaining.length === 1) {
|
|
1064
|
+
await drainSingleMessage(conversation, remaining[0], reason);
|
|
1065
|
+
} else {
|
|
1066
|
+
await drainQueue(conversation);
|
|
1067
|
+
}
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
// Tail case — processing is live, just skip this message. Loop
|
|
1071
|
+
// continues to drain any remaining tails.
|
|
1072
|
+
continue;
|
|
1073
|
+
}
|
|
1074
|
+
const qmContent = qmSlash.content;
|
|
1075
|
+
|
|
1076
|
+
try {
|
|
1077
|
+
if (i === 0) {
|
|
1078
|
+
lastUserMessageId = await conversation.persistUserMessage(
|
|
1079
|
+
qmContent,
|
|
1080
|
+
qm.attachments,
|
|
1081
|
+
qm.requestId,
|
|
1082
|
+
{ ...qm.metadata, sentAt: qm.sentAt },
|
|
1083
|
+
qm.displayContent,
|
|
1084
|
+
);
|
|
1085
|
+
} else {
|
|
1086
|
+
lastUserMessageId = await persistQueuedMessageBody(
|
|
1087
|
+
conversation,
|
|
1088
|
+
qmContent,
|
|
1089
|
+
qm.attachments,
|
|
1090
|
+
qm.requestId,
|
|
1091
|
+
{ ...qm.metadata, sentAt: qm.sentAt },
|
|
1092
|
+
qm.displayContent,
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
} catch (err) {
|
|
1096
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1097
|
+
log.error(
|
|
1098
|
+
{
|
|
1099
|
+
err,
|
|
1100
|
+
conversationId: conversation.conversationId,
|
|
1101
|
+
requestId: qm.requestId,
|
|
1102
|
+
batchIndex: i,
|
|
1103
|
+
},
|
|
1104
|
+
"Failed to persist batched queued message",
|
|
1105
|
+
);
|
|
1106
|
+
conversation.traceEmitter.emit(
|
|
1107
|
+
"request_error",
|
|
1108
|
+
`Queued message persist failed: ${message}`,
|
|
1109
|
+
{
|
|
1110
|
+
requestId: qm.requestId,
|
|
1111
|
+
status: "error",
|
|
1112
|
+
attributes: { reason: "persist_failure" },
|
|
1113
|
+
},
|
|
1114
|
+
);
|
|
1115
|
+
qm.onEvent({ type: "error", message });
|
|
1116
|
+
|
|
1117
|
+
if (i === 0) {
|
|
1118
|
+
// Head persist failed — processing is not set yet, no in-flight turn
|
|
1119
|
+
// to fan tails into. We've already shifted the tails out of the queue
|
|
1120
|
+
// as part of this batch, so if we simply called drainQueue the tails
|
|
1121
|
+
// would be stranded. Reset per-turn state and recursively drain the
|
|
1122
|
+
// remaining tails (they're still valid by the batch invariant).
|
|
1123
|
+
conversation.preactivatedSkillIds = undefined;
|
|
1124
|
+
const remaining = batch.slice(1);
|
|
1125
|
+
if (remaining.length >= 2) {
|
|
1126
|
+
await drainBatch(conversation, remaining, reason);
|
|
1127
|
+
} else if (remaining.length === 1) {
|
|
1128
|
+
await drainSingleMessage(conversation, remaining[0], reason);
|
|
1129
|
+
} else {
|
|
1130
|
+
await drainQueue(conversation);
|
|
1131
|
+
}
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
// Tail persist failed — we cannot abandon the batch without stranding
|
|
1135
|
+
// the head's in-flight turn. Processing state is already set; skip
|
|
1136
|
+
// this message and continue accumulating siblings. The emitted error
|
|
1137
|
+
// event lets the tail client see the failure. Crucially we do NOT
|
|
1138
|
+
// update lastSuccessful* here, so runAgentLoop tags completion with
|
|
1139
|
+
// the most recent successfully-persisted message's requestId.
|
|
1140
|
+
continue;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
// Broadcast the user message to all hub subscribers so passive devices
|
|
1144
|
+
// see each batched user turn before the assistant reply starts streaming.
|
|
1145
|
+
qm.onEvent({
|
|
1146
|
+
type: "user_message_echo",
|
|
1147
|
+
text: qmContent,
|
|
1148
|
+
conversationId: conversation.conversationId,
|
|
1149
|
+
messageId: lastUserMessageId,
|
|
1150
|
+
requestId: qm.requestId,
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
// Persist succeeded. Update last-successful markers so a later tail
|
|
1154
|
+
// failure won't overwrite them.
|
|
1155
|
+
lastSuccessfulRequestId = qm.requestId;
|
|
1156
|
+
lastSuccessfulActiveSurfaceId = qm.activeSurfaceId;
|
|
1157
|
+
lastSuccessfulCurrentPage = qm.currentPage;
|
|
1158
|
+
lastSuccessfulContent = qmContent;
|
|
1159
|
+
successfulBatch.push(qm);
|
|
1160
|
+
|
|
1161
|
+
// Fire-and-forget: detect notification preferences in each batched user
|
|
1162
|
+
// message and persist any that are found, mirroring drainSingleMessage.
|
|
1163
|
+
if (conversation.assistantId) {
|
|
1164
|
+
extractPreferences(qmContent)
|
|
1165
|
+
.then((result) => {
|
|
1166
|
+
if (!result.detected) return;
|
|
1167
|
+
for (const pref of result.preferences) {
|
|
1168
|
+
createPreference({
|
|
1169
|
+
preferenceText: pref.preferenceText,
|
|
1170
|
+
appliesWhen: pref.appliesWhen,
|
|
1171
|
+
priority: pref.priority,
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
log.info(
|
|
1175
|
+
{
|
|
1176
|
+
count: result.preferences.length,
|
|
1177
|
+
conversationId: conversation.conversationId,
|
|
1178
|
+
},
|
|
1179
|
+
"Persisted extracted notification preferences (batched)",
|
|
1180
|
+
);
|
|
1181
|
+
})
|
|
1182
|
+
.catch((err) => {
|
|
1183
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1184
|
+
log.warn(
|
|
1185
|
+
{ err: errMsg, conversationId: conversation.conversationId },
|
|
1186
|
+
"Background preference extraction failed (batched)",
|
|
1187
|
+
);
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// If the user hit abort mid-batch, stop persisting remaining tails.
|
|
1192
|
+
// runAgentLoop's existing abort handling will emit generation_cancelled
|
|
1193
|
+
// and clear processing state for whatever did persist.
|
|
1194
|
+
if (conversation.abortController?.signal.aborted) {
|
|
1195
|
+
log.info(
|
|
1196
|
+
{
|
|
1197
|
+
conversationId: conversation.conversationId,
|
|
1198
|
+
requestId: qm.requestId,
|
|
1199
|
+
batchIndex: i,
|
|
1200
|
+
batchSize: batch.length,
|
|
1201
|
+
},
|
|
1202
|
+
"drainBatch: abort signaled mid-batch; stopping tail persist",
|
|
1203
|
+
);
|
|
1204
|
+
break;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
if (lastUserMessageId === undefined || lastSuccessfulContent === undefined) {
|
|
1209
|
+
// Nothing persisted — either the head's invariant-violation recovery
|
|
1210
|
+
// already drained and returned, or every message failed. Head failure
|
|
1211
|
+
// has its own recovery path above; if we get here it's because a
|
|
1212
|
+
// defensive code path left us with nothing to run. Log and bail.
|
|
1213
|
+
log.error(
|
|
1214
|
+
{
|
|
1215
|
+
conversationId: conversation.conversationId,
|
|
1216
|
+
batchSize: batch.length,
|
|
1217
|
+
},
|
|
1218
|
+
"drainBatch: no messages persisted successfully; skipping runAgentLoop",
|
|
1219
|
+
);
|
|
1220
|
+
conversation.preactivatedSkillIds = undefined;
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// Tag turn-completion state with the last SUCCESSFUL persist so client-
|
|
1225
|
+
// side correlation (message_complete / generation_cancelled /
|
|
1226
|
+
// generation_handoff) surfaces a requestId that actually has a DB row.
|
|
1227
|
+
conversation.currentRequestId = lastSuccessfulRequestId;
|
|
1228
|
+
conversation.currentActiveSurfaceId = lastSuccessfulActiveSurfaceId;
|
|
1229
|
+
conversation.currentPage = lastSuccessfulCurrentPage;
|
|
1230
|
+
|
|
1231
|
+
// Broadcast agent-loop events only to members whose persist succeeded.
|
|
1232
|
+
// Members whose persist failed already received an error event in the
|
|
1233
|
+
// catch block above; sending them the assistant's streaming response
|
|
1234
|
+
// would surface a reply for a user message that isn't in their DB.
|
|
1235
|
+
const fanOutOnEvent = (msg: ServerMessage) => {
|
|
1236
|
+
for (const qm of successfulBatch) qm.onEvent(msg);
|
|
1237
|
+
};
|
|
1238
|
+
|
|
1239
|
+
const drainLoopOptions: {
|
|
1240
|
+
isInteractive?: boolean;
|
|
1241
|
+
isUserMessage?: boolean;
|
|
1242
|
+
titleText?: string;
|
|
1243
|
+
} = { isUserMessage: true };
|
|
1244
|
+
// Source interactive flag from the last successfully-persisted sibling so
|
|
1245
|
+
// a trailing failed tail doesn't flip the agent loop's interactivity.
|
|
1246
|
+
const lastSuccessfulBatchEntry =
|
|
1247
|
+
successfulBatch.length > 0
|
|
1248
|
+
? successfulBatch[successfulBatch.length - 1]
|
|
1249
|
+
: undefined;
|
|
1250
|
+
if (lastSuccessfulBatchEntry?.isInteractive !== undefined)
|
|
1251
|
+
drainLoopOptions.isInteractive = lastSuccessfulBatchEntry.isInteractive;
|
|
1252
|
+
|
|
1253
|
+
// Fire-and-forget: runAgentLoop's finally block recursively calls drainQueue
|
|
1254
|
+
// when this run completes. Mirrors drainSingleMessage.
|
|
1255
|
+
conversation
|
|
1256
|
+
.runAgentLoop(
|
|
1257
|
+
lastSuccessfulContent,
|
|
1258
|
+
lastUserMessageId,
|
|
1259
|
+
fanOutOnEvent,
|
|
1260
|
+
drainLoopOptions,
|
|
1261
|
+
)
|
|
1262
|
+
.catch((err) => {
|
|
1263
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1264
|
+
log.error(
|
|
1265
|
+
{
|
|
1266
|
+
err,
|
|
1267
|
+
conversationId: conversation.conversationId,
|
|
1268
|
+
requestId: lastSuccessfulRequestId,
|
|
1269
|
+
batchSize: batch.length,
|
|
1270
|
+
},
|
|
1271
|
+
"Error processing batched queued messages",
|
|
1272
|
+
);
|
|
1273
|
+
fanOutOnEvent({
|
|
1274
|
+
type: "error",
|
|
1275
|
+
message: `Failed to process queued messages: ${message}`,
|
|
1276
|
+
});
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
|
|
671
1280
|
// ── processMessage ───────────────────────────────────────────────────
|
|
672
1281
|
|
|
673
1282
|
/**
|