veryfront 0.1.326 → 0.1.327

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.
@@ -0,0 +1,579 @@
1
+ import {
2
+ buildFallbackUiMessageChunks,
3
+ extractFinalStepFinishReason,
4
+ extractFinalStepText,
5
+ extractFinalStepToolCalls,
6
+ extractFinalStepToolResults,
7
+ getStreamSteps,
8
+ } from "../chat/final-step-fallback.js";
9
+ import { mapHostedStreamPartToChatUiChunks } from "../chat/hosted-ui-chunk-mapping.js";
10
+ import type { ChatMessageMetadata, ChatUiMessageChunk } from "../chat/protocol.js";
11
+ import {
12
+ appendMissingChildRunToolCalls,
13
+ appendMissingChildRunToolResults,
14
+ buildChildRunExhaustedStepBudgetErrorMessage,
15
+ } from "./child-run-final-step-support.js";
16
+ import {
17
+ buildChildRunFailureResult,
18
+ buildChildRunFailureSnapshot,
19
+ buildChildRunResultCommon,
20
+ buildChildRunSuccessResult,
21
+ buildChildRunSuccessSnapshot,
22
+ type ChildRunExecutionResult,
23
+ type ChildRunExecutionSnapshot,
24
+ type ChildRunExecutionUsage,
25
+ } from "./child-run-execution-snapshot.js";
26
+ import {
27
+ formatChildRunStreamPartError,
28
+ throwIfChildRunAborted,
29
+ toChildRunToolInputRecord,
30
+ } from "./child-run-execution-support.js";
31
+ import {
32
+ buildChildRunResultSummary,
33
+ summarizeChildRunResultValue,
34
+ } from "./child-run-result-summary.js";
35
+ import {
36
+ buildHostedChildCompletedLog,
37
+ buildHostedChildExhaustedStepBudgetLog,
38
+ type HostedChildExecutionLogEntry,
39
+ } from "./hosted-child-execution-logging.js";
40
+ import { isAlreadyMirroredHostedChunk, toMirroredHostedStreamPart } from "./hosted-child-mirror.js";
41
+ import type {
42
+ HostedChildPendingToolCallState,
43
+ HostedChildPendingToolLifecycleCloseReason,
44
+ } from "./hosted-child-pending-tool-lifecycle.js";
45
+ import {
46
+ HOSTED_CHILD_STREAM_TIMEOUT_TOKEN,
47
+ type HostedChildStreamWatchdogState,
48
+ resolveHostedChildPromiseWithTimeout,
49
+ resolveHostedChildStreamWatchdogState,
50
+ withHostedChildStreamIdleTimeout,
51
+ } from "./hosted-child-stream-watchdog.js";
52
+ import type { ForkPart, ForkRuntimeStreamResult } from "./fork-runtime-stream.js";
53
+
54
+ const SOFT_IDLE_HEARTBEAT_PHASE = "post_tool_idle";
55
+ const MAX_SOFT_IDLE_HEARTBEATS = 2;
56
+
57
+ export interface HostedChildForkStreamHandlingState {
58
+ activeToolCallId: string | null;
59
+ finalText: string;
60
+ shouldSeparateNextTextBlock: boolean;
61
+ }
62
+
63
+ export interface HostedChildForkStreamLogger {
64
+ debug?: (message: string, metadata?: Record<string, unknown>) => void;
65
+ info?: (message: string, metadata?: Record<string, unknown>) => void;
66
+ warn?: (message: string, metadata?: Record<string, unknown>) => void;
67
+ }
68
+
69
+ export interface HostedChildForkPendingToolLifecycle {
70
+ emitToolInputStartIfNeeded: (toolCallId: string, toolName: string) => Promise<void> | void;
71
+ upsertPendingToolCall: (toolCallId: string, state: HostedChildPendingToolCallState) => void;
72
+ deletePendingToolCall: (toolCallId: string) => void;
73
+ closePendingToolCalls: (
74
+ reason: HostedChildPendingToolLifecycleCloseReason,
75
+ ) => Promise<void> | void;
76
+ }
77
+
78
+ export interface HostedChildForkStreamTraceInput {
79
+ conversationId?: string;
80
+ parentRunId?: string;
81
+ partType: ForkPart["type"];
82
+ }
83
+
84
+ export interface ExecuteHostedChildForkStreamInput {
85
+ streamResult: ForkRuntimeStreamResult;
86
+ abortSignal?: AbortSignal;
87
+ abortForkStream: (error: Error) => void;
88
+ conversationId?: string;
89
+ parentRunId?: string;
90
+ description: string;
91
+ kind: string;
92
+ durableRunMirror: boolean;
93
+ durableMessageId: string | null;
94
+ durableReasoningMessageId: string | null;
95
+ durableMirrorState: { reasoningStarted: boolean; textStarted: boolean };
96
+ appendDurableMirrorChunk: (chunk: ChatUiMessageChunk<ChatMessageMetadata>) => Promise<void>;
97
+ closeDurableMirrorReasoning: () => Promise<void>;
98
+ closeDurableMirrorText: () => Promise<void>;
99
+ markDurableStepStarted: () => void;
100
+ durableMirrorHasEmittedProgress: () => boolean;
101
+ pendingToolLifecycle: HostedChildForkPendingToolLifecycle;
102
+ toolCalls: Array<{ toolName: string; toolCallId: string; input?: unknown }>;
103
+ toolResults: Array<{ toolName: string; toolCallId: string; input: unknown; output: unknown }>;
104
+ streamState: { finalText: string };
105
+ usage?: ChildRunExecutionUsage;
106
+ maxSteps: number;
107
+ startTime: number;
108
+ finalizationTimeoutMs: number;
109
+ onSettled?: (snapshot: ChildRunExecutionSnapshot) => void | Promise<void>;
110
+ idleTimeoutMs: number;
111
+ activeToolTimeoutMs: number;
112
+ postToolIdleTimeoutMs: number;
113
+ logger?: HostedChildForkStreamLogger;
114
+ writeLog?: (entry: HostedChildExecutionLogEntry) => void;
115
+ tracePart?: (input: HostedChildForkStreamTraceInput) => void | Promise<void>;
116
+ }
117
+
118
+ function isSoftIdleHeartbeatPhase(phase: HostedChildStreamWatchdogState["phase"]): boolean {
119
+ return phase === SOFT_IDLE_HEARTBEAT_PHASE;
120
+ }
121
+
122
+ function getStructuredContent(value: unknown): unknown {
123
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
124
+ return value;
125
+ }
126
+ if (!("structuredContent" in value)) {
127
+ return value;
128
+ }
129
+ return value.structuredContent;
130
+ }
131
+
132
+ export async function finalizeHostedChildForkCompletion(input: {
133
+ streamResult: ForkRuntimeStreamResult;
134
+ finalText: string;
135
+ description: string;
136
+ kind: string;
137
+ maxSteps: number;
138
+ toolCalls: Array<{ toolName: string; toolCallId: string; input?: unknown }>;
139
+ toolResults: Array<{ toolName: string; toolCallId: string; input: unknown; output: unknown }>;
140
+ usage?: ChildRunExecutionUsage;
141
+ startTime: number;
142
+ durableMessageId: string | null;
143
+ durableMirrorHasEmittedProgress: boolean;
144
+ appendDurableMirrorChunk: (chunk: ChatUiMessageChunk<ChatMessageMetadata>) => Promise<void>;
145
+ finalizationTimeoutMs: number;
146
+ onSettled?: (snapshot: ChildRunExecutionSnapshot) => void | Promise<void>;
147
+ logger?: HostedChildForkStreamLogger;
148
+ writeLog?: (entry: HostedChildExecutionLogEntry) => void;
149
+ }): Promise<ChildRunExecutionResult> {
150
+ const { steps: resolvedSteps, lastStep: finalStep } = await getStreamSteps(
151
+ input.streamResult,
152
+ input.finalizationTimeoutMs,
153
+ );
154
+ const stepCount = resolvedSteps.length;
155
+ let finalText = input.finalText;
156
+ let usage = input.usage;
157
+
158
+ if (finalText.trim().length === 0) {
159
+ finalText = extractFinalStepText(finalStep);
160
+ }
161
+
162
+ const fallbackToolCalls = extractFinalStepToolCalls(finalStep);
163
+ appendMissingChildRunToolCalls(input.toolCalls, fallbackToolCalls);
164
+
165
+ const fallbackToolResults = extractFinalStepToolResults(finalStep);
166
+ appendMissingChildRunToolResults(input.toolResults, fallbackToolResults);
167
+
168
+ if (!input.durableMirrorHasEmittedProgress && input.durableMessageId) {
169
+ const fallbackChunks = buildFallbackUiMessageChunks(finalStep, input.durableMessageId);
170
+ for (const chunk of fallbackChunks) {
171
+ await input.appendDurableMirrorChunk(chunk);
172
+ }
173
+ }
174
+
175
+ const totalUsage = await resolveHostedChildPromiseWithTimeout(
176
+ input.streamResult.totalUsage,
177
+ input.finalizationTimeoutMs,
178
+ ).catch((error) => {
179
+ input.logger?.warn?.("Child fork total usage failed after stream completion", {
180
+ description: input.description,
181
+ kind: input.kind,
182
+ error: error instanceof Error ? error.message : String(error),
183
+ });
184
+ return null;
185
+ });
186
+ if (totalUsage === HOSTED_CHILD_STREAM_TIMEOUT_TOKEN) {
187
+ input.logger?.warn?.("Child fork total usage timed out after stream completion", {
188
+ description: input.description,
189
+ kind: input.kind,
190
+ timeoutMs: input.finalizationTimeoutMs,
191
+ });
192
+ } else if (totalUsage) {
193
+ usage = {
194
+ inputTokens: totalUsage.inputTokens ?? 0,
195
+ outputTokens: totalUsage.outputTokens ?? 0,
196
+ totalTokens: (totalUsage.inputTokens ?? 0) + (totalUsage.outputTokens ?? 0),
197
+ };
198
+ }
199
+
200
+ const finalStepFinishReason = extractFinalStepFinishReason(finalStep);
201
+ const agentWantedToContinue = finalStepFinishReason === "tool-calls";
202
+ const exhaustedStepBudget = stepCount >= input.maxSteps && agentWantedToContinue;
203
+ if (exhaustedStepBudget) {
204
+ const errorMessage = buildChildRunExhaustedStepBudgetErrorMessage(stepCount, input.toolCalls);
205
+
206
+ input.writeLog?.(
207
+ buildHostedChildExhaustedStepBudgetLog({
208
+ description: input.description,
209
+ kind: input.kind,
210
+ stepCount,
211
+ maxSteps: input.maxSteps,
212
+ toolCallsLength: input.toolCalls.length,
213
+ }),
214
+ );
215
+
216
+ const common = buildChildRunResultCommon({
217
+ description: input.description,
218
+ steps: stepCount,
219
+ toolCalls: input.toolCalls,
220
+ toolResults: input.toolResults,
221
+ usage,
222
+ durationMs: Date.now() - input.startTime,
223
+ });
224
+ const snapshot = buildChildRunFailureSnapshot(common, errorMessage, finalText || null);
225
+ await input.onSettled?.(snapshot);
226
+ return buildChildRunFailureResult(common, errorMessage);
227
+ }
228
+
229
+ input.writeLog?.(
230
+ buildHostedChildCompletedLog({
231
+ description: input.description,
232
+ kind: input.kind,
233
+ toolCallsLength: input.toolCalls.length,
234
+ finalText,
235
+ }),
236
+ );
237
+
238
+ const common = buildChildRunResultCommon({
239
+ description: input.description,
240
+ steps: stepCount,
241
+ toolCalls: input.toolCalls,
242
+ toolResults: input.toolResults,
243
+ usage,
244
+ durationMs: Date.now() - input.startTime,
245
+ });
246
+ const snapshot = buildChildRunSuccessSnapshot(common, finalText);
247
+ await input.onSettled?.(snapshot);
248
+ return buildChildRunSuccessResult(common, buildChildRunResultSummary(finalText));
249
+ }
250
+
251
+ export async function handleHostedChildForkStreamPart(input: {
252
+ part: ForkPart;
253
+ conversationId?: string;
254
+ description: string;
255
+ durableMessageId: string | null;
256
+ durableReasoningMessageId: string | null;
257
+ durableMirrorState: { reasoningStarted: boolean; textStarted: boolean };
258
+ appendDurableMirrorChunk: (chunk: ChatUiMessageChunk<ChatMessageMetadata>) => Promise<void>;
259
+ closeDurableMirrorReasoning: () => Promise<void>;
260
+ closeDurableMirrorText: () => Promise<void>;
261
+ pendingToolLifecycle: HostedChildForkPendingToolLifecycle;
262
+ toolCalls: Array<{ toolName: string; toolCallId: string; input?: unknown }>;
263
+ toolResults: Array<{ toolName: string; toolCallId: string; input: unknown; output: unknown }>;
264
+ state: HostedChildForkStreamHandlingState;
265
+ logger?: HostedChildForkStreamLogger;
266
+ }): Promise<HostedChildForkStreamHandlingState> {
267
+ let { activeToolCallId, finalText, shouldSeparateNextTextBlock } = input.state;
268
+ const part = input.part;
269
+
270
+ if (part.type === "reasoning-delta") {
271
+ if (input.durableReasoningMessageId) {
272
+ if (!input.durableMirrorState.reasoningStarted) {
273
+ input.durableMirrorState.reasoningStarted = true;
274
+ await input.appendDurableMirrorChunk({
275
+ type: "reasoning-start",
276
+ id: input.durableReasoningMessageId,
277
+ });
278
+ }
279
+ await input.appendDurableMirrorChunk({
280
+ type: "reasoning-delta",
281
+ id: input.durableReasoningMessageId,
282
+ delta: part.text,
283
+ });
284
+ }
285
+ return { activeToolCallId, finalText, shouldSeparateNextTextBlock };
286
+ }
287
+
288
+ if (part.type === "text-delta") {
289
+ await input.closeDurableMirrorReasoning();
290
+ const nextText = shouldSeparateNextTextBlock && finalText.length > 0
291
+ ? `\n\n${part.text}`
292
+ : part.text;
293
+ finalText += nextText;
294
+ shouldSeparateNextTextBlock = false;
295
+ if (input.durableMessageId) {
296
+ if (!input.durableMirrorState.textStarted) {
297
+ input.durableMirrorState.textStarted = true;
298
+ await input.appendDurableMirrorChunk({
299
+ type: "text-start",
300
+ id: input.durableMessageId,
301
+ });
302
+ }
303
+ await input.appendDurableMirrorChunk({
304
+ type: "text-delta",
305
+ id: input.durableMessageId,
306
+ delta: part.text,
307
+ });
308
+ }
309
+ return { activeToolCallId, finalText, shouldSeparateNextTextBlock };
310
+ }
311
+
312
+ if (part.type === "tool-input-start") {
313
+ await input.closeDurableMirrorReasoning();
314
+ await input.closeDurableMirrorText();
315
+ activeToolCallId = part.toolCallId;
316
+ shouldSeparateNextTextBlock = finalText.length > 0;
317
+ await input.pendingToolLifecycle.emitToolInputStartIfNeeded(part.toolCallId, part.toolName);
318
+ input.pendingToolLifecycle.upsertPendingToolCall(part.toolCallId, {
319
+ phase: "input_streaming",
320
+ toolName: part.toolName,
321
+ });
322
+ return { activeToolCallId, finalText, shouldSeparateNextTextBlock };
323
+ }
324
+
325
+ if (part.type === "tool-input-delta") {
326
+ input.pendingToolLifecycle.upsertPendingToolCall(part.toolCallId, {
327
+ phase: "input_streaming",
328
+ });
329
+ return { activeToolCallId, finalText, shouldSeparateNextTextBlock };
330
+ }
331
+
332
+ if (part.type === "tool-call") {
333
+ await input.closeDurableMirrorReasoning();
334
+ await input.closeDurableMirrorText();
335
+ activeToolCallId = part.toolCallId;
336
+ shouldSeparateNextTextBlock = finalText.length > 0;
337
+ const summarizedInput = summarizeChildRunResultValue(part.input);
338
+ input.toolCalls.push({
339
+ toolName: part.toolName,
340
+ toolCallId: part.toolCallId,
341
+ input: summarizedInput,
342
+ });
343
+ input.logger?.debug?.("Child fork tool call", {
344
+ conversationId: input.conversationId,
345
+ toolCallId: part.toolCallId,
346
+ toolName: part.toolName,
347
+ description: input.description,
348
+ });
349
+ input.pendingToolLifecycle.upsertPendingToolCall(part.toolCallId, {
350
+ phase: "awaiting_result",
351
+ toolName: part.toolName,
352
+ input: summarizedInput,
353
+ });
354
+ await input.pendingToolLifecycle.emitToolInputStartIfNeeded(part.toolCallId, part.toolName);
355
+ await input.appendDurableMirrorChunk({
356
+ type: "tool-input-available",
357
+ toolCallId: part.toolCallId,
358
+ toolName: part.toolName,
359
+ input: toChildRunToolInputRecord(summarizedInput),
360
+ });
361
+ return { activeToolCallId, finalText, shouldSeparateNextTextBlock };
362
+ }
363
+
364
+ if (part.type === "tool-result") {
365
+ await input.closeDurableMirrorReasoning();
366
+ await input.closeDurableMirrorText();
367
+ activeToolCallId = null;
368
+ shouldSeparateNextTextBlock = finalText.length > 0;
369
+ const rawOutput = getStructuredContent(part.output);
370
+ const summarizedInput = summarizeChildRunResultValue(part.input);
371
+ const summarizedOutput = summarizeChildRunResultValue(rawOutput);
372
+ input.logger?.debug?.("Child fork tool result", {
373
+ conversationId: input.conversationId,
374
+ toolCallId: part.toolCallId,
375
+ toolName: part.toolName,
376
+ description: input.description,
377
+ });
378
+ input.toolResults.push({
379
+ toolName: part.toolName,
380
+ toolCallId: part.toolCallId,
381
+ input: summarizedInput,
382
+ output: summarizedOutput,
383
+ });
384
+ await input.appendDurableMirrorChunk({
385
+ type: "tool-output-available",
386
+ toolCallId: part.toolCallId,
387
+ output: summarizedOutput,
388
+ });
389
+ input.pendingToolLifecycle.deletePendingToolCall(part.toolCallId);
390
+ return { activeToolCallId, finalText, shouldSeparateNextTextBlock };
391
+ }
392
+
393
+ if (part.type === "tool-error") {
394
+ await input.closeDurableMirrorReasoning();
395
+ await input.closeDurableMirrorText();
396
+ shouldSeparateNextTextBlock = finalText.length > 0;
397
+ input.logger?.warn?.("Child fork tool error", {
398
+ conversationId: input.conversationId,
399
+ toolCallId: part.toolCallId,
400
+ toolName: part.toolName,
401
+ description: input.description,
402
+ });
403
+ await input.pendingToolLifecycle.emitToolInputStartIfNeeded(part.toolCallId, part.toolName);
404
+ await input.appendDurableMirrorChunk({
405
+ type: "tool-input-error",
406
+ toolCallId: part.toolCallId,
407
+ toolName: part.toolName,
408
+ input: toChildRunToolInputRecord(part.input),
409
+ errorText: part.error.message,
410
+ });
411
+ input.pendingToolLifecycle.deletePendingToolCall(part.toolCallId);
412
+ activeToolCallId = null;
413
+ return { activeToolCallId, finalText, shouldSeparateNextTextBlock };
414
+ }
415
+
416
+ return { activeToolCallId, finalText, shouldSeparateNextTextBlock };
417
+ }
418
+
419
+ export async function executeHostedChildForkStream(
420
+ input: ExecuteHostedChildForkStreamInput,
421
+ ): Promise<ChildRunExecutionResult> {
422
+ let activeToolCallId: string | null = null;
423
+ let finalText = input.streamState.finalText;
424
+ let shouldSeparateNextTextBlock = false;
425
+ let softIdleHeartbeatCount = 0;
426
+
427
+ if (input.durableRunMirror) {
428
+ input.markDurableStepStarted();
429
+ await input.appendDurableMirrorChunk({
430
+ type: "start-step",
431
+ });
432
+ }
433
+
434
+ let lastWatchdogPhase: string | null = null;
435
+ for await (
436
+ const part of withHostedChildStreamIdleTimeout({
437
+ stream: input.streamResult.fullStream,
438
+ getWatchdogState: () => {
439
+ const state = resolveHostedChildStreamWatchdogState({
440
+ activeToolCallId,
441
+ completedToolResults: input.toolResults.length,
442
+ idleTimeoutMs: input.idleTimeoutMs,
443
+ activeToolTimeoutMs: input.activeToolTimeoutMs,
444
+ postToolIdleTimeoutMs: input.postToolIdleTimeoutMs,
445
+ });
446
+ if (state.phase !== lastWatchdogPhase) {
447
+ input.logger?.debug?.("Fork watchdog phase changed", {
448
+ conversationId: input.conversationId,
449
+ description: input.description,
450
+ phase: state.phase,
451
+ previousPhase: lastWatchdogPhase,
452
+ timeoutMs: state.timeoutMs,
453
+ });
454
+ lastWatchdogPhase = state.phase;
455
+ }
456
+ return state;
457
+ },
458
+ abortSignal: input.abortSignal,
459
+ onIdleTimeout: async (watchdogState) => {
460
+ if (
461
+ isSoftIdleHeartbeatPhase(watchdogState.phase) &&
462
+ softIdleHeartbeatCount < MAX_SOFT_IDLE_HEARTBEATS
463
+ ) {
464
+ softIdleHeartbeatCount += 1;
465
+ input.logger?.info?.("Fork stream soft-idle heartbeat", {
466
+ conversationId: input.conversationId,
467
+ description: input.description,
468
+ watchdogPhase: watchdogState.phase,
469
+ heartbeatCount: softIdleHeartbeatCount,
470
+ timeoutMs: watchdogState.timeoutMs,
471
+ toolCallsCompleted: input.toolResults.length,
472
+ });
473
+ await input.appendDurableMirrorChunk({
474
+ type: "message-metadata",
475
+ messageMetadata: {
476
+ createdAt: new Date().toISOString(),
477
+ },
478
+ });
479
+ return "continue";
480
+ }
481
+
482
+ input.logger?.warn?.("Fork stream idle timeout triggered", {
483
+ conversationId: input.conversationId,
484
+ description: input.description,
485
+ watchdogPhase: watchdogState.phase ?? lastWatchdogPhase,
486
+ softIdleHeartbeatCount,
487
+ timeoutMs: watchdogState.timeoutMs,
488
+ toolCallsCompleted: input.toolResults.length,
489
+ });
490
+ input.abortForkStream(new DOMException("Child fork stream idle timeout", "AbortError"));
491
+ return undefined;
492
+ },
493
+ })
494
+ ) {
495
+ softIdleHeartbeatCount = 0;
496
+ throwIfChildRunAborted(input.abortSignal);
497
+
498
+ await input.tracePart?.({
499
+ conversationId: input.conversationId,
500
+ parentRunId: input.parentRunId,
501
+ partType: part.type,
502
+ });
503
+ input.logger?.debug?.("Child fork stream part received", {
504
+ conversationId: input.conversationId,
505
+ runId: input.parentRunId,
506
+ partType: part.type,
507
+ });
508
+
509
+ ({ activeToolCallId, finalText, shouldSeparateNextTextBlock } =
510
+ await handleHostedChildForkStreamPart({
511
+ part,
512
+ conversationId: input.conversationId,
513
+ description: input.description,
514
+ durableMessageId: input.durableMessageId,
515
+ durableReasoningMessageId: input.durableReasoningMessageId,
516
+ durableMirrorState: input.durableMirrorState,
517
+ appendDurableMirrorChunk: input.appendDurableMirrorChunk,
518
+ closeDurableMirrorReasoning: input.closeDurableMirrorReasoning,
519
+ closeDurableMirrorText: input.closeDurableMirrorText,
520
+ pendingToolLifecycle: input.pendingToolLifecycle,
521
+ toolCalls: input.toolCalls,
522
+ toolResults: input.toolResults,
523
+ state: {
524
+ activeToolCallId,
525
+ finalText,
526
+ shouldSeparateNextTextBlock,
527
+ },
528
+ logger: input.logger,
529
+ }));
530
+ input.streamState.finalText = finalText;
531
+
532
+ if (input.durableRunMirror) {
533
+ const mirroredChunks = mapHostedStreamPartToChatUiChunks(
534
+ toMirroredHostedStreamPart(part, {
535
+ messageId: input.durableMessageId,
536
+ reasoningMessageId: input.durableReasoningMessageId,
537
+ }),
538
+ {
539
+ messageId: input.durableMessageId,
540
+ reasoningMessageId: input.durableReasoningMessageId,
541
+ onError: formatChildRunStreamPartError,
542
+ },
543
+ );
544
+
545
+ for (const mirroredChunk of mirroredChunks) {
546
+ if (isAlreadyMirroredHostedChunk(part.type, mirroredChunk.type)) {
547
+ continue;
548
+ }
549
+
550
+ await input.appendDurableMirrorChunk(mirroredChunk);
551
+ }
552
+ }
553
+ }
554
+
555
+ await input.closeDurableMirrorReasoning();
556
+ await input.closeDurableMirrorText();
557
+ await input.pendingToolLifecycle.closePendingToolCalls({ kind: "ended" });
558
+ throwIfChildRunAborted(input.abortSignal);
559
+ input.streamState.finalText = finalText;
560
+
561
+ return finalizeHostedChildForkCompletion({
562
+ streamResult: input.streamResult,
563
+ finalText,
564
+ description: input.description,
565
+ kind: input.kind,
566
+ maxSteps: input.maxSteps,
567
+ toolCalls: input.toolCalls,
568
+ toolResults: input.toolResults,
569
+ usage: input.usage,
570
+ startTime: input.startTime,
571
+ durableMessageId: input.durableMessageId,
572
+ durableMirrorHasEmittedProgress: input.durableMirrorHasEmittedProgress(),
573
+ appendDurableMirrorChunk: input.appendDurableMirrorChunk,
574
+ finalizationTimeoutMs: input.finalizationTimeoutMs,
575
+ onSettled: input.onSettled,
576
+ logger: input.logger,
577
+ writeLog: input.writeLog,
578
+ });
579
+ }
@@ -257,6 +257,16 @@ export {
257
257
  resolveForkStepResponse,
258
258
  runFrameworkForkStep,
259
259
  } from "./fork-runtime-stream.js";
