@vertesia/client 1.5.0-dev.20260807.073259Z → 1.5.0-dev.20260901.005903Z

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 (124) hide show
  1. package/lib/AppsApi.d.ts +9 -8
  2. package/lib/AppsApi.d.ts.map +1 -1
  3. package/lib/AppsApi.js +11 -4
  4. package/lib/AppsApi.js.map +1 -1
  5. package/lib/GroupsApi.d.ts +4 -11
  6. package/lib/GroupsApi.d.ts.map +1 -1
  7. package/lib/GroupsApi.js.map +1 -1
  8. package/lib/InteractionBase.d.ts +114 -0
  9. package/lib/InteractionBase.d.ts.map +1 -1
  10. package/lib/InteractionCatalogApi.d.ts +3 -3
  11. package/lib/InteractionCatalogApi.d.ts.map +1 -1
  12. package/lib/InteractionCatalogApi.js +1 -1
  13. package/lib/InteractionOutput.d.ts +13 -3
  14. package/lib/InteractionOutput.d.ts.map +1 -1
  15. package/lib/InteractionOutput.js +33 -3
  16. package/lib/InteractionOutput.js.map +1 -1
  17. package/lib/OAuthServerApi.d.ts +1 -1
  18. package/lib/OAuthServerApi.d.ts.map +1 -1
  19. package/lib/OAuthServerApi.js +9 -2
  20. package/lib/OAuthServerApi.js.map +1 -1
  21. package/lib/ProjectsApi.d.ts +3 -3
  22. package/lib/ProjectsApi.d.ts.map +1 -1
  23. package/lib/ProjectsApi.js.map +1 -1
  24. package/lib/RunsApi.d.ts +6 -28
  25. package/lib/RunsApi.d.ts.map +1 -1
  26. package/lib/RunsApi.js +3 -3
  27. package/lib/RunsApi.js.map +1 -1
  28. package/lib/ToolsApi.d.ts +2 -1
  29. package/lib/ToolsApi.d.ts.map +1 -1
  30. package/lib/ToolsApi.js +9 -0
  31. package/lib/ToolsApi.js.map +1 -1
  32. package/lib/ViewsApi.d.ts +1 -1
  33. package/lib/ViewsApi.js +1 -1
  34. package/lib/client.d.ts +1 -0
  35. package/lib/client.d.ts.map +1 -1
  36. package/lib/client.js +3 -0
  37. package/lib/client.js.map +1 -1
  38. package/lib/execute.js +2 -2
  39. package/lib/execute.js.map +1 -1
  40. package/lib/store/AgentsApi.d.ts +4 -1
  41. package/lib/store/AgentsApi.d.ts.map +1 -1
  42. package/lib/store/AgentsApi.js +6 -4
  43. package/lib/store/AgentsApi.js.map +1 -1
  44. package/lib/store/CollectionsApi.d.ts +5 -2
  45. package/lib/store/CollectionsApi.d.ts.map +1 -1
  46. package/lib/store/CollectionsApi.js.map +1 -1
  47. package/lib/store/EmailApi.d.ts +9 -107
  48. package/lib/store/EmailApi.d.ts.map +1 -1
  49. package/lib/store/EmailApi.js.map +1 -1
  50. package/lib/store/FilesApi.d.ts +3 -1
  51. package/lib/store/FilesApi.d.ts.map +1 -1
  52. package/lib/store/FilesApi.js +7 -0
  53. package/lib/store/FilesApi.js.map +1 -1
  54. package/lib/store/ObjectsApi.d.ts +29 -4
  55. package/lib/store/ObjectsApi.d.ts.map +1 -1
  56. package/lib/store/ObjectsApi.js +0 -2
  57. package/lib/store/ObjectsApi.js.map +1 -1
  58. package/lib/store/PendingAsksApi.d.ts +2 -53
  59. package/lib/store/PendingAsksApi.d.ts.map +1 -1
  60. package/lib/store/PendingAsksApi.js.map +1 -1
  61. package/lib/store/ProcessApi.d.ts +15 -8
  62. package/lib/store/ProcessApi.d.ts.map +1 -1
  63. package/lib/store/ProcessApi.js +27 -1
  64. package/lib/store/ProcessApi.js.map +1 -1
  65. package/lib/store/ProcessTestRunApi.d.ts +26 -0
  66. package/lib/store/ProcessTestRunApi.d.ts.map +1 -0
  67. package/lib/store/ProcessTestRunApi.js +36 -0
  68. package/lib/store/ProcessTestRunApi.js.map +1 -0
  69. package/lib/store/QueryApi.d.ts +9 -51
  70. package/lib/store/QueryApi.d.ts.map +1 -1
  71. package/lib/store/QueryApi.js.map +1 -1
  72. package/lib/store/WorkflowsApi.d.ts +3 -3
  73. package/lib/store/WorkflowsApi.d.ts.map +1 -1
  74. package/lib/store/WorkflowsApi.js.map +1 -1
  75. package/lib/store/client.d.ts +2 -2
  76. package/lib/store/client.d.ts.map +1 -1
  77. package/lib/store/client.js +2 -2
  78. package/lib/store/client.js.map +1 -1
  79. package/lib/store/index.d.ts +1 -1
  80. package/lib/store/index.d.ts.map +1 -1
  81. package/lib/store/index.js +1 -1
  82. package/lib/store/index.js.map +1 -1
  83. package/lib/store/stream-termination.d.ts +2 -2
  84. package/lib/store/stream-termination.d.ts.map +1 -1
  85. package/lib/store/stream-termination.js +6 -4
  86. package/lib/store/stream-termination.js.map +1 -1
  87. package/lib/vertesia-client.js +8 -9
  88. package/lib/vertesia-client.js.map +1 -1
  89. package/package.json +7 -7
  90. package/src/AppsApi.ts +22 -8
  91. package/src/GroupsApi.ts +4 -10
  92. package/src/InteractionCatalogApi.ts +3 -3
  93. package/src/InteractionOutput.test.ts +41 -5
  94. package/src/InteractionOutput.ts +39 -3
  95. package/src/OAuthServerApi.test.ts +56 -0
  96. package/src/OAuthServerApi.ts +12 -2
  97. package/src/ProjectsApi.ts +4 -2
  98. package/src/RunsApi.ts +15 -14
  99. package/src/ToolsApi.ts +10 -0
  100. package/src/ViewsApi.test.ts +3 -1
  101. package/src/ViewsApi.ts +1 -1
  102. package/src/client.ts +4 -0
  103. package/src/execute.ts +2 -2
  104. package/src/store/AgentsApi.stream.test.ts +56 -0
  105. package/src/store/AgentsApi.ts +8 -4
  106. package/src/store/CollectionsApi.ts +8 -1
  107. package/src/store/EmailApi.ts +25 -107
  108. package/src/store/FilesApi.ts +12 -0
  109. package/src/store/ObjectsApi.ts +28 -4
  110. package/src/store/PendingAsksApi.ts +15 -57
  111. package/src/store/ProcessApi.test.ts +24 -0
  112. package/src/store/ProcessApi.ts +49 -8
  113. package/src/store/ProcessTestRunApi.ts +41 -0
  114. package/src/store/QueryApi.ts +9 -45
  115. package/src/store/WorkflowsApi.ts +4 -3
  116. package/src/store/client.ts +2 -2
  117. package/src/store/index.ts +1 -1
  118. package/src/store/stream-termination.test.ts +24 -0
  119. package/src/store/stream-termination.ts +10 -4
  120. package/lib/store/HiveMemoryApi.d.ts +0 -161
  121. package/lib/store/HiveMemoryApi.d.ts.map +0 -1
  122. package/lib/store/HiveMemoryApi.js +0 -170
  123. package/lib/store/HiveMemoryApi.js.map +0 -1
  124. package/src/store/HiveMemoryApi.ts +0 -220
