@agentuity/core 1.0.29 → 1.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.
@@ -110,9 +110,12 @@ export interface KeyValueStats {
110
110
  export interface KeyValueItemWithMetadata<T = unknown> {
111
111
  value: T;
112
112
  contentType: string;
113
+ contentEncoding?: string | null;
113
114
  size: number;
114
- created_at: string;
115
- updated_at: string;
115
+ expiresAt?: string | null;
116
+ firstUsed?: number | null;
117
+ lastUsed?: number | null;
118
+ count?: number | null;
116
119
  }
117
120
 
118
121
  export type KVSortField = 'name' | 'size' | 'records' | 'created' | 'lastUsed';
@@ -284,6 +287,51 @@ export interface KeyValueStorage {
284
287
  createNamespace(name: string, params?: CreateNamespaceParams): Promise<void>;
285
288
  }
286
289
 
290
+ /**
291
+ * Decodes a base64 string to a Uint8Array.
292
+ */
293
+ function base64ToBytes(base64: string): Uint8Array {
294
+ const binaryString = atob(base64);
295
+ const bytes = new Uint8Array(binaryString.length);
296
+ for (let i = 0; i < binaryString.length; i++) {
297
+ bytes[i] = binaryString.charCodeAt(i);
298
+ }
299
+ return bytes;
300
+ }
301
+
302
+ /**
303
+ * Deserializes search result values from the server's wire format.
304
+ *
305
+ * The Go server stores values as []byte, which Go's json.Marshal
306
+ * base64-encodes when embedding in a JSON response. This function
307
+ * decodes each item's value from base64 and parses it according
308
+ * to its contentType, aligning search() behavior with get().
309
+ */
310
+ function deserializeSearchResults<T>(
311
+ data: Record<string, KeyValueItemWithMetadata<T>>
312
+ ): Record<string, KeyValueItemWithMetadata<T>> {
313
+ for (const item of Object.values(data)) {
314
+ if (typeof item.value === 'string') {
315
+ try {
316
+ const bytes = base64ToBytes(item.value);
317
+ const ct = (item.contentType ?? '').toLowerCase();
318
+
319
+ if (ct.includes('json')) {
320
+ const text = new TextDecoder().decode(bytes);
321
+ item.value = JSON.parse(text) as T;
322
+ } else if (ct.startsWith('text/')) {
323
+ item.value = new TextDecoder().decode(bytes) as T;
324
+ } else {
325
+ item.value = bytes.buffer as T;
326
+ }
327
+ } catch {
328
+ // If base64 decoding or parsing fails, leave value as-is
329
+ }
330
+ }
331
+ }
332
+ return data;
333
+ }
334
+
287
335
  export class KeyValueStorageService implements KeyValueStorage {
288
336
  #adapter: FetchAdapter;
289
337
  #baseUrl: string;
@@ -510,7 +558,7 @@ export class KeyValueStorageService implements KeyValueStorage {
510
558
  },
511
559
  });
512
560
  if (res.ok) {
513
- return res.data;
561
+ return deserializeSearchResults<T>(res.data);
514
562
  }
515
563
  throw await toServiceException('GET', url, res.response);
516
564
  }
@@ -1,84 +1,365 @@
1
1
  import { FetchAdapter } from './adapter.ts';
2
2
  import { buildUrl, toServiceException } from './_util.ts';
3
3
 
