@botbotgo/agent-harness 0.0.326 → 0.0.328
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/dist/cli/chat-stream.js +33 -27
- package/dist/cli/main.js +30 -3
- package/dist/contracts/runtime-requests.d.ts +1 -2
- package/dist/contracts/runtime-scheduling.d.ts +1 -1
- package/dist/flow/flow-graph-upstream.js +3 -7
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/projections/request-events.js +0 -1
- package/dist/resource/isolation.js +51 -10
- package/dist/resources/toolkit.mjs +183 -0
- package/dist/resources/tools/cancel_request.mjs +1 -1
- package/dist/resources/tools/fetch_url.mjs +1 -1
- package/dist/resources/tools/http_request.mjs +1 -1
- package/dist/resources/tools/inspect_approvals.mjs +1 -1
- package/dist/resources/tools/inspect_artifacts.mjs +1 -1
- package/dist/resources/tools/inspect_events.mjs +1 -1
- package/dist/resources/tools/inspect_requests.mjs +1 -1
- package/dist/resources/tools/inspect_sessions.mjs +1 -1
- package/dist/resources/tools/list_files.mjs +1 -1
- package/dist/resources/tools/read_artifact.mjs +1 -1
- package/dist/resources/tools/request_approval.mjs +1 -1
- package/dist/resources/tools/run_command.mjs +1 -1
- package/dist/resources/tools/schedule_task.mjs +1 -1
- package/dist/resources/tools/search_files.mjs +1 -1
- package/dist/resources/tools/send_message.mjs +1 -1
- package/dist/runtime/adapter/compat/deepagent-compat.d.ts +0 -9
- package/dist/runtime/adapter/compat/deepagent-compat.js +0 -22
- package/dist/runtime/adapter/flow/stream-runtime.d.ts +4 -0
- package/dist/runtime/adapter/flow/stream-runtime.js +239 -8
- package/dist/runtime/adapter/local-tool-invocation.js +53 -0
- package/dist/runtime/adapter/middleware-assembly.js +174 -29
- package/dist/runtime/adapter/runtime-adapter-support.js +1 -2
- package/dist/runtime/adapter/stream-event-projection.d.ts +17 -0
- package/dist/runtime/adapter/stream-event-projection.js +217 -4
- package/dist/runtime/adapter/tool/builtin-middleware-tools.d.ts +0 -3
- package/dist/runtime/adapter/tool/builtin-middleware-tools.js +37 -17
- package/dist/runtime/adapter/tool/resolved-tool.js +29 -3
- package/dist/runtime/agent-runtime-adapter.d.ts +3 -3
- package/dist/runtime/agent-runtime-adapter.js +12 -33
- package/dist/runtime/agent-runtime-assembly.d.ts +3 -21
- package/dist/runtime/agent-runtime-assembly.js +4 -56
- package/dist/runtime/harness/run/inspection.js +21 -5
- package/dist/runtime/harness/run/run-operations.js +2 -1
- package/dist/runtime/harness/run/stream-run.d.ts +3 -1
- package/dist/runtime/harness/run/stream-run.js +206 -30
- package/dist/runtime/harness.js +3 -0
- package/dist/runtime/parsing/output-content.js +11 -4
- package/dist/runtime/parsing/output-recovery.d.ts +3 -0
- package/dist/runtime/parsing/output-recovery.js +57 -11
- package/dist/runtime/parsing/output-tool-args.d.ts +4 -0
- package/dist/runtime/parsing/output-tool-args.js +122 -0
- package/dist/runtime/parsing/stream-event-parsing.js +37 -3
- package/dist/runtime/support/harness-support.d.ts +1 -0
- package/dist/runtime/support/harness-support.js +44 -2
- package/dist/tools.js +34 -4
- package/package.json +8 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HumanMessage } from "@langchain/core/messages";
|
|
1
|
+
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
|
|
2
2
|
import { createMemoryMiddleware, createPatchToolCallsMiddleware, createSkillsMiddleware, createSubAgentMiddleware, createSummarizationMiddleware, StateBackend, } from "deepagents";
|
|
3
3
|
import { createAgent, humanInTheLoopMiddleware } from "langchain";
|
|
4
4
|
import { createBuiltinMiddlewareTools } from "./tool/builtin-middleware-tools.js";
|
|
@@ -7,9 +7,98 @@ import { extractToolFallbackContext, extractVisibleOutput } from "../parsing/out
|
|
|
7
7
|
import { isRecord } from "../../utils/object.js";
|
|
8
8
|
import { resolveDeclaredMiddleware } from "./tool/declared-middleware.js";
|
|
9
9
|
import { UPSTREAM_SESSION_CONFIG_KEY } from "./upstream-configurable-keys.js";
|
|
10
|
-
import { bindingHasLangChainSubagentSupport, bindingHasMiddlewareKind, getBindingExecutionKind, getBindingGeneralPurposeAgent, getBindingInterruptCompatibilityRules, getBindingMiddlewareConfigs, getBindingMemorySources, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSkills, getBindingSubagents, getBindingTaskDescription, isDeepAgentBinding, isLangChainBinding, } from "../support/compiled-binding.js";
|
|
11
|
-
import {
|
|
10
|
+
import { bindingHasLangChainSubagentSupport, bindingHasMiddlewareKind, getBindingExecutionKind, getBindingGeneralPurposeAgent, getBindingDeepAgentSubagents, getBindingInterruptCompatibilityRules, getBindingMiddlewareConfigs, getBindingMemorySources, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSkills, getBindingSubagents, getBindingTaskDescription, isDeepAgentBinding, isLangChainBinding, } from "../support/compiled-binding.js";
|
|
11
|
+
import { materializeDeepAgentSkillSourcePaths } from "./compat/deepagent-compat.js";
|
|
12
12
|
import { DEFAULT_SUBAGENT_PROMPT } from "../prompts/runtime-prompts.js";
|
|
13
|
+
import { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION } from "../prompts/runtime-prompts.js";
|
|
14
|
+
import { createStreamEventProjectionState, projectRuntimeStreamEvent } from "./stream-event-projection.js";
|
|
15
|
+
const EMPTY_TOOL_NAME_MAPPING = {
|
|
16
|
+
originalToModelFacing: new Map(),
|
|
17
|
+
modelFacingToOriginal: new Map(),
|
|
18
|
+
};
|
|
19
|
+
function readPlanStateSummaryCounts(summary) {
|
|
20
|
+
if (typeof summary !== "object" || summary === null) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const typed = summary;
|
|
24
|
+
const hasAny = typeof typed.pending === "number"
|
|
25
|
+
|| typeof typed.inProgress === "number";
|
|
26
|
+
if (!hasAny) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
pending: typeof typed.pending === "number" ? typed.pending : 0,
|
|
31
|
+
inProgress: typeof typed.inProgress === "number" ? typed.inProgress : 0,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function hasIncompletePlanTodos(value) {
|
|
35
|
+
if (!Array.isArray(value)) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return value.some((item) => {
|
|
39
|
+
if (typeof item !== "object" || item === null) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const status = item.status;
|
|
43
|
+
return status === "pending" || status === "in_progress";
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function hasIncompletePlanStateInValue(value) {
|
|
47
|
+
if (Array.isArray(value)) {
|
|
48
|
+
return value.some((item) => hasIncompletePlanStateInValue(item));
|
|
49
|
+
}
|
|
50
|
+
if (typeof value !== "object" || value === null) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const typed = value;
|
|
54
|
+
const summaryCounts = readPlanStateSummaryCounts(typed.summary);
|
|
55
|
+
if (summaryCounts) {
|
|
56
|
+
return summaryCounts.pending > 0 || summaryCounts.inProgress > 0;
|
|
57
|
+
}
|
|
58
|
+
const todoCompleteness = hasIncompletePlanTodos(typed.todos);
|
|
59
|
+
if (todoCompleteness !== null) {
|
|
60
|
+
return todoCompleteness;
|
|
61
|
+
}
|
|
62
|
+
const nestedCandidates = [
|
|
63
|
+
typed.summary,
|
|
64
|
+
typed.output,
|
|
65
|
+
typed.content,
|
|
66
|
+
typed.update,
|
|
67
|
+
typed.data,
|
|
68
|
+
typed.messages,
|
|
69
|
+
];
|
|
70
|
+
return nestedCandidates.some((candidate) => hasIncompletePlanStateInValue(candidate));
|
|
71
|
+
}
|
|
72
|
+
function hasUnresolvedDelegatedExecution(state) {
|
|
73
|
+
return state.hasIncompletePlanState || state.openTaskDelegations > 0;
|
|
74
|
+
}
|
|
75
|
+
function hasMissingDelegatedToolExecutionEvidence(state, subagentHasTools) {
|
|
76
|
+
return subagentHasTools && !state.emittedToolResult && !state.emittedToolError;
|
|
77
|
+
}
|
|
78
|
+
function formatDelegatedExecutionBlocker(state) {
|
|
79
|
+
const summary = state.emittedOutput.trim();
|
|
80
|
+
if (summary) {
|
|
81
|
+
return summary;
|
|
82
|
+
}
|
|
83
|
+
if (state.emittedToolError) {
|
|
84
|
+
return "Delegated investigation encountered a tool failure before the plan completed.";
|
|
85
|
+
}
|
|
86
|
+
if (state.openTaskDelegations > 0) {
|
|
87
|
+
return "Delegated investigation did not finish before control returned to the parent agent.";
|
|
88
|
+
}
|
|
89
|
+
return "Delegated investigation ended before the plan was completed.";
|
|
90
|
+
}
|
|
91
|
+
function requiresDelegatedExecutionRecovery(state) {
|
|
92
|
+
return hasUnresolvedDelegatedExecution(state) || (state.emittedToolResult && !state.emittedOutput.trim());
|
|
93
|
+
}
|
|
94
|
+
const DELEGATED_FAILURE_PLAN_RECONCILIATION_INSTRUCTION = [
|
|
95
|
+
"Your previous attempt ended with a tool failure while the todo board still had unfinished work.",
|
|
96
|
+
"Do not continue broad investigation from here.",
|
|
97
|
+
"If the failed command had malformed arguments you can correct locally, retry that same command once.",
|
|
98
|
+
"Otherwise, if a todo board already exists, call write_todos again and keep only the tasks that were actually completed in this session.",
|
|
99
|
+
"Remove the unfinished tasks that cannot proceed until the blocker is resolved.",
|
|
100
|
+
"Then return a concise blocker report.",
|
|
101
|
+
].join(" ");
|
|
13
102
|
export function buildBuiltinTaskSubagentMiddleware(input) {
|
|
14
103
|
const { selectedSubagent, builtinBackend, summarizationModel } = input;
|
|
15
104
|
const defaultSubagentMiddleware = [
|
|
@@ -57,13 +146,6 @@ function buildLangChainContextMiddleware(params) {
|
|
|
57
146
|
}
|
|
58
147
|
return middleware;
|
|
59
148
|
}
|
|
60
|
-
function resolveLangChainDelegationCompatibility(params) {
|
|
61
|
-
return applyDeepAgentDelegationPromptCompatibility(params.model, {
|
|
62
|
-
subagents: params.subagents,
|
|
63
|
-
generalPurposeAgent: params.generalPurposeAgent,
|
|
64
|
-
taskDescription: params.taskDescription,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
149
|
export function planLangChainRuntimeExtensions(binding) {
|
|
68
150
|
const primaryModel = getBindingPrimaryModel(binding);
|
|
69
151
|
if (!isLangChainBinding(binding) || !primaryModel) {
|
|
@@ -71,12 +153,6 @@ export function planLangChainRuntimeExtensions(binding) {
|
|
|
71
153
|
}
|
|
72
154
|
const skills = getBindingSkills(binding);
|
|
73
155
|
const memory = getBindingMemorySources(binding);
|
|
74
|
-
const delegationCompatibility = resolveLangChainDelegationCompatibility({
|
|
75
|
-
model: primaryModel,
|
|
76
|
-
subagents: getBindingSubagents(binding),
|
|
77
|
-
generalPurposeAgent: getBindingGeneralPurposeAgent(binding),
|
|
78
|
-
taskDescription: getBindingTaskDescription(binding),
|
|
79
|
-
});
|
|
80
156
|
return {
|
|
81
157
|
includePatchToolCalls: !bindingHasMiddlewareKind(binding, "patchToolCalls"),
|
|
82
158
|
includeAutomaticSummarization: !bindingHasMiddlewareKind(binding, "summarization"),
|
|
@@ -86,9 +162,9 @@ export function planLangChainRuntimeExtensions(binding) {
|
|
|
86
162
|
},
|
|
87
163
|
delegation: bindingHasLangChainSubagentSupport(binding)
|
|
88
164
|
? {
|
|
89
|
-
subagents:
|
|
90
|
-
generalPurposeAgent:
|
|
91
|
-
taskDescription:
|
|
165
|
+
subagents: getBindingSubagents(binding),
|
|
166
|
+
generalPurposeAgent: getBindingGeneralPurposeAgent(binding),
|
|
167
|
+
taskDescription: getBindingTaskDescription(binding),
|
|
92
168
|
interruptOn: getBindingInterruptCompatibilityRules(binding),
|
|
93
169
|
}
|
|
94
170
|
: undefined,
|
|
@@ -142,13 +218,18 @@ export async function invokeBuiltinTaskTool(input) {
|
|
|
142
218
|
}
|
|
143
219
|
const primaryModel = getBindingPrimaryModel(input.binding);
|
|
144
220
|
const primaryTools = getBindingPrimaryTools(input.binding);
|
|
145
|
-
const compiledSubagents =
|
|
221
|
+
const compiledSubagents = getBindingDeepAgentSubagents(input.binding)
|
|
222
|
+
.filter((subagent) => !("graphId" in subagent));
|
|
146
223
|
if (!primaryModel) {
|
|
147
224
|
throw new Error(`Agent ${input.binding.agent.id} has no deepagent params`);
|
|
148
225
|
}
|
|
149
226
|
const typedInput = isRecord(input.toolInput) ? input.toolInput : {};
|
|
150
|
-
const description = typeof typedInput.description === "string"
|
|
151
|
-
|
|
227
|
+
const description = typeof typedInput.description === "string"
|
|
228
|
+
? typedInput.description
|
|
229
|
+
: "";
|
|
230
|
+
const subagentType = typeof typedInput.subagent_type === "string"
|
|
231
|
+
? typedInput.subagent_type
|
|
232
|
+
: "";
|
|
152
233
|
const builtinBackend = input.resolveBuiltinMiddlewareBackend(input.binding, input.options);
|
|
153
234
|
const resolvedSubagents = await input.resolveSubagents(compiledSubagents, input.binding);
|
|
154
235
|
const selectedSubagent = resolvedSubagents.find((subagent) => subagent.name === subagentType);
|
|
@@ -163,16 +244,82 @@ export async function invokeBuiltinTaskTool(input) {
|
|
|
163
244
|
builtinBackend,
|
|
164
245
|
summarizationModel,
|
|
165
246
|
});
|
|
247
|
+
const resolvedSubagentTools = selectedSubagent.tools ?? input.resolveTools(primaryTools, input.binding);
|
|
248
|
+
const subagentHasTools = (resolvedSubagentTools?.length ?? 0) > 0;
|
|
166
249
|
const runnable = createAgent({
|
|
167
250
|
model: (selectedSubagent.model ?? resolvedHostModel),
|
|
168
|
-
tools:
|
|
251
|
+
tools: resolvedSubagentTools,
|
|
169
252
|
systemPrompt: selectedSubagent.systemPrompt ?? DEFAULT_SUBAGENT_PROMPT,
|
|
170
253
|
middleware: middleware,
|
|
171
254
|
responseFormat: selectedSubagent.responseFormat,
|
|
172
255
|
name: selectedSubagent.name,
|
|
173
256
|
description: selectedSubagent.description,
|
|
174
257
|
});
|
|
175
|
-
const
|
|
258
|
+
const invokeConfig = {
|
|
259
|
+
configurable: { [UPSTREAM_SESSION_CONFIG_KEY]: `${input.binding.agent.id}:builtin-task` },
|
|
260
|
+
...(input.options?.context ? { context: input.options.context } : {}),
|
|
261
|
+
};
|
|
262
|
+
const buildMessages = (recoveryInstruction) => ({
|
|
263
|
+
messages: [
|
|
264
|
+
...(recoveryInstruction ? [new SystemMessage({ content: recoveryInstruction })] : []),
|
|
265
|
+
new HumanMessage({ content: description }),
|
|
266
|
+
],
|
|
267
|
+
});
|
|
268
|
+
if (typeof runnable.streamEvents === "function") {
|
|
269
|
+
const runWithStreamInspection = async (recoveryInstruction) => {
|
|
270
|
+
const projectionState = createStreamEventProjectionState();
|
|
271
|
+
const events = await runnable.streamEvents(buildMessages(recoveryInstruction), invokeConfig);
|
|
272
|
+
for await (const event of events) {
|
|
273
|
+
projectRuntimeStreamEvent({
|
|
274
|
+
event,
|
|
275
|
+
allowVisibleStreamDeltas: false,
|
|
276
|
+
includeStateStreamOutput: false,
|
|
277
|
+
rootAgentId: input.binding.agent.id,
|
|
278
|
+
countConfiguredToolsForAgentId: (agentId) => agentId === selectedSubagent.name ? resolvedSubagentTools.length : 0,
|
|
279
|
+
toolNameMapping: EMPTY_TOOL_NAME_MAPPING,
|
|
280
|
+
primaryTools: [],
|
|
281
|
+
state: projectionState,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
return projectionState;
|
|
285
|
+
};
|
|
286
|
+
let projectionState = await runWithStreamInspection();
|
|
287
|
+
if (requiresDelegatedExecutionRecovery(projectionState)) {
|
|
288
|
+
const recoveryInstruction = projectionState.hasIncompletePlanState && projectionState.emittedToolError
|
|
289
|
+
? `${AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION}\n\n${DELEGATED_FAILURE_PLAN_RECONCILIATION_INSTRUCTION}`
|
|
290
|
+
: AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION;
|
|
291
|
+
projectionState = await runWithStreamInspection(recoveryInstruction);
|
|
292
|
+
}
|
|
293
|
+
if (requiresDelegatedExecutionRecovery(projectionState)) {
|
|
294
|
+
throw new Error(formatDelegatedExecutionBlocker(projectionState));
|
|
295
|
+
}
|
|
296
|
+
if (hasMissingDelegatedToolExecutionEvidence(projectionState, subagentHasTools)) {
|
|
297
|
+
throw new Error("Delegated investigation ended without any real tool execution evidence.");
|
|
298
|
+
}
|
|
299
|
+
if (projectionState.emittedToolError) {
|
|
300
|
+
const blockerMessage = projectionState.emittedOutput.trim()
|
|
301
|
+
|| formatDelegatedExecutionBlocker(projectionState);
|
|
302
|
+
if (hasUnresolvedDelegatedExecution(projectionState) || !projectionState.emittedSuccessfulToolResult) {
|
|
303
|
+
throw new Error(blockerMessage);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (projectionState.emittedOutput.trim()) {
|
|
307
|
+
return projectionState.emittedOutput.trim();
|
|
308
|
+
}
|
|
309
|
+
if (projectionState.emittedToolResult) {
|
|
310
|
+
throw new Error("Delegated investigation performed tool work but did not return surfaced findings.");
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
let result = await runnable.invoke(buildMessages(), invokeConfig);
|
|
314
|
+
if (hasIncompletePlanStateInValue(result)) {
|
|
315
|
+
result = await runnable.invoke(buildMessages(AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION), invokeConfig);
|
|
316
|
+
}
|
|
317
|
+
if (hasIncompletePlanStateInValue(result)) {
|
|
318
|
+
throw new Error(extractVisibleOutput(result) || extractToolFallbackContext(result) || "Delegated investigation ended before the plan was completed.");
|
|
319
|
+
}
|
|
320
|
+
if (subagentHasTools) {
|
|
321
|
+
throw new Error("Delegated investigation ended without any real tool execution evidence.");
|
|
322
|
+
}
|
|
176
323
|
const visibleOutput = extractVisibleOutput(result);
|
|
177
324
|
const fallbackOutput = extractToolFallbackContext(result);
|
|
178
325
|
return visibleOutput || fallbackOutput || JSON.stringify(result);
|
|
@@ -180,12 +327,10 @@ export async function invokeBuiltinTaskTool(input) {
|
|
|
180
327
|
export async function resolveBuiltinMiddlewareTools(input) {
|
|
181
328
|
const backend = input.resolveBuiltinMiddlewareBackend(input.binding, input.options);
|
|
182
329
|
return createBuiltinMiddlewareTools(backend, {
|
|
183
|
-
includeTaskTool:
|
|
330
|
+
includeTaskTool: false,
|
|
184
331
|
workspaceRoot: input.binding.harnessRuntime.workspaceRoot,
|
|
185
332
|
toolRuntimeContext: input.options?.toolRuntimeContext,
|
|
186
|
-
invokeTaskTool:
|
|
187
|
-
? async (toolInput) => input.invokeBuiltinTaskTool(input.binding, toolInput, input.options)
|
|
188
|
-
: undefined,
|
|
333
|
+
invokeTaskTool: undefined,
|
|
189
334
|
});
|
|
190
335
|
}
|
|
191
336
|
export async function materializeAutomaticSummarizationMiddleware(input) {
|
|
@@ -214,7 +359,7 @@ export async function materializeLangChainRuntimeMiddleware(input) {
|
|
|
214
359
|
memory: input.plan.context.memory,
|
|
215
360
|
resolveFilesystemBackend: input.resolveFilesystemBackend,
|
|
216
361
|
}));
|
|
217
|
-
if (input.plan.delegation) {
|
|
362
|
+
if (input.plan.delegation && !isDeepAgentBinding(input.binding)) {
|
|
218
363
|
runtimeMiddleware.push(createSubAgentMiddleware({
|
|
219
364
|
defaultModel: (await input.resolveModel(primaryModel)),
|
|
220
365
|
defaultTools: input.resolveTools(primaryTools, input.binding),
|
|
@@ -37,7 +37,6 @@ export function summarizeBuiltinWriteTodosArgs(args) {
|
|
|
37
37
|
completed: items.filter((item) => item.status === "completed").length,
|
|
38
38
|
failed: items.filter((item) => item.status === "failed").length,
|
|
39
39
|
cancelled: items.filter((item) => item.status === "cancelled").length,
|
|
40
|
-
blocked: items.filter((item) => item.status === "blocked").length,
|
|
41
40
|
};
|
|
42
41
|
return {
|
|
43
42
|
items,
|
|
@@ -56,7 +55,7 @@ export function formatBuiltinTodoSnapshot(snapshot) {
|
|
|
56
55
|
return "No todos tracked.";
|
|
57
56
|
}
|
|
58
57
|
const lines = [
|
|
59
|
-
`Tracked ${snapshot.summary.total} todo item(s): ${snapshot.summary.pending + snapshot.summary.inProgress
|
|
58
|
+
`Tracked ${snapshot.summary.total} todo item(s): ${snapshot.summary.pending + snapshot.summary.inProgress} pending, ${snapshot.summary.completed} completed.`,
|
|
60
59
|
...snapshot.items.map((item, index) => `${index + 1}. [${item.status}] ${item.content}`),
|
|
61
60
|
];
|
|
62
61
|
return truncateLines(lines);
|
|
@@ -5,6 +5,21 @@ export type StreamEventProjectionState = {
|
|
|
5
5
|
emittedOutput: string;
|
|
6
6
|
emittedToolError: boolean;
|
|
7
7
|
emittedToolResult: boolean;
|
|
8
|
+
emittedSuccessfulToolResult: boolean;
|
|
9
|
+
emittedSuccessfulTaskResult: boolean;
|
|
10
|
+
emittedPlaceholderTaskResult: boolean;
|
|
11
|
+
hasFailedTaskDelegation: boolean;
|
|
12
|
+
emittedNonTodoToolResult: boolean;
|
|
13
|
+
emittedSuccessfulNonTodoToolResult: boolean;
|
|
14
|
+
sawDelegatedAgentWithConfiguredTools: boolean;
|
|
15
|
+
emittedDelegatedExecutionToolResult: boolean;
|
|
16
|
+
emittedSuccessfulDelegatedExecutionToolResult: boolean;
|
|
17
|
+
emittedDelegatedTerminalOutput: boolean;
|
|
18
|
+
sawPlanState: boolean;
|
|
19
|
+
hasIncompletePlanState: boolean;
|
|
20
|
+
openTaskDelegations: number;
|
|
21
|
+
openToolCapableTaskDelegations: number;
|
|
22
|
+
taskDelegationHasToolsStack: boolean[];
|
|
8
23
|
seenTerminalOutputs: Set<string>;
|
|
9
24
|
};
|
|
10
25
|
export declare function createStreamEventProjectionState(): StreamEventProjectionState;
|
|
@@ -12,6 +27,8 @@ export declare function projectRuntimeStreamEvent(params: {
|
|
|
12
27
|
event: unknown;
|
|
13
28
|
allowVisibleStreamDeltas: boolean;
|
|
14
29
|
includeStateStreamOutput: boolean;
|
|
30
|
+
rootAgentId?: string;
|
|
31
|
+
countConfiguredToolsForAgentId?: (agentId: string) => number;
|
|
15
32
|
toolNameMapping: ToolNameMapping;
|
|
16
33
|
primaryTools: CompiledTool[];
|
|
17
34
|
state: StreamEventProjectionState;
|
|
@@ -6,15 +6,190 @@ export function createStreamEventProjectionState() {
|
|
|
6
6
|
emittedOutput: "",
|
|
7
7
|
emittedToolError: false,
|
|
8
8
|
emittedToolResult: false,
|
|
9
|
+
emittedSuccessfulToolResult: false,
|
|
10
|
+
emittedSuccessfulTaskResult: false,
|
|
11
|
+
emittedPlaceholderTaskResult: false,
|
|
12
|
+
hasFailedTaskDelegation: false,
|
|
13
|
+
emittedNonTodoToolResult: false,
|
|
14
|
+
emittedSuccessfulNonTodoToolResult: false,
|
|
15
|
+
sawDelegatedAgentWithConfiguredTools: false,
|
|
16
|
+
emittedDelegatedExecutionToolResult: false,
|
|
17
|
+
emittedSuccessfulDelegatedExecutionToolResult: false,
|
|
18
|
+
emittedDelegatedTerminalOutput: false,
|
|
19
|
+
sawPlanState: false,
|
|
20
|
+
hasIncompletePlanState: false,
|
|
21
|
+
openTaskDelegations: 0,
|
|
22
|
+
openToolCapableTaskDelegations: 0,
|
|
23
|
+
taskDelegationHasToolsStack: [],
|
|
9
24
|
seenTerminalOutputs: new Set(),
|
|
10
25
|
};
|
|
11
26
|
}
|
|
27
|
+
function readSummaryCounts(summary) {
|
|
28
|
+
if (typeof summary !== "object" || summary === null) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const typed = summary;
|
|
32
|
+
const hasAnyCountField = typeof typed.pending === "number"
|
|
33
|
+
|| typeof typed.inProgress === "number";
|
|
34
|
+
if (!hasAnyCountField) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
pending: typeof typed.pending === "number" ? typed.pending : 0,
|
|
39
|
+
inProgress: typeof typed.inProgress === "number" ? typed.inProgress : 0,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function hasIncompleteTodosArray(value) {
|
|
43
|
+
if (!Array.isArray(value)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return value.some((item) => {
|
|
47
|
+
if (typeof item !== "object" || item === null) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const status = item.status;
|
|
51
|
+
return status === "pending" || status === "in_progress";
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function getPlanStateCompleteness(value) {
|
|
55
|
+
if (typeof value !== "object" || value === null) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const typed = value;
|
|
59
|
+
const summaryCounts = readSummaryCounts(typed.summary);
|
|
60
|
+
if (summaryCounts) {
|
|
61
|
+
return summaryCounts.pending > 0 || summaryCounts.inProgress > 0;
|
|
62
|
+
}
|
|
63
|
+
if (typeof typed.summary === "object" && typed.summary !== null) {
|
|
64
|
+
const nestedSummary = getPlanStateCompleteness(typed.summary);
|
|
65
|
+
if (nestedSummary !== null) {
|
|
66
|
+
return nestedSummary;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const directTodos = hasIncompleteTodosArray(typed.todos);
|
|
70
|
+
if (directTodos !== null) {
|
|
71
|
+
return directTodos;
|
|
72
|
+
}
|
|
73
|
+
if (typeof typed.update === "object" && typed.update !== null) {
|
|
74
|
+
const nestedTodos = hasIncompleteTodosArray(typed.update.todos);
|
|
75
|
+
if (nestedTodos !== null) {
|
|
76
|
+
return nestedTodos;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (typeof typed.output === "object" && typed.output !== null) {
|
|
80
|
+
const nestedOutput = getPlanStateCompleteness(typed.output);
|
|
81
|
+
if (nestedOutput !== null) {
|
|
82
|
+
return nestedOutput;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (typeof typed.data === "object" && typed.data !== null) {
|
|
86
|
+
const nestedData = getPlanStateCompleteness(typed.data);
|
|
87
|
+
if (nestedData !== null) {
|
|
88
|
+
return nestedData;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
function parseMaybeJsonString(value) {
|
|
94
|
+
const trimmed = value.trim();
|
|
95
|
+
if (!trimmed || (!trimmed.startsWith("{") && !trimmed.startsWith("["))) {
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
return JSON.parse(trimmed);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function unwrapPossibleToolInput(value) {
|
|
106
|
+
if (typeof value === "string") {
|
|
107
|
+
return parseMaybeJsonString(value);
|
|
108
|
+
}
|
|
109
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
const typed = value;
|
|
113
|
+
if (typed.args !== undefined) {
|
|
114
|
+
return unwrapPossibleToolInput(typed.args);
|
|
115
|
+
}
|
|
116
|
+
if (typed.input !== undefined) {
|
|
117
|
+
return unwrapPossibleToolInput(typed.input);
|
|
118
|
+
}
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
function readTaskSubagentType(value) {
|
|
122
|
+
const unwrapped = unwrapPossibleToolInput(value);
|
|
123
|
+
if (typeof unwrapped !== "object" || unwrapped === null || Array.isArray(unwrapped)) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const typed = unwrapped;
|
|
127
|
+
return typeof typed.subagent_type === "string" && typed.subagent_type.trim().length > 0
|
|
128
|
+
? typed.subagent_type.trim()
|
|
129
|
+
: null;
|
|
130
|
+
}
|
|
131
|
+
function isUpstreamPlaceholderTaskResult(value) {
|
|
132
|
+
if (typeof value === "string") {
|
|
133
|
+
return value.trim() === "Task completed";
|
|
134
|
+
}
|
|
135
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
const typed = value;
|
|
139
|
+
const messages = Array.isArray(typed.update?.messages) ? typed.update.messages : [];
|
|
140
|
+
if (messages.length !== 1) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
const message = messages[0];
|
|
144
|
+
return typed.lg_name === "Command"
|
|
145
|
+
&& typed.lc_direct_tool_output === true
|
|
146
|
+
&& message?.name === "task"
|
|
147
|
+
&& message?.type === "tool"
|
|
148
|
+
&& typeof message?.tool_call_id === "string"
|
|
149
|
+
&& message?.content === "Task completed";
|
|
150
|
+
}
|
|
151
|
+
function updateDelegationState(state, event, countConfiguredToolsForAgentId) {
|
|
152
|
+
if (typeof event !== "object" || event === null) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const typed = event;
|
|
156
|
+
const eventName = typeof typed.event === "string" ? typed.event : "";
|
|
157
|
+
const toolName = typeof typed.name === "string" ? typed.name : "";
|
|
158
|
+
const runType = typeof typed.run_type === "string" ? typed.run_type : "";
|
|
159
|
+
const isTaskStart = toolName === "task" && (eventName === "on_tool_start" || (eventName === "on_chain_start" && runType === "tool"));
|
|
160
|
+
const isTaskEnd = toolName === "task" && (eventName === "on_tool_end" || (eventName === "on_chain_end" && runType === "tool"));
|
|
161
|
+
const isTaskError = toolName === "task" && (eventName === "on_tool_error" || (eventName === "on_chain_error" && runType === "tool"));
|
|
162
|
+
if (isTaskStart) {
|
|
163
|
+
state.openTaskDelegations += 1;
|
|
164
|
+
const delegatedSubagentType = readTaskSubagentType(typed.data?.input);
|
|
165
|
+
const delegatedTaskHasTools = !!delegatedSubagentType
|
|
166
|
+
&& !!countConfiguredToolsForAgentId
|
|
167
|
+
&& countConfiguredToolsForAgentId(delegatedSubagentType) > 0;
|
|
168
|
+
state.taskDelegationHasToolsStack.push(delegatedTaskHasTools);
|
|
169
|
+
if (delegatedTaskHasTools) {
|
|
170
|
+
state.sawDelegatedAgentWithConfiguredTools = true;
|
|
171
|
+
state.openToolCapableTaskDelegations += 1;
|
|
172
|
+
}
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (isTaskEnd || isTaskError) {
|
|
176
|
+
state.openTaskDelegations = Math.max(0, state.openTaskDelegations - 1);
|
|
177
|
+
const delegatedTaskHadTools = state.taskDelegationHasToolsStack.pop() === true;
|
|
178
|
+
if (delegatedTaskHadTools) {
|
|
179
|
+
state.openToolCapableTaskDelegations = Math.max(0, state.openToolCapableTaskDelegations - 1);
|
|
180
|
+
}
|
|
181
|
+
if (isTaskError) {
|
|
182
|
+
state.hasFailedTaskDelegation = true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
12
186
|
export function projectRuntimeStreamEvent(params) {
|
|
13
|
-
const { event, allowVisibleStreamDeltas, includeStateStreamOutput, toolNameMapping, primaryTools, state, } = params;
|
|
187
|
+
const { event, allowVisibleStreamDeltas, includeStateStreamOutput, rootAgentId, countConfiguredToolsForAgentId, toolNameMapping, primaryTools, state, } = params;
|
|
14
188
|
const chunks = [{
|
|
15
189
|
kind: "upstream-event",
|
|
16
190
|
event: sanitizeRetainedUpstreamEvent(event),
|
|
17
191
|
}];
|
|
192
|
+
updateDelegationState(state, event, countConfiguredToolsForAgentId);
|
|
18
193
|
const interruptPayload = extractInterruptPayload(event);
|
|
19
194
|
if (interruptPayload) {
|
|
20
195
|
chunks.push({ kind: "interrupt", content: interruptPayload });
|
|
@@ -24,7 +199,24 @@ export function projectRuntimeStreamEvent(params) {
|
|
|
24
199
|
if (reasoning) {
|
|
25
200
|
chunks.push({ kind: "reasoning", content: reasoning });
|
|
26
201
|
}
|
|
27
|
-
|
|
202
|
+
const planStateCompleteness = getPlanStateCompleteness(event);
|
|
203
|
+
if (planStateCompleteness !== null) {
|
|
204
|
+
state.sawPlanState = true;
|
|
205
|
+
state.hasIncompletePlanState = planStateCompleteness;
|
|
206
|
+
}
|
|
207
|
+
const eventAgentId = typeof event === "object" && event !== null && typeof event.agentId === "string"
|
|
208
|
+
? event.agentId.trim()
|
|
209
|
+
: "";
|
|
210
|
+
const isDelegatedAgentEvent = !!rootAgentId && !!eventAgentId && eventAgentId !== rootAgentId;
|
|
211
|
+
if (isDelegatedAgentEvent
|
|
212
|
+
&& countConfiguredToolsForAgentId
|
|
213
|
+
&& countConfiguredToolsForAgentId(eventAgentId) > 0) {
|
|
214
|
+
state.sawDelegatedAgentWithConfiguredTools = true;
|
|
215
|
+
}
|
|
216
|
+
const isRootVisibleEvent = !rootAgentId || !eventAgentId || eventAgentId === rootAgentId;
|
|
217
|
+
const allowVisibleContent = isRootVisibleEvent && state.openTaskDelegations === 0;
|
|
218
|
+
const allowStreamedVisibleContent = allowVisibleContent && !state.emittedToolResult && !state.emittedToolError;
|
|
219
|
+
if (allowVisibleStreamDeltas && allowStreamedVisibleContent) {
|
|
28
220
|
const visibleStreamOutput = extractVisibleStreamOutput(event);
|
|
29
221
|
if (visibleStreamOutput) {
|
|
30
222
|
const nextOutput = computeIncrementalOutput(state.emittedOutput, visibleStreamOutput);
|
|
@@ -34,7 +226,7 @@ export function projectRuntimeStreamEvent(params) {
|
|
|
34
226
|
}
|
|
35
227
|
}
|
|
36
228
|
}
|
|
37
|
-
if (includeStateStreamOutput) {
|
|
229
|
+
if (includeStateStreamOutput && allowVisibleContent) {
|
|
38
230
|
const stateStreamOutput = extractStateStreamOutput(event);
|
|
39
231
|
if (stateStreamOutput) {
|
|
40
232
|
const nextOutput = computeIncrementalOutput(state.emittedOutput, sanitizeVisibleText(stateStreamOutput));
|
|
@@ -46,8 +238,23 @@ export function projectRuntimeStreamEvent(params) {
|
|
|
46
238
|
}
|
|
47
239
|
const toolResult = extractToolResult(event);
|
|
48
240
|
if (toolResult) {
|
|
241
|
+
const isTodoTool = toolResult.toolName === "write_todos" || toolResult.toolName === "read_todos";
|
|
242
|
+
const isSuccessfulTaskResult = toolResult.toolName === "task" && toolResult.isError !== true;
|
|
243
|
+
const isPlaceholderTaskResult = isSuccessfulTaskResult && isUpstreamPlaceholderTaskResult(toolResult.output);
|
|
244
|
+
const isDelegatedExecutionTool = (isDelegatedAgentEvent || state.openToolCapableTaskDelegations > 0)
|
|
245
|
+
&& toolResult.toolName !== "write_todos"
|
|
246
|
+
&& toolResult.toolName !== "read_todos"
|
|
247
|
+
&& toolResult.toolName !== "task";
|
|
49
248
|
state.emittedToolResult = true;
|
|
50
249
|
state.emittedToolError = state.emittedToolError || toolResult.isError === true;
|
|
250
|
+
state.emittedSuccessfulToolResult = state.emittedSuccessfulToolResult || toolResult.isError !== true;
|
|
251
|
+
state.emittedSuccessfulTaskResult = state.emittedSuccessfulTaskResult || isSuccessfulTaskResult;
|
|
252
|
+
state.emittedPlaceholderTaskResult = state.emittedPlaceholderTaskResult || isPlaceholderTaskResult;
|
|
253
|
+
state.emittedNonTodoToolResult = state.emittedNonTodoToolResult || !isTodoTool;
|
|
254
|
+
state.emittedSuccessfulNonTodoToolResult = state.emittedSuccessfulNonTodoToolResult || (!isTodoTool && toolResult.isError !== true);
|
|
255
|
+
state.emittedDelegatedExecutionToolResult = state.emittedDelegatedExecutionToolResult || isDelegatedExecutionTool;
|
|
256
|
+
state.emittedSuccessfulDelegatedExecutionToolResult =
|
|
257
|
+
state.emittedSuccessfulDelegatedExecutionToolResult || (isDelegatedExecutionTool && toolResult.isError !== true);
|
|
51
258
|
chunks.push({
|
|
52
259
|
kind: "tool-result",
|
|
53
260
|
toolName: resolveModelFacingToolName(toolResult.toolName, toolNameMapping, primaryTools),
|
|
@@ -55,7 +262,13 @@ export function projectRuntimeStreamEvent(params) {
|
|
|
55
262
|
isError: toolResult.isError,
|
|
56
263
|
});
|
|
57
264
|
}
|
|
58
|
-
const output = extractTerminalStreamOutput(event);
|
|
265
|
+
const output = allowVisibleContent ? extractTerminalStreamOutput(event) : "";
|
|
266
|
+
if (!allowVisibleContent) {
|
|
267
|
+
const delegatedTerminalOutput = extractTerminalStreamOutput(event);
|
|
268
|
+
if (delegatedTerminalOutput) {
|
|
269
|
+
state.emittedDelegatedTerminalOutput = true;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
59
272
|
if (output) {
|
|
60
273
|
const outputKey = normalizeTerminalOutputKey(output);
|
|
61
274
|
if (!outputKey || !state.seenTerminalOutputs.has(outputKey)) {
|
|
@@ -242,9 +242,6 @@ export declare const BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS: readonly [{
|
|
|
242
242
|
}, {
|
|
243
243
|
readonly name: "task";
|
|
244
244
|
readonly description: "Delegate a bounded task to a subagent.";
|
|
245
|
-
}, {
|
|
246
|
-
readonly name: "delegate_task";
|
|
247
|
-
readonly description: "Delegate a bounded task to a subagent.";
|
|
248
245
|
}];
|
|
249
246
|
export declare function createBuiltinMiddlewareTools(backend: BuiltinMiddlewareBackend, options: {
|
|
250
247
|
includeTaskTool: boolean;
|