@vellumai/assistant 0.3.5 → 0.3.7
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/README.md +51 -0
- 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 +18 -2
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +338 -1
- package/src/__tests__/approval-conversation-turn.test.ts +214 -0
- package/src/__tests__/browser-manager.test.ts +1 -0
- package/src/__tests__/call-conversation-messages.test.ts +130 -0
- package/src/__tests__/call-orchestrator.test.ts +752 -271
- 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 +5 -0
- package/src/__tests__/call-store.test.ts +3 -0
- package/src/__tests__/channel-approval-routes.test.ts +1260 -85
- package/src/__tests__/channel-approval.test.ts +37 -0
- package/src/__tests__/channel-approvals.test.ts +4 -65
- package/src/__tests__/channel-guardian.test.ts +556 -0
- package/src/__tests__/channel-readiness-service.test.ts +74 -7
- 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 +12 -7
- 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 +6 -2
- package/src/__tests__/db-migration-rollback.test.ts +752 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -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 +126 -0
- package/src/__tests__/intent-routing.test.ts +2 -0
- package/src/__tests__/ipc-snapshot.test.ts +228 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +828 -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 +2 -0
- package/src/__tests__/run-orchestrator.test.ts +20 -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 +237 -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 +2 -1
- 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 +141 -21
- 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 +45 -29
- 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 +106 -5
- package/src/calls/call-orchestrator.ts +252 -54
- 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 +7 -5
- package/src/calls/twilio-provider.ts +6 -4
- package/src/calls/twilio-rest.ts +40 -15
- package/src/calls/twilio-routes.ts +60 -45
- 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/macos-automation/icon.svg +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +72 -95
- package/src/config/bundled-skills/media-processing/TOOLS.json +57 -147
- 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 +7 -9
- package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +88 -253
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +22 -153
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +28 -51
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +35 -270
- package/src/config/bundled-skills/messaging/SKILL.md +12 -2
- 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/phone-calls/SKILL.md +86 -21
- 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 +27 -3
- package/src/config/env-registry.ts +169 -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 +157 -1138
- 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 +107 -56
- 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 +0 -7
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +1 -0
- package/src/config/vellum-skills/sms-setup/SKILL.md +112 -14
- 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 +254 -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 -2463
- package/src/daemon/handlers/diagnostics.ts +1 -1
- package/src/daemon/handlers/dictation.ts +4 -6
- package/src/daemon/handlers/documents.ts +18 -32
- package/src/daemon/handlers/index.ts +9 -0
- package/src/daemon/handlers/misc.ts +3 -5
- package/src/daemon/handlers/pairing.ts +98 -0
- package/src/daemon/handlers/sessions.ts +74 -5
- package/src/daemon/handlers/shared.ts +3 -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 +2 -2
- 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 +321 -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 +62 -0
- package/src/daemon/ipc-contract-inventory.ts +55 -29
- package/src/daemon/ipc-contract.ts +227 -2527
- package/src/daemon/ipc-protocol.ts +1 -1
- package/src/daemon/ipc-validate.ts +7 -0
- package/src/daemon/lifecycle.ts +97 -379
- package/src/daemon/pairing-store.ts +177 -0
- package/src/daemon/providers-setup.ts +43 -0
- package/src/daemon/ride-shotgun-handler.ts +67 -2
- package/src/daemon/server.ts +60 -44
- package/src/daemon/session-agent-loop-handlers.ts +421 -0
- package/src/daemon/session-agent-loop.ts +113 -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 +98 -4
- package/src/daemon/session-runtime-assembly.ts +149 -15
- package/src/daemon/session-surfaces.ts +26 -4
- package/src/daemon/session-tool-setup.ts +28 -30
- package/src/daemon/session-workspace.ts +1 -1
- package/src/daemon/session.ts +24 -1
- 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 +3 -1
- 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 +200 -1
- 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 +121 -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 +11 -42
- package/src/memory/job-handlers/summarization.ts +32 -26
- package/src/memory/job-utils.ts +3 -10
- package/src/memory/jobs-store.ts +6 -9
- package/src/memory/jobs-worker.ts +51 -36
- 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 +12 -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 +163 -47
- package/src/memory/schema-migration.ts +25 -984
- package/src/memory/schema.ts +130 -7
- package/src/memory/search/entity.ts +10 -19
- package/src/memory/search/lexical.ts +81 -52
- package/src/memory/search/ranking.ts +21 -22
- package/src/memory/search/semantic.ts +157 -19
- 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/providers/sms/adapter.ts +3 -6
- 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 +126 -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 +115 -5
- package/src/runtime/assistant-event-hub.ts +3 -1
- package/src/runtime/channel-approval-parser.ts +36 -2
- package/src/runtime/channel-approvals.ts +0 -21
- package/src/runtime/channel-guardian-service.ts +48 -7
- package/src/runtime/channel-readiness-service.ts +160 -34
- package/src/runtime/channel-readiness-types.ts +10 -4
- package/src/runtime/channel-retry-sweep.ts +184 -0
- package/src/runtime/guardian-context-resolver.ts +108 -0
- package/src/runtime/http-server.ts +289 -745
- package/src/runtime/http-types.ts +56 -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 +49 -6
- 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 -1634
- 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 +144 -0
- package/src/runtime/routes/run-routes.ts +15 -1
- package/src/runtime/run-orchestrator.ts +52 -34
- 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/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 +13 -1
- package/src/tools/browser/browser-manager.ts +119 -4
- package/src/tools/browser/network-recorder.ts +5 -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/executor.ts +80 -18
- 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 +7 -3
- 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/watcher/delete.ts +6 -0
- package/src/tools/weather/service.ts +1 -1
- package/src/twitter/client.ts +190 -24
- 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 +25 -18
- package/src/util/object.ts +3 -0
- package/src/util/platform.ts +72 -365
- 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/bundled-skills/media-processing/services/capability-registry.ts +0 -137
- package/src/config/bundled-skills/media-processing/services/event-detection-service.ts +0 -280
- package/src/config/bundled-skills/media-processing/services/feedback-aggregation.ts +0 -144
- package/src/config/bundled-skills/media-processing/services/feedback-store.ts +0 -136
- package/src/config/bundled-skills/media-processing/services/retrieval-service.ts +0 -95
- package/src/config/bundled-skills/media-processing/services/timeline-service.ts +0 -267
- package/src/config/bundled-skills/media-processing/tools/detect-events.ts +0 -110
- package/src/config/bundled-skills/media-processing/tools/recalibrate.ts +0 -235
- package/src/config/bundled-skills/media-processing/tools/select-tracking-profile.ts +0 -142
- package/src/config/bundled-skills/media-processing/tools/submit-feedback.ts +0 -150
- package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
package/src/memory/schema.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sqliteTable, text, integer, real, blob } from 'drizzle-orm/sqlite-core';
|
|
1
|
+
import { sqliteTable, text, integer, real, blob, index } from 'drizzle-orm/sqlite-core';
|
|
2
2
|
|
|
3
3
|
export const conversations = sqliteTable('conversations', {
|
|
4
4
|
id: text('id').primaryKey(),
|
|
@@ -12,7 +12,9 @@ export const conversations = sqliteTable('conversations', {
|
|
|
12
12
|
contextCompactedMessageCount: integer('context_compacted_message_count').notNull().default(0),
|
|
13
13
|
contextCompactedAt: integer('context_compacted_at'),
|
|
14
14
|
threadType: text('thread_type').notNull().default('standard'),
|
|
15
|
+
source: text('source').notNull().default('user'),
|
|
15
16
|
memoryScopeId: text('memory_scope_id').notNull().default('default'),
|
|
17
|
+
originChannel: text('origin_channel'),
|
|
16
18
|
});
|
|
17
19
|
|
|
18
20
|
export const messages = sqliteTable('messages', {
|
|
@@ -24,7 +26,9 @@ export const messages = sqliteTable('messages', {
|
|
|
24
26
|
content: text('content').notNull(),
|
|
25
27
|
createdAt: integer('created_at').notNull(),
|
|
26
28
|
metadata: text('metadata'),
|
|
27
|
-
})
|
|
29
|
+
}, (table) => [
|
|
30
|
+
index('idx_messages_conversation_id').on(table.conversationId),
|
|
31
|
+
]);
|
|
28
32
|
|
|
29
33
|
export const toolInvocations = sqliteTable('tool_invocations', {
|
|
30
34
|
id: text('id').primaryKey(),
|
|
@@ -38,7 +42,9 @@ export const toolInvocations = sqliteTable('tool_invocations', {
|
|
|
38
42
|
riskLevel: text('risk_level').notNull(),
|
|
39
43
|
durationMs: integer('duration_ms').notNull(),
|
|
40
44
|
createdAt: integer('created_at').notNull(),
|
|
41
|
-
})
|
|
45
|
+
}, (table) => [
|
|
46
|
+
index('idx_tool_invocations_conversation_id').on(table.conversationId),
|
|
47
|
+
]);
|
|
42
48
|
|
|
43
49
|
export const memorySegments = sqliteTable('memory_segments', {
|
|
44
50
|
id: text('id').primaryKey(),
|
|
@@ -56,7 +62,10 @@ export const memorySegments = sqliteTable('memory_segments', {
|
|
|
56
62
|
contentHash: text('content_hash'),
|
|
57
63
|
createdAt: integer('created_at').notNull(),
|
|
58
64
|
updatedAt: integer('updated_at').notNull(),
|
|
59
|
-
})
|
|
65
|
+
}, (table) => [
|
|
66
|
+
index('idx_memory_segments_scope_id').on(table.scopeId),
|
|
67
|
+
index('idx_memory_segments_conversation_id').on(table.conversationId),
|
|
68
|
+
]);
|
|
60
69
|
|
|
61
70
|
export const memoryItems = sqliteTable('memory_items', {
|
|
62
71
|
id: text('id').primaryKey(),
|
|
@@ -75,7 +84,10 @@ export const memoryItems = sqliteTable('memory_items', {
|
|
|
75
84
|
lastUsedAt: integer('last_used_at'),
|
|
76
85
|
validFrom: integer('valid_from'),
|
|
77
86
|
invalidAt: integer('invalid_at'),
|
|
78
|
-
})
|
|
87
|
+
}, (table) => [
|
|
88
|
+
index('idx_memory_items_scope_id').on(table.scopeId),
|
|
89
|
+
index('idx_memory_items_fingerprint').on(table.fingerprint),
|
|
90
|
+
]);
|
|
79
91
|
|
|
80
92
|
export const memoryItemSources = sqliteTable('memory_item_sources', {
|
|
81
93
|
memoryItemId: text('memory_item_id')
|
|
@@ -105,7 +117,9 @@ export const memoryItemConflicts = sqliteTable('memory_item_conflicts', {
|
|
|
105
117
|
resolvedAt: integer('resolved_at'),
|
|
106
118
|
createdAt: integer('created_at').notNull(),
|
|
107
119
|
updatedAt: integer('updated_at').notNull(),
|
|
108
|
-
})
|
|
120
|
+
}, (table) => [
|
|
121
|
+
index('idx_memory_item_conflicts_scope_id').on(table.scopeId),
|
|
122
|
+
]);
|
|
109
123
|
|
|
110
124
|
export const memorySummaries = sqliteTable('memory_summaries', {
|
|
111
125
|
id: text('id').primaryKey(),
|
|
@@ -119,7 +133,9 @@ export const memorySummaries = sqliteTable('memory_summaries', {
|
|
|
119
133
|
endAt: integer('end_at').notNull(),
|
|
120
134
|
createdAt: integer('created_at').notNull(),
|
|
121
135
|
updatedAt: integer('updated_at').notNull(),
|
|
122
|
-
})
|
|
136
|
+
}, (table) => [
|
|
137
|
+
index('idx_memory_summaries_scope_id').on(table.scopeId),
|
|
138
|
+
]);
|
|
123
139
|
|
|
124
140
|
export const memoryEmbeddings = sqliteTable('memory_embeddings', {
|
|
125
141
|
id: text('id').primaryKey(),
|
|
@@ -551,6 +567,8 @@ export const callSessions = sqliteTable('call_sessions', {
|
|
|
551
567
|
status: text('status').notNull().default('initiated'),
|
|
552
568
|
callerIdentityMode: text('caller_identity_mode'),
|
|
553
569
|
callerIdentitySource: text('caller_identity_source'),
|
|
570
|
+
assistantId: text('assistant_id'),
|
|
571
|
+
initiatedFromConversationId: text('initiated_from_conversation_id'),
|
|
554
572
|
startedAt: integer('started_at'),
|
|
555
573
|
endedAt: integer('ended_at'),
|
|
556
574
|
lastError: text('last_error'),
|
|
@@ -778,3 +796,108 @@ export const mediaEventFeedback = sqliteTable('media_event_feedback', {
|
|
|
778
796
|
notes: text('notes'),
|
|
779
797
|
createdAt: integer('created_at').notNull(),
|
|
780
798
|
});
|
|
799
|
+
|
|
800
|
+
// ── Guardian Action Requests (cross-channel voice guardian) ──────────
|
|
801
|
+
|
|
802
|
+
export const guardianActionRequests = sqliteTable('guardian_action_requests', {
|
|
803
|
+
id: text('id').primaryKey(),
|
|
804
|
+
assistantId: text('assistant_id').notNull().default('self'),
|
|
805
|
+
kind: text('kind').notNull(), // 'ask_guardian'
|
|
806
|
+
sourceChannel: text('source_channel').notNull(), // 'voice'
|
|
807
|
+
sourceConversationId: text('source_conversation_id').notNull(),
|
|
808
|
+
callSessionId: text('call_session_id')
|
|
809
|
+
.notNull()
|
|
810
|
+
.references(() => callSessions.id, { onDelete: 'cascade' }),
|
|
811
|
+
pendingQuestionId: text('pending_question_id')
|
|
812
|
+
.notNull()
|
|
813
|
+
.references(() => callPendingQuestions.id, { onDelete: 'cascade' }),
|
|
814
|
+
questionText: text('question_text').notNull(),
|
|
815
|
+
requestCode: text('request_code').notNull(), // short human-readable code for routing replies
|
|
816
|
+
status: text('status').notNull().default('pending'), // pending | answered | expired | cancelled
|
|
817
|
+
answerText: text('answer_text'),
|
|
818
|
+
answeredByChannel: text('answered_by_channel'),
|
|
819
|
+
answeredByExternalUserId: text('answered_by_external_user_id'),
|
|
820
|
+
answeredAt: integer('answered_at'),
|
|
821
|
+
expiresAt: integer('expires_at').notNull(),
|
|
822
|
+
createdAt: integer('created_at').notNull(),
|
|
823
|
+
updatedAt: integer('updated_at').notNull(),
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
// ── Guardian Action Deliveries (per-channel delivery tracking) ───────
|
|
827
|
+
|
|
828
|
+
export const guardianActionDeliveries = sqliteTable('guardian_action_deliveries', {
|
|
829
|
+
id: text('id').primaryKey(),
|
|
830
|
+
requestId: text('request_id')
|
|
831
|
+
.notNull()
|
|
832
|
+
.references(() => guardianActionRequests.id, { onDelete: 'cascade' }),
|
|
833
|
+
destinationChannel: text('destination_channel').notNull(), // 'telegram' | 'sms' | 'macos'
|
|
834
|
+
destinationConversationId: text('destination_conversation_id'),
|
|
835
|
+
destinationChatId: text('destination_chat_id'),
|
|
836
|
+
destinationExternalUserId: text('destination_external_user_id'),
|
|
837
|
+
status: text('status').notNull().default('pending'), // pending | sent | failed | answered | expired | cancelled
|
|
838
|
+
sentAt: integer('sent_at'),
|
|
839
|
+
respondedAt: integer('responded_at'),
|
|
840
|
+
lastError: text('last_error'),
|
|
841
|
+
createdAt: integer('created_at').notNull(),
|
|
842
|
+
updatedAt: integer('updated_at').notNull(),
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
// ── Assistant Inbox ──────────────────────────────────────────────────
|
|
846
|
+
|
|
847
|
+
export const assistantIngressInvites = sqliteTable('assistant_ingress_invites', {
|
|
848
|
+
id: text('id').primaryKey(),
|
|
849
|
+
assistantId: text('assistant_id').notNull().default('self'),
|
|
850
|
+
sourceChannel: text('source_channel').notNull(),
|
|
851
|
+
tokenHash: text('token_hash').notNull(),
|
|
852
|
+
createdBySessionId: text('created_by_session_id'),
|
|
853
|
+
note: text('note'),
|
|
854
|
+
maxUses: integer('max_uses').notNull().default(1),
|
|
855
|
+
useCount: integer('use_count').notNull().default(0),
|
|
856
|
+
expiresAt: integer('expires_at').notNull(),
|
|
857
|
+
status: text('status').notNull().default('active'),
|
|
858
|
+
redeemedByExternalUserId: text('redeemed_by_external_user_id'),
|
|
859
|
+
redeemedByExternalChatId: text('redeemed_by_external_chat_id'),
|
|
860
|
+
redeemedAt: integer('redeemed_at'),
|
|
861
|
+
createdAt: integer('created_at').notNull(),
|
|
862
|
+
updatedAt: integer('updated_at').notNull(),
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
export const assistantIngressMembers = sqliteTable('assistant_ingress_members', {
|
|
866
|
+
id: text('id').primaryKey(),
|
|
867
|
+
assistantId: text('assistant_id').notNull().default('self'),
|
|
868
|
+
sourceChannel: text('source_channel').notNull(),
|
|
869
|
+
externalUserId: text('external_user_id'),
|
|
870
|
+
externalChatId: text('external_chat_id'),
|
|
871
|
+
displayName: text('display_name'),
|
|
872
|
+
username: text('username'),
|
|
873
|
+
status: text('status').notNull().default('pending'),
|
|
874
|
+
policy: text('policy').notNull().default('allow'),
|
|
875
|
+
inviteId: text('invite_id')
|
|
876
|
+
.references(() => assistantIngressInvites.id),
|
|
877
|
+
createdBySessionId: text('created_by_session_id'),
|
|
878
|
+
revokedReason: text('revoked_reason'),
|
|
879
|
+
blockedReason: text('blocked_reason'),
|
|
880
|
+
lastSeenAt: integer('last_seen_at'),
|
|
881
|
+
createdAt: integer('created_at').notNull(),
|
|
882
|
+
updatedAt: integer('updated_at').notNull(),
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
export const assistantInboxThreadState = sqliteTable('assistant_inbox_thread_state', {
|
|
886
|
+
conversationId: text('conversation_id')
|
|
887
|
+
.primaryKey()
|
|
888
|
+
.references(() => conversations.id, { onDelete: 'cascade' }),
|
|
889
|
+
assistantId: text('assistant_id').notNull().default('self'),
|
|
890
|
+
sourceChannel: text('source_channel').notNull(),
|
|
891
|
+
externalChatId: text('external_chat_id').notNull(),
|
|
892
|
+
externalUserId: text('external_user_id'),
|
|
893
|
+
displayName: text('display_name'),
|
|
894
|
+
username: text('username'),
|
|
895
|
+
lastInboundAt: integer('last_inbound_at'),
|
|
896
|
+
lastOutboundAt: integer('last_outbound_at'),
|
|
897
|
+
lastMessageAt: integer('last_message_at'),
|
|
898
|
+
unreadCount: integer('unread_count').notNull().default(0),
|
|
899
|
+
pendingEscalationCount: integer('pending_escalation_count').notNull().default(0),
|
|
900
|
+
hasPendingEscalation: integer('has_pending_escalation').notNull().default(0),
|
|
901
|
+
createdAt: integer('created_at').notNull(),
|
|
902
|
+
updatedAt: integer('updated_at').notNull(),
|
|
903
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { and, desc, eq, inArray, isNull, or } from 'drizzle-orm';
|
|
2
2
|
import type { MemoryEntityConfig } from '../../config/types.js';
|
|
3
3
|
import { getLogger } from '../../util/logger.js';
|
|
4
|
-
import { getDb } from '../db.js';
|
|
4
|
+
import { getDb, rawAll } from '../db.js';
|
|
5
5
|
import {
|
|
6
6
|
memoryEntityRelations,
|
|
7
7
|
memoryItemEntities,
|
|
@@ -130,8 +130,6 @@ export function findMatchedEntities(query: string, maxMatches: number): MatchedE
|
|
|
130
130
|
const trimmed = query.trim();
|
|
131
131
|
if (trimmed.length === 0) return [];
|
|
132
132
|
|
|
133
|
-
const db = getDb();
|
|
134
|
-
const raw = (db as unknown as { $client: { query: (q: string) => { all: (...params: unknown[]) => unknown[] } } }).$client;
|
|
135
133
|
const safeLimit = Math.max(1, Math.floor(maxMatches));
|
|
136
134
|
|
|
137
135
|
// Tokenize query into words for entity matching (min length 3 to reduce false positives)
|
|
@@ -173,14 +171,12 @@ export function findMatchedEntities(query: string, maxMatches: number): MatchedE
|
|
|
173
171
|
queryParams = [fullQuery, fullQuery];
|
|
174
172
|
}
|
|
175
173
|
|
|
176
|
-
let matchedEntities: MatchedEntityRow[] = [];
|
|
177
174
|
try {
|
|
178
|
-
|
|
175
|
+
return rawAll<MatchedEntityRow>(entityQuery, ...queryParams);
|
|
179
176
|
} catch (err) {
|
|
180
177
|
log.warn({ err }, 'Entity search query failed');
|
|
181
178
|
return [];
|
|
182
179
|
}
|
|
183
|
-
return matchedEntities;
|
|
184
180
|
}
|
|
185
181
|
|
|
186
182
|
/**
|
|
@@ -225,9 +221,10 @@ export function findNeighborEntities(
|
|
|
225
221
|
const frontierPlaceholders = frontier.map(() => '?').join(',');
|
|
226
222
|
const limit = Math.max(1, edgeBudget);
|
|
227
223
|
|
|
228
|
-
const raw = (db as unknown as { $client: { query: (q: string) => { all: (...params: unknown[]) => unknown[] } } }).$client;
|
|
229
224
|
const relationParams = relationTypes && relationTypes.length > 0 ? relationTypes : [];
|
|
230
225
|
|
|
226
|
+
type EdgeRow = { sourceEntityId: string; targetEntityId: string };
|
|
227
|
+
|
|
231
228
|
if (directed) {
|
|
232
229
|
// GROUP BY deduplicates entity pairs that have multiple relation rows
|
|
233
230
|
const q1 = `
|
|
@@ -240,8 +237,7 @@ export function findNeighborEntities(
|
|
|
240
237
|
ORDER BY MAX(r.last_seen_at) DESC
|
|
241
238
|
LIMIT ?
|
|
242
239
|
`;
|
|
243
|
-
|
|
244
|
-
rows = raw.query(q1).all(...params1) as Array<{ sourceEntityId: string; targetEntityId: string }>;
|
|
240
|
+
rows = rawAll<EdgeRow>(q1, ...frontier, ...relationParams, ...entityTypes, limit);
|
|
245
241
|
} else {
|
|
246
242
|
// Combine both directions in a single query with global recency
|
|
247
243
|
// ordering so the edge budget isn't direction-biased.
|
|
@@ -263,17 +259,12 @@ export function findNeighborEntities(
|
|
|
263
259
|
ORDER BY MAX(last_seen_at) DESC
|
|
264
260
|
LIMIT ?
|
|
265
261
|
`;
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
...relationParams,
|
|
269
|
-
...entityTypes,
|
|
270
|
-
...frontier,
|
|
271
|
-
...relationParams,
|
|
272
|
-
...entityTypes,
|
|
262
|
+
rows = rawAll<EdgeRow>(
|
|
263
|
+
q,
|
|
264
|
+
...frontier, ...relationParams, ...entityTypes,
|
|
265
|
+
...frontier, ...relationParams, ...entityTypes,
|
|
273
266
|
limit,
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
rows = raw.query(q).all(...params) as Array<{ sourceEntityId: string; targetEntityId: string }>;
|
|
267
|
+
);
|
|
277
268
|
}
|
|
278
269
|
} else {
|
|
279
270
|
const frontierCondition = directed
|
|
@@ -1,62 +1,91 @@
|
|
|
1
1
|
import { and, desc, eq, inArray, notInArray } from 'drizzle-orm';
|
|
2
2
|
import { getLogger } from '../../util/logger.js';
|
|
3
|
-
import { getDb } from '../db.js';
|
|
3
|
+
import { getDb, rawAll } from '../db.js';
|
|
4
4
|
import { memorySegments } from '../schema.js';
|
|
5
5
|
import type { Candidate, CandidateType } from './types.js';
|
|
6
6
|
import { computeRecencyScore } from './ranking.js';
|
|
7
7
|
|
|
8
8
|
const log = getLogger('memory-retriever');
|
|
9
9
|
|
|
10
|
+
// Threshold beyond which a raw SQL query is considered slow and logged as a warning.
|
|
11
|
+
const SLOW_QUERY_MS = 2000;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Execute a synchronous raw SQL query with timing. Logs a warning if the
|
|
15
|
+
* query exceeds SLOW_QUERY_MS. Since bun:sqlite queries are synchronous,
|
|
16
|
+
* we can't abort them mid-execution, but we can detect and report slowness.
|
|
17
|
+
*/
|
|
18
|
+
function timedRawQuery<T>(label: string, fn: () => T[]): T[] {
|
|
19
|
+
const start = performance.now();
|
|
20
|
+
const result = fn();
|
|
21
|
+
const elapsed = performance.now() - start;
|
|
22
|
+
if (elapsed >= SLOW_QUERY_MS) {
|
|
23
|
+
log.warn({ label, elapsedMs: Math.round(elapsed) }, 'Raw SQL query exceeded slow threshold');
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface FtsRow {
|
|
29
|
+
segment_id: string;
|
|
30
|
+
message_id: string;
|
|
31
|
+
text: string;
|
|
32
|
+
created_at: number;
|
|
33
|
+
rank: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
10
36
|
export function lexicalSearch(query: string, limit: number, excludedMessageIds: string[] = [], scopeIds?: string[]): Candidate[] {
|
|
11
37
|
const trimmed = query.trim();
|
|
12
38
|
if (trimmed.length === 0 || limit <= 0) return [];
|
|
13
39
|
const matchQuery = buildFtsMatchQuery(trimmed);
|
|
14
40
|
if (!matchQuery) return [];
|
|
15
41
|
const excluded = new Set(excludedMessageIds);
|
|
16
|
-
const db = getDb();
|
|
17
|
-
const raw = (db as unknown as { $client: { query: (q: string) => { all: (...params: unknown[]) => unknown[] } } }).$client;
|
|
18
|
-
let rows: Array<{
|
|
19
|
-
segment_id: string;
|
|
20
|
-
message_id: string;
|
|
21
|
-
text: string;
|
|
22
|
-
created_at: number;
|
|
23
|
-
rank: number;
|
|
24
|
-
}> = [];
|
|
25
|
-
const queryLimit = excluded.size > 0
|
|
26
|
-
? Math.max(limit + 24, limit * 2)
|
|
27
|
-
: limit;
|
|
28
42
|
const scopeClause = scopeIds
|
|
29
43
|
? ` AND s.scope_id IN (${scopeIds.map(() => '?').join(',')})`
|
|
30
44
|
: '';
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
45
|
+
|
|
46
|
+
// Adaptive overfetch: when exclusions are present, double the SQL LIMIT until we
|
|
47
|
+
// collect `limit` visible rows or the DB has no more matching results to offer.
|
|
48
|
+
// This handles dense exclusion sets without wasteful fixed-ratio over-fetching.
|
|
49
|
+
const MAX_FETCH_MULTIPLIER = 8;
|
|
50
|
+
let queryLimit = excluded.size > 0 ? Math.max(limit * 2, limit + 24) : limit;
|
|
51
|
+
let visibleRows: FtsRow[] = [];
|
|
52
|
+
|
|
53
|
+
while (true) {
|
|
54
|
+
let rows: FtsRow[] = [];
|
|
55
|
+
try {
|
|
56
|
+
rows = timedRawQuery('lexicalSearch', () =>
|
|
57
|
+
rawAll<FtsRow>(`
|
|
58
|
+
SELECT
|
|
59
|
+
f.segment_id AS segment_id,
|
|
60
|
+
s.message_id AS message_id,
|
|
61
|
+
s.text AS text,
|
|
62
|
+
s.created_at AS created_at,
|
|
63
|
+
bm25(memory_segment_fts) AS rank
|
|
64
|
+
FROM memory_segment_fts f
|
|
65
|
+
JOIN memory_segments s ON s.id = f.segment_id
|
|
66
|
+
WHERE memory_segment_fts MATCH ?${scopeClause}
|
|
67
|
+
ORDER BY rank
|
|
68
|
+
LIMIT ?
|
|
69
|
+
`, matchQuery, ...(scopeIds ?? []), queryLimit),
|
|
70
|
+
);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
log.warn({ err, query: truncate(trimmed, 80) }, 'Memory lexical search query parse failed');
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
visibleRows = excluded.size > 0
|
|
77
|
+
? rows.filter((row) => !excluded.has(row.message_id))
|
|
78
|
+
: rows;
|
|
79
|
+
|
|
80
|
+
// Stop when we have enough rows, the DB returned fewer than requested
|
|
81
|
+
// (no more results exist), or we've reached the safety cap.
|
|
82
|
+
if (visibleRows.length >= limit || rows.length < queryLimit || queryLimit >= limit * MAX_FETCH_MULTIPLIER) {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
queryLimit = Math.min(queryLimit * 2, limit * MAX_FETCH_MULTIPLIER);
|
|
55
86
|
}
|
|
56
87
|
|
|
57
|
-
|
|
58
|
-
? rows.filter((row) => !excluded.has(row.message_id)).slice(0, limit)
|
|
59
|
-
: rows;
|
|
88
|
+
visibleRows = visibleRows.slice(0, limit);
|
|
60
89
|
|
|
61
90
|
const finiteRanks = visibleRows
|
|
62
91
|
.map((row) => row.rank)
|
|
@@ -124,17 +153,19 @@ export function recencySearch(conversationId: string, limit: number, excludedMes
|
|
|
124
153
|
* Supplements FTS-based lexical search with LIKE-based matching on items.
|
|
125
154
|
*/
|
|
126
155
|
export function directItemSearch(query: string, limit: number, scopeIds?: string[]): Candidate[] {
|
|
127
|
-
const db = getDb();
|
|
128
156
|
const tokens = [...new Set(query
|
|
129
157
|
.toLowerCase()
|
|
130
158
|
.split(/[^a-z0-9_.-]+/g)
|
|
131
159
|
.filter((t) => t.length >= 2))];
|
|
132
160
|
if (tokens.length === 0) return [];
|
|
133
161
|
|
|
134
|
-
const raw = (db as unknown as { $client: { query: (q: string) => { all: (...params: unknown[]) => unknown[] } } }).$client;
|
|
135
162
|
const likeClauses = tokens.map(
|
|
136
|
-
(
|
|
163
|
+
() => `(LOWER(subject) LIKE ? OR LOWER(statement) LIKE ?)`,
|
|
137
164
|
);
|
|
165
|
+
const likeParams = tokens.flatMap((t) => {
|
|
166
|
+
const pattern = `%${escapeLikeWildcards(t)}%`;
|
|
167
|
+
return [pattern, pattern];
|
|
168
|
+
});
|
|
138
169
|
const scopeClause = scopeIds
|
|
139
170
|
? ` AND scope_id IN (${scopeIds.map(() => '?').join(',')})`
|
|
140
171
|
: '';
|
|
@@ -145,9 +176,8 @@ export function directItemSearch(query: string, limit: number, scopeIds?: string
|
|
|
145
176
|
ORDER BY last_seen_at DESC
|
|
146
177
|
LIMIT ?
|
|
147
178
|
`;
|
|
148
|
-
const params: unknown[] = [...(scopeIds ?? []), limit];
|
|
149
179
|
|
|
150
|
-
|
|
180
|
+
interface ItemRow {
|
|
151
181
|
id: string;
|
|
152
182
|
kind: string;
|
|
153
183
|
subject: string;
|
|
@@ -156,9 +186,13 @@ export function directItemSearch(query: string, limit: number, scopeIds?: string
|
|
|
156
186
|
importance: number | null;
|
|
157
187
|
first_seen_at: number;
|
|
158
188
|
last_seen_at: number;
|
|
159
|
-
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
let rows: ItemRow[] = [];
|
|
160
192
|
try {
|
|
161
|
-
rows =
|
|
193
|
+
rows = timedRawQuery('directItemSearch', () =>
|
|
194
|
+
rawAll<ItemRow>(sqlQuery, ...likeParams, ...(scopeIds ?? []), limit),
|
|
195
|
+
);
|
|
162
196
|
} catch {
|
|
163
197
|
return [];
|
|
164
198
|
}
|
|
@@ -212,11 +246,6 @@ export function buildFtsMatchQuery(text: string): string | null {
|
|
|
212
246
|
.join(' OR ');
|
|
213
247
|
}
|
|
214
248
|
|
|
215
|
-
export function escapeSqlLike(s: string): string {
|
|
216
|
-
return s.replace(/'/g, "''").replace(/%/g, '').replace(/_/g, '');
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/** Escape only LIKE wildcards (% and _) for use with parameterized queries where the driver handles quoting. */
|
|
220
249
|
export function escapeLikeWildcards(s: string): string {
|
|
221
250
|
return s.replace(/%/g, '').replace(/_/g, '');
|
|
222
251
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { inArray, sql } from 'drizzle-orm';
|
|
2
|
-
import Anthropic from '@anthropic-ai/sdk';
|
|
3
2
|
import type { AssistantConfig, MemoryRerankingConfig } from '../../config/types.js';
|
|
4
|
-
import { getConfig } from '../../config/loader.js';
|
|
5
3
|
import { estimateTextTokens } from '../../context/token-estimator.js';
|
|
6
4
|
import { getLogger } from '../../util/logger.js';
|
|
5
|
+
import { getConfiguredProvider, extractText, userMessage } from '../../providers/provider-send-message.js';
|
|
7
6
|
import { getDb } from '../db.js';
|
|
8
7
|
import { memoryItems } from '../schema.js';
|
|
9
8
|
import type { Candidate, CandidateSource, ItemMetadata } from './types.js';
|
|
@@ -296,10 +295,9 @@ export async function rerankWithLLM(
|
|
|
296
295
|
candidates: Candidate[],
|
|
297
296
|
rerankingConfig: MemoryRerankingConfig,
|
|
298
297
|
): Promise<Candidate[]> {
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
log.debug('No Anthropic API key available for LLM re-ranking, skipping');
|
|
298
|
+
const provider = getConfiguredProvider();
|
|
299
|
+
if (!provider) {
|
|
300
|
+
log.debug('Configured provider unavailable for LLM re-ranking, skipping');
|
|
303
301
|
return candidates;
|
|
304
302
|
}
|
|
305
303
|
|
|
@@ -309,26 +307,27 @@ export async function rerankWithLLM(
|
|
|
309
307
|
text: truncate(c.text, 200),
|
|
310
308
|
}));
|
|
311
309
|
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
310
|
+
const response = await provider.sendMessage(
|
|
311
|
+
[userMessage(`Query: ${truncate(query, 200)}\n\nCandidates:\n${candidateList.map((c) => `[${c.index}] ${c.text}`).join('\n')}`)],
|
|
312
|
+
undefined,
|
|
313
|
+
'You are a relevance scoring assistant. Given a query and a list of memory candidates, rate each candidate\'s relevance to the query on a scale of 0-10. Return ONLY a JSON array of objects with "index" (the candidate index) and "score" (0-10 integer). No explanation.',
|
|
314
|
+
{
|
|
315
|
+
config: {
|
|
316
|
+
model: rerankingConfig.model,
|
|
317
|
+
max_tokens: 1024,
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
);
|
|
322
321
|
|
|
323
322
|
// Extract text from the response
|
|
324
|
-
const
|
|
325
|
-
if (!
|
|
323
|
+
const responseText = extractText(response);
|
|
324
|
+
if (!responseText) {
|
|
326
325
|
log.warn('LLM re-ranking returned no text block, skipping');
|
|
327
326
|
return candidates;
|
|
328
327
|
}
|
|
329
328
|
|
|
330
329
|
// Parse the JSON array from the response
|
|
331
|
-
const jsonMatch =
|
|
330
|
+
const jsonMatch = responseText.match(/\[[\s\S]*\]/);
|
|
332
331
|
if (!jsonMatch) {
|
|
333
332
|
log.warn('LLM re-ranking response did not contain JSON array, skipping');
|
|
334
333
|
return candidates;
|
|
@@ -359,10 +358,10 @@ export async function rerankWithLLM(
|
|
|
359
358
|
|
|
360
359
|
reranked.sort((a, b) => {
|
|
361
360
|
// Scored items come before unscored items
|
|
362
|
-
if (a.llmScore
|
|
363
|
-
if (a.llmScore
|
|
361
|
+
if (a.llmScore != null && b.llmScore == null) return -1;
|
|
362
|
+
if (a.llmScore == null && b.llmScore != null) return 1;
|
|
364
363
|
// Both scored: sort by score descending
|
|
365
|
-
if (a.llmScore
|
|
364
|
+
if (a.llmScore != null && b.llmScore != null) {
|
|
366
365
|
const scoreDelta = b.llmScore - a.llmScore;
|
|
367
366
|
if (scoreDelta !== 0) return scoreDelta;
|
|
368
367
|
}
|