@semiont/vectors 0.5.26 → 0.5.27
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 +4 -6
- package/dist/{chunk-LBAPGZOW.js → chunk-GWXB645H.js} +18 -11
- package/dist/chunk-GWXB645H.js.map +1 -0
- package/dist/{chunk-UM3RNDW4.js → chunk-PJ72DF6E.js} +18 -12
- package/dist/chunk-PJ72DF6E.js.map +1 -0
- package/dist/{chunk-Q2LGLRYN.js → chunk-Q7XXWZRC.js} +51 -48
- package/dist/chunk-Q7XXWZRC.js.map +1 -0
- package/dist/index.d.ts +63 -7
- package/dist/index.js +14 -32
- package/dist/index.js.map +1 -1
- package/dist/ollama-GGIIWEBW.js +3 -0
- package/dist/ollama-GGIIWEBW.js.map +1 -0
- package/dist/qdrant-JMDT7ZI5.js +3 -0
- package/dist/qdrant-JMDT7ZI5.js.map +1 -0
- package/dist/testing.d.ts +57 -0
- package/dist/testing.js +44 -0
- package/dist/testing.js.map +1 -0
- package/dist/voyage-MQMTWUMO.js +3 -0
- package/dist/voyage-MQMTWUMO.js.map +1 -0
- package/package.json +7 -2
- package/dist/chunk-LBAPGZOW.js.map +0 -1
- package/dist/chunk-Q2LGLRYN.js.map +0 -1
- package/dist/chunk-UM3RNDW4.js.map +0 -1
- package/dist/ollama-H62PXJ5D.js +0 -7
- package/dist/ollama-H62PXJ5D.js.map +0 -1
- package/dist/qdrant-GNSEAGLI.js +0 -7
- package/dist/qdrant-GNSEAGLI.js.map +0 -1
- package/dist/voyage-NUSVXNJN.js +0 -7
- package/dist/voyage-NUSVXNJN.js.map +0 -1
package/README.md
CHANGED
|
@@ -43,6 +43,8 @@ Brute-force cosine similarity. No external dependencies.
|
|
|
43
43
|
|
|
44
44
|
## Embedding Providers
|
|
45
45
|
|
|
46
|
+
Vector dimensionality is intrinsic to the embedding model, so it is discovered from the provider itself — `await provider.dimensions()` embeds a probe string once per instance and measures it. There is no hand-maintained model→width table: any model the provider serves works, and an unreachable provider fails loudly instead of yielding a wrong-width index.
|
|
47
|
+
|
|
46
48
|
### Voyage AI (cloud)
|
|
47
49
|
|
|
48
50
|
```typescript
|
|
@@ -50,25 +52,21 @@ import { createEmbeddingProvider } from '@semiont/vectors';
|
|
|
50
52
|
|
|
51
53
|
const provider = await createEmbeddingProvider({
|
|
52
54
|
type: 'voyage',
|
|
53
|
-
model: 'voyage-3',
|
|
55
|
+
model: 'voyage-3',
|
|
54
56
|
apiKey: '...',
|
|
55
57
|
});
|
|
56
58
|
```
|
|
57
59
|
|
|
58
|
-
Models: `voyage-3` (1024), `voyage-3-lite` (512), `voyage-code-3`, `voyage-finance-2`, `voyage-law-2`.
|
|
59
|
-
|
|
60
60
|
### Ollama (local)
|
|
61
61
|
|
|
62
62
|
```typescript
|
|
63
63
|
const provider = await createEmbeddingProvider({
|
|
64
64
|
type: 'ollama',
|
|
65
|
-
model: 'nomic-embed-text',
|
|
65
|
+
model: 'nomic-embed-text',
|
|
66
66
|
baseURL: 'http://localhost:11434',
|
|
67
67
|
});
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
Models: `nomic-embed-text` (768), `all-minilm` (384), `mxbai-embed-large` (1024), `snowflake-arctic-embed` (1024).
|
|
71
|
-
|
|
72
70
|
## Text Chunking
|
|
73
71
|
|
|
74
72
|
```typescript
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
// src/embedding/ollama.ts
|
|
2
|
-
var OLLAMA_DIMENSIONS = {
|
|
3
|
-
"nomic-embed-text": 768,
|
|
4
|
-
"all-minilm": 384,
|
|
5
|
-
"mxbai-embed-large": 1024,
|
|
6
|
-
"snowflake-arctic-embed": 1024
|
|
7
|
-
};
|
|
8
2
|
var OllamaEmbeddingProvider = class {
|
|
9
3
|
config;
|
|
4
|
+
dimensionsPromise;
|
|
10
5
|
constructor(config) {
|
|
11
6
|
this.config = config;
|
|
12
7
|
}
|
|
@@ -45,14 +40,26 @@ var OllamaEmbeddingProvider = class {
|
|
|
45
40
|
return json.embeddings;
|
|
46
41
|
}
|
|
47
42
|
dimensions() {
|
|
48
|
-
|
|
43
|
+
if (!this.dimensionsPromise) {
|
|
44
|
+
this.dimensionsPromise = this.measureDimensions().catch((err) => {
|
|
45
|
+
this.dimensionsPromise = void 0;
|
|
46
|
+
throw err;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return this.dimensionsPromise;
|
|
50
|
+
}
|
|
51
|
+
async measureDimensions() {
|
|
52
|
+
const probe = await this.embed("dimension probe");
|
|
53
|
+
if (!Array.isArray(probe) || probe.length === 0) {
|
|
54
|
+
throw new Error(`Ollama returned no embedding for dimension probe of model '${this.config.model}'`);
|
|
55
|
+
}
|
|
56
|
+
return probe.length;
|
|
49
57
|
}
|
|
50
58
|
model() {
|
|
51
59
|
return this.config.model;
|
|
52
60
|
}
|
|
53
61
|
};
|
|
54
62
|
|
|
55
|
-
export {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//# sourceMappingURL=chunk-LBAPGZOW.js.map
|
|
63
|
+
export { OllamaEmbeddingProvider };
|
|
64
|
+
//# sourceMappingURL=chunk-GWXB645H.js.map
|
|
65
|
+
//# sourceMappingURL=chunk-GWXB645H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/embedding/ollama.ts"],"names":[],"mappings":"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","file":"chunk-GWXB645H.js","sourcesContent":["/**\n * Ollama Embedding Provider\n *\n * Local embedding via the Ollama API.\n * Uses models like nomic-embed-text, all-minilm, etc.\n */\n\nimport type { EmbeddingProvider } from './interface';\n\nexport interface OllamaEmbeddingConfig {\n model: string;\n baseURL?: string;\n}\n\nexport class OllamaEmbeddingProvider implements EmbeddingProvider {\n private config: OllamaEmbeddingConfig;\n private dimensionsPromise?: Promise<number>;\n\n constructor(config: OllamaEmbeddingConfig) {\n this.config = config;\n }\n\n async embed(text: string): Promise<number[]> {\n const baseURL = this.config.baseURL ?? 'http://localhost:11434';\n\n const response = await fetch(`${baseURL}/api/embed`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.config.model,\n input: text,\n }),\n });\n\n if (!response.ok) {\n const body = await response.text();\n throw new Error(`Ollama embed error ${response.status}: ${body}`);\n }\n\n const json = await response.json() as { embeddings: number[][] };\n return json.embeddings[0];\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n // Ollama's /api/embed supports batch input\n const baseURL = this.config.baseURL ?? 'http://localhost:11434';\n\n const response = await fetch(`${baseURL}/api/embed`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.config.model,\n input: texts,\n }),\n });\n\n if (!response.ok) {\n const body = await response.text();\n throw new Error(`Ollama embed error ${response.status}: ${body}`);\n }\n\n const json = await response.json() as { embeddings: number[][] };\n return json.embeddings;\n }\n\n dimensions(): Promise<number> {\n if (!this.dimensionsPromise) {\n this.dimensionsPromise = this.measureDimensions().catch((err: unknown) => {\n // Never cache a failed discovery — a transient outage would otherwise\n // pin every future call to the same rejection.\n this.dimensionsPromise = undefined;\n throw err;\n });\n }\n return this.dimensionsPromise;\n }\n\n private async measureDimensions(): Promise<number> {\n // Dimensionality is intrinsic to the model, so the model is the\n // authority: embed a probe and measure it. A hand-maintained table goes\n // stale the day a new model ships and silently mis-sizes the index.\n const probe = await this.embed('dimension probe');\n if (!Array.isArray(probe) || probe.length === 0) {\n throw new Error(`Ollama returned no embedding for dimension probe of model '${this.config.model}'`);\n }\n return probe.length;\n }\n\n model(): string {\n return this.config.model;\n }\n}\n"]}
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
// src/embedding/voyage.ts
|
|
2
|
-
var VOYAGE_DIMENSIONS = {
|
|
3
|
-
"voyage-3": 1024,
|
|
4
|
-
"voyage-3-lite": 512,
|
|
5
|
-
"voyage-code-3": 1024,
|
|
6
|
-
"voyage-finance-2": 1024,
|
|
7
|
-
"voyage-law-2": 1024
|
|
8
|
-
};
|
|
9
2
|
var VoyageEmbeddingProvider = class {
|
|
10
3
|
config;
|
|
4
|
+
dimensionsPromise;
|
|
11
5
|
constructor(config) {
|
|
12
6
|
this.config = config;
|
|
13
7
|
}
|
|
@@ -36,14 +30,26 @@ var VoyageEmbeddingProvider = class {
|
|
|
36
30
|
return json.data.map((d) => d.embedding);
|
|
37
31
|
}
|
|
38
32
|
dimensions() {
|
|
39
|
-
|
|
33
|
+
if (!this.dimensionsPromise) {
|
|
34
|
+
this.dimensionsPromise = this.measureDimensions().catch((err) => {
|
|
35
|
+
this.dimensionsPromise = void 0;
|
|
36
|
+
throw err;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return this.dimensionsPromise;
|
|
40
|
+
}
|
|
41
|
+
async measureDimensions() {
|
|
42
|
+
const probe = await this.embed("dimension probe");
|
|
43
|
+
if (!Array.isArray(probe) || probe.length === 0) {
|
|
44
|
+
throw new Error(`Voyage returned no embedding for dimension probe of model '${this.config.model}'`);
|
|
45
|
+
}
|
|
46
|
+
return probe.length;
|
|
40
47
|
}
|
|
41
48
|
model() {
|
|
42
49
|
return this.config.model;
|
|
43
50
|
}
|
|
44
51
|
};
|
|
45
52
|
|
|
46
|
-
export {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
//# sourceMappingURL=chunk-UM3RNDW4.js.map
|
|
53
|
+
export { VoyageEmbeddingProvider };
|
|
54
|
+
//# sourceMappingURL=chunk-PJ72DF6E.js.map
|
|
55
|
+
//# sourceMappingURL=chunk-PJ72DF6E.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/embedding/voyage.ts"],"names":[],"mappings":";AAeO,IAAM,0BAAN,MAA2D;AAAA,EACxD,MAAA;AAAA,EACA,iBAAA;AAAA,EAER,YAAY,MAAA,EAAsB;AAChC,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA,EAEA,MAAM,MAAM,IAAA,EAAiC;AAC3C,IAAA,MAAM,UAAU,MAAM,IAAA,CAAK,UAAA,CAAW,CAAC,IAAI,CAAC,CAAA;AAC5C,IAAA,OAAO,QAAQ,CAAC,CAAA;AAAA,EAClB;AAAA,EAEA,MAAM,WAAW,KAAA,EAAsC;AACrD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,QAAA,IAAY,wCAAA;AAEzC,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,QAAA,EAAU;AAAA,MACrC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA;AAAA,OAC/C;AAAA,MACA,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,QACnB,KAAA,EAAO,KAAK,MAAA,CAAO,KAAA;AAAA,QACnB,KAAA,EAAO;AAAA,OACR;AAAA,KACF,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,SAAS,MAAM,CAAA,EAAA,EAAK,IAAI,CAAA,CAAE,CAAA;AAAA,IAChE;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,SAAS,CAAA;AAAA,EACvC;AAAA,EAEA,UAAA,GAA8B;AAC5B,IAAA,IAAI,CAAC,KAAK,iBAAA,EAAmB;AAC3B,MAAA,IAAA,CAAK,oBAAoB,IAAA,CAAK,iBAAA,EAAkB,CAAE,KAAA,CAAM,CAAC,GAAA,KAAiB;AAGxE,QAAA,IAAA,CAAK,iBAAA,GAAoB,MAAA;AACzB,QAAA,MAAM,GAAA;AAAA,MACR,CAAC,CAAA;AAAA,IACH;AACA,IAAA,OAAO,IAAA,CAAK,iBAAA;AAAA,EACd;AAAA,EAEA,MAAc,iBAAA,GAAqC;AAIjD,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,KAAA,CAAM,iBAAiB,CAAA;AAChD,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,IAAK,KAAA,CAAM,WAAW,CAAA,EAAG;AAC/C,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2DAAA,EAA8D,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA,CAAA,CAAG,CAAA;AAAA,IACpG;AACA,IAAA,OAAO,KAAA,CAAM,MAAA;AAAA,EACf;AAAA,EAEA,KAAA,GAAgB;AACd,IAAA,OAAO,KAAK,MAAA,CAAO,KAAA;AAAA,EACrB;AACF","file":"chunk-PJ72DF6E.js","sourcesContent":["/**\n * Voyage AI Embedding Provider\n *\n * Cloud embedding via the Voyage AI API.\n * Requires a Voyage AI API key (distinct from Anthropic inference keys).\n */\n\nimport type { EmbeddingProvider } from './interface';\n\nexport interface VoyageConfig {\n apiKey: string;\n model: string;\n endpoint?: string;\n}\n\nexport class VoyageEmbeddingProvider implements EmbeddingProvider {\n private config: VoyageConfig;\n private dimensionsPromise?: Promise<number>;\n\n constructor(config: VoyageConfig) {\n this.config = config;\n }\n\n async embed(text: string): Promise<number[]> {\n const results = await this.embedBatch([text]);\n return results[0];\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n const endpoint = this.config.endpoint ?? 'https://api.voyageai.com/v1/embeddings';\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n model: this.config.model,\n input: texts,\n }),\n });\n\n if (!response.ok) {\n const body = await response.text();\n throw new Error(`Voyage API error ${response.status}: ${body}`);\n }\n\n const json = await response.json() as { data: Array<{ embedding: number[] }> };\n return json.data.map(d => d.embedding);\n }\n\n dimensions(): Promise<number> {\n if (!this.dimensionsPromise) {\n this.dimensionsPromise = this.measureDimensions().catch((err: unknown) => {\n // Never cache a failed discovery — a transient outage would otherwise\n // pin every future call to the same rejection.\n this.dimensionsPromise = undefined;\n throw err;\n });\n }\n return this.dimensionsPromise;\n }\n\n private async measureDimensions(): Promise<number> {\n // Dimensionality is intrinsic to the model, so the model is the\n // authority: embed a probe and measure it. A hand-maintained table goes\n // stale the day a new model ships and silently mis-sizes the index.\n const probe = await this.embed('dimension probe');\n if (!Array.isArray(probe) || probe.length === 0) {\n throw new Error(`Voyage returned no embedding for dimension probe of model '${this.config.model}'`);\n }\n return probe.length;\n }\n\n model(): string {\n return this.config.model;\n }\n}\n"]}
|
|
@@ -1,9 +1,35 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
|
|
3
|
+
// src/store/qdrant.ts
|
|
4
|
+
|
|
5
|
+
// src/store/merge.ts
|
|
6
|
+
function mergeByResource(hits) {
|
|
7
|
+
const bestByResource = /* @__PURE__ */ new Map();
|
|
8
|
+
for (const hit of hits) {
|
|
9
|
+
const key = String(hit.resourceId);
|
|
10
|
+
const prev = bestByResource.get(key);
|
|
11
|
+
if (!prev || hit.score > prev.score) bestByResource.set(key, hit);
|
|
12
|
+
}
|
|
13
|
+
return [...bestByResource.values()].sort((a, b) => b.score - a.score);
|
|
14
|
+
}
|
|
15
|
+
|
|
1
16
|
// src/store/qdrant.ts
|
|
2
|
-
import { createHash } from "crypto";
|
|
3
17
|
function toQdrantId(input) {
|
|
4
18
|
const hex = createHash("md5").update(input).digest("hex");
|
|
5
19
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
6
20
|
}
|
|
21
|
+
function toSearchResult(point) {
|
|
22
|
+
const payload = point.payload ?? {};
|
|
23
|
+
return {
|
|
24
|
+
id: String(point.id),
|
|
25
|
+
score: point.score,
|
|
26
|
+
resourceId: payload.resourceId,
|
|
27
|
+
annotationId: payload.annotationId,
|
|
28
|
+
text: payload.text,
|
|
29
|
+
entityTypes: payload.entityTypes,
|
|
30
|
+
...payload.machineRead ? { machineRead: true } : {}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
7
33
|
var STAMP_FIELDS = ["resourceId", "contentChecksum", "entityTypes", "machineRead"];
|
|
8
34
|
function toStamp(payload) {
|
|
9
35
|
const checksum = payload?.contentChecksum;
|
|
@@ -14,7 +40,13 @@ function toStamp(payload) {
|
|
|
14
40
|
...payload?.machineRead ? { machineRead: true } : {}
|
|
15
41
|
};
|
|
16
42
|
}
|
|
17
|
-
var QdrantVectorStore = class {
|
|
43
|
+
var QdrantVectorStore = class _QdrantVectorStore {
|
|
44
|
+
/**
|
|
45
|
+
* Per-batch point over-fetch for `searchByResource`. The batch limit caps
|
|
46
|
+
* points while the caller wants resources, so multi-chunk targets would
|
|
47
|
+
* otherwise crowd the top-K. See the call site.
|
|
48
|
+
*/
|
|
49
|
+
static SEARCH_BY_RESOURCE_OVER_FETCH = 4;
|
|
18
50
|
client = null;
|
|
19
51
|
config;
|
|
20
52
|
constructor(config) {
|
|
@@ -25,13 +57,13 @@ var QdrantVectorStore = class {
|
|
|
25
57
|
return this.client;
|
|
26
58
|
}
|
|
27
59
|
async connect() {
|
|
28
|
-
const { QdrantClient } = await import(
|
|
60
|
+
const { QdrantClient } = await import('@qdrant/js-client-rest');
|
|
29
61
|
this.client = new QdrantClient({
|
|
30
62
|
host: this.config.host,
|
|
31
63
|
port: this.config.port
|
|
32
64
|
});
|
|
33
|
-
await this.ensureCollection("resources"
|
|
34
|
-
await this.ensureCollection("annotations"
|
|
65
|
+
await this.ensureCollection("resources");
|
|
66
|
+
await this.ensureCollection("annotations");
|
|
35
67
|
await this.ensurePayloadIndex("resources", "entityTypes");
|
|
36
68
|
await this.ensurePayloadIndex("resources", "resourceId");
|
|
37
69
|
await this.ensurePayloadIndex("annotations", "resourceId");
|
|
@@ -48,20 +80,21 @@ var QdrantVectorStore = class {
|
|
|
48
80
|
await this.qdrant.deleteCollection("annotations");
|
|
49
81
|
} catch {
|
|
50
82
|
}
|
|
51
|
-
await this.ensureCollection("resources"
|
|
52
|
-
await this.ensureCollection("annotations"
|
|
83
|
+
await this.ensureCollection("resources");
|
|
84
|
+
await this.ensureCollection("annotations");
|
|
53
85
|
}
|
|
54
86
|
isConnected() {
|
|
55
87
|
return this.client !== null;
|
|
56
88
|
}
|
|
57
|
-
async ensureCollection(name
|
|
89
|
+
async ensureCollection(name) {
|
|
58
90
|
try {
|
|
59
91
|
await this.qdrant.getCollection(name);
|
|
92
|
+
return;
|
|
60
93
|
} catch {
|
|
61
|
-
await this.qdrant.createCollection(name, {
|
|
62
|
-
vectors: { size: dimensions, distance: "Cosine" }
|
|
63
|
-
});
|
|
64
94
|
}
|
|
95
|
+
await this.qdrant.createCollection(name, {
|
|
96
|
+
vectors: { size: await this.config.dimensions(), distance: "Cosine" }
|
|
97
|
+
});
|
|
65
98
|
}
|
|
66
99
|
/**
|
|
67
100
|
* Idempotently create a keyword payload index. Qdrant accepts a repeat call
|
|
@@ -220,32 +253,14 @@ var QdrantVectorStore = class {
|
|
|
220
253
|
const filter = this.buildFilter({ ...opts.filter, excludeResourceId: resourceId });
|
|
221
254
|
const searches = queryVectors.map((vector) => ({
|
|
222
255
|
query: vector,
|
|
223
|
-
limit: opts.limit,
|
|
256
|
+
limit: opts.limit * _QdrantVectorStore.SEARCH_BY_RESOURCE_OVER_FETCH,
|
|
224
257
|
score_threshold: opts.scoreThreshold,
|
|
225
258
|
filter: filter ?? void 0,
|
|
226
259
|
with_payload: true
|
|
227
260
|
}));
|
|
228
261
|
const batches = await this.qdrant.queryBatch("resources", { searches });
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
for (const r of batch.points) {
|
|
232
|
-
const payload = r.payload ?? {};
|
|
233
|
-
const tid = String(payload.resourceId);
|
|
234
|
-
const prev = bestByResource.get(tid);
|
|
235
|
-
if (!prev || r.score > prev.score) {
|
|
236
|
-
bestByResource.set(tid, { id: String(r.id), score: r.score, payload });
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
return [...bestByResource.values()].sort((a, b) => b.score - a.score).slice(0, opts.limit).map((m) => ({
|
|
241
|
-
id: m.id,
|
|
242
|
-
score: m.score,
|
|
243
|
-
resourceId: m.payload.resourceId,
|
|
244
|
-
annotationId: m.payload.annotationId,
|
|
245
|
-
text: m.payload.text,
|
|
246
|
-
entityTypes: m.payload.entityTypes,
|
|
247
|
-
...m.payload.machineRead ? { machineRead: true } : {}
|
|
248
|
-
}));
|
|
262
|
+
const hits = batches.flatMap((batch) => batch.points.map((r) => toSearchResult(r)));
|
|
263
|
+
return mergeByResource(hits).slice(0, opts.limit);
|
|
249
264
|
}
|
|
250
265
|
async search(collection, embedding, opts) {
|
|
251
266
|
const filter = this.buildFilter(opts.filter);
|
|
@@ -256,18 +271,7 @@ var QdrantVectorStore = class {
|
|
|
256
271
|
filter: filter ?? void 0,
|
|
257
272
|
with_payload: true
|
|
258
273
|
});
|
|
259
|
-
return points.map((r) =>
|
|
260
|
-
const payload = r.payload ?? {};
|
|
261
|
-
return {
|
|
262
|
-
id: String(r.id),
|
|
263
|
-
score: r.score,
|
|
264
|
-
resourceId: payload.resourceId,
|
|
265
|
-
annotationId: payload.annotationId,
|
|
266
|
-
text: payload.text,
|
|
267
|
-
entityTypes: payload.entityTypes,
|
|
268
|
-
...payload.machineRead ? { machineRead: true } : {}
|
|
269
|
-
};
|
|
270
|
-
});
|
|
274
|
+
return points.map((r) => toSearchResult(r));
|
|
271
275
|
}
|
|
272
276
|
buildFilter(filter) {
|
|
273
277
|
if (!filter) return null;
|
|
@@ -296,7 +300,6 @@ var QdrantVectorStore = class {
|
|
|
296
300
|
}
|
|
297
301
|
};
|
|
298
302
|
|
|
299
|
-
export {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
//# sourceMappingURL=chunk-Q2LGLRYN.js.map
|
|
303
|
+
export { QdrantVectorStore, mergeByResource };
|
|
304
|
+
//# sourceMappingURL=chunk-Q7XXWZRC.js.map
|
|
305
|
+
//# sourceMappingURL=chunk-Q7XXWZRC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/store/merge.ts","../src/store/qdrant.ts"],"names":[],"mappings":"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","file":"chunk-Q7XXWZRC.js","sourcesContent":["/**\n * Chunk→resource max-sim merge.\n *\n * Vector search returns *chunk*-level hits: one resource can match on several\n * of its chunks, and a caller that wants a list of resources has to fold them.\n * The fold is max-sim (late interaction): a resource scores as its single\n * best-matching chunk, and carries that chunk's text — so the caller can show\n * the passage that actually matched. Averaging instead would blur a\n * multi-topic resource into a vague centroid and lose which passage hit;\n * keeping the first hit seen would make the result order-dependent.\n *\n * Three callers share this: both `searchByResource` implementations (qdrant\n * batches one query per source chunk; memory scores every candidate against\n * every source chunk) and the SEMANTIC-FALLBACK fold over raw `searchResources`\n * output, whose hits map one-to-one with no dedup. All three normalise to\n * `VectorSearchResult[]` first, so this fold is the only copy of the logic.\n *\n * Deliberately does NOT slice to a limit: `searchByResource` and the fallback\n * want different slices, and a fold that silently truncates is the kind of\n * hidden cap that reads as \"covered everything\" when it didn't.\n */\n\nimport type { VectorSearchResult } from './interface';\n\n/**\n * Fold chunk-level hits to one entry per resource — the highest-scoring chunk\n * wins, carrying its own text and metadata — sorted score-descending.\n */\nexport function mergeByResource(hits: VectorSearchResult[]): VectorSearchResult[] {\n const bestByResource = new Map<string, VectorSearchResult>();\n\n for (const hit of hits) {\n const key = String(hit.resourceId);\n const prev = bestByResource.get(key);\n if (!prev || hit.score > prev.score) bestByResource.set(key, hit);\n }\n\n return [...bestByResource.values()].sort((a, b) => b.score - a.score);\n}\n","/**\n * Qdrant VectorStore Implementation\n *\n * Uses the Qdrant REST API via @qdrant/js-client-rest.\n * Manages two collections: 'resources' and 'annotations'.\n */\n\nimport { createHash } from 'crypto';\nimport type { QdrantClient, Schemas } from '@qdrant/js-client-rest';\nimport type { ResourceId, AnnotationId } from '@semiont/core';\nimport type { VectorStore, EmbeddingChunk, AnnotationPayload, VectorSearchResult, SearchOptions, ResourceStamp } from './interface';\nimport { mergeByResource } from './merge';\n\n/**\n * Generate a deterministic UUID v5-style ID from an arbitrary string.\n * Qdrant requires point IDs to be UUIDs or unsigned integers.\n */\nfunction toQdrantId(input: string): string {\n const hex = createHash('md5').update(input).digest('hex');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;\n}\n\n/**\n * Map a scored point to the store-agnostic result shape. Shared by every read\n * path so the payload→result contract (including `machineRead`) has one home.\n */\nfunction toSearchResult(point: Schemas['ScoredPoint']): VectorSearchResult {\n const payload = point.payload ?? {};\n return {\n id: String(point.id),\n score: point.score,\n resourceId: payload.resourceId as ResourceId,\n annotationId: payload.annotationId as AnnotationId | undefined,\n text: payload.text as string,\n entityTypes: payload.entityTypes as string[] | undefined,\n ...(payload.machineRead ? { machineRead: true } : {}),\n };\n}\n\nexport interface QdrantConfig {\n host: string;\n port: number;\n /** Resolves the embedding dimensionality; called only when creating a collection. */\n dimensions: () => Promise<number>;\n}\n\n/** The payload fields a stamp is read from — one list for the scroll and the\n * targeted read, so the two cannot drift. */\nconst STAMP_FIELDS = ['resourceId', 'contentChecksum', 'entityTypes', 'machineRead'];\n\nfunction toStamp(payload: Record<string, unknown> | null | undefined): ResourceStamp {\n const checksum = payload?.contentChecksum;\n const entityTypes = payload?.entityTypes;\n return {\n contentChecksum: typeof checksum === 'string' ? checksum : undefined,\n entityTypes: Array.isArray(entityTypes)\n ? entityTypes.filter((t): t is string => typeof t === 'string')\n : [],\n ...(payload?.machineRead ? { machineRead: true } : {}),\n };\n}\n\nexport class QdrantVectorStore implements VectorStore {\n /**\n * Per-batch point over-fetch for `searchByResource`. The batch limit caps\n * points while the caller wants resources, so multi-chunk targets would\n * otherwise crowd the top-K. See the call site.\n */\n private static readonly SEARCH_BY_RESOURCE_OVER_FETCH = 4;\n\n private client: QdrantClient | null = null;\n private config: QdrantConfig;\n\n constructor(config: QdrantConfig) {\n this.config = config;\n }\n\n private get qdrant(): QdrantClient {\n if (!this.client) throw new Error('QdrantVectorStore is not connected');\n return this.client;\n }\n\n async connect(): Promise<void> {\n const { QdrantClient } = await import('@qdrant/js-client-rest');\n this.client = new QdrantClient({\n host: this.config.host,\n port: this.config.port,\n });\n\n // Ensure collections exist\n await this.ensureCollection('resources');\n await this.ensureCollection('annotations');\n // Payload indexes so filtered operations scale:\n // - entityTypes: the excludeEntityTypes recall filter.\n // - resourceId: searchByResource's by-resource scroll + self-exclusion, and\n // the per-resource delete paths (deleteResourceVectors /\n // deleteAnnotationVectorsForResource).\n await this.ensurePayloadIndex('resources', 'entityTypes');\n await this.ensurePayloadIndex('resources', 'resourceId');\n await this.ensurePayloadIndex('annotations', 'resourceId');\n }\n\n async disconnect(): Promise<void> {\n this.client = null;\n }\n\n async clearAll(): Promise<void> {\n try { await this.qdrant.deleteCollection('resources'); } catch { /* may not exist */ }\n try { await this.qdrant.deleteCollection('annotations'); } catch { /* may not exist */ }\n await this.ensureCollection('resources');\n await this.ensureCollection('annotations');\n }\n\n isConnected(): boolean {\n return this.client !== null;\n }\n\n private async ensureCollection(name: string): Promise<void> {\n try {\n await this.qdrant.getCollection(name);\n return;\n } catch { /* absent — create it below, which is the only path needing the size */ }\n\n // The dimensionality is discovered from the embedding provider, so it is\n // resolved HERE and nowhere else: an existing collection already encodes\n // its vector size, and consulting the provider to re-derive a number we\n // would not use is exactly the eager-probe coupling this avoids.\n await this.qdrant.createCollection(name, {\n vectors: { size: await this.config.dimensions(), distance: 'Cosine' },\n });\n }\n\n /**\n * Idempotently create a keyword payload index. Qdrant accepts a repeat call\n * for an already-indexed field, so this runs safely on every connect and\n * back-fills the index on collections created before the field was indexed.\n */\n private async ensurePayloadIndex(collection: string, field: string): Promise<void> {\n try {\n await this.qdrant.createPayloadIndex(collection, { field_name: field, field_schema: 'keyword' });\n } catch { /* already indexed, or created concurrently */ }\n }\n\n async upsertResourceVectors(resourceId: ResourceId, chunks: EmbeddingChunk[], contentChecksum: string, entityTypes: string[], machineRead?: boolean): Promise<void> {\n // Replace semantics: purge existing chunks first, or a resource that\n // shrinks leaves orphan points at the higher chunk indices.\n await this.deleteResourceVectors(resourceId);\n if (chunks.length === 0) return;\n\n const points = chunks.map((chunk) => ({\n id: toQdrantId(`${resourceId}-${chunk.chunkIndex}`),\n vector: chunk.embedding,\n payload: {\n resourceId: String(resourceId),\n chunkIndex: chunk.chunkIndex,\n text: chunk.text,\n contentChecksum,\n entityTypes,\n // Only stamped when true: absence is the common case and carries no\n // claim, so a native extraction stores nothing extra.\n ...(machineRead ? { machineRead: true } : {}),\n },\n }));\n\n await this.qdrant.upsert('resources', { points });\n }\n\n async upsertAnnotationVector(\n annotationId: AnnotationId,\n embedding: number[],\n payload: AnnotationPayload\n ): Promise<void> {\n await this.qdrant.upsert('annotations', {\n points: [{\n id: toQdrantId(String(annotationId)),\n vector: embedding,\n payload: {\n annotationId: String(payload.annotationId),\n resourceId: String(payload.resourceId),\n motivation: payload.motivation,\n entityTypes: payload.entityTypes,\n text: payload.exactText,\n ...(payload.machineRead ? { machineRead: true } : {}),\n },\n }],\n });\n }\n\n async deleteResourceVectors(resourceId: ResourceId): Promise<void> {\n await this.qdrant.delete('resources', {\n filter: {\n must: [{ key: 'resourceId', match: { value: String(resourceId) } }],\n },\n });\n }\n\n async deleteAnnotationVector(annotationId: AnnotationId): Promise<void> {\n await this.qdrant.delete('annotations', {\n points: [toQdrantId(String(annotationId))],\n });\n }\n\n async deleteAnnotationVectorsForResource(resourceId: ResourceId): Promise<void> {\n await this.qdrant.delete('annotations', {\n filter: {\n must: [{ key: 'resourceId', match: { value: String(resourceId) } }],\n },\n });\n }\n\n async count(): Promise<number> {\n const [resources, annotations] = await Promise.all([\n this.qdrant.count('resources', { exact: true }),\n this.qdrant.count('annotations', { exact: true }),\n ]);\n return resources.count + annotations.count;\n }\n\n async updateResourceEntityTypes(resourceId: ResourceId, entityTypes: string[]): Promise<void> {\n // Payload-only rewrite across the resource's points — no vectors touched,\n // no embedding involved (S13). Qdrant set_payload with a filter is a\n // no-op when the resource has no points.\n await this.qdrant.setPayload('resources', {\n payload: { entityTypes },\n filter: {\n must: [{ key: 'resourceId', match: { value: String(resourceId) } }],\n },\n });\n }\n\n async getResourceStamp(resourceId: ResourceId): Promise<ResourceStamp | undefined> {\n const page = await this.qdrant.scroll('resources', {\n limit: 1,\n filter: { must: [{ key: 'resourceId', match: { value: String(resourceId) } }] },\n with_payload: STAMP_FIELDS,\n with_vector: false,\n });\n const point = page.points[0];\n return point ? toStamp(point.payload) : undefined;\n }\n\n async listResourceStamps(): Promise<Map<string, ResourceStamp>> {\n const stamps = new Map<string, ResourceStamp>();\n let offset: Schemas['ScrollRequest']['offset'] = undefined;\n do {\n const page = await this.qdrant.scroll('resources', {\n limit: 1000,\n offset,\n with_payload: STAMP_FIELDS,\n with_vector: false,\n });\n for (const point of page.points) {\n const rid = point.payload?.resourceId;\n if (typeof rid !== 'string' || stamps.has(rid)) continue;\n stamps.set(rid, toStamp(point.payload));\n }\n offset = page.next_page_offset ?? undefined;\n } while (offset !== undefined && offset !== null);\n return stamps;\n }\n\n async listAnnotationIds(): Promise<Set<string>> {\n return this.scrollPayloadField('annotations', 'annotationId');\n }\n\n /** Collect the distinct values of one payload field across a collection. */\n private async scrollPayloadField(collection: string, field: string): Promise<Set<string>> {\n const values = new Set<string>();\n let offset: Schemas['ScrollRequest']['offset'] = undefined;\n do {\n const page = await this.qdrant.scroll(collection, {\n limit: 1000,\n offset,\n with_payload: [field],\n with_vector: false,\n });\n for (const point of page.points) {\n const value = point.payload?.[field];\n if (typeof value === 'string') values.add(value);\n }\n offset = page.next_page_offset ?? undefined;\n } while (offset !== undefined && offset !== null);\n return values;\n }\n\n async searchResources(embedding: number[], opts: SearchOptions): Promise<VectorSearchResult[]> {\n return this.search('resources', embedding, opts);\n }\n\n async searchAnnotations(embedding: number[], opts: SearchOptions): Promise<VectorSearchResult[]> {\n return this.search('annotations', embedding, opts);\n }\n\n async searchByResource(resourceId: ResourceId, opts: SearchOptions): Promise<VectorSearchResult[]> {\n // Fetch the resource's stored chunk vectors (page through all of them so a\n // long resource isn't silently truncated).\n const queryVectors: number[][] = [];\n let offset: Schemas['ScrollRequest']['offset'] = undefined;\n do {\n const page = await this.qdrant.scroll('resources', {\n filter: { must: [{ key: 'resourceId', match: { value: String(resourceId) } }] },\n with_vector: true,\n with_payload: false,\n limit: 256,\n offset,\n });\n for (const point of page.points) {\n if (Array.isArray(point.vector)) queryVectors.push(point.vector as number[]);\n }\n offset = page.next_page_offset ?? undefined;\n } while (offset !== undefined && offset !== null);\n\n if (queryVectors.length === 0) return [];\n\n // Self-exclude the source; carry the caller's filter (e.g. excludeEntityTypes).\n const filter = this.buildFilter({ ...opts.filter, excludeResourceId: resourceId });\n\n // One batched query per source chunk (single round-trip). Each batch's\n // `limit` caps POINTS, but the merge below yields RESOURCES — so a target\n // with many chunks can fill several point-slots and crowd out resources\n // that belong in the top-`limit` after folding. Over-fetch per batch to\n // leave the merge material to work with; the memory store scores every\n // candidate exhaustively, and without this the two backends disagree on\n // recall. Headroom, not a guarantee: a resource whose chunks are all\n // outranked by OVER_FETCH×limit points in every batch is still missed.\n // Qdrant's group-by would make it exact, but only via the `search`-family\n // endpoints 1.19.0 removed (see qdrant-query-api.test.ts).\n const searches = queryVectors.map((vector) => ({\n query: vector,\n limit: opts.limit * QdrantVectorStore.SEARCH_BY_RESOURCE_OVER_FETCH,\n score_threshold: opts.scoreThreshold,\n filter: filter ?? undefined,\n with_payload: true,\n }));\n const batches = await this.qdrant.queryBatch('resources', { searches });\n\n // Normalise to VectorSearchResult, then fold chunk hits to one entry per\n // resource (max-sim) via the shared merge; slice to the caller's limit.\n const hits = batches.flatMap((batch) => batch.points.map((r) => toSearchResult(r)));\n return mergeByResource(hits).slice(0, opts.limit);\n }\n\n private async search(collection: string, embedding: number[], opts: SearchOptions): Promise<VectorSearchResult[]> {\n const filter = this.buildFilter(opts.filter);\n\n // `query`, not `search`: the REST client dropped `search`/`searchBatch` in\n // 1.19.0 in favour of the universal query endpoint. Same request but the\n // vector moves to `query`, and the response is wrapped in `{ points }`.\n const { points } = await this.qdrant.query(collection, {\n query: embedding,\n limit: opts.limit,\n score_threshold: opts.scoreThreshold,\n filter: filter ?? undefined,\n with_payload: true,\n });\n\n return points.map((r) => toSearchResult(r));\n }\n\n private buildFilter(filter?: SearchOptions['filter']): Schemas['Filter'] | null {\n if (!filter) return null;\n\n const must: Schemas['FieldCondition'][] = [];\n\n if (filter.entityTypes && filter.entityTypes.length > 0) {\n // any-of: match payloads whose `entityTypes` array contains at least one\n // of the requested types. Matches the memory store's `some(t => ...)`\n // semantics; pushing one `must` clause per type would mean all-of.\n must.push({ key: 'entityTypes', match: { any: filter.entityTypes } });\n }\n\n if (filter.resourceId) {\n must.push({ key: 'resourceId', match: { value: String(filter.resourceId) } });\n }\n\n if (filter.motivation) {\n must.push({ key: 'motivation', match: { value: filter.motivation } });\n }\n\n const must_not: Schemas['FieldCondition'][] = [];\n\n if (filter.excludeResourceId) {\n must_not.push({ key: 'resourceId', match: { value: String(filter.excludeResourceId) } });\n }\n\n if (filter.excludeEntityTypes && filter.excludeEntityTypes.length > 0) {\n // any-of exclusion: drop points whose entityTypes contain any of these.\n must_not.push({ key: 'entityTypes', match: { any: filter.excludeEntityTypes } });\n }\n\n if (must.length === 0 && must_not.length === 0) return null;\n\n return {\n ...(must.length > 0 ? { must } : {}),\n ...(must_not.length > 0 ? { must_not } : {}),\n };\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -153,9 +153,16 @@ interface VectorStore {
|
|
|
153
153
|
interface QdrantConfig {
|
|
154
154
|
host: string;
|
|
155
155
|
port: number;
|
|
156
|
-
|
|
156
|
+
/** Resolves the embedding dimensionality; called only when creating a collection. */
|
|
157
|
+
dimensions: () => Promise<number>;
|
|
157
158
|
}
|
|
158
159
|
declare class QdrantVectorStore implements VectorStore {
|
|
160
|
+
/**
|
|
161
|
+
* Per-batch point over-fetch for `searchByResource`. The batch limit caps
|
|
162
|
+
* points while the caller wants resources, so multi-chunk targets would
|
|
163
|
+
* otherwise crowd the top-K. See the call site.
|
|
164
|
+
*/
|
|
165
|
+
private static readonly SEARCH_BY_RESOURCE_OVER_FETCH;
|
|
159
166
|
private client;
|
|
160
167
|
private config;
|
|
161
168
|
constructor(config: QdrantConfig);
|
|
@@ -233,10 +240,49 @@ interface VectorStoreConfig {
|
|
|
233
240
|
type: 'qdrant' | 'memory';
|
|
234
241
|
host?: string;
|
|
235
242
|
port?: number;
|
|
236
|
-
|
|
243
|
+
/**
|
|
244
|
+
* Resolves the embedding dimensionality — a *thunk*, not a value, so the
|
|
245
|
+
* provider is consulted only by a store that actually needs the number and
|
|
246
|
+
* only when it needs it. Mirrors how inference treats provider-derived
|
|
247
|
+
* facts: the client is constructed with zero I/O and its `limits()` are
|
|
248
|
+
* discovered at the point of use, never eagerly at startup.
|
|
249
|
+
*
|
|
250
|
+
* `MemoryVectorStore` never calls it. Qdrant calls it only when it has to
|
|
251
|
+
* *create* a collection, so an already-provisioned instance connects
|
|
252
|
+
* without touching the embedding provider at all.
|
|
253
|
+
*/
|
|
254
|
+
dimensions: () => Promise<number>;
|
|
237
255
|
}
|
|
238
256
|
declare function createVectorStore(config: VectorStoreConfig): Promise<VectorStore>;
|
|
239
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Chunk→resource max-sim merge.
|
|
260
|
+
*
|
|
261
|
+
* Vector search returns *chunk*-level hits: one resource can match on several
|
|
262
|
+
* of its chunks, and a caller that wants a list of resources has to fold them.
|
|
263
|
+
* The fold is max-sim (late interaction): a resource scores as its single
|
|
264
|
+
* best-matching chunk, and carries that chunk's text — so the caller can show
|
|
265
|
+
* the passage that actually matched. Averaging instead would blur a
|
|
266
|
+
* multi-topic resource into a vague centroid and lose which passage hit;
|
|
267
|
+
* keeping the first hit seen would make the result order-dependent.
|
|
268
|
+
*
|
|
269
|
+
* Three callers share this: both `searchByResource` implementations (qdrant
|
|
270
|
+
* batches one query per source chunk; memory scores every candidate against
|
|
271
|
+
* every source chunk) and the SEMANTIC-FALLBACK fold over raw `searchResources`
|
|
272
|
+
* output, whose hits map one-to-one with no dedup. All three normalise to
|
|
273
|
+
* `VectorSearchResult[]` first, so this fold is the only copy of the logic.
|
|
274
|
+
*
|
|
275
|
+
* Deliberately does NOT slice to a limit: `searchByResource` and the fallback
|
|
276
|
+
* want different slices, and a fold that silently truncates is the kind of
|
|
277
|
+
* hidden cap that reads as "covered everything" when it didn't.
|
|
278
|
+
*/
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Fold chunk-level hits to one entry per resource — the highest-scoring chunk
|
|
282
|
+
* wins, carrying its own text and metadata — sorted score-descending.
|
|
283
|
+
*/
|
|
284
|
+
declare function mergeByResource(hits: VectorSearchResult[]): VectorSearchResult[];
|
|
285
|
+
|
|
240
286
|
/**
|
|
241
287
|
* EmbeddingProvider Interface
|
|
242
288
|
*
|
|
@@ -248,8 +294,14 @@ interface EmbeddingProvider {
|
|
|
248
294
|
embed(text: string): Promise<number[]>;
|
|
249
295
|
/** Embed multiple texts in a single batch call. */
|
|
250
296
|
embedBatch(texts: string[]): Promise<number[][]>;
|
|
251
|
-
/**
|
|
252
|
-
|
|
297
|
+
/**
|
|
298
|
+
* The dimensionality of vectors produced by this provider.
|
|
299
|
+
*
|
|
300
|
+
* Discovered from the provider itself (a measured probe embedding), never
|
|
301
|
+
* a hand-maintained constant. Resolved once per instance; a failed
|
|
302
|
+
* discovery is not cached, so a later call retries.
|
|
303
|
+
*/
|
|
304
|
+
dimensions(): Promise<number>;
|
|
253
305
|
/** The model identifier (e.g. "voyage-3", "nomic-embed-text"). */
|
|
254
306
|
model(): string;
|
|
255
307
|
}
|
|
@@ -268,10 +320,12 @@ interface VoyageConfig {
|
|
|
268
320
|
}
|
|
269
321
|
declare class VoyageEmbeddingProvider implements EmbeddingProvider {
|
|
270
322
|
private config;
|
|
323
|
+
private dimensionsPromise?;
|
|
271
324
|
constructor(config: VoyageConfig);
|
|
272
325
|
embed(text: string): Promise<number[]>;
|
|
273
326
|
embedBatch(texts: string[]): Promise<number[][]>;
|
|
274
|
-
dimensions(): number
|
|
327
|
+
dimensions(): Promise<number>;
|
|
328
|
+
private measureDimensions;
|
|
275
329
|
model(): string;
|
|
276
330
|
}
|
|
277
331
|
|
|
@@ -288,10 +342,12 @@ interface OllamaEmbeddingConfig {
|
|
|
288
342
|
}
|
|
289
343
|
declare class OllamaEmbeddingProvider implements EmbeddingProvider {
|
|
290
344
|
private config;
|
|
345
|
+
private dimensionsPromise?;
|
|
291
346
|
constructor(config: OllamaEmbeddingConfig);
|
|
292
347
|
embed(text: string): Promise<number[]>;
|
|
293
348
|
embedBatch(texts: string[]): Promise<number[][]>;
|
|
294
|
-
dimensions(): number
|
|
349
|
+
dimensions(): Promise<number>;
|
|
350
|
+
private measureDimensions;
|
|
295
351
|
model(): string;
|
|
296
352
|
}
|
|
297
353
|
|
|
@@ -308,5 +364,5 @@ interface EmbeddingConfig {
|
|
|
308
364
|
}
|
|
309
365
|
declare function createEmbeddingProvider(config: EmbeddingConfig): Promise<EmbeddingProvider>;
|
|
310
366
|
|
|
311
|
-
export { MemoryVectorStore, OllamaEmbeddingProvider, QdrantVectorStore, VoyageEmbeddingProvider, createEmbeddingProvider, createVectorStore };
|
|
367
|
+
export { MemoryVectorStore, OllamaEmbeddingProvider, QdrantVectorStore, VoyageEmbeddingProvider, createEmbeddingProvider, createVectorStore, mergeByResource };
|
|
312
368
|
export type { AnnotationPayload, EmbeddingChunk, EmbeddingConfig, EmbeddingProvider, OllamaEmbeddingConfig, QdrantConfig, SearchOptions, VectorSearchResult, VectorStore, VectorStoreConfig, VoyageConfig };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
} from
|
|
4
|
-
|
|
5
|
-
VoyageEmbeddingProvider
|
|
6
|
-
} from "./chunk-UM3RNDW4.js";
|
|
7
|
-
import {
|
|
8
|
-
OllamaEmbeddingProvider
|
|
9
|
-
} from "./chunk-LBAPGZOW.js";
|
|
1
|
+
import { mergeByResource } from './chunk-Q7XXWZRC.js';
|
|
2
|
+
export { QdrantVectorStore, mergeByResource } from './chunk-Q7XXWZRC.js';
|
|
3
|
+
export { VoyageEmbeddingProvider } from './chunk-PJ72DF6E.js';
|
|
4
|
+
export { OllamaEmbeddingProvider } from './chunk-GWXB645H.js';
|
|
10
5
|
|
|
11
6
|
// src/store/memory.ts
|
|
12
7
|
function toStamp(point) {
|
|
@@ -129,7 +124,7 @@ var MemoryVectorStore = class {
|
|
|
129
124
|
const queryPoints = this.resources.filter((p) => p.payload.resourceId === rid);
|
|
130
125
|
if (queryPoints.length === 0) return [];
|
|
131
126
|
const filter = { ...opts.filter, excludeResourceId: resourceId };
|
|
132
|
-
const
|
|
127
|
+
const hits = [];
|
|
133
128
|
for (const cand of this.resources) {
|
|
134
129
|
if (!this.passesFilter(cand, filter)) continue;
|
|
135
130
|
let best = -Infinity;
|
|
@@ -137,18 +132,10 @@ var MemoryVectorStore = class {
|
|
|
137
132
|
const score = cosineSimilarity(q.vector, cand.vector);
|
|
138
133
|
if (score > best) best = score;
|
|
139
134
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
bestByResource.set(cand.payload.resourceId, { ...cand, score: best });
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
let merged = [...bestByResource.values()];
|
|
146
|
-
if (opts.scoreThreshold !== void 0) {
|
|
147
|
-
const threshold = opts.scoreThreshold;
|
|
148
|
-
merged = merged.filter((s) => s.score >= threshold);
|
|
135
|
+
if (opts.scoreThreshold !== void 0 && best < opts.scoreThreshold) continue;
|
|
136
|
+
hits.push(this.toResult({ ...cand, score: best }));
|
|
149
137
|
}
|
|
150
|
-
|
|
151
|
-
return merged.slice(0, opts.limit).map((s) => this.toResult(s));
|
|
138
|
+
return mergeByResource(hits).slice(0, opts.limit);
|
|
152
139
|
}
|
|
153
140
|
passesFilter(p, filter) {
|
|
154
141
|
if (!filter) return true;
|
|
@@ -196,7 +183,7 @@ var MemoryVectorStore = class {
|
|
|
196
183
|
async function createVectorStore(config) {
|
|
197
184
|
let store;
|
|
198
185
|
if (config.type === "qdrant") {
|
|
199
|
-
const { QdrantVectorStore: QdrantVectorStore2 } = await import(
|
|
186
|
+
const { QdrantVectorStore: QdrantVectorStore2 } = await import('./qdrant-JMDT7ZI5.js');
|
|
200
187
|
store = new QdrantVectorStore2({
|
|
201
188
|
host: config.host ?? "localhost",
|
|
202
189
|
port: config.port ?? 6333,
|
|
@@ -212,7 +199,7 @@ async function createVectorStore(config) {
|
|
|
212
199
|
// src/embedding/factory.ts
|
|
213
200
|
async function createEmbeddingProvider(config) {
|
|
214
201
|
if (config.type === "voyage") {
|
|
215
|
-
const { VoyageEmbeddingProvider: VoyageEmbeddingProvider2 } = await import(
|
|
202
|
+
const { VoyageEmbeddingProvider: VoyageEmbeddingProvider2 } = await import('./voyage-MQMTWUMO.js');
|
|
216
203
|
if (!config.apiKey) throw new Error("apiKey is required for Voyage embedding provider");
|
|
217
204
|
return new VoyageEmbeddingProvider2({
|
|
218
205
|
apiKey: config.apiKey,
|
|
@@ -221,7 +208,7 @@ async function createEmbeddingProvider(config) {
|
|
|
221
208
|
});
|
|
222
209
|
}
|
|
223
210
|
if (config.type === "ollama") {
|
|
224
|
-
const { OllamaEmbeddingProvider: OllamaEmbeddingProvider2 } = await import(
|
|
211
|
+
const { OllamaEmbeddingProvider: OllamaEmbeddingProvider2 } = await import('./ollama-GGIIWEBW.js');
|
|
225
212
|
return new OllamaEmbeddingProvider2({
|
|
226
213
|
model: config.model,
|
|
227
214
|
baseURL: config.baseURL
|
|
@@ -229,12 +216,7 @@ async function createEmbeddingProvider(config) {
|
|
|
229
216
|
}
|
|
230
217
|
throw new Error(`Unknown embedding provider type: ${config.type}`);
|
|
231
218
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
QdrantVectorStore,
|
|
236
|
-
VoyageEmbeddingProvider,
|
|
237
|
-
createEmbeddingProvider,
|
|
238
|
-
createVectorStore
|
|
239
|
-
};
|
|
219
|
+
|
|
220
|
+
export { MemoryVectorStore, createEmbeddingProvider, createVectorStore };
|
|
221
|
+
//# sourceMappingURL=index.js.map
|
|
240
222
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store/memory.ts","../src/store/factory.ts","../src/embedding/factory.ts"],"sourcesContent":["/**\n * In-Memory VectorStore Implementation\n *\n * For testing and development without a running Qdrant instance.\n * Uses brute-force cosine similarity search.\n */\n\nimport type { ResourceId, AnnotationId } from '@semiont/core';\nimport type { VectorStore, EmbeddingChunk, AnnotationPayload, VectorSearchResult, SearchOptions, ResourceStamp } from './interface';\n\nfunction toStamp(point: { payload: { contentChecksum?: string; entityTypes?: string[]; machineRead?: boolean } }): ResourceStamp {\n return {\n contentChecksum: point.payload.contentChecksum,\n entityTypes: point.payload.entityTypes ?? [],\n ...(point.payload.machineRead ? { machineRead: true } : {}),\n };\n}\n\ninterface StoredPoint {\n id: string;\n vector: number[];\n payload: {\n resourceId: string;\n annotationId?: string;\n chunkIndex?: number;\n text: string;\n contentChecksum?: string;\n motivation?: string;\n entityTypes?: string[];\n machineRead?: boolean;\n };\n}\n\nfunction cosineSimilarity(a: number[], b: number[]): number {\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n return denom === 0 ? 0 : dotProduct / denom;\n}\n\nexport class MemoryVectorStore implements VectorStore {\n private resources: StoredPoint[] = [];\n private annotations: StoredPoint[] = [];\n private connected = false;\n\n async connect(): Promise<void> {\n this.connected = true;\n }\n\n async disconnect(): Promise<void> {\n this.connected = false;\n }\n\n async clearAll(): Promise<void> {\n this.resources = [];\n this.annotations = [];\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n async upsertResourceVectors(resourceId: ResourceId, chunks: EmbeddingChunk[], contentChecksum: string, entityTypes: string[], machineRead?: boolean): Promise<void> {\n // Remove existing vectors for this resource\n this.resources = this.resources.filter(p => p.payload.resourceId !== String(resourceId));\n\n for (const chunk of chunks) {\n this.resources.push({\n id: `${resourceId}-${chunk.chunkIndex}`,\n vector: chunk.embedding,\n payload: {\n resourceId: String(resourceId),\n chunkIndex: chunk.chunkIndex,\n text: chunk.text,\n contentChecksum,\n entityTypes,\n // Only stamped when true: absence is the common case and carries no\n // claim, so a native extraction stores nothing extra.\n ...(machineRead ? { machineRead: true } : {}),\n },\n });\n }\n }\n\n async upsertAnnotationVector(\n annotationId: AnnotationId,\n embedding: number[],\n payload: AnnotationPayload\n ): Promise<void> {\n this.annotations = this.annotations.filter(p => p.id !== String(annotationId));\n this.annotations.push({\n id: String(annotationId),\n vector: embedding,\n payload: {\n annotationId: String(payload.annotationId),\n resourceId: String(payload.resourceId),\n motivation: payload.motivation,\n entityTypes: payload.entityTypes,\n text: payload.exactText,\n ...(payload.machineRead ? { machineRead: true } : {}),\n },\n });\n }\n\n async deleteResourceVectors(resourceId: ResourceId): Promise<void> {\n this.resources = this.resources.filter(p => p.payload.resourceId !== String(resourceId));\n }\n\n async deleteAnnotationVector(annotationId: AnnotationId): Promise<void> {\n this.annotations = this.annotations.filter(p => p.id !== String(annotationId));\n }\n\n async deleteAnnotationVectorsForResource(resourceId: ResourceId): Promise<void> {\n this.annotations = this.annotations.filter(p => p.payload.resourceId !== String(resourceId));\n }\n\n async count(): Promise<number> {\n return this.resources.length + this.annotations.length;\n }\n\n async updateResourceEntityTypes(resourceId: ResourceId, entityTypes: string[]): Promise<void> {\n for (const p of this.resources) {\n if (p.payload.resourceId === String(resourceId)) {\n p.payload.entityTypes = entityTypes;\n }\n }\n }\n\n async listResourceStamps(): Promise<Map<string, ResourceStamp>> {\n const stamps = new Map<string, ResourceStamp>();\n for (const p of this.resources) {\n if (!stamps.has(p.payload.resourceId)) {\n stamps.set(p.payload.resourceId, toStamp(p));\n }\n }\n return stamps;\n }\n\n async getResourceStamp(resourceId: ResourceId): Promise<ResourceStamp | undefined> {\n const point = this.resources.find(p => p.payload.resourceId === String(resourceId));\n return point ? toStamp(point) : undefined;\n }\n\n async listAnnotationIds(): Promise<Set<string>> {\n const ids = new Set<string>();\n for (const p of this.annotations) {\n if (p.payload.annotationId) ids.add(p.payload.annotationId);\n }\n return ids;\n }\n\n async searchResources(embedding: number[], opts: SearchOptions): Promise<VectorSearchResult[]> {\n return this.search(this.resources, embedding, opts);\n }\n\n async searchAnnotations(embedding: number[], opts: SearchOptions): Promise<VectorSearchResult[]> {\n return this.search(this.annotations, embedding, opts);\n }\n\n async searchByResource(resourceId: ResourceId, opts: SearchOptions): Promise<VectorSearchResult[]> {\n const rid = String(resourceId);\n const queryPoints = this.resources.filter(p => p.payload.resourceId === rid);\n if (queryPoints.length === 0) return [];\n\n // Self-exclude the source; carry the caller's filter (e.g. excludeEntityTypes).\n const filter: SearchOptions['filter'] = { ...opts.filter, excludeResourceId: resourceId };\n\n // Per-chunk max-sim, merged by resource: each candidate point scores as the\n // best similarity to any of the source's query chunks; keep, per target\n // resource, the single best-matching point (its score and its text).\n const bestByResource = new Map<string, StoredPoint & { score: number }>();\n for (const cand of this.resources) {\n if (!this.passesFilter(cand, filter)) continue;\n let best = -Infinity;\n for (const q of queryPoints) {\n const score = cosineSimilarity(q.vector, cand.vector);\n if (score > best) best = score;\n }\n const prev = bestByResource.get(cand.payload.resourceId);\n if (!prev || best > prev.score) {\n bestByResource.set(cand.payload.resourceId, { ...cand, score: best });\n }\n }\n\n let merged = [...bestByResource.values()];\n if (opts.scoreThreshold !== undefined) {\n const threshold = opts.scoreThreshold;\n merged = merged.filter(s => s.score >= threshold);\n }\n merged.sort((a, b) => b.score - a.score);\n return merged.slice(0, opts.limit).map(s => this.toResult(s));\n }\n\n private passesFilter(p: StoredPoint, filter: SearchOptions['filter']): boolean {\n if (!filter) return true;\n const f = filter;\n if (f.resourceId && p.payload.resourceId !== String(f.resourceId)) return false;\n if (f.excludeResourceId && p.payload.resourceId === String(f.excludeResourceId)) return false;\n if (f.motivation && p.payload.motivation !== f.motivation) return false;\n if (f.entityTypes && f.entityTypes.length > 0) {\n const pTypes = p.payload.entityTypes ?? [];\n if (!f.entityTypes.some(t => pTypes.includes(t))) return false;\n }\n if (f.excludeEntityTypes && f.excludeEntityTypes.length > 0) {\n const pTypes = p.payload.entityTypes ?? [];\n if (f.excludeEntityTypes.some(t => pTypes.includes(t))) return false;\n }\n return true;\n }\n\n private search(points: StoredPoint[], embedding: number[], opts: SearchOptions): VectorSearchResult[] {\n const filtered = points.filter(p => this.passesFilter(p, opts.filter));\n\n const scored = filtered.map(p => ({\n ...p,\n score: cosineSimilarity(embedding, p.vector),\n }));\n\n scored.sort((a, b) => b.score - a.score);\n\n if (opts.scoreThreshold !== undefined) {\n const threshold = opts.scoreThreshold;\n return scored\n .filter(s => s.score >= threshold)\n .slice(0, opts.limit)\n .map(s => this.toResult(s));\n }\n\n return scored.slice(0, opts.limit).map(s => this.toResult(s));\n }\n\n private toResult(s: StoredPoint & { score: number }): VectorSearchResult {\n return {\n id: s.id,\n score: s.score,\n resourceId: s.payload.resourceId as ResourceId,\n annotationId: s.payload.annotationId as AnnotationId | undefined,\n text: s.payload.text,\n entityTypes: s.payload.entityTypes,\n ...(s.payload.machineRead ? { machineRead: true } : {}),\n };\n }\n}\n","/**\n * VectorStore Factory\n *\n * Creates a connected VectorStore instance based on configuration.\n */\n\nimport type { VectorStore } from './interface';\nimport { MemoryVectorStore } from './memory';\n\nexport interface VectorStoreConfig {\n type: 'qdrant' | 'memory';\n host?: string;\n port?: number;\n dimensions: number;\n}\n\nexport async function createVectorStore(config: VectorStoreConfig): Promise<VectorStore> {\n let store: VectorStore;\n\n if (config.type === 'qdrant') {\n const { QdrantVectorStore } = await import('./qdrant');\n store = new QdrantVectorStore({\n host: config.host ?? 'localhost',\n port: config.port ?? 6333,\n dimensions: config.dimensions,\n });\n } else {\n store = new MemoryVectorStore();\n }\n\n await store.connect();\n return store;\n}\n","/**\n * EmbeddingProvider Factory\n */\n\nimport type { EmbeddingProvider } from './interface';\n\nexport interface EmbeddingConfig {\n type: 'voyage' | 'ollama';\n model: string;\n apiKey?: string;\n baseURL?: string;\n endpoint?: string;\n}\n\nexport async function createEmbeddingProvider(config: EmbeddingConfig): Promise<EmbeddingProvider> {\n if (config.type === 'voyage') {\n const { VoyageEmbeddingProvider } = await import('./voyage');\n if (!config.apiKey) throw new Error('apiKey is required for Voyage embedding provider');\n return new VoyageEmbeddingProvider({\n apiKey: config.apiKey,\n model: config.model,\n endpoint: config.endpoint,\n });\n }\n\n if (config.type === 'ollama') {\n const { OllamaEmbeddingProvider } = await import('./ollama');\n return new OllamaEmbeddingProvider({\n model: config.model,\n baseURL: config.baseURL,\n });\n }\n\n throw new Error(`Unknown embedding provider type: ${config.type}`);\n}\n"],"mappings":"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","names":["QdrantVectorStore","VoyageEmbeddingProvider","OllamaEmbeddingProvider"]}
|
|
1
|
+
{"version":3,"sources":["../src/store/memory.ts","../src/store/factory.ts","../src/embedding/factory.ts"],"names":["QdrantVectorStore","VoyageEmbeddingProvider","OllamaEmbeddingProvider"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * In-Memory VectorStore Implementation\n *\n * For testing and development without a running Qdrant instance.\n * Uses brute-force cosine similarity search.\n */\n\nimport type { ResourceId, AnnotationId } from '@semiont/core';\nimport type { VectorStore, EmbeddingChunk, AnnotationPayload, VectorSearchResult, SearchOptions, ResourceStamp } from './interface';\nimport { mergeByResource } from './merge';\n\nfunction toStamp(point: { payload: { contentChecksum?: string; entityTypes?: string[]; machineRead?: boolean } }): ResourceStamp {\n return {\n contentChecksum: point.payload.contentChecksum,\n entityTypes: point.payload.entityTypes ?? [],\n ...(point.payload.machineRead ? { machineRead: true } : {}),\n };\n}\n\ninterface StoredPoint {\n id: string;\n vector: number[];\n payload: {\n resourceId: string;\n annotationId?: string;\n chunkIndex?: number;\n text: string;\n contentChecksum?: string;\n motivation?: string;\n entityTypes?: string[];\n machineRead?: boolean;\n };\n}\n\nfunction cosineSimilarity(a: number[], b: number[]): number {\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n return denom === 0 ? 0 : dotProduct / denom;\n}\n\nexport class MemoryVectorStore implements VectorStore {\n private resources: StoredPoint[] = [];\n private annotations: StoredPoint[] = [];\n private connected = false;\n\n async connect(): Promise<void> {\n this.connected = true;\n }\n\n async disconnect(): Promise<void> {\n this.connected = false;\n }\n\n async clearAll(): Promise<void> {\n this.resources = [];\n this.annotations = [];\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n async upsertResourceVectors(resourceId: ResourceId, chunks: EmbeddingChunk[], contentChecksum: string, entityTypes: string[], machineRead?: boolean): Promise<void> {\n // Remove existing vectors for this resource\n this.resources = this.resources.filter(p => p.payload.resourceId !== String(resourceId));\n\n for (const chunk of chunks) {\n this.resources.push({\n id: `${resourceId}-${chunk.chunkIndex}`,\n vector: chunk.embedding,\n payload: {\n resourceId: String(resourceId),\n chunkIndex: chunk.chunkIndex,\n text: chunk.text,\n contentChecksum,\n entityTypes,\n // Only stamped when true: absence is the common case and carries no\n // claim, so a native extraction stores nothing extra.\n ...(machineRead ? { machineRead: true } : {}),\n },\n });\n }\n }\n\n async upsertAnnotationVector(\n annotationId: AnnotationId,\n embedding: number[],\n payload: AnnotationPayload\n ): Promise<void> {\n this.annotations = this.annotations.filter(p => p.id !== String(annotationId));\n this.annotations.push({\n id: String(annotationId),\n vector: embedding,\n payload: {\n annotationId: String(payload.annotationId),\n resourceId: String(payload.resourceId),\n motivation: payload.motivation,\n entityTypes: payload.entityTypes,\n text: payload.exactText,\n ...(payload.machineRead ? { machineRead: true } : {}),\n },\n });\n }\n\n async deleteResourceVectors(resourceId: ResourceId): Promise<void> {\n this.resources = this.resources.filter(p => p.payload.resourceId !== String(resourceId));\n }\n\n async deleteAnnotationVector(annotationId: AnnotationId): Promise<void> {\n this.annotations = this.annotations.filter(p => p.id !== String(annotationId));\n }\n\n async deleteAnnotationVectorsForResource(resourceId: ResourceId): Promise<void> {\n this.annotations = this.annotations.filter(p => p.payload.resourceId !== String(resourceId));\n }\n\n async count(): Promise<number> {\n return this.resources.length + this.annotations.length;\n }\n\n async updateResourceEntityTypes(resourceId: ResourceId, entityTypes: string[]): Promise<void> {\n for (const p of this.resources) {\n if (p.payload.resourceId === String(resourceId)) {\n p.payload.entityTypes = entityTypes;\n }\n }\n }\n\n async listResourceStamps(): Promise<Map<string, ResourceStamp>> {\n const stamps = new Map<string, ResourceStamp>();\n for (const p of this.resources) {\n if (!stamps.has(p.payload.resourceId)) {\n stamps.set(p.payload.resourceId, toStamp(p));\n }\n }\n return stamps;\n }\n\n async getResourceStamp(resourceId: ResourceId): Promise<ResourceStamp | undefined> {\n const point = this.resources.find(p => p.payload.resourceId === String(resourceId));\n return point ? toStamp(point) : undefined;\n }\n\n async listAnnotationIds(): Promise<Set<string>> {\n const ids = new Set<string>();\n for (const p of this.annotations) {\n if (p.payload.annotationId) ids.add(p.payload.annotationId);\n }\n return ids;\n }\n\n async searchResources(embedding: number[], opts: SearchOptions): Promise<VectorSearchResult[]> {\n return this.search(this.resources, embedding, opts);\n }\n\n async searchAnnotations(embedding: number[], opts: SearchOptions): Promise<VectorSearchResult[]> {\n return this.search(this.annotations, embedding, opts);\n }\n\n async searchByResource(resourceId: ResourceId, opts: SearchOptions): Promise<VectorSearchResult[]> {\n const rid = String(resourceId);\n const queryPoints = this.resources.filter(p => p.payload.resourceId === rid);\n if (queryPoints.length === 0) return [];\n\n // Self-exclude the source; carry the caller's filter (e.g. excludeEntityTypes).\n const filter: SearchOptions['filter'] = { ...opts.filter, excludeResourceId: resourceId };\n\n // Score every candidate point against the source's chunks (exhaustive — no\n // per-chunk top-K to crowd anything out), then let the shared max-sim fold\n // collapse chunk hits to one entry per resource.\n const hits: VectorSearchResult[] = [];\n for (const cand of this.resources) {\n if (!this.passesFilter(cand, filter)) continue;\n let best = -Infinity;\n for (const q of queryPoints) {\n const score = cosineSimilarity(q.vector, cand.vector);\n if (score > best) best = score;\n }\n if (opts.scoreThreshold !== undefined && best < opts.scoreThreshold) continue;\n hits.push(this.toResult({ ...cand, score: best }));\n }\n\n return mergeByResource(hits).slice(0, opts.limit);\n }\n\n private passesFilter(p: StoredPoint, filter: SearchOptions['filter']): boolean {\n if (!filter) return true;\n const f = filter;\n if (f.resourceId && p.payload.resourceId !== String(f.resourceId)) return false;\n if (f.excludeResourceId && p.payload.resourceId === String(f.excludeResourceId)) return false;\n if (f.motivation && p.payload.motivation !== f.motivation) return false;\n if (f.entityTypes && f.entityTypes.length > 0) {\n const pTypes = p.payload.entityTypes ?? [];\n if (!f.entityTypes.some(t => pTypes.includes(t))) return false;\n }\n if (f.excludeEntityTypes && f.excludeEntityTypes.length > 0) {\n const pTypes = p.payload.entityTypes ?? [];\n if (f.excludeEntityTypes.some(t => pTypes.includes(t))) return false;\n }\n return true;\n }\n\n private search(points: StoredPoint[], embedding: number[], opts: SearchOptions): VectorSearchResult[] {\n const filtered = points.filter(p => this.passesFilter(p, opts.filter));\n\n const scored = filtered.map(p => ({\n ...p,\n score: cosineSimilarity(embedding, p.vector),\n }));\n\n scored.sort((a, b) => b.score - a.score);\n\n if (opts.scoreThreshold !== undefined) {\n const threshold = opts.scoreThreshold;\n return scored\n .filter(s => s.score >= threshold)\n .slice(0, opts.limit)\n .map(s => this.toResult(s));\n }\n\n return scored.slice(0, opts.limit).map(s => this.toResult(s));\n }\n\n private toResult(s: StoredPoint & { score: number }): VectorSearchResult {\n return {\n id: s.id,\n score: s.score,\n resourceId: s.payload.resourceId as ResourceId,\n annotationId: s.payload.annotationId as AnnotationId | undefined,\n text: s.payload.text,\n entityTypes: s.payload.entityTypes,\n ...(s.payload.machineRead ? { machineRead: true } : {}),\n };\n }\n}\n","/**\n * VectorStore Factory\n *\n * Creates a connected VectorStore instance based on configuration.\n */\n\nimport type { VectorStore } from './interface';\nimport { MemoryVectorStore } from './memory';\n\nexport interface VectorStoreConfig {\n type: 'qdrant' | 'memory';\n host?: string;\n port?: number;\n /**\n * Resolves the embedding dimensionality — a *thunk*, not a value, so the\n * provider is consulted only by a store that actually needs the number and\n * only when it needs it. Mirrors how inference treats provider-derived\n * facts: the client is constructed with zero I/O and its `limits()` are\n * discovered at the point of use, never eagerly at startup.\n *\n * `MemoryVectorStore` never calls it. Qdrant calls it only when it has to\n * *create* a collection, so an already-provisioned instance connects\n * without touching the embedding provider at all.\n */\n dimensions: () => Promise<number>;\n}\n\nexport async function createVectorStore(config: VectorStoreConfig): Promise<VectorStore> {\n let store: VectorStore;\n\n if (config.type === 'qdrant') {\n const { QdrantVectorStore } = await import('./qdrant');\n store = new QdrantVectorStore({\n host: config.host ?? 'localhost',\n port: config.port ?? 6333,\n dimensions: config.dimensions,\n });\n } else {\n // MemoryVectorStore holds whatever vectors it is handed — it never reads a\n // configured dimensionality, so the thunk is deliberately never called and\n // a memory-backed deployment boots without contacting the provider.\n store = new MemoryVectorStore();\n }\n\n await store.connect();\n return store;\n}\n","/**\n * EmbeddingProvider Factory\n */\n\nimport type { EmbeddingProvider } from './interface';\n\nexport interface EmbeddingConfig {\n type: 'voyage' | 'ollama';\n model: string;\n apiKey?: string;\n baseURL?: string;\n endpoint?: string;\n}\n\nexport async function createEmbeddingProvider(config: EmbeddingConfig): Promise<EmbeddingProvider> {\n if (config.type === 'voyage') {\n const { VoyageEmbeddingProvider } = await import('./voyage');\n if (!config.apiKey) throw new Error('apiKey is required for Voyage embedding provider');\n return new VoyageEmbeddingProvider({\n apiKey: config.apiKey,\n model: config.model,\n endpoint: config.endpoint,\n });\n }\n\n if (config.type === 'ollama') {\n const { OllamaEmbeddingProvider } = await import('./ollama');\n return new OllamaEmbeddingProvider({\n model: config.model,\n baseURL: config.baseURL,\n });\n }\n\n throw new Error(`Unknown embedding provider type: ${config.type}`);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"ollama-GGIIWEBW.js"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"qdrant-JMDT7ZI5.js"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EmbeddingProvider Interface
|
|
3
|
+
*
|
|
4
|
+
* Abstraction over embedding model providers (Voyage AI, Ollama).
|
|
5
|
+
* Converts text into dense vector representations for similarity search.
|
|
6
|
+
*/
|
|
7
|
+
interface EmbeddingProvider {
|
|
8
|
+
/** Embed a single text string. */
|
|
9
|
+
embed(text: string): Promise<number[]>;
|
|
10
|
+
/** Embed multiple texts in a single batch call. */
|
|
11
|
+
embedBatch(texts: string[]): Promise<number[][]>;
|
|
12
|
+
/**
|
|
13
|
+
* The dimensionality of vectors produced by this provider.
|
|
14
|
+
*
|
|
15
|
+
* Discovered from the provider itself (a measured probe embedding), never
|
|
16
|
+
* a hand-maintained constant. Resolved once per instance; a failed
|
|
17
|
+
* discovery is not cached, so a later call retries.
|
|
18
|
+
*/
|
|
19
|
+
dimensions(): Promise<number>;
|
|
20
|
+
/** The model identifier (e.g. "voyage-3", "nomic-embed-text"). */
|
|
21
|
+
model(): string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* `@semiont/vectors/testing` — test doubles for the vector surface.
|
|
26
|
+
*
|
|
27
|
+
* Not part of the runtime surface; consumers import it from their test suites.
|
|
28
|
+
* Published as a subpath (the `@semiont/core/testing` pattern) because
|
|
29
|
+
* MANDATORY-EMBEDDING makes an `EmbeddingProvider` required at every
|
|
30
|
+
* KnowledgeBase / Gatherer / Matcher construction site — so every consumer's
|
|
31
|
+
* tests need a double, and a copy per package is the redundancy the house rules
|
|
32
|
+
* forbid. Previously this lived in `src/__tests__/`, which
|
|
33
|
+
* `tsconfig.build.json` excludes, so nothing outside this package could reach it.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Mock EmbeddingProvider for testing.
|
|
38
|
+
* Returns deterministic vectors derived from the input text
|
|
39
|
+
* so cosine similarity results are predictable.
|
|
40
|
+
*/
|
|
41
|
+
declare class MockEmbeddingProvider implements EmbeddingProvider {
|
|
42
|
+
private dims;
|
|
43
|
+
private modelName;
|
|
44
|
+
constructor(dimensions?: number, modelName?: string);
|
|
45
|
+
embed(text: string): Promise<number[]>;
|
|
46
|
+
embedBatch(texts: string[]): Promise<number[][]>;
|
|
47
|
+
dimensions(): Promise<number>;
|
|
48
|
+
model(): string;
|
|
49
|
+
/**
|
|
50
|
+
* Generate a reproducible vector from text.
|
|
51
|
+
* Same text always produces the same vector.
|
|
52
|
+
* Similar texts produce somewhat similar vectors (not guaranteed).
|
|
53
|
+
*/
|
|
54
|
+
private deterministicVector;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { MockEmbeddingProvider };
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// src/testing.ts
|
|
2
|
+
var MockEmbeddingProvider = class {
|
|
3
|
+
dims;
|
|
4
|
+
modelName;
|
|
5
|
+
constructor(dimensions = 768, modelName = "mock") {
|
|
6
|
+
this.dims = dimensions;
|
|
7
|
+
this.modelName = modelName;
|
|
8
|
+
}
|
|
9
|
+
async embed(text) {
|
|
10
|
+
return this.deterministicVector(text);
|
|
11
|
+
}
|
|
12
|
+
async embedBatch(texts) {
|
|
13
|
+
return texts.map((t) => this.deterministicVector(t));
|
|
14
|
+
}
|
|
15
|
+
async dimensions() {
|
|
16
|
+
return this.dims;
|
|
17
|
+
}
|
|
18
|
+
model() {
|
|
19
|
+
return this.modelName;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generate a reproducible vector from text.
|
|
23
|
+
* Same text always produces the same vector.
|
|
24
|
+
* Similar texts produce somewhat similar vectors (not guaranteed).
|
|
25
|
+
*/
|
|
26
|
+
deterministicVector(text) {
|
|
27
|
+
const vec = new Array(this.dims);
|
|
28
|
+
for (let i = 0; i < this.dims; i++) {
|
|
29
|
+
const charCode = text.charCodeAt(i % text.length) || 0;
|
|
30
|
+
vec[i] = Math.sin(charCode + i * 0.1) * 0.5;
|
|
31
|
+
}
|
|
32
|
+
const norm = Math.sqrt(vec.reduce((sum, v) => sum + v * v, 0));
|
|
33
|
+
if (norm > 0) {
|
|
34
|
+
for (let i = 0; i < this.dims; i++) {
|
|
35
|
+
vec[i] /= norm;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return vec;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export { MockEmbeddingProvider };
|
|
43
|
+
//# sourceMappingURL=testing.js.map
|
|
44
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testing.ts"],"names":[],"mappings":";AAmBO,IAAM,wBAAN,MAAyD;AAAA,EACtD,IAAA;AAAA,EACA,SAAA;AAAA,EAER,WAAA,CAAY,UAAA,GAAa,GAAA,EAAK,SAAA,GAAY,MAAA,EAAQ;AAChD,IAAA,IAAA,CAAK,IAAA,GAAO,UAAA;AACZ,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAAA,EACnB;AAAA,EAEA,MAAM,MAAM,IAAA,EAAiC;AAC3C,IAAA,OAAO,IAAA,CAAK,oBAAoB,IAAI,CAAA;AAAA,EACtC;AAAA,EAEA,MAAM,WAAW,KAAA,EAAsC;AACrD,IAAA,OAAO,MAAM,GAAA,CAAI,CAAA,CAAA,KAAK,IAAA,CAAK,mBAAA,CAAoB,CAAC,CAAC,CAAA;AAAA,EACnD;AAAA,EAEA,MAAM,UAAA,GAA8B;AAClC,IAAA,OAAO,IAAA,CAAK,IAAA;AAAA,EACd;AAAA,EAEA,KAAA,GAAgB;AACd,IAAA,OAAO,IAAA,CAAK,SAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,oBAAoB,IAAA,EAAwB;AAClD,IAAA,MAAM,GAAA,GAAM,IAAI,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAC/B,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,MAAM,CAAA,EAAA,EAAK;AAClC,MAAA,MAAM,WAAW,IAAA,CAAK,UAAA,CAAW,CAAA,GAAI,IAAA,CAAK,MAAM,CAAA,IAAK,CAAA;AACrD,MAAA,GAAA,CAAI,CAAC,CAAA,GAAI,IAAA,CAAK,IAAI,QAAA,GAAW,CAAA,GAAI,GAAG,CAAA,GAAI,GAAA;AAAA,IAC1C;AAEA,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,CAAC,GAAA,EAAK,CAAA,KAAM,GAAA,GAAM,CAAA,GAAI,CAAA,EAAG,CAAC,CAAC,CAAA;AAC7D,IAAA,IAAI,OAAO,CAAA,EAAG;AACZ,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,MAAM,CAAA,EAAA,EAAK;AAClC,QAAA,GAAA,CAAI,CAAC,CAAA,IAAK,IAAA;AAAA,MACZ;AAAA,IACF;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AACF","file":"testing.js","sourcesContent":["/**\n * `@semiont/vectors/testing` — test doubles for the vector surface.\n *\n * Not part of the runtime surface; consumers import it from their test suites.\n * Published as a subpath (the `@semiont/core/testing` pattern) because\n * MANDATORY-EMBEDDING makes an `EmbeddingProvider` required at every\n * KnowledgeBase / Gatherer / Matcher construction site — so every consumer's\n * tests need a double, and a copy per package is the redundancy the house rules\n * forbid. Previously this lived in `src/__tests__/`, which\n * `tsconfig.build.json` excludes, so nothing outside this package could reach it.\n */\n\nimport type { EmbeddingProvider } from './embedding/interface';\n\n/**\n * Mock EmbeddingProvider for testing.\n * Returns deterministic vectors derived from the input text\n * so cosine similarity results are predictable.\n */\nexport class MockEmbeddingProvider implements EmbeddingProvider {\n private dims: number;\n private modelName: string;\n\n constructor(dimensions = 768, modelName = 'mock') {\n this.dims = dimensions;\n this.modelName = modelName;\n }\n\n async embed(text: string): Promise<number[]> {\n return this.deterministicVector(text);\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n return texts.map(t => this.deterministicVector(t));\n }\n\n async dimensions(): Promise<number> {\n return this.dims;\n }\n\n model(): string {\n return this.modelName;\n }\n\n /**\n * Generate a reproducible vector from text.\n * Same text always produces the same vector.\n * Similar texts produce somewhat similar vectors (not guaranteed).\n */\n private deterministicVector(text: string): number[] {\n const vec = new Array(this.dims);\n for (let i = 0; i < this.dims; i++) {\n const charCode = text.charCodeAt(i % text.length) || 0;\n vec[i] = Math.sin(charCode + i * 0.1) * 0.5;\n }\n // Normalize\n const norm = Math.sqrt(vec.reduce((sum, v) => sum + v * v, 0));\n if (norm > 0) {\n for (let i = 0; i < this.dims; i++) {\n vec[i] /= norm;\n }\n }\n return vec;\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"voyage-MQMTWUMO.js"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semiont/vectors",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.27",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=24.0.0"
|
|
6
6
|
},
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"import": "./dist/index.js",
|
|
15
15
|
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./testing": {
|
|
18
|
+
"types": "./dist/testing.d.ts",
|
|
19
|
+
"import": "./dist/testing.js",
|
|
20
|
+
"default": "./dist/testing.js"
|
|
16
21
|
}
|
|
17
22
|
},
|
|
18
23
|
"scripts": {
|
|
@@ -25,7 +30,7 @@
|
|
|
25
30
|
},
|
|
26
31
|
"dependencies": {
|
|
27
32
|
"@qdrant/js-client-rest": "^1.18.0",
|
|
28
|
-
"@semiont/core": "0.5.
|
|
33
|
+
"@semiont/core": "0.5.27"
|
|
29
34
|
},
|
|
30
35
|
"devDependencies": {
|
|
31
36
|
"@vitest/coverage-v8": "^4.1.8",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/embedding/ollama.ts"],"sourcesContent":["/**\n * Ollama Embedding Provider\n *\n * Local embedding via the Ollama API.\n * Uses models like nomic-embed-text, all-minilm, etc.\n */\n\nimport type { EmbeddingProvider } from './interface';\n\nexport interface OllamaEmbeddingConfig {\n model: string;\n baseURL?: string;\n}\n\nconst OLLAMA_DIMENSIONS: Record<string, number> = {\n 'nomic-embed-text': 768,\n 'all-minilm': 384,\n 'mxbai-embed-large': 1024,\n 'snowflake-arctic-embed': 1024,\n};\n\nexport class OllamaEmbeddingProvider implements EmbeddingProvider {\n private config: OllamaEmbeddingConfig;\n\n constructor(config: OllamaEmbeddingConfig) {\n this.config = config;\n }\n\n async embed(text: string): Promise<number[]> {\n const baseURL = this.config.baseURL ?? 'http://localhost:11434';\n\n const response = await fetch(`${baseURL}/api/embed`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.config.model,\n input: text,\n }),\n });\n\n if (!response.ok) {\n const body = await response.text();\n throw new Error(`Ollama embed error ${response.status}: ${body}`);\n }\n\n const json = await response.json() as { embeddings: number[][] };\n return json.embeddings[0];\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n // Ollama's /api/embed supports batch input\n const baseURL = this.config.baseURL ?? 'http://localhost:11434';\n\n const response = await fetch(`${baseURL}/api/embed`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.config.model,\n input: texts,\n }),\n });\n\n if (!response.ok) {\n const body = await response.text();\n throw new Error(`Ollama embed error ${response.status}: ${body}`);\n }\n\n const json = await response.json() as { embeddings: number[][] };\n return json.embeddings;\n }\n\n dimensions(): number {\n return OLLAMA_DIMENSIONS[this.config.model] ?? 768;\n }\n\n model(): string {\n return this.config.model;\n }\n}\n"],"mappings":";AAcA,IAAM,oBAA4C;AAAA,EAChD,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,0BAA0B;AAC5B;AAEO,IAAM,0BAAN,MAA2D;AAAA,EACxD;AAAA,EAER,YAAY,QAA+B;AACzC,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAM,MAAM,MAAiC;AAC3C,UAAM,UAAU,KAAK,OAAO,WAAW;AAEvC,UAAM,WAAW,MAAM,MAAM,GAAG,OAAO,cAAc;AAAA,MACnD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU;AAAA,QACnB,OAAO,KAAK,OAAO;AAAA,QACnB,OAAO;AAAA,MACT,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAM,IAAI,MAAM,sBAAsB,SAAS,MAAM,KAAK,IAAI,EAAE;AAAA,IAClE;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,WAAO,KAAK,WAAW,CAAC;AAAA,EAC1B;AAAA,EAEA,MAAM,WAAW,OAAsC;AAErD,UAAM,UAAU,KAAK,OAAO,WAAW;AAEvC,UAAM,WAAW,MAAM,MAAM,GAAG,OAAO,cAAc;AAAA,MACnD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU;AAAA,QACnB,OAAO,KAAK,OAAO;AAAA,QACnB,OAAO;AAAA,MACT,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAM,IAAI,MAAM,sBAAsB,SAAS,MAAM,KAAK,IAAI,EAAE;AAAA,IAClE;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,aAAqB;AACnB,WAAO,kBAAkB,KAAK,OAAO,KAAK,KAAK;AAAA,EACjD;AAAA,EAEA,QAAgB;AACd,WAAO,KAAK,OAAO;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store/qdrant.ts"],"sourcesContent":["/**\n * Qdrant VectorStore Implementation\n *\n * Uses the Qdrant REST API via @qdrant/js-client-rest.\n * Manages two collections: 'resources' and 'annotations'.\n */\n\nimport { createHash } from 'crypto';\nimport type { QdrantClient, Schemas } from '@qdrant/js-client-rest';\nimport type { ResourceId, AnnotationId } from '@semiont/core';\nimport type { VectorStore, EmbeddingChunk, AnnotationPayload, VectorSearchResult, SearchOptions, ResourceStamp } from './interface';\n\n/**\n * Generate a deterministic UUID v5-style ID from an arbitrary string.\n * Qdrant requires point IDs to be UUIDs or unsigned integers.\n */\nfunction toQdrantId(input: string): string {\n const hex = createHash('md5').update(input).digest('hex');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;\n}\n\nexport interface QdrantConfig {\n host: string;\n port: number;\n dimensions: number;\n}\n\n/** The payload fields a stamp is read from — one list for the scroll and the\n * targeted read, so the two cannot drift. */\nconst STAMP_FIELDS = ['resourceId', 'contentChecksum', 'entityTypes', 'machineRead'];\n\nfunction toStamp(payload: Record<string, unknown> | null | undefined): ResourceStamp {\n const checksum = payload?.contentChecksum;\n const entityTypes = payload?.entityTypes;\n return {\n contentChecksum: typeof checksum === 'string' ? checksum : undefined,\n entityTypes: Array.isArray(entityTypes)\n ? entityTypes.filter((t): t is string => typeof t === 'string')\n : [],\n ...(payload?.machineRead ? { machineRead: true } : {}),\n };\n}\n\nexport class QdrantVectorStore implements VectorStore {\n private client: QdrantClient | null = null;\n private config: QdrantConfig;\n\n constructor(config: QdrantConfig) {\n this.config = config;\n }\n\n private get qdrant(): QdrantClient {\n if (!this.client) throw new Error('QdrantVectorStore is not connected');\n return this.client;\n }\n\n async connect(): Promise<void> {\n const { QdrantClient } = await import('@qdrant/js-client-rest');\n this.client = new QdrantClient({\n host: this.config.host,\n port: this.config.port,\n });\n\n // Ensure collections exist\n await this.ensureCollection('resources', this.config.dimensions);\n await this.ensureCollection('annotations', this.config.dimensions);\n // Payload indexes so filtered operations scale:\n // - entityTypes: the excludeEntityTypes recall filter.\n // - resourceId: searchByResource's by-resource scroll + self-exclusion, and\n // the per-resource delete paths (deleteResourceVectors /\n // deleteAnnotationVectorsForResource).\n await this.ensurePayloadIndex('resources', 'entityTypes');\n await this.ensurePayloadIndex('resources', 'resourceId');\n await this.ensurePayloadIndex('annotations', 'resourceId');\n }\n\n async disconnect(): Promise<void> {\n this.client = null;\n }\n\n async clearAll(): Promise<void> {\n try { await this.qdrant.deleteCollection('resources'); } catch { /* may not exist */ }\n try { await this.qdrant.deleteCollection('annotations'); } catch { /* may not exist */ }\n await this.ensureCollection('resources', this.config.dimensions);\n await this.ensureCollection('annotations', this.config.dimensions);\n }\n\n isConnected(): boolean {\n return this.client !== null;\n }\n\n private async ensureCollection(name: string, dimensions: number): Promise<void> {\n try {\n await this.qdrant.getCollection(name);\n } catch {\n await this.qdrant.createCollection(name, {\n vectors: { size: dimensions, distance: 'Cosine' },\n });\n }\n }\n\n /**\n * Idempotently create a keyword payload index. Qdrant accepts a repeat call\n * for an already-indexed field, so this runs safely on every connect and\n * back-fills the index on collections created before the field was indexed.\n */\n private async ensurePayloadIndex(collection: string, field: string): Promise<void> {\n try {\n await this.qdrant.createPayloadIndex(collection, { field_name: field, field_schema: 'keyword' });\n } catch { /* already indexed, or created concurrently */ }\n }\n\n async upsertResourceVectors(resourceId: ResourceId, chunks: EmbeddingChunk[], contentChecksum: string, entityTypes: string[], machineRead?: boolean): Promise<void> {\n // Replace semantics: purge existing chunks first, or a resource that\n // shrinks leaves orphan points at the higher chunk indices.\n await this.deleteResourceVectors(resourceId);\n if (chunks.length === 0) return;\n\n const points = chunks.map((chunk) => ({\n id: toQdrantId(`${resourceId}-${chunk.chunkIndex}`),\n vector: chunk.embedding,\n payload: {\n resourceId: String(resourceId),\n chunkIndex: chunk.chunkIndex,\n text: chunk.text,\n contentChecksum,\n entityTypes,\n // Only stamped when true: absence is the common case and carries no\n // claim, so a native extraction stores nothing extra.\n ...(machineRead ? { machineRead: true } : {}),\n },\n }));\n\n await this.qdrant.upsert('resources', { points });\n }\n\n async upsertAnnotationVector(\n annotationId: AnnotationId,\n embedding: number[],\n payload: AnnotationPayload\n ): Promise<void> {\n await this.qdrant.upsert('annotations', {\n points: [{\n id: toQdrantId(String(annotationId)),\n vector: embedding,\n payload: {\n annotationId: String(payload.annotationId),\n resourceId: String(payload.resourceId),\n motivation: payload.motivation,\n entityTypes: payload.entityTypes,\n text: payload.exactText,\n ...(payload.machineRead ? { machineRead: true } : {}),\n },\n }],\n });\n }\n\n async deleteResourceVectors(resourceId: ResourceId): Promise<void> {\n await this.qdrant.delete('resources', {\n filter: {\n must: [{ key: 'resourceId', match: { value: String(resourceId) } }],\n },\n });\n }\n\n async deleteAnnotationVector(annotationId: AnnotationId): Promise<void> {\n await this.qdrant.delete('annotations', {\n points: [toQdrantId(String(annotationId))],\n });\n }\n\n async deleteAnnotationVectorsForResource(resourceId: ResourceId): Promise<void> {\n await this.qdrant.delete('annotations', {\n filter: {\n must: [{ key: 'resourceId', match: { value: String(resourceId) } }],\n },\n });\n }\n\n async count(): Promise<number> {\n const [resources, annotations] = await Promise.all([\n this.qdrant.count('resources', { exact: true }),\n this.qdrant.count('annotations', { exact: true }),\n ]);\n return resources.count + annotations.count;\n }\n\n async updateResourceEntityTypes(resourceId: ResourceId, entityTypes: string[]): Promise<void> {\n // Payload-only rewrite across the resource's points — no vectors touched,\n // no embedding involved (S13). Qdrant set_payload with a filter is a\n // no-op when the resource has no points.\n await this.qdrant.setPayload('resources', {\n payload: { entityTypes },\n filter: {\n must: [{ key: 'resourceId', match: { value: String(resourceId) } }],\n },\n });\n }\n\n async getResourceStamp(resourceId: ResourceId): Promise<ResourceStamp | undefined> {\n const page = await this.qdrant.scroll('resources', {\n limit: 1,\n filter: { must: [{ key: 'resourceId', match: { value: String(resourceId) } }] },\n with_payload: STAMP_FIELDS,\n with_vector: false,\n });\n const point = page.points[0];\n return point ? toStamp(point.payload) : undefined;\n }\n\n async listResourceStamps(): Promise<Map<string, ResourceStamp>> {\n const stamps = new Map<string, ResourceStamp>();\n let offset: Schemas['ScrollRequest']['offset'] = undefined;\n do {\n const page = await this.qdrant.scroll('resources', {\n limit: 1000,\n offset,\n with_payload: STAMP_FIELDS,\n with_vector: false,\n });\n for (const point of page.points) {\n const rid = point.payload?.resourceId;\n if (typeof rid !== 'string' || stamps.has(rid)) continue;\n stamps.set(rid, toStamp(point.payload));\n }\n offset = page.next_page_offset ?? undefined;\n } while (offset !== undefined && offset !== null);\n return stamps;\n }\n\n async listAnnotationIds(): Promise<Set<string>> {\n return this.scrollPayloadField('annotations', 'annotationId');\n }\n\n /** Collect the distinct values of one payload field across a collection. */\n private async scrollPayloadField(collection: string, field: string): Promise<Set<string>> {\n const values = new Set<string>();\n let offset: Schemas['ScrollRequest']['offset'] = undefined;\n do {\n const page = await this.qdrant.scroll(collection, {\n limit: 1000,\n offset,\n with_payload: [field],\n with_vector: false,\n });\n for (const point of page.points) {\n const value = point.payload?.[field];\n if (typeof value === 'string') values.add(value);\n }\n offset = page.next_page_offset ?? undefined;\n } while (offset !== undefined && offset !== null);\n return values;\n }\n\n async searchResources(embedding: number[], opts: SearchOptions): Promise<VectorSearchResult[]> {\n return this.search('resources', embedding, opts);\n }\n\n async searchAnnotations(embedding: number[], opts: SearchOptions): Promise<VectorSearchResult[]> {\n return this.search('annotations', embedding, opts);\n }\n\n async searchByResource(resourceId: ResourceId, opts: SearchOptions): Promise<VectorSearchResult[]> {\n // Fetch the resource's stored chunk vectors (page through all of them so a\n // long resource isn't silently truncated).\n const queryVectors: number[][] = [];\n let offset: Schemas['ScrollRequest']['offset'] = undefined;\n do {\n const page = await this.qdrant.scroll('resources', {\n filter: { must: [{ key: 'resourceId', match: { value: String(resourceId) } }] },\n with_vector: true,\n with_payload: false,\n limit: 256,\n offset,\n });\n for (const point of page.points) {\n if (Array.isArray(point.vector)) queryVectors.push(point.vector as number[]);\n }\n offset = page.next_page_offset ?? undefined;\n } while (offset !== undefined && offset !== null);\n\n if (queryVectors.length === 0) return [];\n\n // Self-exclude the source; carry the caller's filter (e.g. excludeEntityTypes).\n const filter = this.buildFilter({ ...opts.filter, excludeResourceId: resourceId });\n\n // One batched search per query chunk (single round-trip), top-`limit` each;\n // over-fetch beyond `limit` is unnecessary because the max-sim merge only\n // needs a target in some chunk's top-K to surface.\n const searches = queryVectors.map((vector) => ({\n query: vector,\n limit: opts.limit,\n score_threshold: opts.scoreThreshold,\n filter: filter ?? undefined,\n with_payload: true,\n }));\n const batches = await this.qdrant.queryBatch('resources', { searches });\n\n // Max-sim merge: dedup by resourceId, keep the best (query-chunk × target-chunk)\n // score and the best-matching target chunk's payload.\n const bestByResource = new Map<string, { id: string; score: number; payload: Record<string, unknown> }>();\n for (const batch of batches) {\n for (const r of batch.points) {\n const payload = r.payload ?? {};\n const tid = String(payload.resourceId);\n const prev = bestByResource.get(tid);\n if (!prev || r.score > prev.score) {\n bestByResource.set(tid, { id: String(r.id), score: r.score, payload });\n }\n }\n }\n\n return [...bestByResource.values()]\n .sort((a, b) => b.score - a.score)\n .slice(0, opts.limit)\n .map((m) => ({\n id: m.id,\n score: m.score,\n resourceId: m.payload.resourceId as ResourceId,\n annotationId: m.payload.annotationId as AnnotationId | undefined,\n text: m.payload.text as string,\n entityTypes: m.payload.entityTypes as string[] | undefined,\n ...(m.payload.machineRead ? { machineRead: true } : {}),\n }));\n }\n\n private async search(collection: string, embedding: number[], opts: SearchOptions): Promise<VectorSearchResult[]> {\n const filter = this.buildFilter(opts.filter);\n\n // `query`, not `search`: the REST client dropped `search`/`searchBatch` in\n // 1.19.0 in favour of the universal query endpoint. Same request but the\n // vector moves to `query`, and the response is wrapped in `{ points }`.\n const { points } = await this.qdrant.query(collection, {\n query: embedding,\n limit: opts.limit,\n score_threshold: opts.scoreThreshold,\n filter: filter ?? undefined,\n with_payload: true,\n });\n\n return points.map((r) => {\n const payload = r.payload ?? {};\n return {\n id: String(r.id),\n score: r.score,\n resourceId: payload.resourceId as ResourceId,\n annotationId: payload.annotationId as AnnotationId | undefined,\n text: payload.text as string,\n entityTypes: payload.entityTypes as string[] | undefined,\n ...(payload.machineRead ? { machineRead: true } : {}),\n };\n });\n }\n\n private buildFilter(filter?: SearchOptions['filter']): Schemas['Filter'] | null {\n if (!filter) return null;\n\n const must: Schemas['FieldCondition'][] = [];\n\n if (filter.entityTypes && filter.entityTypes.length > 0) {\n // any-of: match payloads whose `entityTypes` array contains at least one\n // of the requested types. Matches the memory store's `some(t => ...)`\n // semantics; pushing one `must` clause per type would mean all-of.\n must.push({ key: 'entityTypes', match: { any: filter.entityTypes } });\n }\n\n if (filter.resourceId) {\n must.push({ key: 'resourceId', match: { value: String(filter.resourceId) } });\n }\n\n if (filter.motivation) {\n must.push({ key: 'motivation', match: { value: filter.motivation } });\n }\n\n const must_not: Schemas['FieldCondition'][] = [];\n\n if (filter.excludeResourceId) {\n must_not.push({ key: 'resourceId', match: { value: String(filter.excludeResourceId) } });\n }\n\n if (filter.excludeEntityTypes && filter.excludeEntityTypes.length > 0) {\n // any-of exclusion: drop points whose entityTypes contain any of these.\n must_not.push({ key: 'entityTypes', match: { any: filter.excludeEntityTypes } });\n }\n\n if (must.length === 0 && must_not.length === 0) return null;\n\n return {\n ...(must.length > 0 ? { must } : {}),\n ...(must_not.length > 0 ? { must_not } : {}),\n };\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/embedding/voyage.ts"],"sourcesContent":["/**\n * Voyage AI Embedding Provider\n *\n * Cloud embedding via the Voyage AI API.\n * Requires a Voyage AI API key (distinct from Anthropic inference keys).\n */\n\nimport type { EmbeddingProvider } from './interface';\n\nexport interface VoyageConfig {\n apiKey: string;\n model: string;\n endpoint?: string;\n}\n\nconst VOYAGE_DIMENSIONS: Record<string, number> = {\n 'voyage-3': 1024,\n 'voyage-3-lite': 512,\n 'voyage-code-3': 1024,\n 'voyage-finance-2': 1024,\n 'voyage-law-2': 1024,\n};\n\nexport class VoyageEmbeddingProvider implements EmbeddingProvider {\n private config: VoyageConfig;\n\n constructor(config: VoyageConfig) {\n this.config = config;\n }\n\n async embed(text: string): Promise<number[]> {\n const results = await this.embedBatch([text]);\n return results[0];\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n const endpoint = this.config.endpoint ?? 'https://api.voyageai.com/v1/embeddings';\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n model: this.config.model,\n input: texts,\n }),\n });\n\n if (!response.ok) {\n const body = await response.text();\n throw new Error(`Voyage API error ${response.status}: ${body}`);\n }\n\n const json = await response.json() as { data: Array<{ embedding: number[] }> };\n return json.data.map(d => d.embedding);\n }\n\n dimensions(): number {\n return VOYAGE_DIMENSIONS[this.config.model] ?? 1024;\n }\n\n model(): string {\n return this.config.model;\n }\n}\n"],"mappings":";AAeA,IAAM,oBAA4C;AAAA,EAChD,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,gBAAgB;AAClB;AAEO,IAAM,0BAAN,MAA2D;AAAA,EACxD;AAAA,EAER,YAAY,QAAsB;AAChC,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAM,MAAM,MAAiC;AAC3C,UAAM,UAAU,MAAM,KAAK,WAAW,CAAC,IAAI,CAAC;AAC5C,WAAO,QAAQ,CAAC;AAAA,EAClB;AAAA,EAEA,MAAM,WAAW,OAAsC;AACrD,UAAM,WAAW,KAAK,OAAO,YAAY;AAEzC,UAAM,WAAW,MAAM,MAAM,UAAU;AAAA,MACrC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,iBAAiB,UAAU,KAAK,OAAO,MAAM;AAAA,MAC/C;AAAA,MACA,MAAM,KAAK,UAAU;AAAA,QACnB,OAAO,KAAK,OAAO;AAAA,QACnB,OAAO;AAAA,MACT,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAM,IAAI,MAAM,oBAAoB,SAAS,MAAM,KAAK,IAAI,EAAE;AAAA,IAChE;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,WAAO,KAAK,KAAK,IAAI,OAAK,EAAE,SAAS;AAAA,EACvC;AAAA,EAEA,aAAqB;AACnB,WAAO,kBAAkB,KAAK,OAAO,KAAK,KAAK;AAAA,EACjD;AAAA,EAEA,QAAgB;AACd,WAAO,KAAK,OAAO;AAAA,EACrB;AACF;","names":[]}
|
package/dist/ollama-H62PXJ5D.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/qdrant-GNSEAGLI.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/voyage-NUSVXNJN.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|