@agentuity/core 0.0.32 → 0.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/json.js +23 -0
- package/dist/json.js.map +1 -0
- package/dist/services/_util.js +107 -0
- package/dist/services/_util.js.map +1 -0
- package/dist/services/adapter.js +2 -0
- package/dist/services/adapter.js.map +1 -0
- package/dist/services/exception.js +8 -0
- package/dist/services/exception.js.map +1 -0
- package/dist/services/index.js +8 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/keyvalue.js +85 -0
- package/dist/services/keyvalue.js.map +1 -0
- package/dist/services/objectstore.js +218 -0
- package/dist/services/objectstore.js.map +1 -0
- package/dist/services/stream.js +392 -0
- package/dist/services/stream.js.map +1 -0
- package/dist/services/vector.js +242 -0
- package/dist/services/vector.js.map +1 -0
- package/dist/standard_schema.js +2 -0
- package/dist/standard_schema.js.map +1 -0
- package/dist/typehelper.js +2 -0
- package/dist/typehelper.js.map +1 -0
- package/package.json +5 -4
- package/src/index.ts +4 -0
- package/src/json.ts +26 -0
- package/src/services/__test__/keyvalue.test.ts +402 -0
- package/src/services/__test__/mock-adapter.ts +114 -0
- package/src/services/__test__/objectstore.test.ts +431 -0
- package/src/services/__test__/stream.test.ts +554 -0
- package/src/services/__test__/vector.test.ts +813 -0
- package/src/services/_util.ts +117 -0
- package/src/services/adapter.ts +33 -0
- package/src/services/exception.ts +7 -0
- package/src/services/index.ts +7 -0
- package/src/services/keyvalue.ts +185 -0
- package/src/services/objectstore.ts +466 -0
- package/src/services/stream.ts +614 -0
- package/src/services/vector.ts +599 -0
- package/src/standard_schema.ts +69 -0
- package/src/typehelper.ts +5 -0
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
import { FetchAdapter } from './adapter';
|
|
2
|
+
import { buildUrl, toServiceException } from './_util';
|
|
3
|
+
import { safeStringify } from '../json';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Base properties shared by all vector upsert operations
|
|
7
|
+
*/
|
|
8
|
+
export interface VectorUpsertBase {
|
|
9
|
+
/**
|
|
10
|
+
* the key of the vector object which can be used as a reference. the value of this key is opaque to the vector storage.
|
|
11
|
+
*/
|
|
12
|
+
key: string;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* the metadata to upsert
|
|
16
|
+
*/
|
|
17
|
+
metadata?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Upsert using pre-computed embeddings
|
|
22
|
+
*/
|
|
23
|
+
export interface VectorUpsertEmbeddings extends VectorUpsertBase {
|
|
24
|
+
/**
|
|
25
|
+
* the embeddings to upsert
|
|
26
|
+
*/
|
|
27
|
+
embeddings: Array<number>;
|
|
28
|
+
document?: never;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Upsert using text that will be converted to embeddings
|
|
33
|
+
*/
|
|
34
|
+
export interface VectorUpsertText extends VectorUpsertBase {
|
|
35
|
+
/**
|
|
36
|
+
* the text to use for the embedding
|
|
37
|
+
*/
|
|
38
|
+
document: string;
|
|
39
|
+
embeddings?: never;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Parameters for upserting a vector
|
|
44
|
+
*/
|
|
45
|
+
export type VectorUpsertParams = VectorUpsertEmbeddings | VectorUpsertText;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Parameters for searching vectors
|
|
49
|
+
*/
|
|
50
|
+
export interface VectorSearchParams<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
51
|
+
/**
|
|
52
|
+
* The text query to search for in the vector storage. This will be converted to embeddings
|
|
53
|
+
* and used to find semantically similar documents.
|
|
54
|
+
*
|
|
55
|
+
* @example "comfortable office chair"
|
|
56
|
+
* @example "machine learning algorithms"
|
|
57
|
+
*/
|
|
58
|
+
query: string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Maximum number of search results to return. If not specified, the server default will be used.
|
|
62
|
+
* Must be a positive integer.
|
|
63
|
+
*
|
|
64
|
+
* @default 10
|
|
65
|
+
* @example 5
|
|
66
|
+
* @example 20
|
|
67
|
+
*/
|
|
68
|
+
limit?: number;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Minimum similarity threshold for results. Only vectors with similarity scores greater than or equal
|
|
72
|
+
* to this value will be returned. Value must be between 0.0 and 1.0, where 1.0 means exact match
|
|
73
|
+
* and 0.0 means no similarity requirement.
|
|
74
|
+
*
|
|
75
|
+
* @minimum 0.0
|
|
76
|
+
* @maximum 1.0
|
|
77
|
+
* @example 0.7
|
|
78
|
+
* @example 0.5
|
|
79
|
+
*/
|
|
80
|
+
similarity?: number;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Metadata filters to apply to the search. Only vectors whose metadata matches all specified
|
|
84
|
+
* key-value pairs will be included in results. Must be a valid JSON object if provided.
|
|
85
|
+
*
|
|
86
|
+
* @example { category: "furniture", inStock: true }
|
|
87
|
+
* @example { userId: "123", type: "product" }
|
|
88
|
+
*/
|
|
89
|
+
metadata?: T;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Result of a vector search operation with optional type-safe metadata
|
|
94
|
+
*/
|
|
95
|
+
export interface VectorSearchResult<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
96
|
+
/**
|
|
97
|
+
* the unique id of the object in vector storage
|
|
98
|
+
*/
|
|
99
|
+
id: string;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* the key used when the vector object was added to vector storage
|
|
103
|
+
*/
|
|
104
|
+
key: string;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* the metadata of the vector object when it was stored
|
|
108
|
+
*/
|
|
109
|
+
metadata?: T;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* the distance of the vector object from the query from 0-1. The larger the number, the more similar the vector object is to the query.
|
|
113
|
+
*/
|
|
114
|
+
similarity: number;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Extended search result that includes the document and embeddings
|
|
119
|
+
*/
|
|
120
|
+
export interface VectorSearchResultWithDocument<
|
|
121
|
+
T extends Record<string, unknown> = Record<string, unknown>,
|
|
122
|
+
> extends VectorSearchResult<T> {
|
|
123
|
+
/**
|
|
124
|
+
* the document that was used to create the vector object
|
|
125
|
+
*/
|
|
126
|
+
document?: string;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* the embeddings of the vector object
|
|
130
|
+
*/
|
|
131
|
+
embeddings?: Array<number>;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Result of a vector upsert operation
|
|
136
|
+
*/
|
|
137
|
+
export interface VectorUpsertResult {
|
|
138
|
+
/**
|
|
139
|
+
* the key from the original upsert document
|
|
140
|
+
*/
|
|
141
|
+
key: string;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* the generated id for this vector in storage
|
|
145
|
+
*/
|
|
146
|
+
id: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Result when a vector is found by key
|
|
151
|
+
*/
|
|
152
|
+
export interface VectorResultFound<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
153
|
+
/**
|
|
154
|
+
* the vector data
|
|
155
|
+
*/
|
|
156
|
+
data: VectorSearchResultWithDocument<T>;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* the vector was found
|
|
160
|
+
*/
|
|
161
|
+
exists: true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Result when a vector is not found by key
|
|
166
|
+
*/
|
|
167
|
+
export interface VectorResultNotFound {
|
|
168
|
+
/**
|
|
169
|
+
* no data available
|
|
170
|
+
*/
|
|
171
|
+
data: never;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* the vector was not found
|
|
175
|
+
*/
|
|
176
|
+
exists: false;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Result of a get operation
|
|
181
|
+
*/
|
|
182
|
+
export type VectorResult<T extends Record<string, unknown> = Record<string, unknown>> =
|
|
183
|
+
| VectorResultFound<T>
|
|
184
|
+
| VectorResultNotFound;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Vector storage service for managing vector embeddings
|
|
188
|
+
*/
|
|
189
|
+
export interface VectorStorage {
|
|
190
|
+
/**
|
|
191
|
+
* upsert a vector into the vector storage
|
|
192
|
+
*
|
|
193
|
+
* @param name - the name of the vector storage
|
|
194
|
+
* @param documents - the documents for the vector upsert
|
|
195
|
+
* @returns array of results with key-to-id mappings for the upserted vectors
|
|
196
|
+
*/
|
|
197
|
+
upsert(name: string, ...documents: VectorUpsertParams[]): Promise<VectorUpsertResult[]>;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* get a vector from the vector storage by key
|
|
201
|
+
*
|
|
202
|
+
* @param name - the name of the vector storage
|
|
203
|
+
* @param key - the key of the vector to get
|
|
204
|
+
* @returns VectorResult with exists field for type-safe checking
|
|
205
|
+
*/
|
|
206
|
+
get<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
207
|
+
name: string,
|
|
208
|
+
key: string
|
|
209
|
+
): Promise<VectorResult<T>>;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* get multiple vectors from the vector storage by keys
|
|
213
|
+
*
|
|
214
|
+
* @param name - the name of the vector storage
|
|
215
|
+
* @param keys - the keys of the vectors to get
|
|
216
|
+
* @returns a Map of key to vector data for found vectors
|
|
217
|
+
*/
|
|
218
|
+
getMany<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
219
|
+
name: string,
|
|
220
|
+
...keys: string[]
|
|
221
|
+
): Promise<Map<string, VectorSearchResultWithDocument<T>>>;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* search for vectors in the vector storage
|
|
225
|
+
*
|
|
226
|
+
* @param name - the name of the vector storage
|
|
227
|
+
* @param params - the parameters for the vector search
|
|
228
|
+
* @returns the results of the vector search with type-safe metadata
|
|
229
|
+
*/
|
|
230
|
+
search<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
231
|
+
name: string,
|
|
232
|
+
params: VectorSearchParams<T>
|
|
233
|
+
): Promise<VectorSearchResult<T>[]>;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* delete vectors from the vector storage
|
|
237
|
+
*
|
|
238
|
+
* @param name - the name of the vector storage
|
|
239
|
+
* @param keys - the keys of the vectors to delete
|
|
240
|
+
* @returns the number of vector objects that were deleted
|
|
241
|
+
*/
|
|
242
|
+
delete(name: string, ...keys: string[]): Promise<number>;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* check if a vector storage exists
|
|
246
|
+
*
|
|
247
|
+
* @param name - the name of the vector storage
|
|
248
|
+
* @returns true if the storage exists, false otherwise
|
|
249
|
+
*/
|
|
250
|
+
exists(name: string): Promise<boolean>;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
interface VectorUpsertSuccessResponse {
|
|
254
|
+
success: true;
|
|
255
|
+
data: Array<{ id: string }>;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
interface VectorUpsertErrorResponse {
|
|
259
|
+
success: false;
|
|
260
|
+
message: string;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
type VectorUpsertResponse = VectorUpsertSuccessResponse | VectorUpsertErrorResponse;
|
|
264
|
+
|
|
265
|
+
interface VectorGetSuccessResponse {
|
|
266
|
+
success: true;
|
|
267
|
+
data: VectorSearchResultWithDocument | null;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
interface VectorGetErrorResponse {
|
|
271
|
+
success: false;
|
|
272
|
+
message: string;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
type VectorGetResponse = VectorGetSuccessResponse | VectorGetErrorResponse;
|
|
276
|
+
|
|
277
|
+
interface VectorSearchSuccessResponse {
|
|
278
|
+
success: true;
|
|
279
|
+
data: VectorSearchResult[];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
interface VectorSearchErrorResponse {
|
|
283
|
+
success: false;
|
|
284
|
+
message: string;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
type VectorSearchResponse = VectorSearchSuccessResponse | VectorSearchErrorResponse;
|
|
288
|
+
|
|
289
|
+
interface VectorDeleteSuccessResponse {
|
|
290
|
+
success: true;
|
|
291
|
+
data: number;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
interface VectorDeleteErrorResponse {
|
|
295
|
+
success: false;
|
|
296
|
+
message: string;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
type VectorDeleteResponse = VectorDeleteSuccessResponse | VectorDeleteErrorResponse;
|
|
300
|
+
|
|
301
|
+
export class VectorStorageService implements VectorStorage {
|
|
302
|
+
#adapter: FetchAdapter;
|
|
303
|
+
#baseUrl: string;
|
|
304
|
+
|
|
305
|
+
constructor(baseUrl: string, adapter: FetchAdapter) {
|
|
306
|
+
this.#adapter = adapter;
|
|
307
|
+
this.#baseUrl = baseUrl;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async upsert(name: string, ...documents: VectorUpsertParams[]): Promise<VectorUpsertResult[]> {
|
|
311
|
+
if (!name || typeof name !== 'string' || name.trim().length === 0) {
|
|
312
|
+
throw new Error('Vector storage name is required and must be a non-empty string');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (!documents || documents.length === 0) {
|
|
316
|
+
throw new Error('At least one document is required for upsert');
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
for (const doc of documents) {
|
|
320
|
+
if (!doc.key || typeof doc.key !== 'string' || doc.key.trim().length === 0) {
|
|
321
|
+
throw new Error('Each document must have a non-empty key');
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (!('embeddings' in doc) && !('document' in doc)) {
|
|
325
|
+
throw new Error('Each document must have either embeddings or document text');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if ('embeddings' in doc && doc.embeddings) {
|
|
329
|
+
if (!Array.isArray(doc.embeddings) || doc.embeddings.length === 0) {
|
|
330
|
+
throw new Error('Embeddings must be a non-empty array of numbers');
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if ('document' in doc && doc.document) {
|
|
335
|
+
if (typeof doc.document !== 'string' || doc.document.trim().length === 0) {
|
|
336
|
+
throw new Error('Document must be a non-empty string');
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const url = buildUrl(this.#baseUrl, `/vector/2025-03-17/${encodeURIComponent(name)}`);
|
|
342
|
+
const signal = AbortSignal.timeout(30_000);
|
|
343
|
+
|
|
344
|
+
const res = await this.#adapter.invoke<VectorUpsertResponse>(url, {
|
|
345
|
+
method: 'PUT',
|
|
346
|
+
body: safeStringify(documents),
|
|
347
|
+
contentType: 'application/json',
|
|
348
|
+
signal,
|
|
349
|
+
telemetry: {
|
|
350
|
+
name: 'agentuity.vector.upsert',
|
|
351
|
+
attributes: {
|
|
352
|
+
name,
|
|
353
|
+
count: String(documents.length),
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
if (res.ok) {
|
|
359
|
+
if (res.data.success) {
|
|
360
|
+
return res.data.data.map((o, index) => ({
|
|
361
|
+
key: documents[index].key,
|
|
362
|
+
id: o.id,
|
|
363
|
+
}));
|
|
364
|
+
}
|
|
365
|
+
if ('message' in res.data) {
|
|
366
|
+
throw new Error(res.data.message);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
throw await toServiceException(res.response);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
async get<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
374
|
+
name: string,
|
|
375
|
+
key: string
|
|
376
|
+
): Promise<VectorResult<T>> {
|
|
377
|
+
if (!name || typeof name !== 'string' || name.trim().length === 0) {
|
|
378
|
+
throw new Error('Vector storage name is required and must be a non-empty string');
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (!key || typeof key !== 'string' || key.trim().length === 0) {
|
|
382
|
+
throw new Error('Key is required and must be a non-empty string');
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const url = buildUrl(
|
|
386
|
+
this.#baseUrl,
|
|
387
|
+
`/vector/2025-03-17/${encodeURIComponent(name)}/${encodeURIComponent(key)}`
|
|
388
|
+
);
|
|
389
|
+
const signal = AbortSignal.timeout(10_000);
|
|
390
|
+
|
|
391
|
+
const res = await this.#adapter.invoke<VectorGetResponse>(url, {
|
|
392
|
+
method: 'GET',
|
|
393
|
+
signal,
|
|
394
|
+
telemetry: {
|
|
395
|
+
name: 'agentuity.vector.get',
|
|
396
|
+
attributes: {
|
|
397
|
+
name,
|
|
398
|
+
key,
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
if (res.response.status === 404) {
|
|
404
|
+
return { exists: false } as VectorResultNotFound;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (res.ok) {
|
|
408
|
+
if (res.data.success) {
|
|
409
|
+
return {
|
|
410
|
+
data: res.data.data as VectorSearchResultWithDocument<T>,
|
|
411
|
+
exists: true,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
if ('message' in res.data) {
|
|
415
|
+
throw new Error(res.data.message);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
throw await toServiceException(res.response);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
async getMany<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
423
|
+
name: string,
|
|
424
|
+
...keys: string[]
|
|
425
|
+
): Promise<Map<string, VectorSearchResultWithDocument<T>>> {
|
|
426
|
+
if (!name || typeof name !== 'string' || name.trim().length === 0) {
|
|
427
|
+
throw new Error('Vector storage name is required and must be a non-empty string');
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (keys.length === 0) {
|
|
431
|
+
return new Map();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
for (const key of keys) {
|
|
435
|
+
if (!key || typeof key !== 'string' || key.trim().length === 0) {
|
|
436
|
+
throw new Error('All keys must be non-empty strings');
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const results = await Promise.all(keys.map((key) => this.get<T>(name, key)));
|
|
441
|
+
|
|
442
|
+
const resultMap = new Map<string, VectorSearchResultWithDocument<T>>();
|
|
443
|
+
results.forEach((result, index) => {
|
|
444
|
+
if (result.exists) {
|
|
445
|
+
resultMap.set(keys[index], result.data);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
return resultMap;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
async search<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
453
|
+
name: string,
|
|
454
|
+
params: VectorSearchParams<T>
|
|
455
|
+
): Promise<VectorSearchResult<T>[]> {
|
|
456
|
+
if (!name || typeof name !== 'string' || name.trim().length === 0) {
|
|
457
|
+
throw new Error('Vector storage name is required and must be a non-empty string');
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (!params.query || typeof params.query !== 'string' || params.query.trim().length === 0) {
|
|
461
|
+
throw new Error('Query is required and must be a non-empty string');
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (params.limit !== undefined) {
|
|
465
|
+
if (typeof params.limit !== 'number' || params.limit <= 0) {
|
|
466
|
+
throw new Error('Limit must be a positive number');
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (params.similarity !== undefined) {
|
|
471
|
+
if (
|
|
472
|
+
typeof params.similarity !== 'number' ||
|
|
473
|
+
params.similarity < 0 ||
|
|
474
|
+
params.similarity > 1
|
|
475
|
+
) {
|
|
476
|
+
throw new Error('Similarity must be a number between 0.0 and 1.0');
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (params.metadata !== undefined) {
|
|
481
|
+
if (typeof params.metadata !== 'object' || params.metadata === null) {
|
|
482
|
+
throw new Error('Metadata must be a valid object');
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const url = buildUrl(this.#baseUrl, `/vector/2025-03-17/search/${encodeURIComponent(name)}`);
|
|
487
|
+
const signal = AbortSignal.timeout(30_000);
|
|
488
|
+
|
|
489
|
+
const attributes: Record<string, string> = {
|
|
490
|
+
name,
|
|
491
|
+
query: params.query,
|
|
492
|
+
};
|
|
493
|
+
if (params.limit !== undefined) {
|
|
494
|
+
attributes.limit = String(params.limit);
|
|
495
|
+
}
|
|
496
|
+
if (params.similarity !== undefined) {
|
|
497
|
+
attributes.similarity = String(params.similarity);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const res = await this.#adapter.invoke<VectorSearchResponse>(url, {
|
|
501
|
+
method: 'POST',
|
|
502
|
+
body: safeStringify(params),
|
|
503
|
+
contentType: 'application/json',
|
|
504
|
+
signal,
|
|
505
|
+
telemetry: {
|
|
506
|
+
name: 'agentuity.vector.search',
|
|
507
|
+
attributes,
|
|
508
|
+
},
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
if (res.response.status === 404) {
|
|
512
|
+
return [];
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (res.ok) {
|
|
516
|
+
if (res.data.success) {
|
|
517
|
+
return res.data.data as VectorSearchResult<T>[];
|
|
518
|
+
}
|
|
519
|
+
if ('message' in res.data) {
|
|
520
|
+
throw new Error(res.data.message);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
throw await toServiceException(res.response);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
async delete(name: string, ...keys: string[]): Promise<number> {
|
|
528
|
+
if (!name || typeof name !== 'string' || name.trim().length === 0) {
|
|
529
|
+
throw new Error('Vector storage name is required and must be a non-empty string');
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (keys.length === 0) {
|
|
533
|
+
return 0;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
for (const key of keys) {
|
|
537
|
+
if (!key || typeof key !== 'string' || key.trim().length === 0) {
|
|
538
|
+
throw new Error('All keys must be non-empty strings');
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const signal = AbortSignal.timeout(30_000);
|
|
543
|
+
let url: string;
|
|
544
|
+
let body: string | undefined;
|
|
545
|
+
|
|
546
|
+
if (keys.length === 1) {
|
|
547
|
+
url = buildUrl(
|
|
548
|
+
this.#baseUrl,
|
|
549
|
+
`/vector/2025-03-17/${encodeURIComponent(name)}/${encodeURIComponent(keys[0])}`
|
|
550
|
+
);
|
|
551
|
+
} else {
|
|
552
|
+
url = buildUrl(this.#baseUrl, `/vector/2025-03-17/${encodeURIComponent(name)}`);
|
|
553
|
+
body = safeStringify({ keys });
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const res = await this.#adapter.invoke<VectorDeleteResponse>(url, {
|
|
557
|
+
method: 'DELETE',
|
|
558
|
+
...(body && { body, contentType: 'application/json' }),
|
|
559
|
+
signal,
|
|
560
|
+
telemetry: {
|
|
561
|
+
name: 'agentuity.vector.delete',
|
|
562
|
+
attributes: {
|
|
563
|
+
name,
|
|
564
|
+
count: String(keys.length),
|
|
565
|
+
},
|
|
566
|
+
},
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
if (res.ok) {
|
|
570
|
+
if (res.data.success) {
|
|
571
|
+
return res.data.data;
|
|
572
|
+
}
|
|
573
|
+
if ('message' in res.data) {
|
|
574
|
+
throw new Error(res.data.message);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
throw await toServiceException(res.response);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
async exists(name: string): Promise<boolean> {
|
|
582
|
+
if (!name || typeof name !== 'string' || name.trim().length === 0) {
|
|
583
|
+
throw new Error('Vector storage name is required and must be a non-empty string');
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
try {
|
|
587
|
+
await this.search(name, { query: '_exists_check_', limit: 1 });
|
|
588
|
+
return true;
|
|
589
|
+
} catch (error) {
|
|
590
|
+
if (error instanceof Error) {
|
|
591
|
+
const statusMatch = error.message.match(/(\d{3})/);
|
|
592
|
+
if (statusMatch && statusMatch[1] === '404') {
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
throw error;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** The Standard Schema interface. */
|
|
2
|
+
export interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
3
|
+
/** The Standard Schema properties. */
|
|
4
|
+
readonly '~standard': StandardSchemaV1.Props<Input, Output>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
8
|
+
export declare namespace StandardSchemaV1 {
|
|
9
|
+
/** The Standard Schema properties interface. */
|
|
10
|
+
export interface Props<Input = unknown, Output = Input> {
|
|
11
|
+
/** The version number of the standard. */
|
|
12
|
+
readonly version: 1;
|
|
13
|
+
/** The vendor name of the schema library. */
|
|
14
|
+
readonly vendor: string;
|
|
15
|
+
/** Validates unknown input values. */
|
|
16
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
17
|
+
/** Inferred types associated with the schema. */
|
|
18
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The result interface of the validate function. */
|
|
22
|
+
export type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
23
|
+
|
|
24
|
+
/** The result interface if validation succeeds. */
|
|
25
|
+
export interface SuccessResult<Output> {
|
|
26
|
+
/** The typed output value. */
|
|
27
|
+
readonly value: Output;
|
|
28
|
+
/** The non-existent issues. */
|
|
29
|
+
readonly issues?: undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The result interface if validation fails. */
|
|
33
|
+
export interface FailureResult {
|
|
34
|
+
/** The issues of failed validation. */
|
|
35
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** The issue interface of the failure output. */
|
|
39
|
+
export interface Issue {
|
|
40
|
+
/** The error message of the issue. */
|
|
41
|
+
readonly message: string;
|
|
42
|
+
/** The path of the issue, if any. */
|
|
43
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The path segment interface of the issue. */
|
|
47
|
+
export interface PathSegment {
|
|
48
|
+
/** The key representing a path segment. */
|
|
49
|
+
readonly key: PropertyKey;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The Standard Schema types interface. */
|
|
53
|
+
export interface Types<Input = unknown, Output = Input> {
|
|
54
|
+
/** The input type of the schema. */
|
|
55
|
+
readonly input: Input;
|
|
56
|
+
/** The output type of the schema. */
|
|
57
|
+
readonly output: Output;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Infers the input type of a Standard Schema. */
|
|
61
|
+
export type InferInput<Schema extends StandardSchemaV1> = NonNullable<
|
|
62
|
+
Schema['~standard']['types']
|
|
63
|
+
>['input'];
|
|
64
|
+
|
|
65
|
+
/** Infers the output type of a Standard Schema. */
|
|
66
|
+
export type InferOutput<Schema extends StandardSchemaV1> = NonNullable<
|
|
67
|
+
Schema['~standard']['types']
|
|
68
|
+
>['output'];
|
|
69
|
+
}
|