@vellumai/assistant 0.5.16 → 0.6.0
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 +1 -1
- package/Dockerfile +0 -3
- package/knip.json +2 -1
- package/openapi.yaml +660 -80
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +68 -0
- package/src/__tests__/agent-loop.test.ts +0 -32
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/anthropic-provider.test.ts +57 -3
- package/src/__tests__/app-compiler.test.ts +120 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
- package/src/__tests__/call-conversation-messages.test.ts +2 -6
- package/src/__tests__/call-domain.test.ts +2 -6
- package/src/__tests__/call-pointer-messages.test.ts +2 -14
- package/src/__tests__/call-recovery.test.ts +2 -6
- package/src/__tests__/call-routes-http.test.ts +2 -6
- package/src/__tests__/call-store.test.ts +2 -6
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
- package/src/__tests__/canonical-guardian-store.test.ts +2 -6
- package/src/__tests__/channel-delivery-store.test.ts +2 -6
- package/src/__tests__/channel-retry-sweep.test.ts +2 -6
- package/src/__tests__/checker.test.ts +25 -3
- package/src/__tests__/clawhub.test.ts +54 -24
- package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
- package/src/__tests__/cli-memory.test.ts +74 -69
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/config-set-platform-guard.test.ts +302 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
- package/src/__tests__/contacts-tools.test.ts +31 -0
- package/src/__tests__/context-overflow-reducer.test.ts +86 -0
- package/src/__tests__/context-token-estimator.test.ts +175 -10
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +9 -0
- package/src/__tests__/conversation-agent-loop.test.ts +9 -0
- package/src/__tests__/conversation-attachments.test.ts +2 -6
- package/src/__tests__/conversation-attention-store.test.ts +2 -6
- package/src/__tests__/conversation-clear-safety.test.ts +2 -6
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
- package/src/__tests__/conversation-disk-view.test.ts +2 -6
- package/src/__tests__/conversation-error.test.ts +33 -2
- package/src/__tests__/conversation-fork-crud.test.ts +2 -6
- package/src/__tests__/conversation-history-web-search.test.ts +5 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
- package/src/__tests__/conversation-media-retry.test.ts +91 -0
- package/src/__tests__/conversation-starter-routes.test.ts +20 -11
- package/src/__tests__/conversation-store.test.ts +2 -6
- package/src/__tests__/conversation-usage.test.ts +2 -6
- package/src/__tests__/conversation-wipe.test.ts +11 -408
- package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
- package/src/__tests__/credential-security-e2e.test.ts +2 -0
- package/src/__tests__/followup-tools.test.ts +2 -6
- package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
- package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
- package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
- package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
- package/src/__tests__/guardian-action-store.test.ts +2 -6
- package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
- package/src/__tests__/guardian-dispatch.test.ts +2 -6
- package/src/__tests__/guardian-grant-minting.test.ts +2 -14
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
- package/src/__tests__/guardian-routing-invariants.test.ts +192 -6
- package/src/__tests__/guardian-routing-state.test.ts +2 -6
- package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
- package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
- package/src/__tests__/injection-block.test.ts +154 -0
- package/src/__tests__/install-meta.test.ts +506 -0
- package/src/__tests__/install-skill-routing.test.ts +292 -0
- package/src/__tests__/invite-redemption-service.test.ts +2 -6
- package/src/__tests__/invite-routes-http.test.ts +2 -6
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -14
- package/src/__tests__/list-messages-attachments.test.ts +2 -6
- package/src/__tests__/llm-context-route-provider.test.ts +2 -6
- package/src/__tests__/llm-request-log-turn-query.test.ts +2 -6
- package/src/__tests__/llm-usage-store.test.ts +2 -6
- package/src/__tests__/log-export-workspace.test.ts +2 -6
- package/src/__tests__/managed-store.test.ts +38 -11
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
- package/src/__tests__/memory-recall-log-store.test.ts +2 -6
- package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
- package/src/__tests__/non-member-access-request.test.ts +2 -6
- package/src/__tests__/notification-guardian-path.test.ts +2 -6
- package/src/__tests__/oauth-cli.test.ts +364 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
- package/src/__tests__/outlook-attachments.test.ts +301 -0
- package/src/__tests__/outlook-automation-tools.test.ts +425 -0
- package/src/__tests__/outlook-categories.test.ts +212 -0
- package/src/__tests__/outlook-client-automation.test.ts +246 -0
- package/src/__tests__/outlook-compose-tools.test.ts +325 -0
- package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
- package/src/__tests__/outlook-email-watcher.test.ts +322 -0
- package/src/__tests__/outlook-follow-up.test.ts +196 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +498 -3
- package/src/__tests__/outlook-trash.test.ts +77 -0
- package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
- package/src/__tests__/platform-callback-registration.test.ts +4 -4
- package/src/__tests__/playbook-execution.test.ts +76 -80
- package/src/__tests__/playbook-tools.test.ts +5 -7
- package/src/__tests__/provider-error-scenarios.test.ts +21 -0
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
- package/src/__tests__/registry.test.ts +2 -2
- package/src/__tests__/require-fresh-approval.test.ts +64 -2
- package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
- package/src/__tests__/runtime-events-sse.test.ts +2 -6
- package/src/__tests__/schedule-store.test.ts +2 -6
- package/src/__tests__/schedule-tools.test.ts +2 -6
- package/src/__tests__/scheduler-recurrence.test.ts +1 -5
- package/src/__tests__/scoped-approval-grants.test.ts +2 -6
- package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
- package/src/__tests__/search-skills-unified.test.ts +421 -0
- package/src/__tests__/secret-onetime-send.test.ts +2 -0
- package/src/__tests__/send-endpoint-busy.test.ts +2 -6
- package/src/__tests__/sequence-store.test.ts +2 -6
- package/src/__tests__/server-history-render.test.ts +2 -6
- package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
- package/src/__tests__/skill-feature-flags.test.ts +6 -6
- package/src/__tests__/skill-load-feature-flag.test.ts +11 -11
- package/src/__tests__/skill-memory.test.ts +140 -98
- package/src/__tests__/skills-uninstall.test.ts +2 -2
- package/src/__tests__/skills.test.ts +1 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -6
- package/src/__tests__/task-compiler.test.ts +2 -6
- package/src/__tests__/task-management-tools.test.ts +2 -6
- package/src/__tests__/task-memory-cleanup.test.ts +173 -229
- package/src/__tests__/task-runner.test.ts +2 -6
- package/src/__tests__/task-scheduler.test.ts +2 -6
- package/src/__tests__/test-preload.ts +3 -0
- package/src/__tests__/tool-approval-handler.test.ts +2 -6
- package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
- package/src/__tests__/trust-store.test.ts +1 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -6
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +2 -6
- package/src/__tests__/trusted-contact-verification.test.ts +2 -6
- package/src/__tests__/turn-boundary-resolution.test.ts +2 -6
- package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -6
- package/src/__tests__/usage-routes.test.ts +2 -6
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-invite-redemption.test.ts +2 -6
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -6
- package/src/__tests__/voice-session-bridge.test.ts +2 -6
- package/src/__tests__/volume-security-guard.test.ts +2 -0
- package/src/__tests__/workspace-lifecycle.test.ts +29 -1
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -6
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -6
- package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
- package/src/__tests__/workspace-policy.test.ts +1 -1
- package/src/agent/attachments.ts +7 -2
- package/src/agent/image-optimize.ts +165 -0
- package/src/agent/loop.ts +1 -15
- package/src/bundler/app-compiler.ts +179 -2
- package/src/bundler/package-resolver.ts +3 -5
- package/src/cli/__tests__/notifications.test.ts +1 -2
- package/src/cli/cli-memory.ts +67 -64
- package/src/cli/commands/avatar.ts +3 -3
- package/src/cli/commands/config.ts +26 -13
- package/src/cli/commands/doctor.ts +2 -2
- package/src/cli/commands/memory.ts +41 -55
- package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
- package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
- package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
- package/src/cli/commands/oauth/connect.ts +11 -6
- package/src/cli/commands/oauth/mode.ts +7 -0
- package/src/cli/commands/oauth/shared.ts +39 -3
- package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +5 -5
- package/src/cli/commands/platform/index.ts +16 -16
- package/src/cli/commands/skills.ts +88 -16
- package/src/cli/commands/trust.ts +2 -2
- package/src/cli/lib/daemon-credential-client.ts +2 -3
- package/src/config/bundled-skills/acp/TOOLS.json +1 -1
- package/src/config/bundled-skills/contacts/SKILL.md +0 -1
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
- package/src/config/bundled-skills/gmail/SKILL.md +2 -10
- package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
- package/src/config/bundled-skills/messaging/SKILL.md +10 -18
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
- package/src/config/bundled-skills/outlook/SKILL.md +189 -0
- package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
- package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
- package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
- package/src/config/bundled-skills/slack/SKILL.md +1 -7
- package/src/config/bundled-tool-registry.ts +56 -4
- package/src/config/env-registry.ts +15 -8
- package/src/config/feature-flag-registry.json +21 -124
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/config/skills.ts +18 -7
- package/src/context/token-estimator.ts +25 -18
- package/src/context/window-manager.ts +6 -2
- package/src/credential-execution/process-manager.ts +3 -1
- package/src/daemon/context-overflow-reducer.ts +46 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +123 -82
- package/src/daemon/conversation-agent-loop.ts +96 -61
- package/src/daemon/conversation-error.ts +31 -8
- package/src/daemon/conversation-lifecycle.ts +33 -0
- package/src/daemon/conversation-media-retry.ts +85 -7
- package/src/daemon/conversation-notifiers.ts +4 -1
- package/src/daemon/conversation-runtime-assembly.ts +5 -0
- package/src/daemon/conversation.ts +41 -2
- package/src/daemon/daemon-control.ts +8 -2
- package/src/daemon/handlers/shared.ts +22 -12
- package/src/daemon/handlers/skills.ts +416 -202
- package/src/daemon/lifecycle.ts +40 -1
- package/src/daemon/main.ts +5 -1
- package/src/daemon/message-types/conversations.ts +4 -1
- package/src/daemon/message-types/messages.ts +3 -1
- package/src/daemon/message-types/skills.ts +97 -36
- package/src/daemon/providers-setup.ts +5 -0
- package/src/daemon/server.ts +11 -2
- package/src/daemon/tool-side-effects.ts +27 -5
- package/src/heartbeat/heartbeat-service.ts +1 -0
- package/src/hooks/cli.ts +2 -2
- package/src/hooks/runner.ts +15 -38
- package/src/inbound/platform-callback-registration.ts +14 -14
- package/src/memory/admin.ts +11 -45
- package/src/memory/conversation-bootstrap.ts +2 -0
- package/src/memory/conversation-crud.ts +242 -348
- package/src/memory/conversation-group-migration.ts +157 -0
- package/src/memory/conversation-queries.ts +4 -2
- package/src/memory/db-init.ts +30 -3
- package/src/memory/embed.ts +73 -0
- package/src/memory/embedding-backend.ts +8 -14
- package/src/memory/embedding-runtime-manager.ts +12 -114
- package/src/memory/fingerprint.ts +2 -2
- package/src/memory/graph/bootstrap.ts +512 -0
- package/src/memory/graph/capability-seed.ts +297 -0
- package/src/memory/graph/consolidation.ts +691 -0
- package/src/memory/graph/conversation-graph-memory.ts +630 -0
- package/src/memory/graph/decay.test.ts +208 -0
- package/src/memory/graph/decay.ts +195 -0
- package/src/memory/graph/extraction-job.ts +69 -0
- package/src/memory/graph/extraction.test.ts +936 -0
- package/src/memory/graph/extraction.ts +1254 -0
- package/src/memory/graph/graph-search.ts +266 -0
- package/src/memory/graph/image-ref-utils.ts +29 -0
- package/src/memory/graph/injection.test.ts +513 -0
- package/src/memory/graph/injection.ts +439 -0
- package/src/memory/graph/inspect.ts +534 -0
- package/src/memory/graph/narrative.ts +267 -0
- package/src/memory/graph/pattern-scan.ts +269 -0
- package/src/memory/graph/retriever.ts +1008 -0
- package/src/memory/graph/scoring.test.ts +548 -0
- package/src/memory/graph/scoring.ts +232 -0
- package/src/memory/graph/serendipity.ts +65 -0
- package/src/memory/graph/store.test.ts +1050 -0
- package/src/memory/graph/store.ts +699 -0
- package/src/memory/graph/tool-handlers.ts +426 -0
- package/src/memory/graph/tools.ts +141 -0
- package/src/memory/graph/triggers.test.ts +487 -0
- package/src/memory/graph/triggers.ts +223 -0
- package/src/memory/graph/types.ts +271 -0
- package/src/memory/group-crud.ts +191 -0
- package/src/memory/indexer.ts +37 -19
- package/src/memory/job-handlers/cleanup.ts +0 -53
- package/src/memory/job-handlers/conversation-starters.ts +91 -53
- package/src/memory/job-handlers/embedding.ts +5 -31
- package/src/memory/job-handlers/index-maintenance.ts +23 -11
- package/src/memory/job-handlers/summarization.ts +32 -17
- package/src/memory/job-utils.ts +1 -1
- package/src/memory/jobs-store.ts +50 -70
- package/src/memory/jobs-worker.ts +147 -112
- package/src/memory/message-content.ts +1 -0
- package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
- package/src/memory/migrations/203-drop-memory-items-tables.ts +23 -0
- package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
- package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/qdrant-client.ts +44 -17
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/memory-graph.ts +139 -0
- package/src/memory/search/semantic.ts +47 -91
- package/src/memory/task-memory-cleanup.ts +28 -50
- package/src/messaging/providers/outlook/adapter.ts +8 -1
- package/src/messaging/providers/outlook/client.ts +299 -0
- package/src/messaging/providers/outlook/types.ts +118 -0
- package/src/notifications/adapters/macos.ts +1 -0
- package/src/notifications/copy-composer.ts +9 -0
- package/src/notifications/signal.ts +16 -0
- package/src/oauth/seed-providers.ts +2 -1
- package/src/permissions/checker.ts +24 -3
- package/src/permissions/defaults.ts +4 -4
- package/src/permissions/workspace-policy.ts +1 -1
- package/src/playbooks/playbook-compiler.ts +19 -18
- package/src/playbooks/types.ts +4 -3
- package/src/prompts/system-prompt.ts +3 -29
- package/src/providers/anthropic/client.ts +47 -19
- package/src/providers/gemini/client.ts +1 -1
- package/src/providers/openai/client.ts +1 -1
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +19 -3
- package/src/runtime/actor-trust-resolver.ts +5 -1
- package/src/runtime/auth/route-policy.ts +7 -0
- package/src/runtime/guardian-reply-router.ts +5 -1
- package/src/runtime/http-server.ts +23 -3
- package/src/runtime/middleware/auth.ts +20 -0
- package/src/runtime/routes/attachment-routes.test.ts +106 -0
- package/src/runtime/routes/attachment-routes.ts +106 -16
- package/src/runtime/routes/brain-graph-routes.ts +21 -22
- package/src/runtime/routes/btw-routes.ts +8 -0
- package/src/runtime/routes/conversation-management-routes.ts +2 -0
- package/src/runtime/routes/conversation-starter-routes.ts +2 -2
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/global-search-routes.ts +21 -19
- package/src/runtime/routes/group-routes.ts +207 -0
- package/src/runtime/routes/guardian-action-routes.ts +21 -10
- package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
- package/src/runtime/routes/inbound-message-handler.ts +19 -0
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
- package/src/runtime/routes/memory-item-routes.test.ts +2 -14
- package/src/runtime/routes/memory-item-routes.ts +341 -388
- package/src/runtime/routes/schedule-routes.ts +2 -0
- package/src/runtime/routes/skills-routes.ts +103 -37
- package/src/runtime/routes/work-items-routes.test.ts +2 -6
- package/src/schedule/scheduler.ts +8 -1
- package/src/security/oauth2.ts +1 -1
- package/src/security/secure-keys.ts +4 -8
- package/src/shared/provider-env-vars.ts +19 -0
- package/src/skills/catalog-cache.ts +5 -0
- package/src/skills/catalog-install.ts +15 -14
- package/src/skills/clawhub.ts +134 -154
- package/src/skills/install-meta.ts +208 -0
- package/src/skills/managed-store.ts +27 -16
- package/src/skills/skill-memory.ts +152 -77
- package/src/skills/skillssh-registry.ts +19 -17
- package/src/tasks/task-runner.ts +3 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
- package/src/tools/browser/runtime-check.ts +3 -1
- package/src/tools/memory/register.ts +63 -46
- package/src/tools/permission-checker.ts +7 -1
- package/src/tools/shared/filesystem/image-read.ts +22 -85
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/tool-manifest.ts +3 -3
- package/src/util/browser.ts +25 -10
- package/src/util/bun-runtime.ts +172 -0
- package/src/watcher/providers/outlook-calendar.ts +343 -0
- package/src/watcher/providers/outlook.ts +198 -0
- package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
- package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
- package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/context-memory-e2e.test.ts +0 -415
- package/src/__tests__/journal-context.test.ts +0 -268
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
- package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
- package/src/__tests__/memory-query-builder.test.ts +0 -59
- package/src/__tests__/memory-recall-quality.test.ts +0 -1046
- package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
- package/src/__tests__/memory-regressions.test.ts +0 -3696
- package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
- package/src/daemon/conversation-memory.ts +0 -207
- package/src/memory/conversation-starters-cadence.ts +0 -74
- package/src/memory/items-extractor.ts +0 -860
- package/src/memory/job-handlers/batch-extraction.ts +0 -753
- package/src/memory/job-handlers/extraction.ts +0 -40
- package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -355
- package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
- package/src/memory/journal-memory.ts +0 -224
- package/src/memory/query-builder.ts +0 -47
- package/src/memory/query-expansion.ts +0 -83
- package/src/memory/retriever.test.ts +0 -1592
- package/src/memory/retriever.ts +0 -1331
- package/src/memory/search/formatting.test.ts +0 -140
- package/src/memory/search/formatting.ts +0 -262
- package/src/memory/search/mmr.ts +0 -139
- package/src/memory/search/ranking.ts +0 -15
- package/src/memory/search/staleness.ts +0 -40
- package/src/memory/search/tier-classifier.ts +0 -18
- package/src/memory/search/types.ts +0 -121
- package/src/prompts/journal-context.ts +0 -154
- package/src/tools/memory/definitions.ts +0 -69
- package/src/tools/memory/handlers.test.ts +0 -562
- package/src/tools/memory/handlers.ts +0 -434
package/src/memory/jobs-store.ts
CHANGED
|
@@ -19,7 +19,7 @@ export type MemoryJobType =
|
|
|
19
19
|
| "extract_items"
|
|
20
20
|
| "extract_entities"
|
|
21
21
|
| "batch_extract"
|
|
22
|
-
| "cleanup_stale_superseded_items"
|
|
22
|
+
| "cleanup_stale_superseded_items" // legacy compat — silently dropped by worker (memory_items table dropped)
|
|
23
23
|
| "prune_old_conversations"
|
|
24
24
|
| "backfill_entity_relations"
|
|
25
25
|
| "refresh_weekly_summary"
|
|
@@ -33,6 +33,14 @@ export type MemoryJobType =
|
|
|
33
33
|
| "embed_attachment"
|
|
34
34
|
| "generate_conversation_starters"
|
|
35
35
|
| "journal_carry_forward"
|
|
36
|
+
| "embed_graph_node"
|
|
37
|
+
| "graph_extract"
|
|
38
|
+
| "graph_decay"
|
|
39
|
+
| "graph_consolidate"
|
|
40
|
+
| "graph_pattern_scan"
|
|
41
|
+
| "graph_narrative_refine"
|
|
42
|
+
| "graph_trigger_embed"
|
|
43
|
+
| "graph_bootstrap"
|
|
36
44
|
| "generate_capability_cards" // legacy compat — silently dropped by worker (capability cards removed)
|
|
37
45
|
| "generate_thread_starters"; // legacy compat — silently dropped by worker (renamed to generate_conversation_starters)
|
|
38
46
|
|
|
@@ -42,6 +50,8 @@ const EMBED_JOB_TYPES: MemoryJobType[] = [
|
|
|
42
50
|
"embed_summary",
|
|
43
51
|
"embed_media",
|
|
44
52
|
"embed_attachment",
|
|
53
|
+
"embed_graph_node",
|
|
54
|
+
"graph_trigger_embed",
|
|
45
55
|
];
|
|
46
56
|
|
|
47
57
|
export interface MemoryJob<T = Record<string, unknown>> {
|
|
@@ -63,10 +73,10 @@ export function enqueueMemoryJob(
|
|
|
63
73
|
payload: Record<string, unknown>,
|
|
64
74
|
runAfter = Date.now(),
|
|
65
75
|
dbOverride?: Parameters<ReturnType<typeof getDb>["transaction"]>[0] extends (
|
|
66
|
-
tx: infer T
|
|
76
|
+
tx: infer T
|
|
67
77
|
) => unknown
|
|
68
78
|
? T
|
|
69
|
-
: never
|
|
79
|
+
: never
|
|
70
80
|
): string {
|
|
71
81
|
const db = dbOverride ?? getDb();
|
|
72
82
|
const id = uuid();
|
|
@@ -101,10 +111,10 @@ export function upsertDebouncedJob(
|
|
|
101
111
|
payload: { conversationId: string },
|
|
102
112
|
runAfter: number,
|
|
103
113
|
dbOverride?: Parameters<ReturnType<typeof getDb>["transaction"]>[0] extends (
|
|
104
|
-
tx: infer T
|
|
114
|
+
tx: infer T
|
|
105
115
|
) => unknown
|
|
106
116
|
? T
|
|
107
|
-
: never
|
|
117
|
+
: never
|
|
108
118
|
): void {
|
|
109
119
|
const db = dbOverride ?? getDb();
|
|
110
120
|
const existing = db
|
|
@@ -114,8 +124,8 @@ export function upsertDebouncedJob(
|
|
|
114
124
|
and(
|
|
115
125
|
eq(memoryJobs.type, type),
|
|
116
126
|
eq(memoryJobs.status, "pending"),
|
|
117
|
-
sql`json_extract(${memoryJobs.payload}, '$.conversationId') = ${payload.conversationId}
|
|
118
|
-
)
|
|
127
|
+
sql`json_extract(${memoryJobs.payload}, '$.conversationId') = ${payload.conversationId}`
|
|
128
|
+
)
|
|
119
129
|
)
|
|
120
130
|
.get();
|
|
121
131
|
if (existing) {
|
|
@@ -135,7 +145,7 @@ export function upsertDebouncedJob(
|
|
|
135
145
|
*/
|
|
136
146
|
export function hasActiveCarryForwardJob(
|
|
137
147
|
filename: string,
|
|
138
|
-
userSlug: string
|
|
148
|
+
userSlug: string
|
|
139
149
|
): boolean {
|
|
140
150
|
const db = getDb();
|
|
141
151
|
return (
|
|
@@ -147,65 +157,35 @@ export function hasActiveCarryForwardJob(
|
|
|
147
157
|
eq(memoryJobs.type, "journal_carry_forward"),
|
|
148
158
|
inArray(memoryJobs.status, ["pending", "running"]),
|
|
149
159
|
sql`json_extract(${memoryJobs.payload}, '$.filename') = ${filename}`,
|
|
150
|
-
sql`json_extract(${memoryJobs.payload}, '$.userSlug') = ${userSlug}
|
|
151
|
-
)
|
|
160
|
+
sql`json_extract(${memoryJobs.payload}, '$.userSlug') = ${userSlug}`
|
|
161
|
+
)
|
|
152
162
|
)
|
|
153
163
|
.get() != null
|
|
154
164
|
);
|
|
155
165
|
}
|
|
156
166
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
167
|
+
/**
|
|
168
|
+
* Check whether a pending or running job of the given type already exists.
|
|
169
|
+
* Used to prevent duplicate enqueues for long-running maintenance jobs.
|
|
170
|
+
*/
|
|
171
|
+
export function hasActiveJobOfType(type: MemoryJobType): boolean {
|
|
160
172
|
const db = getDb();
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if (existing) {
|
|
174
|
-
if (
|
|
175
|
-
existing.status === "pending" &&
|
|
176
|
-
typeof retentionMs === "number" &&
|
|
177
|
-
Number.isFinite(retentionMs) &&
|
|
178
|
-
retentionMs > 0
|
|
179
|
-
) {
|
|
180
|
-
let payload: Record<string, unknown> = {};
|
|
181
|
-
try {
|
|
182
|
-
payload = JSON.parse(existing.payload) as Record<string, unknown>;
|
|
183
|
-
} catch {
|
|
184
|
-
payload = {};
|
|
185
|
-
}
|
|
186
|
-
if (payload.retentionMs !== retentionMs) {
|
|
187
|
-
db.update(memoryJobs)
|
|
188
|
-
.set({
|
|
189
|
-
payload: JSON.stringify({ ...payload, retentionMs }),
|
|
190
|
-
updatedAt: now,
|
|
191
|
-
})
|
|
192
|
-
.where(eq(memoryJobs.id, existing.id))
|
|
193
|
-
.run();
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return existing.id;
|
|
197
|
-
}
|
|
198
|
-
const payload =
|
|
199
|
-
typeof retentionMs === "number" &&
|
|
200
|
-
Number.isFinite(retentionMs) &&
|
|
201
|
-
retentionMs > 0
|
|
202
|
-
? { retentionMs }
|
|
203
|
-
: {};
|
|
204
|
-
return enqueueMemoryJob("cleanup_stale_superseded_items", payload);
|
|
173
|
+
return (
|
|
174
|
+
db
|
|
175
|
+
.select({ id: memoryJobs.id })
|
|
176
|
+
.from(memoryJobs)
|
|
177
|
+
.where(
|
|
178
|
+
and(
|
|
179
|
+
eq(memoryJobs.type, type),
|
|
180
|
+
inArray(memoryJobs.status, ["pending", "running"])
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
.get() != null
|
|
184
|
+
);
|
|
205
185
|
}
|
|
206
186
|
|
|
207
187
|
export function enqueuePruneOldConversationsJob(
|
|
208
|
-
retentionDays?: number
|
|
188
|
+
retentionDays?: number
|
|
209
189
|
): string {
|
|
210
190
|
const db = getDb();
|
|
211
191
|
const existing = db
|
|
@@ -214,8 +194,8 @@ export function enqueuePruneOldConversationsJob(
|
|
|
214
194
|
.where(
|
|
215
195
|
and(
|
|
216
196
|
eq(memoryJobs.type, "prune_old_conversations"),
|
|
217
|
-
inArray(memoryJobs.status, ["pending", "running"])
|
|
218
|
-
)
|
|
197
|
+
inArray(memoryJobs.status, ["pending", "running"])
|
|
198
|
+
)
|
|
219
199
|
)
|
|
220
200
|
.orderBy(asc(memoryJobs.createdAt))
|
|
221
201
|
.get();
|
|
@@ -259,7 +239,7 @@ export function claimMemoryJobs(limit: number): MemoryJob[] {
|
|
|
259
239
|
const now = Date.now();
|
|
260
240
|
const pendingFilter = and(
|
|
261
241
|
eq(memoryJobs.status, "pending"),
|
|
262
|
-
lte(memoryJobs.runAfter, now)
|
|
242
|
+
lte(memoryJobs.runAfter, now)
|
|
263
243
|
);
|
|
264
244
|
|
|
265
245
|
// Claim non-embed jobs first, then fill remaining slots with embed jobs.
|
|
@@ -288,7 +268,7 @@ export function claimMemoryJobs(limit: number): MemoryJob[] {
|
|
|
288
268
|
}
|
|
289
269
|
if (probeAllowed && remainingSlots > 0) {
|
|
290
270
|
log.debug(
|
|
291
|
-
"Allowing 1 embed probe job — Qdrant circuit breaker cooldown elapsed"
|
|
271
|
+
"Allowing 1 embed probe job — Qdrant circuit breaker cooldown elapsed"
|
|
292
272
|
);
|
|
293
273
|
}
|
|
294
274
|
|
|
@@ -318,7 +298,7 @@ export function claimMemoryJobs(limit: number): MemoryJob[] {
|
|
|
318
298
|
status: "running",
|
|
319
299
|
startedAt: now,
|
|
320
300
|
updatedAt: now,
|
|
321
|
-
})
|
|
301
|
+
})
|
|
322
302
|
);
|
|
323
303
|
}
|
|
324
304
|
return claimed;
|
|
@@ -363,7 +343,7 @@ export function deferMemoryJob(id: string): "deferred" | "failed" {
|
|
|
363
343
|
if (deferrals >= MAX_DEFERRALS) {
|
|
364
344
|
log.error(
|
|
365
345
|
{ jobId: id, type: row.type, deferrals },
|
|
366
|
-
"Job exceeded max deferrals, marking as failed"
|
|
346
|
+
"Job exceeded max deferrals, marking as failed"
|
|
367
347
|
);
|
|
368
348
|
db.update(memoryJobs)
|
|
369
349
|
.set({
|
|
@@ -382,14 +362,14 @@ export function deferMemoryJob(id: string): "deferred" | "failed" {
|
|
|
382
362
|
if (DEFERRAL_WARN_MILESTONES.includes(deferrals)) {
|
|
383
363
|
log.warn(
|
|
384
364
|
{ jobId: id, type: row.type, deferrals, max: MAX_DEFERRALS },
|
|
385
|
-
"Job approaching max deferral limit"
|
|
365
|
+
"Job approaching max deferral limit"
|
|
386
366
|
);
|
|
387
367
|
}
|
|
388
368
|
|
|
389
369
|
// Exponential backoff: 30s, 60s, 120s, ... capped at 5 minutes
|
|
390
370
|
const delay = Math.min(
|
|
391
371
|
DEFER_BASE_DELAY_MS * Math.pow(2, Math.min(deferrals - 1, 10)),
|
|
392
|
-
DEFER_MAX_DELAY_MS
|
|
372
|
+
DEFER_MAX_DELAY_MS
|
|
393
373
|
);
|
|
394
374
|
db.update(memoryJobs)
|
|
395
375
|
.set({
|
|
@@ -406,7 +386,7 @@ export function deferMemoryJob(id: string): "deferred" | "failed" {
|
|
|
406
386
|
export function failMemoryJob(
|
|
407
387
|
id: string,
|
|
408
388
|
error: string,
|
|
409
|
-
options?: { retryDelayMs?: number; maxAttempts?: number }
|
|
389
|
+
options?: { retryDelayMs?: number; maxAttempts?: number }
|
|
410
390
|
): void {
|
|
411
391
|
const retryDelayMs = options?.retryDelayMs ?? 30_000;
|
|
412
392
|
const maxAttempts = options?.maxAttempts ?? 5;
|
|
@@ -463,7 +443,7 @@ export function failStalledJobs(timeoutMs: number): number {
|
|
|
463
443
|
AND started_at IS NOT NULL
|
|
464
444
|
AND started_at < ?
|
|
465
445
|
`,
|
|
466
|
-
cutoff
|
|
446
|
+
cutoff
|
|
467
447
|
);
|
|
468
448
|
if (stalled.length === 0) return 0;
|
|
469
449
|
|
|
@@ -474,14 +454,14 @@ export function failStalledJobs(timeoutMs: number): number {
|
|
|
474
454
|
status: "failed",
|
|
475
455
|
updatedAt: now,
|
|
476
456
|
lastError: `Job timed out after ${Math.round(
|
|
477
|
-
timeoutMs / 60_000
|
|
457
|
+
timeoutMs / 60_000
|
|
478
458
|
)} minutes`,
|
|
479
459
|
})
|
|
480
460
|
.where(and(eq(memoryJobs.id, row.id), eq(memoryJobs.status, "running")))
|
|
481
461
|
.run();
|
|
482
462
|
log.warn(
|
|
483
463
|
{ jobId: row.id, type: row.type, timeoutMs },
|
|
484
|
-
"Failed stalled memory job due to timeout"
|
|
464
|
+
"Failed stalled memory job due to timeout"
|
|
485
465
|
);
|
|
486
466
|
}
|
|
487
467
|
return stalled.length;
|
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
import { getConfig } from "../config/loader.js";
|
|
2
2
|
import type { AssistantConfig } from "../config/types.js";
|
|
3
3
|
import { getLogger } from "../util/logger.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { getMemoryCheckpoint, setMemoryCheckpoint } from "./checkpoints.js";
|
|
5
|
+
import { runConsolidation } from "./graph/consolidation.js";
|
|
6
|
+
import { runDecayTick } from "./graph/decay.js";
|
|
7
|
+
import { graphExtractJob } from "./graph/extraction-job.js";
|
|
7
8
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from "./
|
|
9
|
+
embedGraphNodeJob,
|
|
10
|
+
embedGraphTriggerJob,
|
|
11
|
+
} from "./graph/graph-search.js";
|
|
12
|
+
import { runNarrativeRefinement } from "./graph/narrative.js";
|
|
13
|
+
import { runPatternScan } from "./graph/pattern-scan.js";
|
|
14
|
+
import { backfillJob } from "./job-handlers/backfill.js";
|
|
15
|
+
import { pruneOldConversationsJob } from "./job-handlers/cleanup.js";
|
|
11
16
|
import { generateConversationStartersJob } from "./job-handlers/conversation-starters.js";
|
|
12
17
|
// ── Per-job-type handlers ──────────────────────────────────────────
|
|
13
18
|
import {
|
|
14
19
|
embedAttachmentJob,
|
|
15
|
-
embedItemJob,
|
|
16
20
|
embedMediaJob,
|
|
17
21
|
embedSegmentJob,
|
|
18
22
|
embedSummaryJob,
|
|
19
23
|
} from "./job-handlers/embedding.js";
|
|
20
|
-
import { extractItemsJob } from "./job-handlers/extraction.js";
|
|
21
24
|
import {
|
|
22
25
|
deleteQdrantVectorsJob,
|
|
23
26
|
rebuildIndexJob,
|
|
24
27
|
} from "./job-handlers/index-maintenance.js";
|
|
25
|
-
import { journalCarryForwardJob } from "./job-handlers/journal-carry-forward.js";
|
|
26
28
|
import { mediaProcessingJob } from "./job-handlers/media-processing.js";
|
|
29
|
+
import { buildConversationSummaryJob } from "./job-handlers/summarization.js";
|
|
27
30
|
import {
|
|
28
31
|
BackendUnavailableError,
|
|
29
32
|
classifyError,
|
|
@@ -34,12 +37,12 @@ import {
|
|
|
34
37
|
claimMemoryJobs,
|
|
35
38
|
completeMemoryJob,
|
|
36
39
|
deferMemoryJob,
|
|
37
|
-
enqueueCleanupStaleSupersededItemsJob,
|
|
38
40
|
enqueueMemoryJob,
|
|
39
41
|
enqueuePruneOldConversationsJob,
|
|
40
42
|
failMemoryJob,
|
|
41
43
|
failStalledJobs,
|
|
42
44
|
type MemoryJob,
|
|
45
|
+
type MemoryJobType,
|
|
43
46
|
resetRunningJobsToPending,
|
|
44
47
|
} from "./jobs-store.js";
|
|
45
48
|
import { QdrantCircuitOpenError } from "./qdrant-circuit-breaker.js";
|
|
@@ -60,31 +63,6 @@ export function startMemoryJobsWorker(): MemoryJobsWorker {
|
|
|
60
63
|
log.info({ recovered }, "Recovered stale running memory jobs");
|
|
61
64
|
}
|
|
62
65
|
|
|
63
|
-
// Startup recovery: enqueue batch_extract for conversations with pending
|
|
64
|
-
// unextracted messages (e.g. after a crash mid-conversation).
|
|
65
|
-
try {
|
|
66
|
-
const pendingRows = rawAll<{ key: string; value: string }>(
|
|
67
|
-
`SELECT key, value FROM memory_checkpoints WHERE key LIKE 'batch_extract:%:pending_count' AND CAST(value AS INTEGER) > 0`,
|
|
68
|
-
);
|
|
69
|
-
for (const row of pendingRows) {
|
|
70
|
-
// Extract conversationId from key: "batch_extract:<conversationId>:pending_count"
|
|
71
|
-
const parts = row.key.split(":");
|
|
72
|
-
if (parts.length >= 3) {
|
|
73
|
-
const conversationId = parts.slice(1, -1).join(":");
|
|
74
|
-
enqueueMemoryJob("batch_extract", { conversationId });
|
|
75
|
-
log.info(
|
|
76
|
-
{ conversationId, pendingCount: row.value },
|
|
77
|
-
"Recovered pending batch extraction on startup",
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
} catch (err) {
|
|
82
|
-
log.warn(
|
|
83
|
-
{ err: err instanceof Error ? err.message : String(err) },
|
|
84
|
-
"Failed to recover pending batch extractions on startup",
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
66
|
let stopped = false;
|
|
89
67
|
let tickRunning = false;
|
|
90
68
|
let timer: ReturnType<typeof setTimeout>;
|
|
@@ -145,9 +123,6 @@ export async function runMemoryJobsOnce(
|
|
|
145
123
|
if (!config.memory.enabled) return 0;
|
|
146
124
|
const enableScheduledCleanup = options.enableScheduledCleanup === true;
|
|
147
125
|
|
|
148
|
-
// Periodic stale item sweep (throttled to at most once per hour)
|
|
149
|
-
sweepStaleItems(config);
|
|
150
|
-
|
|
151
126
|
// Fail jobs that have been running longer than the configured timeout
|
|
152
127
|
const timedOut = failStalledJobs(config.memory.jobs.stalledJobTimeoutMs);
|
|
153
128
|
if (timedOut > 0) {
|
|
@@ -161,6 +136,7 @@ export async function runMemoryJobsOnce(
|
|
|
161
136
|
if (enableScheduledCleanup) {
|
|
162
137
|
maybeEnqueueScheduledCleanupJobs(config);
|
|
163
138
|
}
|
|
139
|
+
maybeEnqueueGraphMaintenanceJobs();
|
|
164
140
|
return 0;
|
|
165
141
|
}
|
|
166
142
|
|
|
@@ -256,9 +232,67 @@ export async function runMemoryJobsOnce(
|
|
|
256
232
|
if (enableScheduledCleanup) {
|
|
257
233
|
maybeEnqueueScheduledCleanupJobs(config);
|
|
258
234
|
}
|
|
235
|
+
maybeEnqueueGraphMaintenanceJobs();
|
|
259
236
|
return processed;
|
|
260
237
|
}
|
|
261
238
|
|
|
239
|
+
// ── Graph lifecycle job handlers ──────────────────────────────────
|
|
240
|
+
|
|
241
|
+
function graphDecayJob(job: MemoryJob): void {
|
|
242
|
+
const scopeId = (job.payload as { scopeId?: string })?.scopeId ?? "default";
|
|
243
|
+
const result = runDecayTick(scopeId);
|
|
244
|
+
log.info({ jobId: job.id, ...result }, "Graph decay tick complete");
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async function graphConsolidateJob(
|
|
248
|
+
job: MemoryJob,
|
|
249
|
+
config: AssistantConfig,
|
|
250
|
+
): Promise<void> {
|
|
251
|
+
const scopeId = (job.payload as { scopeId?: string })?.scopeId ?? "default";
|
|
252
|
+
const result = await runConsolidation(scopeId, config);
|
|
253
|
+
log.info(
|
|
254
|
+
{
|
|
255
|
+
jobId: job.id,
|
|
256
|
+
updated: result.totalUpdated,
|
|
257
|
+
deleted: result.totalDeleted,
|
|
258
|
+
mergeEdges: result.totalMergeEdges,
|
|
259
|
+
},
|
|
260
|
+
"Graph consolidation complete",
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function graphPatternScanJob(
|
|
265
|
+
job: MemoryJob,
|
|
266
|
+
config: AssistantConfig,
|
|
267
|
+
): Promise<void> {
|
|
268
|
+
const scopeId = (job.payload as { scopeId?: string })?.scopeId ?? "default";
|
|
269
|
+
const result = await runPatternScan(scopeId, config);
|
|
270
|
+
log.info(
|
|
271
|
+
{
|
|
272
|
+
jobId: job.id,
|
|
273
|
+
patterns: result.patternsDetected,
|
|
274
|
+
edges: result.edgesCreated,
|
|
275
|
+
},
|
|
276
|
+
"Graph pattern scan complete",
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async function graphNarrativeRefineJob(
|
|
281
|
+
job: MemoryJob,
|
|
282
|
+
config: AssistantConfig,
|
|
283
|
+
): Promise<void> {
|
|
284
|
+
const scopeId = (job.payload as { scopeId?: string })?.scopeId ?? "default";
|
|
285
|
+
const result = await runNarrativeRefinement(scopeId, config);
|
|
286
|
+
log.info(
|
|
287
|
+
{
|
|
288
|
+
jobId: job.id,
|
|
289
|
+
updated: result.nodesUpdated,
|
|
290
|
+
arcs: result.arcsIdentified,
|
|
291
|
+
},
|
|
292
|
+
"Graph narrative refinement complete",
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
262
296
|
// ── Job error handling ─────────────────────────────────────────────
|
|
263
297
|
|
|
264
298
|
function handleJobError(job: MemoryJob, err: unknown): void {
|
|
@@ -322,33 +356,20 @@ async function processJob(
|
|
|
322
356
|
await embedSegmentJob(job, config);
|
|
323
357
|
return;
|
|
324
358
|
case "embed_item":
|
|
325
|
-
await embedItemJob(job, config);
|
|
326
|
-
return;
|
|
327
|
-
case "embed_summary":
|
|
328
|
-
await embedSummaryJob(job, config);
|
|
329
|
-
return;
|
|
330
359
|
case "extract_items":
|
|
331
|
-
await extractItemsJob(job);
|
|
332
|
-
return;
|
|
333
360
|
case "batch_extract":
|
|
334
|
-
await batchExtractJob(job);
|
|
335
|
-
return;
|
|
336
361
|
case "extract_entities":
|
|
337
|
-
// Entity extraction has been removed — silently drop legacy jobs
|
|
338
|
-
return;
|
|
339
362
|
case "cleanup_stale_superseded_items":
|
|
340
|
-
|
|
363
|
+
// Old extraction pipeline replaced by memory graph — silently drop
|
|
364
|
+
return;
|
|
365
|
+
case "embed_summary":
|
|
366
|
+
await embedSummaryJob(job, config);
|
|
341
367
|
return;
|
|
342
368
|
case "prune_old_conversations":
|
|
343
369
|
pruneOldConversationsJob(job, config);
|
|
344
370
|
return;
|
|
345
371
|
case "build_conversation_summary":
|
|
346
|
-
|
|
347
|
-
// of batch extraction. Silently skip legacy jobs.
|
|
348
|
-
log.debug(
|
|
349
|
-
{ jobId: job.id },
|
|
350
|
-
"Skipping deprecated build_conversation_summary job — handled by batch extraction",
|
|
351
|
-
);
|
|
372
|
+
await buildConversationSummaryJob(job, config);
|
|
352
373
|
return;
|
|
353
374
|
case "backfill":
|
|
354
375
|
await backfillJob(job, config);
|
|
@@ -376,7 +397,28 @@ async function processJob(
|
|
|
376
397
|
await embedAttachmentJob(job, config);
|
|
377
398
|
return;
|
|
378
399
|
case "journal_carry_forward":
|
|
379
|
-
|
|
400
|
+
// Journal carry-forward replaced by graph extraction — silently drop
|
|
401
|
+
return;
|
|
402
|
+
case "embed_graph_node":
|
|
403
|
+
await embedGraphNodeJob(job, config);
|
|
404
|
+
return;
|
|
405
|
+
case "graph_trigger_embed":
|
|
406
|
+
await embedGraphTriggerJob(job, config);
|
|
407
|
+
return;
|
|
408
|
+
case "graph_extract":
|
|
409
|
+
await graphExtractJob(job, config);
|
|
410
|
+
return;
|
|
411
|
+
case "graph_decay":
|
|
412
|
+
graphDecayJob(job);
|
|
413
|
+
return;
|
|
414
|
+
case "graph_consolidate":
|
|
415
|
+
await graphConsolidateJob(job, config);
|
|
416
|
+
return;
|
|
417
|
+
case "graph_pattern_scan":
|
|
418
|
+
await graphPatternScanJob(job, config);
|
|
419
|
+
return;
|
|
420
|
+
case "graph_narrative_refine":
|
|
421
|
+
await graphNarrativeRefineJob(job, config);
|
|
380
422
|
return;
|
|
381
423
|
case "generate_conversation_starters":
|
|
382
424
|
await generateConversationStartersJob(job);
|
|
@@ -416,9 +458,6 @@ export function maybeEnqueueScheduledCleanupJobs(
|
|
|
416
458
|
if (nowMs - lastScheduledCleanupEnqueueMs < cleanup.enqueueIntervalMs)
|
|
417
459
|
return false;
|
|
418
460
|
|
|
419
|
-
const staleSupersededItemsJobId = enqueueCleanupStaleSupersededItemsJob(
|
|
420
|
-
cleanup.supersededItemRetentionMs,
|
|
421
|
-
);
|
|
422
461
|
const pruneConversationsJobId =
|
|
423
462
|
cleanup.conversationRetentionDays > 0
|
|
424
463
|
? enqueuePruneOldConversationsJob(cleanup.conversationRetentionDays)
|
|
@@ -426,10 +465,8 @@ export function maybeEnqueueScheduledCleanupJobs(
|
|
|
426
465
|
lastScheduledCleanupEnqueueMs = nowMs;
|
|
427
466
|
log.debug(
|
|
428
467
|
{
|
|
429
|
-
staleSupersededItemsJobId,
|
|
430
468
|
pruneConversationsJobId,
|
|
431
469
|
enqueueIntervalMs: cleanup.enqueueIntervalMs,
|
|
432
|
-
supersededItemRetentionMs: cleanup.supersededItemRetentionMs,
|
|
433
470
|
conversationRetentionDays: cleanup.conversationRetentionDays,
|
|
434
471
|
},
|
|
435
472
|
"Enqueued scheduled memory cleanup jobs",
|
|
@@ -437,61 +474,59 @@ export function maybeEnqueueScheduledCleanupJobs(
|
|
|
437
474
|
return true;
|
|
438
475
|
}
|
|
439
476
|
|
|
440
|
-
// ──
|
|
477
|
+
// ── Graph maintenance scheduling ──────────────────────────────────
|
|
441
478
|
|
|
442
|
-
const
|
|
443
|
-
|
|
479
|
+
const GRAPH_DECAY_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
|
|
480
|
+
const GRAPH_CONSOLIDATE_INTERVAL_MS = 4 * 60 * 60 * 1000; // 4 hours
|
|
481
|
+
const GRAPH_PATTERN_SCAN_INTERVAL_MS = 24 * 60 * 60 * 1000; // 1 day
|
|
482
|
+
const GRAPH_NARRATIVE_INTERVAL_MS = 7 * 24 * 60 * 60 * 1000; // 1 week
|
|
444
483
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
484
|
+
const GRAPH_MAINTENANCE_CHECKPOINTS = {
|
|
485
|
+
decay: "graph_maintenance:decay:last_run",
|
|
486
|
+
consolidate: "graph_maintenance:consolidate:last_run",
|
|
487
|
+
patternScan: "graph_maintenance:pattern_scan:last_run",
|
|
488
|
+
narrative: "graph_maintenance:narrative:last_run",
|
|
489
|
+
} as const;
|
|
449
490
|
|
|
450
491
|
/**
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
* This is non-destructive: items keep their data but get an `invalid_at`
|
|
456
|
-
* timestamp that excludes them from retrieval queries.
|
|
492
|
+
* Enqueue periodic graph maintenance jobs (decay, consolidation, pattern scan, narrative).
|
|
493
|
+
* Uses durable checkpoints so intervals survive daemon restarts — jobs only fire
|
|
494
|
+
* when the actual elapsed time since last run exceeds the interval.
|
|
457
495
|
*/
|
|
458
|
-
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
);
|
|
488
|
-
if (
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
"Marked stale memory items as invalid",
|
|
492
|
-
);
|
|
493
|
-
totalMarked += changes;
|
|
496
|
+
function maybeEnqueueGraphMaintenanceJobs(nowMs = Date.now()): void {
|
|
497
|
+
const schedule: Array<{
|
|
498
|
+
key: string;
|
|
499
|
+
intervalMs: number;
|
|
500
|
+
jobType: MemoryJobType;
|
|
501
|
+
}> = [
|
|
502
|
+
{
|
|
503
|
+
key: GRAPH_MAINTENANCE_CHECKPOINTS.decay,
|
|
504
|
+
intervalMs: GRAPH_DECAY_INTERVAL_MS,
|
|
505
|
+
jobType: "graph_decay",
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
key: GRAPH_MAINTENANCE_CHECKPOINTS.consolidate,
|
|
509
|
+
intervalMs: GRAPH_CONSOLIDATE_INTERVAL_MS,
|
|
510
|
+
jobType: "graph_consolidate",
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
key: GRAPH_MAINTENANCE_CHECKPOINTS.patternScan,
|
|
514
|
+
intervalMs: GRAPH_PATTERN_SCAN_INTERVAL_MS,
|
|
515
|
+
jobType: "graph_pattern_scan",
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
key: GRAPH_MAINTENANCE_CHECKPOINTS.narrative,
|
|
519
|
+
intervalMs: GRAPH_NARRATIVE_INTERVAL_MS,
|
|
520
|
+
jobType: "graph_narrative_refine",
|
|
521
|
+
},
|
|
522
|
+
];
|
|
523
|
+
|
|
524
|
+
for (const { key, intervalMs, jobType } of schedule) {
|
|
525
|
+
const lastRun = parseInt(getMemoryCheckpoint(key) ?? "0", 10);
|
|
526
|
+
if (nowMs - lastRun >= intervalMs) {
|
|
527
|
+
enqueueMemoryJob(jobType, {});
|
|
528
|
+
setMemoryCheckpoint(key, String(nowMs));
|
|
494
529
|
}
|
|
495
530
|
}
|
|
496
|
-
return totalMarked;
|
|
497
531
|
}
|
|
532
|
+
|