@vellumai/assistant 0.3.14 → 0.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +142 -0
- package/Dockerfile +2 -2
- package/README.md +5 -5
- package/docs/architecture/http-token-refresh.md +252 -0
- package/docs/architecture/memory.md +5 -4
- package/docs/architecture/scheduling.md +4 -88
- package/docs/runbook-trusted-contacts.md +283 -0
- package/docs/trusted-contact-access.md +247 -0
- package/package.json +1 -1
- package/scripts/ipc/check-swift-decoder-drift.ts +2 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +2 -6
- package/src/__tests__/access-request-decision.test.ts +331 -0
- package/src/__tests__/asset-materialize-tool.test.ts +7 -7
- package/src/__tests__/asset-search-tool.test.ts +15 -15
- package/src/__tests__/attachments-store.test.ts +13 -13
- package/src/__tests__/call-controller.test.ts +150 -4
- package/src/__tests__/call-conversation-messages.test.ts +2 -2
- package/src/__tests__/call-pointer-messages.test.ts +28 -0
- package/src/__tests__/call-start-guardian-guard.test.ts +93 -0
- package/src/__tests__/channel-approval-routes.test.ts +108 -12
- package/src/__tests__/channel-guardian.test.ts +16 -14
- package/src/__tests__/checker.test.ts +24 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +2 -2
- package/src/__tests__/config-watcher.test.ts +358 -0
- package/src/__tests__/conversation-pairing.test.ts +24 -24
- package/src/__tests__/conversation-store.test.ts +36 -36
- package/src/__tests__/date-context.test.ts +179 -1
- package/src/__tests__/db-migration-rollback.test.ts +4 -7
- package/src/__tests__/deterministic-verification-control-plane.test.ts +5 -5
- package/src/__tests__/emit-signal-routing-intent.test.ts +179 -0
- package/src/__tests__/gateway-only-guard.test.ts +188 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +451 -0
- package/src/__tests__/guardian-action-copy-generator.test.ts +197 -0
- package/src/__tests__/guardian-action-followup-executor.test.ts +379 -0
- package/src/__tests__/guardian-action-followup-store.test.ts +376 -0
- package/src/__tests__/guardian-action-late-reply.test.ts +294 -0
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +71 -0
- package/src/__tests__/guardian-action-sweep.test.ts +9 -9
- package/src/__tests__/guardian-control-plane-policy.test.ts +1 -3
- package/src/__tests__/guardian-outbound-http.test.ts +202 -10
- package/src/__tests__/guardian-verification-intent-routing.test.ts +179 -0
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +141 -0
- package/src/__tests__/handlers-telegram-config.test.ts +6 -6
- package/src/__tests__/hooks-runner.test.ts +13 -4
- package/src/__tests__/ingress-routes-http.test.ts +443 -0
- package/src/__tests__/intent-routing.test.ts +14 -0
- package/src/__tests__/ipc-snapshot.test.ts +2 -5
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
- package/src/__tests__/memory-regressions.test.ts +16 -12
- package/src/__tests__/non-member-access-request.test.ts +282 -0
- package/src/__tests__/notification-decision-strategy.test.ts +136 -0
- package/src/__tests__/notification-routing-intent.test.ts +11 -2
- package/src/__tests__/notification-thread-candidates.test.ts +166 -0
- package/src/__tests__/recording-intent-fallback.test.ts +0 -1
- package/src/__tests__/recording-intent-handler.test.ts +6 -3
- package/src/__tests__/recording-intent.test.ts +3 -2
- package/src/__tests__/recording-state-machine.test.ts +337 -26
- package/src/__tests__/registry.test.ts +17 -8
- package/src/__tests__/relay-server.test.ts +105 -0
- package/src/__tests__/reminder.test.ts +13 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +4 -4
- package/src/__tests__/scheduler-recurrence.test.ts +50 -0
- package/src/__tests__/server-history-render.test.ts +8 -8
- package/src/__tests__/session-agent-loop.test.ts +1 -0
- package/src/__tests__/session-runtime-assembly.test.ts +49 -0
- package/src/__tests__/session-skill-tools.test.ts +1 -0
- package/src/__tests__/skill-projection.benchmark.test.ts +11 -3
- package/src/__tests__/slack-channel-config.test.ts +230 -0
- package/src/__tests__/subagent-manager-notify.test.ts +4 -4
- package/src/__tests__/swarm-session-integration.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +43 -0
- package/src/__tests__/task-management-tools.test.ts +3 -3
- package/src/__tests__/task-tools.test.ts +3 -3
- package/src/__tests__/trust-store.test.ts +17 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +491 -0
- package/src/__tests__/trusted-contact-multichannel.test.ts +409 -0
- package/src/__tests__/trusted-contact-verification.test.ts +360 -0
- package/src/__tests__/update-bulletin-format.test.ts +119 -0
- package/src/__tests__/update-bulletin-state.test.ts +129 -0
- package/src/__tests__/update-bulletin.test.ts +260 -0
- package/src/__tests__/update-template-contract.test.ts +29 -0
- package/src/agent/loop.ts +2 -2
- package/src/amazon/client.ts +2 -3
- package/src/calls/call-controller.ts +115 -34
- package/src/calls/call-conversation-messages.ts +2 -2
- package/src/calls/call-domain.ts +10 -3
- package/src/calls/call-pointer-messages.ts +17 -5
- package/src/calls/guardian-action-sweep.ts +77 -36
- package/src/calls/relay-server.ts +51 -12
- package/src/calls/twilio-routes.ts +3 -1
- package/src/calls/types.ts +1 -1
- package/src/calls/voice-session-bridge.ts +4 -4
- package/src/cli/core-commands.ts +3 -3
- package/src/cli/map.ts +8 -5
- package/src/config/bundled-skills/phone-calls/SKILL.md +16 -1
- package/src/config/bundled-skills/tasks/SKILL.md +1 -1
- package/src/config/bundled-skills/tasks/TOOLS.json +4 -4
- package/src/config/bundled-skills/time-based-actions/SKILL.md +11 -1
- package/src/config/computer-use-prompt.ts +1 -0
- package/src/config/core-schema.ts +16 -0
- package/src/config/env-registry.ts +1 -0
- package/src/config/env.ts +16 -1
- package/src/config/memory-schema.ts +5 -0
- package/src/config/schema.ts +4 -0
- package/src/config/system-prompt.ts +69 -2
- package/src/config/templates/BOOTSTRAP.md +1 -1
- package/src/config/templates/IDENTITY.md +8 -4
- package/src/config/templates/SOUL.md +14 -0
- package/src/config/templates/UPDATES.md +16 -0
- package/src/config/templates/USER.md +5 -1
- package/src/config/types.ts +1 -0
- package/src/config/update-bulletin-format.ts +52 -0
- package/src/config/update-bulletin-state.ts +49 -0
- package/src/config/update-bulletin.ts +82 -0
- package/src/config/vellum-skills/catalog.json +6 -0
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
- package/src/config/vellum-skills/guardian-verify-setup/SKILL.md +44 -10
- package/src/config/vellum-skills/telegram-setup/SKILL.md +4 -4
- package/src/config/vellum-skills/trusted-contacts/SKILL.md +147 -0
- package/src/config/vellum-skills/twilio-setup/SKILL.md +2 -2
- package/src/context/window-manager.ts +43 -3
- package/src/daemon/config-watcher.ts +1 -0
- package/src/daemon/connection-policy.ts +21 -1
- package/src/daemon/daemon-control.ts +164 -7
- package/src/daemon/date-context.ts +174 -1
- package/src/daemon/guardian-action-generators.ts +175 -0
- package/src/daemon/guardian-verification-intent.ts +120 -0
- package/src/daemon/handlers/apps.ts +1 -3
- package/src/daemon/handlers/config-channels.ts +8 -8
- package/src/daemon/handlers/config-heartbeat.ts +1 -1
- package/src/daemon/handlers/config-inbox.ts +55 -159
- package/src/daemon/handlers/config-ingress.ts +1 -1
- package/src/daemon/handlers/config-integrations.ts +1 -1
- package/src/daemon/handlers/config-platform.ts +1 -1
- package/src/daemon/handlers/config-scheduling.ts +2 -2
- package/src/daemon/handlers/config-slack-channel.ts +190 -0
- package/src/daemon/handlers/config-telegram.ts +1 -1
- package/src/daemon/handlers/config-twilio.ts +1 -1
- package/src/daemon/handlers/config-voice.ts +100 -0
- package/src/daemon/handlers/config.ts +3 -0
- package/src/daemon/handlers/index.ts +1 -1
- package/src/daemon/handlers/misc.ts +84 -6
- package/src/daemon/handlers/navigate-settings.ts +27 -0
- package/src/daemon/handlers/recording.ts +270 -144
- package/src/daemon/handlers/sessions.ts +107 -24
- package/src/daemon/handlers/subagents.ts +3 -3
- package/src/daemon/handlers/work-items.ts +10 -7
- package/src/daemon/ipc-contract/integrations.ts +9 -1
- package/src/daemon/ipc-contract/messages.ts +4 -0
- package/src/daemon/ipc-contract/sessions.ts +1 -1
- package/src/daemon/ipc-contract/settings.ts +26 -0
- package/src/daemon/ipc-contract/shared.ts +2 -0
- package/src/daemon/ipc-contract/work-items.ts +1 -7
- package/src/daemon/ipc-contract-inventory.json +5 -1
- package/src/daemon/ipc-contract.ts +5 -1
- package/src/daemon/lifecycle.ts +306 -266
- package/src/daemon/recording-executor.ts +1 -1
- package/src/daemon/recording-intent.ts +0 -41
- package/src/daemon/response-tier.ts +2 -2
- package/src/daemon/server.ts +6 -6
- package/src/daemon/session-agent-loop-handlers.ts +34 -9
- package/src/daemon/session-agent-loop.ts +15 -8
- package/src/daemon/session-history.ts +3 -2
- package/src/daemon/session-media-retry.ts +3 -0
- package/src/daemon/session-messaging.ts +38 -4
- package/src/daemon/session-notifiers.ts +2 -2
- package/src/daemon/session-process.ts +256 -23
- package/src/daemon/session-queue-manager.ts +2 -0
- package/src/daemon/session-runtime-assembly.ts +39 -0
- package/src/daemon/session-skill-tools.ts +13 -4
- package/src/daemon/session-tool-setup.ts +6 -7
- package/src/daemon/session.ts +19 -8
- package/src/daemon/tls-certs.ts +55 -13
- package/src/daemon/tool-side-effects.ts +13 -5
- package/src/gallery/default-gallery.ts +32 -9
- package/src/influencer/client.ts +2 -1
- package/src/memory/channel-delivery-store.ts +37 -567
- package/src/memory/channel-guardian-store.ts +66 -1317
- package/src/memory/conflict-store.ts +4 -4
- package/src/memory/conversation-attention-store.ts +4 -7
- package/src/memory/conversation-crud.ts +668 -0
- package/src/memory/conversation-queries.ts +361 -0
- package/src/memory/conversation-store.ts +45 -983
- package/src/memory/db-connection.ts +3 -0
- package/src/memory/db-init.ts +25 -0
- package/src/memory/delivery-channels.ts +175 -0
- package/src/memory/delivery-crud.ts +211 -0
- package/src/memory/delivery-status.ts +199 -0
- package/src/memory/embedding-backend.ts +70 -4
- package/src/memory/embedding-local.ts +12 -2
- package/src/memory/entity-extractor.ts +3 -8
- package/src/memory/fts-reconciler.ts +121 -0
- package/src/memory/guardian-action-store.ts +366 -3
- package/src/memory/guardian-approvals.ts +569 -0
- package/src/memory/guardian-bindings.ts +130 -0
- package/src/memory/guardian-rate-limits.ts +196 -0
- package/src/memory/guardian-verification.ts +520 -0
- package/src/memory/job-handlers/index-maintenance.ts +2 -1
- package/src/memory/job-utils.ts +8 -5
- package/src/memory/jobs-store.ts +66 -6
- package/src/memory/jobs-worker.ts +23 -1
- package/src/memory/migrations/030-guardian-action-followup.ts +21 -0
- package/src/memory/migrations/030-guardian-verification-purpose.ts +17 -0
- package/src/memory/migrations/031-conversations-thread-type-index.ts +5 -0
- package/src/memory/migrations/100-core-tables.ts +1 -1
- package/src/memory/migrations/101-watchers-and-logs.ts +4 -0
- package/src/memory/migrations/108-tasks-and-work-items.ts +1 -1
- package/src/memory/migrations/112-assistant-inbox.ts +1 -1
- package/src/memory/migrations/113-late-migrations.ts +1 -1
- package/src/memory/migrations/116-messages-fts.ts +13 -0
- package/src/memory/migrations/119-schema-indexes-and-columns.ts +37 -0
- package/src/memory/migrations/120-fk-cascade-rebuilds.ts +161 -0
- package/src/memory/migrations/index.ts +8 -3
- package/src/memory/migrations/validate-migration-state.ts +114 -15
- package/src/memory/qdrant-circuit-breaker.ts +105 -0
- package/src/memory/retriever.ts +46 -13
- package/src/memory/schema-migration.ts +3 -0
- package/src/memory/schema.ts +25 -7
- package/src/memory/search/semantic.ts +8 -90
- package/src/notifications/README.md +1 -1
- package/src/notifications/broadcaster.ts +20 -2
- package/src/notifications/conversation-pairing.ts +3 -3
- package/src/notifications/decision-engine.ts +173 -8
- package/src/notifications/deliveries-store.ts +27 -8
- package/src/notifications/preferences-store.ts +7 -7
- package/src/notifications/thread-candidates.ts +234 -0
- package/src/notifications/types.ts +18 -0
- package/src/permissions/defaults.ts +11 -1
- package/src/permissions/prompter.ts +17 -0
- package/src/permissions/trust-store.ts +2 -0
- package/src/providers/failover.ts +19 -0
- package/src/providers/registry.ts +46 -1
- package/src/runtime/approval-message-composer.ts +1 -1
- package/src/runtime/channel-guardian-service.ts +15 -3
- package/src/runtime/channel-retry-sweep.ts +7 -2
- package/src/runtime/guardian-action-conversation-turn.ts +85 -0
- package/src/runtime/guardian-action-followup-executor.ts +301 -0
- package/src/runtime/guardian-action-message-composer.ts +245 -0
- package/src/runtime/guardian-outbound-actions.ts +35 -15
- package/src/runtime/guardian-verification-templates.ts +15 -9
- package/src/runtime/http-errors.ts +93 -0
- package/src/runtime/http-server.ts +140 -51
- package/src/runtime/http-types.ts +53 -0
- package/src/runtime/ingress-service.ts +237 -0
- package/src/runtime/middleware/error-handler.ts +4 -3
- package/src/runtime/middleware/rate-limiter.ts +160 -0
- package/src/runtime/middleware/request-logger.ts +71 -0
- package/src/runtime/middleware/twilio-validation.ts +7 -6
- package/src/runtime/pending-interactions.ts +12 -0
- package/src/runtime/routes/access-request-decision.ts +215 -0
- package/src/runtime/routes/app-routes.ts +25 -18
- package/src/runtime/routes/approval-routes.ts +18 -47
- package/src/runtime/routes/attachment-routes.ts +15 -41
- package/src/runtime/routes/call-routes.ts +20 -20
- package/src/runtime/routes/channel-delivery-routes.ts +6 -5
- package/src/runtime/routes/contact-routes.ts +4 -9
- package/src/runtime/routes/conversation-attention-routes.ts +5 -4
- package/src/runtime/routes/conversation-routes.ts +26 -57
- package/src/runtime/routes/debug-routes.ts +71 -0
- package/src/runtime/routes/events-routes.ts +3 -2
- package/src/runtime/routes/guardian-approval-interception.ts +221 -0
- package/src/runtime/routes/identity-routes.ts +14 -10
- package/src/runtime/routes/inbound-conversation.ts +3 -2
- package/src/runtime/routes/inbound-message-handler.ts +527 -62
- package/src/runtime/routes/ingress-routes.ts +174 -0
- package/src/runtime/routes/integration-routes.ts +82 -20
- package/src/runtime/routes/pairing-routes.ts +11 -10
- package/src/runtime/routes/secret-routes.ts +10 -18
- package/src/runtime/verification-rate-limiter.ts +83 -0
- package/src/schedule/schedule-store.ts +13 -1
- package/src/schedule/scheduler.ts +2 -2
- package/src/security/secret-ingress.ts +5 -2
- package/src/security/secret-scanner.ts +72 -6
- package/src/subagent/manager.ts +6 -4
- package/src/swarm/plan-validator.ts +4 -1
- package/src/tasks/task-runner.ts +3 -1
- package/src/tools/browser/api-map.ts +9 -6
- package/src/tools/calls/call-start.ts +20 -0
- package/src/tools/executor.ts +50 -568
- package/src/tools/permission-checker.ts +272 -0
- package/src/tools/registry.ts +14 -6
- package/src/tools/reminder/reminder-store.ts +7 -7
- package/src/tools/reminder/reminder.ts +6 -3
- package/src/tools/secret-detection-handler.ts +301 -0
- package/src/tools/subagent/message.ts +1 -1
- package/src/tools/system/voice-config.ts +62 -0
- package/src/tools/tasks/index.ts +3 -3
- package/src/tools/tasks/work-item-list.ts +3 -3
- package/src/tools/tasks/work-item-update.ts +4 -5
- package/src/tools/tool-approval-handler.ts +192 -0
- package/src/tools/tool-manifest.ts +2 -0
- package/src/watcher/watcher-store.ts +9 -9
- package/src/work-items/work-item-runner.ts +9 -6
- /package/src/memory/migrations/{026-embeddings-nullable-vector-json.ts → 026a-embeddings-nullable-vector-json.ts} +0 -0
- /package/src/memory/migrations/{027-guardian-bootstrap-token.ts → 027a-guardian-bootstrap-token.ts} +0 -0
|
@@ -4,12 +4,77 @@ import { getOllamaBaseUrlEnv } from '../config/env.js';
|
|
|
4
4
|
import type { AssistantConfig } from '../config/types.js';
|
|
5
5
|
import { getLogger } from '../util/logger.js';
|
|
6
6
|
import { GeminiEmbeddingBackend } from './embedding-gemini.js';
|
|
7
|
-
import { LocalEmbeddingBackend } from './embedding-local.js';
|
|
8
7
|
import { OllamaEmbeddingBackend } from './embedding-ollama.js';
|
|
9
8
|
import { OpenAIEmbeddingBackend } from './embedding-openai.js';
|
|
10
9
|
|
|
11
10
|
const log = getLogger('memory-embeddings');
|
|
12
11
|
|
|
12
|
+
// Tracks whether the local embedding backend has permanently failed to load
|
|
13
|
+
// (e.g., onnxruntime-node missing in a compiled binary). Once set, `auto` mode
|
|
14
|
+
// skips `local` as primary, avoiding repeated fallback latency and cost.
|
|
15
|
+
let localBackendBroken = false;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Lazy wrapper around LocalEmbeddingBackend that dynamically imports the
|
|
19
|
+
* module on first use. This avoids eagerly loading @huggingface/transformers
|
|
20
|
+
* (which statically imports onnxruntime-node) at module evaluation time.
|
|
21
|
+
* In compiled binaries where onnxruntime-node isn't bundled, the static
|
|
22
|
+
* import would crash the entire daemon at startup. By deferring the import,
|
|
23
|
+
* the failure is contained and other embedding backends can be used instead.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
class LazyLocalEmbeddingBackend implements EmbeddingBackend {
|
|
27
|
+
readonly provider = 'local' as const;
|
|
28
|
+
readonly model: string;
|
|
29
|
+
private delegate: EmbeddingBackend | null = null;
|
|
30
|
+
private initPromise: Promise<EmbeddingBackend> | null = null;
|
|
31
|
+
|
|
32
|
+
constructor(model: string) {
|
|
33
|
+
this.model = model;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async embed(texts: string[], options?: EmbeddingRequestOptions): Promise<number[][]> {
|
|
37
|
+
const backend = await this.getDelegate();
|
|
38
|
+
try {
|
|
39
|
+
return await backend.embed(texts, options);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
// The onnxruntime-node failure surfaces here during the first embed() call
|
|
42
|
+
// (via LocalEmbeddingBackend.initialize()). Mark broken so auto mode stops
|
|
43
|
+
// selecting local on subsequent requests.
|
|
44
|
+
if (!localBackendBroken && isInitializationError(err)) {
|
|
45
|
+
localBackendBroken = true;
|
|
46
|
+
log.warn({ err }, 'Local embedding backend permanently unavailable; auto mode will skip it');
|
|
47
|
+
}
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private async getDelegate(): Promise<EmbeddingBackend> {
|
|
53
|
+
if (this.delegate) return this.delegate;
|
|
54
|
+
if (!this.initPromise) {
|
|
55
|
+
this.initPromise = (async () => {
|
|
56
|
+
try {
|
|
57
|
+
const { LocalEmbeddingBackend } = await import('./embedding-local.js');
|
|
58
|
+
this.delegate = new LocalEmbeddingBackend(this.model);
|
|
59
|
+
return this.delegate;
|
|
60
|
+
} catch (err) {
|
|
61
|
+
localBackendBroken = true;
|
|
62
|
+
log.warn({ err }, 'Local embedding backend permanently unavailable; auto mode will skip it');
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
})();
|
|
66
|
+
}
|
|
67
|
+
return this.initPromise;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Detect errors thrown by LocalEmbeddingBackend.initialize() so we can
|
|
72
|
+
* distinguish permanent init failures from transient embed-time errors. */
|
|
73
|
+
function isInitializationError(err: unknown): boolean {
|
|
74
|
+
if (!(err instanceof Error)) return false;
|
|
75
|
+
return err.message.includes('Local embedding backend unavailable');
|
|
76
|
+
}
|
|
77
|
+
|
|
13
78
|
/** Global cache of embedding backend instances, keyed by "provider:model". */
|
|
14
79
|
const backendCache = new Map<string, EmbeddingBackend>();
|
|
15
80
|
|
|
@@ -69,6 +134,7 @@ export function clearEmbeddingBackendCache(): void {
|
|
|
69
134
|
backendCache.clear();
|
|
70
135
|
vectorCache.clear();
|
|
71
136
|
vectorCacheBytes = 0;
|
|
137
|
+
localBackendBroken = false;
|
|
72
138
|
}
|
|
73
139
|
|
|
74
140
|
function cacheKey(provider: string, model: string): string {
|
|
@@ -106,7 +172,7 @@ export function selectEmbeddingBackend(config: AssistantConfig): EmbeddingBacken
|
|
|
106
172
|
if (requested === 'local') {
|
|
107
173
|
return {
|
|
108
174
|
backend: getCachedOrCreate('local', config.memory.embeddings.localModel,
|
|
109
|
-
() => new
|
|
175
|
+
() => new LazyLocalEmbeddingBackend(config.memory.embeddings.localModel)),
|
|
110
176
|
reason: null,
|
|
111
177
|
};
|
|
112
178
|
}
|
|
@@ -128,10 +194,10 @@ export function selectEmbeddingBackend(config: AssistantConfig): EmbeddingBacken
|
|
|
128
194
|
for (const provider of order) {
|
|
129
195
|
switch (provider) {
|
|
130
196
|
case 'local':
|
|
131
|
-
|
|
197
|
+
if (localBackendBroken) continue;
|
|
132
198
|
return {
|
|
133
199
|
backend: getCachedOrCreate('local', config.memory.embeddings.localModel,
|
|
134
|
-
() => new
|
|
200
|
+
() => new LazyLocalEmbeddingBackend(config.memory.embeddings.localModel)),
|
|
135
201
|
reason: null,
|
|
136
202
|
};
|
|
137
203
|
case 'openai':
|
|
@@ -56,8 +56,18 @@ export class LocalEmbeddingBackend implements EmbeddingBackend {
|
|
|
56
56
|
|
|
57
57
|
private async initialize(): Promise<void> {
|
|
58
58
|
log.info({ model: this.model }, 'Loading local embedding model (first load downloads the model)');
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
let transformers: typeof import('@huggingface/transformers');
|
|
60
|
+
try {
|
|
61
|
+
transformers = await import('@huggingface/transformers');
|
|
62
|
+
} catch (err) {
|
|
63
|
+
// onnxruntime-node is not bundled in compiled binaries, so the import
|
|
64
|
+
// fails at runtime. Surface a clear error so callers can fall back to
|
|
65
|
+
// another embedding backend.
|
|
66
|
+
throw new Error(
|
|
67
|
+
`Local embedding backend unavailable: failed to load @huggingface/transformers (${err instanceof Error ? err.message : String(err)})`,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
this.extractor = await transformers.pipeline('feature-extraction', this.model, {
|
|
61
71
|
dtype: 'fp32',
|
|
62
72
|
}) as unknown as FeatureExtractionPipeline;
|
|
63
73
|
log.info({ model: this.model }, 'Local embedding model loaded');
|
|
@@ -4,7 +4,7 @@ import type { MemoryEntityConfig } from '../config/types.js';
|
|
|
4
4
|
import { createTimeout, extractToolUse, getConfiguredProvider, userMessage } from '../providers/provider-send-message.js';
|
|
5
5
|
import { getLogger } from '../util/logger.js';
|
|
6
6
|
import { truncate } from '../util/truncate.js';
|
|
7
|
-
import { getDb } from './db.js';
|
|
7
|
+
import { getDb, rawAll } from './db.js';
|
|
8
8
|
import { memoryEntities, memoryEntityRelations, memoryItemEntities } from './schema.js';
|
|
9
9
|
|
|
10
10
|
const log = getLogger('memory-entity-extractor');
|
|
@@ -426,20 +426,15 @@ function parseExtractedRelations(
|
|
|
426
426
|
function findEntityCandidates(nameOrAlias: string): Array<typeof memoryEntities.$inferSelect> {
|
|
427
427
|
const normalized = normalizeEntityName(nameOrAlias);
|
|
428
428
|
if (!normalized) return [];
|
|
429
|
-
const db = getDb();
|
|
430
429
|
const nameLower = normalized.toLowerCase();
|
|
431
430
|
|
|
432
|
-
|
|
433
|
-
$client: { query: (q: string) => { all: (...params: unknown[]) => unknown[] } };
|
|
434
|
-
}).$client;
|
|
435
|
-
|
|
436
|
-
return raw.query(`
|
|
431
|
+
return rawAll<typeof memoryEntities.$inferSelect>(`
|
|
437
432
|
SELECT DISTINCT me.* FROM memory_entities me
|
|
438
433
|
WHERE LOWER(me.name) = ?
|
|
439
434
|
UNION
|
|
440
435
|
SELECT DISTINCT me.* FROM memory_entities me, json_each(me.aliases) je
|
|
441
436
|
WHERE me.aliases IS NOT NULL AND LOWER(je.value) = ?
|
|
442
|
-
|
|
437
|
+
`, nameLower, nameLower);
|
|
443
438
|
}
|
|
444
439
|
|
|
445
440
|
/**
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { getLogger } from '../util/logger.js';
|
|
2
|
+
import { rawGet, rawRun } from './db.js';
|
|
3
|
+
|
|
4
|
+
const log = getLogger('fts-reconciler');
|
|
5
|
+
|
|
6
|
+
export interface FtsReconciliationResult {
|
|
7
|
+
table: string;
|
|
8
|
+
baseCount: number;
|
|
9
|
+
ftsCount: number;
|
|
10
|
+
missingInserted: number;
|
|
11
|
+
orphansRemoved: number;
|
|
12
|
+
staleRefreshed: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Reconcile a single FTS index against its base table. Detects missing entries
|
|
17
|
+
* (rows in the base table with no corresponding FTS row) and orphaned entries
|
|
18
|
+
* (FTS rows whose base table row no longer exists), then repairs both.
|
|
19
|
+
*
|
|
20
|
+
* This is lighter than a full rebuild — it only touches the delta rather than
|
|
21
|
+
* wiping and re-inserting the entire index.
|
|
22
|
+
*/
|
|
23
|
+
function reconcileTable(opts: {
|
|
24
|
+
ftsTable: string;
|
|
25
|
+
ftsIdColumn: string;
|
|
26
|
+
ftsContentColumn: string;
|
|
27
|
+
baseTable: string;
|
|
28
|
+
baseIdColumn: string;
|
|
29
|
+
baseContentColumn: string;
|
|
30
|
+
}): FtsReconciliationResult {
|
|
31
|
+
const { ftsTable, ftsIdColumn, ftsContentColumn, baseTable, baseIdColumn, baseContentColumn } = opts;
|
|
32
|
+
|
|
33
|
+
const baseCount = (rawGet<{ c: number }>(`SELECT COUNT(*) AS c FROM ${baseTable}`) ?? { c: 0 }).c;
|
|
34
|
+
const ftsCount = (rawGet<{ c: number }>(`SELECT COUNT(*) AS c FROM ${ftsTable}`) ?? { c: 0 }).c;
|
|
35
|
+
|
|
36
|
+
// Find base table rows missing from the FTS index
|
|
37
|
+
const missingInserted = rawRun(/*sql*/ `
|
|
38
|
+
INSERT INTO ${ftsTable}(${ftsIdColumn}, ${ftsContentColumn})
|
|
39
|
+
SELECT b.${baseIdColumn}, b.${baseContentColumn}
|
|
40
|
+
FROM ${baseTable} b
|
|
41
|
+
LEFT JOIN ${ftsTable} f ON f.${ftsIdColumn} = b.${baseIdColumn}
|
|
42
|
+
WHERE f.${ftsIdColumn} IS NULL
|
|
43
|
+
`);
|
|
44
|
+
|
|
45
|
+
// Find FTS rows whose base table row no longer exists
|
|
46
|
+
const orphansRemoved = rawRun(/*sql*/ `
|
|
47
|
+
DELETE FROM ${ftsTable}
|
|
48
|
+
WHERE ${ftsIdColumn} IN (
|
|
49
|
+
SELECT f.${ftsIdColumn}
|
|
50
|
+
FROM ${ftsTable} f
|
|
51
|
+
LEFT JOIN ${baseTable} b ON b.${baseIdColumn} = f.${ftsIdColumn}
|
|
52
|
+
WHERE b.${baseIdColumn} IS NULL
|
|
53
|
+
)
|
|
54
|
+
`);
|
|
55
|
+
|
|
56
|
+
// Refresh FTS rows whose content is stale (base row was updated but the
|
|
57
|
+
// update trigger didn't fire or was missing). Delete-then-insert is the
|
|
58
|
+
// standard FTS5 update pattern.
|
|
59
|
+
const staleDeleted = rawRun(/*sql*/ `
|
|
60
|
+
DELETE FROM ${ftsTable}
|
|
61
|
+
WHERE ${ftsIdColumn} IN (
|
|
62
|
+
SELECT f.${ftsIdColumn}
|
|
63
|
+
FROM ${ftsTable} f
|
|
64
|
+
JOIN ${baseTable} b ON b.${baseIdColumn} = f.${ftsIdColumn}
|
|
65
|
+
WHERE b.${baseContentColumn} IS NOT f.${ftsContentColumn}
|
|
66
|
+
)
|
|
67
|
+
`);
|
|
68
|
+
if (staleDeleted > 0) {
|
|
69
|
+
rawRun(/*sql*/ `
|
|
70
|
+
INSERT INTO ${ftsTable}(${ftsIdColumn}, ${ftsContentColumn})
|
|
71
|
+
SELECT b.${baseIdColumn}, b.${baseContentColumn}
|
|
72
|
+
FROM ${baseTable} b
|
|
73
|
+
LEFT JOIN ${ftsTable} f ON f.${ftsIdColumn} = b.${baseIdColumn}
|
|
74
|
+
WHERE f.${ftsIdColumn} IS NULL
|
|
75
|
+
`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { table: ftsTable, baseCount, ftsCount, missingInserted, orphansRemoved, staleRefreshed: staleDeleted };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Reconcile all FTS indexes. Returns results for each table so callers can
|
|
83
|
+
* inspect what was repaired.
|
|
84
|
+
*/
|
|
85
|
+
export function reconcileFtsIndexes(): FtsReconciliationResult[] {
|
|
86
|
+
const results: FtsReconciliationResult[] = [];
|
|
87
|
+
|
|
88
|
+
// memory_segment_fts tracks memory_segments
|
|
89
|
+
const memResult = reconcileTable({
|
|
90
|
+
ftsTable: 'memory_segment_fts',
|
|
91
|
+
ftsIdColumn: 'segment_id',
|
|
92
|
+
ftsContentColumn: 'text',
|
|
93
|
+
baseTable: 'memory_segments',
|
|
94
|
+
baseIdColumn: 'id',
|
|
95
|
+
baseContentColumn: 'text',
|
|
96
|
+
});
|
|
97
|
+
results.push(memResult);
|
|
98
|
+
if (memResult.missingInserted > 0 || memResult.orphansRemoved > 0 || memResult.staleRefreshed > 0) {
|
|
99
|
+
log.info(memResult, 'Reconciled memory_segment_fts');
|
|
100
|
+
} else {
|
|
101
|
+
log.debug(memResult, 'memory_segment_fts is in sync');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// messages_fts tracks messages
|
|
105
|
+
const msgResult = reconcileTable({
|
|
106
|
+
ftsTable: 'messages_fts',
|
|
107
|
+
ftsIdColumn: 'message_id',
|
|
108
|
+
ftsContentColumn: 'content',
|
|
109
|
+
baseTable: 'messages',
|
|
110
|
+
baseIdColumn: 'id',
|
|
111
|
+
baseContentColumn: 'content',
|
|
112
|
+
});
|
|
113
|
+
results.push(msgResult);
|
|
114
|
+
if (msgResult.missingInserted > 0 || msgResult.orphansRemoved > 0 || msgResult.staleRefreshed > 0) {
|
|
115
|
+
log.info(msgResult, 'Reconciled messages_fts');
|
|
116
|
+
} else {
|
|
117
|
+
log.debug(msgResult, 'messages_fts is in sync');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return results;
|
|
121
|
+
}
|