ragpack-js 0.1.2 → 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 +44 -4
- package/dist/index.cjs +86 -2
- package/dist/index.d.cts +137 -12
- package/dist/index.d.ts +137 -12
- package/dist/index.js +86 -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,11 +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 |
|
|
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 |
|
|
80
84
|
| `documents.delete(id)` | Delete a document and its chunks |
|
|
81
85
|
|
|
82
86
|
#### `rag(options)`
|
|
@@ -88,18 +92,54 @@ const { answer, chunks } = await collection.rag({
|
|
|
88
92
|
query: "How do I reset my password?",
|
|
89
93
|
// All options below are optional
|
|
90
94
|
promptSlug: "basic_rag", // defaults to "basic_rag" if omitted
|
|
91
|
-
topK:
|
|
95
|
+
topK: 2, // number of chunks to retrieve (default: 2)
|
|
92
96
|
model: "gpt-4o", // LLM model; falls back to server default
|
|
93
97
|
minSimilarity: 70, // drop chunks below this similarity score (0–100)
|
|
98
|
+
filters: { mime_type: "application/pdf" },
|
|
94
99
|
});
|
|
95
100
|
|
|
96
101
|
console.log(answer);
|
|
97
102
|
|
|
98
103
|
for (const chunk of chunks) {
|
|
99
|
-
console.log(chunk.
|
|
104
|
+
console.log(chunk.vector_similarity, chunk.chunk_text);
|
|
100
105
|
}
|
|
101
106
|
```
|
|
102
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
|
+
|
|
103
143
|
#### Prompt templates
|
|
104
144
|
|
|
105
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,62 @@ 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
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Rename a document.
|
|
142
|
+
* @param id - The document ID.
|
|
143
|
+
* @param name - The new display name.
|
|
144
|
+
*/
|
|
145
|
+
rename(id, name) {
|
|
146
|
+
return this.req(`/collections/${this.slug}/documents/${id}`, {
|
|
147
|
+
method: "PATCH",
|
|
148
|
+
body: JSON.stringify({ name })
|
|
149
|
+
});
|
|
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
|
+
}
|
|
121
177
|
/**
|
|
122
178
|
* Delete a document and all its chunks from this collection.
|
|
123
179
|
* @param id - The document ID.
|
|
@@ -129,6 +185,29 @@ var DocumentsResource = class {
|
|
|
129
185
|
}
|
|
130
186
|
};
|
|
131
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
|
+
|
|
132
211
|
// src/resources/query.ts
|
|
133
212
|
var QueryResource = class {
|
|
134
213
|
constructor(req, slug) {
|
|
@@ -144,7 +223,11 @@ var QueryResource = class {
|
|
|
144
223
|
`/collections/${this.slug}/query`,
|
|
145
224
|
{
|
|
146
225
|
method: "POST",
|
|
147
|
-
body: JSON.stringify({
|
|
226
|
+
body: JSON.stringify({
|
|
227
|
+
query: options.query,
|
|
228
|
+
top_k: options.topK ?? 5,
|
|
229
|
+
...buildHybridBody(options)
|
|
230
|
+
})
|
|
148
231
|
}
|
|
149
232
|
);
|
|
150
233
|
return r.results;
|
|
@@ -204,7 +287,8 @@ var CollectionClient = class {
|
|
|
204
287
|
top_k: options.topK ?? 5,
|
|
205
288
|
...options.promptSlug ? { prompt_slug: options.promptSlug } : {},
|
|
206
289
|
...options.model ? { model: options.model } : {},
|
|
207
|
-
...options.minSimilarity != null ? { min_similarity: options.minSimilarity } : {}
|
|
290
|
+
...options.minSimilarity != null ? { min_similarity: options.minSimilarity } : {},
|
|
291
|
+
...buildHybridBody(options)
|
|
208
292
|
})
|
|
209
293
|
});
|
|
210
294
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -39,6 +39,7 @@ interface Job {
|
|
|
39
39
|
collection_id: string;
|
|
40
40
|
file_uri: string;
|
|
41
41
|
mime_type: string;
|
|
42
|
+
display_name?: string;
|
|
42
43
|
status: "pending" | "processing" | "complete" | "failed";
|
|
43
44
|
error?: string;
|
|
44
45
|
created_at: string;
|
|
@@ -50,6 +51,7 @@ interface Document {
|
|
|
50
51
|
job_id: string;
|
|
51
52
|
file_uri: string;
|
|
52
53
|
mime_type: string;
|
|
54
|
+
name?: string;
|
|
53
55
|
chunk_count: number;
|
|
54
56
|
status: "ingesting" | "complete" | "failed";
|
|
55
57
|
error?: string;
|
|
@@ -72,7 +74,14 @@ interface RagChunk {
|
|
|
72
74
|
chunk_index: number;
|
|
73
75
|
chunk_header: string | null;
|
|
74
76
|
chunk_text: string | null;
|
|
75
|
-
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;
|
|
76
85
|
}
|
|
77
86
|
interface RagResult {
|
|
78
87
|
formatted_prompt: string;
|
|
@@ -85,13 +94,73 @@ interface QueryResult {
|
|
|
85
94
|
file_uri: string;
|
|
86
95
|
mime_type: string;
|
|
87
96
|
chunk_index: number;
|
|
97
|
+
chunk_header: string | null;
|
|
88
98
|
/** The matched text chunk. */
|
|
89
99
|
chunk_text: string | null;
|
|
90
100
|
/** Optional metadata attached at ingest time. */
|
|
91
101
|
extra_json: string | null;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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;
|
|
95
164
|
}
|
|
96
165
|
|
|
97
166
|
type Requester = <T>(path: string, init?: RequestInit) => Promise<T>;
|
|
@@ -131,6 +200,14 @@ declare class JobsResource {
|
|
|
131
200
|
waitUntilComplete(id: string, options?: WaitOptions): Promise<Job>;
|
|
132
201
|
}
|
|
133
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
|
+
}
|
|
134
211
|
declare class DocumentsResource {
|
|
135
212
|
private readonly req;
|
|
136
213
|
private readonly slug?;
|
|
@@ -144,6 +221,41 @@ declare class DocumentsResource {
|
|
|
144
221
|
limit?: number;
|
|
145
222
|
offset?: number;
|
|
146
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>>;
|
|
236
|
+
/**
|
|
237
|
+
* Rename a document.
|
|
238
|
+
* @param id - The document ID.
|
|
239
|
+
* @param name - The new display name.
|
|
240
|
+
*/
|
|
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>;
|
|
147
259
|
/**
|
|
148
260
|
* Delete a document and all its chunks from this collection.
|
|
149
261
|
* @param id - The document ID.
|
|
@@ -151,23 +263,36 @@ declare class DocumentsResource {
|
|
|
151
263
|
delete(id: string): Promise<void>;
|
|
152
264
|
}
|
|
153
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
|
+
|
|
154
279
|
interface RagOptions {
|
|
155
280
|
/** Slug of the prompt template to use. Defaults to `"basic_rag"` if omitted. */
|
|
156
281
|
promptSlug?: string;
|
|
157
282
|
/** The user's question. Substituted into `{{question}}`. */
|
|
158
283
|
query: string;
|
|
159
|
-
/** Number of chunks to retrieve. Defaults to
|
|
284
|
+
/** Number of chunks to retrieve. Defaults to 2, since RAG chunks feed an LLM prompt. */
|
|
160
285
|
topK?: number;
|
|
161
286
|
/** LLM model name to use (e.g. `"gpt-4o"`, `"claude-opus-4-8"`). Falls back to server default. */
|
|
162
287
|
model?: string;
|
|
163
288
|
/** Minimum similarity score (0–100) a chunk must meet to be included in context. Omit to include all top_k results. */
|
|
164
289
|
minSimilarity?: number;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
|
|
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;
|
|
171
296
|
}
|
|
172
297
|
interface IngestUriOptions {
|
|
173
298
|
/** Remote file URI (e.g. `s3://bucket/file.pdf`). */
|
|
@@ -347,4 +472,4 @@ declare class RagPack {
|
|
|
347
472
|
collection(slug: string): CollectionClient;
|
|
348
473
|
}
|
|
349
474
|
|
|
350
|
-
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
|
@@ -39,6 +39,7 @@ interface Job {
|
|
|
39
39
|
collection_id: string;
|
|
40
40
|
file_uri: string;
|
|
41
41
|
mime_type: string;
|
|
42
|
+
display_name?: string;
|
|
42
43
|
status: "pending" | "processing" | "complete" | "failed";
|
|
43
44
|
error?: string;
|
|
44
45
|
created_at: string;
|
|
@@ -50,6 +51,7 @@ interface Document {
|
|
|
50
51
|
job_id: string;
|
|
51
52
|
file_uri: string;
|
|
52
53
|
mime_type: string;
|
|
54
|
+
name?: string;
|
|
53
55
|
chunk_count: number;
|
|
54
56
|
status: "ingesting" | "complete" | "failed";
|
|
55
57
|
error?: string;
|
|
@@ -72,7 +74,14 @@ interface RagChunk {
|
|
|
72
74
|
chunk_index: number;
|
|
73
75
|
chunk_header: string | null;
|
|
74
76
|
chunk_text: string | null;
|
|
75
|
-
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;
|
|
76
85
|
}
|
|
77
86
|
interface RagResult {
|
|
78
87
|
formatted_prompt: string;
|
|
@@ -85,13 +94,73 @@ interface QueryResult {
|
|
|
85
94
|
file_uri: string;
|
|
86
95
|
mime_type: string;
|
|
87
96
|
chunk_index: number;
|
|
97
|
+
chunk_header: string | null;
|
|
88
98
|
/** The matched text chunk. */
|
|
89
99
|
chunk_text: string | null;
|
|
90
100
|
/** Optional metadata attached at ingest time. */
|
|
91
101
|
extra_json: string | null;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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;
|
|
95
164
|
}
|
|
96
165
|
|
|
97
166
|
type Requester = <T>(path: string, init?: RequestInit) => Promise<T>;
|
|
@@ -131,6 +200,14 @@ declare class JobsResource {
|
|
|
131
200
|
waitUntilComplete(id: string, options?: WaitOptions): Promise<Job>;
|
|
132
201
|
}
|
|
133
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
|
+
}
|
|
134
211
|
declare class DocumentsResource {
|
|
135
212
|
private readonly req;
|
|
136
213
|
private readonly slug?;
|
|
@@ -144,6 +221,41 @@ declare class DocumentsResource {
|
|
|
144
221
|
limit?: number;
|
|
145
222
|
offset?: number;
|
|
146
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>>;
|
|
236
|
+
/**
|
|
237
|
+
* Rename a document.
|
|
238
|
+
* @param id - The document ID.
|
|
239
|
+
* @param name - The new display name.
|
|
240
|
+
*/
|
|
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>;
|
|
147
259
|
/**
|
|
148
260
|
* Delete a document and all its chunks from this collection.
|
|
149
261
|
* @param id - The document ID.
|
|
@@ -151,23 +263,36 @@ declare class DocumentsResource {
|
|
|
151
263
|
delete(id: string): Promise<void>;
|
|
152
264
|
}
|
|
153
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
|
+
|
|
154
279
|
interface RagOptions {
|
|
155
280
|
/** Slug of the prompt template to use. Defaults to `"basic_rag"` if omitted. */
|
|
156
281
|
promptSlug?: string;
|
|
157
282
|
/** The user's question. Substituted into `{{question}}`. */
|
|
158
283
|
query: string;
|
|
159
|
-
/** Number of chunks to retrieve. Defaults to
|
|
284
|
+
/** Number of chunks to retrieve. Defaults to 2, since RAG chunks feed an LLM prompt. */
|
|
160
285
|
topK?: number;
|
|
161
286
|
/** LLM model name to use (e.g. `"gpt-4o"`, `"claude-opus-4-8"`). Falls back to server default. */
|
|
162
287
|
model?: string;
|
|
163
288
|
/** Minimum similarity score (0–100) a chunk must meet to be included in context. Omit to include all top_k results. */
|
|
164
289
|
minSimilarity?: number;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
|
|
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;
|
|
171
296
|
}
|
|
172
297
|
interface IngestUriOptions {
|
|
173
298
|
/** Remote file URI (e.g. `s3://bucket/file.pdf`). */
|
|
@@ -347,4 +472,4 @@ declare class RagPack {
|
|
|
347
472
|
collection(slug: string): CollectionClient;
|
|
348
473
|
}
|
|
349
474
|
|
|
350
|
-
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,62 @@ 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
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Rename a document.
|
|
115
|
+
* @param id - The document ID.
|
|
116
|
+
* @param name - The new display name.
|
|
117
|
+
*/
|
|
118
|
+
rename(id, name) {
|
|
119
|
+
return this.req(`/collections/${this.slug}/documents/${id}`, {
|
|
120
|
+
method: "PATCH",
|
|
121
|
+
body: JSON.stringify({ name })
|
|
122
|
+
});
|
|
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
|
+
}
|
|
94
150
|
/**
|
|
95
151
|
* Delete a document and all its chunks from this collection.
|
|
96
152
|
* @param id - The document ID.
|
|
@@ -102,6 +158,29 @@ var DocumentsResource = class {
|
|
|
102
158
|
}
|
|
103
159
|
};
|
|
104
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
|
+
|
|
105
184
|
// src/resources/query.ts
|
|
106
185
|
var QueryResource = class {
|
|
107
186
|
constructor(req, slug) {
|
|
@@ -117,7 +196,11 @@ var QueryResource = class {
|
|
|
117
196
|
`/collections/${this.slug}/query`,
|
|
118
197
|
{
|
|
119
198
|
method: "POST",
|
|
120
|
-
body: JSON.stringify({
|
|
199
|
+
body: JSON.stringify({
|
|
200
|
+
query: options.query,
|
|
201
|
+
top_k: options.topK ?? 5,
|
|
202
|
+
...buildHybridBody(options)
|
|
203
|
+
})
|
|
121
204
|
}
|
|
122
205
|
);
|
|
123
206
|
return r.results;
|
|
@@ -177,7 +260,8 @@ var CollectionClient = class {
|
|
|
177
260
|
top_k: options.topK ?? 5,
|
|
178
261
|
...options.promptSlug ? { prompt_slug: options.promptSlug } : {},
|
|
179
262
|
...options.model ? { model: options.model } : {},
|
|
180
|
-
...options.minSimilarity != null ? { min_similarity: options.minSimilarity } : {}
|
|
263
|
+
...options.minSimilarity != null ? { min_similarity: options.minSimilarity } : {},
|
|
264
|
+
...buildHybridBody(options)
|
|
181
265
|
})
|
|
182
266
|
});
|
|
183
267
|
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ragpack-js",
|
|
3
|
-
"version": "
|
|
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": [
|