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.
- package/esm/deno.js +1 -1
- package/esm/src/agent/hosted-child-fork-stream-execution.d.ts +130 -0
- package/esm/src/agent/hosted-child-fork-stream-execution.d.ts.map +1 -0
- package/esm/src/agent/hosted-child-fork-stream-execution.js +391 -0
- package/esm/src/agent/index.d.ts +1 -0
- package/esm/src/agent/index.d.ts.map +1 -1
- package/esm/src/agent/index.js +1 -0
- package/esm/src/chat/final-step-fallback.js +2 -2
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/deps/esm.sh/@types/react-dom@19.2.3/client.d.ts +1 -1
- package/src/deps/esm.sh/@types/{react@19.2.3 → react@19.2.14}/global.d.ts +1 -0
- package/src/deps/esm.sh/@types/{react@19.2.3 → react@19.2.14}/index.d.ts +93 -24
- package/src/deps/esm.sh/react-dom@19.2.4/client.d.ts +1 -1
- package/src/src/agent/hosted-child-fork-stream-execution.ts +579 -0
- package/src/src/agent/index.ts +10 -0
- package/src/src/chat/final-step-fallback.ts +2 -2
- package/src/src/utils/version-constant.ts +1 -1
|
@@ -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
|
+
}
|
package/src/src/agent/index.ts
CHANGED
|
@@ -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
|
|