@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Route handlers for conversation messages and suggestions.
|
|
3
3
|
*/
|
|
4
|
-
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
4
|
+
import { existsSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { join, relative } from "node:path";
|
|
6
6
|
|
|
7
7
|
import { z } from "zod";
|
|
@@ -12,8 +12,10 @@ import {
|
|
|
12
12
|
createUserMessage,
|
|
13
13
|
} from "../../agent/message-types.js";
|
|
14
14
|
import {
|
|
15
|
+
canServiceRegistryBrowser,
|
|
15
16
|
CHANNEL_IDS,
|
|
16
17
|
INTERFACE_IDS,
|
|
18
|
+
type InterfaceId,
|
|
17
19
|
isInteractiveInterface,
|
|
18
20
|
parseChannelId,
|
|
19
21
|
parseInterfaceId,
|
|
@@ -21,6 +23,7 @@ import {
|
|
|
21
23
|
} from "../../channels/types.js";
|
|
22
24
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
23
25
|
import { getConfig } from "../../config/loader.js";
|
|
26
|
+
import type { Conversation } from "../../daemon/conversation.js";
|
|
24
27
|
import {
|
|
25
28
|
buildModelInfoEvent,
|
|
26
29
|
formatCompactResult,
|
|
@@ -36,14 +39,19 @@ import {
|
|
|
36
39
|
} from "../../daemon/first-greeting.js";
|
|
37
40
|
import { renderHistoryContent } from "../../daemon/handlers/shared.js";
|
|
38
41
|
import { HostBashProxy } from "../../daemon/host-bash-proxy.js";
|
|
42
|
+
import { HostBrowserProxy } from "../../daemon/host-browser-proxy.js";
|
|
39
43
|
import { HostCuProxy } from "../../daemon/host-cu-proxy.js";
|
|
40
44
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
41
45
|
import type { ServerMessage } from "../../daemon/message-protocol.js";
|
|
42
46
|
import type {
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
HostProxyTransportMetadata,
|
|
48
|
+
NonHostProxyTransportMetadata,
|
|
45
49
|
} from "../../daemon/message-types/conversations.js";
|
|
46
50
|
import type { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
|
|
51
|
+
import {
|
|
52
|
+
writeOnboardingSidecar,
|
|
53
|
+
writeRelationshipState,
|
|
54
|
+
} from "../../home/relationship-state-writer.js";
|
|
47
55
|
import * as attachmentsStore from "../../memory/attachments-store.js";
|
|
48
56
|
import {
|
|
49
57
|
createCanonicalGuardianRequest,
|
|
@@ -73,10 +81,12 @@ import { checkIngressForSecrets } from "../../security/secret-ingress.js";
|
|
|
73
81
|
import { redactSecrets } from "../../security/secret-scanner.js";
|
|
74
82
|
import { summarizeToolInput } from "../../tools/tool-input-summary.js";
|
|
75
83
|
import { getLogger } from "../../util/logger.js";
|
|
84
|
+
import { getWorkspacePromptPath } from "../../util/platform.js";
|
|
76
85
|
import { silentlyWithLog } from "../../util/silently.js";
|
|
77
86
|
import { buildAssistantEvent } from "../assistant-event.js";
|
|
78
87
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
79
88
|
import type { AuthContext } from "../auth/types.js";
|
|
89
|
+
import { getChromeExtensionRegistry } from "../chrome-extension-registry.js";
|
|
80
90
|
import { bridgeConfirmationRequestToGuardian } from "../confirmation-request-guardian-bridge.js";
|
|
81
91
|
import { routeGuardianReply } from "../guardian-reply-router.js";
|
|
82
92
|
import { healGuardianBindingDrift } from "../guardian-vellum-migration.js";
|
|
@@ -105,7 +115,7 @@ const SUGGESTION_CACHE_MAX = 100;
|
|
|
105
115
|
function collectCanonicalGuardianRequestHintIds(
|
|
106
116
|
conversationId: string,
|
|
107
117
|
sourceChannel: string,
|
|
108
|
-
conversation:
|
|
118
|
+
conversation: Conversation,
|
|
109
119
|
): string[] {
|
|
110
120
|
const requests = listPendingRequestsByConversationScope(
|
|
111
121
|
conversationId,
|
|
@@ -170,7 +180,7 @@ async function tryConsumeCanonicalGuardianReply(params: {
|
|
|
170
180
|
data: string;
|
|
171
181
|
filePath?: string;
|
|
172
182
|
}>;
|
|
173
|
-
conversation:
|
|
183
|
+
conversation: Conversation;
|
|
174
184
|
onEvent: (msg: ServerMessage) => void;
|
|
175
185
|
approvalConversationGenerator?: ApprovalConversationGenerator;
|
|
176
186
|
/** Verified actor identity from actor-token middleware. */
|
|
@@ -422,8 +432,18 @@ export function handleListMessages(
|
|
|
422
432
|
// pendingToolUses map — otherwise they render as "Unknown" tool calls.
|
|
423
433
|
const mergedMessages = mergeToolResultsIntoAssistantMessages(rawMessages);
|
|
424
434
|
|
|
435
|
+
// During streaming, all assistant turns within one agent loop accumulate
|
|
436
|
+
// on a single client-side ChatMessage (via currentAssistantMessageId).
|
|
437
|
+
// In the DB, each API turn is a separate assistant row because
|
|
438
|
+
// consolidation is deferred to compaction for prefix-cache stability.
|
|
439
|
+
// Merge consecutive assistant messages here at query time so
|
|
440
|
+
// renderHistoryContent produces the same contentOrder shape as streaming
|
|
441
|
+
// (consecutive tool refs grouped together).
|
|
442
|
+
const { messages: consolidatedMessages, mergedIdMap } =
|
|
443
|
+
mergeConsecutiveAssistantMessages(mergedMessages);
|
|
444
|
+
|
|
425
445
|
// Parse content blocks and extract text + tool calls
|
|
426
|
-
const parsed =
|
|
446
|
+
const parsed = consolidatedMessages.map((msg) => {
|
|
427
447
|
let content: unknown;
|
|
428
448
|
try {
|
|
429
449
|
content = JSON.parse(msg.content);
|
|
@@ -548,7 +568,13 @@ export function handleListMessages(
|
|
|
548
568
|
// blobs for non-image attachments (documents, audio). Then
|
|
549
569
|
// selectively fetch full data only for images so the client can
|
|
550
570
|
// generate thumbnails for inline display on history restore.
|
|
551
|
-
|
|
571
|
+
// Also query attachments for any messages that were merged into
|
|
572
|
+
// this one (consecutive assistant merge), so their attachments
|
|
573
|
+
// aren't lost before DB compaction relinks them.
|
|
574
|
+
const idsToQuery = [m.id, ...(mergedIdMap.get(m.id) ?? [])];
|
|
575
|
+
const linked = idsToQuery.flatMap((id) =>
|
|
576
|
+
attachmentsStore.getAttachmentMetadataForMessage(id),
|
|
577
|
+
);
|
|
552
578
|
if (linked.length > 0) {
|
|
553
579
|
msgAttachments = linked.map((a) => {
|
|
554
580
|
if (a.mimeType.startsWith("image/")) {
|
|
@@ -793,19 +819,163 @@ function mergeToolResultsIntoAssistantMessages(
|
|
|
793
819
|
return result;
|
|
794
820
|
}
|
|
795
821
|
|
|
822
|
+
// ── Consecutive assistant message merging ────────────────────────────
|
|
823
|
+
|
|
824
|
+
/** Parse a message's JSON content into an array of content blocks. */
|
|
825
|
+
function parseContentBlocks(content: string): unknown[] {
|
|
826
|
+
try {
|
|
827
|
+
const parsed = JSON.parse(content);
|
|
828
|
+
return Array.isArray(parsed) ? parsed : [parsed];
|
|
829
|
+
} catch (err) {
|
|
830
|
+
log.warn(
|
|
831
|
+
{ err },
|
|
832
|
+
"Failed to parse content blocks during assistant message merge",
|
|
833
|
+
);
|
|
834
|
+
return [];
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Append content blocks from a donor message onto a target block array.
|
|
840
|
+
* Parses the donor's JSON content and pushes each block into `target`.
|
|
841
|
+
*/
|
|
842
|
+
function appendContentBlocks(target: unknown[], donorContent: string): void {
|
|
843
|
+
try {
|
|
844
|
+
const parsed = JSON.parse(donorContent);
|
|
845
|
+
if (Array.isArray(parsed)) {
|
|
846
|
+
target.push(...parsed);
|
|
847
|
+
} else {
|
|
848
|
+
target.push(parsed);
|
|
849
|
+
}
|
|
850
|
+
} catch (err) {
|
|
851
|
+
log.warn(
|
|
852
|
+
{ err },
|
|
853
|
+
"Failed to parse donor content blocks during assistant message merge",
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Promote metadata fields from a donor message to the surviving message
|
|
860
|
+
* when the survivor lacks them. Currently promotes `subagentNotification`.
|
|
861
|
+
* Returns a new MessageRow if promotion occurred, otherwise the original.
|
|
862
|
+
*/
|
|
863
|
+
function promoteMetadata(survivor: MessageRow, donor: MessageRow): MessageRow {
|
|
864
|
+
if (donor.metadata && survivor.metadata) {
|
|
865
|
+
try {
|
|
866
|
+
const survivorMeta = JSON.parse(survivor.metadata);
|
|
867
|
+
const donorMeta = JSON.parse(donor.metadata);
|
|
868
|
+
if (
|
|
869
|
+
!survivorMeta.subagentNotification &&
|
|
870
|
+
donorMeta.subagentNotification
|
|
871
|
+
) {
|
|
872
|
+
survivorMeta.subagentNotification = donorMeta.subagentNotification;
|
|
873
|
+
return { ...survivor, metadata: JSON.stringify(survivorMeta) };
|
|
874
|
+
}
|
|
875
|
+
} catch (err) {
|
|
876
|
+
log.warn(
|
|
877
|
+
{ err },
|
|
878
|
+
"Failed to parse metadata during assistant message merge",
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
} else if (donor.metadata && !survivor.metadata) {
|
|
882
|
+
return { ...survivor, metadata: donor.metadata };
|
|
883
|
+
}
|
|
884
|
+
return survivor;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Merge consecutive assistant messages into a single message at query time.
|
|
889
|
+
*
|
|
890
|
+
* During streaming, all assistant turns within one agent loop accumulate on
|
|
891
|
+
* a single client-side ChatMessage. In the DB, each API turn is stored as a
|
|
892
|
+
* separate assistant row (consolidation is deferred to compaction for
|
|
893
|
+
* prefix-cache stability). This produces N separate assistant messages that
|
|
894
|
+
* the client renders as N individual bubbles — each showing "Completed 1
|
|
895
|
+
* step" instead of one grouped "Completed N steps" accordion.
|
|
896
|
+
*
|
|
897
|
+
* This function concatenates the content block arrays of consecutive
|
|
898
|
+
* assistant messages (no intervening user messages after tool-result
|
|
899
|
+
* merging) into the first message of each run. The merged messages are
|
|
900
|
+
* removed from the output. This is query-time only — the DB is not
|
|
901
|
+
* modified.
|
|
902
|
+
*
|
|
903
|
+
* The first message in each run keeps its id, createdAt, and metadata so
|
|
904
|
+
* that attachment lookups, display timestamps, and subagent notifications
|
|
905
|
+
* continue to work. Metadata from later messages in the run (e.g.
|
|
906
|
+
* subagentNotification) is preserved by promoting it to the surviving
|
|
907
|
+
* message when the surviving message has no metadata of its own for that
|
|
908
|
+
* field.
|
|
909
|
+
*/
|
|
910
|
+
function mergeConsecutiveAssistantMessages(messages: MessageRow[]): {
|
|
911
|
+
messages: MessageRow[];
|
|
912
|
+
/** Maps each surviving message ID → all original message IDs merged into it. */
|
|
913
|
+
mergedIdMap: Map<string, string[]>;
|
|
914
|
+
} {
|
|
915
|
+
const result: MessageRow[] = [];
|
|
916
|
+
// Key = index in `result`, value = accumulated content blocks.
|
|
917
|
+
const pendingMerges = new Map<number, unknown[]>();
|
|
918
|
+
// Key = index in `result`, value = IDs of messages merged into the target.
|
|
919
|
+
const mergedIds = new Map<number, string[]>();
|
|
920
|
+
|
|
921
|
+
for (const msg of messages) {
|
|
922
|
+
const lastIdx = result.length - 1;
|
|
923
|
+
const isConsecutiveAssistant =
|
|
924
|
+
msg.role === "assistant" &&
|
|
925
|
+
lastIdx >= 0 &&
|
|
926
|
+
result[lastIdx].role === "assistant";
|
|
927
|
+
|
|
928
|
+
if (!isConsecutiveAssistant) {
|
|
929
|
+
result.push(msg);
|
|
930
|
+
continue;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// Track the donor message ID.
|
|
934
|
+
let ids = mergedIds.get(lastIdx);
|
|
935
|
+
if (!ids) {
|
|
936
|
+
ids = [];
|
|
937
|
+
mergedIds.set(lastIdx, ids);
|
|
938
|
+
}
|
|
939
|
+
ids.push(msg.id);
|
|
940
|
+
|
|
941
|
+
// Lazily parse the target's content on first merge.
|
|
942
|
+
let targetContent = pendingMerges.get(lastIdx);
|
|
943
|
+
if (!targetContent) {
|
|
944
|
+
targetContent = parseContentBlocks(result[lastIdx].content);
|
|
945
|
+
pendingMerges.set(lastIdx, targetContent);
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
appendContentBlocks(targetContent, msg.content);
|
|
949
|
+
result[lastIdx] = promoteMetadata(result[lastIdx], msg);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// Write back merged content for any messages that were targets.
|
|
953
|
+
for (const [idx, content] of pendingMerges) {
|
|
954
|
+
result[idx] = { ...result[idx], content: JSON.stringify(content) };
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// Build the merged ID map keyed by surviving message ID.
|
|
958
|
+
const mergedIdMap = new Map<string, string[]>();
|
|
959
|
+
for (const [idx, ids] of mergedIds) {
|
|
960
|
+
mergedIdMap.set(result[idx].id, ids);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
return { messages: result, mergedIdMap };
|
|
964
|
+
}
|
|
965
|
+
|
|
796
966
|
/**
|
|
797
967
|
* Build an `onEvent` callback that publishes every outbound event to the
|
|
798
968
|
* assistant event hub, maintaining ordered delivery through a serial chain.
|
|
799
969
|
*
|
|
800
970
|
* Also registers pending interactions when confirmation_request,
|
|
801
|
-
* secret_request, host_bash_request,
|
|
802
|
-
* through, so standalone approval/result
|
|
803
|
-
* by requestId.
|
|
971
|
+
* secret_request, host_bash_request, host_browser_request, host_file_request,
|
|
972
|
+
* or host_cu_request events flow through, so standalone approval/result
|
|
973
|
+
* endpoints can look up the conversation by requestId.
|
|
804
974
|
*/
|
|
805
975
|
function makeHubPublisher(
|
|
806
976
|
deps: SendMessageDeps,
|
|
807
977
|
conversationId: string,
|
|
808
|
-
conversation:
|
|
978
|
+
conversation: Conversation,
|
|
809
979
|
): (msg: ServerMessage) => void {
|
|
810
980
|
let hubChain: Promise<void> = Promise.resolve();
|
|
811
981
|
return (msg: ServerMessage) => {
|
|
@@ -886,24 +1056,8 @@ function makeHubPublisher(
|
|
|
886
1056
|
conversationId,
|
|
887
1057
|
kind: "secret",
|
|
888
1058
|
});
|
|
889
|
-
} else
|
|
890
|
-
|
|
891
|
-
conversation,
|
|
892
|
-
conversationId,
|
|
893
|
-
kind: "host_bash",
|
|
894
|
-
});
|
|
895
|
-
} else if (msg.type === "host_file_request") {
|
|
896
|
-
pendingInteractions.register(msg.requestId, {
|
|
897
|
-
conversation,
|
|
898
|
-
conversationId,
|
|
899
|
-
kind: "host_file",
|
|
900
|
-
});
|
|
901
|
-
} else if (msg.type === "host_cu_request") {
|
|
902
|
-
pendingInteractions.register(msg.requestId, {
|
|
903
|
-
conversation,
|
|
904
|
-
conversationId,
|
|
905
|
-
kind: "host_cu",
|
|
906
|
-
});
|
|
1059
|
+
} else {
|
|
1060
|
+
registerHostProxyPendingInteraction(msg, conversation, conversationId);
|
|
907
1061
|
}
|
|
908
1062
|
|
|
909
1063
|
// ServerMessage is a large union; conversationId exists on most but not all variants.
|
|
@@ -932,6 +1086,202 @@ function makeHubPublisher(
|
|
|
932
1086
|
};
|
|
933
1087
|
}
|
|
934
1088
|
|
|
1089
|
+
/**
|
|
1090
|
+
* Register pending interactions for host proxy request envelopes so
|
|
1091
|
+
* standalone result endpoints can resolve by requestId.
|
|
1092
|
+
*
|
|
1093
|
+
* Returns the registered requestId when a host proxy request was registered.
|
|
1094
|
+
* Callers that route through non-hub transports (e.g. registry-routed
|
|
1095
|
+
* host_browser sends) can use this to clean up the registration if send fails.
|
|
1096
|
+
*/
|
|
1097
|
+
function registerHostProxyPendingInteraction(
|
|
1098
|
+
msg: ServerMessage,
|
|
1099
|
+
conversation: Conversation,
|
|
1100
|
+
conversationId: string,
|
|
1101
|
+
): string | undefined {
|
|
1102
|
+
if (msg.type === "host_bash_request") {
|
|
1103
|
+
pendingInteractions.register(msg.requestId, {
|
|
1104
|
+
conversation,
|
|
1105
|
+
conversationId,
|
|
1106
|
+
kind: "host_bash",
|
|
1107
|
+
});
|
|
1108
|
+
return msg.requestId;
|
|
1109
|
+
}
|
|
1110
|
+
if (msg.type === "host_browser_request") {
|
|
1111
|
+
pendingInteractions.register(msg.requestId, {
|
|
1112
|
+
conversation,
|
|
1113
|
+
conversationId,
|
|
1114
|
+
kind: "host_browser",
|
|
1115
|
+
});
|
|
1116
|
+
return msg.requestId;
|
|
1117
|
+
}
|
|
1118
|
+
if (msg.type === "host_file_request") {
|
|
1119
|
+
pendingInteractions.register(msg.requestId, {
|
|
1120
|
+
conversation,
|
|
1121
|
+
conversationId,
|
|
1122
|
+
kind: "host_file",
|
|
1123
|
+
});
|
|
1124
|
+
return msg.requestId;
|
|
1125
|
+
}
|
|
1126
|
+
if (msg.type === "host_cu_request") {
|
|
1127
|
+
pendingInteractions.register(msg.requestId, {
|
|
1128
|
+
conversation,
|
|
1129
|
+
conversationId,
|
|
1130
|
+
kind: "host_cu",
|
|
1131
|
+
});
|
|
1132
|
+
return msg.requestId;
|
|
1133
|
+
}
|
|
1134
|
+
return undefined;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* Resolve the host_browser sender function for a conversation turn.
|
|
1139
|
+
*
|
|
1140
|
+
* When the guardian has an active extension connection in the
|
|
1141
|
+
* ChromeExtensionRegistry, returns a registry-routed sender that forwards
|
|
1142
|
+
* `host_browser_request` / `host_browser_cancel` frames through the
|
|
1143
|
+
* WebSocket to the connected extension. Otherwise returns the SSE hub
|
|
1144
|
+
* emitter (`onEvent`).
|
|
1145
|
+
*
|
|
1146
|
+
* For `chrome-extension` turns the registry sender is **always** returned
|
|
1147
|
+
* regardless of the POST-time connection check. The chrome-extension
|
|
1148
|
+
* interface has no SSE consumer for `host_browser_request` frames, so
|
|
1149
|
+
* falling back to `onEvent` would cause CDP calls to stall until the proxy
|
|
1150
|
+
* timeout (30 s) instead of failing immediately at send time when the
|
|
1151
|
+
* registry throws on a missing connection.
|
|
1152
|
+
*
|
|
1153
|
+
* This helper is interface-agnostic: both chrome-extension and macOS turns
|
|
1154
|
+
* can obtain a registry-routed sender when extension connectivity exists.
|
|
1155
|
+
* The `isRegistryRouted` flag lets the caller decide whether to set
|
|
1156
|
+
* `hostBrowserSenderOverride` and whether to provision a `HostBrowserProxy`
|
|
1157
|
+
* for interfaces that don't statically support host_browser (e.g. macOS).
|
|
1158
|
+
*/
|
|
1159
|
+
function resolveHostBrowserSender(
|
|
1160
|
+
conversation: Conversation,
|
|
1161
|
+
conversationId: string,
|
|
1162
|
+
authContext: AuthContext,
|
|
1163
|
+
onEvent: (msg: ServerMessage) => void,
|
|
1164
|
+
sourceInterface: InterfaceId,
|
|
1165
|
+
): { sender: (msg: ServerMessage) => void; isRegistryRouted: boolean } {
|
|
1166
|
+
// Check whether the guardian has any active extension connection.
|
|
1167
|
+
const guardianId =
|
|
1168
|
+
conversation.trustContext?.guardianPrincipalId ??
|
|
1169
|
+
authContext.actorPrincipalId;
|
|
1170
|
+
const hasExtensionConnection =
|
|
1171
|
+
!!guardianId && !!getChromeExtensionRegistry().get(guardianId);
|
|
1172
|
+
|
|
1173
|
+
// For chrome-extension, always use the registry sender so that send-time
|
|
1174
|
+
// failures produce immediate errors rather than 30-second proxy timeouts.
|
|
1175
|
+
// The SSE hub has no extension consumer, so falling back to onEvent is
|
|
1176
|
+
// never correct for this interface.
|
|
1177
|
+
if (!hasExtensionConnection && sourceInterface !== "chrome-extension") {
|
|
1178
|
+
return { sender: onEvent, isRegistryRouted: false };
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// Build a registry-routed sender. The guardian principal ID is resolved
|
|
1182
|
+
// at send time rather than captured here so that queue-drain restores
|
|
1183
|
+
// (which re-fire this closure outside the original POST context) follow
|
|
1184
|
+
// the conversation's bound guardian identity rather than a stale
|
|
1185
|
+
// authContext.actorPrincipalId.
|
|
1186
|
+
const registrySender = (msg: ServerMessage): void => {
|
|
1187
|
+
const requestId = registerHostProxyPendingInteraction(
|
|
1188
|
+
msg,
|
|
1189
|
+
conversation,
|
|
1190
|
+
conversationId,
|
|
1191
|
+
);
|
|
1192
|
+
const gid =
|
|
1193
|
+
conversation.trustContext?.guardianPrincipalId ??
|
|
1194
|
+
authContext.actorPrincipalId;
|
|
1195
|
+
if (!gid) {
|
|
1196
|
+
if (requestId) pendingInteractions.resolve(requestId);
|
|
1197
|
+
throw new Error(
|
|
1198
|
+
"host_browser send skipped: no guardianId on AuthContext",
|
|
1199
|
+
);
|
|
1200
|
+
}
|
|
1201
|
+
const ok = getChromeExtensionRegistry().send(gid, msg);
|
|
1202
|
+
if (!ok) {
|
|
1203
|
+
if (requestId) pendingInteractions.resolve(requestId);
|
|
1204
|
+
throw new Error(
|
|
1205
|
+
`host_browser send failed: no active connection for guardian ${gid}`,
|
|
1206
|
+
);
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
|
|
1210
|
+
return { sender: registrySender, isRegistryRouted: true };
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
/**
|
|
1214
|
+
* Persist the pre-chat onboarding payload to disk.
|
|
1215
|
+
*
|
|
1216
|
+
* Runs only on the very first message of a fresh conversation. Three
|
|
1217
|
+
* artifacts are produced:
|
|
1218
|
+
*
|
|
1219
|
+
* 1. `data/onboarding-context.json` — sidecar read by the
|
|
1220
|
+
* relationship-state writer so onboarding-sourced facts survive
|
|
1221
|
+
* the pure-recomputation write cycle (every turn boundary rebuilds
|
|
1222
|
+
* facts from markdown; the sidecar is the durable source for the
|
|
1223
|
+
* tool/task/tone chips).
|
|
1224
|
+
* 2. `IDENTITY.md` / `USER.md` — persona seed files, only written
|
|
1225
|
+
* when missing so we never clobber existing content. These feed
|
|
1226
|
+
* the system prompt and the relationship-state writer's
|
|
1227
|
+
* `parseIdentity` / `parseUserName` helpers after a daemon
|
|
1228
|
+
* restart when the in-memory onboarding context is gone.
|
|
1229
|
+
* 3. `data/relationship-state.json` — kicked off fire-and-forget so
|
|
1230
|
+
* the Home page can populate immediately on first visit instead
|
|
1231
|
+
* of waiting for the first agent-turn boundary.
|
|
1232
|
+
*
|
|
1233
|
+
* Never throws: every write is guarded and logged as a warning on
|
|
1234
|
+
* failure. The route handler path must never reject because of a
|
|
1235
|
+
* best-effort persistence step.
|
|
1236
|
+
*/
|
|
1237
|
+
function persistOnboardingArtifacts(onboarding: {
|
|
1238
|
+
tools: string[];
|
|
1239
|
+
tasks: string[];
|
|
1240
|
+
tone: string;
|
|
1241
|
+
userName?: string;
|
|
1242
|
+
assistantName?: string;
|
|
1243
|
+
}): void {
|
|
1244
|
+
writeOnboardingSidecar(onboarding);
|
|
1245
|
+
|
|
1246
|
+
const assistantName = onboarding.assistantName?.trim();
|
|
1247
|
+
if (assistantName) {
|
|
1248
|
+
const identityPath = getWorkspacePromptPath("IDENTITY.md");
|
|
1249
|
+
if (!existsSync(identityPath)) {
|
|
1250
|
+
try {
|
|
1251
|
+
writeFileSync(
|
|
1252
|
+
identityPath,
|
|
1253
|
+
`# Identity\n\n- Name: ${assistantName}\n`,
|
|
1254
|
+
"utf-8",
|
|
1255
|
+
);
|
|
1256
|
+
} catch (err) {
|
|
1257
|
+
log.warn(
|
|
1258
|
+
{ err, identityPath },
|
|
1259
|
+
"Failed to seed IDENTITY.md from onboarding",
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
const userName = onboarding.userName?.trim();
|
|
1266
|
+
if (userName) {
|
|
1267
|
+
const userPath = getWorkspacePromptPath("USER.md");
|
|
1268
|
+
if (!existsSync(userPath)) {
|
|
1269
|
+
try {
|
|
1270
|
+
writeFileSync(userPath, `# User\n\n- Name: ${userName}\n`, "utf-8");
|
|
1271
|
+
} catch (err) {
|
|
1272
|
+
log.warn({ err, userPath }, "Failed to seed USER.md from onboarding");
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
void writeRelationshipState().catch((err) => {
|
|
1278
|
+
log.warn(
|
|
1279
|
+
{ err },
|
|
1280
|
+
"Failed to kick off relationship-state write after onboarding",
|
|
1281
|
+
);
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
|
|
935
1285
|
export async function handleSendMessage(
|
|
936
1286
|
req: Request,
|
|
937
1287
|
deps: {
|
|
@@ -952,6 +1302,13 @@ export async function handleSendMessage(
|
|
|
952
1302
|
bypassSecretCheck?: boolean;
|
|
953
1303
|
hostHomeDir?: string;
|
|
954
1304
|
hostUsername?: string;
|
|
1305
|
+
onboarding?: {
|
|
1306
|
+
tools: string[];
|
|
1307
|
+
tasks: string[];
|
|
1308
|
+
tone: string;
|
|
1309
|
+
userName?: string;
|
|
1310
|
+
assistantName?: string;
|
|
1311
|
+
};
|
|
955
1312
|
};
|
|
956
1313
|
|
|
957
1314
|
const { conversationKey, content, attachmentIds } = body;
|
|
@@ -1054,28 +1411,58 @@ export async function handleSendMessage(
|
|
|
1054
1411
|
const mapping = getOrCreateConversation(resolvedConversationKey, {
|
|
1055
1412
|
conversationType,
|
|
1056
1413
|
});
|
|
1414
|
+
|
|
1057
1415
|
const smDeps = deps.sendMessageDeps;
|
|
1058
1416
|
|
|
1417
|
+
// Notify all connected clients that the conversation list changed when a
|
|
1418
|
+
// new standard conversation is created so sidebars can refresh.
|
|
1419
|
+
if (mapping.created && mapping.conversationType === "standard") {
|
|
1420
|
+
smDeps.assistantEventHub
|
|
1421
|
+
.publish(
|
|
1422
|
+
buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
|
|
1423
|
+
type: "conversation_list_invalidated",
|
|
1424
|
+
reason: "created",
|
|
1425
|
+
}),
|
|
1426
|
+
)
|
|
1427
|
+
.catch((err) => {
|
|
1428
|
+
log.warn({ err }, "Failed to publish conversation_list_invalidated");
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1059
1432
|
// Build transport metadata from the request so the daemon can inject
|
|
1060
1433
|
// host environment hints (home directory, username) into the LLM context.
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1434
|
+
// The `supportsHostProxy` type predicate narrows `sourceInterface` to
|
|
1435
|
+
// `HostProxyInterfaceId` in the truthy branch, which is exactly the
|
|
1436
|
+
// discriminant the `HostProxyTransportMetadata` variant expects — so the
|
|
1437
|
+
// construction site stays in lock-step with the runtime capability gate.
|
|
1438
|
+
const transport = supportsHostProxy(sourceInterface)
|
|
1439
|
+
? ({
|
|
1440
|
+
channelId: sourceChannel,
|
|
1441
|
+
interfaceId: sourceInterface,
|
|
1442
|
+
hostHomeDir: body.hostHomeDir,
|
|
1443
|
+
hostUsername: body.hostUsername,
|
|
1444
|
+
} satisfies HostProxyTransportMetadata)
|
|
1445
|
+
: ({
|
|
1446
|
+
channelId: sourceChannel,
|
|
1447
|
+
interfaceId: sourceInterface,
|
|
1448
|
+
} satisfies NonHostProxyTransportMetadata);
|
|
1073
1449
|
|
|
1074
1450
|
const conversation = await smDeps.getOrCreateConversation(
|
|
1075
1451
|
mapping.conversationId,
|
|
1076
1452
|
{ transport },
|
|
1077
1453
|
);
|
|
1078
1454
|
|
|
1455
|
+
// Store pre-chat onboarding context on the conversation when this is the
|
|
1456
|
+
// very first message (no prior messages loaded). Also persist the
|
|
1457
|
+
// onboarding selections so the Home page shows onboarding-sourced
|
|
1458
|
+
// chips immediately, and seed IDENTITY.md / USER.md so subsequent
|
|
1459
|
+
// turn-boundary recomputes of relationship-state have a stable
|
|
1460
|
+
// persona source beyond the in-memory conversation object.
|
|
1461
|
+
if (body.onboarding && conversation.messages.length === 0) {
|
|
1462
|
+
conversation.setOnboardingContext(body.onboarding);
|
|
1463
|
+
persistOnboardingArtifacts(body.onboarding);
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1079
1466
|
// Resolve guardian context from the AuthContext's actorPrincipalId.
|
|
1080
1467
|
// The JWT-verified principal is used as the sender identity through
|
|
1081
1468
|
// the same trust resolution pipeline that channel ingress uses.
|
|
@@ -1139,12 +1526,13 @@ export async function handleSendMessage(
|
|
|
1139
1526
|
conversation,
|
|
1140
1527
|
);
|
|
1141
1528
|
const isInteractive = isInteractiveInterface(sourceInterface);
|
|
1142
|
-
// Only create
|
|
1143
|
-
//
|
|
1144
|
-
//
|
|
1529
|
+
// Only create each host proxy for interfaces that support the matching
|
|
1530
|
+
// capability. macOS supports all four; the chrome-extension interface only
|
|
1531
|
+
// supports host_browser. Non-desktop conversations (CLI, channels, headless)
|
|
1532
|
+
// fall back to local execution.
|
|
1145
1533
|
// Set the proxy BEFORE updateClient so updateClient's call to
|
|
1146
1534
|
// hostBashProxy.updateSender targets the correct (new) proxy.
|
|
1147
|
-
if (supportsHostProxy(sourceInterface)) {
|
|
1535
|
+
if (supportsHostProxy(sourceInterface, "host_bash")) {
|
|
1148
1536
|
// Reuse the existing proxy if the conversation is actively processing a
|
|
1149
1537
|
// host bash request to avoid orphaning in-flight requests.
|
|
1150
1538
|
if (!conversation.isProcessing() || !conversation.hostBashProxy) {
|
|
@@ -1153,12 +1541,70 @@ export async function handleSendMessage(
|
|
|
1153
1541
|
});
|
|
1154
1542
|
conversation.setHostBashProxy(proxy);
|
|
1155
1543
|
}
|
|
1544
|
+
} else if (!conversation.isProcessing()) {
|
|
1545
|
+
conversation.setHostBashProxy(undefined);
|
|
1546
|
+
}
|
|
1547
|
+
// Resolve the host_browser sender — registry-routed when the guardian has
|
|
1548
|
+
// an active extension connection, SSE hub otherwise. This applies to both
|
|
1549
|
+
// chrome-extension and macOS interfaces so that macOS turns can route
|
|
1550
|
+
// browser automation through the user's real Chrome session when available.
|
|
1551
|
+
const { sender: browserProxySendToClient, isRegistryRouted } =
|
|
1552
|
+
resolveHostBrowserSender(
|
|
1553
|
+
conversation,
|
|
1554
|
+
mapping.conversationId,
|
|
1555
|
+
authContext,
|
|
1556
|
+
onEvent,
|
|
1557
|
+
sourceInterface,
|
|
1558
|
+
);
|
|
1559
|
+
|
|
1560
|
+
// Stash the registry-routed sender on the conversation so queue-drain
|
|
1561
|
+
// restores (which run outside of conversation-routes.ts and only have
|
|
1562
|
+
// access to `sendToClient`) can preserve it when calling
|
|
1563
|
+
// `restoreBrowserProxyAvailability()`. The override is set when the
|
|
1564
|
+
// sender is registry-routed (regardless of interface) and cleared when
|
|
1565
|
+
// the SSE hub sender is used, so the drain path always restores the
|
|
1566
|
+
// correct transport.
|
|
1567
|
+
if (isRegistryRouted) {
|
|
1568
|
+
conversation.hostBrowserSenderOverride = browserProxySendToClient;
|
|
1569
|
+
} else {
|
|
1570
|
+
conversation.hostBrowserSenderOverride = undefined;
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
// Provision the host browser proxy. For interfaces that natively support
|
|
1574
|
+
// host_browser (chrome-extension), always provision it. For macOS, the
|
|
1575
|
+
// static capability check returns false (supportsHostProxy("macos",
|
|
1576
|
+
// "host_browser") === false) because the extension isn't guaranteed to be
|
|
1577
|
+
// attached — but when the registry confirms an active extension
|
|
1578
|
+
// connection, we provision the proxy anyway so macOS turns can drive the
|
|
1579
|
+
// user's real Chrome session. When no extension is connected, macOS skips
|
|
1580
|
+
// provisioning and browser tools fall through to cdp-inspect/local.
|
|
1581
|
+
const shouldProvisionBrowserProxy =
|
|
1582
|
+
supportsHostProxy(sourceInterface, "host_browser") ||
|
|
1583
|
+
(canServiceRegistryBrowser(sourceInterface) && isRegistryRouted);
|
|
1584
|
+
if (shouldProvisionBrowserProxy) {
|
|
1585
|
+
if (!conversation.isProcessing() || !conversation.hostBrowserProxy) {
|
|
1586
|
+
const browserProxy = new HostBrowserProxy(
|
|
1587
|
+
browserProxySendToClient,
|
|
1588
|
+
(requestId) => {
|
|
1589
|
+
pendingInteractions.resolve(requestId);
|
|
1590
|
+
},
|
|
1591
|
+
);
|
|
1592
|
+
conversation.setHostBrowserProxy(browserProxy);
|
|
1593
|
+
}
|
|
1594
|
+
} else if (!conversation.isProcessing()) {
|
|
1595
|
+
conversation.setHostBrowserProxy(undefined);
|
|
1596
|
+
}
|
|
1597
|
+
if (supportsHostProxy(sourceInterface, "host_file")) {
|
|
1156
1598
|
if (!conversation.isProcessing() || !conversation.hostFileProxy) {
|
|
1157
1599
|
const fileProxy = new HostFileProxy(onEvent, (requestId) => {
|
|
1158
1600
|
pendingInteractions.resolve(requestId);
|
|
1159
1601
|
});
|
|
1160
1602
|
conversation.setHostFileProxy(fileProxy);
|
|
1161
1603
|
}
|
|
1604
|
+
} else if (!conversation.isProcessing()) {
|
|
1605
|
+
conversation.setHostFileProxy(undefined);
|
|
1606
|
+
}
|
|
1607
|
+
if (supportsHostProxy(sourceInterface, "host_cu")) {
|
|
1162
1608
|
if (!conversation.isProcessing() || !conversation.hostCuProxy) {
|
|
1163
1609
|
const cuProxy = new HostCuProxy(onEvent, (requestId) => {
|
|
1164
1610
|
pendingInteractions.resolve(requestId);
|
|
@@ -1172,19 +1618,40 @@ export async function handleSendMessage(
|
|
|
1172
1618
|
conversation.addPreactivatedSkillId("computer-use");
|
|
1173
1619
|
}
|
|
1174
1620
|
} else if (!conversation.isProcessing()) {
|
|
1175
|
-
conversation.setHostBashProxy(undefined);
|
|
1176
|
-
conversation.setHostFileProxy(undefined);
|
|
1177
1621
|
conversation.setHostCuProxy(undefined);
|
|
1178
1622
|
}
|
|
1179
1623
|
// Wire sendToClient to the SSE hub so all subsystems can reach the HTTP client.
|
|
1180
1624
|
// Called after setHostBashProxy so updateSender targets the current proxy.
|
|
1181
1625
|
// When proxies are preserved during an active turn (non-desktop request while
|
|
1182
|
-
// processing), skip updating proxy senders to avoid degrading them.
|
|
1626
|
+
// processing), skip updating proxy senders to avoid degrading them. The gate
|
|
1627
|
+
// matches the host_bash capability because the legacy "reject send during
|
|
1628
|
+
// host bash" flow is what this is really protecting.
|
|
1183
1629
|
const preservingProxies =
|
|
1184
|
-
conversation.isProcessing() &&
|
|
1630
|
+
conversation.isProcessing() &&
|
|
1631
|
+
!supportsHostProxy(sourceInterface, "host_bash");
|
|
1632
|
+
// hasNoClient must remain `!isInteractive` so downstream tool gating
|
|
1633
|
+
// (`isToolActiveForContext` for HOST_TOOL_NAMES, `createToolExecutor`'s
|
|
1634
|
+
// `isInteractive: !ctx.hasNoClient`) keeps host_bash/host_file/host_cu
|
|
1635
|
+
// tools gated for non-desktop interfaces. The chrome-extension interface
|
|
1636
|
+
// is non-interactive (no SSE prompter UI) but still has a connected client
|
|
1637
|
+
// that can service host_browser_request events; we restore that single
|
|
1638
|
+
// proxy explicitly below without relaxing `hasNoClient`.
|
|
1185
1639
|
conversation.updateClient(onEvent, !isInteractive, {
|
|
1186
1640
|
skipProxySenderUpdate: preservingProxies,
|
|
1187
1641
|
});
|
|
1642
|
+
// Re-enable the browser proxy for turns that provisioned one. This covers:
|
|
1643
|
+
// - chrome-extension: natively supports host_browser (non-interactive but
|
|
1644
|
+
// has a connected client for host_browser_request events)
|
|
1645
|
+
// - macOS with extension: provisioned above when isRegistryRouted is true
|
|
1646
|
+
//
|
|
1647
|
+
// The helper bypasses the `hasNoClient` gate so chrome-extension turns can
|
|
1648
|
+
// drive the browser via CDP without leaking host_bash/host_file tool
|
|
1649
|
+
// availability. It reads `hostBrowserSenderOverride` (set above when
|
|
1650
|
+
// registry-routed) and applies the correct sender — including after
|
|
1651
|
+
// queue-drain restores run from conversation-process.ts.
|
|
1652
|
+
if (shouldProvisionBrowserProxy) {
|
|
1653
|
+
conversation.restoreBrowserProxyAvailability?.();
|
|
1654
|
+
}
|
|
1188
1655
|
|
|
1189
1656
|
// ── Canned first-greeting fast path ──
|
|
1190
1657
|
// On a completely fresh workspace, skip LLM inference for the macOS
|
|
@@ -1248,6 +1715,12 @@ export async function handleSendMessage(
|
|
|
1248
1715
|
// fast path) so the HTTP response reaches the client before SSE
|
|
1249
1716
|
// events arrive.
|
|
1250
1717
|
setTimeout(() => {
|
|
1718
|
+
onEvent({
|
|
1719
|
+
type: "user_message_echo",
|
|
1720
|
+
text: rawContent,
|
|
1721
|
+
conversationId,
|
|
1722
|
+
messageId: persisted.id,
|
|
1723
|
+
});
|
|
1251
1724
|
onEvent({ type: "assistant_text_delta", text: cannedGreeting });
|
|
1252
1725
|
onEvent({ type: "message_complete", conversationId });
|
|
1253
1726
|
conversation.processing = false;
|
|
@@ -1541,6 +2014,12 @@ export async function handleSendMessage(
|
|
|
1541
2014
|
const conversationId = mapping.conversationId;
|
|
1542
2015
|
const message = slashResult.message;
|
|
1543
2016
|
setTimeout(() => {
|
|
2017
|
+
onEvent({
|
|
2018
|
+
type: "user_message_echo",
|
|
2019
|
+
text: rawContent,
|
|
2020
|
+
conversationId,
|
|
2021
|
+
messageId: persisted.id,
|
|
2022
|
+
});
|
|
1544
2023
|
if (modelInfoEvent) {
|
|
1545
2024
|
onEvent(modelInfoEvent);
|
|
1546
2025
|
}
|
|
@@ -1567,80 +2046,88 @@ export async function handleSendMessage(
|
|
|
1567
2046
|
|
|
1568
2047
|
if (slashResult.kind === "compact") {
|
|
1569
2048
|
conversation.processing = true;
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
);
|
|
1587
|
-
conversation.getMessages().push(cleanMsg);
|
|
2049
|
+
const provenance = provenanceFromTrustContext(conversation.trustContext);
|
|
2050
|
+
const channelMeta = {
|
|
2051
|
+
...provenance,
|
|
2052
|
+
userMessageChannel: sourceChannel,
|
|
2053
|
+
assistantMessageChannel: sourceChannel,
|
|
2054
|
+
userMessageInterface: sourceInterface,
|
|
2055
|
+
assistantMessageInterface: sourceInterface,
|
|
2056
|
+
};
|
|
2057
|
+
const cleanMsg = createUserMessage(rawContent, attachments);
|
|
2058
|
+
const persisted = await addMessage(
|
|
2059
|
+
mapping.conversationId,
|
|
2060
|
+
"user",
|
|
2061
|
+
JSON.stringify(cleanMsg.content),
|
|
2062
|
+
channelMeta,
|
|
2063
|
+
);
|
|
2064
|
+
conversation.getMessages().push(cleanMsg);
|
|
1588
2065
|
|
|
1589
|
-
|
|
1590
|
-
"thinking",
|
|
1591
|
-
"context_compacting",
|
|
1592
|
-
"assistant_turn",
|
|
1593
|
-
);
|
|
1594
|
-
const result = await conversation.forceCompact();
|
|
1595
|
-
const responseText = formatCompactResult(result);
|
|
2066
|
+
const conversationId = mapping.conversationId;
|
|
1596
2067
|
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
const response = Response.json(
|
|
1607
|
-
{
|
|
1608
|
-
accepted: true,
|
|
2068
|
+
// Fire-and-forget: return 202 immediately, run compaction async.
|
|
2069
|
+
// forceCompact() makes an LLM call that can exceed the client's
|
|
2070
|
+
// HTTP timeout on large contexts, causing a false "Failed to send".
|
|
2071
|
+
(async () => {
|
|
2072
|
+
try {
|
|
2073
|
+
onEvent({
|
|
2074
|
+
type: "user_message_echo",
|
|
2075
|
+
text: rawContent,
|
|
2076
|
+
conversationId,
|
|
1609
2077
|
messageId: persisted.id,
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
2078
|
+
});
|
|
2079
|
+
conversation.emitActivityState(
|
|
2080
|
+
"thinking",
|
|
2081
|
+
"context_compacting",
|
|
2082
|
+
"assistant_turn",
|
|
2083
|
+
);
|
|
2084
|
+
const result = await conversation.forceCompact();
|
|
2085
|
+
const responseText = formatCompactResult(result);
|
|
2086
|
+
|
|
2087
|
+
const assistantMsg = createAssistantMessage(responseText);
|
|
2088
|
+
await addMessage(
|
|
2089
|
+
conversationId,
|
|
2090
|
+
"assistant",
|
|
2091
|
+
JSON.stringify(assistantMsg.content),
|
|
2092
|
+
channelMeta,
|
|
2093
|
+
);
|
|
2094
|
+
conversation.getMessages().push(assistantMsg);
|
|
1614
2095
|
|
|
1615
|
-
const conversationId = mapping.conversationId;
|
|
1616
|
-
setTimeout(() => {
|
|
1617
2096
|
onEvent({ type: "assistant_text_delta", text: responseText });
|
|
2097
|
+
onEvent({ type: "message_complete", conversationId });
|
|
2098
|
+
} catch (err) {
|
|
2099
|
+
log.error({ err, conversationId }, "Compact command failed");
|
|
1618
2100
|
onEvent({
|
|
1619
|
-
type: "
|
|
2101
|
+
type: "conversation_error",
|
|
1620
2102
|
conversationId,
|
|
2103
|
+
code: "UNKNOWN",
|
|
2104
|
+
userMessage: `Compaction failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2105
|
+
retryable: true,
|
|
1621
2106
|
});
|
|
2107
|
+
} finally {
|
|
1622
2108
|
conversation.processing = false;
|
|
1623
2109
|
silentlyWithLog(
|
|
1624
2110
|
conversation.drainQueue(),
|
|
1625
2111
|
"compact-command queue drain",
|
|
1626
2112
|
);
|
|
1627
|
-
}, 0);
|
|
1628
|
-
|
|
1629
|
-
cleanupDeferred = true;
|
|
1630
|
-
return response;
|
|
1631
|
-
} finally {
|
|
1632
|
-
if (!cleanupDeferred && conversation.processing) {
|
|
1633
|
-
conversation.processing = false;
|
|
1634
|
-
silentlyWithLog(conversation.drainQueue(), "error-path queue drain");
|
|
1635
2113
|
}
|
|
1636
|
-
}
|
|
2114
|
+
})();
|
|
2115
|
+
|
|
2116
|
+
return Response.json(
|
|
2117
|
+
{
|
|
2118
|
+
accepted: true,
|
|
2119
|
+
messageId: persisted.id,
|
|
2120
|
+
conversationId,
|
|
2121
|
+
},
|
|
2122
|
+
{ status: 202 },
|
|
2123
|
+
);
|
|
1637
2124
|
}
|
|
1638
2125
|
|
|
1639
2126
|
const resolvedContent = slashResult.content;
|
|
1640
2127
|
|
|
2128
|
+
const requestId = crypto.randomUUID();
|
|
1641
2129
|
let messageId: string;
|
|
1642
2130
|
try {
|
|
1643
|
-
const requestId = crypto.randomUUID();
|
|
1644
2131
|
messageId = await conversation.persistUserMessage(
|
|
1645
2132
|
resolvedContent,
|
|
1646
2133
|
attachments,
|
|
@@ -1651,6 +2138,14 @@ export async function handleSendMessage(
|
|
|
1651
2138
|
throw err;
|
|
1652
2139
|
}
|
|
1653
2140
|
|
|
2141
|
+
onEvent({
|
|
2142
|
+
type: "user_message_echo",
|
|
2143
|
+
text: resolvedContent,
|
|
2144
|
+
conversationId: mapping.conversationId,
|
|
2145
|
+
messageId,
|
|
2146
|
+
requestId,
|
|
2147
|
+
});
|
|
2148
|
+
|
|
1654
2149
|
// Fire-and-forget the agent loop; events flow to the hub via onEvent.
|
|
1655
2150
|
conversation
|
|
1656
2151
|
.runAgentLoop(resolvedContent, messageId, onEvent, {
|