veryfront 0.1.233 → 0.1.235

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.
@@ -4,6 +4,34 @@ import { z } from "zod";
4
4
 
5
5
  const AGENT_RUN_API_TIMEOUT_MS = 15_000;
6
6
 
7
+ function createTimedAbortSignal(timeoutMs: number, abortSignal?: AbortSignal) {
8
+ const controller = new AbortController();
9
+ let abortedByCaller = false;
10
+ const timeout = dntShim.setTimeout(() => {
11
+ controller.abort();
12
+ }, timeoutMs);
13
+
14
+ const onAbort = () => {
15
+ abortedByCaller = true;
16
+ controller.abort();
17
+ };
18
+
19
+ if (abortSignal?.aborted) {
20
+ onAbort();
21
+ } else {
22
+ abortSignal?.addEventListener("abort", onAbort, { once: true });
23
+ }
24
+
25
+ return {
26
+ signal: controller.signal,
27
+ wasAbortedByCaller: () => abortedByCaller,
28
+ cleanup: () => {
29
+ clearTimeout(timeout);
30
+ abortSignal?.removeEventListener("abort", onAbort);
31
+ },
32
+ };
33
+ }
34
+
7
35
  export const ConversationRunTargetsSchema = z.object({
8
36
  sourceTargetKind: z.enum(["project", "preview_branch"]).nullable(),
9
37
  runtimeTargetKind: z.enum(["production", "preview_branch"]).nullable(),
@@ -37,6 +65,15 @@ export function resolveConversationRunTargets(input: {
37
65
  );
38
66
  }
39
67
 
68
+ export const ConversationRunStatusSchema = z.enum([
69
+ "pending",
70
+ "running",
71
+ "waiting_for_tool",
72
+ "completed",
73
+ "failed",
74
+ "cancelled",
75
+ ]);
76
+
40
77
  export const ConversationRunProjectionSchema = z
41
78
  .object({
42
79
  runId: z.string().min(1).optional(),
@@ -49,7 +86,7 @@ export const ConversationRunProjectionSchema = z
49
86
  latest_event_id: z.number().int().nonnegative().optional(),
50
87
  latestExternalEventSequence: z.number().int().nonnegative().optional(),
51
88
  latest_external_event_sequence: z.number().int().nonnegative().optional(),
52
- status: z.enum(["pending", "running", "waiting_for_tool", "completed", "failed", "cancelled"]),
89
+ status: ConversationRunStatusSchema,
53
90
  })
54
91
  .passthrough()
55
92
  .transform((data) => {
@@ -79,6 +116,14 @@ export const ConversationRunProjectionSchema = z
79
116
  });
80
117
 
81
118
  export type ConversationRunProjection = z.infer<typeof ConversationRunProjectionSchema>;
119
+ export type ActiveConversationRunStatus = Extract<
120
+ ConversationRunProjection["status"],
121
+ "pending" | "running" | "waiting_for_tool"
122
+ >;
123
+ export type TerminalConversationRunStatus = Extract<
124
+ ConversationRunProjection["status"],
125
+ "completed" | "failed" | "cancelled"
126
+ >;
82
127
 
83
128
  export const CreateConversationRunAcceptedSchema = z
84
129
  .object({
@@ -112,6 +157,59 @@ export const CompleteConversationRunResponseSchema = z
112
157
  })
113
158
  .passthrough();
114
159
 
160
+ const AppendConversationRunEventsCamelRunSchema = z
161
+ .object({
162
+ runId: z.string().min(1),
163
+ conversationId: z.string().uuid(),
164
+ latestEventId: z.number().int().nonnegative(),
165
+ latestExternalEventSequence: z.number().int().nonnegative(),
166
+ })
167
+ .passthrough();
168
+
169
+ const AppendConversationRunEventsSnakeRunSchema = z
170
+ .object({
171
+ run_id: z.string().min(1),
172
+ conversation_id: z.string().uuid(),
173
+ latest_event_id: z.number().int().nonnegative(),
174
+ latest_external_event_sequence: z.number().int().nonnegative(),
175
+ })
176
+ .passthrough();
177
+
178
+ export const AppendConversationRunEventsResponseSchema = z.union([
179
+ z.object({
180
+ latestEventId: z.number().int().nonnegative(),
181
+ latestExternalEventSequence: z.number().int().nonnegative(),
182
+ appendedCount: z.number().int().nonnegative(),
183
+ run: AppendConversationRunEventsCamelRunSchema,
184
+ }),
185
+ z.object({
186
+ latest_event_id: z.number().int().nonnegative(),
187
+ latest_external_event_sequence: z.number().int().nonnegative(),
188
+ appended_count: z.number().int().nonnegative(),
189
+ run: AppendConversationRunEventsSnakeRunSchema,
190
+ }).transform((data) => ({
191
+ latestEventId: data.latest_event_id,
192
+ latestExternalEventSequence: data.latest_external_event_sequence,
193
+ appendedCount: data.appended_count,
194
+ run: {
195
+ ...data.run,
196
+ runId: data.run.run_id,
197
+ conversationId: data.run.conversation_id,
198
+ latestEventId: data.run.latest_event_id,
199
+ latestExternalEventSequence: data.run.latest_external_event_sequence,
200
+ },
201
+ })),
202
+ ]);
203
+
204
+ export type AppendConversationRunEventsResponse = z.infer<
205
+ typeof AppendConversationRunEventsResponseSchema
206
+ >;
207
+
208
+ const ConversationRunErrorSchema = z.object({
209
+ detail: z.string().min(1).optional(),
210
+ error: z.string().min(1).optional(),
211
+ });
212
+
115
213
  export interface ConversationAgentRunUsage {
116
214
  inputTokens: number;
117
215
  outputTokens: number;
@@ -141,6 +239,113 @@ export interface FinalizeConversationAgentRunInput {
141
239
  terminalErrorMessage?: string | null;
142
240
  }
143
241
 
242
+ export class ConversationRunTerminalStateError extends Error {
243
+ readonly status: TerminalConversationRunStatus;
244
+ readonly run: ConversationRunProjection;
245
+
246
+ constructor(run: ConversationRunProjection, status: TerminalConversationRunStatus) {
247
+ super(`Conversation run ${run.runId} became ${status} before host execution finished`);
248
+ this.name = "ConversationRunTerminalStateError";
249
+ this.status = status;
250
+ this.run = run;
251
+ }
252
+ }
253
+
254
+ export class AppendConversationRunEventsError extends Error {
255
+ readonly status: number;
256
+ readonly detail: string | null;
257
+
258
+ constructor(input: {
259
+ status: number;
260
+ detail?: string | null;
261
+ statusText?: string;
262
+ }) {
263
+ const detail = input.detail?.trim() || input.statusText || `HTTP ${input.status}`;
264
+ super(`Append conversation run events failed (${input.status}): ${detail}`);
265
+ this.name = "AppendConversationRunEventsError";
266
+ this.status = input.status;
267
+ this.detail = input.detail?.trim() || null;
268
+ }
269
+ }
270
+
271
+ export function parseAppendConversationRunEventsErrorBody(bodyText: string): string | null {
272
+ if (!bodyText) {
273
+ return null;
274
+ }
275
+
276
+ try {
277
+ const parsed = ConversationRunErrorSchema.safeParse(JSON.parse(bodyText));
278
+ if (parsed.success) {
279
+ return parsed.data.detail ?? parsed.data.error ?? null;
280
+ }
281
+ } catch {
282
+ return bodyText;
283
+ }
284
+
285
+ return bodyText;
286
+ }
287
+
288
+ export function isIgnorableConversationRunAppendError(
289
+ error: unknown,
290
+ ): error is AppendConversationRunEventsError {
291
+ if (!(error instanceof AppendConversationRunEventsError)) {
292
+ return false;
293
+ }
294
+
295
+ if (error.status === 404) {
296
+ return true;
297
+ }
298
+
299
+ if (error.status !== 400) {
300
+ return false;
301
+ }
302
+
303
+ return (
304
+ error.detail === "Cannot append external events to a terminal run" ||
305
+ error.detail === "Cannot append external events while the run is waiting for a tool result"
306
+ );
307
+ }
308
+
309
+ export function isCursorMismatchConversationRunAppendError(
310
+ error: unknown,
311
+ ): error is AppendConversationRunEventsError {
312
+ return (
313
+ error instanceof AppendConversationRunEventsError &&
314
+ error.status === 400 &&
315
+ error.detail === "External run event cursor mismatch"
316
+ );
317
+ }
318
+
319
+ export function isActiveConversationRunStatus(
320
+ status: ConversationRunProjection["status"],
321
+ ): status is ActiveConversationRunStatus {
322
+ return status === "pending" || status === "running" || status === "waiting_for_tool";
323
+ }
324
+
325
+ async function waitForConversationRunPoll(
326
+ ms: number,
327
+ abortSignal?: AbortSignal,
328
+ ): Promise<void> {
329
+ if (ms <= 0 || abortSignal?.aborted) {
330
+ return;
331
+ }
332
+
333
+ await new Promise<void>((resolve) => {
334
+ const timeoutId = dntShim.setTimeout(() => {
335
+ abortSignal?.removeEventListener("abort", resolveOnAbort);
336
+ resolve();
337
+ }, ms);
338
+
339
+ const resolveOnAbort = () => {
340
+ clearTimeout(timeoutId);
341
+ abortSignal?.removeEventListener("abort", resolveOnAbort);
342
+ resolve();
343
+ };
344
+
345
+ abortSignal?.addEventListener("abort", resolveOnAbort, { once: true });
346
+ });
347
+ }
348
+
144
349
  async function controlPlaneJson<T>(input: {
145
350
  authToken: string;
146
351
  url: string;
@@ -148,11 +353,13 @@ async function controlPlaneJson<T>(input: {
148
353
  body?: unknown;
149
354
  responseSchema: z.ZodSchema<T>;
150
355
  operation: string;
356
+ abortSignal?: AbortSignal;
151
357
  }): Promise<T> {
152
- const controller = new AbortController();
153
- const timeout = dntShim.setTimeout(() => {
154
- controller.abort();
155
- }, AGENT_RUN_API_TIMEOUT_MS);
358
+ if (input.abortSignal?.aborted) {
359
+ throw new DOMException("This operation was aborted", "AbortError");
360
+ }
361
+
362
+ const timedAbort = createTimedAbortSignal(AGENT_RUN_API_TIMEOUT_MS, input.abortSignal);
156
363
 
157
364
  let response: Response;
158
365
  try {
@@ -163,15 +370,19 @@ async function controlPlaneJson<T>(input: {
163
370
  "Content-Type": "application/json",
164
371
  },
165
372
  ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),
166
- signal: controller.signal,
373
+ signal: timedAbort.signal,
167
374
  });
168
375
  } catch (error) {
169
- if (error instanceof DOMException && error.name === "AbortError") {
376
+ if (
377
+ error instanceof DOMException &&
378
+ error.name === "AbortError" &&
379
+ !timedAbort.wasAbortedByCaller()
380
+ ) {
170
381
  throw new Error(`${input.operation} timed out after ${AGENT_RUN_API_TIMEOUT_MS}ms`);
171
382
  }
172
383
  throw error;
173
384
  } finally {
174
- clearTimeout(timeout);
385
+ timedAbort.cleanup();
175
386
  }
176
387
 
177
388
  if (!response.ok) {
@@ -184,6 +395,141 @@ async function controlPlaneJson<T>(input: {
184
395
  return input.responseSchema.parse(await response.json());
185
396
  }
186
397
 
398
+ export async function getConversationRun(input: {
399
+ authToken: string;
400
+ apiUrl: string;
401
+ conversationId: string;
402
+ runId: string;
403
+ abortSignal?: AbortSignal;
404
+ }): Promise<ConversationRunProjection> {
405
+ return controlPlaneJson({
406
+ authToken: input.authToken,
407
+ url: `${input.apiUrl}/conversations/${input.conversationId}/runs/${input.runId}`,
408
+ responseSchema: ConversationRunProjectionSchema,
409
+ operation: "Read conversation durable run projection",
410
+ abortSignal: input.abortSignal,
411
+ });
412
+ }
413
+
414
+ export async function monitorConversationRunStatus(input: {
415
+ authToken: string;
416
+ apiUrl: string;
417
+ conversationId: string;
418
+ runId: string;
419
+ abortSignal?: AbortSignal;
420
+ pollIntervalMs: number;
421
+ onTerminal: (error: ConversationRunTerminalStateError) => void | Promise<void>;
422
+ onPollError?: (error: unknown) => void | Promise<void>;
423
+ }): Promise<void> {
424
+ while (!input.abortSignal?.aborted) {
425
+ await waitForConversationRunPoll(input.pollIntervalMs, input.abortSignal);
426
+ if (input.abortSignal?.aborted) {
427
+ return;
428
+ }
429
+
430
+ try {
431
+ const run = await getConversationRun({
432
+ authToken: input.authToken,
433
+ apiUrl: input.apiUrl,
434
+ conversationId: input.conversationId,
435
+ runId: input.runId,
436
+ abortSignal: input.abortSignal,
437
+ });
438
+
439
+ if (isActiveConversationRunStatus(run.status)) {
440
+ continue;
441
+ }
442
+
443
+ if (
444
+ run.status === "completed" ||
445
+ run.status === "failed" ||
446
+ run.status === "cancelled"
447
+ ) {
448
+ await input.onTerminal(new ConversationRunTerminalStateError(run, run.status));
449
+ }
450
+ return;
451
+ } catch (error) {
452
+ if (input.abortSignal?.aborted) {
453
+ return;
454
+ }
455
+
456
+ if (error instanceof DOMException && error.name === "AbortError") {
457
+ return;
458
+ }
459
+
460
+ await input.onPollError?.(error);
461
+ }
462
+ }
463
+ }
464
+
465
+ export async function appendConversationRunEvents(input: {
466
+ authToken: string;
467
+ apiUrl: string;
468
+ conversationId: string;
469
+ runId: string;
470
+ expectedPreviousEventId?: number;
471
+ expectedPreviousExternalEventSequence?: number;
472
+ events: unknown[];
473
+ abortSignal?: AbortSignal;
474
+ }): Promise<AppendConversationRunEventsResponse> {
475
+ if (input.abortSignal?.aborted) {
476
+ throw new DOMException("This operation was aborted", "AbortError");
477
+ }
478
+
479
+ const timedAbort = createTimedAbortSignal(AGENT_RUN_API_TIMEOUT_MS, input.abortSignal);
480
+
481
+ let response: Response;
482
+ try {
483
+ response = await fetch(
484
+ `${input.apiUrl}/conversations/${input.conversationId}/runs/${input.runId}/events`,
485
+ {
486
+ method: "POST",
487
+ headers: {
488
+ Authorization: `Bearer ${input.authToken}`,
489
+ "Content-Type": "application/json",
490
+ },
491
+ body: JSON.stringify({
492
+ ...(input.expectedPreviousEventId !== undefined
493
+ ? { expected_previous_event_id: input.expectedPreviousEventId }
494
+ : {}),
495
+ ...(input.expectedPreviousExternalEventSequence !== undefined
496
+ ? {
497
+ expected_previous_external_event_sequence:
498
+ input.expectedPreviousExternalEventSequence,
499
+ }
500
+ : {}),
501
+ events: input.events,
502
+ }),
503
+ signal: timedAbort.signal,
504
+ },
505
+ );
506
+ } catch (error) {
507
+ if (
508
+ error instanceof DOMException &&
509
+ error.name === "AbortError" &&
510
+ !timedAbort.wasAbortedByCaller()
511
+ ) {
512
+ throw new Error(
513
+ `Append conversation run events timed out after ${AGENT_RUN_API_TIMEOUT_MS}ms`,
514
+ );
515
+ }
516
+ throw error;
517
+ } finally {
518
+ timedAbort.cleanup();
519
+ }
520
+
521
+ if (!response.ok) {
522
+ const body = await response.text().catch(() => "");
523
+ throw new AppendConversationRunEventsError({
524
+ status: response.status,
525
+ detail: parseAppendConversationRunEventsErrorBody(body),
526
+ statusText: response.statusText,
527
+ });
528
+ }
529
+
530
+ return AppendConversationRunEventsResponseSchema.parse(await response.json());
531
+ }
532
+
187
533
  export async function createConversationAgentRun(
188
534
  input: CreateConversationAgentRunInput,
189
535
  ): Promise<ConversationRunProjection> {
@@ -222,11 +568,11 @@ export async function createConversationAgentRun(
222
568
  operation: "Create canonical durable run",
223
569
  });
224
570
 
225
- return controlPlaneJson({
571
+ return getConversationRun({
226
572
  authToken: input.authToken,
227
- url: `${input.apiUrl}/conversations/${input.conversationId}/runs/${runId}`,
228
- responseSchema: ConversationRunProjectionSchema,
229
- operation: "Read conversation durable run projection",
573
+ apiUrl: input.apiUrl,
574
+ conversationId: input.conversationId,
575
+ runId,
230
576
  });
231
577
  }
232
578
 
@@ -193,16 +193,44 @@ export {
193
193
  fetchConversationRecord,
194
194
  } from "./conversation-bootstrap.js";
195
195
  export {
196
+ type ActiveConversationRunStatus,
197
+ appendConversationRunEvents,
198
+ AppendConversationRunEventsError,
199
+ type AppendConversationRunEventsResponse,
200
+ AppendConversationRunEventsResponseSchema,
196
201
  CompleteConversationRunResponseSchema,
197
202
  type ConversationAgentRunUsage,
198
203
  type ConversationRunProjection,
199
204
  ConversationRunProjectionSchema,
205
+ ConversationRunStatusSchema,
200
206
  type ConversationRunTargets,
201
207
  ConversationRunTargetsSchema,
208
+ ConversationRunTerminalStateError,
202
209
  createConversationAgentRun,
203
210
  finalizeConversationAgentRun,
211
+ getConversationRun,
212
+ isActiveConversationRunStatus,
213
+ isCursorMismatchConversationRunAppendError,
214
+ isIgnorableConversationRunAppendError,
215
+ monitorConversationRunStatus,
216
+ parseAppendConversationRunEventsErrorBody,
204
217
  resolveConversationRunTargets,
218
+ type TerminalConversationRunStatus,
205
219
  } from "./durable.js";
220
+ export {
221
+ buildInvokeAgentChildRunLifecycleCustomEvent,
222
+ buildInvokeAgentChildRunProgressEvents,
223
+ buildInvokeAgentChildRunStateDelta,
224
+ type InvokeAgentChildRunLifecycleCustomEvent,
225
+ InvokeAgentChildRunLifecycleCustomEventSchema,
226
+ type InvokeAgentChildRunLifecycleValue,
227
+ InvokeAgentChildRunLifecycleValueSchema,
228
+ type InvokeAgentChildRunProgressEvent,
229
+ type InvokeAgentChildRunProgressInput,
230
+ type InvokeAgentChildRunStateDelta,
231
+ InvokeAgentChildRunStateDeltaSchema,
232
+ publishInvokeAgentChildRunProgress,
233
+ } from "./invoke-agent-child-runs.js";
206
234
  export {
207
235
  type HostedChildLifecycleAdapter,
208
236
  type HostedChildLifecycleRunnerOptions,
@@ -0,0 +1,170 @@
1
+ import "../../_dnt.polyfills.js";
2
+ import { z } from "zod";
3
+ import { appendConversationRunEvents, isIgnorableConversationRunAppendError } from "./durable.js";
4
+
5
+ const AG_UI_CUSTOM_EVENT_TYPE = "CUSTOM";
6
+
7
+ export const InvokeAgentChildRunLifecycleValueSchema = z.object({
8
+ toolCallId: z.string().min(1),
9
+ childConversationId: z.string().uuid(),
10
+ childRunId: z.string().min(1),
11
+ childMessageId: z.string().uuid(),
12
+ childAgentId: z.string().min(1),
13
+ description: z.string().min(1).optional(),
14
+ status: z.enum(["pending", "running", "waiting_for_tool", "completed", "failed", "cancelled"]),
15
+ sourceTargetKind: z.enum(["project", "production", "environment", "preview_branch"]).nullable()
16
+ .optional(),
17
+ runtimeTargetKind: z.enum(["production", "environment", "preview_branch"]).nullable().optional(),
18
+ targetEnvironmentId: z.string().uuid().nullable().optional(),
19
+ targetBranchId: z.string().uuid().nullable().optional(),
20
+ });
21
+
22
+ export type InvokeAgentChildRunLifecycleValue = z.infer<
23
+ typeof InvokeAgentChildRunLifecycleValueSchema
24
+ >;
25
+
26
+ export const InvokeAgentChildRunStateDeltaSchema = z.object({
27
+ type: z.literal("STATE_DELTA"),
28
+ delta: z.array(
29
+ z.object({
30
+ op: z.enum(["add", "replace"]),
31
+ path: z.string().min(1),
32
+ value: InvokeAgentChildRunLifecycleValueSchema,
33
+ }),
34
+ ),
35
+ });
36
+
37
+ export type InvokeAgentChildRunStateDelta = z.infer<typeof InvokeAgentChildRunStateDeltaSchema>;
38
+
39
+ export const InvokeAgentChildRunLifecycleCustomEventSchema = z.object({
40
+ type: z.literal(AG_UI_CUSTOM_EVENT_TYPE),
41
+ name: z.literal("veryfront.invoke_agent.lifecycle"),
42
+ value: InvokeAgentChildRunLifecycleValueSchema,
43
+ });
44
+
45
+ export type InvokeAgentChildRunLifecycleCustomEvent = z.infer<
46
+ typeof InvokeAgentChildRunLifecycleCustomEventSchema
47
+ >;
48
+
49
+ export type InvokeAgentChildRunProgressInput = {
50
+ toolCallId: string;
51
+ childConversationId: string;
52
+ childRunId: string;
53
+ childMessageId: string;
54
+ childAgentId: string;
55
+ description?: string;
56
+ status: "pending" | "running" | "waiting_for_tool" | "completed" | "failed" | "cancelled";
57
+ sourceTargetKind?: "project" | "production" | "environment" | "preview_branch" | null;
58
+ runtimeTargetKind?: "production" | "environment" | "preview_branch" | null;
59
+ targetEnvironmentId?: string | null;
60
+ targetBranchId?: string | null;
61
+ };
62
+
63
+ export type InvokeAgentChildRunProgressEvent =
64
+ | InvokeAgentChildRunStateDelta
65
+ | InvokeAgentChildRunLifecycleCustomEvent;
66
+
67
+ function buildInvokeAgentChildRunLifecycleValue(
68
+ input: InvokeAgentChildRunProgressInput,
69
+ ): InvokeAgentChildRunLifecycleValue {
70
+ return InvokeAgentChildRunLifecycleValueSchema.parse({
71
+ toolCallId: input.toolCallId,
72
+ childConversationId: input.childConversationId,
73
+ childRunId: input.childRunId,
74
+ childMessageId: input.childMessageId,
75
+ childAgentId: input.childAgentId,
76
+ ...(input.description ? { description: input.description } : {}),
77
+ status: input.status,
78
+ ...(input.sourceTargetKind !== undefined ? { sourceTargetKind: input.sourceTargetKind } : {}),
79
+ ...(input.runtimeTargetKind !== undefined
80
+ ? { runtimeTargetKind: input.runtimeTargetKind }
81
+ : {}),
82
+ ...(input.targetEnvironmentId !== undefined
83
+ ? { targetEnvironmentId: input.targetEnvironmentId }
84
+ : {}),
85
+ ...(input.targetBranchId !== undefined ? { targetBranchId: input.targetBranchId } : {}),
86
+ });
87
+ }
88
+
89
+ export function buildInvokeAgentChildRunStateDelta(
90
+ input: InvokeAgentChildRunProgressInput,
91
+ ): InvokeAgentChildRunStateDelta {
92
+ const escapedToolCallId = input.toolCallId.replaceAll("~", "~0").replaceAll("/", "~1");
93
+ return InvokeAgentChildRunStateDeltaSchema.parse({
94
+ type: "STATE_DELTA",
95
+ delta: [
96
+ {
97
+ op: input.status === "pending" ? "add" : "replace",
98
+ path: `/invokeAgentChildRuns/${escapedToolCallId}`,
99
+ value: buildInvokeAgentChildRunLifecycleValue(input),
100
+ },
101
+ ],
102
+ });
103
+ }
104
+
105
+ export function buildInvokeAgentChildRunLifecycleCustomEvent(
106
+ input: InvokeAgentChildRunProgressInput,
107
+ ): InvokeAgentChildRunLifecycleCustomEvent {
108
+ return InvokeAgentChildRunLifecycleCustomEventSchema.parse({
109
+ type: AG_UI_CUSTOM_EVENT_TYPE,
110
+ name: "veryfront.invoke_agent.lifecycle",
111
+ value: buildInvokeAgentChildRunLifecycleValue(input),
112
+ });
113
+ }
114
+
115
+ export function buildInvokeAgentChildRunProgressEvents(
116
+ input: InvokeAgentChildRunProgressInput,
117
+ ): readonly [InvokeAgentChildRunStateDelta, InvokeAgentChildRunLifecycleCustomEvent] {
118
+ return [
119
+ buildInvokeAgentChildRunStateDelta(input),
120
+ buildInvokeAgentChildRunLifecycleCustomEvent(input),
121
+ ] as const;
122
+ }
123
+
124
+ export async function publishInvokeAgentChildRunProgress(input: {
125
+ authToken: string;
126
+ apiUrl: string;
127
+ conversationId: string;
128
+ runId: string;
129
+ expectedPreviousEventId?: number;
130
+ expectedPreviousExternalEventSequence?: number;
131
+ toolCallId: string;
132
+ childAgentId: string;
133
+ childConversationId: string;
134
+ childRunId: string;
135
+ childMessageId: string;
136
+ description?: string;
137
+ status: "pending" | "running" | "waiting_for_tool" | "completed" | "failed" | "cancelled";
138
+ sourceTargetKind?: "project" | "production" | "environment" | "preview_branch" | null;
139
+ runtimeTargetKind?: "production" | "environment" | "preview_branch" | null;
140
+ targetEnvironmentId?: string | null;
141
+ targetBranchId?: string | null;
142
+ publishParentRunEvents?: (events: InvokeAgentChildRunProgressEvent[]) => Promise<void> | void;
143
+ abortSignal?: AbortSignal;
144
+ }): Promise<void> {
145
+ const events = [...buildInvokeAgentChildRunProgressEvents(input)];
146
+
147
+ if (input.publishParentRunEvents) {
148
+ await input.publishParentRunEvents(events);
149
+ return;
150
+ }
151
+
152
+ try {
153
+ await appendConversationRunEvents({
154
+ authToken: input.authToken,
155
+ apiUrl: input.apiUrl,
156
+ conversationId: input.conversationId,
157
+ runId: input.runId,
158
+ expectedPreviousEventId: input.expectedPreviousEventId,
159
+ expectedPreviousExternalEventSequence: input.expectedPreviousExternalEventSequence,
160
+ events,
161
+ abortSignal: input.abortSignal,
162
+ });
163
+ } catch (error) {
164
+ if (isIgnorableConversationRunAppendError(error)) {
165
+ return;
166
+ }
167
+
168
+ throw error;
169
+ }
170
+ }
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.233";
3
+ export const VERSION = "0.1.235";