@vellumai/assistant 0.3.4 → 0.3.6
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/Dockerfile +2 -0
- package/README.md +88 -2
- package/eslint.config.mjs +31 -0
- package/package.json +1 -1
- package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
- package/scripts/ipc/generate-swift.ts +31 -2
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +438 -1
- package/src/__tests__/approval-conversation-turn.test.ts +214 -0
- package/src/__tests__/approval-hardcoded-copy-guard.test.ts +41 -0
- package/src/__tests__/approval-message-composer.test.ts +253 -0
- package/src/__tests__/browser-manager.test.ts +1 -0
- package/src/__tests__/call-conversation-messages.test.ts +130 -0
- package/src/__tests__/call-domain.test.ts +12 -2
- package/src/__tests__/call-orchestrator.test.ts +799 -249
- package/src/__tests__/call-pointer-messages.test.ts +148 -0
- package/src/__tests__/call-recovery.test.ts +3 -0
- package/src/__tests__/call-routes-http.test.ts +32 -2
- package/src/__tests__/call-store.test.ts +3 -0
- package/src/__tests__/channel-approval-routes.test.ts +1277 -98
- package/src/__tests__/channel-approval.test.ts +37 -0
- package/src/__tests__/channel-approvals.test.ts +36 -50
- package/src/__tests__/channel-guardian.test.ts +630 -22
- package/src/__tests__/channel-readiness-service.test.ts +324 -0
- package/src/__tests__/checker.test.ts +14 -7
- package/src/__tests__/clarification-resolver.test.ts +44 -24
- package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
- package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
- package/src/__tests__/config-schema.test.ts +14 -8
- package/src/__tests__/context-window-manager.test.ts +30 -2
- package/src/__tests__/contradiction-checker.test.ts +20 -5
- package/src/__tests__/credential-security-invariants.test.ts +7 -2
- package/src/__tests__/daemon-lifecycle.test.ts +13 -12
- package/src/__tests__/db-migration-rollback.test.ts +752 -0
- package/src/__tests__/dictation-mode-detection.test.ts +63 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
- package/src/__tests__/entity-search.test.ts +615 -0
- package/src/__tests__/fuzzy-match-property.test.ts +5 -5
- package/src/__tests__/guardian-action-store.test.ts +123 -0
- package/src/__tests__/guardian-action-sweep.test.ts +277 -0
- package/src/__tests__/guardian-dispatch.test.ts +389 -0
- package/src/__tests__/guardian-question-copy.test.ts +47 -0
- package/src/__tests__/handlers-telegram-config.test.ts +4 -2
- package/src/__tests__/handlers-twilio-config.test.ts +533 -0
- package/src/__tests__/intent-routing.test.ts +2 -0
- package/src/__tests__/ipc-snapshot.test.ts +291 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
- package/src/__tests__/messaging-send-tool.test.ts +65 -0
- package/src/__tests__/model-intents.test.ts +96 -0
- package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
- package/src/__tests__/provider-error-scenarios.test.ts +621 -0
- package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
- package/src/__tests__/qdrant-manager.test.ts +27 -20
- package/src/__tests__/relay-server.test.ts +779 -40
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +6 -0
- package/src/__tests__/run-orchestrator.test.ts +42 -4
- package/src/__tests__/runtime-runs-http.test.ts +17 -1
- package/src/__tests__/runtime-runs.test.ts +16 -0
- package/src/__tests__/schedule-store.test.ts +18 -4
- package/src/__tests__/scheduler-recurrence.test.ts +13 -4
- package/src/__tests__/session-abort-tool-results.test.ts +6 -0
- package/src/__tests__/session-agent-loop.test.ts +857 -0
- package/src/__tests__/session-conflict-gate.test.ts +6 -0
- package/src/__tests__/session-pre-run-repair.test.ts +6 -0
- package/src/__tests__/session-profile-injection.test.ts +6 -0
- package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/session-queue.test.ts +6 -0
- package/src/__tests__/session-runtime-assembly.test.ts +321 -13
- package/src/__tests__/session-slash-known.test.ts +6 -0
- package/src/__tests__/session-slash-queue.test.ts +6 -0
- package/src/__tests__/session-slash-unknown.test.ts +6 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
- package/src/__tests__/session-workspace-injection.test.ts +6 -0
- package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/skills.test.ts +2 -0
- package/src/__tests__/sms-messaging-provider.test.ts +126 -0
- package/src/__tests__/starter-task-flow.test.ts +2 -0
- package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
- package/src/__tests__/system-prompt.test.ts +2 -0
- package/src/__tests__/task-management-tools.test.ts +2 -2
- package/src/__tests__/task-runner.test.ts +14 -4
- package/src/__tests__/terminal-tools.test.ts +25 -19
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
- package/src/__tests__/tool-executor.test.ts +23 -24
- package/src/__tests__/trust-store.test.ts +3 -3
- package/src/__tests__/twilio-rest.test.ts +29 -0
- package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
- package/src/__tests__/twilio-routes.test.ts +167 -11
- package/src/__tests__/twitter-cli-error-shaping.test.ts +2 -2
- package/src/__tests__/user-reference.test.ts +2 -0
- package/src/__tests__/voice-quality.test.ts +222 -0
- package/src/__tests__/web-search.test.ts +46 -30
- package/src/__tests__/work-item-output.test.ts +110 -0
- package/src/agent/loop.ts +1 -1
- package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
- package/src/amazon/client.ts +1418 -0
- package/src/amazon/request-extractor.ts +135 -0
- package/src/amazon/session.ts +109 -0
- package/src/autonomy/autonomy-store.ts +5 -5
- package/src/browser-extension-relay/client.ts +124 -0
- package/src/browser-extension-relay/protocol.ts +63 -0
- package/src/browser-extension-relay/server.ts +177 -0
- package/src/bundler/app-bundler.ts +3 -3
- package/src/bundler/bundle-signer.ts +1 -1
- package/src/bundler/signature-verifier.ts +1 -1
- package/src/calls/call-conversation-messages.ts +33 -0
- package/src/calls/call-domain.ts +114 -10
- package/src/calls/call-orchestrator.ts +268 -59
- package/src/calls/call-pointer-messages.ts +53 -0
- package/src/calls/call-recovery.ts +3 -8
- package/src/calls/call-store.ts +69 -87
- package/src/calls/elevenlabs-config.ts +3 -2
- package/src/calls/guardian-action-sweep.ts +105 -0
- package/src/calls/guardian-dispatch.ts +203 -0
- package/src/calls/guardian-question-copy.ts +133 -0
- package/src/calls/relay-server.ts +466 -8
- package/src/calls/speaker-identification.ts +1 -1
- package/src/calls/twilio-config.ts +22 -14
- package/src/calls/twilio-provider.ts +6 -4
- package/src/calls/twilio-rest.ts +308 -7
- package/src/calls/twilio-routes.ts +65 -12
- package/src/calls/types.ts +3 -1
- package/src/channels/types.ts +25 -0
- package/src/cli/amazon.ts +815 -0
- package/src/cli/config-commands.ts +2 -2
- package/src/cli/core-commands.ts +4 -3
- package/src/cli/influencer.ts +244 -0
- package/src/cli/map.ts +89 -6
- package/src/cli.ts +1 -1
- package/src/config/agent-schema.ts +171 -0
- package/src/config/bundled-skills/amazon/SKILL.md +127 -0
- package/src/config/bundled-skills/amazon/icon.svg +13 -0
- package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
- package/src/config/bundled-skills/browser/SKILL.md +1 -0
- package/src/config/bundled-skills/browser/TOOLS.json +17 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
- package/src/config/bundled-skills/doordash/SKILL.md +51 -51
- package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
- package/src/config/bundled-skills/influencer/SKILL.md +144 -0
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +15 -0
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +56 -0
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +185 -0
- package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +176 -0
- package/src/config/bundled-skills/media-processing/TOOLS.json +230 -0
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
- package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
- package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
- package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +259 -0
- package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +136 -0
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +59 -0
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +195 -0
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +197 -0
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +143 -0
- package/src/config/bundled-skills/media-processing/tools/media-status.ts +75 -0
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +65 -0
- package/src/config/bundled-skills/messaging/SKILL.md +33 -8
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +88 -23
- package/src/config/bundled-skills/twitter/SKILL.md +19 -3
- package/src/config/bundled-skills/twitter/icon.svg +14 -0
- package/src/config/bundled-tool-registry.ts +310 -0
- package/src/config/calls-schema.ts +181 -0
- package/src/config/core-schema.ts +309 -0
- package/src/config/defaults.ts +28 -3
- package/src/config/env-registry.ts +162 -0
- package/src/config/env.ts +175 -0
- package/src/config/loader.ts +6 -6
- package/src/config/memory-schema.ts +528 -0
- package/src/config/sandbox-schema.ts +55 -0
- package/src/config/schema.ts +158 -1133
- package/src/config/skill-state.ts +1 -1
- package/src/config/skills-schema.ts +32 -0
- package/src/config/skills.ts +35 -24
- package/src/config/system-prompt.ts +131 -56
- package/src/config/templates/IDENTITY.md +2 -2
- package/src/config/templates/SOUL.md +1 -1
- package/src/config/types.ts +1 -0
- package/src/config/user-reference.ts +4 -9
- package/src/config/vellum-skills/catalog.json +6 -7
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +4 -3
- package/src/config/vellum-skills/sms-setup/SKILL.md +216 -0
- package/src/config/vellum-skills/twilio-setup/SKILL.md +40 -8
- package/src/context/window-manager.ts +27 -7
- package/src/daemon/approval-generators.ts +186 -0
- package/src/daemon/approved-devices-store.ts +140 -0
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/classifier.ts +35 -32
- package/src/daemon/config-watcher.ts +1 -1
- package/src/daemon/daemon-control.ts +217 -0
- package/src/daemon/handlers/apps.ts +2 -3
- package/src/daemon/handlers/config-channels.ts +158 -0
- package/src/daemon/handlers/config-inbox.ts +540 -0
- package/src/daemon/handlers/config-ingress.ts +231 -0
- package/src/daemon/handlers/config-integrations.ts +258 -0
- package/src/daemon/handlers/config-model.ts +143 -0
- package/src/daemon/handlers/config-parental.ts +163 -0
- package/src/daemon/handlers/config-scheduling.ts +172 -0
- package/src/daemon/handlers/config-slack.ts +92 -0
- package/src/daemon/handlers/config-telegram.ts +301 -0
- package/src/daemon/handlers/config-tools.ts +177 -0
- package/src/daemon/handlers/config-trust.ts +104 -0
- package/src/daemon/handlers/config-twilio.ts +1080 -0
- package/src/daemon/handlers/config.ts +53 -1689
- package/src/daemon/handlers/diagnostics.ts +1 -1
- package/src/daemon/handlers/dictation.ts +180 -0
- package/src/daemon/handlers/documents.ts +18 -32
- package/src/daemon/handlers/identity.ts +14 -23
- package/src/daemon/handlers/index.ts +11 -0
- package/src/daemon/handlers/misc.ts +3 -5
- package/src/daemon/handlers/pairing.ts +98 -0
- package/src/daemon/handlers/sessions.ts +56 -5
- package/src/daemon/handlers/shared.ts +6 -1
- package/src/daemon/handlers/skills.ts +1 -1
- package/src/daemon/handlers/twitter-auth.ts +2 -0
- package/src/daemon/handlers/work-items.ts +17 -9
- package/src/daemon/handlers/workspace-files.ts +4 -3
- package/src/daemon/install-cli-launchers.ts +113 -0
- package/src/daemon/ipc-contract/apps.ts +356 -0
- package/src/daemon/ipc-contract/browser.ts +74 -0
- package/src/daemon/ipc-contract/computer-use.ts +151 -0
- package/src/daemon/ipc-contract/diagnostics.ts +56 -0
- package/src/daemon/ipc-contract/documents.ts +74 -0
- package/src/daemon/ipc-contract/inbox.ts +209 -0
- package/src/daemon/ipc-contract/integrations.ts +284 -0
- package/src/daemon/ipc-contract/memory.ts +48 -0
- package/src/daemon/ipc-contract/messages.ts +211 -0
- package/src/daemon/ipc-contract/pairing.ts +45 -0
- package/src/daemon/ipc-contract/parental-control.ts +95 -0
- package/src/daemon/ipc-contract/schedules.ts +97 -0
- package/src/daemon/ipc-contract/sessions.ts +315 -0
- package/src/daemon/ipc-contract/shared.ts +42 -0
- package/src/daemon/ipc-contract/skills.ts +120 -0
- package/src/daemon/ipc-contract/subagents.ts +58 -0
- package/src/daemon/ipc-contract/surfaces.ts +250 -0
- package/src/daemon/ipc-contract/trust.ts +60 -0
- package/src/daemon/ipc-contract/work-items.ts +225 -0
- package/src/daemon/ipc-contract/workspace.ts +113 -0
- package/src/daemon/ipc-contract-inventory.json +70 -0
- package/src/daemon/ipc-contract-inventory.ts +55 -29
- package/src/daemon/ipc-contract.ts +229 -2426
- package/src/daemon/ipc-protocol.ts +1 -1
- package/src/daemon/ipc-validate.ts +7 -0
- package/src/daemon/lifecycle.ts +97 -377
- package/src/daemon/pairing-store.ts +177 -0
- package/src/daemon/providers-setup.ts +43 -0
- package/src/daemon/ride-shotgun-handler.ts +68 -3
- package/src/daemon/server.ts +66 -46
- package/src/daemon/session-agent-loop-handlers.ts +421 -0
- package/src/daemon/session-agent-loop.ts +117 -275
- package/src/daemon/session-dynamic-profile.ts +1 -1
- package/src/daemon/session-history.ts +1 -1
- package/src/daemon/session-media-retry.ts +1 -1
- package/src/daemon/session-messaging.ts +37 -2
- package/src/daemon/session-notifiers.ts +5 -25
- package/src/daemon/session-process.ts +99 -59
- package/src/daemon/session-queue-manager.ts +96 -4
- package/src/daemon/session-runtime-assembly.ts +199 -10
- package/src/daemon/session-surfaces.ts +19 -4
- package/src/daemon/session-tool-setup.ts +30 -30
- package/src/daemon/session-workspace.ts +1 -1
- package/src/daemon/session.ts +35 -2
- package/src/daemon/shutdown-handlers.ts +122 -0
- package/src/daemon/trace-emitter.ts +1 -1
- package/src/daemon/watch-handler.ts +36 -33
- package/src/doordash/cart-queries.ts +787 -0
- package/src/doordash/client.ts +144 -127
- package/src/doordash/order-queries.ts +85 -0
- package/src/doordash/queries.ts +10 -1308
- package/src/doordash/search-queries.ts +203 -0
- package/src/doordash/session.ts +3 -2
- package/src/doordash/store-queries.ts +246 -0
- package/src/doordash/types.ts +367 -0
- package/src/email/providers/agentmail.ts +2 -1
- package/src/email/providers/index.ts +3 -2
- package/src/email/service.ts +3 -2
- package/src/errors.ts +43 -0
- package/src/home-base/prebuilt/seed.ts +1 -1
- package/src/hooks/cli.ts +6 -5
- package/src/hooks/config.ts +6 -8
- package/src/hooks/discovery.ts +6 -5
- package/src/hooks/manager.ts +4 -3
- package/src/hooks/runner.ts +2 -2
- package/src/hooks/templates.ts +5 -5
- package/src/inbound/public-ingress-urls.ts +6 -4
- package/src/index.ts +4 -2
- package/src/influencer/client.ts +1104 -0
- package/src/instrument.ts +4 -3
- package/src/logfire.ts +4 -3
- package/src/memory/admin.ts +25 -35
- package/src/memory/attachments-store.ts +4 -7
- package/src/memory/channel-delivery-store.ts +30 -1
- package/src/memory/channel-guardian-store.ts +202 -2
- package/src/memory/clarification-resolver.ts +37 -33
- package/src/memory/conflict-store.ts +67 -61
- package/src/memory/contradiction-checker.ts +141 -117
- package/src/memory/conversation-store.ts +335 -51
- package/src/memory/db-connection.ts +27 -4
- package/src/memory/db-init.ts +265 -4
- package/src/memory/db.ts +14 -1
- package/src/memory/embedding-backend.ts +27 -5
- package/src/memory/embedding-ollama.ts +2 -1
- package/src/memory/entity-extractor.ts +38 -35
- package/src/memory/guardian-action-store.ts +430 -0
- package/src/memory/inbox-escalation-projection.ts +59 -0
- package/src/memory/inbox-thread-store.ts +218 -0
- package/src/memory/ingress-invite-store.ts +338 -0
- package/src/memory/ingress-member-store.ts +350 -0
- package/src/memory/items-extractor.ts +91 -97
- package/src/memory/job-handlers/index-maintenance.ts +3 -3
- package/src/memory/job-handlers/media-processing.ts +69 -0
- package/src/memory/job-handlers/summarization.ts +32 -26
- package/src/memory/job-utils.ts +3 -10
- package/src/memory/jobs-store.ts +8 -10
- package/src/memory/jobs-worker.ts +55 -36
- package/src/memory/media-store.ts +759 -0
- package/src/memory/migrations/001-job-deferrals.ts +45 -0
- package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
- package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
- package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
- package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
- package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
- package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
- package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
- package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
- package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
- package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
- package/src/memory/migrations/017-memory-items-indexes.ts +10 -0
- package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
- package/src/memory/migrations/index.ts +24 -0
- package/src/memory/migrations/registry.ts +79 -0
- package/src/memory/migrations/validate-migration-state.ts +69 -0
- package/src/memory/qdrant-manager.ts +49 -8
- package/src/memory/query-builder.ts +1 -1
- package/src/memory/raw-query.ts +119 -0
- package/src/memory/recall-cache.ts +4 -1
- package/src/memory/retriever.ts +165 -47
- package/src/memory/schema-migration.ts +25 -984
- package/src/memory/schema.ts +228 -7
- package/src/memory/search/entity.ts +205 -31
- package/src/memory/search/lexical.ts +81 -52
- package/src/memory/search/ranking.ts +27 -23
- package/src/memory/search/semantic.ts +157 -19
- package/src/memory/search/types.ts +24 -0
- package/src/memory/shared-app-links-store.ts +4 -5
- package/src/memory/validation.ts +19 -0
- package/src/messaging/draft-store.ts +5 -6
- package/src/messaging/provider-types.ts +2 -0
- package/src/messaging/providers/sms/adapter.ts +201 -0
- package/src/messaging/providers/sms/client.ts +93 -0
- package/src/messaging/providers/sms/types.ts +7 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
- package/src/messaging/providers/whatsapp/adapter.ts +136 -0
- package/src/messaging/providers/whatsapp/client.ts +67 -0
- package/src/messaging/style-analyzer.ts +5 -4
- package/src/messaging/thread-summarizer.ts +61 -69
- package/src/messaging/triage-engine.ts +62 -71
- package/src/migrations/config-merge.ts +53 -0
- package/src/migrations/data-layout.ts +68 -0
- package/src/migrations/data-merge.ts +33 -0
- package/src/migrations/hooks-merge.ts +90 -0
- package/src/migrations/index.ts +6 -0
- package/src/migrations/log.ts +23 -0
- package/src/migrations/skills-merge.ts +33 -0
- package/src/migrations/workspace-layout.ts +79 -0
- package/src/permissions/checker.ts +133 -11
- package/src/permissions/prompter.ts +14 -0
- package/src/permissions/shell-identity.ts +31 -1
- package/src/permissions/trust-store.ts +21 -1
- package/src/providers/anthropic/client.ts +4 -4
- package/src/providers/failover.ts +2 -2
- package/src/providers/model-intents.ts +70 -0
- package/src/providers/ollama/client.ts +2 -1
- package/src/providers/provider-send-message.ts +176 -0
- package/src/providers/registry.ts +71 -30
- package/src/providers/retry.ts +35 -1
- package/src/providers/types.ts +12 -1
- package/src/runtime/approval-conversation-turn.ts +97 -0
- package/src/runtime/approval-message-composer.ts +253 -0
- package/src/runtime/channel-approval-parser.ts +36 -2
- package/src/runtime/channel-approvals.ts +11 -24
- package/src/runtime/channel-guardian-service.ts +88 -21
- package/src/runtime/channel-readiness-service.ts +418 -0
- package/src/runtime/channel-readiness-types.ts +35 -0
- package/src/runtime/channel-retry-sweep.ts +184 -0
- package/src/runtime/guardian-context-resolver.ts +108 -0
- package/src/runtime/http-server.ts +275 -717
- package/src/runtime/http-types.ts +59 -3
- package/src/runtime/middleware/auth.ts +116 -0
- package/src/runtime/middleware/error-handler.ts +33 -0
- package/src/runtime/middleware/twilio-validation.ts +127 -0
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/call-routes.ts +51 -7
- package/src/runtime/routes/channel-delivery-routes.ts +170 -0
- package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
- package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
- package/src/runtime/routes/channel-route-shared.ts +144 -0
- package/src/runtime/routes/channel-routes.ts +32 -1588
- package/src/runtime/routes/conversation-routes.ts +50 -7
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/identity-routes.ts +126 -0
- package/src/runtime/routes/pairing-routes.ts +143 -0
- package/src/runtime/routes/run-routes.ts +15 -1
- package/src/runtime/run-orchestrator.ts +86 -35
- package/src/schedule/schedule-store.ts +36 -32
- package/src/schedule/scheduler.ts +3 -3
- package/src/security/encrypted-store.ts +5 -7
- package/src/security/oauth2.ts +45 -15
- package/src/security/parental-control-store.ts +183 -0
- package/src/security/secret-allowlist.ts +4 -3
- package/src/security/secret-scanner.ts +5 -5
- package/src/security/secure-keys.ts +1 -1
- package/src/security/token-manager.ts +3 -2
- package/src/services/vercel-deploy.ts +6 -2
- package/src/skills/tool-manifest.ts +3 -3
- package/src/skills/vellum-catalog-remote.ts +75 -16
- package/src/slack/slack-webhook.ts +2 -1
- package/src/swarm/orchestrator.ts +92 -1
- package/src/swarm/router-planner.ts +6 -9
- package/src/swarm/worker-prompts.ts +9 -12
- package/src/tasks/task-compiler.ts +19 -28
- package/src/tasks/task-runner.ts +1 -1
- package/src/tools/assets/materialize.ts +2 -2
- package/src/tools/assets/search.ts +15 -14
- package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
- package/src/tools/browser/auto-navigate.ts +1 -0
- package/src/tools/browser/browser-execution.ts +10 -1
- package/src/tools/browser/browser-manager.ts +119 -4
- package/src/tools/browser/network-recorder.ts +5 -0
- package/src/tools/calls/call-start.ts +1 -0
- package/src/tools/credentials/broker.ts +11 -2
- package/src/tools/credentials/metadata-store.ts +18 -14
- package/src/tools/credentials/post-connect-hooks.ts +61 -0
- package/src/tools/credentials/vault.ts +49 -23
- package/src/tools/execution-target.ts +11 -1
- package/src/tools/executor.ts +68 -9
- package/src/tools/host-terminal/cli-discover.ts +1 -1
- package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
- package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
- package/src/tools/network/script-proxy/server.ts +1 -1
- package/src/tools/network/script-proxy/session-manager.ts +6 -5
- package/src/tools/network/web-fetch.ts +18 -2
- package/src/tools/network/web-search.ts +8 -4
- package/src/tools/reminder/reminder-store.ts +14 -15
- package/src/tools/schedule/create.ts +1 -0
- package/src/tools/schedule/list.ts +2 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
- package/src/tools/skills/skill-script-runner.ts +24 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -0
- package/src/tools/tasks/work-item-enqueue.ts +2 -2
- package/src/tools/terminal/evaluate-typescript.ts +21 -12
- package/src/tools/terminal/parser.ts +50 -0
- package/src/tools/types.ts +2 -0
- package/src/tools/watcher/delete.ts +6 -0
- package/src/tools/weather/service.ts +1 -1
- package/src/twitter/client.ts +190 -24
- package/src/twitter/router.ts +1 -1
- package/src/twitter/session.ts +4 -3
- package/src/util/clipboard.ts +1 -1
- package/src/util/errors.ts +65 -8
- package/src/util/fs.ts +40 -0
- package/src/util/json.ts +10 -0
- package/src/util/log-redact.ts +189 -0
- package/src/util/logger.ts +19 -17
- package/src/util/object.ts +3 -0
- package/src/util/platform.ts +105 -363
- package/src/util/pricing.ts +1 -1
- package/src/util/promise-guard.ts +1 -1
- package/src/util/retry.ts +19 -0
- package/src/util/row-mapper.ts +79 -0
- package/src/util/silently.ts +21 -0
- package/src/watcher/engine.ts +5 -1
- package/src/watcher/provider-types.ts +20 -0
- package/src/watcher/providers/github.ts +156 -0
- package/src/watcher/providers/gmail.ts +1 -0
- package/src/watcher/providers/google-calendar.ts +1 -0
- package/src/watcher/providers/linear.ts +460 -0
- package/src/watcher/providers/slack.ts +1 -0
- package/src/work-items/work-item-runner.ts +1 -1
- package/src/workspace/git-service.ts +1 -1
- package/src/workspace/provider-commit-message-generator.ts +51 -22
- package/src/__tests__/call-bridge.test.ts +0 -517
- package/src/__tests__/session-process-bridge.test.ts +0 -244
- package/src/calls/call-bridge.ts +0 -168
- package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { and, asc, eq } from 'drizzle-orm';
|
|
2
2
|
import { v4 as uuid } from 'uuid';
|
|
3
|
-
import { getDb } from './db.js';
|
|
3
|
+
import { getDb, getSqlite, rawAll } from './db.js';
|
|
4
4
|
import { enqueueMemoryJob } from './jobs-store.js';
|
|
5
5
|
import { memoryItemConflicts, memoryItems } from './schema.js';
|
|
6
|
+
import { clampUnitInterval } from './validation.js';
|
|
6
7
|
|
|
7
8
|
export type MemoryConflictRelationship =
|
|
8
9
|
| 'contradiction'
|
|
@@ -64,48 +65,54 @@ export interface ApplyConflictResolutionInput {
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
export function createOrUpdatePendingConflict(input: CreatePendingConflictInput): MemoryItemConflict {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
// Wrap in BEGIN IMMEDIATE so the SELECT-then-INSERT is atomic against concurrent
|
|
69
|
+
// writers. Without this, two parallel memory workers could both observe no
|
|
70
|
+
// existing conflict and both attempt to INSERT the same pair, resulting in a
|
|
71
|
+
// duplicate or an unexpected constraint violation.
|
|
72
|
+
return getSqlite().transaction((): MemoryItemConflict => {
|
|
73
|
+
const db = getDb();
|
|
74
|
+
const now = Date.now();
|
|
75
|
+
const scopeId = input.scopeId;
|
|
76
|
+
const existing = getPendingConflictByPair(scopeId, input.existingItemId, input.candidateItemId);
|
|
71
77
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
if (existing) {
|
|
79
|
+
db.update(memoryItemConflicts)
|
|
80
|
+
.set({
|
|
81
|
+
relationship: input.relationship,
|
|
82
|
+
clarificationQuestion: input.clarificationQuestion !== undefined ? input.clarificationQuestion : existing.clarificationQuestion,
|
|
83
|
+
updatedAt: now,
|
|
84
|
+
})
|
|
85
|
+
.where(eq(memoryItemConflicts.id, existing.id))
|
|
86
|
+
.run();
|
|
87
|
+
const updated = getConflictById(existing.id);
|
|
88
|
+
if (!updated) {
|
|
89
|
+
throw new Error(`Failed to reload updated conflict: ${existing.id}`);
|
|
90
|
+
}
|
|
91
|
+
return updated;
|
|
84
92
|
}
|
|
85
|
-
return updated;
|
|
86
|
-
}
|
|
87
93
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
94
|
+
const id = uuid();
|
|
95
|
+
db.insert(memoryItemConflicts).values({
|
|
96
|
+
id,
|
|
97
|
+
scopeId,
|
|
98
|
+
existingItemId: input.existingItemId,
|
|
99
|
+
candidateItemId: input.candidateItemId,
|
|
100
|
+
relationship: input.relationship,
|
|
101
|
+
status: 'pending_clarification',
|
|
102
|
+
clarificationQuestion: input.clarificationQuestion ?? null,
|
|
103
|
+
resolutionNote: null,
|
|
104
|
+
lastAskedAt: null,
|
|
105
|
+
resolvedAt: null,
|
|
106
|
+
createdAt: now,
|
|
107
|
+
updatedAt: now,
|
|
108
|
+
}).run();
|
|
103
109
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
const created = getConflictById(id);
|
|
111
|
+
if (!created) {
|
|
112
|
+
throw new Error(`Failed to load created conflict: ${id}`);
|
|
113
|
+
}
|
|
114
|
+
return created;
|
|
115
|
+
}).immediate();
|
|
109
116
|
}
|
|
110
117
|
|
|
111
118
|
export function getConflictById(conflictId: string): MemoryItemConflict | null {
|
|
@@ -155,9 +162,25 @@ export function listPendingConflicts(scopeId: string, limit = 100): MemoryItemCo
|
|
|
155
162
|
|
|
156
163
|
export function listPendingConflictDetails(scopeId: string, limit = 100): PendingConflictDetail[] {
|
|
157
164
|
if (limit <= 0) return [];
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
165
|
+
interface ConflictDetailRow {
|
|
166
|
+
id: string;
|
|
167
|
+
scope_id: string;
|
|
168
|
+
existing_item_id: string;
|
|
169
|
+
candidate_item_id: string;
|
|
170
|
+
relationship: string;
|
|
171
|
+
status: MemoryConflictStatus;
|
|
172
|
+
clarification_question: string | null;
|
|
173
|
+
resolution_note: string | null;
|
|
174
|
+
last_asked_at: number | null;
|
|
175
|
+
resolved_at: number | null;
|
|
176
|
+
created_at: number;
|
|
177
|
+
updated_at: number;
|
|
178
|
+
existing_statement: string;
|
|
179
|
+
candidate_statement: string;
|
|
180
|
+
existing_kind: string;
|
|
181
|
+
candidate_kind: string;
|
|
182
|
+
}
|
|
183
|
+
const rows = rawAll<ConflictDetailRow>(`
|
|
161
184
|
SELECT
|
|
162
185
|
c.id,
|
|
163
186
|
c.scope_id,
|
|
@@ -182,24 +205,7 @@ export function listPendingConflictDetails(scopeId: string, limit = 100): Pendin
|
|
|
182
205
|
AND c.status = 'pending_clarification'
|
|
183
206
|
ORDER BY c.created_at ASC
|
|
184
207
|
LIMIT ?
|
|
185
|
-
|
|
186
|
-
id: string;
|
|
187
|
-
scope_id: string;
|
|
188
|
-
existing_item_id: string;
|
|
189
|
-
candidate_item_id: string;
|
|
190
|
-
relationship: string;
|
|
191
|
-
status: MemoryConflictStatus;
|
|
192
|
-
clarification_question: string | null;
|
|
193
|
-
resolution_note: string | null;
|
|
194
|
-
last_asked_at: number | null;
|
|
195
|
-
resolved_at: number | null;
|
|
196
|
-
created_at: number;
|
|
197
|
-
updated_at: number;
|
|
198
|
-
existing_statement: string;
|
|
199
|
-
candidate_statement: string;
|
|
200
|
-
existing_kind: string;
|
|
201
|
-
candidate_kind: string;
|
|
202
|
-
}>;
|
|
208
|
+
`, scopeId, limit);
|
|
203
209
|
|
|
204
210
|
return rows.map((row) => ({
|
|
205
211
|
id: row.id,
|
|
@@ -314,7 +320,7 @@ export function applyConflictResolution(input: ApplyConflictResolutionInput): bo
|
|
|
314
320
|
status: 'active',
|
|
315
321
|
invalidAt: null,
|
|
316
322
|
lastSeenAt: Math.max(existingItem.lastSeenAt, candidateItem.lastSeenAt, now),
|
|
317
|
-
confidence: Math.max(existingItem.confidence, candidateItem.confidence),
|
|
323
|
+
confidence: clampUnitInterval(Math.max(existingItem.confidence, candidateItem.confidence)),
|
|
318
324
|
})
|
|
319
325
|
.where(eq(memoryItems.id, existingItem.id))
|
|
320
326
|
.run();
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import Anthropic from '@anthropic-ai/sdk';
|
|
2
1
|
import { eq } from 'drizzle-orm';
|
|
3
2
|
import { getConfig } from '../config/loader.js';
|
|
4
3
|
import { getLogger } from '../util/logger.js';
|
|
5
4
|
import { truncate } from '../util/truncate.js';
|
|
5
|
+
import { getConfiguredProvider, createTimeout, extractToolUse, userMessage } from '../providers/provider-send-message.js';
|
|
6
6
|
import { areStatementsCoherent } from './conflict-intent.js';
|
|
7
7
|
import { isConflictKindEligible, isStatementConflictEligible } from './conflict-policy.js';
|
|
8
8
|
import { createOrUpdatePendingConflict } from './conflict-store.js';
|
|
9
|
-
import { getDb } from './db.js';
|
|
9
|
+
import { getDb, getSqlite, rawAll } from './db.js';
|
|
10
10
|
import { enqueueMemoryJob } from './jobs-store.js';
|
|
11
11
|
import { memoryItems } from './schema.js';
|
|
12
|
+
import { clampUnitInterval } from './validation.js';
|
|
12
13
|
|
|
13
14
|
const log = getLogger('memory-contradiction-checker');
|
|
14
15
|
|
|
@@ -56,13 +57,14 @@ export async function checkContradictions(newItemId: string): Promise<void> {
|
|
|
56
57
|
return;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
log.debug('No Anthropic API key available for contradiction checking');
|
|
60
|
+
const provider = getConfiguredProvider();
|
|
61
|
+
if (!provider) {
|
|
62
|
+
log.debug('Configured provider unavailable for contradiction checking');
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
const config = getConfig();
|
|
67
|
+
|
|
66
68
|
if (!isConflictKindEligible(newItem.kind, config.memory.conflicts)) {
|
|
67
69
|
log.debug({ newItemId, kind: newItem.kind }, 'Skipping contradiction check — kind not eligible for conflicts');
|
|
68
70
|
return;
|
|
@@ -91,14 +93,14 @@ export async function checkContradictions(newItemId: string): Promise<void> {
|
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
try {
|
|
94
|
-
const result = await classifyRelationship(
|
|
95
|
-
|
|
96
|
-
// Only stop when the new item itself
|
|
97
|
-
// For contradiction, the old item is
|
|
98
|
-
// active and should continue to be
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
if (result.relationship === 'update' || result.relationship === 'ambiguous_contradiction') break;
|
|
96
|
+
const result = await classifyRelationship(existing, newItem);
|
|
97
|
+
const mutated = handleRelationship(result, existing, newItem);
|
|
98
|
+
// Only stop when the new item itself was actually invalidated (update case)
|
|
99
|
+
// or gated (ambiguous_contradiction). For contradiction, the old item is
|
|
100
|
+
// invalidated but the new item remains active and should continue to be
|
|
101
|
+
// checked against remaining candidates. Skip the break when the transaction
|
|
102
|
+
// detected stale data and performed no mutation.
|
|
103
|
+
if (mutated && (result.relationship === 'update' || result.relationship === 'ambiguous_contradiction')) break;
|
|
102
104
|
} catch (err) {
|
|
103
105
|
const message = err instanceof Error ? err.message : String(err);
|
|
104
106
|
log.warn({ err: message, newItemId, existingId: existing.id }, 'Contradiction classification failed for pair');
|
|
@@ -123,8 +125,6 @@ interface MemoryItemRow {
|
|
|
123
125
|
* Uses LIKE queries on subject and keyword overlap on statement.
|
|
124
126
|
*/
|
|
125
127
|
function findSimilarItems(item: MemoryItemRow): MemoryItemRow[] {
|
|
126
|
-
const db = getDb();
|
|
127
|
-
const raw = (db as unknown as { $client: { query: (q: string) => { all: (...params: unknown[]) => unknown[] } } }).$client;
|
|
128
128
|
|
|
129
129
|
// Extract significant words from subject for LIKE matching
|
|
130
130
|
const subjectWords = item.subject
|
|
@@ -172,7 +172,7 @@ function findSimilarItems(item: MemoryItemRow): MemoryItemRow[] {
|
|
|
172
172
|
`;
|
|
173
173
|
|
|
174
174
|
try {
|
|
175
|
-
|
|
175
|
+
interface SimilarItemRow {
|
|
176
176
|
id: string;
|
|
177
177
|
kind: string;
|
|
178
178
|
subject: string;
|
|
@@ -182,7 +182,8 @@ function findSimilarItems(item: MemoryItemRow): MemoryItemRow[] {
|
|
|
182
182
|
importance: number | null;
|
|
183
183
|
scope_id: string;
|
|
184
184
|
last_seen_at: number;
|
|
185
|
-
}
|
|
185
|
+
}
|
|
186
|
+
const rows = rawAll<SimilarItemRow>(sqlQuery, item.kind, item.id, item.scopeId);
|
|
186
187
|
|
|
187
188
|
return rows.map((row) => ({
|
|
188
189
|
id: row.id,
|
|
@@ -205,25 +206,23 @@ function findSimilarItems(item: MemoryItemRow): MemoryItemRow[] {
|
|
|
205
206
|
* Use LLM to classify the relationship between two memory items.
|
|
206
207
|
*/
|
|
207
208
|
async function classifyRelationship(
|
|
208
|
-
apiKey: string,
|
|
209
209
|
existingItem: MemoryItemRow,
|
|
210
210
|
newItem: MemoryItemRow,
|
|
211
211
|
): Promise<ClassifyResult> {
|
|
212
|
-
const
|
|
212
|
+
const provider = getConfiguredProvider()!;
|
|
213
213
|
|
|
214
|
-
const
|
|
214
|
+
const userContent = [
|
|
215
215
|
`Subject: ${newItem.subject}`,
|
|
216
216
|
'',
|
|
217
217
|
`Old statement: ${existingItem.statement}`,
|
|
218
218
|
`New statement: ${newItem.statement}`,
|
|
219
219
|
].join('\n');
|
|
220
220
|
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
tools: [{
|
|
221
|
+
const { signal, cleanup } = createTimeout(CONTRADICTION_LLM_TIMEOUT_MS);
|
|
222
|
+
try {
|
|
223
|
+
const response = await provider.sendMessage(
|
|
224
|
+
[userMessage(userContent)],
|
|
225
|
+
[{
|
|
227
226
|
name: 'classify_relationship',
|
|
228
227
|
description: 'Classify the relationship between two memory statements',
|
|
229
228
|
input_schema: {
|
|
@@ -242,109 +241,134 @@ async function classifyRelationship(
|
|
|
242
241
|
required: ['relationship', 'explanation'],
|
|
243
242
|
},
|
|
244
243
|
}],
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
244
|
+
CONTRADICTION_SYSTEM_PROMPT,
|
|
245
|
+
{
|
|
246
|
+
config: {
|
|
247
|
+
modelIntent: 'latency-optimized',
|
|
248
|
+
max_tokens: 256,
|
|
249
|
+
tool_choice: { type: 'tool' as const, name: 'classify_relationship' },
|
|
250
|
+
},
|
|
251
|
+
signal,
|
|
252
|
+
},
|
|
253
|
+
);
|
|
254
|
+
cleanup();
|
|
255
|
+
|
|
256
|
+
const toolBlock = extractToolUse(response);
|
|
257
|
+
if (!toolBlock) {
|
|
258
|
+
throw new Error('No tool_use block in contradiction check response');
|
|
259
|
+
}
|
|
257
260
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
261
|
+
const input = toolBlock.input as { relationship?: string; explanation?: string };
|
|
262
|
+
const relationship = input.relationship as Relationship;
|
|
263
|
+
if (!['contradiction', 'update', 'complement', 'ambiguous_contradiction'].includes(relationship)) {
|
|
264
|
+
throw new Error(`Invalid relationship type: ${relationship}`);
|
|
265
|
+
}
|
|
263
266
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
267
|
+
return {
|
|
268
|
+
relationship,
|
|
269
|
+
explanation: truncate(String(input.explanation ?? ''), 500, ''),
|
|
270
|
+
};
|
|
271
|
+
} finally {
|
|
272
|
+
cleanup();
|
|
273
|
+
}
|
|
268
274
|
}
|
|
269
275
|
|
|
270
276
|
/**
|
|
271
277
|
* Handle the classified relationship between an existing and new memory item.
|
|
278
|
+
*
|
|
279
|
+
* Wrapped in a SQLite transaction so that multi-row mutations (e.g. invalidating
|
|
280
|
+
* the old item AND setting validFrom on the new one) are atomic. The transaction
|
|
281
|
+
* also re-verifies both items are still active before mutating, preventing a
|
|
282
|
+
* TOCTOU race when multiple workers process contradictions concurrently.
|
|
272
283
|
*/
|
|
273
|
-
|
|
284
|
+
function handleRelationship(
|
|
274
285
|
result: ClassifyResult,
|
|
275
286
|
existingItem: MemoryItemRow,
|
|
276
287
|
newItem: MemoryItemRow,
|
|
277
|
-
):
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
case 'update': {
|
|
299
|
-
// Merge info — update old item's statement, bump lastSeenAt
|
|
300
|
-
log.debug(
|
|
301
|
-
{ existingId: existingItem.id, newId: newItem.id, explanation: result.explanation },
|
|
302
|
-
'Update detected — merging into existing item',
|
|
303
|
-
);
|
|
304
|
-
db.update(memoryItems)
|
|
305
|
-
.set({
|
|
306
|
-
statement: newItem.statement,
|
|
307
|
-
lastSeenAt: Math.max(existingItem.lastSeenAt, newItem.lastSeenAt),
|
|
308
|
-
confidence: Math.max(existingItem.confidence, newItem.confidence),
|
|
309
|
-
})
|
|
310
|
-
.where(eq(memoryItems.id, existingItem.id))
|
|
311
|
-
.run();
|
|
312
|
-
// Re-embed the existing item so its vector matches the updated statement
|
|
313
|
-
enqueueMemoryJob('embed_item', { itemId: existingItem.id });
|
|
314
|
-
// Invalidate the new item since its content has been merged into the existing one
|
|
315
|
-
db.update(memoryItems)
|
|
316
|
-
.set({ invalidAt: now })
|
|
317
|
-
.where(eq(memoryItems.id, newItem.id))
|
|
318
|
-
.run();
|
|
319
|
-
break;
|
|
288
|
+
): boolean {
|
|
289
|
+
if (result.relationship === 'complement') {
|
|
290
|
+
log.debug(
|
|
291
|
+
{ existingId: existingItem.id, newId: newItem.id, explanation: result.explanation },
|
|
292
|
+
'Complement detected — keeping both items',
|
|
293
|
+
);
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return getSqlite().transaction(() => {
|
|
298
|
+
const db = getDb();
|
|
299
|
+
const now = Date.now();
|
|
300
|
+
|
|
301
|
+
// Re-check both items inside the transaction to guard against concurrent mutations
|
|
302
|
+
const freshExisting = db.select().from(memoryItems).where(eq(memoryItems.id, existingItem.id)).get();
|
|
303
|
+
const freshNew = db.select().from(memoryItems).where(eq(memoryItems.id, newItem.id)).get();
|
|
304
|
+
|
|
305
|
+
if (!freshExisting || freshExisting.status !== 'active' || freshExisting.invalidAt != null) {
|
|
306
|
+
log.debug({ existingId: existingItem.id }, 'Existing item no longer active — skipping');
|
|
307
|
+
return false;
|
|
320
308
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
{ existingId: existingItem.id, newId: newItem.id, explanation: result.explanation },
|
|
325
|
-
'Complement detected — keeping both items',
|
|
326
|
-
);
|
|
327
|
-
break;
|
|
309
|
+
if (!freshNew || (freshNew.status !== 'active' && result.relationship !== 'ambiguous_contradiction') || freshNew.invalidAt != null) {
|
|
310
|
+
log.debug({ newId: newItem.id }, 'New item no longer active — skipping');
|
|
311
|
+
return false;
|
|
328
312
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
.
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
313
|
+
|
|
314
|
+
switch (result.relationship) {
|
|
315
|
+
case 'contradiction': {
|
|
316
|
+
log.info(
|
|
317
|
+
{ existingId: existingItem.id, newId: newItem.id, explanation: result.explanation },
|
|
318
|
+
'Contradiction detected — invalidating old item',
|
|
319
|
+
);
|
|
320
|
+
db.update(memoryItems)
|
|
321
|
+
.set({ invalidAt: now })
|
|
322
|
+
.where(eq(memoryItems.id, existingItem.id))
|
|
323
|
+
.run();
|
|
324
|
+
db.update(memoryItems)
|
|
325
|
+
.set({ validFrom: now })
|
|
326
|
+
.where(eq(memoryItems.id, newItem.id))
|
|
327
|
+
.run();
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
case 'update': {
|
|
331
|
+
log.debug(
|
|
332
|
+
{ existingId: existingItem.id, newId: newItem.id, explanation: result.explanation },
|
|
333
|
+
'Update detected — merging into existing item',
|
|
334
|
+
);
|
|
335
|
+
db.update(memoryItems)
|
|
336
|
+
.set({
|
|
337
|
+
statement: newItem.statement,
|
|
338
|
+
lastSeenAt: Math.max(freshExisting.lastSeenAt, freshNew!.lastSeenAt),
|
|
339
|
+
confidence: clampUnitInterval(Math.max(freshExisting.confidence, freshNew!.confidence)),
|
|
340
|
+
})
|
|
341
|
+
.where(eq(memoryItems.id, existingItem.id))
|
|
342
|
+
.run();
|
|
343
|
+
enqueueMemoryJob('embed_item', { itemId: existingItem.id });
|
|
344
|
+
db.update(memoryItems)
|
|
345
|
+
.set({ invalidAt: now })
|
|
346
|
+
.where(eq(memoryItems.id, newItem.id))
|
|
347
|
+
.run();
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
case 'ambiguous_contradiction': {
|
|
351
|
+
log.info(
|
|
352
|
+
{ existingId: existingItem.id, newId: newItem.id, explanation: result.explanation },
|
|
353
|
+
'Ambiguous contradiction detected — gating candidate pending clarification',
|
|
354
|
+
);
|
|
355
|
+
db.update(memoryItems)
|
|
356
|
+
.set({ status: 'pending_clarification' })
|
|
357
|
+
.where(eq(memoryItems.id, newItem.id))
|
|
358
|
+
.run();
|
|
359
|
+
createOrUpdatePendingConflict({
|
|
360
|
+
scopeId: newItem.scopeId,
|
|
361
|
+
existingItemId: existingItem.id,
|
|
362
|
+
candidateItemId: newItem.id,
|
|
363
|
+
relationship: 'ambiguous_contradiction',
|
|
364
|
+
clarificationQuestion: buildClarificationQuestion(existingItem.statement, newItem.statement),
|
|
365
|
+
});
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
default:
|
|
369
|
+
return false;
|
|
346
370
|
}
|
|
347
|
-
}
|
|
371
|
+
}).immediate();
|
|
348
372
|
}
|
|
349
373
|
|
|
350
374
|
function escapeSqlLike(s: string): string {
|