@nacre.work/core 0.0.0 → 0.1.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/LICENSE +202 -0
- package/NOTICE +9 -0
- package/dist/authz/filter.d.ts +54 -3
- package/dist/authz/filter.d.ts.map +1 -1
- package/dist/authz/filter.js +45 -9
- package/dist/authz/filter.js.map +1 -1
- package/dist/authz/index.d.ts +2 -2
- package/dist/authz/index.d.ts.map +1 -1
- package/dist/authz/index.js +1 -1
- package/dist/authz/index.js.map +1 -1
- package/dist/config.d.ts +33 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +137 -3
- package/dist/config.js.map +1 -1
- package/dist/db/client.d.ts +39 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +82 -0
- package/dist/db/client.js.map +1 -1
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +49 -0
- package/dist/db/migrate.js.map +1 -1
- package/dist/index.d.ts +15 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +57 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +97 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/metadata.d.ts +50 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +127 -0
- package/dist/metadata.js.map +1 -0
- package/dist/metrics.d.ts +18 -1
- package/dist/metrics.d.ts.map +1 -1
- package/dist/metrics.js +77 -2
- package/dist/metrics.js.map +1 -1
- package/dist/migrations/0008_authenticating_lookup.sql +124 -0
- package/dist/migrations/0009_refresh_tokens.sql +73 -0
- package/dist/migrations/0010_definer_search_path.sql +22 -0
- package/dist/migrations/0011_sweep_lease.sql +36 -0
- package/dist/migrations/0012_prune.sql +118 -0
- package/dist/migrations/0013_reindex.sql +65 -0
- package/dist/oauth.d.ts +45 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +53 -0
- package/dist/oauth.js.map +1 -0
- package/dist/observability.d.ts.map +1 -1
- package/dist/observability.js +81 -13
- package/dist/observability.js.map +1 -1
- package/dist/passwords.d.ts +37 -0
- package/dist/passwords.d.ts.map +1 -0
- package/dist/passwords.js +234 -0
- package/dist/passwords.js.map +1 -0
- package/dist/redis.d.ts +46 -0
- package/dist/redis.d.ts.map +1 -0
- package/dist/redis.js +234 -0
- package/dist/redis.js.map +1 -0
- package/dist/reindex.d.ts +87 -0
- package/dist/reindex.d.ts.map +1 -0
- package/dist/reindex.js +97 -0
- package/dist/reindex.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/vector/query.d.ts +49 -4
- package/dist/vector/query.d.ts.map +1 -1
- package/dist/vector/query.js +43 -10
- package/dist/vector/query.js.map +1 -1
- package/dist/vector/search.d.ts +109 -4
- package/dist/vector/search.d.ts.map +1 -1
- package/dist/vector/search.js +166 -7
- package/dist/vector/search.js.map +1 -1
- package/package.json +26 -8
package/dist/vector/query.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../vector/query.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../vector/query.ts"],"names":[],"mappings":"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"}
|
package/dist/vector/search.d.ts
CHANGED
|
@@ -1,16 +1,44 @@
|
|
|
1
|
-
import { type QueryablePlan } from '../authz/filter.js';
|
|
1
|
+
import { type Narrowing, type QueryablePlan } from '../authz/filter.js';
|
|
2
2
|
import { type Branch } from './query.js';
|
|
3
|
+
/**
|
|
4
|
+
* What Qdrant actually said.
|
|
5
|
+
*
|
|
6
|
+
* The REST client throws `Error: Bad Request` with the reason in a `data`
|
|
7
|
+
* property nobody looks at, so an unhandled one reaches a log as four words
|
|
8
|
+
* that name no collection, no vector and no cause. Both times a query in this
|
|
9
|
+
* repository was malformed, the message alone was useless and the reason was
|
|
10
|
+
* one line inside `data`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function explainQdrant(cause: unknown): string;
|
|
3
13
|
export interface VectorStoreOptions {
|
|
4
14
|
readonly url: string;
|
|
5
15
|
readonly apiKey?: string;
|
|
6
16
|
}
|
|
7
17
|
export interface SearchRequest {
|
|
8
18
|
readonly orgId: string;
|
|
9
|
-
|
|
19
|
+
/**
|
|
20
|
+
* The organization's collection, read from `organizations.vector_collection`.
|
|
21
|
+
*
|
|
22
|
+
* Not derived from the slug. It was, everywhere, and the column was written
|
|
23
|
+
* once at `init` and read by nothing — so a reindex that moved the pointer
|
|
24
|
+
* moved a pointer no query followed, and the copy it had just finished sat
|
|
25
|
+
* unused while search carried on against the old collection. The name is a
|
|
26
|
+
* value the database owns; deriving it in six places is what let the two
|
|
27
|
+
* disagree silently.
|
|
28
|
+
*/
|
|
29
|
+
readonly collection: string;
|
|
10
30
|
/** What the caller may reach. `none` is not accepted — see buildFilter. */
|
|
11
31
|
readonly plan: QueryablePlan;
|
|
12
32
|
readonly branches: readonly Branch[];
|
|
13
33
|
readonly topK: number;
|
|
34
|
+
/**
|
|
35
|
+
* A restriction the caller asked for, layered on top of the permission one.
|
|
36
|
+
*
|
|
37
|
+
* Still not a filter the caller assembles — it is a list of layer ids that
|
|
38
|
+
* `buildFilter` turns into a `must`, so it can only ever remove results. The
|
|
39
|
+
* distinction is the whole reason this is not `filter?: VectorFilter`.
|
|
40
|
+
*/
|
|
41
|
+
readonly narrow?: Narrowing;
|
|
14
42
|
}
|
|
15
43
|
export interface Hit {
|
|
16
44
|
readonly id: string;
|
|
@@ -32,7 +60,15 @@ export interface Hit {
|
|
|
32
60
|
export declare class VectorStore {
|
|
33
61
|
#private;
|
|
34
62
|
constructor(options: VectorStoreOptions);
|
|
35
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Create an organization's first collection, if it is not there.
|
|
65
|
+
*
|
|
66
|
+
* `collectionName(orgSlug)` is the *initial* name and only that. Once a
|
|
67
|
+
* reindex has rebuilt the collection the organization's name no longer
|
|
68
|
+
* derives from its slug, which is why every other method here takes the
|
|
69
|
+
* collection rather than working it out.
|
|
70
|
+
*/
|
|
71
|
+
ensureCollection(orgSlug: string, vectorName: string, size: number): Promise<string>;
|
|
36
72
|
/**
|
|
37
73
|
* Mark every point of a document deleted.
|
|
38
74
|
*
|
|
@@ -46,7 +82,68 @@ export declare class VectorStore {
|
|
|
46
82
|
* is tombstoned in Postgres but not here stays searchable until a background
|
|
47
83
|
* job gets to it. That window is exactly what invariant I5 forbids.
|
|
48
84
|
*/
|
|
49
|
-
tombstone(
|
|
85
|
+
tombstone(collection: string, documentId: string): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Replace the caller's metadata on every point of a document.
|
|
88
|
+
*
|
|
89
|
+
* `setPayload` under the reserved key, which merges at the top level and so
|
|
90
|
+
* leaves `org_id`, `deleted`, `acl_tags` and the rest exactly as they were —
|
|
91
|
+
* the namespace is what makes that safe rather than a list of fields to
|
|
92
|
+
* preserve.
|
|
93
|
+
*
|
|
94
|
+
* Whole-object replacement inside that key, not a merge: a caller sending
|
|
95
|
+
* `{source: "notion"}` after `{source: "confluence", team: "legal"}` means
|
|
96
|
+
* the document now has one tag, and merging would leave a tag they removed
|
|
97
|
+
* still matching filters. `PATCH` names the resource, not the field.
|
|
98
|
+
*
|
|
99
|
+
* The vectors are untouched. Re-embedding a document because a tag moved
|
|
100
|
+
* would make a bulk retag cost as much as a bulk ingest, which is the same
|
|
101
|
+
* argument the ACL retag path is built on.
|
|
102
|
+
*/
|
|
103
|
+
setMetadata(collection: string, documentId: string, metadata: Record<string, unknown>): Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* The named vectors a collection has, and their widths.
|
|
106
|
+
*
|
|
107
|
+
* The set is fixed when the collection is created. That is the fact the whole
|
|
108
|
+
* reindex design turns on, and it was worth checking rather than assuming:
|
|
109
|
+
* `update_collection` adjusts the parameters of vectors that already exist and
|
|
110
|
+
* answers `Not existing vector name error` for anything else, so there is no
|
|
111
|
+
* way to add one to a live collection.
|
|
112
|
+
*/
|
|
113
|
+
vectorsOf(collection: string): Promise<Record<string, number>>;
|
|
114
|
+
/**
|
|
115
|
+
* Copy an organization's collection into a new one that also has room for a
|
|
116
|
+
* new model.
|
|
117
|
+
*
|
|
118
|
+
* This exists because a named vector cannot be added to a collection after it
|
|
119
|
+
* is created. The way around that is not to add one — it is to create a
|
|
120
|
+
* collection that already has the slot, move the points across as they are,
|
|
121
|
+
* and switch which collection the organization points at.
|
|
122
|
+
*
|
|
123
|
+
* **No embeddings are computed here.** The vectors that come out of the old
|
|
124
|
+
* collection go into the new one unchanged. That is what makes this the cheap
|
|
125
|
+
* half of a model migration: the expensive half — computing vectors with the
|
|
126
|
+
* new model — happens afterwards, one layer at a time, into the slot this
|
|
127
|
+
* created.
|
|
128
|
+
*
|
|
129
|
+
* Idempotent by construction: if the target already exists it is deleted and
|
|
130
|
+
* rebuilt. A half-copied collection is worse than none, and there is no way to
|
|
131
|
+
* tell one from a complete one by looking at it — the source is still live and
|
|
132
|
+
* still authoritative until the pointer moves, so throwing away a partial
|
|
133
|
+
* attempt costs only the time it took.
|
|
134
|
+
*/
|
|
135
|
+
copyCollection(input: {
|
|
136
|
+
from: string;
|
|
137
|
+
to: string;
|
|
138
|
+
/** Added alongside everything the source already has. */
|
|
139
|
+
addVector: {
|
|
140
|
+
name: string;
|
|
141
|
+
size: number;
|
|
142
|
+
};
|
|
143
|
+
/** Points per scroll page and per upsert. */
|
|
144
|
+
batch?: number;
|
|
145
|
+
onProgress?: (copied: number) => void;
|
|
146
|
+
}): Promise<void>;
|
|
50
147
|
search(request: SearchRequest): Promise<readonly Hit[]>;
|
|
51
148
|
/**
|
|
52
149
|
* Re-check the tenant on the way out.
|
|
@@ -57,6 +154,14 @@ export declare class VectorStore {
|
|
|
57
154
|
* and a bug that produces one cross-tenant row will produce more.
|
|
58
155
|
*/
|
|
59
156
|
static assertTenant(orgId: string, hits: readonly Hit[]): readonly Hit[];
|
|
157
|
+
/**
|
|
158
|
+
* Whether the vector store is answering.
|
|
159
|
+
*
|
|
160
|
+
* `getCollections` rather than a bare TCP connect: Qdrant accepting a socket
|
|
161
|
+
* while refusing queries is the failure a readiness probe exists to catch,
|
|
162
|
+
* and the Compose healthcheck already covers the socket.
|
|
163
|
+
*/
|
|
164
|
+
ready(): Promise<boolean>;
|
|
60
165
|
close(): Promise<void>;
|
|
61
166
|
}
|
|
62
167
|
//# sourceMappingURL=search.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../vector/search.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../vector/search.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgC,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACrG,OAAO,EAAqF,KAAK,MAAM,EAAE,MAAM,YAAY,CAAA;AAE3H;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGpD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB;;;;;;;;;OASG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAC5B;AAED,MAAM,WAAW,GAAG;IAClB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC1C;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,WAAW;;gBAGV,OAAO,EAAE,kBAAkB;IAWvC;;;;;;;OAOG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAoB1F;;;;;;;;;;;;OAYG;IACG,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtE;;;;;;;;;;;;;;;;OAgBG;IACG,WAAW,CACf,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC;IAehB;;;;;;;;OAQG;IACG,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAQpE;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,cAAc,CAAC,KAAK,EAAE;QAC1B,IAAI,EAAE,MAAM,CAAA;QACZ,EAAE,EAAE,MAAM,CAAA;QACV,yDAAyD;QACzD,SAAS,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;QACzC,6CAA6C;QAC7C,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;KACtC,GAAG,OAAO,CAAC,IAAI,CAAC;IA+DX,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,GAAG,EAAE,CAAC;IA4B7D;;;;;;;OAOG;IACH,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,EAAE,GAAG,SAAS,GAAG,EAAE;IAYxE;;;;;;OAMG;IACG,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;IAKzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
|
package/dist/vector/search.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { QdrantClient } from '@qdrant/js-client-rest';
|
|
2
|
-
import { buildFilter } from '../authz/filter.js';
|
|
3
|
-
import { buildHybridQuery, collectionConfig, collectionName, PAYLOAD_INDEXES } from './query.js';
|
|
2
|
+
import { buildFilter, METADATA_PREFIX } from '../authz/filter.js';
|
|
3
|
+
import { buildHybridQuery, collectionConfig, collectionName, PAYLOAD_INDEXES, vectorParams } from './query.js';
|
|
4
|
+
/**
|
|
5
|
+
* What Qdrant actually said.
|
|
6
|
+
*
|
|
7
|
+
* The REST client throws `Error: Bad Request` with the reason in a `data`
|
|
8
|
+
* property nobody looks at, so an unhandled one reaches a log as four words
|
|
9
|
+
* that name no collection, no vector and no cause. Both times a query in this
|
|
10
|
+
* repository was malformed, the message alone was useless and the reason was
|
|
11
|
+
* one line inside `data`.
|
|
12
|
+
*/
|
|
13
|
+
export function explainQdrant(cause) {
|
|
14
|
+
const data = cause?.data;
|
|
15
|
+
return data === undefined ? String(cause) : `${String(cause)} — ${JSON.stringify(data)}`;
|
|
16
|
+
}
|
|
4
17
|
/**
|
|
5
18
|
* The vector store.
|
|
6
19
|
*
|
|
@@ -23,11 +36,19 @@ export class VectorStore {
|
|
|
23
36
|
? { url: options.url }
|
|
24
37
|
: { url: options.url, apiKey: options.apiKey });
|
|
25
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Create an organization's first collection, if it is not there.
|
|
41
|
+
*
|
|
42
|
+
* `collectionName(orgSlug)` is the *initial* name and only that. Once a
|
|
43
|
+
* reindex has rebuilt the collection the organization's name no longer
|
|
44
|
+
* derives from its slug, which is why every other method here takes the
|
|
45
|
+
* collection rather than working it out.
|
|
46
|
+
*/
|
|
26
47
|
async ensureCollection(orgSlug, vectorName, size) {
|
|
27
48
|
const name = collectionName(orgSlug);
|
|
28
49
|
const existing = await this.#client.getCollections();
|
|
29
50
|
if (existing.collections.some((c) => c.name === name))
|
|
30
|
-
return;
|
|
51
|
+
return name;
|
|
31
52
|
await this.#client.createCollection(name, collectionConfig(vectorName, size));
|
|
32
53
|
// Created here rather than left to an operator: a filter that falls back to
|
|
33
54
|
// a scan is a latency problem that only shows up at a customer's volume.
|
|
@@ -38,6 +59,7 @@ export class VectorStore {
|
|
|
38
59
|
wait: true,
|
|
39
60
|
});
|
|
40
61
|
}
|
|
62
|
+
return name;
|
|
41
63
|
}
|
|
42
64
|
/**
|
|
43
65
|
* Mark every point of a document deleted.
|
|
@@ -52,21 +74,147 @@ export class VectorStore {
|
|
|
52
74
|
* is tombstoned in Postgres but not here stays searchable until a background
|
|
53
75
|
* job gets to it. That window is exactly what invariant I5 forbids.
|
|
54
76
|
*/
|
|
55
|
-
async tombstone(
|
|
56
|
-
await this.#client.setPayload(
|
|
77
|
+
async tombstone(collection, documentId) {
|
|
78
|
+
await this.#client.setPayload(collection, {
|
|
57
79
|
wait: true,
|
|
58
80
|
payload: { deleted: true },
|
|
59
81
|
filter: { must: [{ key: 'doc_id', match: { value: documentId } }] },
|
|
60
82
|
});
|
|
61
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Replace the caller's metadata on every point of a document.
|
|
86
|
+
*
|
|
87
|
+
* `setPayload` under the reserved key, which merges at the top level and so
|
|
88
|
+
* leaves `org_id`, `deleted`, `acl_tags` and the rest exactly as they were —
|
|
89
|
+
* the namespace is what makes that safe rather than a list of fields to
|
|
90
|
+
* preserve.
|
|
91
|
+
*
|
|
92
|
+
* Whole-object replacement inside that key, not a merge: a caller sending
|
|
93
|
+
* `{source: "notion"}` after `{source: "confluence", team: "legal"}` means
|
|
94
|
+
* the document now has one tag, and merging would leave a tag they removed
|
|
95
|
+
* still matching filters. `PATCH` names the resource, not the field.
|
|
96
|
+
*
|
|
97
|
+
* The vectors are untouched. Re-embedding a document because a tag moved
|
|
98
|
+
* would make a bulk retag cost as much as a bulk ingest, which is the same
|
|
99
|
+
* argument the ACL retag path is built on.
|
|
100
|
+
*/
|
|
101
|
+
async setMetadata(collection, documentId, metadata) {
|
|
102
|
+
try {
|
|
103
|
+
await this.#client.setPayload(collection, {
|
|
104
|
+
wait: true,
|
|
105
|
+
payload: { [METADATA_PREFIX]: metadata },
|
|
106
|
+
filter: { must: [{ key: 'doc_id', match: { value: documentId } }] },
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
catch (cause) {
|
|
110
|
+
throw new Error(`metadata write to ${collection} rejected: ${explainQdrant(cause)}`, { cause });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The named vectors a collection has, and their widths.
|
|
115
|
+
*
|
|
116
|
+
* The set is fixed when the collection is created. That is the fact the whole
|
|
117
|
+
* reindex design turns on, and it was worth checking rather than assuming:
|
|
118
|
+
* `update_collection` adjusts the parameters of vectors that already exist and
|
|
119
|
+
* answers `Not existing vector name error` for anything else, so there is no
|
|
120
|
+
* way to add one to a live collection.
|
|
121
|
+
*/
|
|
122
|
+
async vectorsOf(collection) {
|
|
123
|
+
const info = await this.#client.getCollection(collection);
|
|
124
|
+
const vectors = (info.config?.params?.vectors ?? {});
|
|
125
|
+
return Object.fromEntries(Object.entries(vectors).map(([name, v]) => [name, Number(v.size ?? 0)]));
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Copy an organization's collection into a new one that also has room for a
|
|
129
|
+
* new model.
|
|
130
|
+
*
|
|
131
|
+
* This exists because a named vector cannot be added to a collection after it
|
|
132
|
+
* is created. The way around that is not to add one — it is to create a
|
|
133
|
+
* collection that already has the slot, move the points across as they are,
|
|
134
|
+
* and switch which collection the organization points at.
|
|
135
|
+
*
|
|
136
|
+
* **No embeddings are computed here.** The vectors that come out of the old
|
|
137
|
+
* collection go into the new one unchanged. That is what makes this the cheap
|
|
138
|
+
* half of a model migration: the expensive half — computing vectors with the
|
|
139
|
+
* new model — happens afterwards, one layer at a time, into the slot this
|
|
140
|
+
* created.
|
|
141
|
+
*
|
|
142
|
+
* Idempotent by construction: if the target already exists it is deleted and
|
|
143
|
+
* rebuilt. A half-copied collection is worse than none, and there is no way to
|
|
144
|
+
* tell one from a complete one by looking at it — the source is still live and
|
|
145
|
+
* still authoritative until the pointer moves, so throwing away a partial
|
|
146
|
+
* attempt costs only the time it took.
|
|
147
|
+
*/
|
|
148
|
+
async copyCollection(input) {
|
|
149
|
+
const existing = await this.vectorsOf(input.from);
|
|
150
|
+
if (input.addVector.name in existing) {
|
|
151
|
+
throw new Error(`${input.from} already has a vector called ${input.addVector.name}; nothing to copy for`);
|
|
152
|
+
}
|
|
153
|
+
const vectors = {};
|
|
154
|
+
for (const [name, size] of Object.entries(existing)) {
|
|
155
|
+
vectors[name] = vectorParams(size);
|
|
156
|
+
}
|
|
157
|
+
vectors[input.addVector.name] = vectorParams(input.addVector.size);
|
|
158
|
+
// Rebuilt rather than resumed. See the note above.
|
|
159
|
+
await this.#client.deleteCollection(input.to).catch(() => undefined);
|
|
160
|
+
await this.#client.createCollection(input.to, {
|
|
161
|
+
vectors: vectors,
|
|
162
|
+
sparse_vectors: { bm25: {} },
|
|
163
|
+
optimizers_config: { default_segment_number: 4 },
|
|
164
|
+
on_disk_payload: true,
|
|
165
|
+
});
|
|
166
|
+
for (const index of PAYLOAD_INDEXES) {
|
|
167
|
+
await this.#client.createPayloadIndex(input.to, {
|
|
168
|
+
field_name: index.field_name,
|
|
169
|
+
field_schema: index.field_schema,
|
|
170
|
+
wait: true,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
const batch = input.batch ?? 256;
|
|
174
|
+
let offset = undefined;
|
|
175
|
+
let copied = 0;
|
|
176
|
+
do {
|
|
177
|
+
const page = await this.#client.scroll(input.from, {
|
|
178
|
+
limit: batch,
|
|
179
|
+
with_payload: true,
|
|
180
|
+
with_vector: true,
|
|
181
|
+
...(offset === undefined || offset === null ? {} : { offset }),
|
|
182
|
+
});
|
|
183
|
+
const points = page.points ?? [];
|
|
184
|
+
if (points.length > 0) {
|
|
185
|
+
await this.#client.upsert(input.to, {
|
|
186
|
+
wait: true,
|
|
187
|
+
points: points.map((p) => ({
|
|
188
|
+
id: p.id,
|
|
189
|
+
// Whatever the source had, unchanged. The new slot stays empty
|
|
190
|
+
// until a layer is reindexed into it.
|
|
191
|
+
vector: p.vector,
|
|
192
|
+
payload: p.payload ?? {},
|
|
193
|
+
})),
|
|
194
|
+
});
|
|
195
|
+
copied += points.length;
|
|
196
|
+
input.onProgress?.(copied);
|
|
197
|
+
}
|
|
198
|
+
offset = page.next_page_offset;
|
|
199
|
+
} while (offset !== undefined && offset !== null);
|
|
200
|
+
}
|
|
62
201
|
async search(request) {
|
|
63
|
-
const filter = buildFilter(request.orgId, request.plan);
|
|
202
|
+
const filter = buildFilter(request.orgId, request.plan, request.narrow);
|
|
64
203
|
const query = buildHybridQuery({
|
|
65
204
|
branches: request.branches,
|
|
66
205
|
filter,
|
|
67
206
|
limit: request.topK,
|
|
68
207
|
});
|
|
69
|
-
|
|
208
|
+
let result;
|
|
209
|
+
try {
|
|
210
|
+
result = await this.#client.query(request.collection, query);
|
|
211
|
+
}
|
|
212
|
+
catch (cause) {
|
|
213
|
+
// Named, because the query has as many branches as the organization has
|
|
214
|
+
// models and "Bad Request" does not say which one Qdrant objected to.
|
|
215
|
+
throw new Error(`query against ${request.collection} using ` +
|
|
216
|
+
`${query.prefetch.map((b) => b.using).join(', ')} rejected: ${explainQdrant(cause)}`, { cause });
|
|
217
|
+
}
|
|
70
218
|
return result.points.map((p) => ({
|
|
71
219
|
id: String(p.id),
|
|
72
220
|
score: p.score,
|
|
@@ -90,6 +238,17 @@ export class VectorStore {
|
|
|
90
238
|
}
|
|
91
239
|
return hits;
|
|
92
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Whether the vector store is answering.
|
|
243
|
+
*
|
|
244
|
+
* `getCollections` rather than a bare TCP connect: Qdrant accepting a socket
|
|
245
|
+
* while refusing queries is the failure a readiness probe exists to catch,
|
|
246
|
+
* and the Compose healthcheck already covers the socket.
|
|
247
|
+
*/
|
|
248
|
+
async ready() {
|
|
249
|
+
await this.#client.getCollections();
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
93
252
|
async close() {
|
|
94
253
|
// The REST client holds no pool; this exists so callers have one shape to
|
|
95
254
|
// depend on when it does.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../vector/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAErD,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../vector/search.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nacre.work/core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Nacre core: data model, permission resolver, and shared types",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/nacre-work/nacre.git",
|
|
@@ -10,10 +10,6 @@
|
|
|
10
10
|
"homepage": "https://nacre.work",
|
|
11
11
|
"license": "Apache-2.0",
|
|
12
12
|
"type": "module",
|
|
13
|
-
"scripts": {
|
|
14
|
-
"build": "tsc -b && node ./scripts/copy-migrations.mjs",
|
|
15
|
-
"dev": "tsx watch index.ts"
|
|
16
|
-
},
|
|
17
13
|
"publishConfig": {
|
|
18
14
|
"access": "public"
|
|
19
15
|
},
|
|
@@ -26,7 +22,9 @@
|
|
|
26
22
|
}
|
|
27
23
|
},
|
|
28
24
|
"files": [
|
|
29
|
-
"dist"
|
|
25
|
+
"dist",
|
|
26
|
+
"LICENSE",
|
|
27
|
+
"NOTICE"
|
|
30
28
|
],
|
|
31
29
|
"dependencies": {
|
|
32
30
|
"@qdrant/js-client-rest": "^1.18.0",
|
|
@@ -35,5 +33,25 @@
|
|
|
35
33
|
"devDependencies": {
|
|
36
34
|
"@types/node": "^26.1.2",
|
|
37
35
|
"jose": "^6.2.7"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"nacre",
|
|
39
|
+
"rag",
|
|
40
|
+
"permissions",
|
|
41
|
+
"access-control",
|
|
42
|
+
"authorization",
|
|
43
|
+
"vector-search",
|
|
44
|
+
"self-hosted"
|
|
45
|
+
],
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/nacre-work/nacre/issues"
|
|
48
|
+
},
|
|
49
|
+
"author": "Nacre",
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=22"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsc -b && node ./scripts/copy-migrations.mjs",
|
|
55
|
+
"dev": "tsx watch index.ts"
|
|
38
56
|
}
|
|
39
|
-
}
|
|
57
|
+
}
|