@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
|
@@ -10,11 +10,12 @@ import {
|
|
|
10
10
|
readdirSync,
|
|
11
11
|
watch,
|
|
12
12
|
} from "node:fs";
|
|
13
|
-
import { homedir } from "node:os";
|
|
14
13
|
import { join } from "node:path";
|
|
15
14
|
|
|
16
15
|
import { clearFeatureFlagOverridesCache } from "../config/assistant-feature-flags.js";
|
|
17
16
|
import { getConfig, invalidateConfigCache } from "../config/loader.js";
|
|
17
|
+
import type { MemoryCleanupConfig } from "../config/schemas/memory-lifecycle.js";
|
|
18
|
+
import { resetCleanupScheduleThrottle } from "../memory/cleanup-schedule-state.js";
|
|
18
19
|
import { clearEmbeddingBackendCache } from "../memory/embedding-backend.js";
|
|
19
20
|
import { clearCache as clearTrustCache } from "../permissions/trust-store.js";
|
|
20
21
|
import { initializeProviders } from "../providers/registry.js";
|
|
@@ -30,6 +31,7 @@ import { getLogger } from "../util/logger.js";
|
|
|
30
31
|
import {
|
|
31
32
|
AVATAR_IMAGE_FILENAME,
|
|
32
33
|
getAvatarDir,
|
|
34
|
+
getProtectedDir,
|
|
33
35
|
getSignalsDir,
|
|
34
36
|
getSoundsDir,
|
|
35
37
|
getWorkspaceDir,
|
|
@@ -38,6 +40,17 @@ import {
|
|
|
38
40
|
|
|
39
41
|
const log = getLogger("config-watcher");
|
|
40
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Attach a resilient error handler to an FSWatcher so that async errors
|
|
45
|
+
* (e.g. ENXIO when a Unix socket file like `gateway.sock` appears in a
|
|
46
|
+
* watched directory) are logged instead of crashing the process.
|
|
47
|
+
*/
|
|
48
|
+
function attachWatcherErrorHandler(watcher: FSWatcher, dir: string): void {
|
|
49
|
+
watcher.on("error", (err) => {
|
|
50
|
+
log.warn({ err, dir }, "FSWatcher error (non-fatal, continuing)");
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
41
54
|
export class ConfigWatcher {
|
|
42
55
|
private watchers: FSWatcher[] = [];
|
|
43
56
|
private debounceTimers = new DebouncerMap({
|
|
@@ -94,6 +107,7 @@ export class ConfigWatcher {
|
|
|
94
107
|
* Returns true if config actually changed.
|
|
95
108
|
*/
|
|
96
109
|
async refreshConfigFromSources(): Promise<boolean> {
|
|
110
|
+
const prevCleanup = safeGetCleanupConfig();
|
|
97
111
|
invalidateConfigCache();
|
|
98
112
|
const config = getConfig();
|
|
99
113
|
const fingerprint = this.configFingerprint(config);
|
|
@@ -102,6 +116,13 @@ export class ConfigWatcher {
|
|
|
102
116
|
}
|
|
103
117
|
clearTrustCache();
|
|
104
118
|
clearEmbeddingBackendCache();
|
|
119
|
+
// If cleanup retention settings changed, reset the cleanup scheduler
|
|
120
|
+
// throttle so the next worker tick re-enqueues jobs with the new values
|
|
121
|
+
// instead of waiting out the remaining enqueueIntervalMs (default 6h).
|
|
122
|
+
const nextCleanup = config.memory?.cleanup;
|
|
123
|
+
if (cleanupSettingsChanged(prevCleanup, nextCleanup)) {
|
|
124
|
+
resetCleanupScheduleThrottle();
|
|
125
|
+
}
|
|
105
126
|
const isFirstInit = this.lastFingerprint === "";
|
|
106
127
|
await initializeProviders(config);
|
|
107
128
|
this.lastFingerprint = fingerprint;
|
|
@@ -151,7 +172,6 @@ export class ConfigWatcher {
|
|
|
151
172
|
onConversationEvict();
|
|
152
173
|
onIdentityChanged?.();
|
|
153
174
|
},
|
|
154
|
-
"USER.md": () => onConversationEvict(),
|
|
155
175
|
"UPDATES.md": () => onConversationEvict(),
|
|
156
176
|
};
|
|
157
177
|
|
|
@@ -170,6 +190,7 @@ export class ConfigWatcher {
|
|
|
170
190
|
handlers[file]();
|
|
171
191
|
});
|
|
172
192
|
});
|
|
193
|
+
attachWatcherErrorHandler(watcher, dir);
|
|
173
194
|
this.watchers.push(watcher);
|
|
174
195
|
log.info({ dir }, `Watching ${label}`);
|
|
175
196
|
} catch (err) {
|
|
@@ -195,6 +216,7 @@ export class ConfigWatcher {
|
|
|
195
216
|
|
|
196
217
|
this.startFeatureFlagsWatcher(onFeatureFlagsChanged);
|
|
197
218
|
this.startSignalsWatcher();
|
|
219
|
+
this.startUsersWatcher(onConversationEvict);
|
|
198
220
|
this.startSkillsWatchers(onConversationEvict);
|
|
199
221
|
}
|
|
200
222
|
|
|
@@ -227,6 +249,7 @@ export class ConfigWatcher {
|
|
|
227
249
|
onSoundsConfigChanged();
|
|
228
250
|
});
|
|
229
251
|
});
|
|
252
|
+
attachWatcherErrorHandler(watcher, soundsDir);
|
|
230
253
|
this.watchers.push(watcher);
|
|
231
254
|
log.info({ dir: soundsDir }, "Watching sounds directory for changes");
|
|
232
255
|
} catch (err) {
|
|
@@ -237,6 +260,40 @@ export class ConfigWatcher {
|
|
|
237
260
|
}
|
|
238
261
|
}
|
|
239
262
|
|
|
263
|
+
private startUsersWatcher(onConversationEvict: () => void): void {
|
|
264
|
+
const usersDir = join(getWorkspaceDir(), "users");
|
|
265
|
+
try {
|
|
266
|
+
if (!existsSync(usersDir)) {
|
|
267
|
+
mkdirSync(usersDir, { recursive: true });
|
|
268
|
+
}
|
|
269
|
+
} catch {
|
|
270
|
+
// If we can't create it, watching will also fail — handled below.
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
const watcher = watch(usersDir, (_eventType, filename) => {
|
|
275
|
+
if (!filename) return;
|
|
276
|
+
const file = String(filename);
|
|
277
|
+
if (!file.endsWith(".md")) return;
|
|
278
|
+
this.debounceTimers.schedule(`file:users/${file}`, () => {
|
|
279
|
+
log.info({ file }, "Users persona file changed, reloading");
|
|
280
|
+
onConversationEvict();
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
attachWatcherErrorHandler(watcher, usersDir);
|
|
284
|
+
this.watchers.push(watcher);
|
|
285
|
+
log.info(
|
|
286
|
+
{ dir: usersDir },
|
|
287
|
+
"Watching users directory for persona changes",
|
|
288
|
+
);
|
|
289
|
+
} catch (err) {
|
|
290
|
+
log.warn(
|
|
291
|
+
{ err, dir: usersDir },
|
|
292
|
+
"Failed to watch users directory. Persona file changes will require a restart.",
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
240
297
|
private startAvatarWatcher(onAvatarChanged: () => void): void {
|
|
241
298
|
const avatarDir = getAvatarDir();
|
|
242
299
|
try {
|
|
@@ -259,6 +316,7 @@ export class ConfigWatcher {
|
|
|
259
316
|
onAvatarChanged();
|
|
260
317
|
});
|
|
261
318
|
});
|
|
319
|
+
attachWatcherErrorHandler(watcher, avatarDir);
|
|
262
320
|
this.watchers.push(watcher);
|
|
263
321
|
log.info({ dir: avatarDir }, "Watching avatar directory for changes");
|
|
264
322
|
} catch (err) {
|
|
@@ -270,9 +328,7 @@ export class ConfigWatcher {
|
|
|
270
328
|
}
|
|
271
329
|
|
|
272
330
|
private startFeatureFlagsWatcher(onFeatureFlagsChanged?: () => void): void {
|
|
273
|
-
const protectedDir = process.env.GATEWAY_SECURITY_DIR
|
|
274
|
-
? process.env.GATEWAY_SECURITY_DIR
|
|
275
|
-
: join(homedir(), ".vellum", "protected");
|
|
331
|
+
const protectedDir = process.env.GATEWAY_SECURITY_DIR || getProtectedDir();
|
|
276
332
|
|
|
277
333
|
try {
|
|
278
334
|
if (!existsSync(protectedDir)) {
|
|
@@ -305,6 +361,7 @@ export class ConfigWatcher {
|
|
|
305
361
|
500,
|
|
306
362
|
);
|
|
307
363
|
});
|
|
364
|
+
attachWatcherErrorHandler(watcher, protectedDir);
|
|
308
365
|
this.watchers.push(watcher);
|
|
309
366
|
log.info(
|
|
310
367
|
{ dir: protectedDir },
|
|
@@ -367,6 +424,7 @@ export class ConfigWatcher {
|
|
|
367
424
|
}
|
|
368
425
|
}
|
|
369
426
|
});
|
|
427
|
+
attachWatcherErrorHandler(watcher, signalsDir);
|
|
370
428
|
this.watchers.push(watcher);
|
|
371
429
|
log.info({ dir: signalsDir }, "Watching signals directory");
|
|
372
430
|
} catch (err) {
|
|
@@ -396,6 +454,7 @@ export class ConfigWatcher {
|
|
|
396
454
|
scheduleSkillsReload(filename ? String(filename) : "(unknown)");
|
|
397
455
|
},
|
|
398
456
|
);
|
|
457
|
+
attachWatcherErrorHandler(recursiveWatcher, skillsDir);
|
|
399
458
|
this.watchers.push(recursiveWatcher);
|
|
400
459
|
log.info({ dir: skillsDir }, "Watching skills directory recursively");
|
|
401
460
|
return;
|
|
@@ -416,6 +475,7 @@ export class ConfigWatcher {
|
|
|
416
475
|
const watcher = watch(dirPath, (_eventType, filename) => {
|
|
417
476
|
onChange(filename ? String(filename) : "(unknown)");
|
|
418
477
|
});
|
|
478
|
+
attachWatcherErrorHandler(watcher, dirPath);
|
|
419
479
|
this.watchers.push(watcher);
|
|
420
480
|
return watcher;
|
|
421
481
|
} catch (err) {
|
|
@@ -481,3 +541,37 @@ export class ConfigWatcher {
|
|
|
481
541
|
);
|
|
482
542
|
}
|
|
483
543
|
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Snapshot the current cleanup config so we can compare it against the
|
|
547
|
+
* post-reload value. Tolerant of config-load failures — if the config can't
|
|
548
|
+
* be read (e.g. first-load), returns undefined so the comparison below
|
|
549
|
+
* treats it as "no previous value".
|
|
550
|
+
*/
|
|
551
|
+
function safeGetCleanupConfig(): MemoryCleanupConfig | undefined {
|
|
552
|
+
try {
|
|
553
|
+
return getConfig().memory?.cleanup;
|
|
554
|
+
} catch {
|
|
555
|
+
return undefined;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Return true if any cleanup field the user can change via the UI differs
|
|
561
|
+
* between the previous and next config snapshots. Used to decide whether to
|
|
562
|
+
* reset the cleanup-scheduler throttle after a config reload so retention
|
|
563
|
+
* changes take effect immediately instead of waiting up to 6 hours.
|
|
564
|
+
*
|
|
565
|
+
* Exported for unit testing.
|
|
566
|
+
*/
|
|
567
|
+
export function cleanupSettingsChanged(
|
|
568
|
+
prev: MemoryCleanupConfig | undefined,
|
|
569
|
+
next: MemoryCleanupConfig | undefined,
|
|
570
|
+
): boolean {
|
|
571
|
+
if (!prev || !next) return false;
|
|
572
|
+
return (
|
|
573
|
+
prev.llmRequestLogRetentionMs !== next.llmRequestLogRetentionMs ||
|
|
574
|
+
prev.conversationRetentionDays !== next.conversationRetentionDays ||
|
|
575
|
+
prev.enabled !== next.enabled
|
|
576
|
+
);
|
|
577
|
+
}
|
|
@@ -64,6 +64,8 @@ export interface EventHandlerState {
|
|
|
64
64
|
exchangeCacheCreationInputTokens: number;
|
|
65
65
|
exchangeCacheReadInputTokens: number;
|
|
66
66
|
exchangeOutputTokens: number;
|
|
67
|
+
/** Input tokens from the most recent LLM API call (overwritten, not accumulated). */
|
|
68
|
+
lastCallInputTokens: number;
|
|
67
69
|
/** Number of actual LLM API calls within this exchange. */
|
|
68
70
|
exchangeLlmCallCount: number;
|
|
69
71
|
readonly exchangeRawResponses: unknown[];
|
|
@@ -135,6 +137,7 @@ export function createEventHandlerState(): EventHandlerState {
|
|
|
135
137
|
exchangeCacheCreationInputTokens: 0,
|
|
136
138
|
exchangeCacheReadInputTokens: 0,
|
|
137
139
|
exchangeOutputTokens: 0,
|
|
140
|
+
lastCallInputTokens: 0,
|
|
138
141
|
exchangeLlmCallCount: 0,
|
|
139
142
|
exchangeRawResponses: [],
|
|
140
143
|
model: "",
|
|
@@ -590,6 +593,7 @@ function annotatePersistedAssistantMessage(
|
|
|
590
593
|
data: surface.data,
|
|
591
594
|
actions: surface.actions,
|
|
592
595
|
display: surface.display,
|
|
596
|
+
...(surface.persistent ? { persistent: true } : {}),
|
|
593
597
|
} as unknown as ContentBlock);
|
|
594
598
|
}
|
|
595
599
|
modified = true;
|
|
@@ -759,6 +763,7 @@ export async function handleMessageComplete(
|
|
|
759
763
|
data: surface.data,
|
|
760
764
|
actions: surface.actions,
|
|
761
765
|
display: surface.display,
|
|
766
|
+
...(surface.persistent ? { persistent: true } : {}),
|
|
762
767
|
} as unknown as ContentBlock);
|
|
763
768
|
}
|
|
764
769
|
|
|
@@ -831,6 +836,7 @@ export function handleUsage(
|
|
|
831
836
|
state.exchangeProviderName = providerName;
|
|
832
837
|
state.exchangeLlmCallCount += 1;
|
|
833
838
|
state.exchangeInputTokens += event.inputTokens;
|
|
839
|
+
state.lastCallInputTokens = event.inputTokens;
|
|
834
840
|
state.exchangeCacheCreationInputTokens += event.cacheCreationInputTokens ?? 0;
|
|
835
841
|
state.exchangeCacheReadInputTokens += event.cacheReadInputTokens ?? 0;
|
|
836
842
|
state.exchangeOutputTokens += event.outputTokens;
|
|
@@ -24,10 +24,14 @@ import type {
|
|
|
24
24
|
} from "../channels/types.js";
|
|
25
25
|
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
26
26
|
import { getConfig } from "../config/loader.js";
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
derefToolResultReReads,
|
|
29
|
+
postTurnTruncateToolResults,
|
|
30
|
+
} from "../context/post-turn-tool-result-truncation.js";
|
|
28
31
|
import { estimatePromptTokens } from "../context/token-estimator.js";
|
|
29
32
|
import type { ContextWindowManager } from "../context/window-manager.js";
|
|
30
33
|
import type { ToolProfiler } from "../events/tool-profiling-listener.js";
|
|
34
|
+
import { writeRelationshipState } from "../home/relationship-state-writer.js";
|
|
31
35
|
import { getHookManager } from "../hooks/manager.js";
|
|
32
36
|
import {
|
|
33
37
|
clearSentryConversationContext,
|
|
@@ -35,12 +39,15 @@ import {
|
|
|
35
39
|
} from "../instrument.js";
|
|
36
40
|
import { commitAppTurnChanges } from "../memory/app-git-service.js";
|
|
37
41
|
import { getApp, listAppFiles, resolveAppDir } from "../memory/app-store.js";
|
|
42
|
+
import { enqueueAutoAnalysisOnCompaction } from "../memory/auto-analysis-enqueue.js";
|
|
38
43
|
import {
|
|
39
44
|
addMessage,
|
|
40
45
|
deleteMessageById,
|
|
41
46
|
getConversation,
|
|
42
47
|
getConversationOriginChannel,
|
|
43
48
|
getConversationOriginInterface,
|
|
49
|
+
getLastUserTimestampBefore,
|
|
50
|
+
getMessageById,
|
|
44
51
|
provenanceFromTrustContext,
|
|
45
52
|
updateConversationContextWindow,
|
|
46
53
|
updateConversationTitle,
|
|
@@ -64,6 +71,7 @@ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
|
64
71
|
import { getSubagentManager } from "../subagent/index.js";
|
|
65
72
|
import type { UsageActor } from "../usage/actors.js";
|
|
66
73
|
import { getLogger } from "../util/logger.js";
|
|
74
|
+
import { timeAgo } from "../util/time.js";
|
|
67
75
|
import { truncate } from "../util/truncate.js";
|
|
68
76
|
import { getWorkspaceGitService } from "../workspace/git-service.js";
|
|
69
77
|
import { commitTurnChanges } from "../workspace/turn-commit.js";
|
|
@@ -234,6 +242,7 @@ export interface AgentLoopConversationContext {
|
|
|
234
242
|
data: SurfaceData;
|
|
235
243
|
actions?: Array<{ id: string; label: string; style?: string }>;
|
|
236
244
|
display?: string;
|
|
245
|
+
persistent?: boolean;
|
|
237
246
|
}>;
|
|
238
247
|
|
|
239
248
|
workingDir: string;
|
|
@@ -246,6 +255,8 @@ export interface AgentLoopConversationContext {
|
|
|
246
255
|
currentTurnChannelCapabilities?: ChannelCapabilities;
|
|
247
256
|
commandIntent?: { type: string; payload?: string; languageCode?: string };
|
|
248
257
|
trustContext?: TrustContext;
|
|
258
|
+
/** Task-run scope for the current turn. Cleared at turn end so queued/drained turns don't inherit it. */
|
|
259
|
+
taskRunId?: string;
|
|
249
260
|
assistantId?: string;
|
|
250
261
|
voiceCallControlPrompt?: string;
|
|
251
262
|
transportHints?: string[];
|
|
@@ -541,6 +552,13 @@ export async function runAgentLoopImpl(
|
|
|
541
552
|
compacted.summaryText,
|
|
542
553
|
ctx.contextCompactedMessageCount,
|
|
543
554
|
);
|
|
555
|
+
// Fire auto-analysis on compaction so the reflective agent can
|
|
556
|
+
// crystallize anything worth remembering before the context window
|
|
557
|
+
// narrows further.
|
|
558
|
+
enqueueAutoAnalysisOnCompaction(
|
|
559
|
+
ctx.conversationId,
|
|
560
|
+
ctx.trustContext?.trustClass,
|
|
561
|
+
);
|
|
544
562
|
onEvent({
|
|
545
563
|
type: "context_compacted",
|
|
546
564
|
previousEstimatedInputTokens: compacted.previousEstimatedInputTokens,
|
|
@@ -773,14 +791,35 @@ export async function runAgentLoopImpl(
|
|
|
773
791
|
const isGuardian =
|
|
774
792
|
resolvedInboundActorContext?.trustClass === "guardian" ||
|
|
775
793
|
!resolvedInboundActorContext;
|
|
794
|
+
|
|
795
|
+
// Surface long gaps between user messages so the model can acknowledge
|
|
796
|
+
// the absence naturally. Gated at >12h to avoid noisy injection during
|
|
797
|
+
// normal back-and-forth turns.
|
|
798
|
+
const TWELVE_HOURS_MS = 12 * 60 * 60 * 1000;
|
|
799
|
+
let timeSinceLastMessage: string | null = null;
|
|
800
|
+
const currentUserMessage = getMessageById(userMessageId);
|
|
801
|
+
if (currentUserMessage) {
|
|
802
|
+
const prevUserTs = getLastUserTimestampBefore(
|
|
803
|
+
ctx.conversationId,
|
|
804
|
+
currentUserMessage.createdAt,
|
|
805
|
+
);
|
|
806
|
+
if (
|
|
807
|
+
prevUserTs > 0 &&
|
|
808
|
+
currentUserMessage.createdAt - prevUserTs > TWELVE_HOURS_MS
|
|
809
|
+
) {
|
|
810
|
+
timeSinceLastMessage = timeAgo(prevUserTs);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
776
814
|
const unifiedTurnContextStr = buildUnifiedTurnContextBlock(
|
|
777
815
|
isGuardian
|
|
778
|
-
? { timestamp, interfaceName, channelName }
|
|
816
|
+
? { timestamp, interfaceName, channelName, timeSinceLastMessage }
|
|
779
817
|
: {
|
|
780
818
|
timestamp,
|
|
781
819
|
interfaceName,
|
|
782
820
|
channelName,
|
|
783
821
|
actorContext: resolvedInboundActorContext,
|
|
822
|
+
timeSinceLastMessage,
|
|
784
823
|
},
|
|
785
824
|
);
|
|
786
825
|
|
|
@@ -908,6 +947,11 @@ export async function runAgentLoopImpl(
|
|
|
908
947
|
step.compactionResult.summaryText,
|
|
909
948
|
ctx.contextCompactedMessageCount,
|
|
910
949
|
);
|
|
950
|
+
// Fire auto-analysis on compaction — see forceCompact() for rationale.
|
|
951
|
+
enqueueAutoAnalysisOnCompaction(
|
|
952
|
+
ctx.conversationId,
|
|
953
|
+
ctx.trustContext?.trustClass,
|
|
954
|
+
);
|
|
911
955
|
onEvent({
|
|
912
956
|
type: "context_compacted",
|
|
913
957
|
previousEstimatedInputTokens:
|
|
@@ -945,8 +989,12 @@ export async function runAgentLoopImpl(
|
|
|
945
989
|
// value from injectionOpts to avoid duplicate injection.
|
|
946
990
|
runMessages = applyRuntimeInjections(ctx.messages, {
|
|
947
991
|
...injectionOpts,
|
|
948
|
-
...(step.compactionResult?.compacted && {
|
|
949
|
-
|
|
992
|
+
...(step.compactionResult?.compacted && {
|
|
993
|
+
pkbContext: currentPkbContent,
|
|
994
|
+
}),
|
|
995
|
+
...(step.compactionResult?.compacted && {
|
|
996
|
+
nowScratchpad: currentNowContent,
|
|
997
|
+
}),
|
|
950
998
|
workspaceTopLevelContext: shouldInjectWorkspace
|
|
951
999
|
? ctx.workspaceTopLevelContext
|
|
952
1000
|
: null,
|
|
@@ -1108,6 +1156,11 @@ export async function runAgentLoopImpl(
|
|
|
1108
1156
|
midLoopCompact.summaryText,
|
|
1109
1157
|
ctx.contextCompactedMessageCount,
|
|
1110
1158
|
);
|
|
1159
|
+
// Fire auto-analysis on compaction — see forceCompact() for rationale.
|
|
1160
|
+
enqueueAutoAnalysisOnCompaction(
|
|
1161
|
+
ctx.conversationId,
|
|
1162
|
+
ctx.trustContext?.trustClass,
|
|
1163
|
+
);
|
|
1111
1164
|
onEvent({
|
|
1112
1165
|
type: "context_compacted",
|
|
1113
1166
|
previousEstimatedInputTokens:
|
|
@@ -1151,8 +1204,7 @@ export async function runAgentLoopImpl(
|
|
|
1151
1204
|
mode: currentInjectionMode,
|
|
1152
1205
|
});
|
|
1153
1206
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
1154
|
-
|
|
1155
|
-
runMessages = memResult.runMessages;
|
|
1207
|
+
ctx.graphMemory.retrackCachedNodes();
|
|
1156
1208
|
}
|
|
1157
1209
|
preRepairMessages = runMessages;
|
|
1158
1210
|
preRunHistoryLength = runMessages.length;
|
|
@@ -1326,6 +1378,11 @@ export async function runAgentLoopImpl(
|
|
|
1326
1378
|
step.compactionResult.summaryText,
|
|
1327
1379
|
ctx.contextCompactedMessageCount,
|
|
1328
1380
|
);
|
|
1381
|
+
// Fire auto-analysis on compaction — see forceCompact() for rationale.
|
|
1382
|
+
enqueueAutoAnalysisOnCompaction(
|
|
1383
|
+
ctx.conversationId,
|
|
1384
|
+
ctx.trustContext?.trustClass,
|
|
1385
|
+
);
|
|
1329
1386
|
onEvent({
|
|
1330
1387
|
type: "context_compacted",
|
|
1331
1388
|
previousEstimatedInputTokens:
|
|
@@ -1370,8 +1427,7 @@ export async function runAgentLoopImpl(
|
|
|
1370
1427
|
mode: currentInjectionMode,
|
|
1371
1428
|
});
|
|
1372
1429
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
1373
|
-
|
|
1374
|
-
runMessages = memResult.runMessages;
|
|
1430
|
+
ctx.graphMemory.retrackCachedNodes();
|
|
1375
1431
|
}
|
|
1376
1432
|
preRepairMessages = runMessages;
|
|
1377
1433
|
preRunHistoryLength = runMessages.length;
|
|
@@ -1450,6 +1506,11 @@ export async function runAgentLoopImpl(
|
|
|
1450
1506
|
emergencyCompact.summaryText,
|
|
1451
1507
|
ctx.contextCompactedMessageCount,
|
|
1452
1508
|
);
|
|
1509
|
+
// Fire auto-analysis on compaction — see forceCompact() for rationale.
|
|
1510
|
+
enqueueAutoAnalysisOnCompaction(
|
|
1511
|
+
ctx.conversationId,
|
|
1512
|
+
ctx.trustContext?.trustClass,
|
|
1513
|
+
);
|
|
1453
1514
|
onEvent({
|
|
1454
1515
|
type: "context_compacted",
|
|
1455
1516
|
previousEstimatedInputTokens:
|
|
@@ -1493,9 +1554,7 @@ export async function runAgentLoopImpl(
|
|
|
1493
1554
|
mode: currentInjectionMode,
|
|
1494
1555
|
});
|
|
1495
1556
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
1496
|
-
|
|
1497
|
-
ctx.graphMemory.reinjectCachedMemory(runMessages);
|
|
1498
|
-
runMessages = memResult.runMessages;
|
|
1557
|
+
ctx.graphMemory.retrackCachedNodes();
|
|
1499
1558
|
}
|
|
1500
1559
|
preRepairMessages = runMessages;
|
|
1501
1560
|
preRunHistoryLength = runMessages.length;
|
|
@@ -1570,6 +1629,11 @@ export async function runAgentLoopImpl(
|
|
|
1570
1629
|
emergencyCompact.summaryText,
|
|
1571
1630
|
ctx.contextCompactedMessageCount,
|
|
1572
1631
|
);
|
|
1632
|
+
// Fire auto-analysis on compaction — see forceCompact() for rationale.
|
|
1633
|
+
enqueueAutoAnalysisOnCompaction(
|
|
1634
|
+
ctx.conversationId,
|
|
1635
|
+
ctx.trustContext?.trustClass,
|
|
1636
|
+
);
|
|
1573
1637
|
onEvent({
|
|
1574
1638
|
type: "context_compacted",
|
|
1575
1639
|
previousEstimatedInputTokens:
|
|
@@ -1613,8 +1677,7 @@ export async function runAgentLoopImpl(
|
|
|
1613
1677
|
mode: currentInjectionMode,
|
|
1614
1678
|
});
|
|
1615
1679
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
1616
|
-
|
|
1617
|
-
runMessages = memResult.runMessages;
|
|
1680
|
+
ctx.graphMemory.retrackCachedNodes();
|
|
1618
1681
|
}
|
|
1619
1682
|
preRepairMessages = runMessages;
|
|
1620
1683
|
preRunHistoryLength = runMessages.length;
|
|
@@ -1753,9 +1816,16 @@ export async function runAgentLoopImpl(
|
|
|
1753
1816
|
try {
|
|
1754
1817
|
const conv = getConversation(ctx.conversationId);
|
|
1755
1818
|
if (conv) {
|
|
1756
|
-
const convDir = getResolvedConversationDirPath(
|
|
1757
|
-
|
|
1758
|
-
|
|
1819
|
+
const convDir = getResolvedConversationDirPath(
|
|
1820
|
+
ctx.conversationId,
|
|
1821
|
+
conv.createdAt,
|
|
1822
|
+
);
|
|
1823
|
+
const { messages: derefMessages, dereferencedCount } =
|
|
1824
|
+
derefToolResultReReads(restoredHistory);
|
|
1825
|
+
const { messages: truncatedMessages, truncatedCount } =
|
|
1826
|
+
postTurnTruncateToolResults(derefMessages, {
|
|
1827
|
+
conversationDir: convDir,
|
|
1828
|
+
});
|
|
1759
1829
|
if (truncatedCount > 0 || dereferencedCount > 0) {
|
|
1760
1830
|
rlog.info(
|
|
1761
1831
|
{ truncatedCount, dereferencedCount },
|
|
@@ -1765,16 +1835,13 @@ export async function runAgentLoopImpl(
|
|
|
1765
1835
|
restoredHistory = truncatedMessages;
|
|
1766
1836
|
}
|
|
1767
1837
|
} catch (err) {
|
|
1768
|
-
rlog.warn(
|
|
1838
|
+
rlog.warn(
|
|
1839
|
+
{ err },
|
|
1840
|
+
"Post-turn tool result truncation failed (non-fatal)",
|
|
1841
|
+
);
|
|
1769
1842
|
}
|
|
1770
1843
|
}
|
|
1771
1844
|
|
|
1772
|
-
const postLoopContextEstimate = estimatePromptTokens(
|
|
1773
|
-
restoredHistory,
|
|
1774
|
-
ctx.systemPrompt,
|
|
1775
|
-
{ providerName: ctx.provider.name, toolTokenBudget },
|
|
1776
|
-
);
|
|
1777
|
-
|
|
1778
1845
|
// Persist injections in history: runtime-injected context stays on
|
|
1779
1846
|
// historical user messages so the conversation prefix is stable for
|
|
1780
1847
|
// Anthropic's prefix caching. Stripping only happens during
|
|
@@ -1795,7 +1862,7 @@ export async function runAgentLoopImpl(
|
|
|
1795
1862
|
state.exchangeProviderName,
|
|
1796
1863
|
state.exchangeLlmCallCount,
|
|
1797
1864
|
{
|
|
1798
|
-
tokens:
|
|
1865
|
+
tokens: state.lastCallInputTokens,
|
|
1799
1866
|
maxTokens: config.contextWindow.maxInputTokens,
|
|
1800
1867
|
},
|
|
1801
1868
|
);
|
|
@@ -2014,6 +2081,12 @@ export async function runAgentLoopImpl(
|
|
|
2014
2081
|
|
|
2015
2082
|
// Commit app changes (fire-and-forget — apps repo is separate from workspace)
|
|
2016
2083
|
void commitAppTurnChanges(ctx.conversationId, ctx.turnCount);
|
|
2084
|
+
|
|
2085
|
+
// Recompute relationship-state.json at turn boundary (fire-and-forget).
|
|
2086
|
+
// The writer swallows its own errors, but we still guard with catch()
|
|
2087
|
+
// here so a regression in the writer can never bubble out of the
|
|
2088
|
+
// agent loop and reject an otherwise-complete turn.
|
|
2089
|
+
void writeRelationshipState().catch(() => {});
|
|
2017
2090
|
}
|
|
2018
2091
|
|
|
2019
2092
|
ctx.profiler.emitSummary(ctx.traceEmitter, reqId);
|
|
@@ -2029,6 +2102,10 @@ export async function runAgentLoopImpl(
|
|
|
2029
2102
|
// Channel command intents (e.g. Telegram /start) are single-turn metadata.
|
|
2030
2103
|
// Clear at turn end so they never leak into subsequent unrelated messages.
|
|
2031
2104
|
ctx.commandIntent = undefined;
|
|
2105
|
+
// taskRunId scopes ephemeral task-run permissions to a single turn. Clear
|
|
2106
|
+
// before drainQueue so queued/drained turns on a reused conversation can't
|
|
2107
|
+
// inherit stale in-task-run scope from the turn that just finished.
|
|
2108
|
+
ctx.taskRunId = undefined;
|
|
2032
2109
|
|
|
2033
2110
|
// Consolidation deferred to compaction: keeping assistant + tool_result
|
|
2034
2111
|
// messages unconsolidated preserves the exact message structure sent to
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getProviderRoutingSource } from "../providers/registry.js";
|
|
2
|
+
import { isAbortReason } from "../util/abort-reasons.js";
|
|
2
3
|
import { ProviderError, ProviderNotConfiguredError } from "../util/errors.js";
|
|
3
4
|
import type {
|
|
4
5
|
ConversationErrorCode,
|
|
@@ -110,11 +111,21 @@ export interface ErrorContext {
|
|
|
110
111
|
* Returns true if the error looks like a user-initiated cancellation
|
|
111
112
|
* (AbortError or explicit cancel). These should use `generation_cancelled`
|
|
112
113
|
* instead of `conversation_error`.
|
|
114
|
+
*
|
|
115
|
+
* Provider SDKs wrap the underlying AbortError in their own error class
|
|
116
|
+
* (e.g. `ProviderError("Anthropic API error (undefined): Request was aborted.")`),
|
|
117
|
+
* which erases the `AbortError` name. To compensate, the daemon tags every
|
|
118
|
+
* `controller.abort(reason)` call with an `AbortReason` object — when the
|
|
119
|
+
* wrapped `ProviderError` carries that tagged reason, we treat it as a user
|
|
120
|
+
* cancellation regardless of error class.
|
|
113
121
|
*/
|
|
114
122
|
export function isUserCancellation(error: unknown, ctx: ErrorContext): boolean {
|
|
115
123
|
if (!ctx.aborted) return false;
|
|
116
124
|
if (error instanceof DOMException && error.name === "AbortError") return true;
|
|
117
125
|
if (error instanceof Error && error.name === "AbortError") return true;
|
|
126
|
+
if (error instanceof ProviderError && isAbortReason(error.abortReason)) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
118
129
|
return false;
|
|
119
130
|
}
|
|
120
131
|
|
|
@@ -15,6 +15,7 @@ import { withQdrantBreaker } from "../memory/qdrant-circuit-breaker.js";
|
|
|
15
15
|
import { getQdrantClient } from "../memory/qdrant-client.js";
|
|
16
16
|
import type { ContentBlock, Message } from "../providers/types.js";
|
|
17
17
|
import { getLogger } from "../util/logger.js";
|
|
18
|
+
import { truncate } from "../util/truncate.js";
|
|
18
19
|
import type { ServerMessage } from "./message-protocol.js";
|
|
19
20
|
import type { TraceEmitter } from "./trace-emitter.js";
|
|
20
21
|
|
|
@@ -564,10 +565,43 @@ export async function regenerate(
|
|
|
564
565
|
// in both this.messages and the DB.
|
|
565
566
|
conversation.processing = true;
|
|
566
567
|
conversation.abortController = new AbortController();
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
568
|
+
const resolvedRequestId = requestId ?? uuid();
|
|
569
|
+
conversation.currentRequestId = resolvedRequestId;
|
|
570
|
+
|
|
571
|
+
// Fire-and-forget: matches the /v1/messages pattern so the HTTP handler
|
|
572
|
+
// returns 202 immediately rather than blocking on the full agent turn.
|
|
573
|
+
// Otherwise the client's 15s POST timeout fires on any non-trivial
|
|
574
|
+
// regenerate and surfaces a misleading "Failed to regenerate message"
|
|
575
|
+
// banner even though the response streams in normally via SSE.
|
|
576
|
+
//
|
|
577
|
+
// runAgentLoop catches most errors internally and emits `request_error`
|
|
578
|
+
// itself, but anything thrown from its `finally` block (commit, drain,
|
|
579
|
+
// profiler) would otherwise escape silently because the caller does
|
|
580
|
+
// not await the agent loop. Emit a structured trace event so the
|
|
581
|
+
// observability contract is preserved on those paths too.
|
|
582
|
+
void conversation
|
|
583
|
+
.runAgentLoop(content, existingUserMessageId, onEvent, {
|
|
584
|
+
skipPreMessageRollback: true,
|
|
585
|
+
isUserMessage: true,
|
|
586
|
+
})
|
|
587
|
+
.catch((err) => {
|
|
588
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
589
|
+
log.error(
|
|
590
|
+
{ err, conversationId: conversation.conversationId },
|
|
591
|
+
"runAgentLoop after regenerate failed",
|
|
592
|
+
);
|
|
593
|
+
conversation.traceEmitter.emit(
|
|
594
|
+
"request_error",
|
|
595
|
+
truncate(message, 200, ""),
|
|
596
|
+
{
|
|
597
|
+
requestId: resolvedRequestId,
|
|
598
|
+
status: "error",
|
|
599
|
+
attributes: {
|
|
600
|
+
errorClass: err instanceof Error ? err.constructor.name : "Error",
|
|
601
|
+
message: truncate(message, 500, ""),
|
|
602
|
+
source: "regenerate_fire_and_forget",
|
|
603
|
+
},
|
|
604
|
+
},
|
|
605
|
+
);
|
|
606
|
+
});
|
|
573
607
|
}
|