260
+ export {
261
+ executeHostedChildForkStream,
262
+ type ExecuteHostedChildForkStreamInput,
263
+ finalizeHostedChildForkCompletion,
264
+ handleHostedChildForkStreamPart,
265
+ type HostedChildForkPendingToolLifecycle,
266
+ type HostedChildForkStreamHandlingState,
267
+ type HostedChildForkStreamLogger,
268
+ type HostedChildForkStreamTraceInput,
269
+ } from "./hosted-child-fork-stream-execution.js";
260
270
  export {
261
271
  type ConversationRunContext,
262
272
  createConversationRunContext,
@@ -153,7 +153,7 @@ function buildOrderedFallbackPartsFromContentMessages(messages: unknown[]): Chat
153
153
 
154
154
  if (existingIndex >= 0) {
155
155
  const existingPart = orderedParts[existingIndex];
156
- if (!isToolUiPart(existingPart)) {
156
+ if (existingPart === undefined || !isToolUiPart(existingPart)) {
157
157
  continue;
158
158
  }
159
159
 
@@ -245,7 +245,7 @@ function buildOrderedFallbackPartsFromUiMessages(messages: unknown[]): ChatPart[
245
245
  }
246
246
 
247
247
  const existingPart = orderedParts[existingIndex];
248
- if (!isToolUiPart(existingPart)) {
248
+ if (existingPart === undefined || !isToolUiPart(existingPart)) {
249
249
  continue;
250
250
  }
251
251
 
@@ -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.326";
3
+ export const VERSION = "0.1.327";