@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
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared state for the cleanup-scheduler throttle.
|
|
3
|
+
*
|
|
4
|
+
* `maybeEnqueueScheduledCleanupJobs` in jobs-worker.ts gates cleanup-job
|
|
5
|
+
* enqueueing behind a 6-hour window (configurable via
|
|
6
|
+
* memory.cleanup.enqueueIntervalMs). This module owns the "last enqueue"
|
|
7
|
+
* timestamp so that code paths outside jobs-worker — notably
|
|
8
|
+
* ConfigWatcher.refreshConfigFromSources — can reset the throttle without
|
|
9
|
+
* pulling in jobs-worker's large transitive import graph.
|
|
10
|
+
*
|
|
11
|
+
* The ConfigWatcher uses resetCleanupScheduleThrottle() to ensure that
|
|
12
|
+
* retention changes made via the UI (which flow through config.json →
|
|
13
|
+
* invalidateConfigCache → refreshConfigFromSources) take effect on the
|
|
14
|
+
* very next scheduler tick instead of waiting out the remaining window.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
let lastScheduledCleanupEnqueueMs = 0;
|
|
18
|
+
|
|
19
|
+
/** Read the timestamp of the most recent enqueue (0 if never/reset). */
|
|
20
|
+
export function getLastScheduledCleanupEnqueueMs(): number {
|
|
21
|
+
return lastScheduledCleanupEnqueueMs;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Record that an enqueue just happened at `nowMs`. */
|
|
25
|
+
export function markScheduledCleanupEnqueued(nowMs: number): void {
|
|
26
|
+
lastScheduledCleanupEnqueueMs = nowMs;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Clear the throttle so the next `maybeEnqueueScheduledCleanupJobs` call
|
|
31
|
+
* bypasses the `enqueueIntervalMs` window. Used by ConfigWatcher when
|
|
32
|
+
* retention settings change, and by tests that need deterministic
|
|
33
|
+
* scheduling.
|
|
34
|
+
*/
|
|
35
|
+
export function resetCleanupScheduleThrottle(): void {
|
|
36
|
+
lastScheduledCleanupEnqueueMs = 0;
|
|
37
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Auto-analyze — conversation_analyze job handler
|
|
3
|
+
//
|
|
4
|
+
// Bridges the jobs worker to the shared analyzeConversation() service. The
|
|
5
|
+
// deps bundle is stashed on a module singleton during daemon startup; if it
|
|
6
|
+
// isn't set yet we skip this iteration. The next batch / idle / lifecycle
|
|
7
|
+
// trigger from `enqueueAutoAnalysisIfEnabled()` will produce a fresh job
|
|
8
|
+
// once the daemon has fully started.
|
|
9
|
+
//
|
|
10
|
+
// The service itself distinguishes manual vs. auto triggers: this handler
|
|
11
|
+
// always invokes with `trigger: "auto"`, so the rolling analysis conversation
|
|
12
|
+
// logic and recursion guard apply.
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
import type { AssistantConfig } from "../config/types.js";
|
|
16
|
+
import { analyzeConversation } from "../runtime/services/analyze-conversation.js";
|
|
17
|
+
import { getAnalysisDeps } from "../runtime/services/analyze-deps-singleton.js";
|
|
18
|
+
import { getLogger } from "../util/logger.js";
|
|
19
|
+
import { enqueueAutoAnalysisIfEnabled } from "./auto-analysis-enqueue.js";
|
|
20
|
+
import type { MemoryJob } from "./jobs-store.js";
|
|
21
|
+
|
|
22
|
+
const log = getLogger("conversation-analyze-job");
|
|
23
|
+
|
|
24
|
+
export async function conversationAnalyzeJob(
|
|
25
|
+
job: MemoryJob<{ conversationId?: string }>,
|
|
26
|
+
_config: AssistantConfig,
|
|
27
|
+
): Promise<void> {
|
|
28
|
+
const { conversationId } = job.payload;
|
|
29
|
+
if (!conversationId) {
|
|
30
|
+
log.warn({ jobId: job.id }, "Skipping job: missing conversationId");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const deps = getAnalysisDeps();
|
|
35
|
+
if (!deps) {
|
|
36
|
+
// Daemon hasn't finished startup. Return without throwing — a plain
|
|
37
|
+
// Error here would be classified as fatal by `classifyError()` and the
|
|
38
|
+
// worker would mark the job permanently failed. Throwing
|
|
39
|
+
// `BackendUnavailableError` would defer, but defer counters cap out and
|
|
40
|
+
// would still permanently fail in the worst case. Since
|
|
41
|
+
// `enqueueAutoAnalysisIfEnabled()` re-enqueues on the next batch / idle
|
|
42
|
+
// / lifecycle trigger, dropping this iteration is the safest choice and
|
|
43
|
+
// avoids retry storms during slow daemon startup.
|
|
44
|
+
log.warn(
|
|
45
|
+
{ jobId: job.id, conversationId },
|
|
46
|
+
"Skipping job: analysis deps not yet initialized; will retrigger",
|
|
47
|
+
);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const result = await analyzeConversation(conversationId, deps, {
|
|
52
|
+
trigger: "auto",
|
|
53
|
+
});
|
|
54
|
+
if ("error" in result) {
|
|
55
|
+
log.warn(
|
|
56
|
+
{ jobId: job.id, conversationId, error: result.error },
|
|
57
|
+
"Auto-analysis service rejected source conversation",
|
|
58
|
+
);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (result.skipped) {
|
|
62
|
+
// The rolling analysis conversation was still processing a prior run, so
|
|
63
|
+
// this invocation was a no-op. Schedule a debounced follow-up ourselves
|
|
64
|
+
// — otherwise, if no later batch/idle/lifecycle trigger arrives (e.g.
|
|
65
|
+
// the conversation goes quiet after a long in-flight analysis), new
|
|
66
|
+
// source messages would stay un-analyzed indefinitely.
|
|
67
|
+
enqueueAutoAnalysisIfEnabled({ conversationId, trigger: "idle" });
|
|
68
|
+
log.debug(
|
|
69
|
+
{ jobId: job.id, conversationId },
|
|
70
|
+
"Auto-analysis skipped (rolling conversation busy); requeued follow-up",
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
deleteOrphanAttachments,
|
|
31
31
|
linkAttachmentToMessage,
|
|
32
32
|
} from "./attachments-store.js";
|
|
33
|
+
import { AUTO_ANALYSIS_SOURCE } from "./auto-analysis-guard.js";
|
|
33
34
|
import {
|
|
34
35
|
projectAssistantMessage,
|
|
35
36
|
seedForkedConversationAttention,
|
|
@@ -174,6 +175,7 @@ export interface ConversationRow {
|
|
|
174
175
|
isAutoTitle: number;
|
|
175
176
|
scheduleJobId: string | null;
|
|
176
177
|
lastMessageAt: number | null;
|
|
178
|
+
archivedAt: number | null;
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
export const parseConversation = createRowMapper<
|
|
@@ -201,6 +203,7 @@ export const parseConversation = createRowMapper<
|
|
|
201
203
|
isAutoTitle: "isAutoTitle",
|
|
202
204
|
scheduleJobId: "scheduleJobId",
|
|
203
205
|
lastMessageAt: "lastMessageAt",
|
|
206
|
+
archivedAt: "archivedAt",
|
|
204
207
|
});
|
|
205
208
|
|
|
206
209
|
export interface MessageRow {
|
|
@@ -248,6 +251,7 @@ export function createConversation(
|
|
|
248
251
|
scheduleJobId?: string;
|
|
249
252
|
groupId?: string;
|
|
250
253
|
hostAccess?: boolean;
|
|
254
|
+
forkParentConversationId?: string;
|
|
251
255
|
},
|
|
252
256
|
) {
|
|
253
257
|
const db = getDb();
|
|
@@ -284,6 +288,7 @@ export function createConversation(
|
|
|
284
288
|
source,
|
|
285
289
|
memoryScopeId,
|
|
286
290
|
scheduleJobId: opts.scheduleJobId ?? null,
|
|
291
|
+
forkParentConversationId: opts.forkParentConversationId ?? null,
|
|
287
292
|
};
|
|
288
293
|
|
|
289
294
|
// Retry on SQLITE_BUSY and SQLITE_IOERR — transient disk I/O errors or WAL
|
|
@@ -379,6 +384,54 @@ export function countConversationsByScheduleJobId(
|
|
|
379
384
|
);
|
|
380
385
|
}
|
|
381
386
|
|
|
387
|
+
/**
|
|
388
|
+
* Find the rolling analysis conversation for a given source conversation,
|
|
389
|
+
* or null if none exists yet. Used by the auto-analyze loop to append
|
|
390
|
+
* to an existing analysis conversation rather than creating a new one
|
|
391
|
+
* each time the analyze job fires.
|
|
392
|
+
*
|
|
393
|
+
* Returns the most recently updated match if multiple exist (defensive —
|
|
394
|
+
* shouldn't happen in normal operation but the contract is well-defined).
|
|
395
|
+
*
|
|
396
|
+
* Hits `idx_conversations_fork_parent_conversation_id` for the
|
|
397
|
+
* `forkParentConversationId` lookup.
|
|
398
|
+
*/
|
|
399
|
+
export function findAnalysisConversationFor(
|
|
400
|
+
parentConversationId: string,
|
|
401
|
+
): { id: string } | null {
|
|
402
|
+
const db = getDb();
|
|
403
|
+
const row = db
|
|
404
|
+
.select({ id: conversations.id })
|
|
405
|
+
.from(conversations)
|
|
406
|
+
.where(
|
|
407
|
+
and(
|
|
408
|
+
eq(conversations.source, AUTO_ANALYSIS_SOURCE),
|
|
409
|
+
eq(conversations.forkParentConversationId, parentConversationId),
|
|
410
|
+
),
|
|
411
|
+
)
|
|
412
|
+
.orderBy(desc(conversations.updatedAt))
|
|
413
|
+
.limit(1)
|
|
414
|
+
.get();
|
|
415
|
+
return row ? { id: row.id } : null;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Returns the `source` column for the given conversation, or null if
|
|
420
|
+
* not found. Tiny convenience used by the recursion guard in the
|
|
421
|
+
* auto-analyze loop.
|
|
422
|
+
*/
|
|
423
|
+
export function getConversationSource(
|
|
424
|
+
conversationId: string,
|
|
425
|
+
): string | null {
|
|
426
|
+
const db = getDb();
|
|
427
|
+
const row = db
|
|
428
|
+
.select({ source: conversations.source })
|
|
429
|
+
.from(conversations)
|
|
430
|
+
.where(eq(conversations.id, conversationId))
|
|
431
|
+
.get();
|
|
432
|
+
return row?.source ?? null;
|
|
433
|
+
}
|
|
434
|
+
|
|
382
435
|
export function getConversationType(
|
|
383
436
|
conversationId: string,
|
|
384
437
|
): "standard" | "private" {
|
|
@@ -1062,6 +1115,27 @@ export function getLastAssistantTimestampBefore(
|
|
|
1062
1115
|
return row?.createdAt ?? 0;
|
|
1063
1116
|
}
|
|
1064
1117
|
|
|
1118
|
+
export function getLastUserTimestampBefore(
|
|
1119
|
+
conversationId: string,
|
|
1120
|
+
beforeTimestamp: number,
|
|
1121
|
+
): number {
|
|
1122
|
+
const db = getDb();
|
|
1123
|
+
const row = db
|
|
1124
|
+
.select({ createdAt: messages.createdAt })
|
|
1125
|
+
.from(messages)
|
|
1126
|
+
.where(
|
|
1127
|
+
and(
|
|
1128
|
+
eq(messages.conversationId, conversationId),
|
|
1129
|
+
eq(messages.role, "user"),
|
|
1130
|
+
lt(messages.createdAt, beforeTimestamp),
|
|
1131
|
+
),
|
|
1132
|
+
)
|
|
1133
|
+
.orderBy(desc(messages.createdAt))
|
|
1134
|
+
.limit(1)
|
|
1135
|
+
.get();
|
|
1136
|
+
return row?.createdAt ?? 0;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1065
1139
|
/** Fetch a single message by ID, optionally scoped to a specific conversation. */
|
|
1066
1140
|
export function getMessageById(
|
|
1067
1141
|
messageId: string,
|
|
@@ -1146,6 +1220,31 @@ export function updateConversationHostAccess(
|
|
|
1146
1220
|
.run();
|
|
1147
1221
|
}
|
|
1148
1222
|
|
|
1223
|
+
export function archiveConversation(id: string): boolean {
|
|
1224
|
+
const conv = getConversation(id);
|
|
1225
|
+
if (!conv) return false;
|
|
1226
|
+
const now = Date.now();
|
|
1227
|
+
rawRun(
|
|
1228
|
+
"UPDATE conversations SET archived_at = ?, updated_at = ? WHERE id = ?",
|
|
1229
|
+
now,
|
|
1230
|
+
now,
|
|
1231
|
+
id,
|
|
1232
|
+
);
|
|
1233
|
+
return true;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
export function unarchiveConversation(id: string): boolean {
|
|
1237
|
+
const conv = getConversation(id);
|
|
1238
|
+
if (!conv) return false;
|
|
1239
|
+
const now = Date.now();
|
|
1240
|
+
rawRun(
|
|
1241
|
+
"UPDATE conversations SET archived_at = NULL, updated_at = ? WHERE id = ?",
|
|
1242
|
+
now,
|
|
1243
|
+
id,
|
|
1244
|
+
);
|
|
1245
|
+
return true;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1149
1248
|
/**
|
|
1150
1249
|
* Delete all conversations, messages, and related data (tool invocations,
|
|
1151
1250
|
* memory segments, etc.) from the daemon database.
|
|
@@ -310,6 +310,13 @@ export function syncMessageToDisk(
|
|
|
310
310
|
if (toolResults.length > 0) record.toolResults = toolResults;
|
|
311
311
|
if (attachmentFilenames.length > 0)
|
|
312
312
|
record.attachments = attachmentFilenames;
|
|
313
|
+
if (message.metadata) {
|
|
314
|
+
try {
|
|
315
|
+
record.metadata = JSON.parse(message.metadata);
|
|
316
|
+
} catch {
|
|
317
|
+
// Invalid JSON — omit metadata from disk record
|
|
318
|
+
}
|
|
319
|
+
}
|
|
313
320
|
|
|
314
321
|
appendFileSync(
|
|
315
322
|
join(dirPath, "messages.jsonl"),
|
|
@@ -57,7 +57,11 @@ export function ensureGroupMigration(): void {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
// 3. Seed system groups
|
|
60
|
+
// 3. Seed system groups.
|
|
61
|
+
//
|
|
62
|
+
// `system:reflections` is a legacy group kept for backward compatibility
|
|
63
|
+
// with existing installations. New auto-analysis conversations are assigned
|
|
64
|
+
// to `system:background`; the migration in step 6 moves existing ones.
|
|
61
65
|
const now = Math.floor(Date.now() / 1000);
|
|
62
66
|
rawExec(`
|
|
63
67
|
INSERT OR IGNORE INTO conversation_groups (id, name, sort_position, is_system_group, created_at, updated_at)
|
|
@@ -65,7 +69,8 @@ export function ensureGroupMigration(): void {
|
|
|
65
69
|
('system:pinned', 'Pinned', 0, TRUE, ${now}, ${now}),
|
|
66
70
|
('system:scheduled', 'Scheduled', 1, TRUE, ${now}, ${now}),
|
|
67
71
|
('system:background', 'Background', 2, TRUE, ${now}, ${now}),
|
|
68
|
-
('system:all', 'Recents', 3, TRUE, ${now}, ${now})
|
|
72
|
+
('system:all', 'Recents', 3, TRUE, ${now}, ${now}),
|
|
73
|
+
('system:reflections', 'Reflections', 100, TRUE, ${now}, ${now})
|
|
69
74
|
`);
|
|
70
75
|
|
|
71
76
|
// One-time migration: move system:all to sortPosition 3 (from 999999).
|
|
@@ -213,5 +218,32 @@ export function ensureGroupMigration(): void {
|
|
|
213
218
|
}
|
|
214
219
|
}
|
|
215
220
|
|
|
221
|
+
// 6. One-time migration: move auto-analysis conversations from system:reflections to system:background
|
|
222
|
+
const reflectionsMigrateDone = rawGet<{ id: string }>(
|
|
223
|
+
"SELECT id FROM conversation_groups WHERE id = '_reflections_to_background_complete'",
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
if (!reflectionsMigrateDone) {
|
|
227
|
+
try {
|
|
228
|
+
rawExec("BEGIN");
|
|
229
|
+
|
|
230
|
+
rawExec(`
|
|
231
|
+
UPDATE conversations SET group_id = 'system:background'
|
|
232
|
+
WHERE group_id = 'system:reflections'
|
|
233
|
+
`);
|
|
234
|
+
|
|
235
|
+
rawExec(`
|
|
236
|
+
INSERT OR IGNORE INTO conversation_groups (id, name, sort_position, is_system_group)
|
|
237
|
+
VALUES ('_reflections_to_background_complete', '_reflections_to_background_complete', -1, TRUE)
|
|
238
|
+
`);
|
|
239
|
+
|
|
240
|
+
rawExec("COMMIT");
|
|
241
|
+
} catch (err) {
|
|
242
|
+
rawExec("ROLLBACK");
|
|
243
|
+
log.error({ err }, "reflections-to-background migration failed, rolled back");
|
|
244
|
+
throw err;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
216
248
|
migrated = true;
|
|
217
249
|
}
|
|
@@ -218,7 +218,7 @@ export function searchConversations(
|
|
|
218
218
|
FROM messages_fts f
|
|
219
219
|
JOIN messages m ON m.id = f.message_id
|
|
220
220
|
JOIN conversations c ON c.id = m.conversation_id
|
|
221
|
-
WHERE messages_fts MATCH ? AND c.conversation_type NOT IN ('background', 'private', 'scheduled')
|
|
221
|
+
WHERE messages_fts MATCH ? AND c.conversation_type NOT IN ('background', 'private', 'scheduled') AND c.archived_at IS NULL
|
|
222
222
|
LIMIT 1000
|
|
223
223
|
`,
|
|
224
224
|
ftsMatch,
|
|
@@ -243,7 +243,7 @@ export function searchConversations(
|
|
|
243
243
|
SELECT DISTINCT m.conversation_id
|
|
244
244
|
FROM messages m
|
|
245
245
|
JOIN conversations c ON c.id = m.conversation_id
|
|
246
|
-
WHERE m.content LIKE ? ESCAPE '\\' AND c.conversation_type NOT IN ('background', 'private', 'scheduled')
|
|
246
|
+
WHERE m.content LIKE ? ESCAPE '\\' AND c.conversation_type NOT IN ('background', 'private', 'scheduled') AND c.archived_at IS NULL
|
|
247
247
|
LIMIT 1000
|
|
248
248
|
`,
|
|
249
249
|
likePattern,
|
|
@@ -257,9 +257,10 @@ export function searchConversations(
|
|
|
257
257
|
.from(conversations)
|
|
258
258
|
.where(
|
|
259
259
|
and(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
sql`${conversations.conversationType} NOT IN ('background', 'private', 'scheduled')`,
|
|
261
|
+
sql`${conversations.title} LIKE ${titlePattern} ESCAPE '\\'`,
|
|
262
|
+
sql`${conversations.archivedAt} IS NULL`,
|
|
263
|
+
),
|
|
263
264
|
)
|
|
264
265
|
.all();
|
|
265
266
|
for (const row of titleMatchConvs) ftsConvIds.add(row.id);
|
package/src/memory/db-init.ts
CHANGED
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
migrateContactsUserFileColumn,
|
|
60
60
|
migrateConversationForkLineage,
|
|
61
61
|
migrateConversationHostAccess,
|
|
62
|
+
migrateConversationsArchivedAt,
|
|
62
63
|
migrateConversationsLastMessageAt,
|
|
63
64
|
migrateConversationsThreadTypeIndex,
|
|
64
65
|
migrateCreateConversationGraphMemoryState,
|
|
@@ -106,6 +107,7 @@ import {
|
|
|
106
107
|
migrateMessagesConversationCreatedAtIndex,
|
|
107
108
|
migrateMessagesFtsBackfill,
|
|
108
109
|
migrateNormalizePhoneIdentities,
|
|
110
|
+
migrateNormalizeUserFileByPrincipal,
|
|
109
111
|
migrateNotificationDeliveryThreadDecision,
|
|
110
112
|
migrateOAuthAppsClientSecretPath,
|
|
111
113
|
migrateOAuthProvidersBehaviorColumns,
|
|
@@ -119,6 +121,7 @@ import {
|
|
|
119
121
|
migrateOAuthProvidersRevoke,
|
|
120
122
|
migrateOAuthProvidersScopeSeparator,
|
|
121
123
|
migrateOAuthProvidersTokenAuthMethodDefault,
|
|
124
|
+
migrateOAuthProvidersTokenExchangeBodyFormat,
|
|
122
125
|
migrateReminderRoutingIntent,
|
|
123
126
|
migrateRemindersToSchedules,
|
|
124
127
|
migrateRenameConversationTypeColumn,
|
|
@@ -364,6 +367,9 @@ export function initializeDb(): void {
|
|
|
364
367
|
migrateOAuthProvidersTokenAuthMethodDefault,
|
|
365
368
|
migrateConversationHostAccess,
|
|
366
369
|
migrateOAuthProvidersLogoUrl,
|
|
370
|
+
migrateOAuthProvidersTokenExchangeBodyFormat,
|
|
371
|
+
migrateNormalizeUserFileByPrincipal,
|
|
372
|
+
migrateConversationsArchivedAt,
|
|
367
373
|
];
|
|
368
374
|
|
|
369
375
|
// Run each migration step, catching and logging individual failures so one
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { statSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { getLogger } from "../util/logger.js";
|
|
4
|
+
import { getDbPath } from "../util/platform.js";
|
|
5
|
+
import { getMemoryCheckpoint, setMemoryCheckpoint } from "./checkpoints.js";
|
|
6
|
+
import { getSqlite } from "./db-connection.js";
|
|
7
|
+
|
|
8
|
+
const log = getLogger("db-maintenance");
|
|
9
|
+
|
|
10
|
+
const DB_MAINTENANCE_CHECKPOINT_KEY = "db_maintenance:last_run";
|
|
11
|
+
const DB_MAINTENANCE_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
12
|
+
|
|
13
|
+
interface DbStats {
|
|
14
|
+
pageSizeBytes: number;
|
|
15
|
+
pageCount: number;
|
|
16
|
+
freelistCount: number;
|
|
17
|
+
fileSizeBytes: number | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getDbStats(): DbStats {
|
|
21
|
+
const sqlite = getSqlite();
|
|
22
|
+
const pageSizeBytes = (
|
|
23
|
+
sqlite.query("PRAGMA page_size").get() as { page_size: number }
|
|
24
|
+
).page_size;
|
|
25
|
+
const pageCount = (
|
|
26
|
+
sqlite.query("PRAGMA page_count").get() as { page_count: number }
|
|
27
|
+
).page_count;
|
|
28
|
+
const freelistCount = (
|
|
29
|
+
sqlite.query("PRAGMA freelist_count").get() as { freelist_count: number }
|
|
30
|
+
).freelist_count;
|
|
31
|
+
let fileSizeBytes: number | null = null;
|
|
32
|
+
try {
|
|
33
|
+
fileSizeBytes = statSync(getDbPath()).size;
|
|
34
|
+
} catch {
|
|
35
|
+
/* non-fatal */
|
|
36
|
+
}
|
|
37
|
+
return { pageSizeBytes, pageCount, freelistCount, fileSizeBytes };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function runDbMaintenance(): void {
|
|
41
|
+
const before = getDbStats();
|
|
42
|
+
const freelistPct =
|
|
43
|
+
before.pageCount > 0
|
|
44
|
+
? ((before.freelistCount / before.pageCount) * 100).toFixed(1)
|
|
45
|
+
: "0";
|
|
46
|
+
|
|
47
|
+
log.info(
|
|
48
|
+
{
|
|
49
|
+
pageCount: before.pageCount,
|
|
50
|
+
freelistCount: before.freelistCount,
|
|
51
|
+
freelistPct,
|
|
52
|
+
fileSizeBytes: before.fileSizeBytes,
|
|
53
|
+
},
|
|
54
|
+
"Starting database maintenance",
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
getSqlite().exec("VACUUM");
|
|
59
|
+
} catch (err) {
|
|
60
|
+
log.warn({ err }, "VACUUM failed (non-fatal)");
|
|
61
|
+
try {
|
|
62
|
+
getSqlite().exec("PRAGMA optimize");
|
|
63
|
+
} catch (optErr) {
|
|
64
|
+
log.warn({ err: optErr }, "PRAGMA optimize failed (non-fatal)");
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
getSqlite().exec("PRAGMA optimize");
|
|
71
|
+
} catch (err) {
|
|
72
|
+
log.warn({ err }, "PRAGMA optimize failed (non-fatal)");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const after = getDbStats();
|
|
76
|
+
const reclaimedPages = before.pageCount - after.pageCount;
|
|
77
|
+
const reclaimedBytes =
|
|
78
|
+
before.fileSizeBytes != null && after.fileSizeBytes != null
|
|
79
|
+
? before.fileSizeBytes - after.fileSizeBytes
|
|
80
|
+
: null;
|
|
81
|
+
|
|
82
|
+
log.info(
|
|
83
|
+
{
|
|
84
|
+
beforePageCount: before.pageCount,
|
|
85
|
+
afterPageCount: after.pageCount,
|
|
86
|
+
reclaimedPages,
|
|
87
|
+
reclaimedBytes,
|
|
88
|
+
afterFileSizeBytes: after.fileSizeBytes,
|
|
89
|
+
},
|
|
90
|
+
"Database maintenance complete",
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function maybeRunDbMaintenance(nowMs = Date.now()): void {
|
|
95
|
+
const lastRun = parseInt(
|
|
96
|
+
getMemoryCheckpoint(DB_MAINTENANCE_CHECKPOINT_KEY) ?? "0",
|
|
97
|
+
10,
|
|
98
|
+
);
|
|
99
|
+
if (nowMs - lastRun < DB_MAINTENANCE_INTERVAL_MS) return;
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
runDbMaintenance();
|
|
103
|
+
} catch (err) {
|
|
104
|
+
log.error({ err }, "Database maintenance failed unexpectedly");
|
|
105
|
+
}
|
|
106
|
+
// Always set checkpoint — even on failure — to avoid retry-hammering every tick.
|
|
107
|
+
setMemoryCheckpoint(DB_MAINTENANCE_CHECKPOINT_KEY, String(nowMs));
|
|
108
|
+
}
|
package/src/memory/db.ts
CHANGED
|
@@ -252,6 +252,21 @@ export class ConversationGraphMemory {
|
|
|
252
252
|
};
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Re-register cached node IDs with the InContextTracker after compaction
|
|
257
|
+
* WITHOUT modifying messages. Use this at post-agent-loop compaction sites
|
|
258
|
+
* where the memory block already survives on the original user message
|
|
259
|
+
* (since `<memory __injected>` is not stripped by stripInjectionsForCompaction).
|
|
260
|
+
*
|
|
261
|
+
* Calling reinjectCachedMemory at these sites would inject a duplicate
|
|
262
|
+
* onto the last user message — which after tool calls is a tool_result,
|
|
263
|
+
* not the original user message.
|
|
264
|
+
*/
|
|
265
|
+
retrackCachedNodes(): void {
|
|
266
|
+
if (this.lastInjectedNodeIds.length === 0) return;
|
|
267
|
+
this.tracker.add(this.lastInjectedNodeIds);
|
|
268
|
+
}
|
|
269
|
+
|
|
255
270
|
/**
|
|
256
271
|
* Main entry point — called on every turn before the LLM sees the messages.
|
|
257
272
|
*
|
|
@@ -111,6 +111,29 @@ describe("parseExtractionResponse — node creation", () => {
|
|
|
111
111
|
expect(diff.createNodes[0].stability).toBe(14);
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
+
test("procedural nodes get stability=60", () => {
|
|
115
|
+
const { diff } = parse({
|
|
116
|
+
create_nodes: [
|
|
117
|
+
{
|
|
118
|
+
content: "ffmpeg needs -ac 2 to force stereo output.",
|
|
119
|
+
type: "procedural",
|
|
120
|
+
emotional_charge: {
|
|
121
|
+
valence: 0,
|
|
122
|
+
intensity: 0,
|
|
123
|
+
decay_curve: "linear",
|
|
124
|
+
decay_rate: 0.05,
|
|
125
|
+
},
|
|
126
|
+
significance: 0.5,
|
|
127
|
+
confidence: 0.9,
|
|
128
|
+
source_type: "direct",
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
reinforce_node_ids: [],
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
expect(diff.createNodes[0].stability).toBe(60);
|
|
135
|
+
});
|
|
136
|
+
|
|
114
137
|
test("clamps significance to [0, 1]", () => {
|
|
115
138
|
const { diff } = parse({
|
|
116
139
|
create_nodes: [
|
|
@@ -596,6 +596,14 @@ export function parseExtractionResponse(
|
|
|
596
596
|
node.stability = 5;
|
|
597
597
|
}
|
|
598
598
|
|
|
599
|
+
// Procedural nodes (learned skills, how-to knowledge — "ffmpeg needs -ac 2
|
|
600
|
+
// for stereo") encode facts that stay useful long after the moment they
|
|
601
|
+
// were learned. Higher initial stability slows Ebbinghaus decay so they
|
|
602
|
+
// remain retrievable months later without needing explicit reinforcement.
|
|
603
|
+
if (node.type === "procedural") {
|
|
604
|
+
node.stability = 60;
|
|
605
|
+
}
|
|
606
|
+
|
|
599
607
|
diff.createNodes.push(node);
|
|
600
608
|
const nodeIndex = diff.createNodes.length - 1;
|
|
601
609
|
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
computeTemporalBoost,
|
|
26
26
|
PER_TURN_WEIGHTS,
|
|
27
27
|
scoreCandidate,
|
|
28
|
+
weightsForContextLoad,
|
|
28
29
|
} from "./scoring.js";
|
|
29
30
|
import { sampleSerendipity } from "./serendipity.js";
|
|
30
31
|
import { getEdgesForNode, getNodesByIds, queryNodes } from "./store.js";
|
|
@@ -530,15 +531,19 @@ export async function loadContextMemory(
|
|
|
530
531
|
const recency = computeRecencyBoost(node, nowMs);
|
|
531
532
|
|
|
532
533
|
scored.push(
|
|
533
|
-
scoreCandidate(
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
534
|
+
scoreCandidate(
|
|
535
|
+
node,
|
|
536
|
+
{
|
|
537
|
+
semanticSimilarity: semanticSim,
|
|
538
|
+
effectiveSignificance: effectiveSig,
|
|
539
|
+
emotionalIntensity: node.emotionalCharge.intensity,
|
|
540
|
+
temporalBoost: normalizedTemporal,
|
|
541
|
+
recencyBoost: recency,
|
|
542
|
+
triggerBoost,
|
|
543
|
+
activationBoost: activation,
|
|
544
|
+
},
|
|
545
|
+
weightsForContextLoad(node),
|
|
546
|
+
),
|
|
542
547
|
);
|
|
543
548
|
}
|
|
544
549
|
|
|
@@ -592,15 +597,19 @@ export async function loadContextMemory(
|
|
|
592
597
|
(node) => {
|
|
593
598
|
const existing = scored.find((s) => s.node.id === node.id);
|
|
594
599
|
if (existing) return existing;
|
|
595
|
-
return scoreCandidate(
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
600
|
+
return scoreCandidate(
|
|
601
|
+
node,
|
|
602
|
+
{
|
|
603
|
+
semanticSimilarity: semanticCandidateIds.get(node.id) ?? 0,
|
|
604
|
+
effectiveSignificance: computeEffectiveSignificance(node, nowMs),
|
|
605
|
+
emotionalIntensity: node.emotionalCharge.intensity,
|
|
606
|
+
temporalBoost: (computeTemporalBoost(node, now) + 1) / 2,
|
|
607
|
+
recencyBoost: 0,
|
|
608
|
+
triggerBoost: 0,
|
|
609
|
+
activationBoost: 0,
|
|
610
|
+
},
|
|
611
|
+
weightsForContextLoad(node),
|
|
612
|
+
);
|
|
604
613
|
},
|
|
605
614
|
);
|
|
606
615
|
|