4
+ /**
5
+ * A scheduled job that fires at intervals defined by a cron expression.
6
+ *
7
+ * Schedules are the top-level resource. Each schedule has one or more
8
+ * {@link ScheduleDestination | destinations} that receive HTTP callbacks
9
+ * when the schedule fires.
10
+ */
4
11
  export interface Schedule {
12
+ /**
13
+ * Unique identifier for the schedule.
14
+ *
15
+ * @remarks Prefixed with `sch_`.
16
+ */
5
17
  id: string;
18
+
19
+ /**
20
+ * ISO 8601 timestamp when the schedule was created.
21
+ */
6
22
  created_at: string;
23
+
24
+ /**
25
+ * ISO 8601 timestamp when the schedule was last modified.
26
+ */
7
27
  updated_at: string;
28
+
29
+ /**
30
+ * ID of the user who created the schedule.
31
+ */
8
32
  created_by: string;
33
+
34
+ /**
35
+ * Human-readable name for the schedule.
36
+ */
9
37
  name: string;
38
+
39
+ /**
40
+ * Optional description of the schedule's purpose.
41
+ */
10
42
  description: string | null;
43
+
44
+ /**
45
+ * A cron expression defining the schedule's firing interval
46
+ * (e.g., `'0 9 * * 1-5'` for weekdays at 9 AM).
47
+ *
48
+ * @remarks Validated on creation and update by the server.
49
+ * Supports standard five-field cron syntax including step values (e.g., every 5 minutes).
50
+ */
11
51
  expression: string;
52
+
53
+ /**
54
+ * ISO 8601 timestamp of the next scheduled execution.
55
+ *
56
+ * @remarks Automatically computed from the cron expression. Updated each time
57
+ * the schedule fires or the expression is changed.
58
+ */
12
59
  due_date: string;
13
60
  }
14
61
 
62
+ /**
63
+ * A delivery target for a scheduled job.
64
+ *
65
+ * When the schedule fires, an HTTP request is sent to each of its destinations.
66
+ */
15
67
  export interface ScheduleDestination {
68
+ /**
69
+ * Unique identifier for the destination.
70
+ *
71
+ * @remarks Prefixed with `sdst_`.
72
+ */
16
73
  id: string;
74
+
75
+ /**
76
+ * The ID of the parent schedule.
77
+ */
17
78
  schedule_id: string;
79
+
80
+ /**
81
+ * ISO 8601 timestamp when the destination was created.
82
+ */
18
83
  created_at: string;
84
+
85
+ /**
86
+ * ISO 8601 timestamp when the destination was last updated.
87
+ */
19
88
  updated_at: string;
89
+
90
+ /**
91
+ * ID of the user who created the destination.
92
+ */
20
93
  created_by: string;
94
+
95
+ /**
96
+ * The destination type: `'url'` for HTTP endpoints or `'sandbox'` for Agentuity sandbox execution.
97
+ */
21
98
  type: 'url' | 'sandbox';
99
+
100
+ /**
101
+ * Type-specific destination configuration.
102
+ *
103
+ * @remarks
104
+ * For `'url'` type:
105
+ * ```typescript
106
+ * { url: string; headers?: Record<string, string>; method?: string }
107
+ * ```
108
+ * For `'sandbox'` type: sandbox-specific configuration.
109
+ */
22
110
  config: Record<string, unknown>;
23
111
  }
24
112
 
113
+ /**
114
+ * A record of a single delivery attempt for a scheduled execution.
115
+ *
116
+ * Each time a schedule fires, one delivery record is created per destination.
117
+ * Failed deliveries may be retried automatically.
118
+ */
25
119
  export interface ScheduleDelivery {
120
+ /**
121
+ * Unique identifier for the delivery attempt.
122
+ */
26
123
  id: string;
124
+
125
+ /**
126
+ * ISO 8601 timestamp when the delivery was attempted.
127
+ */
27
128
  date: string;
129
+
130
+ /**
131
+ * The ID of the schedule that triggered this delivery.
132
+ */
28
133
  schedule_id: string;
134
+
135
+ /**
136
+ * The ID of the destination this delivery was sent to.
137
+ */
29
138
  schedule_destination_id: string;
139
+
140
+ /**
141
+ * Delivery status: `'pending'` (queued), `'success'` (delivered), or `'failed'` (delivery error).
142
+ */
30
143
  status: 'pending' | 'success' | 'failed';
144
+
145
+ /**
146
+ * Number of retry attempts made for this delivery.
147
+ */
31
148
  retries: number;
149
+
150
+ /**
151
+ * Error message if the delivery failed, `null` on success.
152
+ */
32
153
  error: string | null;
154
+
155
+ /**
156
+ * The response received from the destination, or `null` if no response.
157
+ */
33
158
  response: Record<string, unknown> | null;
34
159
  }
