ragpack-js 1.0.0 → 1.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/README.md +43 -4
- package/dist/index.cjs +75 -2
- package/dist/index.d.cts +129 -12
- package/dist/index.d.ts +129 -12
- package/dist/index.js +75 -2
- package/package.json +11 -6
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ console.log(answer);
|
|
|
41
41
|
// Semantic search (without LLM)
|
|
42
42
|
const results = await collection.findSimilar({ query: "how does auth work?", topK: 5 });
|
|
43
43
|
for (const r of results) {
|
|
44
|
-
console.log(r.
|
|
44
|
+
console.log(r.vector_similarity, r.chunk_text);
|
|
45
45
|
}
|
|
46
46
|
```
|
|
47
47
|
|
|
@@ -72,12 +72,15 @@ Returns a `CollectionClient` scoped to that collection.
|
|
|
72
72
|
| `ingest(file, filename?)` | Upload a file directly |
|
|
73
73
|
| `ingest({ uri, mimeType? })` | Ingest from a URL or S3 URI, MIME type auto-detected if omitted |
|
|
74
74
|
| `rag(options)` | Full RAG pipeline — retrieves chunks and returns an LLM answer |
|
|
75
|
-
| `findSimilar(
|
|
75
|
+
| `findSimilar(options)` | Hybrid (vector + keyword) search without LLM, returns ranked chunks |
|
|
76
76
|
| `jobs.list()` | List ingestion jobs for this collection |
|
|
77
77
|
| `jobs.get(id)` | Get a single job by ID |
|
|
78
78
|
| `jobs.waitUntilComplete(id)` | Poll until job is `complete` or `failed` |
|
|
79
79
|
| `documents.list(options?)` | List indexed documents |
|
|
80
|
+
| `documents.get(id)` | Get a single document by ID |
|
|
81
|
+
| `documents.metadata(id)` | Get a document's typed metadata field values |
|
|
80
82
|
| `documents.rename(id, name)` | Set the display name of a document |
|
|
83
|
+
| `documents.update(id, options)` | Update a document's name, `extraJson`, and/or typed metadata |
|
|
81
84
|
| `documents.delete(id)` | Delete a document and its chunks |
|
|
82
85
|
|
|
83
86
|
#### `rag(options)`
|
|
@@ -89,18 +92,54 @@ const { answer, chunks } = await collection.rag({
|
|
|
89
92
|
query: "How do I reset my password?",
|
|
90
93
|
// All options below are optional
|
|
91
94
|
promptSlug: "basic_rag", // defaults to "basic_rag" if omitted
|
|
92
|
-
topK:
|
|
95
|
+
topK: 2, // number of chunks to retrieve (default: 2)
|
|
93
96
|
model: "gpt-4o", // LLM model; falls back to server default
|
|
94
97
|
minSimilarity: 70, // drop chunks below this similarity score (0–100)
|
|
98
|
+
filters: { mime_type: "application/pdf" },
|
|
95
99
|
});
|
|
96
100
|
|
|
97
101
|
console.log(answer);
|
|
98
102
|
|
|
99
103
|
for (const chunk of chunks) {
|
|
100
|
-
console.log(chunk.
|
|
104
|
+
console.log(chunk.vector_similarity, chunk.chunk_text);
|
|
101
105
|
}
|
|
102
106
|
```
|
|
103
107
|
|
|
108
|
+
#### Hybrid (vector + keyword) search
|
|
109
|
+
|
|
110
|
+
`findSimilar` and `rag` run hybrid search by default: a vector pass and a keyword/BM25 pass are fused server-side via weighted RRF (semantic-favored 7:3). Each result carries `vector_similarity`, `keyword_bm25_score`, `rrf_score`, and `rrf_score_normalized` (0–100, normalized so the batch's top result is always 100).
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const results = await collection.findSimilar({
|
|
114
|
+
query: "password reset",
|
|
115
|
+
vectorSearchOnly: false, // set true to skip the keyword pass entirely
|
|
116
|
+
hybridSettings: {
|
|
117
|
+
semanticWeight: 0.7,
|
|
118
|
+
fullTextWeight: 0.3,
|
|
119
|
+
rrfK: 60,
|
|
120
|
+
fullTextLimit: 200,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Filtering by metadata
|
|
126
|
+
|
|
127
|
+
Both `findSimilar` and `rag` accept a `filters` option — a MongoDB-style expression compiled server-side into a predicate over a document's built-in (`mime_type`, `source_name`, `file_uri`, `created_at`, `updated_at`, …) and registered metadata fields.
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
await collection.findSimilar({
|
|
131
|
+
query: "refund policy",
|
|
132
|
+
filters: {
|
|
133
|
+
$and: [
|
|
134
|
+
{ mime_type: "application/pdf" },
|
|
135
|
+
{ $or: [{ tags: { $contains: "billing" } }, { created_at: { $gte: "7 days ago" } }] },
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Supported operators: `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$exists`, `$like`/`$ilike` (string fields), `$contains`/`$containsAny`/`$containsAll` (array fields), plus `$and`/`$or` for nesting.
|
|
142
|
+
|
|
104
143
|
#### Prompt templates
|
|
105
144
|
|
|
106
145
|
Three built-in prompts are always available: `basic_rag`, `rag_with_citations`, and `concise_rag`. List all available prompts (including any you've created in the admin UI) with:
|
package/dist/index.cjs
CHANGED
|
@@ -118,6 +118,25 @@ var DocumentsResource = class {
|
|
|
118
118
|
);
|
|
119
119
|
return r.documents;
|
|
120
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Get a single document by ID.
|
|
123
|
+
* @param id - The document ID.
|
|
124
|
+
*/
|
|
125
|
+
get(id) {
|
|
126
|
+
return this.req(`/collections/${this.slug}/documents/${id}`);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get this document's typed metadata field values.
|
|
130
|
+
* A field is only included if its value is identical across every chunk
|
|
131
|
+
* of the document — this avoids showing a value that's mid-sync.
|
|
132
|
+
* @param id - The document ID.
|
|
133
|
+
*/
|
|
134
|
+
async metadata(id) {
|
|
135
|
+
const r = await this.req(
|
|
136
|
+
`/collections/${this.slug}/documents/${id}/metadata`
|
|
137
|
+
);
|
|
138
|
+
return r.metadata;
|
|
139
|
+
}
|
|
121
140
|
/**
|
|
122
141
|
* Rename a document.
|
|
123
142
|
* @param id - The document ID.
|
|
@@ -129,6 +148,32 @@ var DocumentsResource = class {
|
|
|
129
148
|
body: JSON.stringify({ name })
|
|
130
149
|
});
|
|
131
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Update a document's name, extra_json, and/or typed metadata.
|
|
153
|
+
* `metadata` keys that aren't registered fields on this collection (or whose
|
|
154
|
+
* value doesn't match the field's declared type) are silently dropped by
|
|
155
|
+
* the server — the request still succeeds, with no signal for which keys
|
|
156
|
+
* landed. Register fields first via the metadata-fields admin API.
|
|
157
|
+
* @param id - The document ID.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```ts
|
|
161
|
+
* await collection.documents.update(id, {
|
|
162
|
+
* metadata: { reviewed: true },
|
|
163
|
+
* extraJson: JSON.stringify({ source: "zendesk" }),
|
|
164
|
+
* });
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
update(id, options) {
|
|
168
|
+
return this.req(`/collections/${this.slug}/documents/${id}`, {
|
|
169
|
+
method: "PATCH",
|
|
170
|
+
body: JSON.stringify({
|
|
171
|
+
...options.name !== void 0 && { name: options.name },
|
|
172
|
+
...options.extraJson !== void 0 && { extra_json: options.extraJson },
|
|
173
|
+
...options.metadata !== void 0 && { metadata: options.metadata }
|
|
174
|
+
})
|
|
175
|
+
});
|
|
176
|
+
}
|
|
132
177
|
/**
|
|
133
178
|
* Delete a document and all its chunks from this collection.
|
|
134
179
|
* @param id - The document ID.
|
|
@@ -140,6 +185,29 @@ var DocumentsResource = class {
|
|
|
140
185
|
}
|
|
141
186
|
};
|
|
142
187
|
|
|
188
|
+
// src/hybrid.ts
|
|
189
|
+
function buildHybridBody(options) {
|
|
190
|
+
const { filters, vectorSearchOnly, hybridSettings } = options;
|
|
191
|
+
return {
|
|
192
|
+
...filters !== void 0 && { filters },
|
|
193
|
+
...vectorSearchOnly !== void 0 && { vector_search_only: vectorSearchOnly },
|
|
194
|
+
...hybridSettings !== void 0 && {
|
|
195
|
+
hybrid_settings: {
|
|
196
|
+
...hybridSettings.fullTextWeight !== void 0 && {
|
|
197
|
+
full_text_weight: hybridSettings.fullTextWeight
|
|
198
|
+
},
|
|
199
|
+
...hybridSettings.semanticWeight !== void 0 && {
|
|
200
|
+
semantic_weight: hybridSettings.semanticWeight
|
|
201
|
+
},
|
|
202
|
+
...hybridSettings.rrfK !== void 0 && { rrf_k: hybridSettings.rrfK },
|
|
203
|
+
...hybridSettings.fullTextLimit !== void 0 && {
|
|
204
|
+
full_text_limit: hybridSettings.fullTextLimit
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
143
211
|
// src/resources/query.ts
|
|
144
212
|
var QueryResource = class {
|
|
145
213
|
constructor(req, slug) {
|
|
@@ -155,7 +223,11 @@ var QueryResource = class {
|
|
|
155
223
|
`/collections/${this.slug}/query`,
|
|
156
224
|
{
|
|
157
225
|
method: "POST",
|
|
158
|
-
body: JSON.stringify({
|
|
226
|
+
body: JSON.stringify({
|
|
227
|
+
query: options.query,
|
|
228
|
+
top_k: options.topK ?? 5,
|
|
229
|
+
...buildHybridBody(options)
|
|
230
|
+
})
|
|
159
231
|
}
|
|
160
232
|
);
|
|
161
233
|
return r.results;
|
|
@@ -215,7 +287,8 @@ var CollectionClient = class {
|
|
|
215
287
|
top_k: options.topK ?? 5,
|
|
216
288
|
...options.promptSlug ? { prompt_slug: options.promptSlug } : {},
|
|
217
289
|
...options.model ? { model: options.model } : {},
|
|
218
|
-
...options.minSimilarity != null ? { min_similarity: options.minSimilarity } : {}
|
|
290
|
+
...options.minSimilarity != null ? { min_similarity: options.minSimilarity } : {},
|
|
291
|
+
...buildHybridBody(options)
|
|
219
292
|
})
|
|
220
293
|
});
|
|
221
294
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -74,7 +74,14 @@ interface RagChunk {
|
|
|
74
74
|
chunk_index: number;
|
|
75
75
|
chunk_header: string | null;
|
|
76
76
|
chunk_text: string | null;
|
|
77
|
-
similarity
|
|
77
|
+
/** Cosine similarity score between 0 and 100. Higher is more relevant. */
|
|
78
|
+
vector_similarity: number;
|
|
79
|
+
/** Raw BM25 score from the keyword channel; present only for hybrid results. */
|
|
80
|
+
keyword_bm25_score?: number;
|
|
81
|
+
/** Weighted RRF fusion score, normalized so this batch's top result is 100. */
|
|
82
|
+
rrf_score_normalized?: number;
|
|
83
|
+
/** Raw RRF fusion score; only comparable within this query's own weights/k. */
|
|
84
|
+
rrf_score?: number;
|
|
78
85
|
}
|
|
79
86
|
interface RagResult {
|
|
80
87
|
formatted_prompt: string;
|
|
@@ -87,13 +94,73 @@ interface QueryResult {
|
|
|
87
94
|
file_uri: string;
|
|
88
95
|
mime_type: string;
|
|
89
96
|
chunk_index: number;
|
|
97
|
+
chunk_header: string | null;
|
|
90
98
|
/** The matched text chunk. */
|
|
91
99
|
chunk_text: string | null;
|
|
92
100
|
/** Optional metadata attached at ingest time. */
|
|
93
101
|
extra_json: string | null;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
/** Typed metadata field values registered for this collection. */
|
|
103
|
+
metadata?: Record<string, unknown>;
|
|
104
|
+
vector_distance: number;
|
|
105
|
+
/** Cosine similarity score between 0 and 100. Higher is more relevant. */
|
|
106
|
+
vector_similarity: number;
|
|
107
|
+
/** Raw BM25 score from the keyword channel; present only for hybrid results. */
|
|
108
|
+
keyword_bm25_score?: number;
|
|
109
|
+
/** Weighted RRF fusion score, normalized so this batch's top result is 100. */
|
|
110
|
+
rrf_score_normalized?: number;
|
|
111
|
+
/** Raw RRF fusion score; only comparable within this query's own weights/k. */
|
|
112
|
+
rrf_score?: number;
|
|
113
|
+
}
|
|
114
|
+
type FilterValue = string | number | boolean;
|
|
115
|
+
/** Operators usable against a single field in a {@link FilterExpression}. */
|
|
116
|
+
interface FilterOps {
|
|
117
|
+
$eq?: FilterValue;
|
|
118
|
+
$ne?: FilterValue;
|
|
119
|
+
$gt?: FilterValue;
|
|
120
|
+
$gte?: FilterValue;
|
|
121
|
+
$lt?: FilterValue;
|
|
122
|
+
$lte?: FilterValue;
|
|
123
|
+
$in?: FilterValue[];
|
|
124
|
+
$nin?: FilterValue[];
|
|
125
|
+
$exists?: boolean;
|
|
126
|
+
/** str/timestamp fields only. */
|
|
127
|
+
$like?: string;
|
|
128
|
+
/** str fields only. */
|
|
129
|
+
$ilike?: string;
|
|
130
|
+
/** arr fields only. */
|
|
131
|
+
$contains?: string;
|
|
132
|
+
/** arr fields only. */
|
|
133
|
+
$containsAny?: string[];
|
|
134
|
+
/** arr fields only. */
|
|
135
|
+
$containsAll?: string[];
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* MongoDB-style filter expression, compiled server-side into a predicate over
|
|
139
|
+
* a document's built-in and registered metadata fields.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* { mime_type: "application/pdf", score: { $gte: 4 } }
|
|
144
|
+
* { $or: [{ tags: { $contains: "urgent" } }, { created_at: { $gte: "7 days ago" } }] }
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
type FilterExpression = {
|
|
148
|
+
$and: FilterExpression[];
|
|
149
|
+
} | {
|
|
150
|
+
$or: FilterExpression[];
|
|
151
|
+
} | {
|
|
152
|
+
[field: string]: FilterValue | FilterOps;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Per-request override of the weighted RRF merge between vector and keyword
|
|
156
|
+
* search. Unset fields fall back to server defaults (semantic-favored 7:3).
|
|
157
|
+
*/
|
|
158
|
+
interface HybridSettings {
|
|
159
|
+
fullTextWeight?: number;
|
|
160
|
+
semanticWeight?: number;
|
|
161
|
+
rrfK?: number;
|
|
162
|
+
/** Caps FTS candidates considered before fusion; FTS search has no native limit. */
|
|
163
|
+
fullTextLimit?: number;
|
|
97
164
|
}
|
|
98
165
|
|
|
99
166
|
type Requester = <T>(path: string, init?: RequestInit) => Promise<T>;
|
|
@@ -133,6 +200,14 @@ declare class JobsResource {
|
|
|
133
200
|
waitUntilComplete(id: string, options?: WaitOptions): Promise<Job>;
|
|
134
201
|
}
|
|
135
202
|
|
|
203
|
+
interface UpdateDocumentOptions {
|
|
204
|
+
/** New display name. */
|
|
205
|
+
name?: string;
|
|
206
|
+
/** Replaces the document's freeform extra_json metadata. */
|
|
207
|
+
extraJson?: string;
|
|
208
|
+
/** Merges values into the document's typed metadata fields. */
|
|
209
|
+
metadata?: Record<string, unknown>;
|
|
210
|
+
}
|
|
136
211
|
declare class DocumentsResource {
|
|
137
212
|
private readonly req;
|
|
138
213
|
private readonly slug?;
|
|
@@ -146,12 +221,41 @@ declare class DocumentsResource {
|
|
|
146
221
|
limit?: number;
|
|
147
222
|
offset?: number;
|
|
148
223
|
}): Promise<Document[]>;
|
|
224
|
+
/**
|
|
225
|
+
* Get a single document by ID.
|
|
226
|
+
* @param id - The document ID.
|
|
227
|
+
*/
|
|
228
|
+
get(id: string): Promise<Document>;
|
|
229
|
+
/**
|
|
230
|
+
* Get this document's typed metadata field values.
|
|
231
|
+
* A field is only included if its value is identical across every chunk
|
|
232
|
+
* of the document — this avoids showing a value that's mid-sync.
|
|
233
|
+
* @param id - The document ID.
|
|
234
|
+
*/
|
|
235
|
+
metadata(id: string): Promise<Record<string, unknown>>;
|
|
149
236
|
/**
|
|
150
237
|
* Rename a document.
|
|
151
238
|
* @param id - The document ID.
|
|
152
239
|
* @param name - The new display name.
|
|
153
240
|
*/
|
|
154
241
|
rename(id: string, name: string): Promise<Document>;
|
|
242
|
+
/**
|
|
243
|
+
* Update a document's name, extra_json, and/or typed metadata.
|
|
244
|
+
* `metadata` keys that aren't registered fields on this collection (or whose
|
|
245
|
+
* value doesn't match the field's declared type) are silently dropped by
|
|
246
|
+
* the server — the request still succeeds, with no signal for which keys
|
|
247
|
+
* landed. Register fields first via the metadata-fields admin API.
|
|
248
|
+
* @param id - The document ID.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```ts
|
|
252
|
+
* await collection.documents.update(id, {
|
|
253
|
+
* metadata: { reviewed: true },
|
|
254
|
+
* extraJson: JSON.stringify({ source: "zendesk" }),
|
|
255
|
+
* });
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
update(id: string, options: UpdateDocumentOptions): Promise<Document>;
|
|
155
259
|
/**
|
|
156
260
|
* Delete a document and all its chunks from this collection.
|
|
157
261
|
* @param id - The document ID.
|
|
@@ -159,23 +263,36 @@ declare class DocumentsResource {
|
|
|
159
263
|
delete(id: string): Promise<void>;
|
|
160
264
|
}
|
|
161
265
|
|
|
266
|
+
interface FindSimilarOptions {
|
|
267
|
+
/** The search query text. */
|
|
268
|
+
query: string;
|
|
269
|
+
/** Number of results to return. Defaults to 5. */
|
|
270
|
+
topK?: number;
|
|
271
|
+
/** Restrict results to chunks whose document matches this filter expression. */
|
|
272
|
+
filters?: FilterExpression;
|
|
273
|
+
/** Skip the keyword/BM25 pass and use pure vector search. Hybrid search runs by default. */
|
|
274
|
+
vectorSearchOnly?: boolean;
|
|
275
|
+
/** Per-request override of the weighted RRF merge between vector and keyword search. */
|
|
276
|
+
hybridSettings?: HybridSettings;
|
|
277
|
+
}
|
|
278
|
+
|
|
162
279
|
interface RagOptions {
|
|
163
280
|
/** Slug of the prompt template to use. Defaults to `"basic_rag"` if omitted. */
|
|
164
281
|
promptSlug?: string;
|
|
165
282
|
/** The user's question. Substituted into `{{question}}`. */
|
|
166
283
|
query: string;
|
|
167
|
-
/** Number of chunks to retrieve. Defaults to
|
|
284
|
+
/** Number of chunks to retrieve. Defaults to 2, since RAG chunks feed an LLM prompt. */
|
|
168
285
|
topK?: number;
|
|
169
286
|
/** LLM model name to use (e.g. `"gpt-4o"`, `"claude-opus-4-8"`). Falls back to server default. */
|
|
170
287
|
model?: string;
|
|
171
288
|
/** Minimum similarity score (0–100) a chunk must meet to be included in context. Omit to include all top_k results. */
|
|
172
289
|
minSimilarity?: number;
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
|
|
290
|
+
/** Restrict retrieval to chunks whose document matches this filter expression. */
|
|
291
|
+
filters?: FilterExpression;
|
|
292
|
+
/** Skip the keyword/BM25 pass and use pure vector search. Hybrid search runs by default. */
|
|
293
|
+
vectorSearchOnly?: boolean;
|
|
294
|
+
/** Per-request override of the weighted RRF merge between vector and keyword search. */
|
|
295
|
+
hybridSettings?: HybridSettings;
|
|
179
296
|
}
|
|
180
297
|
interface IngestUriOptions {
|
|
181
298
|
/** Remote file URI (e.g. `s3://bucket/file.pdf`). */
|
|
@@ -355,4 +472,4 @@ declare class RagPack {
|
|
|
355
472
|
collection(slug: string): CollectionClient;
|
|
356
473
|
}
|
|
357
474
|
|
|
358
|
-
export { type Collection, type Document, type EmbedderInfo, type FindSimilarOptions, type IngestUriOptions, type Job, type LLMInfo, type Prompt, type QueryResult, type RagChunk, type RagOptions, RagPack, type RagPackConfig, RagPackError, type RagResult };
|
|
475
|
+
export { type Collection, type Document, type EmbedderInfo, type FilterExpression, type FilterOps, type FilterValue, type FindSimilarOptions, type HybridSettings, type IngestUriOptions, type Job, type LLMInfo, type Prompt, type QueryResult, type RagChunk, type RagOptions, RagPack, type RagPackConfig, RagPackError, type RagResult, type UpdateDocumentOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -74,7 +74,14 @@ interface RagChunk {
|
|
|
74
74
|
chunk_index: number;
|
|
75
75
|
chunk_header: string | null;
|
|
76
76
|
chunk_text: string | null;
|
|
77
|
-
similarity
|
|
77
|
+
/** Cosine similarity score between 0 and 100. Higher is more relevant. */
|
|
78
|
+
vector_similarity: number;
|
|
79
|
+
/** Raw BM25 score from the keyword channel; present only for hybrid results. */
|
|
80
|
+
keyword_bm25_score?: number;
|
|
81
|
+
/** Weighted RRF fusion score, normalized so this batch's top result is 100. */
|
|
82
|
+
rrf_score_normalized?: number;
|
|
83
|
+
/** Raw RRF fusion score; only comparable within this query's own weights/k. */
|
|
84
|
+
rrf_score?: number;
|
|
78
85
|
}
|
|
79
86
|
interface RagResult {
|
|
80
87
|
formatted_prompt: string;
|
|
@@ -87,13 +94,73 @@ interface QueryResult {
|
|
|
87
94
|
file_uri: string;
|
|
88
95
|
mime_type: string;
|
|
89
96
|
chunk_index: number;
|
|
97
|
+
chunk_header: string | null;
|
|
90
98
|
/** The matched text chunk. */
|
|
91
99
|
chunk_text: string | null;
|
|
92
100
|
/** Optional metadata attached at ingest time. */
|
|
93
101
|
extra_json: string | null;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
/** Typed metadata field values registered for this collection. */
|
|
103
|
+
metadata?: Record<string, unknown>;
|
|
104
|
+
vector_distance: number;
|
|
105
|
+
/** Cosine similarity score between 0 and 100. Higher is more relevant. */
|
|
106
|
+
vector_similarity: number;
|
|
107
|
+
/** Raw BM25 score from the keyword channel; present only for hybrid results. */
|
|
108
|
+
keyword_bm25_score?: number;
|
|
109
|
+
/** Weighted RRF fusion score, normalized so this batch's top result is 100. */
|
|
110
|
+
rrf_score_normalized?: number;
|
|
111
|
+
/** Raw RRF fusion score; only comparable within this query's own weights/k. */
|
|
112
|
+
rrf_score?: number;
|
|
113
|
+
}
|
|
114
|
+
type FilterValue = string | number | boolean;
|
|
115
|
+
/** Operators usable against a single field in a {@link FilterExpression}. */
|
|
116
|
+
interface FilterOps {
|
|
117
|
+
$eq?: FilterValue;
|
|
118
|
+
$ne?: FilterValue;
|
|
119
|
+
$gt?: FilterValue;
|
|
120
|
+
$gte?: FilterValue;
|
|
121
|
+
$lt?: FilterValue;
|
|
122
|
+
$lte?: FilterValue;
|
|
123
|
+
$in?: FilterValue[];
|
|
124
|
+
$nin?: FilterValue[];
|
|
125
|
+
$exists?: boolean;
|
|
126
|
+
/** str/timestamp fields only. */
|
|
127
|
+
$like?: string;
|
|
128
|
+
/** str fields only. */
|
|
129
|
+
$ilike?: string;
|
|
130
|
+
/** arr fields only. */
|
|
131
|
+
$contains?: string;
|
|
132
|
+
/** arr fields only. */
|
|
133
|
+
$containsAny?: string[];
|
|
134
|
+
/** arr fields only. */
|
|
135
|
+
$containsAll?: string[];
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* MongoDB-style filter expression, compiled server-side into a predicate over
|
|
139
|
+
* a document's built-in and registered metadata fields.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* { mime_type: "application/pdf", score: { $gte: 4 } }
|
|
144
|
+
* { $or: [{ tags: { $contains: "urgent" } }, { created_at: { $gte: "7 days ago" } }] }
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
type FilterExpression = {
|
|
148
|
+
$and: FilterExpression[];
|
|
149
|
+
} | {
|
|
150
|
+
$or: FilterExpression[];
|
|
151
|
+
} | {
|
|
152
|
+
[field: string]: FilterValue | FilterOps;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Per-request override of the weighted RRF merge between vector and keyword
|
|
156
|
+
* search. Unset fields fall back to server defaults (semantic-favored 7:3).
|
|
157
|
+
*/
|
|
158
|
+
interface HybridSettings {
|
|
159
|
+
fullTextWeight?: number;
|
|
160
|
+
semanticWeight?: number;
|
|
161
|
+
rrfK?: number;
|
|
162
|
+
/** Caps FTS candidates considered before fusion; FTS search has no native limit. */
|
|
163
|
+
fullTextLimit?: number;
|
|
97
164
|
}
|
|
98
165
|
|
|
99
166
|
type Requester = <T>(path: string, init?: RequestInit) => Promise<T>;
|
|
@@ -133,6 +200,14 @@ declare class JobsResource {
|
|
|
133
200
|
waitUntilComplete(id: string, options?: WaitOptions): Promise<Job>;
|
|
134
201
|
}
|
|
135
202
|
|
|
203
|
+
interface UpdateDocumentOptions {
|
|
204
|
+
/** New display name. */
|
|
205
|
+
name?: string;
|
|
206
|
+
/** Replaces the document's freeform extra_json metadata. */
|
|
207
|
+
extraJson?: string;
|
|
208
|
+
/** Merges values into the document's typed metadata fields. */
|
|
209
|
+
metadata?: Record<string, unknown>;
|
|
210
|
+
}
|
|
136
211
|
declare class DocumentsResource {
|
|
137
212
|
private readonly req;
|
|
138
213
|
private readonly slug?;
|
|
@@ -146,12 +221,41 @@ declare class DocumentsResource {
|
|
|
146
221
|
limit?: number;
|
|
147
222
|
offset?: number;
|
|
148
223
|
}): Promise<Document[]>;
|
|
224
|
+
/**
|
|
225
|
+
* Get a single document by ID.
|
|
226
|
+
* @param id - The document ID.
|
|
227
|
+
*/
|
|
228
|
+
get(id: string): Promise<Document>;
|
|
229
|
+
/**
|
|
230
|
+
* Get this document's typed metadata field values.
|
|
231
|
+
* A field is only included if its value is identical across every chunk
|
|
232
|
+
* of the document — this avoids showing a value that's mid-sync.
|
|
233
|
+
* @param id - The document ID.
|
|
234
|
+
*/
|
|
235
|
+
metadata(id: string): Promise<Record<string, unknown>>;
|
|
149
236
|
/**
|
|
150
237
|
* Rename a document.
|
|
151
238
|
* @param id - The document ID.
|
|
152
239
|
* @param name - The new display name.
|
|
153
240
|
*/
|
|
154
241
|
rename(id: string, name: string): Promise<Document>;
|
|
242
|
+
/**
|
|
243
|
+
* Update a document's name, extra_json, and/or typed metadata.
|
|
244
|
+
* `metadata` keys that aren't registered fields on this collection (or whose
|
|
245
|
+
* value doesn't match the field's declared type) are silently dropped by
|
|
246
|
+
* the server — the request still succeeds, with no signal for which keys
|
|
247
|
+
* landed. Register fields first via the metadata-fields admin API.
|
|
248
|
+
* @param id - The document ID.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```ts
|
|
252
|
+
* await collection.documents.update(id, {
|
|
253
|
+
* metadata: { reviewed: true },
|
|
254
|
+
* extraJson: JSON.stringify({ source: "zendesk" }),
|
|
255
|
+
* });
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
update(id: string, options: UpdateDocumentOptions): Promise<Document>;
|
|
155
259
|
/**
|
|
156
260
|
* Delete a document and all its chunks from this collection.
|
|
157
261
|
* @param id - The document ID.
|
|
@@ -159,23 +263,36 @@ declare class DocumentsResource {
|
|
|
159
263
|
delete(id: string): Promise<void>;
|
|
160
264
|
}
|
|
161
265
|
|
|
266
|
+
interface FindSimilarOptions {
|
|
267
|
+
/** The search query text. */
|
|
268
|
+
query: string;
|
|
269
|
+
/** Number of results to return. Defaults to 5. */
|
|
270
|
+
topK?: number;
|
|
271
|
+
/** Restrict results to chunks whose document matches this filter expression. */
|
|
272
|
+
filters?: FilterExpression;
|
|
273
|
+
/** Skip the keyword/BM25 pass and use pure vector search. Hybrid search runs by default. */
|
|
274
|
+
vectorSearchOnly?: boolean;
|
|
275
|
+
/** Per-request override of the weighted RRF merge between vector and keyword search. */
|
|
276
|
+
hybridSettings?: HybridSettings;
|
|
277
|
+
}
|
|
278
|
+
|
|
162
279
|
interface RagOptions {
|
|
163
280
|
/** Slug of the prompt template to use. Defaults to `"basic_rag"` if omitted. */
|
|
164
281
|
promptSlug?: string;
|
|
165
282
|
/** The user's question. Substituted into `{{question}}`. */
|
|
166
283
|
query: string;
|
|
167
|
-
/** Number of chunks to retrieve. Defaults to
|
|
284
|
+
/** Number of chunks to retrieve. Defaults to 2, since RAG chunks feed an LLM prompt. */
|
|
168
285
|
topK?: number;
|
|
169
286
|
/** LLM model name to use (e.g. `"gpt-4o"`, `"claude-opus-4-8"`). Falls back to server default. */
|
|
170
287
|
model?: string;
|
|
171
288
|
/** Minimum similarity score (0–100) a chunk must meet to be included in context. Omit to include all top_k results. */
|
|
172
289
|
minSimilarity?: number;
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
|
|
290
|
+
/** Restrict retrieval to chunks whose document matches this filter expression. */
|
|
291
|
+
filters?: FilterExpression;
|
|
292
|
+
/** Skip the keyword/BM25 pass and use pure vector search. Hybrid search runs by default. */
|
|
293
|
+
vectorSearchOnly?: boolean;
|
|
294
|
+
/** Per-request override of the weighted RRF merge between vector and keyword search. */
|
|
295
|
+
hybridSettings?: HybridSettings;
|
|
179
296
|
}
|
|
180
297
|
interface IngestUriOptions {
|
|
181
298
|
/** Remote file URI (e.g. `s3://bucket/file.pdf`). */
|
|
@@ -355,4 +472,4 @@ declare class RagPack {
|
|
|
355
472
|
collection(slug: string): CollectionClient;
|
|
356
473
|
}
|
|
357
474
|
|
|
358
|
-
export { type Collection, type Document, type EmbedderInfo, type FindSimilarOptions, type IngestUriOptions, type Job, type LLMInfo, type Prompt, type QueryResult, type RagChunk, type RagOptions, RagPack, type RagPackConfig, RagPackError, type RagResult };
|
|
475
|
+
export { type Collection, type Document, type EmbedderInfo, type FilterExpression, type FilterOps, type FilterValue, type FindSimilarOptions, type HybridSettings, type IngestUriOptions, type Job, type LLMInfo, type Prompt, type QueryResult, type RagChunk, type RagOptions, RagPack, type RagPackConfig, RagPackError, type RagResult, type UpdateDocumentOptions };
|
package/dist/index.js
CHANGED
|
@@ -91,6 +91,25 @@ var DocumentsResource = class {
|
|
|
91
91
|
);
|
|
92
92
|
return r.documents;
|
|
93
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Get a single document by ID.
|
|
96
|
+
* @param id - The document ID.
|
|
97
|
+
*/
|
|
98
|
+
get(id) {
|
|
99
|
+
return this.req(`/collections/${this.slug}/documents/${id}`);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get this document's typed metadata field values.
|
|
103
|
+
* A field is only included if its value is identical across every chunk
|
|
104
|
+
* of the document — this avoids showing a value that's mid-sync.
|
|
105
|
+
* @param id - The document ID.
|
|
106
|
+
*/
|
|
107
|
+
async metadata(id) {
|
|
108
|
+
const r = await this.req(
|
|
109
|
+
`/collections/${this.slug}/documents/${id}/metadata`
|
|
110
|
+
);
|
|
111
|
+
return r.metadata;
|
|
112
|
+
}
|
|
94
113
|
/**
|
|
95
114
|
* Rename a document.
|
|
96
115
|
* @param id - The document ID.
|
|
@@ -102,6 +121,32 @@ var DocumentsResource = class {
|
|
|
102
121
|
body: JSON.stringify({ name })
|
|
103
122
|
});
|
|
104
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Update a document's name, extra_json, and/or typed metadata.
|
|
126
|
+
* `metadata` keys that aren't registered fields on this collection (or whose
|
|
127
|
+
* value doesn't match the field's declared type) are silently dropped by
|
|
128
|
+
* the server — the request still succeeds, with no signal for which keys
|
|
129
|
+
* landed. Register fields first via the metadata-fields admin API.
|
|
130
|
+
* @param id - The document ID.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* await collection.documents.update(id, {
|
|
135
|
+
* metadata: { reviewed: true },
|
|
136
|
+
* extraJson: JSON.stringify({ source: "zendesk" }),
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
update(id, options) {
|
|
141
|
+
return this.req(`/collections/${this.slug}/documents/${id}`, {
|
|
142
|
+
method: "PATCH",
|
|
143
|
+
body: JSON.stringify({
|
|
144
|
+
...options.name !== void 0 && { name: options.name },
|
|
145
|
+
...options.extraJson !== void 0 && { extra_json: options.extraJson },
|
|
146
|
+
...options.metadata !== void 0 && { metadata: options.metadata }
|
|
147
|
+
})
|
|
148
|
+
});
|
|
149
|
+
}
|
|
105
150
|
/**
|
|
106
151
|
* Delete a document and all its chunks from this collection.
|
|
107
152
|
* @param id - The document ID.
|
|
@@ -113,6 +158,29 @@ var DocumentsResource = class {
|
|
|
113
158
|
}
|
|
114
159
|
};
|
|
115
160
|
|
|
161
|
+
// src/hybrid.ts
|
|
162
|
+
function buildHybridBody(options) {
|
|
163
|
+
const { filters, vectorSearchOnly, hybridSettings } = options;
|
|
164
|
+
return {
|
|
165
|
+
...filters !== void 0 && { filters },
|
|
166
|
+
...vectorSearchOnly !== void 0 && { vector_search_only: vectorSearchOnly },
|
|
167
|
+
...hybridSettings !== void 0 && {
|
|
168
|
+
hybrid_settings: {
|
|
169
|
+
...hybridSettings.fullTextWeight !== void 0 && {
|
|
170
|
+
full_text_weight: hybridSettings.fullTextWeight
|
|
171
|
+
},
|
|
172
|
+
...hybridSettings.semanticWeight !== void 0 && {
|
|
173
|
+
semantic_weight: hybridSettings.semanticWeight
|
|
174
|
+
},
|
|
175
|
+
...hybridSettings.rrfK !== void 0 && { rrf_k: hybridSettings.rrfK },
|
|
176
|
+
...hybridSettings.fullTextLimit !== void 0 && {
|
|
177
|
+
full_text_limit: hybridSettings.fullTextLimit
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
116
184
|
// src/resources/query.ts
|
|
117
185
|
var QueryResource = class {
|
|
118
186
|
constructor(req, slug) {
|
|
@@ -128,7 +196,11 @@ var QueryResource = class {
|
|
|
128
196
|
`/collections/${this.slug}/query`,
|
|
129
197
|
{
|
|
130
198
|
method: "POST",
|
|
131
|
-
body: JSON.stringify({
|
|
199
|
+
body: JSON.stringify({
|
|
200
|
+
query: options.query,
|
|
201
|
+
top_k: options.topK ?? 5,
|
|
202
|
+
...buildHybridBody(options)
|
|
203
|
+
})
|
|
132
204
|
}
|
|
133
205
|
);
|
|
134
206
|
return r.results;
|
|
@@ -188,7 +260,8 @@ var CollectionClient = class {
|
|
|
188
260
|
top_k: options.topK ?? 5,
|
|
189
261
|
...options.promptSlug ? { prompt_slug: options.promptSlug } : {},
|
|
190
262
|
...options.model ? { model: options.model } : {},
|
|
191
|
-
...options.minSimilarity != null ? { min_similarity: options.minSimilarity } : {}
|
|
263
|
+
...options.minSimilarity != null ? { min_similarity: options.minSimilarity } : {},
|
|
264
|
+
...buildHybridBody(options)
|
|
192
265
|
})
|
|
193
266
|
});
|
|
194
267
|
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ragpack-js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "TypeScript client for the Ragpack self-hosted RAG engine",
|
|
5
|
-
"main": "./dist/index.
|
|
6
|
-
"module": "./dist/index.
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.cts",
|
|
16
|
+
"default": "./dist/index.cjs"
|
|
17
|
+
}
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
"files": [
|