@vellumai/assistant 0.4.49 → 0.4.50
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 +24 -33
- package/README.md +3 -3
- package/docs/architecture/memory.md +180 -119
- package/package.json +2 -2
- package/src/__tests__/agent-loop.test.ts +3 -1
- package/src/__tests__/anthropic-provider.test.ts +114 -23
- package/src/__tests__/approval-cascade.test.ts +1 -15
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
- package/src/__tests__/canonical-guardian-store.test.ts +95 -0
- package/src/__tests__/checker.test.ts +13 -0
- package/src/__tests__/config-schema.test.ts +1 -68
- package/src/__tests__/context-memory-e2e.test.ts +11 -100
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/credential-security-e2e.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +4 -0
- package/src/__tests__/credential-vault.test.ts +13 -1
- package/src/__tests__/cu-unified-flow.test.ts +532 -0
- package/src/__tests__/date-context.test.ts +93 -77
- package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
- package/src/__tests__/history-repair.test.ts +245 -0
- package/src/__tests__/host-cu-proxy.test.ts +165 -3
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/invite-redemption-service.test.ts +65 -1
- package/src/__tests__/keychain-broker-client.test.ts +4 -4
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
- package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
- package/src/__tests__/memory-recall-quality.test.ts +244 -407
- package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
- package/src/__tests__/memory-regressions.test.ts +477 -2841
- package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
- package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
- package/src/__tests__/mime-builder.test.ts +28 -0
- package/src/__tests__/native-web-search.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +572 -5
- package/src/__tests__/oauth-store.test.ts +120 -6
- package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
- package/src/__tests__/registry.test.ts +0 -1
- package/src/__tests__/relay-server.test.ts +46 -1
- package/src/__tests__/schedule-tools.test.ts +32 -0
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +1 -0
- package/src/__tests__/secure-keys.test.ts +7 -2
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/session-abort-tool-results.test.ts +1 -14
- package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
- package/src/__tests__/session-agent-loop.test.ts +19 -15
- package/src/__tests__/session-confirmation-signals.test.ts +1 -15
- package/src/__tests__/session-error.test.ts +124 -2
- package/src/__tests__/session-history-web-search.test.ts +918 -0
- package/src/__tests__/session-pre-run-repair.test.ts +1 -14
- package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
- package/src/__tests__/session-queue.test.ts +37 -27
- package/src/__tests__/session-runtime-assembly.test.ts +54 -0
- package/src/__tests__/session-slash-known.test.ts +1 -15
- package/src/__tests__/session-slash-queue.test.ts +1 -15
- package/src/__tests__/session-slash-unknown.test.ts +1 -15
- package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
- package/src/__tests__/session-workspace-injection.test.ts +3 -37
- package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
- package/src/__tests__/skills-install-extract.test.ts +93 -0
- package/src/__tests__/skillssh-registry.test.ts +451 -0
- package/src/__tests__/trust-store.test.ts +15 -0
- package/src/__tests__/voice-invite-redemption.test.ts +32 -1
- package/src/agent/ax-tree-compaction.test.ts +51 -0
- package/src/agent/loop.ts +39 -12
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/guardian-request-resolvers.ts +14 -2
- package/src/bundler/compiler-tools.ts +66 -2
- package/src/calls/call-domain.ts +132 -0
- package/src/calls/call-store.ts +6 -0
- package/src/calls/relay-server.ts +43 -5
- package/src/calls/relay-setup-router.ts +17 -1
- package/src/calls/twilio-config.ts +1 -1
- package/src/calls/types.ts +3 -1
- package/src/cli/commands/doctor.ts +4 -3
- package/src/cli/commands/mcp.ts +46 -59
- package/src/cli/commands/memory.ts +16 -165
- package/src/cli/commands/oauth/apps.ts +31 -2
- package/src/cli/commands/oauth/connections.ts +431 -97
- package/src/cli/commands/oauth/providers.ts +15 -1
- package/src/cli/commands/sessions.ts +5 -2
- package/src/cli/commands/skills.ts +173 -1
- package/src/cli/http-client.ts +0 -20
- package/src/cli/main-screen.tsx +2 -2
- package/src/cli/program.ts +5 -6
- package/src/cli.ts +4 -10
- package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
- package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
- package/src/config/bundled-tool-registry.ts +2 -5
- package/src/config/schema.ts +1 -12
- package/src/config/schemas/memory-lifecycle.ts +0 -9
- package/src/config/schemas/memory-processing.ts +0 -180
- package/src/config/schemas/memory-retrieval.ts +32 -104
- package/src/config/schemas/memory.ts +0 -10
- package/src/config/types.ts +0 -4
- package/src/context/window-manager.ts +4 -1
- package/src/daemon/config-watcher.ts +61 -3
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +114 -31
- package/src/daemon/handlers/sessions.ts +18 -13
- package/src/daemon/handlers/skills.ts +20 -1
- package/src/daemon/history-repair.ts +72 -8
- package/src/daemon/host-cu-proxy.ts +55 -26
- package/src/daemon/lifecycle.ts +31 -3
- package/src/daemon/mcp-reload-service.ts +2 -2
- package/src/daemon/message-types/computer-use.ts +1 -12
- package/src/daemon/message-types/memory.ts +4 -16
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/sessions.ts +4 -0
- package/src/daemon/server.ts +12 -1
- package/src/daemon/session-agent-loop-handlers.ts +38 -0
- package/src/daemon/session-agent-loop.ts +334 -48
- package/src/daemon/session-error.ts +89 -6
- package/src/daemon/session-history.ts +17 -7
- package/src/daemon/session-media-retry.ts +6 -2
- package/src/daemon/session-memory.ts +69 -149
- package/src/daemon/session-process.ts +10 -1
- package/src/daemon/session-runtime-assembly.ts +49 -19
- package/src/daemon/session-surfaces.ts +4 -1
- package/src/daemon/session-tool-setup.ts +7 -1
- package/src/daemon/session.ts +12 -2
- package/src/instrument.ts +61 -1
- package/src/memory/admin.ts +2 -191
- package/src/memory/canonical-guardian-store.ts +38 -2
- package/src/memory/conversation-crud.ts +0 -33
- package/src/memory/conversation-queries.ts +22 -3
- package/src/memory/db-init.ts +28 -0
- package/src/memory/embedding-backend.ts +84 -8
- package/src/memory/embedding-types.ts +9 -1
- package/src/memory/indexer.ts +7 -46
- package/src/memory/items-extractor.ts +274 -76
- package/src/memory/job-handlers/backfill.ts +2 -127
- package/src/memory/job-handlers/cleanup.ts +2 -16
- package/src/memory/job-handlers/extraction.ts +2 -138
- package/src/memory/job-handlers/index-maintenance.ts +1 -6
- package/src/memory/job-handlers/summarization.ts +3 -148
- package/src/memory/job-utils.ts +21 -59
- package/src/memory/jobs-store.ts +1 -159
- package/src/memory/jobs-worker.ts +9 -52
- package/src/memory/migrations/104-core-indexes.ts +3 -3
- package/src/memory/migrations/149-oauth-tables.ts +2 -0
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
- package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
- package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
- package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
- package/src/memory/migrations/154-drop-fts.ts +20 -0
- package/src/memory/migrations/155-drop-conflicts.ts +7 -0
- package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/qdrant-client.ts +148 -51
- package/src/memory/raw-query.ts +1 -1
- package/src/memory/retriever.test.ts +294 -273
- package/src/memory/retriever.ts +421 -645
- package/src/memory/schema/calls.ts +2 -0
- package/src/memory/schema/memory-core.ts +3 -48
- package/src/memory/schema/oauth.ts +2 -0
- package/src/memory/search/formatting.ts +263 -176
- package/src/memory/search/lexical.ts +1 -254
- package/src/memory/search/ranking.ts +0 -455
- package/src/memory/search/semantic.ts +100 -14
- package/src/memory/search/staleness.ts +47 -0
- package/src/memory/search/tier-classifier.ts +21 -0
- package/src/memory/search/types.ts +15 -77
- package/src/memory/task-memory-cleanup.ts +4 -6
- package/src/messaging/providers/gmail/mime-builder.ts +17 -7
- package/src/oauth/byo-connection.test.ts +8 -1
- package/src/oauth/oauth-store.ts +113 -27
- package/src/oauth/seed-providers.ts +6 -0
- package/src/oauth/token-persistence.ts +11 -3
- package/src/permissions/defaults.ts +1 -0
- package/src/permissions/trust-store.ts +23 -1
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/prompts/system-prompt.ts +18 -2
- package/src/providers/anthropic/client.ts +56 -126
- package/src/providers/types.ts +7 -1
- package/src/runtime/AGENTS.md +9 -0
- package/src/runtime/auth/route-policy.ts +6 -3
- package/src/runtime/guardian-reply-router.ts +24 -22
- package/src/runtime/http-server.ts +2 -2
- package/src/runtime/invite-redemption-service.ts +19 -1
- package/src/runtime/invite-service.ts +25 -0
- package/src/runtime/pending-interactions.ts +2 -2
- package/src/runtime/routes/brain-graph-routes.ts +10 -90
- package/src/runtime/routes/conversation-routes.ts +9 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
- package/src/runtime/routes/memory-item-routes.test.ts +754 -0
- package/src/runtime/routes/memory-item-routes.ts +503 -0
- package/src/runtime/routes/session-management-routes.ts +3 -3
- package/src/runtime/routes/settings-routes.ts +2 -2
- package/src/runtime/routes/trust-rules-routes.ts +14 -0
- package/src/runtime/routes/workspace-routes.ts +2 -1
- package/src/security/keychain-broker-client.ts +17 -4
- package/src/security/secure-keys.ts +25 -3
- package/src/security/token-manager.ts +36 -36
- package/src/skills/catalog-install.ts +74 -18
- package/src/skills/skillssh-registry.ts +503 -0
- package/src/tools/assets/search.ts +5 -1
- package/src/tools/computer-use/definitions.ts +0 -10
- package/src/tools/computer-use/registry.ts +1 -1
- package/src/tools/credentials/vault.ts +1 -3
- package/src/tools/memory/definitions.ts +4 -13
- package/src/tools/memory/handlers.test.ts +83 -103
- package/src/tools/memory/handlers.ts +50 -85
- package/src/tools/schedule/create.ts +8 -1
- package/src/tools/schedule/update.ts +8 -1
- package/src/tools/skills/load.ts +25 -2
- package/src/__tests__/clarification-resolver.test.ts +0 -193
- package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
- package/src/__tests__/conflict-policy.test.ts +0 -269
- package/src/__tests__/conflict-store.test.ts +0 -372
- package/src/__tests__/contradiction-checker.test.ts +0 -361
- package/src/__tests__/entity-extractor.test.ts +0 -211
- package/src/__tests__/entity-search.test.ts +0 -1117
- package/src/__tests__/profile-compiler.test.ts +0 -392
- package/src/__tests__/session-conflict-gate.test.ts +0 -1228
- package/src/__tests__/session-profile-injection.test.ts +0 -557
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
- package/src/daemon/session-conflict-gate.ts +0 -167
- package/src/daemon/session-dynamic-profile.ts +0 -77
- package/src/memory/clarification-resolver.ts +0 -417
- package/src/memory/conflict-intent.ts +0 -205
- package/src/memory/conflict-policy.ts +0 -127
- package/src/memory/conflict-store.ts +0 -410
- package/src/memory/contradiction-checker.ts +0 -508
- package/src/memory/entity-extractor.ts +0 -535
- package/src/memory/format-recall.ts +0 -47
- package/src/memory/fts-reconciler.ts +0 -165
- package/src/memory/job-handlers/conflict.ts +0 -200
- package/src/memory/profile-compiler.ts +0 -195
- package/src/memory/recall-cache.ts +0 -117
- package/src/memory/search/entity.ts +0 -535
- package/src/memory/search/query-expansion.test.ts +0 -70
- package/src/memory/search/query-expansion.ts +0 -118
- package/src/runtime/routes/mcp-routes.ts +0 -20
|
@@ -5,6 +5,11 @@ import { getLogger } from "../util/logger.js";
|
|
|
5
5
|
|
|
6
6
|
const log = getLogger("qdrant-client");
|
|
7
7
|
|
|
8
|
+
export interface QdrantSparseVector {
|
|
9
|
+
indices: number[];
|
|
10
|
+
values: number[];
|
|
11
|
+
}
|
|
12
|
+
|
|
8
13
|
export interface QdrantClientConfig {
|
|
9
14
|
url: string;
|
|
10
15
|
collection: string;
|
|
@@ -28,7 +33,6 @@ export interface QdrantPointPayload {
|
|
|
28
33
|
conversation_id?: string;
|
|
29
34
|
message_id?: string;
|
|
30
35
|
memory_scope_id?: string;
|
|
31
|
-
entity_ids?: string[];
|
|
32
36
|
modality?: "text" | "image" | "audio" | "video";
|
|
33
37
|
}
|
|
34
38
|
|
|
@@ -79,17 +83,29 @@ export class VellumQdrantClient {
|
|
|
79
83
|
this.embeddingModel = config.embeddingModel;
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
async ensureCollection(): Promise<
|
|
83
|
-
if (this.collectionReady) return;
|
|
86
|
+
async ensureCollection(): Promise<{ migrated: boolean }> {
|
|
87
|
+
if (this.collectionReady) return { migrated: false };
|
|
88
|
+
|
|
89
|
+
let migrated = false;
|
|
84
90
|
|
|
85
91
|
try {
|
|
86
92
|
const exists = await this.client.collectionExists(this.collection);
|
|
87
93
|
if (exists.exists) {
|
|
88
94
|
try {
|
|
89
95
|
const info = await this.client.getCollection(this.collection);
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
)
|
|
96
|
+
const vectorsConfig = info.config?.params?.vectors;
|
|
97
|
+
|
|
98
|
+
// Detect whether the collection uses unnamed vectors (legacy) vs named vectors
|
|
99
|
+
const isUnnamedVectors =
|
|
100
|
+
vectorsConfig != null &&
|
|
101
|
+
typeof vectorsConfig === "object" &&
|
|
102
|
+
"size" in vectorsConfig;
|
|
103
|
+
|
|
104
|
+
const currentSize = isUnnamedVectors
|
|
105
|
+
? (vectorsConfig as { size?: number })?.size
|
|
106
|
+
: (vectorsConfig as Record<string, { size?: number }> | undefined)
|
|
107
|
+
?.dense?.size;
|
|
108
|
+
|
|
93
109
|
const dimMismatch =
|
|
94
110
|
currentSize != null && currentSize !== this.vectorSize;
|
|
95
111
|
|
|
@@ -102,7 +118,19 @@ export class VellumQdrantClient {
|
|
|
102
118
|
}
|
|
103
119
|
}
|
|
104
120
|
|
|
105
|
-
if (
|
|
121
|
+
if (isUnnamedVectors) {
|
|
122
|
+
log.warn(
|
|
123
|
+
{
|
|
124
|
+
collection: this.collection,
|
|
125
|
+
currentSize,
|
|
126
|
+
expectedSize: this.vectorSize,
|
|
127
|
+
},
|
|
128
|
+
"Qdrant collection uses unnamed vectors (legacy) — deleting and recreating with named vectors. Embeddings will be re-indexed.",
|
|
129
|
+
);
|
|
130
|
+
await this.client.deleteCollection(this.collection);
|
|
131
|
+
migrated = true;
|
|
132
|
+
// Fall through to collection creation below
|
|
133
|
+
} else if (dimMismatch || modelMismatch) {
|
|
106
134
|
log.warn(
|
|
107
135
|
{
|
|
108
136
|
collection: this.collection,
|
|
@@ -113,12 +141,13 @@ export class VellumQdrantClient {
|
|
|
113
141
|
"Qdrant collection incompatible (dimension or model change) — deleting and recreating. Embeddings will be regenerated on demand.",
|
|
114
142
|
);
|
|
115
143
|
await this.client.deleteCollection(this.collection);
|
|
144
|
+
migrated = true;
|
|
116
145
|
// Fall through to collection creation below
|
|
117
146
|
} else {
|
|
118
147
|
if (await this.ensurePayloadIndexesSafe()) {
|
|
119
148
|
this.collectionReady = true;
|
|
120
149
|
}
|
|
121
|
-
return;
|
|
150
|
+
return { migrated: false };
|
|
122
151
|
}
|
|
123
152
|
} catch (err) {
|
|
124
153
|
log.warn(
|
|
@@ -128,7 +157,7 @@ export class VellumQdrantClient {
|
|
|
128
157
|
if (await this.ensurePayloadIndexesSafe()) {
|
|
129
158
|
this.collectionReady = true;
|
|
130
159
|
}
|
|
131
|
-
return;
|
|
160
|
+
return { migrated: false };
|
|
132
161
|
}
|
|
133
162
|
}
|
|
134
163
|
} catch {
|
|
@@ -137,15 +166,20 @@ export class VellumQdrantClient {
|
|
|
137
166
|
|
|
138
167
|
log.info(
|
|
139
168
|
{ collection: this.collection, vectorSize: this.vectorSize },
|
|
140
|
-
"Creating Qdrant collection",
|
|
169
|
+
"Creating Qdrant collection with named vectors (dense + sparse)",
|
|
141
170
|
);
|
|
142
171
|
|
|
143
172
|
try {
|
|
144
173
|
await this.client.createCollection(this.collection, {
|
|
145
174
|
vectors: {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
175
|
+
dense: {
|
|
176
|
+
size: this.vectorSize,
|
|
177
|
+
distance: "Cosine",
|
|
178
|
+
on_disk: this.onDisk,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
sparse_vectors: {
|
|
182
|
+
sparse: {}, // Qdrant auto-infers sparse vector params
|
|
149
183
|
},
|
|
150
184
|
hnsw_config: {
|
|
151
185
|
on_disk: this.onDisk,
|
|
@@ -174,7 +208,7 @@ export class VellumQdrantClient {
|
|
|
174
208
|
if (await this.ensurePayloadIndexesSafe()) {
|
|
175
209
|
this.collectionReady = true;
|
|
176
210
|
}
|
|
177
|
-
return;
|
|
211
|
+
return { migrated };
|
|
178
212
|
}
|
|
179
213
|
throw err;
|
|
180
214
|
}
|
|
@@ -191,6 +225,8 @@ export class VellumQdrantClient {
|
|
|
191
225
|
"Qdrant collection created with payload indexes",
|
|
192
226
|
);
|
|
193
227
|
}
|
|
228
|
+
|
|
229
|
+
return { migrated };
|
|
194
230
|
}
|
|
195
231
|
|
|
196
232
|
async upsert(
|
|
@@ -198,6 +234,7 @@ export class VellumQdrantClient {
|
|
|
198
234
|
targetId: string,
|
|
199
235
|
vector: number[],
|
|
200
236
|
payload: Omit<QdrantPointPayload, "target_type" | "target_id">,
|
|
237
|
+
sparseVector?: QdrantSparseVector,
|
|
201
238
|
): Promise<string> {
|
|
202
239
|
await this.ensureCollection();
|
|
203
240
|
|
|
@@ -205,20 +242,33 @@ export class VellumQdrantClient {
|
|
|
205
242
|
const existing = await this.findByTarget(targetType, targetId);
|
|
206
243
|
const pointId = existing ?? uuid();
|
|
207
244
|
|
|
245
|
+
const namedVector: Record<
|
|
246
|
+
string,
|
|
247
|
+
number[] | { indices: number[]; values: number[] }
|
|
248
|
+
> = {
|
|
249
|
+
dense: vector,
|
|
250
|
+
};
|
|
251
|
+
if (sparseVector) {
|
|
252
|
+
namedVector.sparse = {
|
|
253
|
+
indices: sparseVector.indices,
|
|
254
|
+
values: sparseVector.values,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const point = {
|
|
259
|
+
id: pointId,
|
|
260
|
+
vector: namedVector,
|
|
261
|
+
payload: {
|
|
262
|
+
target_type: targetType,
|
|
263
|
+
target_id: targetId,
|
|
264
|
+
...payload,
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
|
|
208
268
|
try {
|
|
209
269
|
await this.client.upsert(this.collection, {
|
|
210
270
|
wait: true,
|
|
211
|
-
points: [
|
|
212
|
-
{
|
|
213
|
-
id: pointId,
|
|
214
|
-
vector,
|
|
215
|
-
payload: {
|
|
216
|
-
target_type: targetType,
|
|
217
|
-
target_id: targetId,
|
|
218
|
-
...payload,
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
],
|
|
271
|
+
points: [point],
|
|
222
272
|
});
|
|
223
273
|
} catch (err) {
|
|
224
274
|
if (this.isCollectionMissing(err)) {
|
|
@@ -226,17 +276,7 @@ export class VellumQdrantClient {
|
|
|
226
276
|
await this.ensureCollection();
|
|
227
277
|
await this.client.upsert(this.collection, {
|
|
228
278
|
wait: true,
|
|
229
|
-
points: [
|
|
230
|
-
{
|
|
231
|
-
id: pointId,
|
|
232
|
-
vector,
|
|
233
|
-
payload: {
|
|
234
|
-
target_type: targetType,
|
|
235
|
-
target_id: targetId,
|
|
236
|
-
...payload,
|
|
237
|
-
},
|
|
238
|
-
},
|
|
239
|
-
],
|
|
279
|
+
points: [point],
|
|
240
280
|
});
|
|
241
281
|
} else {
|
|
242
282
|
throw err;
|
|
@@ -253,26 +293,22 @@ export class VellumQdrantClient {
|
|
|
253
293
|
): Promise<QdrantSearchResult[]> {
|
|
254
294
|
await this.ensureCollection();
|
|
255
295
|
|
|
296
|
+
const searchParams = {
|
|
297
|
+
vector: { name: "dense", vector },
|
|
298
|
+
limit,
|
|
299
|
+
with_payload: true,
|
|
300
|
+
score_threshold: 0.0,
|
|
301
|
+
filter: filter as Parameters<QdrantRestClient["search"]>[1]["filter"],
|
|
302
|
+
};
|
|
303
|
+
|
|
256
304
|
let results;
|
|
257
305
|
try {
|
|
258
|
-
results = await this.client.search(this.collection,
|
|
259
|
-
vector,
|
|
260
|
-
limit,
|
|
261
|
-
with_payload: true,
|
|
262
|
-
score_threshold: 0.0,
|
|
263
|
-
filter: filter as Parameters<QdrantRestClient["search"]>[1]["filter"],
|
|
264
|
-
});
|
|
306
|
+
results = await this.client.search(this.collection, searchParams);
|
|
265
307
|
} catch (err) {
|
|
266
308
|
if (this.isCollectionMissing(err)) {
|
|
267
309
|
this.collectionReady = false;
|
|
268
310
|
await this.ensureCollection();
|
|
269
|
-
results = await this.client.search(this.collection,
|
|
270
|
-
vector,
|
|
271
|
-
limit,
|
|
272
|
-
with_payload: true,
|
|
273
|
-
score_threshold: 0.0,
|
|
274
|
-
filter: filter as Parameters<QdrantRestClient["search"]>[1]["filter"],
|
|
275
|
-
});
|
|
311
|
+
results = await this.client.search(this.collection, searchParams);
|
|
276
312
|
} else {
|
|
277
313
|
throw err;
|
|
278
314
|
}
|
|
@@ -334,6 +370,65 @@ export class VellumQdrantClient {
|
|
|
334
370
|
return this.search(vector, limit, filter);
|
|
335
371
|
}
|
|
336
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Hybrid search using both dense and sparse vectors with RRF fusion.
|
|
375
|
+
* Performs two prefetch queries (dense + sparse) and fuses results
|
|
376
|
+
* using Reciprocal Rank Fusion via Qdrant's query API.
|
|
377
|
+
*/
|
|
378
|
+
async hybridSearch(params: {
|
|
379
|
+
denseVector: number[];
|
|
380
|
+
sparseVector: QdrantSparseVector;
|
|
381
|
+
filter?: object;
|
|
382
|
+
limit: number;
|
|
383
|
+
prefetchLimit?: number;
|
|
384
|
+
}): Promise<QdrantSearchResult[]> {
|
|
385
|
+
await this.ensureCollection();
|
|
386
|
+
|
|
387
|
+
const { denseVector, sparseVector, filter, limit, prefetchLimit } = params;
|
|
388
|
+
const effectivePrefetchLimit = prefetchLimit ?? 40;
|
|
389
|
+
|
|
390
|
+
const queryParams = {
|
|
391
|
+
prefetch: [
|
|
392
|
+
{
|
|
393
|
+
query: denseVector as unknown as number[],
|
|
394
|
+
using: "dense",
|
|
395
|
+
limit: effectivePrefetchLimit,
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
query: {
|
|
399
|
+
indices: sparseVector.indices,
|
|
400
|
+
values: sparseVector.values,
|
|
401
|
+
},
|
|
402
|
+
using: "sparse",
|
|
403
|
+
limit: effectivePrefetchLimit,
|
|
404
|
+
},
|
|
405
|
+
],
|
|
406
|
+
query: { fusion: "rrf" as const },
|
|
407
|
+
limit,
|
|
408
|
+
filter: filter as Record<string, unknown> | undefined,
|
|
409
|
+
with_payload: true,
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
let results;
|
|
413
|
+
try {
|
|
414
|
+
results = await this.client.query(this.collection, queryParams);
|
|
415
|
+
} catch (err) {
|
|
416
|
+
if (this.isCollectionMissing(err)) {
|
|
417
|
+
this.collectionReady = false;
|
|
418
|
+
await this.ensureCollection();
|
|
419
|
+
results = await this.client.query(this.collection, queryParams);
|
|
420
|
+
} else {
|
|
421
|
+
throw err;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return (results.points ?? []).map((point) => ({
|
|
426
|
+
id: typeof point.id === "string" ? point.id : String(point.id),
|
|
427
|
+
score: point.score ?? 0,
|
|
428
|
+
payload: point.payload as unknown as QdrantPointPayload,
|
|
429
|
+
}));
|
|
430
|
+
}
|
|
431
|
+
|
|
337
432
|
async deleteByTarget(targetType: string, targetId: string): Promise<void> {
|
|
338
433
|
await this.ensureCollection();
|
|
339
434
|
|
|
@@ -492,7 +587,9 @@ export class VellumQdrantClient {
|
|
|
492
587
|
points: [
|
|
493
588
|
{
|
|
494
589
|
id: this.SENTINEL_ID,
|
|
495
|
-
vector:
|
|
590
|
+
vector: {
|
|
591
|
+
dense: new Array(this.vectorSize).fill(0), // zero vector, never matched in search
|
|
592
|
+
},
|
|
496
593
|
payload: { _meta: true, embedding_model: model },
|
|
497
594
|
},
|
|
498
595
|
],
|
package/src/memory/raw-query.ts
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* use Drizzle's `sql` template, but raw SQL is acceptable when simpler.
|
|
25
25
|
*
|
|
26
26
|
* - **Bulk deletes across virtual tables**: Operations like clearing
|
|
27
|
-
*
|
|
27
|
+
* messages_fts that reference virtual tables not modeled in Drizzle.
|
|
28
28
|
*
|
|
29
29
|
* For everything else — selects, inserts, updates, deletes, joins, aggregations,
|
|
30
30
|
* filtering, ordering, pagination — use Drizzle.
|