@vellumai/assistant 0.6.3 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +273 -10
- package/Dockerfile +2 -3
- package/bun.lock +5 -13
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/stt-provider-onboarding.md +120 -0
- package/knip.json +12 -2
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +3 -3
- package/openapi.yaml +982 -72
- package/package.json +4 -6
- package/scripts/generate-openapi.ts +0 -1
- package/scripts/test.sh +73 -18
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop.test.ts +123 -0
- package/src/__tests__/anthropic-provider.test.ts +263 -10
- package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
- package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
- package/src/__tests__/browser-fill-credential.test.ts +11 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/browser-skill-endstate.test.ts +31 -7
- package/src/__tests__/btw-routes.test.ts +7 -0
- package/src/__tests__/call-controller.test.ts +581 -20
- package/src/__tests__/catalog-files.test.ts +138 -0
- package/src/__tests__/channel-invite-transport.test.ts +2 -2
- package/src/__tests__/channel-readiness-routes.test.ts +16 -20
- package/src/__tests__/channel-readiness-service.test.ts +12 -7
- package/src/__tests__/checker.test.ts +157 -10
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/config-analysis.test.ts +100 -0
- package/src/__tests__/config-schema.test.ts +1013 -66
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +43 -8
- package/src/__tests__/contact-store-user-file.test.ts +512 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-window-manager.test.ts +88 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +98 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +135 -0
- package/src/__tests__/conversation-error.test.ts +70 -0
- package/src/__tests__/conversation-history-web-search.test.ts +11 -4
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +901 -60
- package/src/__tests__/conversation-routes-disk-view.test.ts +270 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +55 -0
- package/src/__tests__/conversation-skill-tools.test.ts +7 -4
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +89 -18
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/credential-vault-unit.test.ts +379 -3
- package/src/__tests__/credentials-cli.test.ts +40 -16
- package/src/__tests__/cross-provider-web-search.test.ts +146 -35
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
- package/src/__tests__/email-html-renderer.test.ts +71 -0
- package/src/__tests__/email-invite-adapter.test.ts +36 -32
- package/src/__tests__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +75 -8
- package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +64 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
- package/src/__tests__/gmail-archive-gate.test.ts +246 -0
- package/src/__tests__/gmail-preferences.test.ts +117 -0
- package/src/__tests__/headless-browser-interactions.test.ts +43 -0
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +142 -5
- package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
- package/src/__tests__/heartbeat-service.test.ts +70 -17
- package/src/__tests__/home-state-routes.test.ts +162 -0
- package/src/__tests__/host-bash-proxy.test.ts +0 -5
- package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
- package/src/__tests__/host-cu-proxy.test.ts +0 -5
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/llm-context-normalization.test.ts +488 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/media-stream-output.test.ts +555 -0
- package/src/__tests__/media-stream-parser.test.ts +374 -0
- package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
- package/src/__tests__/media-stream-stt-session.test.ts +588 -0
- package/src/__tests__/media-turn-detector.test.ts +440 -0
- package/src/__tests__/message-queue.test.ts +125 -0
- package/src/__tests__/migration-export-http.test.ts +6 -6
- package/src/__tests__/migration-import-commit-http.test.ts +8 -6
- package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +151 -0
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +2 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
- package/src/__tests__/oauth-providers-routes.test.ts +2 -0
- package/src/__tests__/oauth-store.test.ts +85 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +249 -6
- package/src/__tests__/onboarding-template-contract.test.ts +6 -13
- package/src/__tests__/openai-provider.test.ts +176 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1105 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outlook-unsubscribe.test.ts +31 -2
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +174 -0
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
- package/src/__tests__/relationship-state-contract.test.ts +175 -0
- package/src/__tests__/relay-server.test.ts +423 -5
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-scanner-executor.test.ts +4 -0
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +5 -1
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +49 -0
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
- package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
- package/src/__tests__/skills.test.ts +5 -2
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +564 -1
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/system-prompt.test.ts +112 -26
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +18 -7
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +33 -24
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +345 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
- package/src/__tests__/twilio-routes.test.ts +376 -0
- package/src/__tests__/unicode.test.ts +293 -0
- package/src/__tests__/update-bulletin-format.test.ts +59 -0
- package/src/__tests__/update-bulletin.test.ts +206 -5
- package/src/__tests__/usage-routes.test.ts +25 -4
- package/src/__tests__/user-reference.test.ts +46 -61
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
- package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
- package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
- package/src/__tests__/workspace-migration-meets.test.ts +244 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
- package/src/__tests__/workspace-policy.test.ts +2 -0
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +43 -3
- package/src/backup/__tests__/backup-key.test.ts +152 -0
- package/src/backup/__tests__/backup-worker.test.ts +767 -0
- package/src/backup/__tests__/list-snapshots.test.ts +87 -0
- package/src/backup/__tests__/local-writer.test.ts +218 -0
- package/src/backup/__tests__/offsite-writer.test.ts +641 -0
- package/src/backup/__tests__/paths.test.ts +300 -0
- package/src/backup/__tests__/restore.test.ts +498 -0
- package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
- package/src/backup/__tests__/stream-crypt.test.ts +228 -0
- package/src/backup/backup-key.ts +137 -0
- package/src/backup/backup-worker.ts +459 -0
- package/src/backup/list-snapshots.ts +147 -0
- package/src/backup/local-writer.ts +133 -0
- package/src/backup/offsite-writer.ts +222 -0
- package/src/backup/paths.ts +226 -0
- package/src/backup/restore.ts +322 -0
- package/src/backup/snapshot-lock.ts +431 -0
- package/src/backup/stream-crypt.ts +263 -0
- package/src/bundler/package-resolver.ts +4 -0
- package/src/calls/audio-store.ts +11 -5
- package/src/calls/call-controller.ts +226 -71
- package/src/calls/call-domain.ts +9 -0
- package/src/calls/call-speech-output.ts +190 -0
- package/src/calls/call-transport.ts +77 -0
- package/src/calls/media-stream-audio-transcode.ts +173 -0
- package/src/calls/media-stream-output.ts +660 -0
- package/src/calls/media-stream-parser.ts +300 -0
- package/src/calls/media-stream-protocol.ts +166 -0
- package/src/calls/media-stream-server.ts +592 -0
- package/src/calls/media-stream-stt-session.ts +460 -0
- package/src/calls/media-turn-detector.ts +230 -0
- package/src/calls/relay-server.ts +90 -75
- package/src/calls/resolve-call-tts-provider.ts +136 -0
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +161 -0
- package/src/calls/tts-text-sanitizer.ts +32 -16
- package/src/calls/twilio-routes.ts +281 -17
- package/src/calls/voice-quality.ts +78 -35
- package/src/calls/voice-session-bridge.ts +8 -1
- package/src/channels/types.ts +16 -0
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
- package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
- package/src/cli/commands/__tests__/email-download.test.ts +16 -1
- package/src/cli/commands/__tests__/email-list.test.ts +22 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +37 -4
- package/src/cli/commands/__tests__/email-status.test.ts +5 -1
- package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/conversations.ts +77 -0
- package/src/cli/commands/credentials.ts +0 -1
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +255 -3
- package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +15 -0
- package/src/cli/commands/oauth/shared.ts +2 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -9
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
- package/src/cli/program.ts +30 -4
- package/src/config/__tests__/backup-schema.test.ts +134 -0
- package/src/config/assistant-feature-flags.ts +61 -62
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
- package/src/config/bundled-skills/browser/SKILL.md +30 -5
- package/src/config/bundled-skills/browser/TOOLS.json +123 -0
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
- package/src/config/bundled-skills/contacts/SKILL.md +2 -2
- package/src/config/bundled-skills/gmail/SKILL.md +53 -7
- package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
- package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/outlook/SKILL.md +2 -2
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
- package/src/config/bundled-skills/slack/SKILL.md +1 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
- package/src/config/bundled-tool-registry.ts +8 -0
- package/src/config/env-registry.ts +24 -0
- package/src/config/env.ts +34 -10
- package/src/config/feature-flag-registry.json +46 -14
- package/src/config/loader.ts +26 -12
- package/src/config/schema.ts +35 -10
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +51 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -26
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +47 -7
- package/src/config/schemas/heartbeat.ts +27 -5
- package/src/config/schemas/host-browser.ts +47 -1
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/services.ts +44 -0
- package/src/config/schemas/stt.ts +59 -0
- package/src/config/schemas/tts.ts +230 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/skills.ts +4 -0
- package/src/config/types.ts +4 -0
- package/src/contacts/contact-store.ts +56 -11
- package/src/contacts/contacts-write.ts +38 -1
- package/src/context/post-turn-tool-result-truncation.ts +3 -2
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +45 -12
- package/src/credential-execution/executable-discovery.ts +12 -2
- package/src/credential-execution/process-manager.ts +33 -2
- package/src/credential-health/credential-health-service.ts +366 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/config-watcher.ts +99 -5
- package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
- package/src/daemon/conversation-agent-loop.ts +101 -24
- package/src/daemon/conversation-error.ts +11 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +59 -9
- package/src/daemon/conversation-messaging.ts +37 -3
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +581 -19
- package/src/daemon/conversation-queue-manager.ts +24 -0
- package/src/daemon/conversation-runtime-assembly.ts +11 -1
- package/src/daemon/conversation-slash.ts +36 -0
- package/src/daemon/conversation-surfaces.ts +94 -4
- package/src/daemon/conversation-tool-setup.ts +25 -0
- package/src/daemon/conversation-usage.ts +7 -4
- package/src/daemon/conversation.ts +86 -28
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +4 -1
- package/src/daemon/handlers/shared.ts +22 -0
- package/src/daemon/handlers/skills.ts +321 -77
- package/src/daemon/host-browser-proxy.ts +2 -1
- package/src/daemon/lifecycle.ts +122 -25
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/conversations.ts +34 -1
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +14 -0
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +16 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/server.ts +347 -2
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +9 -0
- package/src/email/html-renderer.ts +76 -0
- package/src/heartbeat/heartbeat-service.ts +93 -7
- package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
- package/src/home/__tests__/emit-feed-event.test.ts +169 -0
- package/src/home/__tests__/feed-scheduler.test.ts +194 -0
- package/src/home/__tests__/feed-types.test.ts +275 -0
- package/src/home/__tests__/feed-writer.test.ts +688 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
- package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
- package/src/home/__tests__/progress-formula.test.ts +213 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
- package/src/home/__tests__/rollup-producer.test.ts +398 -0
- package/src/home/assistant-feed-authoring.ts +124 -0
- package/src/home/emit-feed-event.ts +158 -0
- package/src/home/feed-scheduler.ts +247 -0
- package/src/home/feed-types.ts +181 -0
- package/src/home/feed-writer.ts +469 -0
- package/src/home/platform-gmail-digest.ts +163 -0
- package/src/home/progress-formula.ts +86 -0
- package/src/home/relationship-state-writer.ts +824 -0
- package/src/home/relationship-state.ts +143 -0
- package/src/home/rollup-producer.ts +384 -0
- package/src/hooks/runner.ts +7 -0
- package/src/inbound/platform-callback-registration.ts +12 -3
- package/src/inbound/public-ingress-urls.ts +12 -0
- package/src/instrument.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/cli-client.ts +151 -0
- package/src/ipc/cli-server.ts +234 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/index.ts +5 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
- package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/app-store.ts +1 -1
- package/src/memory/attachments-store.ts +70 -0
- package/src/memory/auto-analysis-enqueue.ts +127 -0
- package/src/memory/auto-analysis-guard.ts +27 -0
- package/src/memory/cleanup-schedule-state.ts +37 -0
- package/src/memory/conversation-analyze-job.ts +73 -0
- package/src/memory/conversation-crud.ts +99 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +34 -2
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/db-init.ts +6 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/graph/conversation-graph-memory.ts +15 -0
- package/src/memory/graph/extraction.test.ts +23 -0
- package/src/memory/graph/extraction.ts +8 -0
- package/src/memory/graph/retriever.ts +27 -18
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/group-crud.ts +6 -1
- package/src/memory/indexer.ts +95 -16
- package/src/memory/job-handlers/cleanup.ts +11 -8
- package/src/memory/job-handlers/conversation-starters.ts +16 -10
- package/src/memory/jobs-store.ts +64 -4
- package/src/memory/jobs-worker.ts +22 -9
- package/src/memory/llm-usage-store.ts +92 -56
- package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
- package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/oauth.ts +3 -0
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/client.ts +57 -6
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +143 -38
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/notifications/decision-engine.ts +3 -3
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
- package/src/oauth/byo-connection.test.ts +18 -1
- package/src/oauth/byo-connection.ts +3 -1
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.ts +6 -2
- package/src/oauth/connection.ts +2 -0
- package/src/oauth/oauth-store.ts +9 -0
- package/src/oauth/platform-connection.test.ts +98 -0
- package/src/oauth/platform-connection.ts +52 -31
- package/src/oauth/seed-providers.ts +7 -0
- package/src/permissions/checker.ts +16 -6
- package/src/permissions/defaults.ts +49 -1
- package/src/permissions/trust-store.ts +3 -3
- package/src/permissions/workspace-policy.ts +3 -0
- package/src/platform/client.test.ts +10 -0
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +126 -2
- package/src/prompts/system-prompt.ts +59 -18
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/prompts/templates/UPDATES.md +12 -0
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-format.ts +26 -9
- package/src/prompts/update-bulletin.ts +34 -23
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/anthropic/client.ts +157 -61
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +9 -1
- package/src/providers/model-catalog.ts +6 -0
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +474 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +502 -0
- package/src/providers/openrouter/client.ts +101 -4
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +14 -3
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
- package/src/providers/speech-to-text/deepgram.test.ts +332 -0
- package/src/providers/speech-to-text/deepgram.ts +115 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
- package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
- package/src/providers/speech-to-text/google-gemini.ts +101 -0
- package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
- package/src/providers/speech-to-text/openai-whisper.ts +63 -33
- package/src/providers/speech-to-text/provider-catalog.ts +306 -0
- package/src/providers/speech-to-text/resolve.ts +386 -6
- package/src/providers/types.ts +9 -0
- package/src/runtime/AGENTS.md +43 -1
- package/src/runtime/__tests__/agent-wake.test.ts +831 -0
- package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
- package/src/runtime/agent-wake.ts +512 -0
- package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
- package/src/runtime/auth/route-policy.ts +30 -5
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/capability-tokens.ts +10 -10
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-invite-transports/email.ts +14 -6
- package/src/runtime/channel-readiness-service.ts +12 -22
- package/src/runtime/chrome-extension-registry.ts +38 -2
- package/src/runtime/http-server.ts +395 -10
- package/src/runtime/http-types.ts +6 -2
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/migration-transport.ts +1 -0
- package/src/runtime/migrations/migration-wizard.ts +1 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
- package/src/runtime/migrations/vbundle-importer.ts +34 -0
- package/src/runtime/pending-interactions.ts +0 -11
- package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
- package/src/runtime/routes/app-management-routes.ts +12 -18
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/backup-routes.ts +519 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
- package/src/runtime/routes/btw-routes.ts +8 -6
- package/src/runtime/routes/contact-routes.test.ts +298 -0
- package/src/runtime/routes/contact-routes.ts +132 -5
- package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
- package/src/runtime/routes/conversation-management-routes.ts +115 -0
- package/src/runtime/routes/conversation-routes.ts +367 -146
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/home-feed-routes.ts +334 -0
- package/src/runtime/routes/home-state-routes.ts +138 -0
- package/src/runtime/routes/host-browser-routes.ts +3 -14
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +3 -17
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
- package/src/runtime/routes/integrations/slack/channel.ts +11 -3
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +303 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/migration-routes.ts +40 -5
- package/src/runtime/routes/settings-routes.ts +22 -5
- package/src/runtime/routes/skills-routes.ts +76 -7
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/surface-action-routes.ts +41 -2
- package/src/runtime/routes/tts-routes.ts +108 -24
- package/src/runtime/routes/usage-routes.ts +30 -2
- package/src/runtime/routes/user-route-dispatcher.ts +50 -5
- package/src/runtime/routes/user-routes.ts +13 -1
- package/src/runtime/routes/work-items-routes.ts +8 -1
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
- package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
- package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
- package/src/runtime/services/analyze-conversation.ts +344 -0
- package/src/runtime/services/analyze-deps-singleton.ts +32 -0
- package/src/runtime/services/auto-analysis-prompt.ts +55 -0
- package/src/runtime/skill-route-registry.ts +49 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +50 -0
- package/src/security/oauth2.ts +26 -4
- package/src/security/secure-keys.ts +25 -2
- package/src/security/token-manager.ts +8 -0
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-files.ts +64 -2
- package/src/skills/category-inference.ts +122 -0
- package/src/skills/clawhub-files.ts +213 -0
- package/src/skills/clawhub.ts +84 -23
- package/src/skills/skill-file-provider.ts +40 -0
- package/src/skills/skillssh-files.ts +395 -0
- package/src/skills/skillssh-registry.ts +4 -4
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +195 -0
- package/src/stt/stt-stream-session.ts +499 -0
- package/src/stt/types.ts +330 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +38 -14
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
- package/src/tools/browser/browser-execution.ts +1163 -23
- package/src/tools/browser/browser-manager.ts +45 -0
- package/src/tools/browser/browser-mode-constants.ts +12 -0
- package/src/tools/browser/browser-mode.ts +92 -0
- package/src/tools/browser/browser-status-constants.ts +33 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +183 -17
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
- package/src/tools/browser/cdp-client/errors.ts +15 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
- package/src/tools/browser/cdp-client/factory.ts +797 -87
- package/src/tools/browser/cdp-client/index.ts +16 -2
- package/src/tools/browser/cdp-client/types.ts +68 -0
- package/src/tools/credentials/vault.ts +35 -6
- package/src/tools/network/web-fetch.ts +5 -2
- package/src/tools/network/web-search.ts +5 -2
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +2 -0
- package/src/tools/skills/sandbox-runner.ts +3 -2
- package/src/tools/terminal/safe-env.ts +10 -2
- package/src/tools/terminal/shell.ts +15 -4
- package/src/tools/tool-manifest.ts +21 -0
- package/src/tools/types.ts +17 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tts/__tests__/provider-adapters.test.ts +834 -0
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
- package/src/tts/__tests__/provider-catalog.test.ts +183 -0
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +201 -0
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +219 -0
- package/src/tts/providers/elevenlabs-provider.ts +211 -0
- package/src/tts/providers/fish-audio-provider.ts +183 -0
- package/src/tts/providers/index.ts +42 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +153 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/util/abort-reasons.ts +58 -0
- package/src/util/device-id.ts +32 -16
- package/src/util/errors.ts +9 -1
- package/src/util/platform.ts +54 -10
- package/src/util/pricing.ts +66 -3
- package/src/util/spawn.ts +1 -1
- package/src/util/truncate.ts +4 -2
- package/src/util/unicode.ts +201 -0
- package/src/version.ts +19 -24
- package/src/watcher/engine.ts +23 -0
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/migrations/003-seed-device-id.ts +9 -3
- package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
- package/src/workspace/migrations/029-seed-pkb.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +317 -0
- package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
- package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
- package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
- package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
- package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
- package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
- package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/top-level-renderer.ts +13 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/cli/commands/browser-relay.ts +0 -466
- package/src/email/guardrails.ts +0 -221
- package/src/email/provider.ts +0 -117
- package/src/email/providers/agentmail.ts +0 -361
- package/src/email/providers/index.ts +0 -65
- package/src/email/service.ts +0 -384
- package/src/email/types.ts +0 -126
- package/src/prompts/templates/USER.md +0 -13
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/runtime/routes/browser-cdp-routes.ts +0 -229
|
@@ -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,
|
|
@@ -45,6 +48,10 @@ import type {
|
|
|
45
48
|
NonHostProxyTransportMetadata,
|
|
46
49
|
} from "../../daemon/message-types/conversations.js";
|
|
47
50
|
import type { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
|
|
51
|
+
import {
|
|
52
|
+
writeOnboardingSidecar,
|
|
53
|
+
writeRelationshipState,
|
|
54
|
+
} from "../../home/relationship-state-writer.js";
|
|
48
55
|
import * as attachmentsStore from "../../memory/attachments-store.js";
|
|
49
56
|
import {
|
|
50
57
|
createCanonicalGuardianRequest,
|
|
@@ -74,6 +81,7 @@ import { checkIngressForSecrets } from "../../security/secret-ingress.js";
|
|
|
74
81
|
import { redactSecrets } from "../../security/secret-scanner.js";
|
|
75
82
|
import { summarizeToolInput } from "../../tools/tool-input-summary.js";
|
|
76
83
|
import { getLogger } from "../../util/logger.js";
|
|
84
|
+
import { getWorkspacePromptPath } from "../../util/platform.js";
|
|
77
85
|
import { silentlyWithLog } from "../../util/silently.js";
|
|
78
86
|
import { buildAssistantEvent } from "../assistant-event.js";
|
|
79
87
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
@@ -107,7 +115,7 @@ const SUGGESTION_CACHE_MAX = 100;
|
|
|
107
115
|
function collectCanonicalGuardianRequestHintIds(
|
|
108
116
|
conversationId: string,
|
|
109
117
|
sourceChannel: string,
|
|
110
|
-
conversation:
|
|
118
|
+
conversation: Conversation,
|
|
111
119
|
): string[] {
|
|
112
120
|
const requests = listPendingRequestsByConversationScope(
|
|
113
121
|
conversationId,
|
|
@@ -172,7 +180,7 @@ async function tryConsumeCanonicalGuardianReply(params: {
|
|
|
172
180
|
data: string;
|
|
173
181
|
filePath?: string;
|
|
174
182
|
}>;
|
|
175
|
-
conversation:
|
|
183
|
+
conversation: Conversation;
|
|
176
184
|
onEvent: (msg: ServerMessage) => void;
|
|
177
185
|
approvalConversationGenerator?: ApprovalConversationGenerator;
|
|
178
186
|
/** Verified actor identity from actor-token middleware. */
|
|
@@ -967,7 +975,7 @@ function mergeConsecutiveAssistantMessages(messages: MessageRow[]): {
|
|
|
967
975
|
function makeHubPublisher(
|
|
968
976
|
deps: SendMessageDeps,
|
|
969
977
|
conversationId: string,
|
|
970
|
-
conversation:
|
|
978
|
+
conversation: Conversation,
|
|
971
979
|
): (msg: ServerMessage) => void {
|
|
972
980
|
let hubChain: Promise<void> = Promise.resolve();
|
|
973
981
|
return (msg: ServerMessage) => {
|
|
@@ -1048,30 +1056,8 @@ function makeHubPublisher(
|
|
|
1048
1056
|
conversationId,
|
|
1049
1057
|
kind: "secret",
|
|
1050
1058
|
});
|
|
1051
|
-
} else
|
|
1052
|
-
|
|
1053
|
-
conversation,
|
|
1054
|
-
conversationId,
|
|
1055
|
-
kind: "host_bash",
|
|
1056
|
-
});
|
|
1057
|
-
} else if (msg.type === "host_browser_request") {
|
|
1058
|
-
pendingInteractions.register(msg.requestId, {
|
|
1059
|
-
conversation,
|
|
1060
|
-
conversationId,
|
|
1061
|
-
kind: "host_browser",
|
|
1062
|
-
});
|
|
1063
|
-
} else if (msg.type === "host_file_request") {
|
|
1064
|
-
pendingInteractions.register(msg.requestId, {
|
|
1065
|
-
conversation,
|
|
1066
|
-
conversationId,
|
|
1067
|
-
kind: "host_file",
|
|
1068
|
-
});
|
|
1069
|
-
} else if (msg.type === "host_cu_request") {
|
|
1070
|
-
pendingInteractions.register(msg.requestId, {
|
|
1071
|
-
conversation,
|
|
1072
|
-
conversationId,
|
|
1073
|
-
kind: "host_cu",
|
|
1074
|
-
});
|
|
1059
|
+
} else {
|
|
1060
|
+
registerHostProxyPendingInteraction(msg, conversation, conversationId);
|
|
1075
1061
|
}
|
|
1076
1062
|
|
|
1077
1063
|
// ServerMessage is a large union; conversationId exists on most but not all variants.
|
|
@@ -1100,6 +1086,202 @@ function makeHubPublisher(
|
|
|
1100
1086
|
};
|
|
1101
1087
|
}
|
|
1102
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
|
+
|
|
1103
1285
|
export async function handleSendMessage(
|
|
1104
1286
|
req: Request,
|
|
1105
1287
|
deps: {
|
|
@@ -1120,6 +1302,13 @@ export async function handleSendMessage(
|
|
|
1120
1302
|
bypassSecretCheck?: boolean;
|
|
1121
1303
|
hostHomeDir?: string;
|
|
1122
1304
|
hostUsername?: string;
|
|
1305
|
+
onboarding?: {
|
|
1306
|
+
tools: string[];
|
|
1307
|
+
tasks: string[];
|
|
1308
|
+
tone: string;
|
|
1309
|
+
userName?: string;
|
|
1310
|
+
assistantName?: string;
|
|
1311
|
+
};
|
|
1123
1312
|
};
|
|
1124
1313
|
|
|
1125
1314
|
const { conversationKey, content, attachmentIds } = body;
|
|
@@ -1222,8 +1411,24 @@ export async function handleSendMessage(
|
|
|
1222
1411
|
const mapping = getOrCreateConversation(resolvedConversationKey, {
|
|
1223
1412
|
conversationType,
|
|
1224
1413
|
});
|
|
1414
|
+
|
|
1225
1415
|
const smDeps = deps.sendMessageDeps;
|
|
1226
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
|
+
|
|
1227
1432
|
// Build transport metadata from the request so the daemon can inject
|
|
1228
1433
|
// host environment hints (home directory, username) into the LLM context.
|
|
1229
1434
|
// The `supportsHostProxy` type predicate narrows `sourceInterface` to
|
|
@@ -1247,6 +1452,17 @@ export async function handleSendMessage(
|
|
|
1247
1452
|
{ transport },
|
|
1248
1453
|
);
|
|
1249
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
|
+
|
|
1250
1466
|
// Resolve guardian context from the AuthContext's actorPrincipalId.
|
|
1251
1467
|
// The JWT-verified principal is used as the sender identity through
|
|
1252
1468
|
// the same trust resolution pipeline that channel ingress uses.
|
|
@@ -1328,66 +1544,44 @@ export async function handleSendMessage(
|
|
|
1328
1544
|
} else if (!conversation.isProcessing()) {
|
|
1329
1545
|
conversation.setHostBashProxy(undefined);
|
|
1330
1546
|
}
|
|
1331
|
-
//
|
|
1332
|
-
//
|
|
1333
|
-
//
|
|
1334
|
-
//
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
// `sendToInstance` if a caller ever needs it.
|
|
1345
|
-
//
|
|
1346
|
-
// macOS (and any other interface that supports host_browser in the
|
|
1347
|
-
// future via the SSE hub) keeps using `onEvent` — see the else branch.
|
|
1348
|
-
const browserProxySendToClient: (msg: ServerMessage) => void =
|
|
1349
|
-
sourceInterface === "chrome-extension"
|
|
1350
|
-
? (msg) => {
|
|
1351
|
-
// Resolve the guardian principal id at send time rather than
|
|
1352
|
-
// capturing it from the POST-time authContext. This closure can be
|
|
1353
|
-
// re-fired on queue drain — if a different actor's POST lands while
|
|
1354
|
-
// the queue is still draining an earlier turn, a captured
|
|
1355
|
-
// authContext.actorPrincipalId would mis-route the earlier turn's
|
|
1356
|
-
// host_browser frames to the *new* actor. Preferring
|
|
1357
|
-
// conversation.trustContext?.guardianPrincipalId makes the routing
|
|
1358
|
-
// follow the conversation's bound guardian, which is stable across
|
|
1359
|
-
// subsequent POSTs. Falls back to the per-POST authContext for
|
|
1360
|
-
// turns that haven't been bound to a trust context yet.
|
|
1361
|
-
const gid =
|
|
1362
|
-
conversation.trustContext?.guardianPrincipalId ??
|
|
1363
|
-
authContext.actorPrincipalId;
|
|
1364
|
-
if (!gid) {
|
|
1365
|
-
// No guardian identity on this turn — nothing to route to.
|
|
1366
|
-
// The proxy will observe this via its try/catch and surface a
|
|
1367
|
-
// transport error back to the caller.
|
|
1368
|
-
throw new Error(
|
|
1369
|
-
"chrome-extension host_browser send skipped: no guardianId on AuthContext",
|
|
1370
|
-
);
|
|
1371
|
-
}
|
|
1372
|
-
const ok = getChromeExtensionRegistry().send(gid, msg);
|
|
1373
|
-
if (!ok) {
|
|
1374
|
-
throw new Error(
|
|
1375
|
-
`chrome-extension host_browser send failed: no active connection for guardian ${gid}`,
|
|
1376
|
-
);
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
: onEvent;
|
|
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
|
+
|
|
1380
1560
|
// Stash the registry-routed sender on the conversation so queue-drain
|
|
1381
1561
|
// restores (which run outside of conversation-routes.ts and only have
|
|
1382
1562
|
// access to `sendToClient`) can preserve it when calling
|
|
1383
|
-
// `restoreBrowserProxyAvailability()`.
|
|
1384
|
-
//
|
|
1385
|
-
|
|
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) {
|
|
1386
1568
|
conversation.hostBrowserSenderOverride = browserProxySendToClient;
|
|
1387
1569
|
} else {
|
|
1388
1570
|
conversation.hostBrowserSenderOverride = undefined;
|
|
1389
1571
|
}
|
|
1390
|
-
|
|
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) {
|
|
1391
1585
|
if (!conversation.isProcessing() || !conversation.hostBrowserProxy) {
|
|
1392
1586
|
const browserProxy = new HostBrowserProxy(
|
|
1393
1587
|
browserProxySendToClient,
|
|
@@ -1445,18 +1639,17 @@ export async function handleSendMessage(
|
|
|
1445
1639
|
conversation.updateClient(onEvent, !isInteractive, {
|
|
1446
1640
|
skipProxySenderUpdate: preservingProxies,
|
|
1447
1641
|
});
|
|
1448
|
-
//
|
|
1449
|
-
//
|
|
1450
|
-
//
|
|
1451
|
-
//
|
|
1452
|
-
// host_bash/host_file tool availability into tool gating.
|
|
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
|
|
1453
1646
|
//
|
|
1454
|
-
// `
|
|
1455
|
-
//
|
|
1456
|
-
//
|
|
1457
|
-
//
|
|
1458
|
-
//
|
|
1459
|
-
if (
|
|
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) {
|
|
1460
1653
|
conversation.restoreBrowserProxyAvailability?.();
|
|
1461
1654
|
}
|
|
1462
1655
|
|
|
@@ -1522,6 +1715,12 @@ export async function handleSendMessage(
|
|
|
1522
1715
|
// fast path) so the HTTP response reaches the client before SSE
|
|
1523
1716
|
// events arrive.
|
|
1524
1717
|
setTimeout(() => {
|
|
1718
|
+
onEvent({
|
|
1719
|
+
type: "user_message_echo",
|
|
1720
|
+
text: rawContent,
|
|
1721
|
+
conversationId,
|
|
1722
|
+
messageId: persisted.id,
|
|
1723
|
+
});
|
|
1525
1724
|
onEvent({ type: "assistant_text_delta", text: cannedGreeting });
|
|
1526
1725
|
onEvent({ type: "message_complete", conversationId });
|
|
1527
1726
|
conversation.processing = false;
|
|
@@ -1815,6 +2014,12 @@ export async function handleSendMessage(
|
|
|
1815
2014
|
const conversationId = mapping.conversationId;
|
|
1816
2015
|
const message = slashResult.message;
|
|
1817
2016
|
setTimeout(() => {
|
|
2017
|
+
onEvent({
|
|
2018
|
+
type: "user_message_echo",
|
|
2019
|
+
text: rawContent,
|
|
2020
|
+
conversationId,
|
|
2021
|
+
messageId: persisted.id,
|
|
2022
|
+
});
|
|
1818
2023
|
if (modelInfoEvent) {
|
|
1819
2024
|
onEvent(modelInfoEvent);
|
|
1820
2025
|
}
|
|
@@ -1841,80 +2046,88 @@ export async function handleSendMessage(
|
|
|
1841
2046
|
|
|
1842
2047
|
if (slashResult.kind === "compact") {
|
|
1843
2048
|
conversation.processing = true;
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
);
|
|
1861
|
-
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);
|
|
1862
2065
|
|
|
1863
|
-
|
|
1864
|
-
"thinking",
|
|
1865
|
-
"context_compacting",
|
|
1866
|
-
"assistant_turn",
|
|
1867
|
-
);
|
|
1868
|
-
const result = await conversation.forceCompact();
|
|
1869
|
-
const responseText = formatCompactResult(result);
|
|
2066
|
+
const conversationId = mapping.conversationId;
|
|
1870
2067
|
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
const response = Response.json(
|
|
1881
|
-
{
|
|
1882
|
-
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,
|
|
1883
2077
|
messageId: persisted.id,
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
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);
|
|
1888
2095
|
|
|
1889
|
-
const conversationId = mapping.conversationId;
|
|
1890
|
-
setTimeout(() => {
|
|
1891
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");
|
|
1892
2100
|
onEvent({
|
|
1893
|
-
type: "
|
|
2101
|
+
type: "conversation_error",
|
|
1894
2102
|
conversationId,
|
|
2103
|
+
code: "UNKNOWN",
|
|
2104
|
+
userMessage: `Compaction failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2105
|
+
retryable: true,
|
|
1895
2106
|
});
|
|
2107
|
+
} finally {
|
|
1896
2108
|
conversation.processing = false;
|
|
1897
2109
|
silentlyWithLog(
|
|
1898
2110
|
conversation.drainQueue(),
|
|
1899
2111
|
"compact-command queue drain",
|
|
1900
2112
|
);
|
|
1901
|
-
}, 0);
|
|
1902
|
-
|
|
1903
|
-
cleanupDeferred = true;
|
|
1904
|
-
return response;
|
|
1905
|
-
} finally {
|
|
1906
|
-
if (!cleanupDeferred && conversation.processing) {
|
|
1907
|
-
conversation.processing = false;
|
|
1908
|
-
silentlyWithLog(conversation.drainQueue(), "error-path queue drain");
|
|
1909
2113
|
}
|
|
1910
|
-
}
|
|
2114
|
+
})();
|
|
2115
|
+
|
|
2116
|
+
return Response.json(
|
|
2117
|
+
{
|
|
2118
|
+
accepted: true,
|
|
2119
|
+
messageId: persisted.id,
|
|
2120
|
+
conversationId,
|
|
2121
|
+
},
|
|
2122
|
+
{ status: 202 },
|
|
2123
|
+
);
|
|
1911
2124
|
}
|
|
1912
2125
|
|
|
1913
2126
|
const resolvedContent = slashResult.content;
|
|
1914
2127
|
|
|
2128
|
+
const requestId = crypto.randomUUID();
|
|
1915
2129
|
let messageId: string;
|
|
1916
2130
|
try {
|
|
1917
|
-
const requestId = crypto.randomUUID();
|
|
1918
2131
|
messageId = await conversation.persistUserMessage(
|
|
1919
2132
|
resolvedContent,
|
|
1920
2133
|
attachments,
|
|
@@ -1925,6 +2138,14 @@ export async function handleSendMessage(
|
|
|
1925
2138
|
throw err;
|
|
1926
2139
|
}
|
|
1927
2140
|
|
|
2141
|
+
onEvent({
|
|
2142
|
+
type: "user_message_echo",
|
|
2143
|
+
text: resolvedContent,
|
|
2144
|
+
conversationId: mapping.conversationId,
|
|
2145
|
+
messageId,
|
|
2146
|
+
requestId,
|
|
2147
|
+
});
|
|
2148
|
+
|
|
1928
2149
|
// Fire-and-forget the agent loop; events flow to the hub via onEvent.
|
|
1929
2150
|
conversation
|
|
1930
2151
|
.runAgentLoop(resolvedContent, messageId, onEvent, {
|