@agentuity/core 2.0.1 → 2.0.2

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 (52) hide show
  1. package/AGENTS.md +15 -0
  2. package/dist/deprecation.d.ts +1 -1
  3. package/dist/deprecation.d.ts.map +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/services/auth/index.d.ts +1 -1
  9. package/dist/services/auth/index.d.ts.map +1 -1
  10. package/dist/services/index.d.ts +1 -0
  11. package/dist/services/index.d.ts.map +1 -1
  12. package/dist/services/index.js +1 -0
  13. package/dist/services/index.js.map +1 -1
  14. package/dist/services/queue/destinations.d.ts +10 -0
  15. package/dist/services/queue/destinations.d.ts.map +1 -1
  16. package/dist/services/queue/destinations.js.map +1 -1
  17. package/dist/services/queue/types.d.ts +24 -33
  18. package/dist/services/queue/types.d.ts.map +1 -1
  19. package/dist/services/queue/types.js +11 -5
  20. package/dist/services/queue/types.js.map +1 -1
  21. package/dist/services/webhook/types.d.ts +1 -0
  22. package/dist/services/webhook/types.d.ts.map +1 -1
  23. package/dist/services/webhook/types.js +1 -0
  24. package/dist/services/webhook/types.js.map +1 -1
  25. package/dist/services/workflow/api-reference.d.ts +4 -0
  26. package/dist/services/workflow/api-reference.d.ts.map +1 -0
  27. package/dist/services/workflow/api-reference.js +335 -0
  28. package/dist/services/workflow/api-reference.js.map +1 -0
  29. package/dist/services/workflow/index.d.ts +3 -0
  30. package/dist/services/workflow/index.d.ts.map +1 -0
  31. package/dist/services/workflow/index.js +3 -0
  32. package/dist/services/workflow/index.js.map +1 -0
  33. package/dist/services/workflow/service.d.ts +235 -0
  34. package/dist/services/workflow/service.d.ts.map +1 -0
  35. package/dist/services/workflow/service.js +553 -0
  36. package/dist/services/workflow/service.js.map +1 -0
  37. package/dist/services/workflow/types.d.ts +270 -0
  38. package/dist/services/workflow/types.d.ts.map +1 -0
  39. package/dist/services/workflow/types.js +174 -0
  40. package/dist/services/workflow/types.js.map +1 -0
  41. package/package.json +2 -2
  42. package/src/deprecation.ts +1 -1
  43. package/src/index.ts +1 -1
  44. package/src/services/auth/index.ts +1 -1
  45. package/src/services/index.ts +1 -0
  46. package/src/services/queue/destinations.ts +1 -1
  47. package/src/services/queue/types.ts +11 -5
  48. package/src/services/webhook/types.ts +1 -0
  49. package/src/services/workflow/api-reference.ts +350 -0
  50. package/src/services/workflow/index.ts +2 -0
  51. package/src/services/workflow/service.ts +633 -0
  52. package/src/services/workflow/types.ts +233 -0
