@zauso-ai/capstan-db 0.2.0 → 0.3.0
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/dist/client.d.ts +3 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +206 -27
- package/dist/client.js.map +1 -1
- package/dist/crud.d.ts +14 -0
- package/dist/crud.d.ts.map +1 -1
- package/dist/crud.js +49 -39
- package/dist/crud.js.map +1 -1
- package/dist/dialect.d.ts +25 -0
- package/dist/dialect.d.ts.map +1 -0
- package/dist/dialect.js +208 -0
- package/dist/dialect.js.map +1 -0
- package/dist/embedding.d.ts +63 -0
- package/dist/embedding.d.ts.map +1 -0
- package/dist/embedding.js +61 -0
- package/dist/embedding.js.map +1 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/migrate.d.ts +44 -23
- package/dist/migrate.d.ts.map +1 -1
- package/dist/migrate.js +308 -125
- package/dist/migrate.js.map +1 -1
- package/dist/model.d.ts +9 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +13 -0
- package/dist/model.js.map +1 -1
- package/dist/naming.d.ts +37 -0
- package/dist/naming.d.ts.map +1 -0
- package/dist/naming.js +196 -0
- package/dist/naming.js.map +1 -0
- package/dist/runtime.d.ts +51 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +490 -0
- package/dist/runtime.js.map +1 -0
- package/dist/schema.d.ts +2 -27
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +181 -197
- package/dist/schema.js.map +1 -1
- package/dist/search.d.ts +52 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +110 -0
- package/dist/search.js.map +1 -0
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-store-memory.d.ts +31 -0
- package/dist/vector-store-memory.d.ts.map +1 -0
- package/dist/vector-store-memory.js +125 -0
- package/dist/vector-store-memory.js.map +1 -0
- package/dist/vector-store-pgvector.d.ts +46 -0
- package/dist/vector-store-pgvector.d.ts.map +1 -0
- package/dist/vector-store-pgvector.js +215 -0
- package/dist/vector-store-pgvector.js.map +1 -0
- package/dist/vector-store-sqlite.d.ts +51 -0
- package/dist/vector-store-sqlite.d.ts.map +1 -0
- package/dist/vector-store-sqlite.js +203 -0
- package/dist/vector-store-sqlite.js.map +1 -0
- package/dist/vector-store.d.ts +79 -0
- package/dist/vector-store.d.ts.map +1 -0
- package/dist/vector-store.js +5 -0
- package/dist/vector-store.js.map +1 -0
- package/dist/write.d.ts +15 -0
- package/dist/write.d.ts.map +1 -0
- package/dist/write.js +156 -0
- package/dist/write.js.map +1 -0
- package/package.json +9 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ScalarType = "string" | "integer" | "number" | "boolean" | "date" | "datetime" | "text" | "json";
|
|
1
|
+
export type ScalarType = "string" | "integer" | "number" | "boolean" | "date" | "datetime" | "text" | "json" | "vector";
|
|
2
2
|
export interface FieldDefinition {
|
|
3
3
|
type: ScalarType;
|
|
4
4
|
required?: boolean;
|
|
@@ -7,6 +7,8 @@ export interface FieldDefinition {
|
|
|
7
7
|
min?: number;
|
|
8
8
|
max?: number;
|
|
9
9
|
enum?: readonly string[];
|
|
10
|
+
/** Number of dimensions for vector fields */
|
|
11
|
+
dimensions?: number;
|
|
10
12
|
/** Auto-set to current time on update */
|
|
11
13
|
updatedAt?: boolean;
|
|
12
14
|
/** Auto-generate UUID */
|
|
@@ -32,7 +34,7 @@ export interface ModelDefinition {
|
|
|
32
34
|
relations: Record<string, RelationDefinition>;
|
|
33
35
|
indexes: IndexDefinition[];
|
|
34
36
|
}
|
|
35
|
-
export type DbProvider = "sqlite" | "postgres" | "mysql";
|
|
37
|
+
export type DbProvider = "sqlite" | "postgres" | "mysql" | "libsql";
|
|
36
38
|
export interface DatabaseConfig {
|
|
37
39
|
provider: DbProvider;
|
|
38
40
|
url: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AAExH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,yBAAyB;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE7E,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC9C,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEpE,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,UAAU,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACb"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { VectorFilter, VectorHybridSearchOptions, VectorSearchResult, VectorStore, VectorStoreConfig } from "./vector-store.js";
|
|
2
|
+
interface StoredEntry {
|
|
3
|
+
vector: number[];
|
|
4
|
+
metadata: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* In-memory vector store backed by a `Map`.
|
|
8
|
+
*
|
|
9
|
+
* This implementation wraps the same cosine-distance utilities that power the
|
|
10
|
+
* existing `findNearest` and `hybridSearch` exports so that behaviour is
|
|
11
|
+
* identical when running without a database.
|
|
12
|
+
*/
|
|
13
|
+
export declare class InMemoryVectorStore implements VectorStore {
|
|
14
|
+
/** @internal */
|
|
15
|
+
readonly _store: Map<string, StoredEntry>;
|
|
16
|
+
private readonly _dimensions;
|
|
17
|
+
constructor(config?: Partial<VectorStoreConfig>);
|
|
18
|
+
private _validateDimensions;
|
|
19
|
+
upsert(id: string, vector: number[], metadata?: Record<string, unknown>): Promise<void>;
|
|
20
|
+
upsertBatch(items: ReadonlyArray<{
|
|
21
|
+
id: string;
|
|
22
|
+
vector: number[];
|
|
23
|
+
metadata?: Record<string, unknown>;
|
|
24
|
+
}>): Promise<void>;
|
|
25
|
+
search(query: number[], k: number, filter?: VectorFilter): Promise<VectorSearchResult[]>;
|
|
26
|
+
hybridSearch(query: string, queryVector: number[], k: number, opts?: VectorHybridSearchOptions): Promise<VectorSearchResult[]>;
|
|
27
|
+
remove(id: string): Promise<boolean>;
|
|
28
|
+
count(): Promise<number>;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=vector-store-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-store-memory.d.ts","sourceRoot":"","sources":["../../../.claude/worktrees/agent-a1ae6f0b/packages/db/src/vector-store-memory.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,YAAY,EACZ,yBAAyB,EACzB,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAE3B,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAqCD;;;;;;GAMG;AACH,qBAAa,mBAAoB,YAAW,WAAW;IACrD,gBAAgB;IAChB,QAAQ,CAAC,MAAM,2BAAkC;IACjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;gBAErC,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAI/C,OAAO,CAAC,mBAAmB;IAWrB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvF,WAAW,CACf,KAAK,EAAE,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,GACzF,OAAO,CAAC,IAAI,CAAC;IASV,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAexF,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EAAE,EACrB,CAAC,EAAE,MAAM,EACT,IAAI,CAAC,EAAE,yBAAyB,GAC/B,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAgC1B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIpC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;CAG/B"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// InMemoryVectorStore — brute-force in-memory vector search
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// Suitable for development and small datasets (<10K vectors). All data lives
|
|
6
|
+
// in a plain Map and is lost when the process exits. Search is O(n) per
|
|
7
|
+
// query — acceptable for prototyping but not for production workloads.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
import { cosineDistance } from "./search.js";
|
|
10
|
+
/** Simple whitespace tokeniser with lower-casing and deduplication. */
|
|
11
|
+
function tokenize(text) {
|
|
12
|
+
return [
|
|
13
|
+
...new Set(text
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.split(/\W+/)
|
|
16
|
+
.filter((t) => t.length > 0)),
|
|
17
|
+
];
|
|
18
|
+
}
|
|
19
|
+
/** Normalised keyword overlap score in [0, 1]. */
|
|
20
|
+
function keywordOverlap(queryTerms, text) {
|
|
21
|
+
if (queryTerms.length === 0)
|
|
22
|
+
return 0;
|
|
23
|
+
const docTokens = new Set(tokenize(text));
|
|
24
|
+
let hits = 0;
|
|
25
|
+
for (const term of queryTerms) {
|
|
26
|
+
if (docTokens.has(term))
|
|
27
|
+
hits++;
|
|
28
|
+
}
|
|
29
|
+
return hits / queryTerms.length;
|
|
30
|
+
}
|
|
31
|
+
function matchesFilter(metadata, filter) {
|
|
32
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
33
|
+
const actual = metadata[key];
|
|
34
|
+
if (Array.isArray(value)) {
|
|
35
|
+
if (!value.includes(actual))
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
else if (actual !== value) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* In-memory vector store backed by a `Map`.
|
|
46
|
+
*
|
|
47
|
+
* This implementation wraps the same cosine-distance utilities that power the
|
|
48
|
+
* existing `findNearest` and `hybridSearch` exports so that behaviour is
|
|
49
|
+
* identical when running without a database.
|
|
50
|
+
*/
|
|
51
|
+
export class InMemoryVectorStore {
|
|
52
|
+
/** @internal */
|
|
53
|
+
_store = new Map();
|
|
54
|
+
_dimensions;
|
|
55
|
+
constructor(config) {
|
|
56
|
+
this._dimensions = config?.dimensions;
|
|
57
|
+
}
|
|
58
|
+
_validateDimensions(vector) {
|
|
59
|
+
if (vector.length === 0) {
|
|
60
|
+
throw new Error("Cannot store a zero-length vector.");
|
|
61
|
+
}
|
|
62
|
+
if (this._dimensions !== undefined && vector.length !== this._dimensions) {
|
|
63
|
+
throw new Error(`Dimension mismatch: expected ${this._dimensions}, got ${vector.length}.`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async upsert(id, vector, metadata) {
|
|
67
|
+
this._validateDimensions(vector);
|
|
68
|
+
this._store.set(id, { vector, metadata: metadata ?? {} });
|
|
69
|
+
}
|
|
70
|
+
async upsertBatch(items) {
|
|
71
|
+
for (const item of items) {
|
|
72
|
+
this._validateDimensions(item.vector);
|
|
73
|
+
}
|
|
74
|
+
for (const item of items) {
|
|
75
|
+
this._store.set(item.id, { vector: item.vector, metadata: item.metadata ?? {} });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async search(query, k, filter) {
|
|
79
|
+
if (query.length === 0)
|
|
80
|
+
return [];
|
|
81
|
+
const results = [];
|
|
82
|
+
for (const [id, entry] of this._store) {
|
|
83
|
+
if (filter && !matchesFilter(entry.metadata, filter))
|
|
84
|
+
continue;
|
|
85
|
+
if (entry.vector.length !== query.length)
|
|
86
|
+
continue;
|
|
87
|
+
const score = 1 - cosineDistance(query, entry.vector);
|
|
88
|
+
results.push({ id, score, metadata: entry.metadata });
|
|
89
|
+
}
|
|
90
|
+
results.sort((a, b) => b.score - a.score);
|
|
91
|
+
return results.slice(0, Math.max(0, k));
|
|
92
|
+
}
|
|
93
|
+
async hybridSearch(query, queryVector, k, opts) {
|
|
94
|
+
const keywordWeight = opts?.keywordWeight ?? 0.3;
|
|
95
|
+
const vectorWeight = opts?.vectorWeight ?? 0.7;
|
|
96
|
+
const queryTerms = tokenize(query);
|
|
97
|
+
if (queryTerms.length === 0 && queryVector.length === 0)
|
|
98
|
+
return [];
|
|
99
|
+
const results = [];
|
|
100
|
+
for (const [id, entry] of this._store) {
|
|
101
|
+
if (opts?.filter && !matchesFilter(entry.metadata, opts.filter))
|
|
102
|
+
continue;
|
|
103
|
+
const vectorScore = queryVector.length > 0 && entry.vector.length === queryVector.length
|
|
104
|
+
? 1 - cosineDistance(queryVector, entry.vector)
|
|
105
|
+
: 0;
|
|
106
|
+
// Use the "text" metadata field for keyword matching when available.
|
|
107
|
+
const text = typeof entry.metadata["text"] === "string" ? entry.metadata["text"] : "";
|
|
108
|
+
const kwScore = keywordOverlap(queryTerms, text);
|
|
109
|
+
results.push({
|
|
110
|
+
id,
|
|
111
|
+
score: vectorWeight * vectorScore + keywordWeight * kwScore,
|
|
112
|
+
metadata: entry.metadata,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
results.sort((a, b) => b.score - a.score);
|
|
116
|
+
return results.slice(0, Math.max(0, k));
|
|
117
|
+
}
|
|
118
|
+
async remove(id) {
|
|
119
|
+
return this._store.delete(id);
|
|
120
|
+
}
|
|
121
|
+
async count() {
|
|
122
|
+
return this._store.size;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=vector-store-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-store-memory.js","sourceRoot":"","sources":["../../../.claude/worktrees/agent-a1ae6f0b/packages/db/src/vector-store-memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { VectorFilter, VectorHybridSearchOptions, VectorSearchResult, VectorStore, VectorStoreConfig } from "./vector-store.js";
|
|
2
|
+
/** Minimal query interface accepted by the pgvector store. */
|
|
3
|
+
export interface PgQueryFn {
|
|
4
|
+
/** Execute a parameterised SQL statement and return rows. */
|
|
5
|
+
(sql: string, params?: unknown[]): Promise<Record<string, unknown>[]>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* PostgreSQL vector store powered by the pgvector extension.
|
|
9
|
+
*
|
|
10
|
+
* The store creates a `capstan_vectors` table (configurable via
|
|
11
|
+
* `config.tableName`) and uses the `<=>` cosine distance operator for
|
|
12
|
+
* similarity search. The pgvector extension is created automatically on
|
|
13
|
+
* first use if the connected role has the required permissions.
|
|
14
|
+
*
|
|
15
|
+
* No pgvector npm package is required — all interaction happens through raw
|
|
16
|
+
* parameterised SQL.
|
|
17
|
+
*/
|
|
18
|
+
export declare class PgVectorStore implements VectorStore {
|
|
19
|
+
private readonly _query;
|
|
20
|
+
private readonly _table;
|
|
21
|
+
private readonly _dimensions;
|
|
22
|
+
private _initialised;
|
|
23
|
+
constructor(config: VectorStoreConfig & {
|
|
24
|
+
connection: PgQueryFn;
|
|
25
|
+
});
|
|
26
|
+
/** @internal */
|
|
27
|
+
_ensureSchema(): Promise<void>;
|
|
28
|
+
upsert(id: string, vector: number[], metadata?: Record<string, unknown>): Promise<void>;
|
|
29
|
+
upsertBatch(items: ReadonlyArray<{
|
|
30
|
+
id: string;
|
|
31
|
+
vector: number[];
|
|
32
|
+
metadata?: Record<string, unknown>;
|
|
33
|
+
}>): Promise<void>;
|
|
34
|
+
search(query: number[], k: number, filter?: VectorFilter): Promise<VectorSearchResult[]>;
|
|
35
|
+
hybridSearch(query: string, queryVector: number[], k: number, opts?: VectorHybridSearchOptions): Promise<VectorSearchResult[]>;
|
|
36
|
+
remove(id: string): Promise<boolean>;
|
|
37
|
+
count(): Promise<number>;
|
|
38
|
+
private _validateDimensions;
|
|
39
|
+
/** Format a number array as a pgvector literal `[1,2,3]`. */
|
|
40
|
+
private _vec;
|
|
41
|
+
/** Quote a SQL identifier to prevent injection. */
|
|
42
|
+
private _qi;
|
|
43
|
+
/** Build a WHERE clause from a VectorFilter, starting param indices at `startIdx`. */
|
|
44
|
+
private _buildFilterClause;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=vector-store-pgvector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-store-pgvector.d.ts","sourceRoot":"","sources":["../../../.claude/worktrees/agent-a1ae6f0b/packages/db/src/vector-store-pgvector.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,YAAY,EACZ,yBAAyB,EACzB,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAE3B,8DAA8D;AAC9D,MAAM,WAAW,SAAS;IACxB,6DAA6D;IAC7D,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;CACvE;AAED;;;;;;;;;;GAUG;AACH,qBAAa,aAAc,YAAW,WAAW;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,YAAY,CAAS;gBAEjB,MAAM,EAAE,iBAAiB,GAAG;QAAE,UAAU,EAAE,SAAS,CAAA;KAAE;IAgBjE,gBAAgB;IACV,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IA6C9B,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBvF,WAAW,CACf,KAAK,EAAE,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,GACzF,OAAO,CAAC,IAAI,CAAC;IA6BV,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IA0BxF,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EAAE,EACrB,CAAC,EAAE,MAAM,EACT,IAAI,CAAC,EAAE,yBAAyB,GAC/B,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAkC1B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASpC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAY9B,OAAO,CAAC,mBAAmB;IAW3B,6DAA6D;IAC7D,OAAO,CAAC,IAAI;IAIZ,mDAAmD;IACnD,OAAO,CAAC,GAAG;IAIX,sFAAsF;IACtF,OAAO,CAAC,kBAAkB;CA0B3B"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// PgVectorStore — PostgreSQL pgvector-backed vector search
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// Uses raw SQL over a caller-supplied query function so there is no hard
|
|
6
|
+
// dependency on any specific PostgreSQL client library. The pgvector
|
|
7
|
+
// extension must be installed in the target database.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
/**
|
|
10
|
+
* PostgreSQL vector store powered by the pgvector extension.
|
|
11
|
+
*
|
|
12
|
+
* The store creates a `capstan_vectors` table (configurable via
|
|
13
|
+
* `config.tableName`) and uses the `<=>` cosine distance operator for
|
|
14
|
+
* similarity search. The pgvector extension is created automatically on
|
|
15
|
+
* first use if the connected role has the required permissions.
|
|
16
|
+
*
|
|
17
|
+
* No pgvector npm package is required — all interaction happens through raw
|
|
18
|
+
* parameterised SQL.
|
|
19
|
+
*/
|
|
20
|
+
export class PgVectorStore {
|
|
21
|
+
_query;
|
|
22
|
+
_table;
|
|
23
|
+
_dimensions;
|
|
24
|
+
_initialised = false;
|
|
25
|
+
constructor(config) {
|
|
26
|
+
if (!config.connection) {
|
|
27
|
+
throw new Error("PgVectorStore requires a `connection` query function.");
|
|
28
|
+
}
|
|
29
|
+
if (!config.dimensions) {
|
|
30
|
+
throw new Error("PgVectorStore requires `dimensions` to be specified.");
|
|
31
|
+
}
|
|
32
|
+
this._query = config.connection;
|
|
33
|
+
this._table = config.tableName ?? "capstan_vectors";
|
|
34
|
+
this._dimensions = config.dimensions;
|
|
35
|
+
}
|
|
36
|
+
// -------------------------------------------------------------------------
|
|
37
|
+
// Schema bootstrap
|
|
38
|
+
// -------------------------------------------------------------------------
|
|
39
|
+
/** @internal */
|
|
40
|
+
async _ensureSchema() {
|
|
41
|
+
if (this._initialised)
|
|
42
|
+
return;
|
|
43
|
+
try {
|
|
44
|
+
await this._query("CREATE EXTENSION IF NOT EXISTS vector");
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
48
|
+
throw new Error(`pgvector extension not found. Run: CREATE EXTENSION vector;\n` +
|
|
49
|
+
`Underlying error: ${message}`);
|
|
50
|
+
}
|
|
51
|
+
const table = this._table;
|
|
52
|
+
const dim = this._dimensions;
|
|
53
|
+
await this._query(`
|
|
54
|
+
CREATE TABLE IF NOT EXISTS ${this._qi(table)} (
|
|
55
|
+
id TEXT PRIMARY KEY,
|
|
56
|
+
embedding vector(${dim}) NOT NULL,
|
|
57
|
+
content TEXT NOT NULL DEFAULT '',
|
|
58
|
+
metadata JSONB NOT NULL DEFAULT '{}'::jsonb
|
|
59
|
+
)
|
|
60
|
+
`);
|
|
61
|
+
// Create an IVFFlat index if it does not already exist. The index
|
|
62
|
+
// requires at least one row so we wrap in a DO block that is safe to
|
|
63
|
+
// re-run.
|
|
64
|
+
await this._query(`
|
|
65
|
+
CREATE INDEX IF NOT EXISTS ${this._qi(table + "_embedding_idx")}
|
|
66
|
+
ON ${this._qi(table)}
|
|
67
|
+
USING ivfflat (embedding vector_cosine_ops)
|
|
68
|
+
WITH (lists = 100)
|
|
69
|
+
`).catch(() => {
|
|
70
|
+
// Index creation can fail on an empty table — that is fine, it will
|
|
71
|
+
// be retried lazily on the next search.
|
|
72
|
+
});
|
|
73
|
+
this._initialised = true;
|
|
74
|
+
}
|
|
75
|
+
// -------------------------------------------------------------------------
|
|
76
|
+
// VectorStore implementation
|
|
77
|
+
// -------------------------------------------------------------------------
|
|
78
|
+
async upsert(id, vector, metadata) {
|
|
79
|
+
this._validateDimensions(vector);
|
|
80
|
+
await this._ensureSchema();
|
|
81
|
+
const text = typeof metadata?.["text"] === "string" ? metadata["text"] : "";
|
|
82
|
+
const metaJson = JSON.stringify(metadata ?? {});
|
|
83
|
+
await this._query(`INSERT INTO ${this._qi(this._table)} (id, embedding, content, metadata)
|
|
84
|
+
VALUES ($1, $2::vector, $3, $4::jsonb)
|
|
85
|
+
ON CONFLICT (id) DO UPDATE
|
|
86
|
+
SET embedding = EXCLUDED.embedding,
|
|
87
|
+
content = EXCLUDED.content,
|
|
88
|
+
metadata = EXCLUDED.metadata`, [id, this._vec(vector), text, metaJson]);
|
|
89
|
+
}
|
|
90
|
+
async upsertBatch(items) {
|
|
91
|
+
if (items.length === 0)
|
|
92
|
+
return;
|
|
93
|
+
for (const item of items)
|
|
94
|
+
this._validateDimensions(item.vector);
|
|
95
|
+
await this._ensureSchema();
|
|
96
|
+
// Batch upserts using a single multi-row INSERT .. ON CONFLICT.
|
|
97
|
+
const valueClauses = [];
|
|
98
|
+
const params = [];
|
|
99
|
+
let idx = 1;
|
|
100
|
+
for (const item of items) {
|
|
101
|
+
const text = typeof item.metadata?.["text"] === "string" ? item.metadata["text"] : "";
|
|
102
|
+
const metaJson = JSON.stringify(item.metadata ?? {});
|
|
103
|
+
valueClauses.push(`($${idx}, $${idx + 1}::vector, $${idx + 2}, $${idx + 3}::jsonb)`);
|
|
104
|
+
params.push(item.id, this._vec(item.vector), text, metaJson);
|
|
105
|
+
idx += 4;
|
|
106
|
+
}
|
|
107
|
+
await this._query(`INSERT INTO ${this._qi(this._table)} (id, embedding, content, metadata)
|
|
108
|
+
VALUES ${valueClauses.join(", ")}
|
|
109
|
+
ON CONFLICT (id) DO UPDATE
|
|
110
|
+
SET embedding = EXCLUDED.embedding,
|
|
111
|
+
content = EXCLUDED.content,
|
|
112
|
+
metadata = EXCLUDED.metadata`, params);
|
|
113
|
+
}
|
|
114
|
+
async search(query, k, filter) {
|
|
115
|
+
if (query.length === 0)
|
|
116
|
+
return [];
|
|
117
|
+
this._validateDimensions(query);
|
|
118
|
+
await this._ensureSchema();
|
|
119
|
+
const { clause, params, nextIndex } = this._buildFilterClause(filter, 2);
|
|
120
|
+
const rows = await this._query(`SELECT id, metadata, 1 - (embedding <=> $1::vector) AS score
|
|
121
|
+
FROM ${this._qi(this._table)}
|
|
122
|
+
${clause}
|
|
123
|
+
ORDER BY embedding <=> $1::vector
|
|
124
|
+
LIMIT $${nextIndex}`, [this._vec(query), ...params, Math.max(1, k)]);
|
|
125
|
+
return rows.map((row) => {
|
|
126
|
+
const meta = typeof row["metadata"] === "string"
|
|
127
|
+
? JSON.parse(row["metadata"])
|
|
128
|
+
: row["metadata"];
|
|
129
|
+
const result = { id: String(row["id"]), score: Number(row["score"]) };
|
|
130
|
+
if (meta !== undefined)
|
|
131
|
+
result.metadata = meta;
|
|
132
|
+
return result;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async hybridSearch(query, queryVector, k, opts) {
|
|
136
|
+
if (query.length === 0 && queryVector.length === 0)
|
|
137
|
+
return [];
|
|
138
|
+
if (queryVector.length > 0)
|
|
139
|
+
this._validateDimensions(queryVector);
|
|
140
|
+
await this._ensureSchema();
|
|
141
|
+
const vectorWeight = opts?.vectorWeight ?? 0.7;
|
|
142
|
+
const keywordWeight = opts?.keywordWeight ?? 0.3;
|
|
143
|
+
const { clause, params, nextIndex } = this._buildFilterClause(opts?.filter, 3);
|
|
144
|
+
let idx = nextIndex;
|
|
145
|
+
// Use ts_rank for text relevance combined with cosine similarity.
|
|
146
|
+
const rows = await this._query(`SELECT id, metadata,
|
|
147
|
+
${vectorWeight} * (1 - (embedding <=> $1::vector))
|
|
148
|
+
+ ${keywordWeight} * COALESCE(ts_rank(to_tsvector('simple', content), plainto_tsquery('simple', $2)), 0)
|
|
149
|
+
AS score
|
|
150
|
+
FROM ${this._qi(this._table)}
|
|
151
|
+
${clause}
|
|
152
|
+
ORDER BY score DESC
|
|
153
|
+
LIMIT $${idx}`, [this._vec(queryVector), query, ...params, Math.max(1, k)]);
|
|
154
|
+
return rows.map((row) => {
|
|
155
|
+
const meta = typeof row["metadata"] === "string"
|
|
156
|
+
? JSON.parse(row["metadata"])
|
|
157
|
+
: row["metadata"];
|
|
158
|
+
const result = { id: String(row["id"]), score: Number(row["score"]) };
|
|
159
|
+
if (meta !== undefined)
|
|
160
|
+
result.metadata = meta;
|
|
161
|
+
return result;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
async remove(id) {
|
|
165
|
+
await this._ensureSchema();
|
|
166
|
+
const rows = await this._query(`DELETE FROM ${this._qi(this._table)} WHERE id = $1 RETURNING id`, [id]);
|
|
167
|
+
return rows.length > 0;
|
|
168
|
+
}
|
|
169
|
+
async count() {
|
|
170
|
+
await this._ensureSchema();
|
|
171
|
+
const rows = await this._query(`SELECT COUNT(*)::int AS count FROM ${this._qi(this._table)}`);
|
|
172
|
+
return Number(rows[0]?.["count"] ?? 0);
|
|
173
|
+
}
|
|
174
|
+
// -------------------------------------------------------------------------
|
|
175
|
+
// Internal helpers
|
|
176
|
+
// -------------------------------------------------------------------------
|
|
177
|
+
_validateDimensions(vector) {
|
|
178
|
+
if (vector.length === 0) {
|
|
179
|
+
throw new Error("Cannot store a zero-length vector.");
|
|
180
|
+
}
|
|
181
|
+
if (vector.length !== this._dimensions) {
|
|
182
|
+
throw new Error(`Dimension mismatch: expected ${this._dimensions}, got ${vector.length}.`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Format a number array as a pgvector literal `[1,2,3]`. */
|
|
186
|
+
_vec(v) {
|
|
187
|
+
return `[${v.join(",")}]`;
|
|
188
|
+
}
|
|
189
|
+
/** Quote a SQL identifier to prevent injection. */
|
|
190
|
+
_qi(identifier) {
|
|
191
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
192
|
+
}
|
|
193
|
+
/** Build a WHERE clause from a VectorFilter, starting param indices at `startIdx`. */
|
|
194
|
+
_buildFilterClause(filter, startIdx) {
|
|
195
|
+
if (!filter || Object.keys(filter).length === 0) {
|
|
196
|
+
return { clause: "", params: [], nextIndex: startIdx };
|
|
197
|
+
}
|
|
198
|
+
const parts = [];
|
|
199
|
+
const params = [];
|
|
200
|
+
let idx = startIdx;
|
|
201
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
202
|
+
// Use JSONB containment for metadata filtering.
|
|
203
|
+
const fragment = JSON.stringify({ [key]: value });
|
|
204
|
+
parts.push(`metadata @> $${idx}::jsonb`);
|
|
205
|
+
params.push(fragment);
|
|
206
|
+
idx++;
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
clause: `WHERE ${parts.join(" AND ")}`,
|
|
210
|
+
params,
|
|
211
|
+
nextIndex: idx,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=vector-store-pgvector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-store-pgvector.js","sourceRoot":"","sources":["../../../.claude/worktrees/agent-a1ae6f0b/packages/db/src/vector-store-pgvector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { VectorFilter, VectorHybridSearchOptions, VectorSearchResult, VectorStore, VectorStoreConfig } from "./vector-store.js";
|
|
2
|
+
/**
|
|
3
|
+
* Minimal interface for a `better-sqlite3` Database instance.
|
|
4
|
+
*
|
|
5
|
+
* We only declare the subset of the API we actually use so that callers are
|
|
6
|
+
* not forced to depend on `@types/better-sqlite3`.
|
|
7
|
+
*/
|
|
8
|
+
export interface SqliteConnection {
|
|
9
|
+
prepare(sql: string): {
|
|
10
|
+
run(...params: unknown[]): {
|
|
11
|
+
changes: number;
|
|
12
|
+
};
|
|
13
|
+
all(...params: unknown[]): Record<string, unknown>[];
|
|
14
|
+
get(...params: unknown[]): Record<string, unknown> | undefined;
|
|
15
|
+
};
|
|
16
|
+
exec(sql: string): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* SQLite vector store.
|
|
20
|
+
*
|
|
21
|
+
* Stores vectors as JSON text columns and loads them into memory for
|
|
22
|
+
* brute-force cosine search. The trade-off is durability with a simple
|
|
23
|
+
* dependency chain — no native extensions beyond `better-sqlite3`.
|
|
24
|
+
*/
|
|
25
|
+
export declare class SqliteVectorStore implements VectorStore {
|
|
26
|
+
private readonly _db;
|
|
27
|
+
private readonly _table;
|
|
28
|
+
private readonly _dimensions;
|
|
29
|
+
private _initialised;
|
|
30
|
+
constructor(config: VectorStoreConfig & {
|
|
31
|
+
connection: SqliteConnection;
|
|
32
|
+
});
|
|
33
|
+
/** @internal */
|
|
34
|
+
_ensureSchema(): void;
|
|
35
|
+
upsert(id: string, vector: number[], metadata?: Record<string, unknown>): Promise<void>;
|
|
36
|
+
upsertBatch(items: ReadonlyArray<{
|
|
37
|
+
id: string;
|
|
38
|
+
vector: number[];
|
|
39
|
+
metadata?: Record<string, unknown>;
|
|
40
|
+
}>): Promise<void>;
|
|
41
|
+
search(query: number[], k: number, filter?: VectorFilter): Promise<VectorSearchResult[]>;
|
|
42
|
+
hybridSearch(query: string, queryVector: number[], k: number, opts?: VectorHybridSearchOptions): Promise<VectorSearchResult[]>;
|
|
43
|
+
remove(id: string): Promise<boolean>;
|
|
44
|
+
count(): Promise<number>;
|
|
45
|
+
private _validateDimensions;
|
|
46
|
+
/** Load all stored rows, parsing JSON columns. */
|
|
47
|
+
private _loadAll;
|
|
48
|
+
/** Escape a SQL identifier (double-quote style). */
|
|
49
|
+
private _esc;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=vector-store-sqlite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-store-sqlite.d.ts","sourceRoot":"","sources":["../../../.claude/worktrees/agent-a1ae6f0b/packages/db/src/vector-store-sqlite.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,YAAY,EACZ,yBAAyB,EACzB,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAE3B;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG;QACpB,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;QAC/C,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;KAChE,CAAC;IACF,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AA2CD;;;;;;GAMG;AACH,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAmB;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,YAAY,CAAS;gBAEjB,MAAM,EAAE,iBAAiB,GAAG;QAAE,UAAU,EAAE,gBAAgB,CAAA;KAAE;IAaxE,gBAAgB;IAChB,aAAa,IAAI,IAAI;IAiBf,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBvF,WAAW,CACf,KAAK,EAAE,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,GACzF,OAAO,CAAC,IAAI,CAAC;IAqBV,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAkBxF,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EAAE,EACrB,CAAC,EAAE,MAAM,EACT,IAAI,CAAC,EAAE,yBAAyB,GAC/B,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAgC1B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQpC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAY9B,OAAO,CAAC,mBAAmB;IAW3B,kDAAkD;IAClD,OAAO,CAAC,QAAQ;IAahB,oDAAoD;IACpD,OAAO,CAAC,IAAI;CAGb"}
|