@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,5 +1,10 @@
|
|
|
1
1
|
// Skill management types.
|
|
2
2
|
|
|
3
|
+
import type { PartnerAudit } from "../../skills/skillssh-registry.js";
|
|
4
|
+
|
|
5
|
+
// Re-export so consumers can access the audit types from this module.
|
|
6
|
+
export type { PartnerAudit } from "../../skills/skillssh-registry.js";
|
|
7
|
+
|
|
3
8
|
// === Client → Server ===
|
|
4
9
|
|
|
5
10
|
export interface SkillsListRequest {
|
|
@@ -98,6 +103,7 @@ interface ClawhubSlimSkill extends SlimSkillBase {
|
|
|
98
103
|
installs: number;
|
|
99
104
|
reports: number;
|
|
100
105
|
publishedAt?: string;
|
|
106
|
+
version: string;
|
|
101
107
|
}
|
|
102
108
|
|
|
103
109
|
interface SkillsshSlimSkill extends SlimSkillBase {
|
|
@@ -105,6 +111,7 @@ interface SkillsshSlimSkill extends SlimSkillBase {
|
|
|
105
111
|
slug: string;
|
|
106
112
|
sourceRepo: string;
|
|
107
113
|
installs: number;
|
|
114
|
+
audit?: Record<string, PartnerAudit>;
|
|
108
115
|
}
|
|
109
116
|
|
|
110
117
|
interface CustomSlimSkill extends SlimSkillBase {
|
|
@@ -122,6 +129,13 @@ export interface SkillsListResponse {
|
|
|
122
129
|
skills: SlimSkillResponse[];
|
|
123
130
|
}
|
|
124
131
|
|
|
132
|
+
export interface SkillsListFilteredResponse {
|
|
133
|
+
type: "skills_list_response";
|
|
134
|
+
skills: SlimSkillResponse[];
|
|
135
|
+
categoryCounts: Record<string, number>;
|
|
136
|
+
totalCount: number;
|
|
137
|
+
}
|
|
138
|
+
|
|
125
139
|
export interface SkillStateChanged {
|
|
126
140
|
type: "skills_state_changed";
|
|
127
141
|
name: string;
|
|
@@ -159,6 +173,7 @@ interface ClawhubSkillDetail extends SkillDetailBase {
|
|
|
159
173
|
installs: number;
|
|
160
174
|
reports: number;
|
|
161
175
|
publishedAt?: string;
|
|
176
|
+
version: string;
|
|
162
177
|
// Enrichment fields (from clawhubInspect):
|
|
163
178
|
owner?: { handle: string; displayName: string; image?: string } | null;
|
|
164
179
|
stats?: {
|
|
@@ -177,6 +192,7 @@ interface SkillsshSkillDetail extends SkillDetailBase {
|
|
|
177
192
|
slug: string;
|
|
178
193
|
sourceRepo: string;
|
|
179
194
|
installs: number;
|
|
195
|
+
audit?: Record<string, PartnerAudit>;
|
|
180
196
|
}
|
|
181
197
|
|
|
182
198
|
interface CustomSkillDetail extends SkillDetailBase {
|
|
@@ -184,6 +184,8 @@ interface UiSurfaceShowBase {
|
|
|
184
184
|
display?: "inline" | "panel";
|
|
185
185
|
/** The message ID that this surface belongs to (for history loading). */
|
|
186
186
|
messageId?: string;
|
|
187
|
+
/** When `true`, clicking an action does not dismiss the surface — the client keeps the card visible and only marks the clicked `actionId` as spent so siblings remain clickable. */
|
|
188
|
+
persistent?: boolean;
|
|
187
189
|
}
|
|
188
190
|
|
|
189
191
|
export interface UiSurfaceShowCard extends UiSurfaceShowBase {
|
package/src/daemon/server.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
setBroadcastToAllClients,
|
|
8
8
|
} from "../acp/index.js";
|
|
9
9
|
import { enrichMessageWithSourcePaths } from "../agent/attachments.js";
|
|
10
|
+
import type { AgentEvent } from "../agent/loop.js";
|
|
10
11
|
import {
|
|
11
12
|
createAssistantMessage,
|
|
12
13
|
createUserMessage,
|
|
@@ -23,7 +24,9 @@ import { getConfig } from "../config/loader.js";
|
|
|
23
24
|
import { onContactChange } from "../contacts/contact-events.js";
|
|
24
25
|
import type { CesClient } from "../credential-execution/client.js";
|
|
25
26
|
import type { CesProcessManager } from "../credential-execution/process-manager.js";
|
|
27
|
+
import type { FilingService } from "../filing/filing-service.js";
|
|
26
28
|
import type { HeartbeatService } from "../heartbeat/heartbeat-service.js";
|
|
29
|
+
import { CliIpcServer } from "../ipc/cli-server.js";
|
|
27
30
|
import { getApp, getAppDirPath, isMultifileApp } from "../memory/app-store.js";
|
|
28
31
|
import * as attachmentsStore from "../memory/attachments-store.js";
|
|
29
32
|
import {
|
|
@@ -39,11 +42,19 @@ import {
|
|
|
39
42
|
setConversationOriginChannelIfUnset,
|
|
40
43
|
setConversationOriginInterfaceIfUnset,
|
|
41
44
|
} from "../memory/conversation-crud.js";
|
|
42
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
syncMessageToDisk,
|
|
47
|
+
updateMetaFile,
|
|
48
|
+
} from "../memory/conversation-disk-view.js";
|
|
43
49
|
import { getOrCreateConversation } from "../memory/conversation-key-store.js";
|
|
50
|
+
import { syncIdentityNameToPlatform } from "../platform/sync-identity.js";
|
|
44
51
|
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
45
52
|
import { RateLimitProvider } from "../providers/ratelimit.js";
|
|
46
53
|
import { getProvider, initializeProviders } from "../providers/registry.js";
|
|
54
|
+
import {
|
|
55
|
+
registerDefaultWakeResolver,
|
|
56
|
+
type WakeTarget,
|
|
57
|
+
} from "../runtime/agent-wake.js";
|
|
47
58
|
import { buildAssistantEvent } from "../runtime/assistant-event.js";
|
|
48
59
|
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
49
60
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
@@ -59,6 +70,7 @@ import { appendEventToStream } from "../signals/event-stream.js";
|
|
|
59
70
|
import { registerUserMessageCallback } from "../signals/user-message.js";
|
|
60
71
|
import { getSubagentManager } from "../subagent/index.js";
|
|
61
72
|
import { summarizeToolInput } from "../tools/tool-input-summary.js";
|
|
73
|
+
import { createAbortReason } from "../util/abort-reasons.js";
|
|
62
74
|
import { getLogger } from "../util/logger.js";
|
|
63
75
|
import {
|
|
64
76
|
getAvatarImagePath,
|
|
@@ -77,6 +89,7 @@ import {
|
|
|
77
89
|
DEFAULT_MEMORY_POLICY,
|
|
78
90
|
} from "./conversation.js";
|
|
79
91
|
import { ConversationEvictor } from "./conversation-evictor.js";
|
|
92
|
+
import { registerLaunchConversationDeps } from "./conversation-launch.js";
|
|
80
93
|
import { formatCompactResult } from "./conversation-process.js";
|
|
81
94
|
import { resolveChannelCapabilities } from "./conversation-runtime-assembly.js";
|
|
82
95
|
import { resolveSlash, type SlashContext } from "./conversation-slash.js";
|
|
@@ -288,6 +301,7 @@ export class DaemonServer {
|
|
|
288
301
|
// Composed subsystems
|
|
289
302
|
private configWatcher = new ConfigWatcher();
|
|
290
303
|
private appSourceWatcher = new AppSourceWatcher();
|
|
304
|
+
private cliIpc = new CliIpcServer();
|
|
291
305
|
|
|
292
306
|
// CES (Credential Execution Service) — process-level singleton.
|
|
293
307
|
// Lifecycle is managed by startCesProcess() in lifecycle.ts; the server
|
|
@@ -364,6 +378,17 @@ export class DaemonServer {
|
|
|
364
378
|
return this._heartbeatService;
|
|
365
379
|
}
|
|
366
380
|
|
|
381
|
+
/** Optional filing service reference for "Run Now" from the UI. */
|
|
382
|
+
private _filingService?: FilingService;
|
|
383
|
+
|
|
384
|
+
setFilingService(service: FilingService): void {
|
|
385
|
+
this._filingService = service;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
getFilingService(): FilingService | undefined {
|
|
389
|
+
return this._filingService;
|
|
390
|
+
}
|
|
391
|
+
|
|
367
392
|
private deriveMemoryPolicy(conversationId: string): ConversationMemoryPolicy {
|
|
368
393
|
const conversationType = getConversationType(conversationId);
|
|
369
394
|
if (conversationType === "private") {
|
|
@@ -545,11 +570,32 @@ export class DaemonServer {
|
|
|
545
570
|
emoji: fields.emoji,
|
|
546
571
|
home: fields.home,
|
|
547
572
|
});
|
|
573
|
+
|
|
574
|
+
// Best-effort sync of the assistant name to the platform record.
|
|
575
|
+
if (fields.name) {
|
|
576
|
+
syncIdentityNameToPlatform(fields.name);
|
|
577
|
+
}
|
|
548
578
|
} catch (err) {
|
|
549
579
|
log.error({ err }, "Failed to broadcast identity change");
|
|
550
580
|
}
|
|
551
581
|
}
|
|
552
582
|
|
|
583
|
+
/** Best-effort sync of the IDENTITY.md name to the platform record. */
|
|
584
|
+
private syncIdentityToPlatform(): void {
|
|
585
|
+
try {
|
|
586
|
+
const identityPath = getWorkspacePromptPath("IDENTITY.md");
|
|
587
|
+
const content = existsSync(identityPath)
|
|
588
|
+
? readFileSync(identityPath, "utf-8")
|
|
589
|
+
: "";
|
|
590
|
+
const fields = parseIdentityFields(content);
|
|
591
|
+
if (fields.name) {
|
|
592
|
+
syncIdentityNameToPlatform(fields.name);
|
|
593
|
+
}
|
|
594
|
+
} catch (err) {
|
|
595
|
+
log.error({ err }, "Failed to sync identity to platform at startup");
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
553
599
|
private broadcastConfigChanged(): void {
|
|
554
600
|
this.broadcast({ type: "config_changed" });
|
|
555
601
|
}
|
|
@@ -626,7 +672,13 @@ export class DaemonServer {
|
|
|
626
672
|
const conversation = this.conversations.get(conversationId);
|
|
627
673
|
if (!conversation) return false;
|
|
628
674
|
this.evictor.touch(conversationId);
|
|
629
|
-
conversation.abort(
|
|
675
|
+
conversation.abort(
|
|
676
|
+
createAbortReason(
|
|
677
|
+
"signal_cancel",
|
|
678
|
+
"registerCancelCallback",
|
|
679
|
+
conversationId,
|
|
680
|
+
),
|
|
681
|
+
);
|
|
630
682
|
getSubagentManager().abortAllForParent(conversationId);
|
|
631
683
|
return true;
|
|
632
684
|
});
|
|
@@ -753,6 +805,56 @@ export class DaemonServer {
|
|
|
753
805
|
return { accepted: true };
|
|
754
806
|
});
|
|
755
807
|
|
|
808
|
+
// Install the default resolver for `wakeAgentForOpportunity()` so
|
|
809
|
+
// internal subsystems (e.g. the Meet chat-opportunity detector wired
|
|
810
|
+
// up in `MeetSessionManager`) can invoke it without having to build
|
|
811
|
+
// a `WakeTarget` adapter themselves. The adapter wraps a live
|
|
812
|
+
// `Conversation` fetched from the in-memory map / hydrated from the
|
|
813
|
+
// DB, exposing only the narrow surface the wake helper needs.
|
|
814
|
+
registerDefaultWakeResolver(async (conversationId) => {
|
|
815
|
+
try {
|
|
816
|
+
const conversation = await this.getOrCreateConversation(conversationId);
|
|
817
|
+
return conversationToWakeTarget(conversation);
|
|
818
|
+
} catch (err) {
|
|
819
|
+
log.warn(
|
|
820
|
+
{ err, conversationId },
|
|
821
|
+
"agent-wake default resolver: failed to hydrate conversation",
|
|
822
|
+
);
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
// Start the CLI IPC server. Built-in methods (wake_conversation) are
|
|
828
|
+
// registered by the constructor; CLI commands connect to this socket to
|
|
829
|
+
// invoke daemon-side operations that require in-process state.
|
|
830
|
+
this.cliIpc.start();
|
|
831
|
+
|
|
832
|
+
// Wire the launchConversation helper to daemon-side state so
|
|
833
|
+
// handleSurfaceAction can spawn conversations through it.
|
|
834
|
+
registerLaunchConversationDeps({
|
|
835
|
+
getOrCreateConversation: (id, options) =>
|
|
836
|
+
this.getOrCreateConversation(id, options),
|
|
837
|
+
persistAndProcessMessage: (
|
|
838
|
+
conversationId,
|
|
839
|
+
content,
|
|
840
|
+
attachmentIds,
|
|
841
|
+
options,
|
|
842
|
+
sourceChannel,
|
|
843
|
+
sourceInterface,
|
|
844
|
+
) =>
|
|
845
|
+
this.persistAndProcessMessage(
|
|
846
|
+
conversationId,
|
|
847
|
+
content,
|
|
848
|
+
attachmentIds,
|
|
849
|
+
options,
|
|
850
|
+
sourceChannel,
|
|
851
|
+
sourceInterface,
|
|
852
|
+
),
|
|
853
|
+
publishAssistantEvent: (msg, conversationId) =>
|
|
854
|
+
this.publishAssistantEvent(msg, conversationId),
|
|
855
|
+
getAssistantId: () => this.assistantId,
|
|
856
|
+
});
|
|
857
|
+
|
|
756
858
|
this.configWatcher.start(
|
|
757
859
|
() => this.evictConversationsForReload(),
|
|
758
860
|
() => this.broadcastIdentityChanged(),
|
|
@@ -762,6 +864,8 @@ export class DaemonServer {
|
|
|
762
864
|
() => this.broadcastFeatureFlagsChanged(),
|
|
763
865
|
);
|
|
764
866
|
|
|
867
|
+
this.syncIdentityToPlatform();
|
|
868
|
+
|
|
765
869
|
this.appSourceWatcher.start((appId) => this.handleAppSourceChange(appId));
|
|
766
870
|
|
|
767
871
|
// Broadcast contacts_changed to all clients when any contact mutation occurs.
|
|
@@ -778,6 +882,7 @@ export class DaemonServer {
|
|
|
778
882
|
this.evictor.stop();
|
|
779
883
|
this.configWatcher.stop();
|
|
780
884
|
this.appSourceWatcher.stop();
|
|
885
|
+
this.cliIpc.stop();
|
|
781
886
|
if (this.unsubscribeContactChange) {
|
|
782
887
|
this.unsubscribeContactChange();
|
|
783
888
|
this.unsubscribeContactChange = null;
|
|
@@ -959,6 +1064,9 @@ export class DaemonServer {
|
|
|
959
1064
|
memoryPolicy,
|
|
960
1065
|
sharedCesClient,
|
|
961
1066
|
storedOptions?.speed,
|
|
1067
|
+
undefined,
|
|
1068
|
+
storedOptions?.modelIntent,
|
|
1069
|
+
storedOptions?.modelOverride,
|
|
962
1070
|
);
|
|
963
1071
|
newConversation.updateClient(sendToClient, true);
|
|
964
1072
|
await newConversation.loadFromDb();
|
|
@@ -997,6 +1105,15 @@ export class DaemonServer {
|
|
|
997
1105
|
// overwrite the in-flight conversation's transportHints.
|
|
998
1106
|
if (!conversation.isProcessing()) {
|
|
999
1107
|
this.applyTransportMetadata(conversation, options);
|
|
1108
|
+
// trustContext is reapplied here only when the conversation is idle,
|
|
1109
|
+
// so concurrent requests cannot overwrite an in-flight turn's guardian
|
|
1110
|
+
// scope. Direct callers (e.g. schedule-routes run-now) that invoke
|
|
1111
|
+
// processMessage without going through prepareConversationForMessage
|
|
1112
|
+
// rely on this to pick up the trustContext passed in options.
|
|
1113
|
+
// prepareConversationForMessage also reapplies after its own idle check.
|
|
1114
|
+
if (options?.trustContext !== undefined) {
|
|
1115
|
+
conversation.setTrustContext(options.trustContext);
|
|
1116
|
+
}
|
|
1000
1117
|
}
|
|
1001
1118
|
this.evictor.touch(conversationId);
|
|
1002
1119
|
}
|
|
@@ -1584,3 +1701,231 @@ function extractConversationId(msg: ServerMessage): string | undefined {
|
|
|
1584
1701
|
}
|
|
1585
1702
|
return undefined;
|
|
1586
1703
|
}
|
|
1704
|
+
|
|
1705
|
+
/**
|
|
1706
|
+
* Translate a raw {@link AgentEvent} from the agent loop into the
|
|
1707
|
+
* corresponding {@link ServerMessage} wire frame. The normal user-turn
|
|
1708
|
+
* path does this via the full state-aware handler in
|
|
1709
|
+
* `conversation-agent-loop-handlers.ts`; the wake path has no tool
|
|
1710
|
+
* accounting, title generation, or activity-state tracking to worry
|
|
1711
|
+
* about, so we only need the subset that produces client-visible
|
|
1712
|
+
* frames. Events that have no client-visible wire shape (usage, error,
|
|
1713
|
+
* preview/input-json deltas, etc.) are dropped — they produce no UI.
|
|
1714
|
+
*
|
|
1715
|
+
* Keeping this translator co-located with the wake adapter preserves
|
|
1716
|
+
* the runtime/daemon layering: `runtime/agent-wake.ts` never imports
|
|
1717
|
+
* `message-protocol.ts` or wire shapes, and the daemon owns all
|
|
1718
|
+
* translation from agent-loop semantics to client frames.
|
|
1719
|
+
*/
|
|
1720
|
+
function translateAgentEventToServerMessage(
|
|
1721
|
+
event: AgentEvent,
|
|
1722
|
+
conversationId: string,
|
|
1723
|
+
): ServerMessage | null {
|
|
1724
|
+
switch (event.type) {
|
|
1725
|
+
case "text_delta":
|
|
1726
|
+
return {
|
|
1727
|
+
type: "assistant_text_delta",
|
|
1728
|
+
text: event.text,
|
|
1729
|
+
conversationId,
|
|
1730
|
+
};
|
|
1731
|
+
case "thinking_delta":
|
|
1732
|
+
return {
|
|
1733
|
+
type: "assistant_thinking_delta",
|
|
1734
|
+
thinking: event.thinking,
|
|
1735
|
+
conversationId,
|
|
1736
|
+
};
|
|
1737
|
+
case "tool_use":
|
|
1738
|
+
return {
|
|
1739
|
+
type: "tool_use_start",
|
|
1740
|
+
toolName: event.name,
|
|
1741
|
+
input: event.input,
|
|
1742
|
+
conversationId,
|
|
1743
|
+
toolUseId: event.id,
|
|
1744
|
+
};
|
|
1745
|
+
case "tool_use_preview_start":
|
|
1746
|
+
return {
|
|
1747
|
+
type: "tool_use_preview_start",
|
|
1748
|
+
toolUseId: event.toolUseId,
|
|
1749
|
+
toolName: event.toolName,
|
|
1750
|
+
conversationId,
|
|
1751
|
+
};
|
|
1752
|
+
case "tool_output_chunk":
|
|
1753
|
+
return {
|
|
1754
|
+
type: "tool_output_chunk",
|
|
1755
|
+
chunk: event.chunk,
|
|
1756
|
+
conversationId,
|
|
1757
|
+
toolUseId: event.toolUseId,
|
|
1758
|
+
};
|
|
1759
|
+
case "tool_result": {
|
|
1760
|
+
const imageBlocks = event.contentBlocks?.filter(
|
|
1761
|
+
(b): b is Extract<typeof b, { type: "image" }> => b.type === "image",
|
|
1762
|
+
);
|
|
1763
|
+
const imageDataList = imageBlocks?.length
|
|
1764
|
+
? imageBlocks.map((b) => b.source.data)
|
|
1765
|
+
: undefined;
|
|
1766
|
+
return {
|
|
1767
|
+
type: "tool_result",
|
|
1768
|
+
toolName: "",
|
|
1769
|
+
result: event.content,
|
|
1770
|
+
isError: event.isError,
|
|
1771
|
+
diff: event.diff,
|
|
1772
|
+
status: event.status,
|
|
1773
|
+
conversationId,
|
|
1774
|
+
imageData: imageDataList?.[0],
|
|
1775
|
+
imageDataList,
|
|
1776
|
+
toolUseId: event.toolUseId,
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
case "server_tool_start":
|
|
1780
|
+
return {
|
|
1781
|
+
type: "tool_use_start",
|
|
1782
|
+
toolName: event.name,
|
|
1783
|
+
input: event.input,
|
|
1784
|
+
conversationId,
|
|
1785
|
+
toolUseId: event.toolUseId,
|
|
1786
|
+
};
|
|
1787
|
+
case "server_tool_complete": {
|
|
1788
|
+
let resultText = "";
|
|
1789
|
+
if (Array.isArray(event.content) && event.content.length > 0) {
|
|
1790
|
+
resultText = (event.content as unknown[])
|
|
1791
|
+
.filter(
|
|
1792
|
+
(r): r is { type: string; title: string; url: string } =>
|
|
1793
|
+
typeof r === "object" &&
|
|
1794
|
+
r != null &&
|
|
1795
|
+
(r as { type?: string }).type === "web_search_result",
|
|
1796
|
+
)
|
|
1797
|
+
.map((r) => `${r.title}\n${r.url}`)
|
|
1798
|
+
.join("\n\n");
|
|
1799
|
+
}
|
|
1800
|
+
return {
|
|
1801
|
+
type: "tool_result",
|
|
1802
|
+
toolName: "web_search",
|
|
1803
|
+
result: resultText,
|
|
1804
|
+
isError: event.isError,
|
|
1805
|
+
conversationId,
|
|
1806
|
+
toolUseId: event.toolUseId,
|
|
1807
|
+
};
|
|
1808
|
+
}
|
|
1809
|
+
case "message_complete":
|
|
1810
|
+
return {
|
|
1811
|
+
type: "message_complete",
|
|
1812
|
+
conversationId,
|
|
1813
|
+
};
|
|
1814
|
+
// No wire frame for these — usage/error/input_json_delta are either
|
|
1815
|
+
// server-internal (accounting/classification) or app-only debug
|
|
1816
|
+
// streams the client doesn't surface for wake-originated turns.
|
|
1817
|
+
case "input_json_delta":
|
|
1818
|
+
case "usage":
|
|
1819
|
+
case "error":
|
|
1820
|
+
return null;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
/**
|
|
1825
|
+
* Adapt a live {@link Conversation} to the narrow {@link WakeTarget}
|
|
1826
|
+
* surface expected by `wakeAgentForOpportunity()`. Kept here so the
|
|
1827
|
+
* runtime-level wake helper stays decoupled from the heavyweight
|
|
1828
|
+
* conversation class (see `registerDefaultWakeResolver` above).
|
|
1829
|
+
*
|
|
1830
|
+
* Routing notes:
|
|
1831
|
+
* - `emitAgentEvent` dispatches via `broadcastToAllClients` rather
|
|
1832
|
+
* than `sendToClient`. Several signal-injected paths reset
|
|
1833
|
+
* `sendToClient` to a no-op in their `finally` blocks (see the
|
|
1834
|
+
* `updateClient(() => {}, true)` calls in `persistAndProcessMessage`
|
|
1835
|
+
* / `processMessage`), so a wake fired on such a conversation would
|
|
1836
|
+
* find a silent sink. `broadcastToAllClients` is wired to
|
|
1837
|
+
* `this.broadcast(msg)` at construction time and always reaches the
|
|
1838
|
+
* hub, regardless of which sender the most-recent user turn left
|
|
1839
|
+
* behind.
|
|
1840
|
+
* - `persistTailMessage` mirrors the canonical user-turn handlers
|
|
1841
|
+
* (`handleMessageComplete` / the tool-result block in
|
|
1842
|
+
* `conversation-agent-loop-handlers.ts`): builds channel/interface
|
|
1843
|
+
* metadata via `provenanceFromTrustContext` plus the live turn
|
|
1844
|
+
* channel/interface contexts, persists with metadata, and syncs the
|
|
1845
|
+
* resulting row to the disk view so wake-produced messages appear
|
|
1846
|
+
* in the on-disk transcript and carry provenance tags.
|
|
1847
|
+
* - `drainQueue` delegates to the conversation so any user messages
|
|
1848
|
+
* queued while the wake was running are processed. The wake helper
|
|
1849
|
+
* calls this in its finally AFTER `markProcessing(false)`; the
|
|
1850
|
+
* order matters because `enqueueMessage` only queues when
|
|
1851
|
+
* `processing === true`.
|
|
1852
|
+
*/
|
|
1853
|
+
function conversationToWakeTarget(conversation: Conversation): WakeTarget {
|
|
1854
|
+
return {
|
|
1855
|
+
conversationId: conversation.conversationId,
|
|
1856
|
+
agentLoop: conversation.agentLoop,
|
|
1857
|
+
getMessages: () => conversation.getMessages(),
|
|
1858
|
+
pushMessage: (msg) => {
|
|
1859
|
+
conversation.messages.push(msg);
|
|
1860
|
+
},
|
|
1861
|
+
emitAgentEvent: (event) => {
|
|
1862
|
+
const frame = translateAgentEventToServerMessage(
|
|
1863
|
+
event,
|
|
1864
|
+
conversation.conversationId,
|
|
1865
|
+
);
|
|
1866
|
+
if (!frame) return;
|
|
1867
|
+
// Prefer `broadcastToAllClients` (wired to the hub at construction
|
|
1868
|
+
// time and always live) over `sendToClient` (which several
|
|
1869
|
+
// signal-injected paths reset to `() => {}` in their finally
|
|
1870
|
+
// blocks). Fall back to `sendToClient` when the broadcaster is
|
|
1871
|
+
// missing (e.g. in tests that construct a Conversation directly).
|
|
1872
|
+
if (conversation.broadcastToAllClients) {
|
|
1873
|
+
conversation.broadcastToAllClients(frame);
|
|
1874
|
+
} else {
|
|
1875
|
+
conversation.sendToClient(frame);
|
|
1876
|
+
}
|
|
1877
|
+
},
|
|
1878
|
+
isProcessing: () => conversation.isProcessing(),
|
|
1879
|
+
markProcessing: (on) => {
|
|
1880
|
+
conversation.processing = on;
|
|
1881
|
+
},
|
|
1882
|
+
persistTailMessage: async (message) => {
|
|
1883
|
+
// Build metadata that mirrors the canonical handlers in
|
|
1884
|
+
// `conversation-agent-loop-handlers.ts`. If the live turn channel
|
|
1885
|
+
// / interface contexts are missing (a wake can fire on a
|
|
1886
|
+
// conversation that has never run a user turn), fall back to the
|
|
1887
|
+
// conversation's origin channel/interface defaults (`"vellum"`)
|
|
1888
|
+
// so persisted rows still carry valid channel/interface ids.
|
|
1889
|
+
const turnChannelCtx = conversation.getTurnChannelContext();
|
|
1890
|
+
const turnInterfaceCtx = conversation.getTurnInterfaceContext();
|
|
1891
|
+
const metadata: Record<string, unknown> = {
|
|
1892
|
+
...provenanceFromTrustContext(conversation.trustContext),
|
|
1893
|
+
userMessageChannel: turnChannelCtx?.userMessageChannel ?? "vellum",
|
|
1894
|
+
assistantMessageChannel:
|
|
1895
|
+
turnChannelCtx?.assistantMessageChannel ?? "vellum",
|
|
1896
|
+
userMessageInterface:
|
|
1897
|
+
turnInterfaceCtx?.userMessageInterface ?? "vellum",
|
|
1898
|
+
assistantMessageInterface:
|
|
1899
|
+
turnInterfaceCtx?.assistantMessageInterface ?? "vellum",
|
|
1900
|
+
};
|
|
1901
|
+
const persisted = await addMessage(
|
|
1902
|
+
conversation.conversationId,
|
|
1903
|
+
message.role,
|
|
1904
|
+
JSON.stringify(message.content),
|
|
1905
|
+
metadata,
|
|
1906
|
+
);
|
|
1907
|
+
// Sync the persisted row to the disk view so wake-produced
|
|
1908
|
+
// messages appear in the on-disk transcript and tools that read
|
|
1909
|
+
// from disk (e.g. `messages.jsonl`-based diagnostics) see them.
|
|
1910
|
+
// Mirrors the `syncMessageToDisk(...)` calls in the canonical
|
|
1911
|
+
// handlers — best-effort because a sync failure must not strand
|
|
1912
|
+
// the in-memory tail.
|
|
1913
|
+
try {
|
|
1914
|
+
const convRow = getConversation(conversation.conversationId);
|
|
1915
|
+
if (convRow) {
|
|
1916
|
+
syncMessageToDisk(
|
|
1917
|
+
conversation.conversationId,
|
|
1918
|
+
persisted.id,
|
|
1919
|
+
convRow.createdAt,
|
|
1920
|
+
);
|
|
1921
|
+
}
|
|
1922
|
+
} catch (err) {
|
|
1923
|
+
log.warn(
|
|
1924
|
+
{ err, conversationId: conversation.conversationId },
|
|
1925
|
+
"wake adapter: syncMessageToDisk failed (non-fatal)",
|
|
1926
|
+
);
|
|
1927
|
+
}
|
|
1928
|
+
},
|
|
1929
|
+
drainQueue: () => conversation.drainQueue(),
|
|
1930
|
+
};
|
|
1931
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Sentry from "@sentry/node";
|
|
2
2
|
|
|
3
|
+
import type { BackupWorkerHandle } from "../backup/backup-worker.js";
|
|
3
4
|
import type { FilingService } from "../filing/filing-service.js";
|
|
4
5
|
import type { HeartbeatService } from "../heartbeat/heartbeat-service.js";
|
|
5
6
|
import type { HookManager } from "../hooks/manager.js";
|
|
@@ -13,6 +14,7 @@ import { getLogger } from "../util/logger.js";
|
|
|
13
14
|
import { getEnrichmentService } from "../workspace/commit-message-enrichment-service.js";
|
|
14
15
|
import type { WorkspaceHeartbeatService } from "../workspace/heartbeat-service.js";
|
|
15
16
|
import type { DaemonServer } from "./server.js";
|
|
17
|
+
import { runShutdownHooks } from "./shutdown-registry.js";
|
|
16
18
|
|
|
17
19
|
const log = getLogger("lifecycle");
|
|
18
20
|
|
|
@@ -24,7 +26,9 @@ export interface ShutdownDeps {
|
|
|
24
26
|
hookManager: HookManager;
|
|
25
27
|
runtimeHttp: RuntimeHttpServer | null;
|
|
26
28
|
scheduler: { stop(): void };
|
|
29
|
+
feedScheduler: { stop(): void } | null;
|
|
27
30
|
getMemoryWorker: () => { stop(): void } | null;
|
|
31
|
+
getBackupWorker: () => BackupWorkerHandle | null;
|
|
28
32
|
getQdrantManager: () => QdrantManager | null;
|
|
29
33
|
mcpManager: McpServerManager | null;
|
|
30
34
|
telemetryReporter: { stop(): Promise<void> } | null;
|
|
@@ -45,11 +49,18 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
45
49
|
// Force exit if graceful shutdown takes too long.
|
|
46
50
|
// Set this BEFORE awaiting heartbeat stop and triggering daemon-stop hooks
|
|
47
51
|
// so it covers all potentially-blocking async shutdown work.
|
|
52
|
+
//
|
|
53
|
+
// 20s budget: 15s reserved for Meet session teardown
|
|
54
|
+
// (`MeetSessionManager.shutdownAll`), plus ~5s for the remaining
|
|
55
|
+
// daemon work (workspace commits, server drain, enrichment, telemetry,
|
|
56
|
+
// mcp, qdrant, sqlite checkpoint). Without a live Meet session the
|
|
57
|
+
// rest of the shutdown routinely completes in under a second, so this
|
|
58
|
+
// bump only changes behavior for the stuck-shutdown path.
|
|
48
59
|
const forceTimer = setTimeout(() => {
|
|
49
60
|
log.warn("Graceful shutdown timed out, forcing exit");
|
|
50
61
|
deps.cleanupPidFile();
|
|
51
62
|
process.exit(1);
|
|
52
|
-
},
|
|
63
|
+
}, 20_000);
|
|
53
64
|
forceTimer.unref();
|
|
54
65
|
|
|
55
66
|
await deps.workspaceHeartbeat.stop();
|
|
@@ -62,6 +73,15 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
62
73
|
// Don't let hook failures block shutdown
|
|
63
74
|
}
|
|
64
75
|
|
|
76
|
+
// Run registered skill shutdown hooks (e.g. meet-join session teardown)
|
|
77
|
+
// before stopping the server so any HTTP round-trips and SSE emissions
|
|
78
|
+
// still have live transports.
|
|
79
|
+
try {
|
|
80
|
+
await runShutdownHooks("daemon-shutdown");
|
|
81
|
+
} catch (err) {
|
|
82
|
+
log.warn({ err }, "Skill shutdown hooks failed (non-fatal)");
|
|
83
|
+
}
|
|
84
|
+
|
|
65
85
|
// Commit any uncommitted workspace changes before stopping the server.
|
|
66
86
|
// This ensures no workspace state is lost during graceful shutdown.
|
|
67
87
|
try {
|
|
@@ -111,7 +131,9 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
111
131
|
await browserManager.closeAllPages();
|
|
112
132
|
cleanupShellOutputTempFiles();
|
|
113
133
|
deps.scheduler.stop();
|
|
134
|
+
deps.feedScheduler?.stop();
|
|
114
135
|
deps.getMemoryWorker()?.stop();
|
|
136
|
+
deps.getBackupWorker()?.stop();
|
|
115
137
|
|
|
116
138
|
if (deps.mcpManager) {
|
|
117
139
|
try {
|
|
@@ -123,9 +145,15 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
123
145
|
|
|
124
146
|
await deps.getQdrantManager()?.stop();
|
|
125
147
|
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
//
|
|
148
|
+
// Optimize query planner statistics before closing so they persist for
|
|
149
|
+
// the next session. Checkpoint WAL and close SQLite so no writes are
|
|
150
|
+
// lost on exit. Each step is in its own try block so later steps still
|
|
151
|
+
// run if an earlier one throws (e.g. SQLITE_BUSY).
|
|
152
|
+
try {
|
|
153
|
+
getSqlite().exec("PRAGMA optimize");
|
|
154
|
+
} catch (err) {
|
|
155
|
+
log.warn({ err }, "PRAGMA optimize at shutdown failed (non-fatal)");
|
|
156
|
+
}
|
|
129
157
|
try {
|
|
130
158
|
getSqlite().exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
131
159
|
} catch (err) {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry for skill shutdown hooks.
|
|
3
|
+
*
|
|
4
|
+
* Skills register async shutdown callbacks at initialization time. The daemon
|
|
5
|
+
* calls {@link runShutdownHooks} during graceful shutdown so skill-owned
|
|
6
|
+
* resources (containers, sockets, etc.) are torn down before the process exits.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { getLogger } from "../util/logger.js";
|
|
10
|
+
|
|
11
|
+
const log = getLogger("shutdown-registry");
|
|
12
|
+
|
|
13
|
+
type ShutdownHook = (reason: string) => Promise<void>;
|
|
14
|
+
|
|
15
|
+
const hooks = new Map<string, ShutdownHook>();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Register a named shutdown hook. Called by skills at initialization time.
|
|
19
|
+
* If a hook with the same name already exists it is silently replaced (supports
|
|
20
|
+
* hot-reload).
|
|
21
|
+
*/
|
|
22
|
+
export function registerShutdownHook(name: string, hook: ShutdownHook): void {
|
|
23
|
+
hooks.set(name, hook);
|
|
24
|
+
log.info({ name }, "Shutdown hook registered");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Run all registered shutdown hooks. Each hook receives a human-readable
|
|
29
|
+
* `reason` string (e.g. "daemon-shutdown"). Failures are logged but do not
|
|
30
|
+
* prevent other hooks from running.
|
|
31
|
+
*/
|
|
32
|
+
export async function runShutdownHooks(reason: string): Promise<void> {
|
|
33
|
+
for (const [name, hook] of hooks) {
|
|
34
|
+
try {
|
|
35
|
+
await hook(reason);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
log.warn({ err, name }, `Shutdown hook "${name}" failed (non-fatal)`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -215,7 +215,9 @@ registerHook(
|
|
|
215
215
|
const SETTING_TO_KEY: Record<string, string> = {
|
|
216
216
|
activation_key: "pttActivationKey",
|
|
217
217
|
tts_voice_id: "ttsVoiceId",
|
|
218
|
+
tts_provider: "ttsProvider",
|
|
218
219
|
conversation_timeout: "voiceConversationTimeoutSeconds",
|
|
220
|
+
fish_audio_reference_id: "fishAudioReferenceId",
|
|
219
221
|
};
|
|
220
222
|
const key = SETTING_TO_KEY[setting];
|
|
221
223
|
if (!key) return;
|
|
@@ -228,6 +230,13 @@ registerHook(
|
|
|
228
230
|
coerced = typeof raw === "number" ? raw : Number(raw);
|
|
229
231
|
} else if (setting === "tts_voice_id" && typeof raw === "string") {
|
|
230
232
|
coerced = raw.trim();
|
|
233
|
+
} else if (
|
|
234
|
+
setting === "fish_audio_reference_id" &&
|
|
235
|
+
typeof raw === "string"
|
|
236
|
+
) {
|
|
237
|
+
coerced = raw.trim();
|
|
238
|
+
} else if (setting === "tts_provider" && typeof raw === "string") {
|
|
239
|
+
coerced = raw.trim();
|
|
231
240
|
}
|
|
232
241
|
broadcastToAllClients?.({
|
|
233
242
|
type: "client_settings_update",
|