@@ -0,0 +1,633 @@
1
+ import { buildUrl, toServiceException } from '../_util.ts';
2
+ import { StructuredError } from '../../error.ts';
3
+ import type {
4
+ CreateWorkflowRequest,
5
+ ListWorkflowsRequest,
6
+ UpdateWorkflowGraphRequest,
7
+ UpdateWorkflowRequest,
8
+ WorkflowActivity,
9
+ WorkflowCreateResult,
10
+ WorkflowDelivery,
11
+ WorkflowExecution,
12
+ WorkflowGetResult,
13
+ WorkflowListResult,
14
+ WorkflowUpdateResult,
15
+ TestWorkflowRequest,
16
+ TestWorkflowResult,
17
+ } from './types.ts';
18
+ import type { FetchAdapter } from '../adapter.ts';
19
+
20
+ /**
21
+ * Thrown when the API returns a success HTTP status but the response body indicates failure.
22
+ */
23
+ const WorkflowResponseError = StructuredError('WorkflowResponseError')<{
24
+ status: number;
25
+ }>();
26
+
27
+ /**
28
+ * Creates an {@link AbortSignal} that will abort after the specified timeout.
29
+ *
30
+ * @remarks
31
+ * Falls back to a manual `AbortController` + `setTimeout` if `AbortSignal.timeout`
32
+ * is not available in the runtime.
33
+ *
34
+ * @param ms - Timeout in milliseconds
35
+ * @returns An abort signal that triggers after `ms` milliseconds
36
+ *
37
+ * @default 30000
38
+ */
39
+ function createTimeoutSignal(ms = 30_000): AbortSignal {
40
+ if (typeof AbortSignal.timeout === 'function') {
41
+ return AbortSignal.timeout(ms);
42
+ }
43
+ const controller = new AbortController();
44
+ const timer = setTimeout(() => controller.abort(), ms);
45
+ controller.signal.addEventListener('abort', () => clearTimeout(timer), { once: true });
46
+ return controller.signal;
47
+ }
48
+
49
+ /**
50
+ * Internal API success response envelope for workflow operations.
51
+ */
52
+ type WorkflowSuccessResponse<T> = { success: true; data: T };
53
+
54
+ /**
55
+ * Internal API error response envelope for workflow operations.
56
+ */
57
+ type WorkflowErrorResponse = { success: false; message: string };
58
+
59
+ /**
60
+ * Discriminated union of API success and error responses for workflow operations.
61
+ */
62
+ type WorkflowResponse<T> = WorkflowSuccessResponse<T> | WorkflowErrorResponse;
63
+
64
+ /**
65
+ * Client for the Agentuity Workflow service.
66
+ *
67
+ * Provides methods for creating and managing workflows that route events from
68
+ * sources (email, queue, webhook, schedule) to configured destinations. The
69
+ * service supports:
70
+ *
71
+ * - **Workflows**: Named routing configurations with a source and graph
72
+ * - **Executions**: Records of workflow runs with step-level detail
73
+ * - **Deliveries**: Records of destination delivery attempts
74
+ * - **Testing**: Send test payloads through a workflow
75
+ *
76
+ * All methods are instrumented with OpenTelemetry spans for observability.
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const workflows = new WorkflowService(baseUrl, adapter);
81
+ *
82
+ * // Create a workflow
83
+ * const { workflow } = await workflows.create({
84
+ * name: 'GitHub to Slack',
85
+ * source_type: 'webhook',
86
+ * source_ref_id: 'wh_abc123',
87
+ * });
88
+ *
89
+ * // List active workflows
90
+ * const { workflows: list } = await workflows.list({ status: 'enabled' });
91
+ * ```
92
+ */
93
+ export class WorkflowService {
94
+ #baseUrl: string;
95
+ #adapter: FetchAdapter;
96
+
97
+ /**
98
+ * Creates a new WorkflowService instance.
99
+ *
100
+ * @param baseUrl - The base URL of the workflow API
101
+ * @param adapter - The HTTP fetch adapter used for making API requests
102
+ */
103
+ constructor(baseUrl: string, adapter: FetchAdapter) {
104
+ this.#baseUrl = baseUrl;
105
+ this.#adapter = adapter;
106
+ }
107
+
108
+ #createUrl(path: string): string {
109
+ const url = buildUrl(this.#baseUrl, path);
110
+ return url;
111
+ }
112
+
113
+ /**
114
+ * Lists all workflows for the authenticated organization.
115
+ *
116
+ * @param params - Optional filter and pagination parameters
117
+ * @returns A promise resolving to the paginated list of workflows
118
+ * @throws {@link WorkflowResponseError} If the API returns a failure response body
119
+ * @throws {@link ServiceException} If the HTTP request fails
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * const result = await service.list({ status: 'enabled', limit: 10 });
124
+ * console.log(`Found ${result.total} workflows`);
125
+ * for (const wf of result.workflows) {
126
+ * console.log(`${wf.name} (${wf.source_type})`);
127
+ * }
128
+ * ```
129
+ */
130
+ async list(params?: ListWorkflowsRequest): Promise<WorkflowListResult> {
131
+ const url = this.#createUrl('/workflow/list');
132
+ const signal = createTimeoutSignal();
133
+ const queryParams: Record<string, string> = {};
134
+ if (params?.limit !== undefined) queryParams['limit'] = String(params.limit);
135
+ if (params?.offset !== undefined) queryParams['offset'] = String(params.offset);
136
+ if (params?.status) queryParams['status'] = params.status;
137
+ if (params?.source_type) queryParams['source_type'] = params.source_type;
138
+ if (params?.filter) queryParams['filter'] = params.filter;
139
+
140
+ const qs = new URLSearchParams(queryParams);
141
+ const finalUrl = qs.toString() ? `${url}?${qs.toString()}` : url;
142
+ const res = await this.#adapter.invoke<WorkflowResponse<WorkflowListResult>>(finalUrl, {
143
+ method: 'GET',
144
+ signal,
145
+ contentType: 'application/json',
146
+ telemetry: {
147
+ name: 'agentuity.workflow.list',
148
+ },
149
+ });
150
+
151
+ if (res.ok) {
152
+ if (res.data.success) {
153
+ return res.data.data;
154
+ }
155
+ throw new WorkflowResponseError({
156
+ status: res.response.status,
157
+ message: res.data.message || 'Failed to list workflows',
158
+ });
159
+ }
160
+
161
+ throw await toServiceException('GET', url, res.response);
162
+ }
163
+
164
+ /**
165
+ * Gets a single workflow by its ID.
166
+ *
167
+ * @param workflowId - The unique workflow identifier (prefixed with wf_)
168
+ * @returns A promise resolving to the workflow details
169
+ * @throws {@link WorkflowResponseError} If the API returns a failure response body
170
+ * @throws {@link ServiceException} If the HTTP request fails
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * const result = await service.get('wf_abc123');
175
+ * console.log(result.workflow.name);
176
+ * ```
177
+ */
178
+ async get(workflowId: string): Promise<WorkflowGetResult> {
179
+ const url = this.#createUrl(`/workflow/${encodeURIComponent(workflowId)}`);
180
+ const signal = createTimeoutSignal();
181
+
182
+ const res = await this.#adapter.invoke<WorkflowResponse<WorkflowGetResult>>(url, {
183
+ method: 'GET',
184
+ signal,
185
+ contentType: 'application/json',
186
+ telemetry: {
187
+ name: 'agentuity.workflow.get',
188
+ attributes: {
189
+ workflowId,
190
+ },
191
+ },
192
+ });
193
+
194
+ if (res.ok) {
195
+ if (res.data.success) {
196
+ return res.data.data;
197
+ }
198
+ throw new WorkflowResponseError({
199
+ status: res.response.status,
200
+ message: res.data.message || 'Failed to get workflow',
201
+ });
202
+ }
203
+
204
+ throw await toServiceException('GET', url, res.response);
205
+ }
206
+
207
+ /**
208
+ * Creates a new workflow.
209
+ *
210
+ * @param params - The workflow creation parameters including name, source type, and source reference
211
+ * @returns A promise resolving to the newly created workflow
212
+ * @throws {@link WorkflowResponseError} If the API returns a failure response body
213
+ * @throws {@link ServiceException} If the HTTP request fails
214
+ *
215
+ * @example
216
+ * ```typescript
217
+ * const result = await service.create({
218
+ * name: 'Email to Slack',
219
+ * source_type: 'email',
220
+ * source_ref_id: 'user@example.com',
221
+ * });
222
+ * console.log('Created:', result.workflow.id);
223
+ * ```
224
+ */
225
+ async create(params: CreateWorkflowRequest): Promise<WorkflowCreateResult> {
226
+ const url = this.#createUrl('/workflow/create');
227
+ const signal = createTimeoutSignal();
228
+
229
+ const res = await this.#adapter.invoke<WorkflowResponse<WorkflowCreateResult>>(url, {
230
+ method: 'POST',
231
+ signal,
232
+ body: JSON.stringify(params),
233
+ contentType: 'application/json',
234
+ telemetry: {
235
+ name: 'agentuity.workflow.create',
236
+ attributes: {
237
+ name: params.name,
238
+ source_type: params.source_type,
239
+ },
240
+ },
241
+ });
242
+
243
+ if (res.ok) {
244
+ if (res.data.success) {
245
+ return res.data.data;
246
+ }
247
+ throw new WorkflowResponseError({
248
+ status: res.response.status,
249
+ message: res.data.message || 'Failed to create workflow',
250
+ });
251
+ }
252
+
253
+ throw await toServiceException('POST', url, res.response);
254
+ }
255
+
256
+ /**
257
+ * Updates an existing workflow's name, description, or status.
258
+ *
259
+ * @param workflowId - The unique workflow identifier
260
+ * @param params - Fields to update; only provided fields are changed
261
+ * @returns A promise resolving to the updated workflow
262
+ * @throws {@link WorkflowResponseError} If the API returns a failure response body
263
+ * @throws {@link ServiceException} If the HTTP request fails
264
+ *
265
+ * @example
266
+ * ```typescript
267
+ * const result = await service.update('wf_abc123', {
268
+ * name: 'Updated Workflow Name',
269
+ * status: 'disabled',
270
+ * });
271
+ * console.log('Updated:', result.workflow.name);
272
+ * ```
273
+ */
274
+ async update(workflowId: string, params: UpdateWorkflowRequest): Promise<WorkflowUpdateResult> {
275
+ const url = this.#createUrl(`/workflow/${encodeURIComponent(workflowId)}`);
276
+ const signal = createTimeoutSignal();
277
+
278
+ const res = await this.#adapter.invoke<WorkflowResponse<WorkflowUpdateResult>>(url, {
279
+ method: 'PATCH',
280
+ signal,
281
+ body: JSON.stringify(params),
282
+ contentType: 'application/json',
283
+ telemetry: {
284
+ name: 'agentuity.workflow.update',
285
+ attributes: {
286
+ workflowId,
287
+ },
288
+ },
289
+ });
290
+
291
+ if (res.ok) {
292
+ if (res.data.success) {
293
+ return res.data.data;
294
+ }
295
+ throw new WorkflowResponseError({
296
+ status: res.response.status,
297
+ message: res.data.message || 'Failed to update workflow',
298
+ });
299
+ }
300
+
301
+ throw await toServiceException('PATCH', url, res.response);
302
+ }
303
+
304
+ /**
305
+ * Updates the workflow graph (nodes and edges) for a workflow.
306
+ *
307
+ * @param workflowId - The unique workflow identifier
308
+ * @param params - The new graph definition with nodes and edges
309
+ * @returns A promise resolving to the updated workflow
310
+ * @throws {@link WorkflowResponseError} If the API returns a failure response body
311
+ * @throws {@link ServiceException} If the HTTP request fails
312
+ *
313
+ * @example
314
+ * ```typescript
315
+ * const result = await service.updateGraph('wf_abc123', {
316
+ * nodes: [{ id: 'n1', type: 'filter', data: { expr: '...' } }],
317
+ * edges: [{ id: 'e1', source: 'n1', target: 'n2' }],
318
+ * });
319
+ * ```
320
+ */
321
+ async updateGraph(
322
+ workflowId: string,
323
+ params: UpdateWorkflowGraphRequest
324
+ ): Promise<WorkflowUpdateResult> {
325
+ const url = this.#createUrl(`/workflow/${encodeURIComponent(workflowId)}/graph`);
326
+ const signal = createTimeoutSignal();
327
+
328
+ const res = await this.#adapter.invoke<WorkflowResponse<WorkflowUpdateResult>>(url, {
329
+ method: 'PUT',
330
+ signal,
331
+ body: JSON.stringify(params),
332
+ contentType: 'application/json',
333
+ telemetry: {
334
+ name: 'agentuity.workflow.updateGraph',
335
+ attributes: {
336
+ workflowId,
337
+ },
338
+ },
339
+ });
340
+
341
+ if (res.ok) {
342
+ if (res.data.success) {
343
+ return res.data.data;
344
+ }
345
+ throw new WorkflowResponseError({
346
+ status: res.response.status,
347
+ message: res.data.message || 'Failed to update workflow graph',
348
+ });
349
+ }
350
+
351
+ throw await toServiceException('PUT', url, res.response);
352
+ }
353
+
354
+ /**
355
+ * Deletes a workflow and all associated data.
356
+ *
357
+ * @param workflowId - The unique workflow identifier
358
+ * @throws {@link WorkflowResponseError} If the API returns a failure response body
359
+ * @throws {@link ServiceException} If the HTTP request fails
360
+ *
361
+ * @example
362
+ * ```typescript
363
+ * await service.delete('wf_abc123');
364
+ * console.log('Workflow deleted');
365
+ * ```
366
+ */
367
+ async delete(workflowId: string): Promise<void> {
368
+ const url = this.#createUrl(`/workflow/${encodeURIComponent(workflowId)}`);
369
+ const signal = createTimeoutSignal();
370
+
371
+ const res = await this.#adapter.invoke<WorkflowResponse<void>>(url, {
372
+ method: 'DELETE',
373
+ signal,
374
+ contentType: 'application/json',
375
+ telemetry: {
376
+ name: 'agentuity.workflow.delete',
377
+ attributes: {
378
+ workflowId,
379
+ },
380
+ },
381
+ });
382
+
383
+ if (res.ok) {
384
+ // Handle 204 No Content or responses without a body
385
+ if (res.response.status === 204 || res.data === undefined) {
386
+ return;
387
+ }
388
+ if (res.data.success) {
389
+ return;
390
+ }
391
+ throw new WorkflowResponseError({
392
+ status: res.response.status,
393
+ message: res.data.message || 'Failed to delete workflow',
394
+ });
395
+ }
396
+
397
+ throw await toServiceException('DELETE', url, res.response);
398
+ }
399
+
400
+ /**
401
+ * Tests a workflow with a sample payload.
402
+ *
403
+ * Sends the provided payload through the workflow and returns the execution
404
+ * result including individual step outcomes.
405
+ *
406
+ * @param workflowId - The unique workflow identifier
407
+ * @param params - The test parameters including the payload to send
408
+ * @returns A promise resolving to the test execution result
409
+ * @throws {@link WorkflowResponseError} If the API returns a failure response body
410
+ * @throws {@link ServiceException} If the HTTP request fails
411
+ *
412
+ * @example
413
+ * ```typescript
414
+ * const result = await service.test('wf_abc123', {
415
+ * payload: { event: 'push', repo: 'my-repo' },
416
+ * });
417
+ * console.log('Test status:', result.status);
418
+ * ```
419
+ */
420
+ async test(workflowId: string, params: TestWorkflowRequest): Promise<TestWorkflowResult> {
421
+ const url = this.#createUrl(`/workflow/${encodeURIComponent(workflowId)}/test`);
422
+ const signal = createTimeoutSignal();
423
+
424
+ const res = await this.#adapter.invoke<WorkflowResponse<TestWorkflowResult>>(url, {
425
+ method: 'POST',
426
+ signal,
427
+ body: JSON.stringify(params),
428
+ contentType: 'application/json',
429
+ telemetry: {
430
+ name: 'agentuity.workflow.test',
431
+ attributes: {
432
+ workflowId,
433
+ },
434
+ },
435
+ });
436
+
437
+ if (res.ok) {
438
+ if (res.data.success) {
439
+ return res.data.data;
440
+ }
441
+ throw new WorkflowResponseError({
442
+ status: res.response.status,
443
+ message: res.data.message || 'Failed to test workflow',
444
+ });
445
+ }
446
+
447
+ throw await toServiceException('POST', url, res.response);
448
+ }
449
+
450
+ /**
451
+ * Gets workflow activity statistics for the authenticated organization.
452
+ *
453
+ * Returns aggregate counts of workflows, executions, and their statuses.
454
+ *
455
+ * @param days - Optional number of days to look back for activity (default: server-side default)
456
+ * @returns A promise resolving to the activity statistics
457
+ * @throws {@link WorkflowResponseError} If the API returns a failure response body
458
+ * @throws {@link ServiceException} If the HTTP request fails
459
+ *
460
+ * @example
461
+ * ```typescript
462
+ * const activity = await service.activity(7);
463
+ * console.log(`${activity.total_workflows} workflows, ${activity.total_executions} executions`);
464
+ * ```
465
+ */
466
+ async activity(days?: number): Promise<WorkflowActivity> {
467
+ const url = this.#createUrl('/workflow/activity');
468
+ const signal = createTimeoutSignal();
469
+ const queryParams: Record<string, string> = {};
470
+ if (days !== undefined) queryParams['days'] = String(days);
471
+
472
+ const qs = new URLSearchParams(queryParams);
473
+ const finalUrl = qs.toString() ? `${url}?${qs.toString()}` : url;
474
+ const res = await this.#adapter.invoke<WorkflowResponse<WorkflowActivity>>(finalUrl, {
475
+ method: 'GET',
476
+ signal,
477
+ contentType: 'application/json',
478
+ telemetry: {
479
+ name: 'agentuity.workflow.activity',
480
+ },
481
+ });
482
+
483
+ if (res.ok) {
484
+ if (res.data.success) {
485
+ return res.data.data;
486
+ }
487
+ throw new WorkflowResponseError({
488
+ status: res.response.status,
489
+ message: res.data.message || 'Failed to get workflow activity',
490
+ });
491
+ }
492
+
493
+ throw await toServiceException('GET', url, res.response);
494
+ }
495
+
496
+ /**
497
+ * Lists execution records for a specific workflow.
498
+ *
499
+ * @param workflowId - The unique workflow identifier
500
+ * @returns A promise resolving to the list of executions
501
+ * @throws {@link WorkflowResponseError} If the API returns a failure response body
502
+ * @throws {@link ServiceException} If the HTTP request fails
503
+ *
504
+ * @example
505
+ * ```typescript
506
+ * const executions = await service.listExecutions('wf_abc123');
507
+ * for (const exec of executions) {
508
+ * console.log(`${exec.id}: ${exec.status}`);
509
+ * }
510
+ * ```
511
+ */
512
+ async listExecutions(workflowId: string): Promise<WorkflowExecution[]> {
513
+ const url = this.#createUrl(`/workflow/${encodeURIComponent(workflowId)}/executions`);
514
+ const signal = createTimeoutSignal();
515
+
516
+ const res = await this.#adapter.invoke<WorkflowResponse<WorkflowExecution[]>>(url, {
517
+ method: 'GET',
518
+ signal,
519
+ contentType: 'application/json',
520
+ telemetry: {
521
+ name: 'agentuity.workflow.listExecutions',
522
+ attributes: {
523
+ workflowId,
524
+ },
525
+ },
526
+ });
527
+
528
+ if (res.ok) {
529
+ if (res.data.success) {
530
+ return res.data.data;
531
+ }
532
+ throw new WorkflowResponseError({
533
+ status: res.response.status,
534
+ message: res.data.message || 'Failed to list workflow executions',
535
+ });
536
+ }
537
+
538
+ throw await toServiceException('GET', url, res.response);
539
+ }
540
+
541
+ /**
542
+ * Lists delivery records for a specific workflow execution.
543
+ *
544
+ * @param executionId - The unique execution identifier
545
+ * @returns A promise resolving to the list of deliveries
546
+ * @throws {@link WorkflowResponseError} If the API returns a failure response body
547
+ * @throws {@link ServiceException} If the HTTP request fails
548
+ *
549
+ * @example
550
+ * ```typescript
551
+ * const deliveries = await service.listDeliveries('exec_abc123');
552
+ * for (const d of deliveries) {
553
+ * console.log(`${d.destination_type}: ${d.status}`);
554
+ * }
555
+ * ```
556
+ */
557
+ async listDeliveries(executionId: string): Promise<WorkflowDelivery[]> {
558
+ const url = this.#createUrl(
559
+ `/workflow/executions/${encodeURIComponent(executionId)}/deliveries`
560
+ );
561
+ const signal = createTimeoutSignal();
562
+
563
+ const res = await this.#adapter.invoke<WorkflowResponse<WorkflowDelivery[]>>(url, {
564
+ method: 'GET',
565
+ signal,
566
+ contentType: 'application/json',
567
+ telemetry: {
568
+ name: 'agentuity.workflow.listDeliveries',
569
+ attributes: {
570
+ executionId,
571
+ },
572
+ },
573
+ });
574
+
575
+ if (res.ok) {
576
+ if (res.data.success) {
577
+ return res.data.data;
578
+ }
579
+ throw new WorkflowResponseError({
580
+ status: res.response.status,
581
+ message: res.data.message || 'Failed to list workflow deliveries',
582
+ });
583
+ }
584
+
585
+ throw await toServiceException('GET', url, res.response);
586
+ }
587
+
588
+ /**
589
+ * Gets the most recent payload received by a workflow.
590
+ *
591
+ * Useful for inspecting the last event that triggered the workflow, e.g.
592
+ * when building or debugging workflow graphs.
593
+ *
594
+ * @param workflowId - The unique workflow identifier
595
+ * @returns A promise resolving to the recent payload data
596
+ * @throws {@link WorkflowResponseError} If the API returns a failure response body
597
+ * @throws {@link ServiceException} If the HTTP request fails
598
+ *
599
+ * @example
600
+ * ```typescript
601
+ * const payload = await service.getRecentPayload('wf_abc123');
602
+ * console.log('Last payload:', JSON.stringify(payload, null, 2));
603
+ * ```
604
+ */
605
+ async getRecentPayload(workflowId: string): Promise<unknown> {
606
+ const url = this.#createUrl(`/workflow/${encodeURIComponent(workflowId)}/recent-payload`);
607
+ const signal = createTimeoutSignal();
608
+
609
+ const res = await this.#adapter.invoke<WorkflowResponse<unknown>>(url, {
610
+ method: 'GET',
611
+ signal,
612
+ contentType: 'application/json',
613
+ telemetry: {
614
+ name: 'agentuity.workflow.getRecentPayload',
615
+ attributes: {
616
+ workflowId,
617
+ },
618
+ },
619
+ });
620
+
621
+ if (res.ok) {
622
+ if (res.data.success) {
623
+ return res.data.data;
624
+ }
625
+ throw new WorkflowResponseError({
626
+ status: res.response.status,
627
+ message: res.data.message || 'Failed to get recent payload',
628
+ });
629
+ }
630
+
631
+ throw await toServiceException('GET', url, res.response);
632
+ }
633
+ }