@agentuity/core 0.0.29 → 0.0.30

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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/dist/index.js +0 -1014
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentuity/core",
3
- "version": "0.0.29",
3
+ "version": "0.0.30",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "scripts": {
19
19
  "clean": "rm -rf dist",
20
- "build": "bun build --target bun src/index.ts --outdir ./dist && bunx tsc --build --emitDeclarationOnly --force",
20
+ "build": "bunx tsc --build --emitDeclarationOnly --force",
21
21
  "typecheck": "bunx tsc --noEmit",
22
22
  "prepublishOnly": "bun run clean && bun run build"
23
23
  },
package/dist/index.js DELETED
@@ -1,1014 +0,0 @@
1
- // @bun
2
- var __create = Object.create;
3
- var __getProtoOf = Object.getPrototypeOf;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __toESM = (mod, isNodeMode, target) => {
8
- target = mod != null ? __create(__getProtoOf(mod)) : {};
9
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
- for (let key of __getOwnPropNames(mod))
11
- if (!__hasOwnProp.call(to, key))
12
- __defProp(to, key, {
13
- get: () => mod[key],
14
- enumerable: true
15
- });
16
- return to;
17
- };
18
- var __require = import.meta.require;
19
-
20
- // src/json.ts
21
- function safeStringify(obj) {
22
- const visited = new WeakSet;
23
- function replacer(_key, value) {
24
- if (typeof value === "bigint") {
25
- return value.toString();
26
- }
27
- if (typeof value === "object" && value !== null) {
28
- if (visited.has(value)) {
29
- return "[Circular]";
30
- }
31
- visited.add(value);
32
- return value;
33
- }
34
- return value;
35
- }
36
- return JSON.stringify(obj, replacer);
37
- }
38
- // src/services/exception.ts
39
- class ServiceException extends Error {
40
- statusCode;
41
- constructor(message, statusCode) {
42
- super(message);
43
- this.statusCode = statusCode;
44
- }
45
- }
46
- // src/services/_util.ts
47
- var buildUrl = (base, path, subpath, query) => {
48
- path = path.startsWith("/") ? path : `/${path}`;
49
- let url = base.replace(/\/$/, "") + path;
50
- if (subpath) {
51
- subpath = subpath.startsWith("/") ? subpath : `/${subpath}`;
52
- url += subpath;
53
- }
54
- if (query) {
55
- url += `?${query.toString()}`;
56
- }
57
- return url;
58
- };
59
- async function toServiceException(response) {
60
- switch (response.status) {
61
- case 401:
62
- case 403:
63
- return new ServiceException("Unauthorized", response.status);
64
- case 404:
65
- return new ServiceException("Not Found", response.status);
66
- default:
67
- }
68
- const ct = response.headers.get("content-type");
69
- if (ct?.includes("json")) {
70
- try {
71
- const payload = await response.json();
72
- if (payload.error) {
73
- return new ServiceException(payload.error, response.status);
74
- }
75
- if (payload.message) {
76
- return new ServiceException(payload.message, response.status);
77
- }
78
- return new ServiceException(JSON.stringify(payload), response.status);
79
- } catch {}
80
- }
81
- try {
82
- const body = await response.text();
83
- return new ServiceException(body, response.status);
84
- } catch {}
85
- return new ServiceException(response.statusText, response.status);
86
- }
87
- var binaryContentType = "application/octet-stream";
88
- var textContentType = "text/plain";
89
- var jsonContentType = "application/json";
90
- async function toPayload(data) {
91
- if (data === undefined || data === null) {
92
- return ["", textContentType];
93
- }
94
- switch (typeof data) {
95
- case "string":
96
- if (data.charAt(0) === "{" && data.charAt(data.length - 1) === "}" || data.charAt(0) === "[" && data.charAt(data.length - 1) === "]") {
97
- try {
98
- JSON.parse(data);
99
- return [data, jsonContentType];
100
- } catch {}
101
- }
102
- return [data, textContentType];
103
- case "boolean":
104
- return [String(data), textContentType];
105
- case "number":
106
- return [String(data), textContentType];
107
- case "object": {
108
- if (data instanceof ArrayBuffer) {
109
- return [data, binaryContentType];
110
- }
111
- if (data instanceof Buffer) {
112
- return [data, binaryContentType];
113
- }
114
- if (data instanceof ReadableStream) {
115
- return [data, binaryContentType];
116
- }
117
- if (data instanceof Promise) {
118
- return toPayload(await data);
119
- }
120
- if (data instanceof Function) {
121
- return toPayload(data());
122
- }
123
- return [safeStringify(data), jsonContentType];
124
- }
125
- }
126
- return ["", textContentType];
127
- }
128
- async function fromResponse(response) {
129
- const contentType = response.headers.get("content-type");
130
- if (!contentType || contentType?.includes("/json")) {
131
- return await response.json();
132
- }
133
- if (contentType?.includes("text/")) {
134
- return await response.text();
135
- }
136
- if (contentType?.includes(binaryContentType)) {
137
- return await response.arrayBuffer();
138
- }
139
- throw new ServiceException(`Unsupported content-type: ${contentType}`, response.status);
140
- }
141
-
142
- // src/services/keyvalue.ts
143
- class KeyValueStorageService {
144
- #adapter;
145
- #baseUrl;
146
- constructor(baseUrl, adapter) {
147
- this.#adapter = adapter;
148
- this.#baseUrl = baseUrl;
149
- }
150
- async get(name, key) {
151
- const url = buildUrl(this.#baseUrl, `/kv/2025-03-17/${encodeURIComponent(name)}/${encodeURIComponent(key)}`);
152
- const signal = AbortSignal.timeout(1e4);
153
- const res = await this.#adapter.invoke(url, {
154
- method: "GET",
155
- signal,
156
- telemetry: {
157
- name: "agentuity.keyvalue.get",
158
- attributes: {
159
- name,
160
- key
161
- }
162
- }
163
- });
164
- if (res.ok) {
165
- return {
166
- data: res.data,
167
- contentType: res.response.headers.get("content-type") ?? "application/octet-stream",
168
- exists: true
169
- };
170
- }
171
- if (res.response.status === 404) {
172
- return { exists: false };
173
- }
174
- throw await toServiceException(res.response);
175
- }
176
- async set(name, key, value, params) {
177
- let ttlstr = "";
178
- if (params?.ttl) {
179
- if (params.ttl < 60) {
180
- throw new Error(`ttl for keyvalue set must be at least 60 seconds, got ${params.ttl}`);
181
- }
182
- ttlstr = `/${params.ttl}`;
183
- }
184
- const url = buildUrl(this.#baseUrl, `/kv/2025-03-17/${encodeURIComponent(name)}/${encodeURIComponent(key)}${ttlstr}`);
185
- const [body, contentType] = await toPayload(value);
186
- const signal = AbortSignal.timeout(30000);
187
- const res = await this.#adapter.invoke(url, {
188
- method: "PUT",
189
- signal,
190
- body,
191
- contentType: params?.contentType || contentType,
192
- telemetry: {
193
- name: "agentuity.keyvalue.set",
194
- attributes: {
195
- name,
196
- key,
197
- ttl: ttlstr
198
- }
199
- }
200
- });
201
- if (res.ok) {
202
- return;
203
- }
204
- throw await toServiceException(res.response);
205
- }
206
- async delete(name, key) {
207
- const url = buildUrl(this.#baseUrl, `/kv/2025-03-17/${encodeURIComponent(name)}/${encodeURIComponent(key)}`);
208
- const signal = AbortSignal.timeout(30000);
209
- const res = await this.#adapter.invoke(url, {
210
- method: "DELETE",
211
- signal,
212
- telemetry: {
213
- name: "agentuity.keyvalue.delete",
214
- attributes: {
215
- name,
216
- key
217
- }
218
- }
219
- });
220
- if (res.ok) {
221
- return;
222
- }
223
- throw await toServiceException(res.response);
224
- }
225
- }
226
- // src/services/objectstore.ts
227
- class ObjectStorageService {
228
- #adapter;
229
- #baseUrl;
230
- constructor(baseUrl, adapter) {
231
- this.#baseUrl = baseUrl;
232
- this.#adapter = adapter;
233
- }
234
- async get(bucket, key) {
235
- if (!bucket?.trim()) {
236
- throw new Error("bucket is required and cannot be empty");
237
- }
238
- if (!key?.trim()) {
239
- throw new Error("key is required and cannot be empty");
240
- }
241
- const url = buildUrl(this.#baseUrl, `/object/2025-03-17/${encodeURIComponent(bucket)}/${encodeURIComponent(key)}`);
242
- const signal = AbortSignal.timeout(1e4);
243
- const options = {
244
- method: "GET",
245
- signal,
246
- telemetry: {
247
- name: "agentuity.objectstore.get",
248
- attributes: {
249
- "objectstore.bucket": bucket,
250
- "objectstore.key": key
251
- }
252
- }
253
- };
254
- try {
255
- const result = await this.#adapter.invoke(url, options);
256
- if (result.response.status === 404) {
257
- return { exists: false };
258
- }
259
- if (!result.ok) {
260
- throw new Error(`Failed to get object: ${result.response.statusText} (${result.response.status})`);
261
- }
262
- const data = result.data;
263
- if (!(data instanceof ArrayBuffer)) {
264
- throw new Error("Expected ArrayBuffer response from object store");
265
- }
266
- const contentType = result.response.headers.get("content-type") || "application/octet-stream";
267
- return {
268
- exists: true,
269
- data: new Uint8Array(data),
270
- contentType
271
- };
272
- } catch (err) {
273
- if (err instanceof Response) {
274
- throw await toServiceException(err);
275
- }
276
- throw err;
277
- }
278
- }
279
- async put(bucket, key, data, params) {
280
- if (!bucket?.trim()) {
281
- throw new Error("bucket is required and cannot be empty");
282
- }
283
- if (!key?.trim()) {
284
- throw new Error("key is required and cannot be empty");
285
- }
286
- if (!data) {
287
- throw new Error("data is required");
288
- }
289
- const url = buildUrl(this.#baseUrl, `/object/2025-03-17/${encodeURIComponent(bucket)}/${encodeURIComponent(key)}`);
290
- const headers = {
291
- "Content-Type": params?.contentType || "application/octet-stream"
292
- };
293
- if (params?.contentEncoding) {
294
- headers["Content-Encoding"] = params.contentEncoding;
295
- }
296
- if (params?.cacheControl) {
297
- headers["Cache-Control"] = params.cacheControl;
298
- }
299
- if (params?.contentDisposition) {
300
- headers["Content-Disposition"] = params.contentDisposition;
301
- }
302
- if (params?.contentLanguage) {
303
- headers["Content-Language"] = params.contentLanguage;
304
- }
305
- if (params?.metadata) {
306
- for (const [metaKey, metaValue] of Object.entries(params.metadata)) {
307
- headers[`x-metadata-${metaKey}`] = metaValue;
308
- }
309
- }
310
- let body;
311
- if (data instanceof ArrayBuffer) {
312
- body = data;
313
- } else if (data instanceof Uint8Array) {
314
- if (data.byteOffset !== 0 || data.byteLength !== data.buffer.byteLength) {
315
- body = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
316
- } else {
317
- body = data.buffer;
318
- }
319
- } else {
320
- body = data;
321
- }
322
- const signal = AbortSignal.timeout(30000);
323
- const options = {
324
- method: "PUT",
325
- headers,
326
- body,
327
- signal,
328
- telemetry: {
329
- name: "agentuity.objectstore.put",
330
- attributes: {
331
- "objectstore.bucket": bucket,
332
- "objectstore.key": key,
333
- "objectstore.contentType": params?.contentType || "application/octet-stream"
334
- }
335
- }
336
- };
337
- try {
338
- const result = await this.#adapter.invoke(url, options);
339
- if (!result.ok || result.response.status !== 200 && result.response.status !== 201) {
340
- throw new Error(`Failed to put object: ${result.response.statusText} (${result.response.status})`);
341
- }
342
- } catch (err) {
343
- if (err instanceof Response) {
344
- throw await toServiceException(err);
345
- }
346
- throw err;
347
- }
348
- }
349
- async delete(bucket, key) {
350
- if (!bucket?.trim()) {
351
- throw new Error("bucket is required and cannot be empty");
352
- }
353
- if (!key?.trim()) {
354
- throw new Error("key is required and cannot be empty");
355
- }
356
- const url = buildUrl(this.#baseUrl, `/object/2025-03-17/${encodeURIComponent(bucket)}/${encodeURIComponent(key)}`);
357
- const signal = AbortSignal.timeout(1e4);
358
- const options = {
359
- method: "DELETE",
360
- signal,
361
- telemetry: {
362
- name: "agentuity.objectstore.delete",
363
- attributes: {
364
- "objectstore.bucket": bucket,
365
- "objectstore.key": key
366
- }
367
- }
368
- };
369
- try {
370
- const result = await this.#adapter.invoke(url, options);
371
- if (result.response.status === 404) {
372
- return false;
373
- }
374
- if (result.response.status === 200) {
375
- return true;
376
- }
377
- throw new Error(`Failed to delete object: ${result.response.statusText} (${result.response.status})`);
378
- } catch (err) {
379
- if (err instanceof Response) {
380
- throw await toServiceException(err);
381
- }
382
- throw err;
383
- }
384
- }
385
- async createPublicURL(bucket, key, params) {
386
- if (!bucket?.trim()) {
387
- throw new Error("bucket is required and cannot be empty");
388
- }
389
- if (!key?.trim()) {
390
- throw new Error("key is required and cannot be empty");
391
- }
392
- const url = buildUrl(this.#baseUrl, `/object/2025-03-17/presigned/${encodeURIComponent(bucket)}/${encodeURIComponent(key)}`);
393
- const requestBody = {};
394
- if (params?.expiresDuration) {
395
- requestBody.expires = params.expiresDuration;
396
- }
397
- const signal = AbortSignal.timeout(1e4);
398
- const options = {
399
- method: "POST",
400
- contentType: "application/json",
401
- body: JSON.stringify(requestBody),
402
- signal,
403
- telemetry: {
404
- name: "agentuity.objectstore.createPublicURL",
405
- attributes: {
406
- "objectstore.bucket": bucket,
407
- "objectstore.key": key,
408
- "objectstore.expiresDuration": params?.expiresDuration?.toString() || ""
409
- }
410
- }
411
- };
412
- try {
413
- const result = await this.#adapter.invoke(url, options);
414
- if (!result.ok) {
415
- throw new Error(`Failed to create public URL: ${result.response.statusText} (${result.response.status})`);
416
- }
417
- const data = result.data;
418
- if (!data.success) {
419
- throw new Error(data.message || "Failed to create public URL");
420
- }
421
- return data.url;
422
- } catch (err) {
423
- if (err instanceof Error && err.message.includes("Object not found")) {
424
- throw err;
425
- }
426
- if (err instanceof Response) {
427
- throw await toServiceException(err);
428
- }
429
- throw err;
430
- }
431
- }
432
- }
433
- // src/services/stream.ts
434
- var encoder = new TextEncoder;
435
-
436
- class StreamImpl extends WritableStream {
437
- id;
438
- url;
439
- activeWriter = null;
440
- _compressed;
441
- _adapter;
442
- _sink;
443
- constructor(id, url, compressed, underlyingSink, adapter) {
444
- super(underlyingSink);
445
- this.id = id;
446
- this.url = url;
447
- this._compressed = compressed;
448
- this._adapter = adapter;
449
- this._sink = underlyingSink;
450
- }
451
- get bytesWritten() {
452
- return this._sink.total;
453
- }
454
- get compressed() {
455
- return this._compressed;
456
- }
457
- async write(chunk) {
458
- let binaryChunk;
459
- if (chunk instanceof Uint8Array) {
460
- binaryChunk = chunk;
461
- } else if (typeof chunk === "string") {
462
- binaryChunk = encoder.encode(chunk);
463
- } else if (chunk instanceof ArrayBuffer) {
464
- binaryChunk = new Uint8Array(chunk);
465
- } else if (typeof chunk === "object" && chunk !== null) {
466
- binaryChunk = encoder.encode(safeStringify(chunk));
467
- } else {
468
- binaryChunk = encoder.encode(String(chunk));
469
- }
470
- if (!this.activeWriter) {
471
- this.activeWriter = this.getWriter();
472
- }
473
- await this.activeWriter.write(binaryChunk);
474
- }
475
- async close() {
476
- try {
477
- if (this.activeWriter) {
478
- const writer2 = this.activeWriter;
479
- this.activeWriter = null;
480
- await writer2.close();
481
- return;
482
- }
483
- const writer = this.getWriter();
484
- await writer.close();
485
- } catch (error) {
486
- if (error instanceof TypeError && (error.message.includes("closed") || error.message.includes("errored") || error.message.includes("Cannot close"))) {
487
- return Promise.resolve();
488
- }
489
- if (error instanceof TypeError && error.message.includes("locked")) {
490
- return Promise.resolve();
491
- }
492
- throw error;
493
- }
494
- }
495
- getReader() {
496
- const url = this.url;
497
- const adapter = this._adapter;
498
- let ac = null;
499
- return new ReadableStream({
500
- async start(controller) {
501
- try {
502
- ac = new AbortController;
503
- const res = await adapter.invoke(url, {
504
- method: "GET",
505
- signal: ac.signal,
506
- binary: true
507
- });
508
- const response = res.response;
509
- if (!res.ok) {
510
- controller.error(new Error(`Failed to read stream: ${response.status} ${response.statusText}`));
511
- return;
512
- }
513
- if (!response.body) {
514
- controller.error(new Error("Response body is null"));
515
- return;
516
- }
517
- const reader = response.body.getReader();
518
- try {
519
- while (true) {
520
- const { done, value } = await reader.read();
521
- if (done)
522
- break;
523
- if (value)
524
- controller.enqueue(value);
525
- }
526
- controller.close();
527
- } catch (error) {
528
- controller.error(error);
529
- }
530
- } catch (error) {
531
- controller.error(error);
532
- }
533
- },
534
- cancel(reason) {
535
- if (ac) {
536
- ac.abort(reason);
537
- ac = null;
538
- }
539
- }
540
- });
541
- }
542
- }
543
-
544
- class UnderlyingSink {
545
- adapter;
546
- abortController = null;
547
- writer = null;
548
- putRequestPromise = null;
549
- total = 0;
550
- closed = false;
551
- url;
552
- props;
553
- constructor(url, adapter, props) {
554
- this.url = url;
555
- this.adapter = adapter;
556
- this.props = props;
557
- }
558
- async start() {
559
- this.abortController = new AbortController;
560
- let { readable, writable } = new TransformStream;
561
- if (this.props?.compress) {
562
- const { Readable, Writable } = await import("stream");
563
- const { readable: compressedReadable, writable: compressedWritable } = new TransformStream;
564
- const { createGzip } = await import("zlib");
565
- const gzipStream = createGzip();
566
- const nodeWritable = Writable.toWeb(gzipStream);
567
- const gzipReader = Readable.toWeb(gzipStream);
568
- gzipReader.pipeTo(compressedWritable).catch((error) => {
569
- this.abortController?.abort(error);
570
- this.writer?.abort(error).catch(() => {});
571
- });
572
- readable.pipeTo(nodeWritable).catch((error) => {
573
- this.abortController?.abort(error);
574
- this.writer?.abort(error).catch(() => {});
575
- });
576
- readable = compressedReadable;
577
- }
578
- this.writer = writable.getWriter();
579
- const headers = {
580
- "Content-Type": this.props?.contentType || "application/octet-stream"
581
- };
582
- if (this.props?.compress) {
583
- headers["Content-Encoding"] = "gzip";
584
- }
585
- this.putRequestPromise = this.adapter.invoke(this.url, {
586
- method: "PUT",
587
- headers,
588
- body: readable,
589
- signal: this.abortController.signal,
590
- duplex: "half"
591
- });
592
- }
593
- async write(chunk) {
594
- if (!this.writer) {
595
- throw new Error("Stream writer not initialized");
596
- }
597
- let binaryChunk;
598
- if (chunk instanceof Uint8Array) {
599
- binaryChunk = chunk;
600
- } else if (typeof chunk === "string") {
601
- binaryChunk = new TextEncoder().encode(chunk);
602
- } else if (chunk instanceof ArrayBuffer) {
603
- binaryChunk = new Uint8Array(chunk);
604
- } else if (typeof chunk === "object" && chunk !== null) {
605
- binaryChunk = new TextEncoder().encode(safeStringify(chunk));
606
- } else {
607
- binaryChunk = new TextEncoder().encode(String(chunk));
608
- }
609
- await this.writer.write(binaryChunk);
610
- this.total += binaryChunk.length;
611
- }
612
- async close() {
613
- if (this.closed) {
614
- return;
615
- }
616
- this.closed = true;
617
- if (this.writer) {
618
- await this.writer.close();
619
- this.writer = null;
620
- }
621
- if (this.putRequestPromise) {
622
- try {
623
- const res = await this.putRequestPromise;
624
- if (!res.ok) {
625
- throw new Error(`PUT request failed: ${res.response.status} ${res.response.statusText}`);
626
- }
627
- } catch (error) {
628
- if (error instanceof Error && error.name !== "AbortError") {
629
- throw error;
630
- }
631
- }
632
- this.putRequestPromise = null;
633
- }
634
- this.abortController = null;
635
- }
636
- async abort(reason) {
637
- if (this.writer) {
638
- await this.writer.abort(reason);
639
- this.writer = null;
640
- }
641
- if (this.abortController) {
642
- this.abortController.abort(reason);
643
- this.abortController = null;
644
- }
645
- this.putRequestPromise = null;
646
- }
647
- }
648
-
649
- class StreamStorageService {
650
- #adapter;
651
- #baseUrl;
652
- constructor(baseUrl, adapter) {
653
- this.#adapter = adapter;
654
- this.#baseUrl = baseUrl;
655
- }
656
- async create(name, props) {
657
- if (!name || name.length < 1 || name.length > 254) {
658
- throw new Error("Stream name must be between 1 and 254 characters");
659
- }
660
- const url = this.#baseUrl;
661
- const signal = AbortSignal.timeout(1e4);
662
- const attributes = {
663
- name
664
- };
665
- if (!props?.contentType) {
666
- props = props ?? {};
667
- props.contentType = "application/octet-stream";
668
- }
669
- if (props?.metadata) {
670
- attributes["metadata"] = JSON.stringify(props.metadata);
671
- }
672
- if (props?.contentType) {
673
- attributes["stream.content_type"] = props.contentType;
674
- }
675
- const body = JSON.stringify({
676
- name,
677
- ...props?.metadata && { metadata: props.metadata },
678
- ...props?.contentType && { contentType: props.contentType }
679
- });
680
- const res = await this.#adapter.invoke(url, {
681
- method: "POST",
682
- body,
683
- contentType: "application/json",
684
- signal,
685
- telemetry: {
686
- name: "agentuity.stream.create",
687
- attributes
688
- }
689
- });
690
- if (res.ok) {
691
- const streamUrl = buildUrl(this.#baseUrl, res.data.id);
692
- const underlyingSink = new UnderlyingSink(streamUrl, this.#adapter, props);
693
- const stream = new StreamImpl(res.data.id, streamUrl, props?.compress ?? false, underlyingSink, this.#adapter);
694
- return stream;
695
- }
696
- throw await toServiceException(res.response);
697
- }
698
- async list(params) {
699
- const attributes = {};
700
- if (params?.limit !== undefined) {
701
- if (params.limit <= 0 || params.limit > 1000) {
702
- throw new Error("limit must be greater than 0 and less than or equal to 1000");
703
- }
704
- attributes["limit"] = String(params.limit);
705
- }
706
- if (params?.offset !== undefined) {
707
- attributes["offset"] = String(params.offset);
708
- }
709
- if (params?.name) {
710
- attributes["name"] = params.name;
711
- }
712
- if (params?.metadata) {
713
- attributes["metadata"] = JSON.stringify(params.metadata);
714
- }
715
- const requestBody = {};
716
- if (params?.name) {
717
- requestBody.name = params.name;
718
- }
719
- if (params?.metadata) {
720
- requestBody.metadata = params.metadata;
721
- }
722
- if (params?.limit) {
723
- requestBody.limit = params.limit;
724
- }
725
- if (params?.offset) {
726
- requestBody.offset = params.offset;
727
- }
728
- const signal = AbortSignal.timeout(30000);
729
- const url = buildUrl(this.#baseUrl, "list");
730
- const res = await this.#adapter.invoke(url, {
731
- method: "POST",
732
- signal,
733
- body: JSON.stringify(requestBody),
734
- contentType: "application/json",
735
- telemetry: {
736
- name: "agentuity.stream.list",
737
- attributes
738
- }
739
- });
740
- if (res.ok) {
741
- return res.data;
742
- }
743
- throw await toServiceException(res.response);
744
- }
745
- async delete(id) {
746
- if (!id || typeof id !== "string" || id.trim().length === 0) {
747
- throw new Error("Stream id is required and must be a non-empty string");
748
- }
749
- const signal = AbortSignal.timeout(30000);
750
- const url = buildUrl(this.#baseUrl, id);
751
- const res = await this.#adapter.invoke(url, {
752
- method: "DELETE",
753
- signal,
754
- telemetry: {
755
- name: "agentuity.stream.delete",
756
- attributes: {
757
- "stream.id": id
758
- }
759
- }
760
- });
761
- if (res.ok) {
762
- return;
763
- }
764
- throw await toServiceException(res.response);
765
- }
766
- }
767
- // src/services/vector.ts
768
- class VectorStorageService {
769
- #adapter;
770
- #baseUrl;
771
- constructor(baseUrl, adapter) {
772
- this.#adapter = adapter;
773
- this.#baseUrl = baseUrl;
774
- }
775
- async upsert(name, ...documents) {
776
- if (!name || typeof name !== "string" || name.trim().length === 0) {
777
- throw new Error("Vector storage name is required and must be a non-empty string");
778
- }
779
- if (!documents || documents.length === 0) {
780
- throw new Error("At least one document is required for upsert");
781
- }
782
- for (const doc of documents) {
783
- if (!doc.key || typeof doc.key !== "string" || doc.key.trim().length === 0) {
784
- throw new Error("Each document must have a non-empty key");
785
- }
786
- if (!("embeddings" in doc) && !("document" in doc)) {
787
- throw new Error("Each document must have either embeddings or document text");
788
- }
789
- if ("embeddings" in doc && doc.embeddings) {
790
- if (!Array.isArray(doc.embeddings) || doc.embeddings.length === 0) {
791
- throw new Error("Embeddings must be a non-empty array of numbers");
792
- }
793
- }
794
- if ("document" in doc && doc.document) {
795
- if (typeof doc.document !== "string" || doc.document.trim().length === 0) {
796
- throw new Error("Document must be a non-empty string");
797
- }
798
- }
799
- }
800
- const url = buildUrl(this.#baseUrl, `/vector/2025-03-17/${encodeURIComponent(name)}`);
801
- const signal = AbortSignal.timeout(30000);
802
- const res = await this.#adapter.invoke(url, {
803
- method: "PUT",
804
- body: safeStringify(documents),
805
- contentType: "application/json",
806
- signal,
807
- telemetry: {
808
- name: "agentuity.vector.upsert",
809
- attributes: {
810
- name,
811
- count: String(documents.length)
812
- }
813
- }
814
- });
815
- if (res.ok) {
816
- if (res.data.success) {
817
- return res.data.data.map((o, index) => ({
818
- key: documents[index].key,
819
- id: o.id
820
- }));
821
- }
822
- if ("message" in res.data) {
823
- throw new Error(res.data.message);
824
- }
825
- }
826
- throw await toServiceException(res.response);
827
- }
828
- async get(name, key) {
829
- if (!name || typeof name !== "string" || name.trim().length === 0) {
830
- throw new Error("Vector storage name is required and must be a non-empty string");
831
- }
832
- if (!key || typeof key !== "string" || key.trim().length === 0) {
833
- throw new Error("Key is required and must be a non-empty string");
834
- }
835
- const url = buildUrl(this.#baseUrl, `/vector/2025-03-17/${encodeURIComponent(name)}/${encodeURIComponent(key)}`);
836
- const signal = AbortSignal.timeout(1e4);
837
- const res = await this.#adapter.invoke(url, {
838
- method: "GET",
839
- signal,
840
- telemetry: {
841
- name: "agentuity.vector.get",
842
- attributes: {
843
- name,
844
- key
845
- }
846
- }
847
- });
848
- if (res.response.status === 404) {
849
- return { exists: false };
850
- }
851
- if (res.ok) {
852
- if (res.data.success) {
853
- return {
854
- data: res.data.data,
855
- exists: true
856
- };
857
- }
858
- if ("message" in res.data) {
859
- throw new Error(res.data.message);
860
- }
861
- }
862
- throw await toServiceException(res.response);
863
- }
864
- async getMany(name, ...keys) {
865
- if (!name || typeof name !== "string" || name.trim().length === 0) {
866
- throw new Error("Vector storage name is required and must be a non-empty string");
867
- }
868
- if (keys.length === 0) {
869
- return new Map;
870
- }
871
- for (const key of keys) {
872
- if (!key || typeof key !== "string" || key.trim().length === 0) {
873
- throw new Error("All keys must be non-empty strings");
874
- }
875
- }
876
- const results = await Promise.all(keys.map((key) => this.get(name, key)));
877
- const resultMap = new Map;
878
- results.forEach((result, index) => {
879
- if (result.exists) {
880
- resultMap.set(keys[index], result.data);
881
- }
882
- });
883
- return resultMap;
884
- }
885
- async search(name, params) {
886
- if (!name || typeof name !== "string" || name.trim().length === 0) {
887
- throw new Error("Vector storage name is required and must be a non-empty string");
888
- }
889
- if (!params.query || typeof params.query !== "string" || params.query.trim().length === 0) {
890
- throw new Error("Query is required and must be a non-empty string");
891
- }
892
- if (params.limit !== undefined) {
893
- if (typeof params.limit !== "number" || params.limit <= 0) {
894
- throw new Error("Limit must be a positive number");
895
- }
896
- }
897
- if (params.similarity !== undefined) {
898
- if (typeof params.similarity !== "number" || params.similarity < 0 || params.similarity > 1) {
899
- throw new Error("Similarity must be a number between 0.0 and 1.0");
900
- }
901
- }
902
- if (params.metadata !== undefined) {
903
- if (typeof params.metadata !== "object" || params.metadata === null) {
904
- throw new Error("Metadata must be a valid object");
905
- }
906
- }
907
- const url = buildUrl(this.#baseUrl, `/vector/2025-03-17/search/${encodeURIComponent(name)}`);
908
- const signal = AbortSignal.timeout(30000);
909
- const attributes = {
910
- name,
911
- query: params.query
912
- };
913
- if (params.limit !== undefined) {
914
- attributes.limit = String(params.limit);
915
- }
916
- if (params.similarity !== undefined) {
917
- attributes.similarity = String(params.similarity);
918
- }
919
- const res = await this.#adapter.invoke(url, {
920
- method: "POST",
921
- body: safeStringify(params),
922
- contentType: "application/json",
923
- signal,
924
- telemetry: {
925
- name: "agentuity.vector.search",
926
- attributes
927
- }
928
- });
929
- if (res.response.status === 404) {
930
- return [];
931
- }
932
- if (res.ok) {
933
- if (res.data.success) {
934
- return res.data.data;
935
- }
936
- if ("message" in res.data) {
937
- throw new Error(res.data.message);
938
- }
939
- }
940
- throw await toServiceException(res.response);
941
- }
942
- async delete(name, ...keys) {
943
- if (!name || typeof name !== "string" || name.trim().length === 0) {
944
- throw new Error("Vector storage name is required and must be a non-empty string");
945
- }
946
- if (keys.length === 0) {
947
- return 0;
948
- }
949
- for (const key of keys) {
950
- if (!key || typeof key !== "string" || key.trim().length === 0) {
951
- throw new Error("All keys must be non-empty strings");
952
- }
953
- }
954
- const signal = AbortSignal.timeout(30000);
955
- let url;
956
- let body;
957
- if (keys.length === 1) {
958
- url = buildUrl(this.#baseUrl, `/vector/2025-03-17/${encodeURIComponent(name)}/${encodeURIComponent(keys[0])}`);
959
- } else {
960
- url = buildUrl(this.#baseUrl, `/vector/2025-03-17/${encodeURIComponent(name)}`);
961
- body = safeStringify({ keys });
962
- }
963
- const res = await this.#adapter.invoke(url, {
964
- method: "DELETE",
965
- ...body && { body, contentType: "application/json" },
966
- signal,
967
- telemetry: {
968
- name: "agentuity.vector.delete",
969
- attributes: {
970
- name,
971
- count: String(keys.length)
972
- }
973
- }
974
- });
975
- if (res.ok) {
976
- if (res.data.success) {
977
- return res.data.data;
978
- }
979
- if ("message" in res.data) {
980
- throw new Error(res.data.message);
981
- }
982
- }
983
- throw await toServiceException(res.response);
984
- }
985
- async exists(name) {
986
- if (!name || typeof name !== "string" || name.trim().length === 0) {
987
- throw new Error("Vector storage name is required and must be a non-empty string");
988
- }
989
- try {
990
- await this.search(name, { query: "_exists_check_", limit: 1 });
991
- return true;
992
- } catch (error) {
993
- if (error instanceof Error) {
994
- const statusMatch = error.message.match(/(\d{3})/);
995
- if (statusMatch && statusMatch[1] === "404") {
996
- return false;
997
- }
998
- }
999
- throw error;
1000
- }
1001
- }
1002
- }
1003
- export {
1004
- toServiceException,
1005
- toPayload,
1006
- safeStringify,
1007
- fromResponse,
1008
- buildUrl,
1009
- VectorStorageService,
1010
- StreamStorageService,
1011
- ServiceException,
1012
- ObjectStorageService,
1013
- KeyValueStorageService
1014
- };