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.
- package/esm/deno.d.ts +1 -0
- package/esm/deno.js +2 -1
- package/esm/src/agent/durable.d.ts +102 -0
- package/esm/src/agent/durable.d.ts.map +1 -1
- package/esm/src/agent/durable.js +258 -12
- package/esm/src/agent/index.d.ts +2 -1
- package/esm/src/agent/index.d.ts.map +1 -1
- package/esm/src/agent/index.js +2 -1
- package/esm/src/agent/invoke-agent-child-runs.d.ts +145 -0
- package/esm/src/agent/invoke-agent-child-runs.d.ts.map +1 -0
- package/esm/src/agent/invoke-agent-child-runs.js +101 -0
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +5 -1
- package/src/deno.js +2 -1
- package/src/src/agent/durable.ts +358 -12
- package/src/src/agent/index.ts +28 -0
- package/src/src/agent/invoke-agent-child-runs.ts +170 -0
- package/src/src/utils/version-constant.ts +1 -1
package/src/src/agent/durable.ts
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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:
|
|
373
|
+
signal: timedAbort.signal,
|
|
167
374
|
});
|
|
168
375
|
} catch (error) {
|
|
169
|
-
if (
|
|
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
|
-
|
|
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
|
|
571
|
+
return getConversationRun({
|
|
226
572
|
authToken: input.authToken,
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
573
|
+
apiUrl: input.apiUrl,
|
|
574
|
+
conversationId: input.conversationId,
|
|
575
|
+
runId,
|
|
230
576
|
});
|
|
231
577
|
}
|
|
232
578
|
|
package/src/src/agent/index.ts
CHANGED
|
@@ -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
|
+
}
|