35
160
 
161
+ /**
162
+ * Parameters for creating a new schedule.
163
+ */
36
164
  export interface CreateScheduleParams {
165
+ /**
166
+ * Human-readable name for the schedule.
167
+ */
37
168
  name: string;
169
+
170
+ /**
171
+ * Optional description of the schedule's purpose.
172
+ */
38
173
  description?: string;
174
+
175
+ /**
176
+ * Cron expression defining when the schedule fires
177
+ * (e.g., `'0 * * * *'` for every hour).
178
+ *
179
+ * @remarks Must be a valid cron expression. Validated by the server on creation.
180
+ * Supports standard five-field cron syntax including step values.
181
+ */
39
182
  expression: string;
183
+
184
+ /**
185
+ * Optional array of destinations to create alongside the schedule.
186
+ *
187
+ * @remarks Destinations are created atomically with the schedule — if any destination
188
+ * fails validation, the entire creation is rolled back.
189
+ */
40
190
  destinations?: CreateScheduleDestinationParams[];
41
191
  }
42
192
 
193
+ /**
194
+ * Parameters for creating a new destination on a schedule.
195
+ */
43
196
  export interface CreateScheduleDestinationParams {
197
+ /**
198
+ * The destination type: `'url'` for HTTP endpoints or `'sandbox'` for Agentuity sandbox execution.
199
+ */
44
200
  type: 'url' | 'sandbox';
201
+
202
+ /**
203
+ * Type-specific destination configuration.
204
+ *
205
+ * @remarks
206
+ * For `'url'` type:
207
+ * ```typescript
208
+ * { url: string; headers?: Record<string, string>; method?: string }
209
+ * ```
210
+ * For `'sandbox'` type: sandbox-specific configuration.
211
+ */
45
212
  config: Record<string, unknown>;
46
213
  }
47
214
 
215
+ /**
216
+ * Parameters for updating an existing schedule.
217
+ *
218
+ * All fields are optional; only provided fields are updated.
219
+ */
48
220
  export interface UpdateScheduleParams {
221
+ /**
222
+ * Updated human-readable name for the schedule.
223
+ */
49
224
  name?: string;
225
+
226
+ /**
227
+ * Updated description.
228
+ */
50
229
  description?: string;
230
+
231
+ /**
232
+ * Updated cron expression. If changed, the `due_date` is automatically recomputed.
233
+ *
234
+ * @remarks Must be a valid cron expression. Validated by the server on update.
235
+ */
51
236
  expression?: string;
52
237
  }
53
238
 
239
+ /**
240
+ * Paginated list of schedules.
241
+ */
54
242
  export interface ScheduleListResult {
243
+ /**
244
+ * Array of schedule records for the current page.
245
+ */
55
246
  schedules: Schedule[];
247
+
248
+ /**
249
+ * Total number of schedules across all pages.
250
+ */
56
251
  total: number;
57
252
  }
58
253
 
254
+ /**
255
+ * A schedule with its associated destinations.
256
+ */
59
257
  export interface ScheduleGetResult {
258
+ /**
259
+ * The schedule record.
260
+ */
60
261
  schedule: Schedule;
262
+
263
+ /**
264
+ * Array of destinations configured for this schedule.
265
+ */
61
266
  destinations: ScheduleDestination[];
62
267
  }
63
268
 
269
+ /**
270
+ * Result of creating a schedule, including any destinations created atomically.
271
+ */
64
272
  export interface ScheduleCreateResult {
273
+ /**
274
+ * The newly created schedule record.
275
+ */
65
276
  schedule: Schedule;
277
+
278
+ /**
279
+ * Array of destinations that were created alongside the schedule.
280
+ */
66
281
  destinations: ScheduleDestination[];
67
282
  }
68
283
 
284
+ /**
285
+ * List of delivery attempts for a schedule.
286
+ */
69
287
  export interface ScheduleDeliveryListResult {
288
+ /**
289
+ * Array of delivery attempt records.
290
+ */
70
291
  deliveries: ScheduleDelivery[];
71
292
  }