@@ -151,6 +151,62 @@ describe('AgentsApi.streamMessages reconnection', () => {
151
151
  vi.useRealTimers();
152
152
  });
153
153
 
154
+ it('keeps interactive streams open on root IDLE by default', async () => {
155
+ const harness = createHarness();
156
+ const settled = vi.fn();
157
+ const received: AgentMessage[] = [];
158
+ const done = harness.client.agents
159
+ .streamMessages(AGENT_RUN_ID, (message) => received.push(message))
160
+ .then(settled);
161
+ await settle();
162
+
163
+ FakeEventSource.instances[0].emit({
164
+ t: AgentMessageType.IDLE,
165
+ m: 'Waiting for your command...',
166
+ w: 'main',
167
+ ts: 1_000,
168
+ });
169
+ await settle();
170
+ expect(settled).not.toHaveBeenCalled();
171
+
172
+ FakeEventSource.instances[0].emit({
173
+ t: AgentMessageType.ANSWER,
174
+ m: 'Follow-up response',
175
+ w: 'main',
176
+ ts: 1_500,
177
+ });
178
+ await settle();
179
+ expect(received.map((message) => message.message)).toEqual([
180
+ 'Waiting for your command...',
181
+ 'Follow-up response',
182
+ ]);
183
+
184
+ FakeEventSource.instances[0].emit({
185
+ t: AgentMessageType.COMPLETE,
186
+ m: 'Conversation complete',
187
+ w: 'main',
188
+ ts: 2_000,
189
+ });
190
+ await expect(done).resolves.toBeUndefined();
191
+ });
192
+
193
+ it('lets headless followers opt into closing on root IDLE', async () => {
194
+ const harness = createHarness();
195
+ const done = harness.client.agents.streamMessages(AGENT_RUN_ID, undefined, undefined, undefined, {
196
+ closeOnIdle: true,
197
+ });
198
+ await settle();
199
+
200
+ FakeEventSource.instances[0].emit({
201
+ t: AgentMessageType.IDLE,
202
+ m: 'Waiting for your command...',
203
+ w: 'main',
204
+ ts: 1_000,
205
+ });
206
+
207
+ await expect(done).resolves.toBeNull();
208
+ });
209
+
154
210
  it('resolves a fresh auth token for every reconnection attempt', async () => {
155
211
  const harness = createHarness();
156
212
  const abort = new AbortController();
@@ -58,6 +58,8 @@ import { fetchSignedUrl } from './signed-url.js';
58
58
  import { shouldCloseAgentRunStream, shouldCloseCompactRunStream } from './stream-termination.js';
59
59
 
60
60
  export interface AgentRunStreamMessagesOptions {
61
+ /** Resolve the stream when the root conversation becomes idle. Headless followers should opt in. */
62
+ closeOnIdle?: boolean;
61
63
  onHistoryLoaded?: (messages: AgentMessage[]) => void;
62
64
  onHistoryError?: (error: unknown) => void;
63
65
  }
@@ -253,7 +255,8 @@ export class AgentsApi extends ApiTopic {
253
255
 
254
256
  /**
255
257
  * Send a signal to a running agent.
256
- * Signals: "UserInput", "Stop", "FileUploaded", "FileRemoved"
258
+ * Signals include "UserInput", "Stop", "ModelConfigChanged", "FileUploaded", "FileRemoved", and
259
+ * "FileBatchClosed".
257
260
  */
258
261
  sendSignal(id: string, signalName: string, payload?: SignalAgentPayload): Promise<SignalAgentResponse> {
259
262
  return this.post(`/${id}/signal/${signalName}`, { payload });
@@ -421,7 +424,7 @@ export class AgentsApi extends ApiTopic {
421
424
  lastMessageTimestamp = timestamp;
422
425
  if (onMessage) onMessage(msg, exit);
423
426
  if (isClosed) return;
424
- if (shouldCloseAgentRunStream(msg, id)) {
427
+ if (shouldCloseAgentRunStream(msg, id, options?.closeOnIdle)) {
425
428
  exit(null);
426
429
  return;
427
430
  }
@@ -512,7 +515,8 @@ export class AgentsApi extends ApiTopic {
512
515
  if (onMessage) onMessage(msg, exit);
513
516
  if (isClosed) break;
514
517
 
515
- shouldCloseAfterHistory = index === historical.length - 1 && shouldCloseAgentRunStream(msg, id);
518
+ shouldCloseAfterHistory =
519
+ index === historical.length - 1 && shouldCloseAgentRunStream(msg, id, options?.closeOnIdle);
516
520
  }
517
521
  if (shouldCloseAfterHistory) {
518
522
  exit(null);
@@ -598,7 +602,7 @@ export class AgentsApi extends ApiTopic {
598
602
  onMessage(agentMessage, exit);
599
603
  }
600
604
 
601
- if (shouldCloseCompactRunStream(compactMessage, id)) {
605
+ if (shouldCloseCompactRunStream(compactMessage, id, options?.closeOnIdle)) {
602
606
  exit(null);
603
607
  }
604
608
  } catch (err) {
@@ -10,7 +10,9 @@ import type {
10
10
  ContentObjectStatus,
11
11
  CreateCollectionPayload,
12
12
  DynamicCollection,
13
+ FullObjectSearchResponse,
13
14
  ObjectSearchResponse,
15
+ UpdateCollectionPayload,
14
16
  } from '@vertesia/common';
15
17
 
16
18
  export class CollectionsApi extends ApiTopic {
@@ -53,7 +55,7 @@ export class CollectionsApi extends ApiTopic {
53
55
  });
54
56
  }
55
57
 
56
- update(collectionId: string, payload: Partial<CreateCollectionPayload>): Promise<{ id: string }> {
58
+ update(collectionId: string, payload: UpdateCollectionPayload): Promise<{ id: string }> {
57
59
  return this.put(`/${collectionId}`, {
58
60
  payload,
59
61
  });
@@ -90,6 +92,11 @@ export class CollectionsApi extends ApiTopic {
90
92
  });
91
93
  }
92
94
 
95
+ searchMembers(
96
+ collectionId: string,
97
+ payload: ComplexSearchPayload & { select?: undefined },
98
+ ): Promise<FullObjectSearchResponse>;
99
+ searchMembers(collectionId: string, payload: ComplexSearchPayload): Promise<ObjectSearchResponse>;
93
100
  searchMembers(collectionId: string, payload: ComplexSearchPayload): Promise<ObjectSearchResponse> {
94
101
  return this.post(`/${collectionId}/search`, { payload });
95
102
  }
@@ -1,109 +1,27 @@
1
1
  import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
2
- import type { EmailRouteData } from '@vertesia/common';
2
+ import type {
3
+ CreateEmailRouteRequest,
4
+ CreateEmailRouteResponse,
5
+ EmailRouteData,
6
+ EmailRouteResponse,
7
+ ForwardEmailRequest,
8
+ ForwardEmailResponse,
9
+ SendEmailRequest,
10
+ SendEmailResponse,
11
+ UpdateEmailRouteRequest,
12
+ UpdateEmailRouteResponse,
13
+ } from '@vertesia/common';
3
14
 
4
- /**
5
- * Request payload for sending an email via the agent.
6
- * Resend configuration is fetched from project settings.
7
- * From address is constructed as: {project_namespace}+{agent_name}@{email_domain}
8
- */
9
- export interface SendEmailRequest {
10
- /** Email address to send to */
11
- to_email: string;
12
- /** Email subject */
13
- subject: string;
14
- /** Email body in markdown format */
15
- body: string;
16
- /** Agent/interaction endpoint name (used in from address) */
17
- agent_name: string;
18
- /** Display name for the sender (overrides project default) */
19
- from_name?: string;
20
- /** Workflow run ID for routing replies */
21
- run_id: string;
22
- /** Existing route key (for subsequent emails in same conversation) */
23
- route_key?: string;
24
- /** Message ID for In-Reply-To header (email threading) */
25
- in_reply_to?: string;
26
- /** Chain of message IDs for References header */
27
- references?: string[];
28
- }
29
-
30
- /**
31
- * Response from sending an email.
32
- */
33
- export interface SendEmailResponse {
34
- success: boolean;
35
- /** Resend email ID */
36
- email_id?: string;
37
- /** Message-ID header for threading */
38
- message_id?: string;
39
- /** Short route key for reply routing */
40
- route_key?: string;
41
- /** Error message if failed */
42
- error?: string;
43
- }
44
-
45
- /**
46
- * Response from creating an email route.
47
- */
48
- export interface CreateRouteResponse {
49
- /** The generated route key (8-char alphanumeric) */
50
- route_key: string;
51
- /** Full reply-to address: r+{route_key}@{email_domain} */
52
- reply_to: string;
53
- /** The email domain for sending and receiving */
54
- email_domain: string;
55
- }
56
-
57
- /**
58
- * Request to forward an email to a workflow.
59
- * Used by external services that handle email reception themselves.
60
- */
61
- export interface ForwardEmailRequest {
62
- /** Email content received by the external service */
63
- email: {
64
- /** Sender email address */
65
- from: string;
66
- /** Email subject */
67
- subject?: string;
68
- /** Plain text body */
69
- text: string;
70
- /** HTML body (optional) */
71
- html?: string;
72
- /** Message-ID header for threading */
73
- message_id?: string;
74
- };
75
- /** Custom context data from the external service (e.g., auth tokens, user IDs) */
76
- context?: Record<string, unknown>;
77
- /** Attachments with download URLs */
78
- attachments?: Array<{
79
- filename: string;
80
- content_type: string;
81
- size: number;
82
- download_url: string;
83
- }>;
84
- }
85
-
86
- /**
87
- * Response from forwarding an email.
88
- */
89
- export interface ForwardEmailResponse {
90
- success: boolean;
91
- run_id: string;
92
- workflow_id: string;
93
- route_key: string;
94
- }
95
-
96
- /**
97
- * Request to create an email route.
98
- */
99
- export interface CreateRouteRequest {
100
- /** Workflow run ID for routing replies */
101
- run_id: string;
102
- /** Email address of the user (for context) */
103
- user_email: string;
104
- /** Subject of the email thread (optional) */
105
- thread_subject?: string;
106
- }
15
+ export type {
16
+ ForwardEmailRequest,
17
+ ForwardEmailResponse,
18
+ SendEmailRequest,
19
+ SendEmailResponse,
20
+ } from '@vertesia/common';
21
+ /** @deprecated Use CreateEmailRouteRequest from @vertesia/common. */
22
+ export type CreateRouteRequest = CreateEmailRouteRequest;
23
+ /** @deprecated Use CreateEmailRouteResponse from @vertesia/common. */
24
+ export type CreateRouteResponse = CreateEmailRouteResponse;
107
25
 
108
26
  /**
109
27
  * Email API for sending emails from workflows.
@@ -150,21 +68,21 @@ export class EmailApi extends ApiTopic {
150
68
  * // Replies will be routed back to the workflow
151
69
  * ```
152
70
  */
153
- createRoute(request: CreateRouteRequest): Promise<CreateRouteResponse> {
71
+ createRoute(request: CreateEmailRouteRequest): Promise<CreateEmailRouteResponse> {
154
72
  return this.post('/routes', { payload: request });
155
73
  }
156
74
 
157
75
  /**
158
76
  * Get an email route by key.
159
77
  */
160
- getRoute(routeKey: string): Promise<EmailRouteData & { route_key: string }> {
78
+ getRoute(routeKey: string): Promise<EmailRouteResponse> {
161
79
  return this.get(`/routes/${routeKey}`);
162
80
  }
163
81
 
164
82
  /**
165
83
  * Update an email route (e.g., to update threading info).
166
84
  */
167
- updateRoute(routeKey: string, updates: Partial<EmailRouteData>): Promise<{ success: boolean; route_key: string }> {
85
+ updateRoute(routeKey: string, updates: UpdateEmailRouteRequest): Promise<UpdateEmailRouteResponse> {
168
86
  return this.put(`/routes/${routeKey}`, { payload: updates });
169
87
  }
170
88
 
@@ -1,9 +1,12 @@
1
1
  import { ApiTopic, type ClientBase, type IRequestRetryPolicy } from '@vertesia/api-fetch-client';
2
2
  import type {
3
+ BucketCreateAccessStatusResponse,
3
4
  BucketReadAccessStatusResponse,
4
5
  BulkUploadUrlsPayload,
5
6
  BulkUploadUrlsResponse,
6
7
  DeleteFileResult,
8
+ EnsureBucketCreateAccessPayload,
9
+ EnsureBucketCreateAccessResponse,
7
10
  EnsureBucketReadAccessPayload,
8
11
  EnsureBucketReadAccessResponse,
9
12
  FileBucketResponse,
@@ -133,6 +136,15 @@ export class FilesApi extends ApiTopic {
133
136
  return this.get('/bucket/read-access', { query: { principal } });
134
137
  }
135
138
 
139
+ ensureBucketCreateAccess(principal: string): Promise<EnsureBucketCreateAccessResponse> {
140
+ const payload: EnsureBucketCreateAccessPayload = { principal };
141
+ return this.post('/bucket/create-access', { payload });
142
+ }
143
+
144
+ getBucketCreateAccessStatus(principal: string): Promise<BucketCreateAccessStatusResponse> {
145
+ return this.get('/bucket/create-access', { query: { principal } });
146
+ }
147
+
136
148
  list(prefix: string): Promise<FileListResponse> {
137
149
  return this.get('/list', { query: { prefix } });
138
150
  }
@@ -26,6 +26,7 @@ import {
26
26
  type ExportPropertiesPayload,
27
27
  type ExportPropertiesResponse,
28
28
  type FindPayload,
29
+ type FullObjectSearchResponse,
29
30
  type GetFileUrlPayload,
30
31
  type GetFileUrlResponse,
31
32
  type GetRenditionParams,
@@ -36,10 +37,12 @@ import {
36
37
  type ObjectSearchPayload,
37
38
  type ObjectSearchQuery,
38
39
  type ObjectSearchResponse,
40
+ type ProjectedContentObjectApiResponse,
39
41
  type SetObjectEmbeddingsResponse,
40
42
  type StartContentObjectExportRequest,
41
43
  type StartContentObjectExportResponse,
42
44
  type SupportedEmbeddingTypes,
45
+ type UpdateContentObjectPayload,
43
46
  type ZenoBulkContentObjectExportComposeRequest,
44
47
  type ZenoBulkContentObjectExportPlanRequest,
45
48
  type ZenoBulkContentObjectExportPlanResponse,
@@ -60,10 +63,22 @@ import type { ZenoClient } from './client.js';
60
63
  import { fetchSignedUrl } from './signed-url.js';
61
64
  import { getUploadMimeTypeHint, resolveUploadMimeType } from './uploadMimeType.js';
62
65
 
66
+ /**
67
+ * The two write payloads, each widened at `content` so callers can hand us a browser `File` or a
68
+ * `StreamSource` and let the method upload it before sending the wire shape.
69
+ *
70
+ * They are separate on purpose: `POST /objects` and `PUT /objects/:id` publish distinct components,
71
+ * so deriving the update signature from the create payload would silently drift the day the two
72
+ * schemas diverge.
73
+ */
63
74
  type ContentObjectWritePayload = Omit<CreateContentObjectPayload, 'content'> & {
64
75
  content?: ContentSource | File | StreamSource;
65
76
  };
66
77
 
78
+ type ContentObjectUpdateWritePayload = Omit<UpdateContentObjectPayload, 'content'> & {
79
+ content?: ContentSource | File | StreamSource;
80
+ };
81
+
67
82
  export class ObjectsApi extends ApiTopic {
68
83
  declare client: ZenoClient;
69
84
 
@@ -224,7 +239,11 @@ export class ObjectsApi extends ApiTopic {
224
239
  }
225
240
 
226
241
  /** Find object based on query */
227
- find(payload: FindPayload): Promise<ContentObject[]> {
242
+ find(payload: FindPayload & { select?: undefined }): Promise<ContentObject[]>;
243
+ find(payload: FindPayload & { select: `+${string}` }): Promise<ContentObject[]>;
244
+ find(payload: FindPayload & { select: string }): Promise<ProjectedContentObjectApiResponse[]>;
245
+ find(payload: FindPayload): Promise<ContentObject[] | ProjectedContentObjectApiResponse[]>;
246
+ find(payload: FindPayload): Promise<ContentObject[] | ProjectedContentObjectApiResponse[]> {
228
247
  return this.post('/find', {
229
248
  payload,
230
249
  });
@@ -238,13 +257,18 @@ export class ObjectsApi extends ApiTopic {
238
257
  }
239
258
 
240
259
  /** Search object — different from find because allow full text search */
260
+ search(payload: ComplexSearchPayload & { select?: undefined }): Promise<FullObjectSearchResponse>;
261
+ search(payload: ComplexSearchPayload): Promise<ObjectSearchResponse>;
241
262
  search(payload: ComplexSearchPayload): Promise<ObjectSearchResponse> {
242
263
  return this.post('/search', {
243
264
  payload,
244
265
  });
245
266
  }
246
267
 
247
- retrieve(id: string, select?: string): Promise<ContentObject> {
268
+ retrieve(id: string): Promise<ContentObject>;
269
+ retrieve(id: string, select: `+${string}` | undefined): Promise<ContentObject>;
270
+ retrieve(id: string, select: string): Promise<ProjectedContentObjectApiResponse>;
271
+ retrieve(id: string, select?: string): Promise<ContentObject | ProjectedContentObjectApiResponse> {
248
272
  return this.get(`/${id}`, {
249
273
  query: {
250
274
  select,
@@ -381,7 +405,7 @@ export class ObjectsApi extends ApiTopic {
381
405
  */
382
406
  async update(
383
407
  id: string,
384
- payload: Partial<ContentObjectWritePayload>,
408
+ payload: ContentObjectUpdateWritePayload,
385
409
  options?: {
386
410
  createRevision?: boolean;
387
411
  revisionLabel?: string;
@@ -393,7 +417,7 @@ export class ObjectsApi extends ApiTopic {
393
417
  },
394
418
  ): Promise<ContentObject> {
395
419
  const { content, ...payloadWithoutContent } = payload;
396
- const updatePayload: Partial<CreateContentObjectPayload> = {
420
+ const updatePayload: UpdateContentObjectPayload = {
397
421
  ...payloadWithoutContent,
398
422
  };
399
423
 
@@ -1,61 +1,19 @@
1
1
  import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
2
- import type { ListPendingAsksResponse, PendingAskData, TaskField, UserChannel } from '@vertesia/common';
3
-
4
- /**
5
- * Request to register a pending ask.
6
- */
7
- export interface RegisterPendingAskRequest {
8
- /** Temporal workflow run ID */
9
- runId: string;
10
- /** Temporal workflow ID */
11
- workflowId: string;
12
- /** Name of the agent/interaction */
13
- agentName: string;
14
- /** Questions asked by the agent */
15
- questions: string[];
16
- /** Timeout in hours (default 48) */
17
- timeoutHours?: number;
18
- /** User communication channels */
19
- userChannels: UserChannel[];
20
- /** Durable task fields shown in task inbox */
21
- taskFields?: TaskField[];
22
- }
23
-
24
- /**
25
- * Response from registering a pending ask.
26
- */
27
- export interface RegisterPendingAskResponse {
28
- /** Whether registration succeeded */
29
- success: boolean;
30
- /** Generated ask ID */
31
- askId?: string;
32
- /** Whether webhook was sent */
33
- webhookSent?: boolean;
34
- /** Error message if failed */
35
- error?: string;
36
- }
37
-
38
- /**
39
- * Request to resolve a pending ask.
40
- */
41
- export interface ResolvePendingAskRequest {
42
- /** User's response */
43
- response: string;
44
- }
45
-
46
- /**
47
- * Response from resolving a pending ask.
48
- */
49
- export interface ResolvePendingAskResponse {
50
- /** Whether resolution succeeded */
51
- success: boolean;
52
- /** Whether webhook was sent */
53
- webhookSent?: boolean;
54
- /** How long the user took to respond (ms) */
55
- waitDurationMs?: number;
56
- /** Error message if failed */
57
- error?: string;
58
- }
2
+ import type {
3
+ ListPendingAsksResponse,
4
+ PendingAskData,
5
+ RegisterPendingAskRequest,
6
+ RegisterPendingAskResponse,
7
+ ResolvePendingAskRequest,
8
+ ResolvePendingAskResponse,
9
+ } from '@vertesia/common';
10
+
11
+ export type {
12
+ RegisterPendingAskRequest,
13
+ RegisterPendingAskResponse,
14
+ ResolvePendingAskRequest,
15
+ ResolvePendingAskResponse,
16
+ } from '@vertesia/common';
59
17
 
60
18
  /**
61
19
  * Pending Asks API for tracking ask_user requests.
@@ -0,0 +1,24 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { ZenoClient } from './client.js';
3
+
4
+ function createClient(requests: Request[]) {
5
+ return new ZenoClient({
6
+ serverUrl: 'https://zeno.example.com',
7
+ fetch: vi.fn(async () => Response.json([])),
8
+ onRequest: (request) => requests.push(request),
9
+ });
10
+ }
11
+
12
+ describe('ProcessApi.list', () => {
13
+ it.each([
14
+ ['canonical', { all_versions: true }],
15
+ ['deprecated', { allVersions: true }],
16
+ ])('maps the %s all-versions option to the wire query', async (_name, query) => {
17
+ const requests: Request[] = [];
18
+ const client = createClient(requests);
19
+
20
+ await client.processes.list(query);
21
+
22
+ expect(requests[0]?.url).toBe('https://zeno.example.com/api/v1/processes?all_versions=true');
23
+ });
24
+ });
@@ -1,20 +1,23 @@
1
1
  import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
2
2
  import type {
3
3
  CreateProcessDefinitionPayload,
4
+ CreateProcessTestSuitePayload,
5
+ ListProcessDefinitionsQuery as ListProcessDefinitionsWireQuery,
6
+ ListProcessTestRunsQuery,
4
7
  ProcessDefinition,
8
+ ProcessTestRun,
9
+ ProcessTestSuite,
5
10
  PublishProcessDefinitionPayload,
6
11
  RevertProcessDefinitionPayload,
12
+ StartProcessTestRunPayload,
7
13
  UpdateProcessDefinitionPayload,
14
+ UpdateProcessTestSuitePayload,
8
15
  } from '@vertesia/common';
9
16
 
10
- export interface ListProcessDefinitionsQuery {
11
- status?: string;
12
- process?: string;
13
- limit?: number;
14
- offset?: number;
15
- /** Include every revision/version instead of only the latest head revision. */
17
+ export type ListProcessDefinitionsQuery = ListProcessDefinitionsWireQuery & {
18
+ /** @deprecated Use the wire-compatible `all_versions` property. */
16
19
  allVersions?: boolean;
17
- }
20
+ };
18
21
 
19
22
  export class ProcessApi extends ApiTopic {
20
23
  constructor(parent: ClientBase) {
@@ -27,7 +30,7 @@ export class ProcessApi extends ApiTopic {
27
30
  if (query?.process) params.process = query.process;
28
31
  if (query?.limit != null) params.limit = String(query.limit);
29
32
  if (query?.offset != null) params.offset = String(query.offset);
30
- if (query?.allVersions) params.all_versions = 'true';
33
+ if (query?.all_versions || query?.allVersions) params.all_versions = 'true';
31
34
  return this.get('/', { query: params });
32
35
  }
33
36
 
@@ -58,4 +61,42 @@ export class ProcessApi extends ApiTopic {
58
61
  delete(id: string): Promise<{ id: string; count: number }> {
59
62
  return this.del(`/${id}`);
60
63
  }
64
+
65
+ listTestSuites(processId: string): Promise<ProcessTestSuite[]> {
66
+ return this.get(`/${processId}/test-suites`);
67
+ }
68
+
69
+ createTestSuite(processId: string, payload: CreateProcessTestSuitePayload): Promise<ProcessTestSuite> {
70
+ return this.post(`/${processId}/test-suites`, { payload });
71
+ }
72
+
73
+ updateTestSuite(
74
+ processId: string,
75
+ suiteId: string,
76
+ payload: UpdateProcessTestSuitePayload,
77
+ ): Promise<ProcessTestSuite> {
78
+ return this.put(`/${processId}/test-suites/${suiteId}`, { payload });
79
+ }
80
+
81
+ deleteTestSuite(processId: string, suiteId: string): Promise<{ id: string; count: number }> {
82
+ return this.del(`/${processId}/test-suites/${suiteId}`);
83
+ }
84
+
85
+ startTestRun(processId: string, payload: StartProcessTestRunPayload): Promise<ProcessTestRun> {
86
+ return this.post(`/${processId}/test-runs`, { payload });
87
+ }
88
+
89
+ listTestRuns(processId: string, query?: ListProcessTestRunsQuery): Promise<ProcessTestRun[]> {
90
+ return this.get(`/${processId}/test-runs`, {
91
+ query: query?.limit == null ? undefined : { limit: String(query.limit) },
92
+ });
93
+ }
94
+
95
+ retrieveTestRun(processId: string, runId: string): Promise<ProcessTestRun> {
96
+ return this.get(`/${processId}/test-runs/${runId}`);
97
+ }
98
+
99
+ cancelTestRun(processId: string, runId: string): Promise<ProcessTestRun> {
100
+ return this.post(`/${processId}/test-runs/${runId}/cancel`, {});
101
+ }
61
102
  }
@@ -0,0 +1,41 @@
1
+ import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
2
+ import type { ProcessTestRun, SubmitProcessTestRunPayload } from '@vertesia/common';
3
+
4
+ /**
5
+ * Run-scoped process test operations.
6
+ *
7
+ * Test runs are addressed by their own id here, so these methods work for every run whatever it
8
+ * was started against — a stored process test suite, an in-code `app:`/`sys:` process, or an
9
+ * ephemeral definition submitted inline.
10
+ */
11
+ export class ProcessTestRunApi extends ApiTopic {
12
+ constructor(parent: ClientBase) {
13
+ super(parent, '/api/v1/process-test-runs');
14
+ }
15
+
16
+ /**
17
+ * Start a test run against an in-code process or an inline definition, with the scenarios
18
+ * supplied in the request instead of a stored suite. Use
19
+ * `client.store.processes.startTestRun()` for stored process definitions and their suites.
20
+ */
21
+ submit(payload: SubmitProcessTestRunPayload): Promise<ProcessTestRun> {
22
+ // Starting a run is not idempotent and the contract carries no request key, so a replay
23
+ // would create a second run. Opt out of any client-level retry policy explicitly rather
24
+ // than relying on POST being absent from its method list. Rate-limiter pacing retries are
25
+ // unaffected: those happen before the request reaches the handler.
26
+ return this.post('/', { payload, retryPolicy: false });
27
+ }
28
+
29
+ retrieve(runId: string): Promise<ProcessTestRun> {
30
+ return this.get(`/${runId}`);
31
+ }
32
+
33
+ cancel(runId: string): Promise<ProcessTestRun> {
34
+ return this.post(`/${runId}/cancel`, {});
35
+ }
36
+
37
+ /** Deletes a run and its snapshot, cancelling it first when it is still active. */
38
+ delete(runId: string): Promise<{ id: string; count: number }> {
39
+ return this.del(`/${runId}`);
40
+ }
41
+ }