@vellumai/assistant 0.5.15 → 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 +3 -3
- package/Dockerfile +0 -3
- package/docs/architecture/integrations.md +15 -14
- package/knip.json +4 -1
- package/openapi.yaml +670 -122
- 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 +5 -377
- 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__/ces-rpc-credential-backend.test.ts +4 -1
- 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 +84 -3
- package/src/__tests__/clawhub.test.ts +54 -24
- package/src/__tests__/cli-command-risk-guard.test.ts +108 -6
- package/src/__tests__/cli-memory.test.ts +377 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -2
- package/src/__tests__/config-schema.test.ts +1 -3
- package/src/__tests__/config-set-platform-guard.test.ts +302 -0
- package/src/__tests__/config-watcher-feature-flags.test.ts +211 -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-runtime-assembly.test.ts +7 -4
- package/src/__tests__/conversation-slash-commands.test.ts +2 -6
- 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 +3 -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 +6 -1
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +7 -73
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -7
- 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 +343 -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__/heartbeat-service.test.ts +1 -3
- 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__/intent-routing.test.ts +6 -18
- 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 +4 -34
- package/src/__tests__/managed-skill-lifecycle.test.ts +7 -37
- package/src/__tests__/managed-store.test.ts +40 -21
- 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__/messaging-send-tool.test.ts +6 -6
- package/src/__tests__/migration-cross-version-compatibility.test.ts +1 -29
- package/src/__tests__/migration-export-http.test.ts +3 -34
- package/src/__tests__/migration-import-commit-http.test.ts +1 -29
- package/src/__tests__/migration-import-preflight-http.test.ts +3 -34
- package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +2 -1
- 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-apps-routes.test.ts +120 -10
- package/src/__tests__/oauth-cli.test.ts +364 -2
- package/src/__tests__/oauth-connect-orchestrator.test.ts +709 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +2 -1
- package/src/__tests__/oauth-provider-visibility.test.ts +149 -0
- package/src/__tests__/oauth-providers-routes.test.ts +5 -2
- package/src/__tests__/oauth-store.test.ts +0 -5
- 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 +1071 -0
- package/src/__tests__/outlook-trash.test.ts +77 -0
- package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
- package/src/__tests__/path-policy.test.ts +2 -17
- package/src/__tests__/permission-types.test.ts +0 -1
- package/src/__tests__/platform-callback-registration.test.ts +7 -11
- package/src/__tests__/playbook-execution.test.ts +76 -80
- package/src/__tests__/playbook-tools.test.ts +5 -7
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
- package/src/__tests__/provider-error-scenarios.test.ts +21 -2
- package/src/__tests__/qdrant-manager.test.ts +68 -21
- 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 -3
- package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
- package/src/__tests__/runtime-events-sse.test.ts +2 -6
- package/src/__tests__/sandbox-diagnostics.test.ts +20 -29
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +2 -10
- 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-allowlist.test.ts +20 -35
- 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__/shell-credential-ref.test.ts +0 -5
- 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 +13 -54
- package/src/__tests__/skill-load-inline-command.test.ts +3 -65
- package/src/__tests__/skill-load-inline-includes.test.ts +3 -65
- package/src/__tests__/skill-load-tool.test.ts +3 -67
- package/src/__tests__/skill-memory.test.ts +480 -195
- package/src/__tests__/skills-uninstall.test.ts +2 -2
- package/src/__tests__/skills.test.ts +23 -50
- package/src/__tests__/slack-channel-config.test.ts +2 -21
- package/src/__tests__/slack-inbound-verification.test.ts +2 -6
- package/src/__tests__/starter-bundle.test.ts +2 -8
- package/src/__tests__/stt-hints.test.ts +7 -2
- package/src/__tests__/system-prompt.test.ts +25 -45
- package/src/__tests__/task-compiler.test.ts +2 -27
- package/src/__tests__/task-management-tools.test.ts +2 -27
- package/src/__tests__/task-memory-cleanup.test.ts +173 -250
- package/src/__tests__/task-runner.test.ts +2 -27
- package/src/__tests__/task-scheduler.test.ts +2 -27
- package/src/__tests__/terminal-tools.test.ts +1 -17
- package/src/__tests__/test-preload.ts +3 -0
- package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +0 -79
- package/src/__tests__/tool-approval-handler.test.ts +4 -27
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +2 -11
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -25
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +4 -27
- package/src/__tests__/tool-preview-lifecycle.test.ts +0 -20
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
- package/src/__tests__/trust-store.test.ts +10 -42
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -30
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +3 -27
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -28
- package/src/__tests__/trusted-contact-multichannel.test.ts +2 -28
- package/src/__tests__/trusted-contact-verification.test.ts +2 -28
- package/src/__tests__/turn-boundary-resolution.test.ts +2 -34
- package/src/__tests__/twilio-provider.test.ts +0 -16
- package/src/__tests__/twilio-routes-twiml.test.ts +7 -12
- package/src/__tests__/twilio-routes.test.ts +0 -24
- package/src/__tests__/update-bulletin.test.ts +17 -89
- package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -26
- package/src/__tests__/usage-routes.test.ts +2 -27
- package/src/__tests__/user-reference.test.ts +1 -5
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +4 -34
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -53
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-invite-redemption.test.ts +2 -27
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -30
- package/src/__tests__/voice-session-bridge.test.ts +2 -27
- 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 +4 -29
- package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +2 -2
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +4 -29
- package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
- package/src/__tests__/workspace-migration-down-functions.test.ts +0 -6
- package/src/__tests__/workspace-policy.test.ts +1 -1
- package/src/acp/client-handler.ts +1 -2
- 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 -24
- package/src/cli/cli-memory.ts +179 -0
- 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__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
- package/src/cli/commands/oauth/connect.ts +26 -6
- package/src/cli/commands/oauth/mode.ts +7 -0
- package/src/cli/commands/oauth/providers.ts +49 -42
- package/src/cli/commands/oauth/shared.ts +39 -3
- package/src/cli/commands/platform/__tests__/connect.test.ts +3 -49
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +3 -49
- package/src/cli/commands/platform/__tests__/status.test.ts +5 -55
- 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/computer-use/TOOLS.json +7 -7
- 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 +26 -19
- 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/settings/TOOLS.json +3 -3
- 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 +29 -116
- package/src/config/loader.ts +4 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/security.ts +0 -6
- package/src/config/schemas/services.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 +32 -9
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/process-manager.ts +3 -1
- package/src/daemon/config-watcher.ts +51 -0
- 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 +99 -63
- 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-process.ts +1 -0
- package/src/daemon/conversation-runtime-assembly.ts +5 -0
- package/src/daemon/conversation-usage.ts +1 -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 +423 -201
- package/src/daemon/lifecycle.ts +52 -4
- package/src/daemon/main.ts +5 -1
- package/src/daemon/message-types/conversations.ts +5 -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 +7 -0
- package/src/daemon/server.ts +35 -22
- package/src/daemon/tool-side-effects.ts +27 -5
- package/src/events/domain-events.ts +1 -2
- 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 +39 -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.test.ts +3 -27
- 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/llm-usage-store.ts +35 -2
- package/src/memory/message-content.ts +1 -0
- package/src/memory/migrations/201-oauth-providers-feature-flag.ts +11 -0
- package/src/memory/migrations/202-drop-callback-transport-column.ts +13 -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 +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/qdrant-client.ts +44 -17
- package/src/memory/qdrant-manager.ts +26 -5
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/memory-graph.ts +139 -0
- package/src/memory/schema/oauth.ts +1 -1
- package/src/memory/search/semantic.ts +47 -91
- package/src/memory/slack-thread-store.ts +17 -0
- package/src/memory/task-memory-cleanup.ts +28 -50
- package/src/messaging/providers/outlook/adapter.ts +200 -0
- package/src/messaging/providers/outlook/client.ts +610 -0
- package/src/messaging/providers/outlook/types.ts +201 -0
- package/src/notifications/adapters/macos.ts +1 -0
- package/src/notifications/adapters/slack.ts +1 -1
- package/src/notifications/copy-composer.ts +9 -0
- package/src/notifications/signal.ts +16 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +1 -1
- package/src/oauth/connect-orchestrator.ts +10 -3
- package/src/oauth/oauth-store.ts +10 -11
- package/src/oauth/provider-serializer.ts +3 -0
- package/src/oauth/provider-visibility.ts +16 -0
- package/src/oauth/seed-providers.ts +50 -17
- package/src/permissions/checker.ts +62 -9
- package/src/permissions/defaults.ts +4 -4
- package/src/permissions/types.ts +2 -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 +6 -93
- package/src/prompts/templates/UPDATES.md +6 -0
- 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/__tests__/credential-service.test.ts +1 -27
- package/src/runtime/auth/__tests__/token-service.test.ts +1 -25
- package/src/runtime/auth/route-policy.ts +7 -4
- package/src/runtime/guardian-reply-router.ts +10 -2
- 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-query-routes.ts +2 -58
- 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/background-dispatch.ts +43 -2
- 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 -31
- package/src/runtime/routes/memory-item-routes.ts +385 -341
- package/src/runtime/routes/oauth-apps.ts +18 -1
- package/src/runtime/routes/oauth-providers.ts +13 -1
- package/src/runtime/routes/schedule-routes.ts +2 -0
- package/src/runtime/routes/settings-routes.ts +1 -0
- package/src/runtime/routes/skills-routes.ts +103 -37
- package/src/runtime/routes/usage-routes.ts +19 -2
- package/src/runtime/routes/work-items-routes.test.ts +2 -27
- package/src/runtime/routes/workspace-routes.test.ts +3 -27
- package/src/schedule/scheduler.ts +8 -1
- package/src/security/oauth2.ts +1 -1
- package/src/security/secret-allowlist.ts +4 -4
- 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 +210 -96
- 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 -19
- package/src/tools/shared/filesystem/image-read.ts +22 -85
- package/src/tools/skills/skill-script-runner.ts +1 -1
- 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/util/device-id.ts +3 -65
- package/src/watcher/providers/outlook-calendar.ts +343 -0
- package/src/watcher/providers/outlook.ts +198 -0
- package/src/workspace/git-service.ts +27 -6
- 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 -741
- package/src/memory/job-handlers/extraction.ts +0 -40
- package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -383
- 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 -1590
- package/src/memory/retriever.ts +0 -1323
- package/src/memory/search/formatting.test.ts +0 -140
- package/src/memory/search/formatting.ts +0 -262
- package/src/memory/search/mmr.ts +0 -136
- 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 -156
- package/src/tools/memory/definitions.ts +0 -69
- package/src/tools/memory/handlers.test.ts +0 -590
- package/src/tools/memory/handlers.ts +0 -434
|
@@ -8,15 +8,42 @@ import type {
|
|
|
8
8
|
QdrantSparseVector,
|
|
9
9
|
} from "../qdrant-client.js";
|
|
10
10
|
import { getQdrantClient } from "../qdrant-client.js";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
import { conversations, memorySegments, memorySummaries } from "../schema.js";
|
|
12
|
+
// ── Types (inlined from deleted types.ts) ──────────────────────────
|
|
13
|
+
|
|
14
|
+
type CandidateType = "segment" | "item" | "summary" | "media";
|
|
15
|
+
|
|
16
|
+
export interface Candidate {
|
|
17
|
+
key: string;
|
|
18
|
+
type: CandidateType;
|
|
19
|
+
id: string;
|
|
20
|
+
source: "semantic";
|
|
21
|
+
text: string;
|
|
22
|
+
kind: string;
|
|
23
|
+
modality?: "text" | "image" | "audio" | "video";
|
|
24
|
+
conversationId?: string;
|
|
25
|
+
messageId?: string;
|
|
26
|
+
confidence: number;
|
|
27
|
+
importance: number;
|
|
28
|
+
createdAt: number;
|
|
29
|
+
semantic: number;
|
|
30
|
+
recency: number;
|
|
31
|
+
finalScore: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ── Recency scoring (inlined from deleted ranking.ts) ──────────────
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Logarithmic recency decay (ACT-R inspired).
|
|
38
|
+
*
|
|
39
|
+
* 1 day -> 0.50, 7 days -> 0.25, 30 days -> 0.17
|
|
40
|
+
* 90 days -> 0.15, 1 year -> 0.12, 2 years -> 0.10
|
|
41
|
+
*/
|
|
42
|
+
function computeRecencyScore(createdAt: number): number {
|
|
43
|
+
const ageMs = Math.max(0, Date.now() - createdAt);
|
|
44
|
+
const ageDays = ageMs / (24 * 60 * 60 * 1000);
|
|
45
|
+
return 1 / (1 + Math.log2(1 + ageDays));
|
|
46
|
+
}
|
|
20
47
|
|
|
21
48
|
const _log = getLogger("semantic-search");
|
|
22
49
|
|
|
@@ -27,7 +54,7 @@ export async function semanticSearch(
|
|
|
27
54
|
limit: number,
|
|
28
55
|
excludedMessageIds: string[] = [],
|
|
29
56
|
scopeIds?: string[],
|
|
30
|
-
sparseVector?: QdrantSparseVector
|
|
57
|
+
sparseVector?: QdrantSparseVector
|
|
31
58
|
): Promise<Candidate[]> {
|
|
32
59
|
if (limit <= 0) return [];
|
|
33
60
|
|
|
@@ -52,31 +79,28 @@ export async function semanticSearch(
|
|
|
52
79
|
filter,
|
|
53
80
|
limit: fetchLimit,
|
|
54
81
|
prefetchLimit: fetchLimit,
|
|
55
|
-
})
|
|
82
|
+
})
|
|
56
83
|
);
|
|
57
84
|
} else {
|
|
58
85
|
results = await withQdrantBreaker(() =>
|
|
59
86
|
qdrant.searchWithFilter(
|
|
60
87
|
queryVector,
|
|
61
88
|
fetchLimit,
|
|
62
|
-
["
|
|
89
|
+
["summary", "segment", "media"],
|
|
63
90
|
excludedMessageIds,
|
|
64
|
-
scopeIds
|
|
65
|
-
)
|
|
91
|
+
scopeIds
|
|
92
|
+
)
|
|
66
93
|
);
|
|
67
94
|
}
|
|
68
95
|
|
|
69
96
|
const db = getDb();
|
|
70
97
|
|
|
71
98
|
// Batch-fetch all backing records upfront to avoid N+1 queries per result
|
|
72
|
-
const itemTargetIds: string[] = [];
|
|
73
99
|
const summaryTargetIds: string[] = [];
|
|
74
100
|
const segmentTargetIds: string[] = [];
|
|
75
101
|
const mediaConversationIds: string[] = [];
|
|
76
102
|
for (const r of results) {
|
|
77
|
-
if (r.payload.target_type === "
|
|
78
|
-
itemTargetIds.push(r.payload.target_id);
|
|
79
|
-
else if (r.payload.target_type === "summary")
|
|
103
|
+
if (r.payload.target_type === "summary")
|
|
80
104
|
summaryTargetIds.push(r.payload.target_id);
|
|
81
105
|
else if (r.payload.target_type === "segment")
|
|
82
106
|
segmentTargetIds.push(r.payload.target_id);
|
|
@@ -84,33 +108,6 @@ export async function semanticSearch(
|
|
|
84
108
|
mediaConversationIds.push(r.payload.conversation_id);
|
|
85
109
|
}
|
|
86
110
|
|
|
87
|
-
const itemsMap = new Map<string, typeof memoryItems.$inferSelect>();
|
|
88
|
-
if (itemTargetIds.length > 0) {
|
|
89
|
-
const allItems = db
|
|
90
|
-
.select()
|
|
91
|
-
.from(memoryItems)
|
|
92
|
-
.where(inArray(memoryItems.id, itemTargetIds))
|
|
93
|
-
.all();
|
|
94
|
-
for (const item of allItems) itemsMap.set(item.id, item);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const sourcesMap = new Map<string, string[]>();
|
|
98
|
-
if (itemTargetIds.length > 0) {
|
|
99
|
-
const allSources = db
|
|
100
|
-
.select({
|
|
101
|
-
memoryItemId: memoryItemSources.memoryItemId,
|
|
102
|
-
messageId: memoryItemSources.messageId,
|
|
103
|
-
})
|
|
104
|
-
.from(memoryItemSources)
|
|
105
|
-
.where(inArray(memoryItemSources.memoryItemId, itemTargetIds))
|
|
106
|
-
.all();
|
|
107
|
-
for (const s of allSources) {
|
|
108
|
-
const existing = sourcesMap.get(s.memoryItemId);
|
|
109
|
-
if (existing) existing.push(s.messageId);
|
|
110
|
-
else sourcesMap.set(s.memoryItemId, [s.messageId]);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
111
|
const summariesMap = new Map<string, typeof memorySummaries.$inferSelect>();
|
|
115
112
|
if (scopeIds && summaryTargetIds.length > 0) {
|
|
116
113
|
const allSummaries = db
|
|
@@ -148,8 +145,6 @@ export async function semanticSearch(
|
|
|
148
145
|
for (const row of rows) mediaScopeMap.set(row.id, row.memoryScopeId);
|
|
149
146
|
}
|
|
150
147
|
|
|
151
|
-
const excludedSet =
|
|
152
|
-
excludedMessageIds.length > 0 ? new Set(excludedMessageIds) : null;
|
|
153
148
|
|
|
154
149
|
const candidates: Candidate[] = [];
|
|
155
150
|
for (const result of results) {
|
|
@@ -159,29 +154,8 @@ export async function semanticSearch(
|
|
|
159
154
|
const createdAt = payload.created_at ?? Date.now();
|
|
160
155
|
|
|
161
156
|
if (payload.target_type === "item") {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (scopeIds && !scopeIds.includes(item.scopeId)) continue;
|
|
165
|
-
const sources = sourcesMap.get(payload.target_id);
|
|
166
|
-
if (!sources || sources.length === 0) continue;
|
|
167
|
-
if (excludedSet) {
|
|
168
|
-
const hasNonExcluded = sources.some((msgId) => !excludedSet.has(msgId));
|
|
169
|
-
if (!hasNonExcluded) continue;
|
|
170
|
-
}
|
|
171
|
-
candidates.push({
|
|
172
|
-
key: `item:${payload.target_id}`,
|
|
173
|
-
type: "item",
|
|
174
|
-
id: payload.target_id,
|
|
175
|
-
source: "semantic",
|
|
176
|
-
text: `${item.subject}: ${item.statement}`,
|
|
177
|
-
kind: item.kind,
|
|
178
|
-
confidence: item.confidence,
|
|
179
|
-
importance: item.importance ?? 0.5,
|
|
180
|
-
createdAt: item.lastSeenAt,
|
|
181
|
-
semantic,
|
|
182
|
-
recency: computeRecencyScore(item.lastSeenAt),
|
|
183
|
-
finalScore: 0,
|
|
184
|
-
});
|
|
157
|
+
// Legacy item vectors — skip (table dropped, Qdrant cleanup pending)
|
|
158
|
+
continue;
|
|
185
159
|
} else if (payload.target_type === "summary") {
|
|
186
160
|
if (scopeIds) {
|
|
187
161
|
const summary = summariesMap.get(payload.target_id);
|
|
@@ -284,33 +258,15 @@ export async function semanticSearch(
|
|
|
284
258
|
*/
|
|
285
259
|
function buildHybridFilter(
|
|
286
260
|
excludeMessageIds: string[],
|
|
287
|
-
scopeIds?: string[]
|
|
261
|
+
scopeIds?: string[]
|
|
288
262
|
): Record<string, unknown> {
|
|
289
263
|
const mustConditions: Array<Record<string, unknown>> = [
|
|
290
264
|
{
|
|
291
265
|
key: "target_type",
|
|
292
|
-
match: { any: ["
|
|
266
|
+
match: { any: ["summary", "segment", "media"] },
|
|
293
267
|
},
|
|
294
268
|
];
|
|
295
269
|
|
|
296
|
-
if (excludeMessageIds.length > 0) {
|
|
297
|
-
// Only require status=active for items; segments and summaries don't have a status field
|
|
298
|
-
mustConditions.push({
|
|
299
|
-
should: [
|
|
300
|
-
{
|
|
301
|
-
must: [
|
|
302
|
-
{ key: "target_type", match: { value: "item" } },
|
|
303
|
-
{ key: "status", match: { value: "active" } },
|
|
304
|
-
],
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
key: "target_type",
|
|
308
|
-
match: { any: ["segment", "summary", "media"] },
|
|
309
|
-
},
|
|
310
|
-
],
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
|
|
314
270
|
// Scope filtering: accept points whose memory_scope_id matches one of the
|
|
315
271
|
// allowed scopes, OR points that lack the field entirely (legacy data).
|
|
316
272
|
// Post-query DB filtering remains as defense-in-depth for legacy points.
|
|
@@ -346,6 +302,6 @@ export function mapCosineToUnit(value: number): number {
|
|
|
346
302
|
export function isQdrantConnectionError(err: unknown): boolean {
|
|
347
303
|
if (!(err instanceof Error)) return false;
|
|
348
304
|
return /ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENETUNREACH|fetch failed/i.test(
|
|
349
|
-
err.message
|
|
305
|
+
err.message
|
|
350
306
|
);
|
|
351
307
|
}
|
|
@@ -78,6 +78,23 @@ export function extractThreadTsFromCallbackUrl(
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Extract the messageTs from a Slack reply callback URL, if present.
|
|
83
|
+
* The gateway encodes messageTs for non-threaded DMs so the runtime
|
|
84
|
+
* can target the original message for emoji-based indicators.
|
|
85
|
+
*/
|
|
86
|
+
export function extractMessageTsFromCallbackUrl(
|
|
87
|
+
callbackUrl: string | undefined,
|
|
88
|
+
): string | null {
|
|
89
|
+
if (!callbackUrl) return null;
|
|
90
|
+
try {
|
|
91
|
+
const url = new URL(callbackUrl);
|
|
92
|
+
return url.searchParams.get("messageTs");
|
|
93
|
+
} catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
81
98
|
/**
|
|
82
99
|
* Extract the channel from a Slack reply callback URL, if present.
|
|
83
100
|
*/
|
|
@@ -24,62 +24,41 @@ export function isConversationFailed(conversationId: string): boolean {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* Invalidate assistant-
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
27
|
+
* Invalidate assistant-inferred memory graph nodes sourced *exclusively* from
|
|
28
|
+
* the given conversation. Called when a background task or schedule fails —
|
|
29
|
+
* the assistant's optimistic claims are not trustworthy if the task didn't
|
|
30
|
+
* complete.
|
|
31
31
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* Items that also have sources from other conversations are left alone
|
|
37
|
-
* only when those conversations come from non-failed task/schedule runs
|
|
38
|
-
* (or are ordinary user conversations). This prevents cascading failures
|
|
39
|
-
* from mutually protecting each other — if two conversations both source
|
|
40
|
-
* a memory item and both fail, the item is correctly invalidated.
|
|
32
|
+
* Nodes that also have sources from other non-failed conversations are left
|
|
33
|
+
* alone (corroboration). Uses the `source_conversations` JSON array to
|
|
34
|
+
* determine provenance.
|
|
41
35
|
*/
|
|
42
36
|
export function invalidateAssistantInferredItemsForConversation(
|
|
43
37
|
conversationId: string,
|
|
44
38
|
): number {
|
|
45
|
-
// Cancel pending extraction jobs for this conversation's messages
|
|
46
|
-
// so the worker never processes them. Jobs already running will be
|
|
47
|
-
// caught by the isConversationFailed check in the extraction handler.
|
|
48
|
-
// NOTE: Only extract_items jobs are cancelled here — not embed_item or
|
|
49
|
-
// other job types. Multi-sourced items may still be valid (corroborated
|
|
50
|
-
// by other conversations), and their embedding jobs must not be killed.
|
|
51
|
-
// The broader cancelPendingJobsForConversation is used by the wipe path.
|
|
52
39
|
cancelPendingExtractionJobsForConversation(conversationId);
|
|
53
40
|
|
|
54
41
|
const affected = rawRun(
|
|
55
|
-
`UPDATE
|
|
56
|
-
SET
|
|
57
|
-
|
|
58
|
-
WHERE source_type = '
|
|
59
|
-
AND
|
|
60
|
-
AND
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
FROM memory_item_sources mis
|
|
64
|
-
JOIN messages m ON m.id = mis.message_id
|
|
65
|
-
WHERE m.conversation_id = ?
|
|
42
|
+
`UPDATE memory_graph_nodes
|
|
43
|
+
SET fidelity = 'gone',
|
|
44
|
+
last_accessed = ?
|
|
45
|
+
WHERE source_type = 'inferred'
|
|
46
|
+
AND fidelity != 'gone'
|
|
47
|
+
AND EXISTS (
|
|
48
|
+
SELECT 1 FROM json_each(source_conversations) jc
|
|
49
|
+
WHERE jc.value = ?
|
|
66
50
|
)
|
|
67
51
|
AND NOT EXISTS (
|
|
68
|
-
SELECT 1
|
|
69
|
-
|
|
70
|
-
JOIN messages m2 ON m2.id = mis2.message_id
|
|
71
|
-
WHERE mis2.memory_item_id = memory_items.id
|
|
72
|
-
AND m2.conversation_id != ?
|
|
73
|
-
-- Only count as corroboration if the other conversation is NOT
|
|
74
|
-
-- from a failed task run or failed schedule run.
|
|
52
|
+
SELECT 1 FROM json_each(source_conversations) jc2
|
|
53
|
+
WHERE jc2.value != ?
|
|
75
54
|
AND NOT EXISTS (
|
|
76
55
|
SELECT 1 FROM task_runs tr
|
|
77
|
-
WHERE tr.conversation_id =
|
|
56
|
+
WHERE tr.conversation_id = jc2.value
|
|
78
57
|
AND tr.status = 'failed'
|
|
79
58
|
)
|
|
80
59
|
AND NOT EXISTS (
|
|
81
60
|
SELECT 1 FROM cron_runs cr
|
|
82
|
-
WHERE cr.conversation_id =
|
|
61
|
+
WHERE cr.conversation_id = jc2.value
|
|
83
62
|
AND cr.status = 'error'
|
|
84
63
|
)
|
|
85
64
|
)`,
|
|
@@ -91,7 +70,7 @@ export function invalidateAssistantInferredItemsForConversation(
|
|
|
91
70
|
if (affected > 0) {
|
|
92
71
|
log.info(
|
|
93
72
|
{ conversationId, affected },
|
|
94
|
-
"Invalidated assistant-inferred memory
|
|
73
|
+
"Invalidated assistant-inferred memory graph nodes after task failure",
|
|
95
74
|
);
|
|
96
75
|
}
|
|
97
76
|
|
|
@@ -103,7 +82,7 @@ export function invalidateAssistantInferredItemsForConversation(
|
|
|
103
82
|
* Covers every job type: `extract_items`, `embed_attachment` (keyed by messageId),
|
|
104
83
|
* `embed_segment` (keyed by segmentId via memory_segments),
|
|
105
84
|
* `build_conversation_summary` (keyed by conversationId),
|
|
106
|
-
* and `
|
|
85
|
+
* and `embed_graph_node` (keyed by nodeId sourced from the conversation).
|
|
107
86
|
*/
|
|
108
87
|
export function cancelPendingJobsForConversation(
|
|
109
88
|
conversationId: string,
|
|
@@ -155,18 +134,17 @@ export function cancelPendingJobsForConversation(
|
|
|
155
134
|
conversationId,
|
|
156
135
|
);
|
|
157
136
|
|
|
158
|
-
// Jobs keyed by
|
|
137
|
+
// Jobs keyed by nodeId: embed_graph_node (nodes sourced from this conversation)
|
|
159
138
|
total += rawRun(
|
|
160
139
|
`UPDATE memory_jobs
|
|
161
140
|
SET status = 'failed',
|
|
162
141
|
last_error = ?,
|
|
163
142
|
updated_at = ?
|
|
164
143
|
WHERE status IN ('pending', 'running')
|
|
165
|
-
AND json_extract(payload, '$.
|
|
166
|
-
SELECT
|
|
167
|
-
FROM
|
|
168
|
-
|
|
169
|
-
WHERE m.conversation_id = ?
|
|
144
|
+
AND json_extract(payload, '$.nodeId') IN (
|
|
145
|
+
SELECT mgn.id
|
|
146
|
+
FROM memory_graph_nodes mgn, json_each(mgn.source_conversations) jc
|
|
147
|
+
WHERE jc.value = ?
|
|
170
148
|
)`,
|
|
171
149
|
reason,
|
|
172
150
|
now,
|
|
@@ -186,8 +164,8 @@ export function cancelPendingJobsForConversation(
|
|
|
186
164
|
/**
|
|
187
165
|
* Cancel only pending/running `extract_items` jobs for messages in the
|
|
188
166
|
* given conversation. Used by the task-failure path where we want to
|
|
189
|
-
* stop new extractions but must NOT cancel `
|
|
190
|
-
*
|
|
167
|
+
* stop new extractions but must NOT cancel `embed_graph_node` jobs —
|
|
168
|
+
* those nodes may be multi-sourced and still valid.
|
|
191
169
|
*/
|
|
192
170
|
function cancelPendingExtractionJobsForConversation(
|
|
193
171
|
conversationId: string,
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outlook messaging provider adapter.
|
|
3
|
+
*
|
|
4
|
+
* Maps Microsoft Graph API responses to the platform-agnostic messaging types
|
|
5
|
+
* and implements the MessagingProvider interface.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { OAuthConnection } from "../../../oauth/connection.js";
|
|
9
|
+
import type { MessagingProvider } from "../../provider.js";
|
|
10
|
+
import type {
|
|
11
|
+
ConnectionInfo,
|
|
12
|
+
Conversation,
|
|
13
|
+
HistoryOptions,
|
|
14
|
+
ListOptions,
|
|
15
|
+
Message,
|
|
16
|
+
SearchOptions,
|
|
17
|
+
SearchResult,
|
|
18
|
+
SendOptions,
|
|
19
|
+
SendResult,
|
|
20
|
+
} from "../../provider-types.js";
|
|
21
|
+
import * as outlook from "./client.js";
|
|
22
|
+
import type { OutlookMessage } from "./types.js";
|
|
23
|
+
|
|
24
|
+
function requireConnection(
|
|
25
|
+
connection: OAuthConnection | undefined,
|
|
26
|
+
): OAuthConnection {
|
|
27
|
+
if (!connection) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
"Outlook requires an OAuth connection — is the account connected?",
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return connection;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function mapOutlookMessage(msg: OutlookMessage): Message {
|
|
36
|
+
const senderEmail = msg.from?.emailAddress?.address ?? "";
|
|
37
|
+
const senderName = msg.from?.emailAddress?.name || senderEmail || "Unknown";
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
id: msg.id,
|
|
41
|
+
conversationId: msg.conversationId,
|
|
42
|
+
sender: {
|
|
43
|
+
id: senderEmail,
|
|
44
|
+
name: senderName,
|
|
45
|
+
email: senderEmail,
|
|
46
|
+
},
|
|
47
|
+
text: msg.body.contentType === "text" ? msg.body.content : msg.bodyPreview,
|
|
48
|
+
timestamp: new Date(msg.receivedDateTime).getTime(),
|
|
49
|
+
threadId: msg.conversationId,
|
|
50
|
+
platform: "outlook",
|
|
51
|
+
hasAttachments: msg.hasAttachments ?? false,
|
|
52
|
+
metadata: {
|
|
53
|
+
subject: msg.subject,
|
|
54
|
+
categories: msg.categories,
|
|
55
|
+
isRead: msg.isRead,
|
|
56
|
+
parentFolderId: msg.parentFolderId,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const MESSAGE_SELECT_FIELDS =
|
|
62
|
+
"id,conversationId,subject,bodyPreview,body,from,toRecipients,receivedDateTime,isRead,hasAttachments,parentFolderId,categories,flag";
|
|
63
|
+
|
|
64
|
+
export const outlookMessagingProvider: MessagingProvider = {
|
|
65
|
+
id: "outlook",
|
|
66
|
+
displayName: "Outlook",
|
|
67
|
+
credentialService: "outlook",
|
|
68
|
+
capabilities: new Set([
|
|
69
|
+
"threads",
|
|
70
|
+
"folders",
|
|
71
|
+
"categories",
|
|
72
|
+
"drafts_native",
|
|
73
|
+
"archive",
|
|
74
|
+
"unsubscribe",
|
|
75
|
+
]),
|
|
76
|
+
|
|
77
|
+
async testConnection(connection?: OAuthConnection): Promise<ConnectionInfo> {
|
|
78
|
+
const conn = requireConnection(connection);
|
|
79
|
+
const profile = await outlook.getProfile(conn);
|
|
80
|
+
return {
|
|
81
|
+
connected: true,
|
|
82
|
+
user: profile.mail || profile.userPrincipalName,
|
|
83
|
+
platform: "outlook",
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
async listConversations(
|
|
88
|
+
connection: OAuthConnection | undefined,
|
|
89
|
+
_options?: ListOptions,
|
|
90
|
+
): Promise<Conversation[]> {
|
|
91
|
+
const conn = requireConnection(connection);
|
|
92
|
+
const folders = await outlook.listMailFolders(conn);
|
|
93
|
+
return folders.map((folder) => ({
|
|
94
|
+
id: folder.id,
|
|
95
|
+
name: folder.displayName,
|
|
96
|
+
type: "inbox" as const,
|
|
97
|
+
platform: "outlook",
|
|
98
|
+
unreadCount: folder.unreadItemCount ?? 0,
|
|
99
|
+
lastActivityAt: Date.now(),
|
|
100
|
+
metadata: {
|
|
101
|
+
totalItemCount: folder.totalItemCount,
|
|
102
|
+
childFolderCount: folder.childFolderCount,
|
|
103
|
+
},
|
|
104
|
+
}));
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
async getHistory(
|
|
108
|
+
connection: OAuthConnection | undefined,
|
|
109
|
+
conversationId: string,
|
|
110
|
+
options?: HistoryOptions,
|
|
111
|
+
): Promise<Message[]> {
|
|
112
|
+
const conn = requireConnection(connection);
|
|
113
|
+
const result = await outlook.listMessages(conn, {
|
|
114
|
+
folderId: conversationId,
|
|
115
|
+
top: options?.limit ?? 50,
|
|
116
|
+
orderby: "receivedDateTime desc",
|
|
117
|
+
select: MESSAGE_SELECT_FIELDS,
|
|
118
|
+
});
|
|
119
|
+
return (result.value ?? []).map(mapOutlookMessage);
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
async search(
|
|
123
|
+
connection: OAuthConnection | undefined,
|
|
124
|
+
query: string,
|
|
125
|
+
options?: SearchOptions,
|
|
126
|
+
): Promise<SearchResult> {
|
|
127
|
+
const conn = requireConnection(connection);
|
|
128
|
+
const result = await outlook.searchMessages(conn, query, {
|
|
129
|
+
top: options?.count ?? 20,
|
|
130
|
+
});
|
|
131
|
+
const messages = result.value ?? [];
|
|
132
|
+
return {
|
|
133
|
+
total: result["@odata.count"] ?? messages.length,
|
|
134
|
+
messages: messages.map(mapOutlookMessage),
|
|
135
|
+
hasMore: !!result["@odata.nextLink"],
|
|
136
|
+
};
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
async sendMessage(
|
|
140
|
+
connection: OAuthConnection | undefined,
|
|
141
|
+
conversationId: string,
|
|
142
|
+
text: string,
|
|
143
|
+
options?: SendOptions,
|
|
144
|
+
): Promise<SendResult> {
|
|
145
|
+
const conn = requireConnection(connection);
|
|
146
|
+
|
|
147
|
+
if (options?.inReplyTo) {
|
|
148
|
+
await outlook.replyToMessage(conn, options.inReplyTo, text);
|
|
149
|
+
return {
|
|
150
|
+
id: "",
|
|
151
|
+
timestamp: Date.now(),
|
|
152
|
+
conversationId,
|
|
153
|
+
threadId: options?.threadId,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
await outlook.sendMessage(conn, {
|
|
158
|
+
message: {
|
|
159
|
+
subject: options?.subject ?? "",
|
|
160
|
+
body: { contentType: "text", content: text },
|
|
161
|
+
toRecipients: [{ emailAddress: { address: conversationId } }],
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Microsoft Graph's sendMail returns 202 with no body
|
|
166
|
+
return {
|
|
167
|
+
id: "",
|
|
168
|
+
timestamp: Date.now(),
|
|
169
|
+
conversationId,
|
|
170
|
+
threadId: options?.threadId,
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
async getThreadReplies(
|
|
175
|
+
connection: OAuthConnection | undefined,
|
|
176
|
+
_conversationId: string,
|
|
177
|
+
threadId: string,
|
|
178
|
+
options?: HistoryOptions,
|
|
179
|
+
): Promise<Message[]> {
|
|
180
|
+
const conn = requireConnection(connection);
|
|
181
|
+
const result = await outlook.listMessages(conn, {
|
|
182
|
+
filter: `conversationId eq '${threadId.replace(/'/g, "''")}'`,
|
|
183
|
+
top: options?.limit ?? 50,
|
|
184
|
+
orderby: "receivedDateTime asc",
|
|
185
|
+
select: MESSAGE_SELECT_FIELDS,
|
|
186
|
+
});
|
|
187
|
+
return (result.value ?? []).map(mapOutlookMessage);
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
async markRead(
|
|
191
|
+
connection: OAuthConnection | undefined,
|
|
192
|
+
_conversationId: string,
|
|
193
|
+
messageId?: string,
|
|
194
|
+
): Promise<void> {
|
|
195
|
+
const conn = requireConnection(connection);
|
|
196
|
+
if (messageId) {
|
|
197
|
+
await outlook.markMessageRead(conn, messageId);
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
};
|