72
293
 
294
+ /**
295
+ * Client for the Agentuity Schedule service.
296
+ *
297
+ * Provides methods for creating, managing, and monitoring cron-based scheduled jobs.
298
+ * Schedules fire at intervals defined by cron expressions and deliver HTTP requests
299
+ * to configured destinations (URLs or sandboxes).
300
+ *
301
+ * The service supports:
302
+ * - CRUD operations on schedules and their destinations
303
+ * - Cron expression validation
304
+ * - Delivery history and monitoring
305
+ * - Automatic due date computation from cron expressions
306
+ *
307
+ * All methods are instrumented with OpenTelemetry spans for observability.
308
+ *
309
+ * @example
310
+ * ```typescript
311
+ * const schedules = new ScheduleService(baseUrl, adapter);
312
+ *
313
+ * // Create a schedule that fires every hour
314
+ * const result = await schedules.create({
315
+ * name: 'Hourly Sync',
316
+ * expression: '0 * * * *',
317
+ * destinations: [{ type: 'url', config: { url: 'https://example.com/sync' } }],
318
+ * });
319
+ *
320
+ * // List all schedules
321
+ * const { schedules: list, total } = await schedules.list();
322
+ * ```
323
+ */
73
324
  export class ScheduleService {
74
325
  #adapter: FetchAdapter;
75
326
  #baseUrl: string;
76
327
 
328
+ /**
329
+ * Create a new ScheduleService instance.
330
+ *
331
+ * @param baseUrl - The base URL for the Agentuity Schedule API (e.g., `https://api.agentuity.com`)
332
+ * @param adapter - The HTTP fetch adapter used for making API requests
333
+ */
77
334
  constructor(baseUrl: string, adapter: FetchAdapter) {
78
335
  this.#adapter = adapter;
79
336
  this.#baseUrl = baseUrl;
80
337
  }
81
338
 
339
+ /**
340
+ * Create a new schedule with optional destinations.
341
+ *
342
+ * The schedule and its destinations are created atomically — if any validation
343
+ * fails, the entire operation is rolled back.
344
+ *
345
+ * @param params - The schedule creation parameters including name, cron expression, and optional destinations
346
+ * @returns The created schedule and its destinations
347
+ * @throws ServiceException on API errors (e.g., invalid cron expression, invalid destination URL)
348
+ *
349
+ * @example
350
+ * ```typescript
351
+ * const result = await schedules.create({
352
+ * name: 'Daily Report',
353
+ * description: 'Generate and send daily reports',
354
+ * expression: '0 9 * * *',
355
+ * destinations: [
356
+ * { type: 'url', config: { url: 'https://example.com/reports' } },
357
+ * ],
358
+ * });
359
+ * console.log('Created schedule:', result.schedule.id);
360
+ * console.log('Next run:', result.schedule.due_date);
361
+ * ```
362
+ */
82
363
  async create(params: CreateScheduleParams): Promise<ScheduleCreateResult> {
83
364
  const url = buildUrl(this.#baseUrl, '/schedule/create/2026-02-24');
84
365
  const signal = AbortSignal.timeout(30_000);
@@ -103,6 +384,25 @@ export class ScheduleService {
103
384
  throw await toServiceException('POST', url, res.response);
104
385
  }
105
386
 
387
+ /**
388
+ * List all schedules with optional pagination.
389
+ *
390
+ * @param params - Optional pagination parameters
391
+ * @param params.limit - Maximum number of schedules to return (max 500)
392
+ * @param params.offset - Number of schedules to skip for pagination
393
+ * @returns A paginated list of schedules with the total count
394
+ * @throws ServiceException on API errors
395
+ *
396
+ * @example
397
+ * ```typescript
398
+ * // List first page
399
+ * const { schedules, total } = await service.list({ limit: 20 });
400
+ * console.log(`Showing ${schedules.length} of ${total} schedules`);
401
+ *
402
+ * // Paginate through all schedules
403
+ * const page2 = await service.list({ limit: 20, offset: 20 });
404
+ * ```
405
+ */
106
406
  async list(params?: { limit?: number; offset?: number }): Promise<ScheduleListResult> {
107
407
  const qs = new URLSearchParams();
108
408
  if (params?.limit !== undefined) {
@@ -136,6 +436,21 @@ export class ScheduleService {
136
436
  throw await toServiceException('GET', url, res.response);
137
437
  }
138
438
 
439
+ /**
440
+ * Get a schedule by its ID, including all configured destinations.
441
+ *
442
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
443
+ * @returns The schedule record and its array of destinations
444
+ * @throws ServiceException on API errors (including 404 if not found)
445
+ *
446
+ * @example
447
+ * ```typescript
448
+ * const { schedule, destinations } = await service.get('sch_abc123');
449
+ * console.log('Schedule:', schedule.name);
450
+ * console.log('Next run:', schedule.due_date);
451
+ * console.log('Destinations:', destinations.length);
452
+ * ```
453
+ */
139
454
  async get(scheduleId: string): Promise<ScheduleGetResult> {
140
455
  const url = buildUrl(
141
456
  this.#baseUrl,
@@ -164,6 +479,27 @@ export class ScheduleService {
164
479
  throw await toServiceException('GET', url, res.response);
165
480
  }
166
481
 
482
+ /**
483
+ * Update an existing schedule. Only the provided fields are modified.
484
+ *
485
+ * @remarks If the `expression` field is changed, the `due_date` is automatically
486
+ * recomputed based on the new cron expression.
487
+ *
488
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
489
+ * @param params - The fields to update (all optional)
490
+ * @returns The updated schedule record
491
+ * @throws ServiceException on API errors (e.g., invalid cron expression, schedule not found)
492
+ *
493
+ * @example
494
+ * ```typescript
495
+ * // Update the name and expression
496
+ * const { schedule } = await service.update('sch_abc123', {
497
+ * name: 'Daily Midnight Sync',
498
+ * expression: '0 0 * * *',
499
+ * });
500
+ * console.log('Updated. Next run:', schedule.due_date);
501
+ * ```
502
+ */
167
503
  async update(scheduleId: string, params: UpdateScheduleParams): Promise<{ schedule: Schedule }> {
168
504
  const url = buildUrl(
169
505
  this.#baseUrl,
@@ -190,6 +526,18 @@ export class ScheduleService {
190
526
  throw await toServiceException('PUT', url, res.response);
191
527
  }
192
528
 
529
+ /**
530
+ * Delete a schedule and all of its destinations and delivery history.
531
+ *
532
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
533
+ * @throws ServiceException on API errors (e.g., schedule not found)
534
+ *
535
+ * @example
536
+ * ```typescript
537
+ * await service.delete('sch_abc123');
538
+ * console.log('Schedule deleted');
539
+ * ```
540
+ */
193
541
  async delete(scheduleId: string): Promise<void> {
194
542
  const url = buildUrl(
195
543
  this.#baseUrl,
@@ -214,6 +562,26 @@ export class ScheduleService {
214
562
  throw await toServiceException('DELETE', url, res.response);
215
563
  }
216
564
 
565
+ /**
566
+ * Create a new destination on an existing schedule.
567
+ *
568
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
569
+ * @param params - The destination configuration including type and type-specific config
570
+ * @returns The newly created destination record
571
+ * @throws ServiceException on API errors (e.g., invalid URL, schedule not found)
572
+ *
573
+ * @example
574
+ * ```typescript
575
+ * const { destination } = await service.createDestination('sch_abc123', {
576
+ * type: 'url',
577
+ * config: {
578
+ * url: 'https://example.com/webhook',
579
+ * headers: { 'Authorization': 'Bearer token' },
580
+ * },
581
+ * });
582
+ * console.log('Destination created:', destination.id);
583
+ * ```
584
+ */
217
585
  async createDestination(
218
586
  scheduleId: string,
219
587
  params: CreateScheduleDestinationParams
@@ -244,6 +612,18 @@ export class ScheduleService {
244
612
  throw await toServiceException('POST', url, res.response);
245
613
  }
246
614
 
615
+ /**
616
+ * Delete a destination from a schedule.
617
+ *
618
+ * @param destinationId - The destination ID (prefixed with `sdst_`)
619
+ * @throws ServiceException on API errors (e.g., destination not found)
620
+ *
621
+ * @example
622
+ * ```typescript
623
+ * await service.deleteDestination('sdst_xyz789');
624
+ * console.log('Destination removed');
625
+ * ```
626
+ */
247
627
  async deleteDestination(destinationId: string): Promise<void> {
248
628
  const url = buildUrl(
249
629
  this.#baseUrl,
@@ -268,6 +648,27 @@ export class ScheduleService {
268
648
  throw await toServiceException('DELETE', url, res.response);
269
649
  }
270
650
 
651
+ /**
652
+ * List delivery attempts for a schedule with optional pagination.
653
+ *
654
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
655
+ * @param params - Optional pagination parameters
656
+ * @param params.limit - Maximum number of deliveries to return
657
+ * @param params.offset - Number of deliveries to skip for pagination
658
+ * @returns A list of delivery attempt records
659
+ * @throws ServiceException on API errors (including 404 if schedule not found)
660
+ *
661
+ * @example
662
+ * ```typescript
663
+ * const { deliveries } = await service.listDeliveries('sch_abc123');
664
+ * for (const d of deliveries) {
665
+ * console.log(`${d.date}: ${d.status} (retries: ${d.retries})`);
666
+ * if (d.error) {
667
+ * console.error(' Error:', d.error);
668
+ * }
669
+ * }
670
+ * ```
671
+ */
271
672
  async listDeliveries(
272
673
  scheduleId: string,
273
674
  params?: { limit?: number; offset?: number }
@@ -308,6 +709,26 @@ export class ScheduleService {
308
709
  throw await toServiceException('GET', url, res.response);
309
710
  }
310
711
 
712
+ /**
713
+ * Get a specific destination for a schedule by its ID.
714
+ *
715
+ * @remarks This is a convenience method that fetches the schedule and filters
716
+ * its destinations client-side. For large destination lists, prefer using
717
+ * {@link get} directly.
718
+ *
719
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
720
+ * @param destinationId - The destination ID (prefixed with `sdst_`)
721
+ * @returns The matching destination record
722
+ * @throws Error if the destination is not found within the schedule
723
+ * @throws ServiceException on API errors when fetching the schedule
724
+ *
725
+ * @example
726
+ * ```typescript
727
+ * const dest = await service.getDestination('sch_abc123', 'sdst_xyz789');
728
+ * console.log('Destination type:', dest.type);
729
+ * console.log('Config:', dest.config);
730
+ * ```
731
+ */
311
732
  async getDestination(scheduleId: string, destinationId: string): Promise<ScheduleDestination> {
312
733
  const result = await this.get(scheduleId);
313
734
  const destination = result.destinations.find((d) => d.id === destinationId);
@@ -317,6 +738,27 @@ export class ScheduleService {
317
738
  return destination;
318
739
  }
319
740
 
741
+ /**
742
+ * Get a specific delivery record by its ID.
743
+ *
744
+ * @remarks This is a convenience method that lists deliveries and filters
745
+ * client-side. Use the optional `params` to control the search window if
746
+ * the delivery may not be in the first page of results.
747
+ *
748
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
749
+ * @param deliveryId - The delivery ID to find
750
+ * @param params - Optional pagination parameters to control the search window
751
+ * @returns The matching delivery record
752
+ * @throws Error if the delivery is not found in the result set
753
+ * @throws ServiceException on API errors when listing deliveries
754
+ *
755
+ * @example
756
+ * ```typescript
757
+ * const delivery = await service.getDelivery('sch_abc123', 'del_xyz789');
758
+ * console.log('Status:', delivery.status);
759
+ * console.log('Retries:', delivery.retries);
760
+ * ```
761
+ */
320
762
  async getDelivery(
321
763
  scheduleId: string,
322
764
  deliveryId: string,