@botbotgo/agent-harness 0.0.462 → 0.0.463
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/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/adapter/flow/stream-runtime.js +8 -6
- package/dist/runtime/adapter/local-tool-invocation.js +26 -7
- package/dist/runtime/adapter/model/model-providers.js +4 -2
- package/dist/runtime/adapter/tool/tool-arguments.js +35 -3
- package/dist/runtime/agent-runtime-adapter.js +69 -22
- package/dist/runtime/parsing/output-tool-args.d.ts +4 -0
- package/dist/runtime/parsing/output-tool-args.js +38 -2
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.463";
|
|
2
2
|
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-05-04";
|
package/dist/package-version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.463";
|
|
2
2
|
export const AGENT_HARNESS_RELEASE_DATE = "2026-05-04";
|
|
@@ -25,6 +25,8 @@ const RUN_EVIDENCE_AFTER_PREMATURE_PLAN_CLOSE_INSTRUCTION = [
|
|
|
25
25
|
"The required todo board was closed before any non-TODO evidence tool returned.",
|
|
26
26
|
"Do not call write_todos again yet.",
|
|
27
27
|
"Your next action must be exactly one non-TODO evidence tool call selected from the available tool descriptions and schemas.",
|
|
28
|
+
"If the current request or todo board explicitly names one available non-TODO tool, call that named tool.",
|
|
29
|
+
"Do not substitute a neighboring, broader, narrower, or similarly named tool when an exact available tool name is present.",
|
|
28
30
|
"After that evidence tool returns, update the todo board and then provide the final answer required by the agent response format.",
|
|
29
31
|
].join("\n");
|
|
30
32
|
function readPrimaryToolName(tool) {
|
|
@@ -43,11 +45,11 @@ function buildRunEvidenceAfterPlanInstruction(primaryTools) {
|
|
|
43
45
|
`Available non-planning tool names: ${toolNames.join(", ")}.`,
|
|
44
46
|
].join("\n");
|
|
45
47
|
}
|
|
46
|
-
function
|
|
47
|
-
const
|
|
48
|
+
function resolveSingleConfiguredPlanEvidenceTool(primaryTools) {
|
|
49
|
+
const toolNames = primaryTools
|
|
48
50
|
.map(readPrimaryToolName)
|
|
49
|
-
.
|
|
50
|
-
return
|
|
51
|
+
.filter((name) => name.length > 0 && !isPlanToolName(name));
|
|
52
|
+
return toolNames.length === 1 ? [{ name: toolNames[0], args: {}, id: "stream-single-plan-evidence-tool-1" }] : [];
|
|
51
53
|
}
|
|
52
54
|
const INITIAL_REQUIRED_PLAN_INSTRUCTION = [
|
|
53
55
|
"This agent has a required visible planning contract.",
|
|
@@ -704,7 +706,7 @@ export async function* streamRuntimeExecution(options) {
|
|
|
704
706
|
&& hadPriorPlanToolResult
|
|
705
707
|
&& projectedChunks.some((chunk) => chunk.kind === "tool-result" && isPlanToolName(chunk.toolName));
|
|
706
708
|
if (repeatedPlanToolResultBeforeEvidence) {
|
|
707
|
-
earlyStreamExternalPlanEvidenceTools =
|
|
709
|
+
earlyStreamExternalPlanEvidenceTools = resolveSingleConfiguredPlanEvidenceTool(options.primaryTools);
|
|
708
710
|
earlyStreamRecoveryInstruction = buildRunEvidenceAfterPlanInstruction(options.primaryTools);
|
|
709
711
|
earlyStreamRecoverySuppressInitialPlan = true;
|
|
710
712
|
break;
|
|
@@ -750,7 +752,7 @@ export async function* streamRuntimeExecution(options) {
|
|
|
750
752
|
&& (hadPriorPlanToolResult
|
|
751
753
|
|| projectedChunks.some((chunk) => isCompletedPlanToolResultChunk(chunk)))
|
|
752
754
|
&& !sawSuccessfulNonTodoToolResult) {
|
|
753
|
-
earlyStreamExternalPlanEvidenceTools =
|
|
755
|
+
earlyStreamExternalPlanEvidenceTools = resolveSingleConfiguredPlanEvidenceTool(options.primaryTools);
|
|
754
756
|
earlyStreamRecoveryInstruction = buildRunEvidenceAfterPlanInstruction(options.primaryTools);
|
|
755
757
|
earlyStreamRecoverySuppressInitialPlan = true;
|
|
756
758
|
break;
|
|
@@ -13,15 +13,21 @@ const TOOL_FOLLOW_UP_INSTRUCTION = "One or more tool results are already availab
|
|
|
13
13
|
const DEFAULT_MAX_TOOL_ITERATIONS = 10_000;
|
|
14
14
|
const MAX_REPEATED_RECOVERY_WITHOUT_PROGRESS = 2;
|
|
15
15
|
const MAX_REPEATED_PLAN_ONLY_AFTER_PLAN = 2;
|
|
16
|
-
|
|
16
|
+
const REQUIRED_PLAN_CONTRACT_MARKER = "This agent has a required visible planning contract.";
|
|
17
|
+
const INITIAL_WRITE_TODOS_MARKER = "Your first action for this request must be write_todos";
|
|
18
|
+
function resolveSingleBootstrapEvidenceTool(primaryTools) {
|
|
17
19
|
const evidenceTools = primaryTools
|
|
18
20
|
.map((tool) => typeof tool.name === "string" ? tool.name.trim() : "")
|
|
19
21
|
.filter((name) => name.length > 0 && !isPlanToolName(name));
|
|
20
|
-
return evidenceTools.
|
|
22
|
+
return evidenceTools.length === 1 ? evidenceTools[0] : undefined;
|
|
21
23
|
}
|
|
22
24
|
function createBootstrapTodoPlan(primaryTools) {
|
|
23
|
-
const evidenceTool =
|
|
24
|
-
|
|
25
|
+
const evidenceTool = resolveSingleBootstrapEvidenceTool(primaryTools);
|
|
26
|
+
const evidenceToolCount = primaryTools
|
|
27
|
+
.map((tool) => typeof tool.name === "string" ? tool.name.trim() : "")
|
|
28
|
+
.filter((name) => name.length > 0 && !isPlanToolName(name))
|
|
29
|
+
.length;
|
|
30
|
+
if (evidenceToolCount === 0) {
|
|
25
31
|
return [
|
|
26
32
|
{
|
|
27
33
|
content: "Establish the required visible plan for this request",
|
|
@@ -35,7 +41,9 @@ function createBootstrapTodoPlan(primaryTools) {
|
|
|
35
41
|
}
|
|
36
42
|
return [
|
|
37
43
|
{
|
|
38
|
-
content:
|
|
44
|
+
content: evidenceTool
|
|
45
|
+
? `Run the only configured non-planning evidence tool: ${evidenceTool}`
|
|
46
|
+
: "Select and run the appropriate non-planning evidence tool from the declared tool surface",
|
|
39
47
|
status: "in_progress",
|
|
40
48
|
},
|
|
41
49
|
{
|
|
@@ -76,6 +84,15 @@ function buildExternalPlanEvidenceToolResult(tools) {
|
|
|
76
84
|
}],
|
|
77
85
|
};
|
|
78
86
|
}
|
|
87
|
+
function stripSatisfiedInitialPlanInstruction(messages) {
|
|
88
|
+
return messages.filter((message) => {
|
|
89
|
+
const typed = typeof message === "object" && message !== null ? message : {};
|
|
90
|
+
if (typeof typed.content !== "string") {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return !(typed.content.includes(REQUIRED_PLAN_CONTRACT_MARKER) && typed.content.includes(INITIAL_WRITE_TODOS_MARKER));
|
|
94
|
+
});
|
|
95
|
+
}
|
|
79
96
|
function readPlanStateSummary(output) {
|
|
80
97
|
if (typeof output !== "object" || output === null) {
|
|
81
98
|
return null;
|
|
@@ -217,7 +234,7 @@ function debugLocalToolReplay(input) {
|
|
|
217
234
|
}
|
|
218
235
|
console.error(JSON.stringify({
|
|
219
236
|
type: "local-tool-replay",
|
|
220
|
-
|
|
237
|
+
toolCalls: input.toolCalls.map((toolCall) => ({ name: toolCall.name, args: toolCall.args })),
|
|
221
238
|
resultMessages: summarizeResultMessages(input.result),
|
|
222
239
|
executableToolNames: input.executableToolNames,
|
|
223
240
|
builtinToolNames: input.builtinToolNames,
|
|
@@ -534,7 +551,9 @@ export async function runLocalToolInvocationLoop({ binding, request, primaryTool
|
|
|
534
551
|
executedToolResults,
|
|
535
552
|
};
|
|
536
553
|
}
|
|
537
|
-
currentMessages =
|
|
554
|
+
currentMessages = hasPlanStateEvidence(executedToolResults, externalPlanEvidence)
|
|
555
|
+
? stripSatisfiedInitialPlanInstruction(nextMessages)
|
|
556
|
+
: nextMessages;
|
|
538
557
|
activeRequest = {
|
|
539
558
|
...activeRequest,
|
|
540
559
|
messages: currentMessages,
|
|
@@ -6,7 +6,7 @@ import { ChatOpenAI } from "@langchain/openai";
|
|
|
6
6
|
import { AIMessage } from "langchain";
|
|
7
7
|
import { initChatModel } from "langchain";
|
|
8
8
|
import { salvageToolArgs, tryParseJson } from "../../parsing/output-parsing.js";
|
|
9
|
-
import { salvageJsonToolCalls } from "../../parsing/output-tool-args.js";
|
|
9
|
+
import { normalizeKnownToolArgs, salvageJsonToolCalls } from "../../parsing/output-tool-args.js";
|
|
10
10
|
import { normalizeModelFacingToolSchema } from "../tool/resolved-tool.js";
|
|
11
11
|
import { normalizeOpenAICompatibleInit } from "../compat/openai-compatible.js";
|
|
12
12
|
import { recordPromptedJsonToolCall } from "./prompted-json-tool-call-capture.js";
|
|
@@ -640,7 +640,7 @@ function normalizeParsedToolCall(payload) {
|
|
|
640
640
|
const args = Array.isArray(argsCandidate)
|
|
641
641
|
? { args: argsCandidate }
|
|
642
642
|
: salvageToolArgs(argsCandidate) ?? {};
|
|
643
|
-
return { name, args };
|
|
643
|
+
return { name, args: normalizeKnownToolArgs(name, args) };
|
|
644
644
|
}
|
|
645
645
|
function buildFallbackTodoContents() {
|
|
646
646
|
return [
|
|
@@ -770,6 +770,8 @@ function withPromptedJsonToolPrompt(input, tools, options = {}) {
|
|
|
770
770
|
? [
|
|
771
771
|
"Required evidence tool call:",
|
|
772
772
|
"A todo board already exists. Your next action must be exactly one non-planning tool call chosen from the available tool descriptions and schemas.",
|
|
773
|
+
"If the current request or todo board explicitly names one available non-planning tool, call that named tool.",
|
|
774
|
+
"Do not substitute a neighboring, broader, narrower, or similarly named tool when an exact available tool name is present.",
|
|
773
775
|
"Do not call write_todos or read_todos now.",
|
|
774
776
|
"Do not write prose, markdown, analysis, or a plain-text plan.",
|
|
775
777
|
].join("\n")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { salvageToolArgs } from "../../parsing/output-parsing.js";
|
|
2
|
-
import { salvageJsonToolCalls } from "../../parsing/output-tool-args.js";
|
|
2
|
+
import { normalizeKnownToolArgs, salvageJsonToolCalls, salvageResultLabeledToolCall } from "../../parsing/output-tool-args.js";
|
|
3
3
|
import { isRecord } from "../../../utils/object.js";
|
|
4
4
|
import { extractExplicitResourceReferences, hasExplicitResourceReference } from "../../harness/system/runtime-memory-policy.js";
|
|
5
5
|
import { readCapturedPromptedJsonToolCalls } from "../model/prompted-json-tool-call-capture.js";
|
|
@@ -175,6 +175,29 @@ function mapDelimitedListLikeArgs(args) {
|
|
|
175
175
|
}
|
|
176
176
|
return next;
|
|
177
177
|
}
|
|
178
|
+
function dropDelimitedScalarPathArgs(args, shape) {
|
|
179
|
+
let next = args;
|
|
180
|
+
for (const [key, schemaPart] of Object.entries(shape)) {
|
|
181
|
+
const value = next[key];
|
|
182
|
+
if (typeof value !== "string") {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const normalizedKey = key.trim().toLowerCase();
|
|
186
|
+
if (!/(?:^path$|path$|^filepath$|^targetpath$)/u.test(normalizedKey)) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (schemaPartExpectsArray(schemaPart)) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
const raw = value.trim();
|
|
193
|
+
if (!/[,;\n]/u.test(raw)) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const { [key]: _dropped, ...rest } = next;
|
|
197
|
+
next = rest;
|
|
198
|
+
}
|
|
199
|
+
return next;
|
|
200
|
+
}
|
|
178
201
|
export function normalizeToolArgsForSchema(args, schema, rawArgsInput, options = {}) {
|
|
179
202
|
const schemaDef = isObject(schema) ? schema._def : undefined;
|
|
180
203
|
const zodShape = schemaDef
|
|
@@ -191,7 +214,7 @@ export function normalizeToolArgsForSchema(args, schema, rawArgsInput, options =
|
|
|
191
214
|
if (!shape || !isRecord(shape)) {
|
|
192
215
|
return mapDelimitedListLikeArgs(args);
|
|
193
216
|
}
|
|
194
|
-
const aliasMappedArgs = mapStringArrayFields(mapCommonArgumentAliases(args, shape), shape);
|
|
217
|
+
const aliasMappedArgs = dropDelimitedScalarPathArgs(mapStringArrayFields(mapCommonArgumentAliases(args, shape), shape), shape);
|
|
195
218
|
const keys = Object.keys(shape);
|
|
196
219
|
if (keys.length !== 1) {
|
|
197
220
|
return fillLatestUserInputForQueryLikeFields(aliasMappedArgs, shape, options.latestUserInput);
|
|
@@ -270,7 +293,7 @@ export function extractToolCallsFromResult(result) {
|
|
|
270
293
|
if (id && answeredToolCallIds.has(id)) {
|
|
271
294
|
return null;
|
|
272
295
|
}
|
|
273
|
-
return { id, name, args: rawArgs, rawArgsInput };
|
|
296
|
+
return { id, name, args: normalizeKnownToolArgs(name, rawArgs), rawArgsInput };
|
|
274
297
|
})
|
|
275
298
|
.filter((item) => item !== null);
|
|
276
299
|
if (extracted.length > 0) {
|
|
@@ -296,6 +319,15 @@ export function extractToolCallsFromResult(result) {
|
|
|
296
319
|
if (!content.trim()) {
|
|
297
320
|
continue;
|
|
298
321
|
}
|
|
322
|
+
const resultLabeledToolCall = salvageResultLabeledToolCall(content);
|
|
323
|
+
if (resultLabeledToolCall) {
|
|
324
|
+
return [{
|
|
325
|
+
id: "salvaged-result-label-1",
|
|
326
|
+
name: resultLabeledToolCall.name,
|
|
327
|
+
args: resultLabeledToolCall.args,
|
|
328
|
+
rawArgsInput: content,
|
|
329
|
+
}];
|
|
330
|
+
}
|
|
299
331
|
const salvaged = salvageJsonToolCalls(content);
|
|
300
332
|
if (salvaged.length > 0) {
|
|
301
333
|
return salvaged.map((toolCall, salvageIndex) => ({
|
|
@@ -247,6 +247,32 @@ function hasDelegatedPlanEvidence(result) {
|
|
|
247
247
|
return Array.isArray(toolResults)
|
|
248
248
|
&& toolResults.some((item) => isPlanToolName(item.toolName));
|
|
249
249
|
}
|
|
250
|
+
function hasIncompleteDelegatedTodos(value) {
|
|
251
|
+
if (Array.isArray(value)) {
|
|
252
|
+
return value.some((item) => hasIncompleteDelegatedTodos(item));
|
|
253
|
+
}
|
|
254
|
+
if (typeof value !== "object" || value === null) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
const record = value;
|
|
258
|
+
const status = typeof record.status === "string" ? record.status.trim().toLowerCase() : "";
|
|
259
|
+
if (status === "pending" || status === "in_progress") {
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
return hasIncompleteDelegatedTodos(record.todos)
|
|
263
|
+
|| hasIncompleteDelegatedTodos(record.update)
|
|
264
|
+
|| hasIncompleteDelegatedTodos(record.stateSnapshot)
|
|
265
|
+
|| hasIncompleteDelegatedTodos(record.metadata);
|
|
266
|
+
}
|
|
267
|
+
function hasIncompleteDelegatedPlanState(result) {
|
|
268
|
+
const toolResults = result?.metadata?.executedToolResults;
|
|
269
|
+
return Array.isArray(toolResults)
|
|
270
|
+
&& toolResults.some((item) => isPlanToolName(item.toolName) && hasIncompleteDelegatedTodos(item.output));
|
|
271
|
+
}
|
|
272
|
+
function needsDelegatedPlanRecovery(binding, result) {
|
|
273
|
+
return binding?.harnessRuntime.executionContract?.requiresPlan === true
|
|
274
|
+
&& (!hasDelegatedPlanEvidence(result) || hasIncompleteDelegatedPlanState(result));
|
|
275
|
+
}
|
|
250
276
|
function readUpstreamToolEvidence(event) {
|
|
251
277
|
if (typeof event !== "object" || event === null) {
|
|
252
278
|
return null;
|
|
@@ -839,6 +865,28 @@ export class AgentRuntimeAdapter {
|
|
|
839
865
|
const inlineSubagents = input.resolvedSubagents.filter((subagent) => !("graphId" in subagent));
|
|
840
866
|
const asyncSubagents = input.resolvedSubagents.filter((subagent) => "graphId" in subagent);
|
|
841
867
|
const subagents = inlineSubagents;
|
|
868
|
+
const subagentDefaultMiddleware = [
|
|
869
|
+
...(builtinTools.todos === false ? [] : [todoListMiddleware()]),
|
|
870
|
+
...(builtinTools.filesystem === false ? [] : [createFilesystemMiddleware({ backend })]),
|
|
871
|
+
createSummarizationMiddleware({
|
|
872
|
+
model: input.resolvedModel,
|
|
873
|
+
backend,
|
|
874
|
+
}),
|
|
875
|
+
createPatchToolCallsMiddleware(),
|
|
876
|
+
];
|
|
877
|
+
const generalPurposeMiddleware = [
|
|
878
|
+
...subagentDefaultMiddleware,
|
|
879
|
+
...(input.resolvedSkills.length > 0 ? [createSkillsMiddleware({
|
|
880
|
+
backend,
|
|
881
|
+
sources: resolveDeepAgentSkillSourceRootPaths({
|
|
882
|
+
workspaceRoot: binding.harnessRuntime.workspaceRoot,
|
|
883
|
+
runtimeRoot: binding.harnessRuntime.runtimeRoot,
|
|
884
|
+
ownerId: binding.agent.id,
|
|
885
|
+
skillPaths: input.resolvedSkills,
|
|
886
|
+
}) ?? input.resolvedSkills,
|
|
887
|
+
})] : []),
|
|
888
|
+
];
|
|
889
|
+
const hasGeneralPurposeOverride = subagents.some((subagent) => subagent.name === "general-purpose");
|
|
842
890
|
const middleware = [
|
|
843
891
|
...(builtinTools.todos === false ? [] : [todoListMiddleware()]),
|
|
844
892
|
...(input.resolvedSkills.length > 0 ? [createSkillsMiddleware({
|
|
@@ -851,15 +899,15 @@ export class AgentRuntimeAdapter {
|
|
|
851
899
|
}) ?? input.resolvedSkills,
|
|
852
900
|
})] : []),
|
|
853
901
|
...(builtinTools.filesystem === false ? [] : [createFilesystemMiddleware({ backend })]),
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
902
|
+
createSubAgentMiddleware({
|
|
903
|
+
defaultModel: input.resolvedModel,
|
|
904
|
+
defaultTools: input.resolvedTools,
|
|
905
|
+
defaultMiddleware: subagentDefaultMiddleware,
|
|
906
|
+
generalPurposeMiddleware: generalPurposeMiddleware,
|
|
907
|
+
defaultInterruptOn: input.resolvedInterruptOn,
|
|
908
|
+
subagents: subagents,
|
|
909
|
+
generalPurposeAgent: !hasGeneralPurposeOverride,
|
|
910
|
+
}),
|
|
863
911
|
createSummarizationMiddleware({
|
|
864
912
|
model: input.resolvedModel,
|
|
865
913
|
backend,
|
|
@@ -1195,8 +1243,7 @@ export class AgentRuntimeAdapter {
|
|
|
1195
1243
|
};
|
|
1196
1244
|
}
|
|
1197
1245
|
}
|
|
1198
|
-
if (selectedBinding
|
|
1199
|
-
&& !hasDelegatedPlanEvidence(delegatedResult)) {
|
|
1246
|
+
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1200
1247
|
try {
|
|
1201
1248
|
delegatedResult = await runDelegatedRequest([requestText, DELEGATED_PLAN_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-retry");
|
|
1202
1249
|
}
|
|
@@ -1214,8 +1261,7 @@ export class AgentRuntimeAdapter {
|
|
|
1214
1261
|
};
|
|
1215
1262
|
}
|
|
1216
1263
|
}
|
|
1217
|
-
if (selectedBinding
|
|
1218
|
-
&& !hasDelegatedPlanEvidence(delegatedResult)) {
|
|
1264
|
+
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1219
1265
|
const output = buildDelegatedPlanEvidenceBlocker(selectedBinding.agent.id);
|
|
1220
1266
|
return {
|
|
1221
1267
|
toolOutput: output,
|
|
@@ -1606,12 +1652,16 @@ export class AgentRuntimeAdapter {
|
|
|
1606
1652
|
agentId: selectedBinding?.agent.id ?? planned.subagentType,
|
|
1607
1653
|
};
|
|
1608
1654
|
let delegatedResult = yield* runPlannedDelegation(planned.subagentType, delegatedText);
|
|
1609
|
-
if (selectedBinding
|
|
1655
|
+
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1610
1656
|
const previousDelegatedResult = delegatedResult;
|
|
1611
1657
|
delegatedResult = mergeDelegatedResultToolEvidence(yield* runPlannedDelegation(planned.subagentType, [delegatedText, DELEGATED_PLAN_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-retry"), previousDelegatedResult);
|
|
1612
1658
|
}
|
|
1613
|
-
if (selectedBinding
|
|
1614
|
-
const
|
|
1659
|
+
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1660
|
+
const previousDelegatedResult = delegatedResult;
|
|
1661
|
+
delegatedResult = mergeDelegatedResultToolEvidence(yield* runPlannedDelegation(planned.subagentType, [delegatedText, DELEGATED_PLAN_EVIDENCE_FINAL_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-final-retry"), previousDelegatedResult);
|
|
1662
|
+
}
|
|
1663
|
+
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1664
|
+
const output = buildDelegatedPlanEvidenceBlocker(selectedBinding?.agent.id ?? planned.subagentType);
|
|
1615
1665
|
delegatedResult = {
|
|
1616
1666
|
...delegatedResult,
|
|
1617
1667
|
state: "failed",
|
|
@@ -1803,18 +1853,15 @@ export class AgentRuntimeAdapter {
|
|
|
1803
1853
|
originalRequest: requestText,
|
|
1804
1854
|
});
|
|
1805
1855
|
let delegatedResult = yield* runDelegatedStreamAttempt(delegatedText);
|
|
1806
|
-
if (selectedBinding
|
|
1807
|
-
&& !hasDelegatedPlanEvidence(delegatedResult)) {
|
|
1856
|
+
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1808
1857
|
const previousDelegatedResult = delegatedResult;
|
|
1809
1858
|
delegatedResult = mergeDelegatedResultToolEvidence(yield* runDelegatedStreamAttempt([delegatedText, DELEGATED_PLAN_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-retry"), previousDelegatedResult);
|
|
1810
1859
|
}
|
|
1811
|
-
if (selectedBinding
|
|
1812
|
-
&& !hasDelegatedPlanEvidence(delegatedResult)) {
|
|
1860
|
+
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1813
1861
|
const previousDelegatedResult = delegatedResult;
|
|
1814
1862
|
delegatedResult = mergeDelegatedResultToolEvidence(yield* runDelegatedStreamAttempt([delegatedText, DELEGATED_PLAN_EVIDENCE_FINAL_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-final-retry"), previousDelegatedResult);
|
|
1815
1863
|
}
|
|
1816
|
-
if (selectedBinding
|
|
1817
|
-
&& !hasDelegatedPlanEvidence(delegatedResult)) {
|
|
1864
|
+
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1818
1865
|
const output = buildDelegatedPlanEvidenceBlocker(selectedBinding.agent.id);
|
|
1819
1866
|
delegatedResult = {
|
|
1820
1867
|
...delegatedResult,
|
|
@@ -7,6 +7,10 @@ export declare function salvageLabeledToolCall(value: unknown): {
|
|
|
7
7
|
name: string;
|
|
8
8
|
args: Record<string, unknown>;
|
|
9
9
|
} | null;
|
|
10
|
+
export declare function salvageResultLabeledToolCall(value: unknown): {
|
|
11
|
+
name: string;
|
|
12
|
+
args: Record<string, unknown>;
|
|
13
|
+
} | null;
|
|
10
14
|
export declare function salvageToolArgs(value: unknown): Record<string, unknown> | null;
|
|
11
15
|
export declare function salvageJsonToolCalls(value: unknown): Array<{
|
|
12
16
|
name: string;
|
|
@@ -179,6 +179,22 @@ export function salvageLabeledToolCall(value) {
|
|
|
179
179
|
}
|
|
180
180
|
return null;
|
|
181
181
|
}
|
|
182
|
+
export function salvageResultLabeledToolCall(value) {
|
|
183
|
+
if (typeof value !== "string") {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
const lines = value
|
|
187
|
+
.split("\n")
|
|
188
|
+
.map((line) => line.trim())
|
|
189
|
+
.filter(Boolean);
|
|
190
|
+
const label = lines[0]?.replace(/[*`#]/gu, "").trim() ?? "";
|
|
191
|
+
const match = /^([A-Za-z_][A-Za-z0-9_]*)\s+result\b/iu.exec(label);
|
|
192
|
+
if (!match || !isToolName(match[1])) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
const args = salvageToolArgs(lines.slice(1).join("\n")) ?? {};
|
|
196
|
+
return { name: match[1], args: normalizeKnownToolArgs(match[1], args) };
|
|
197
|
+
}
|
|
182
198
|
function extractBalancedJsonValue(value, openChar, closeChar) {
|
|
183
199
|
const start = value.indexOf(openChar);
|
|
184
200
|
if (start < 0)
|
|
@@ -514,12 +530,26 @@ function normalizeWriteTodosArgs(args) {
|
|
|
514
530
|
if (Array.isArray(args.items) && !Array.isArray(args.todos)) {
|
|
515
531
|
return normalizeWriteTodosArgs({ ...args, todos: args.items });
|
|
516
532
|
}
|
|
533
|
+
if (Array.isArray(args.tasks) && !Array.isArray(args.todos)) {
|
|
534
|
+
return normalizeWriteTodosArgs({ ...args, todos: args.tasks });
|
|
535
|
+
}
|
|
536
|
+
if (Array.isArray(args.todo) && !Array.isArray(args.todos)) {
|
|
537
|
+
return normalizeWriteTodosArgs({ ...args, todos: args.todo });
|
|
538
|
+
}
|
|
517
539
|
if (!Array.isArray(args.todos)) {
|
|
518
540
|
return args;
|
|
519
541
|
}
|
|
542
|
+
const { items: _items, tasks: _tasks, todo: _todo, ...rest } = args;
|
|
520
543
|
return {
|
|
521
|
-
...
|
|
544
|
+
...rest,
|
|
522
545
|
todos: args.todos.map((todo, index) => {
|
|
546
|
+
if (typeof todo === "string") {
|
|
547
|
+
const content = todo.trim();
|
|
548
|
+
return {
|
|
549
|
+
content: content.length > 0 ? content : `Step ${index + 1}`,
|
|
550
|
+
status: index === 0 ? "in_progress" : "pending",
|
|
551
|
+
};
|
|
552
|
+
}
|
|
523
553
|
if (typeof todo !== "object" || !todo || Array.isArray(todo)) {
|
|
524
554
|
return todo;
|
|
525
555
|
}
|
|
@@ -534,7 +564,13 @@ function normalizeWriteTodosArgs(args) {
|
|
|
534
564
|
? record.name
|
|
535
565
|
: typeof record.text === "string" && record.text.trim().length > 0
|
|
536
566
|
? record.text
|
|
537
|
-
:
|
|
567
|
+
: typeof record.task === "string" && record.task.trim().length > 0
|
|
568
|
+
? record.task
|
|
569
|
+
: typeof record.action === "string" && record.action.trim().length > 0
|
|
570
|
+
? record.action
|
|
571
|
+
: typeof record.step === "string" && record.step.trim().length > 0
|
|
572
|
+
? record.step
|
|
573
|
+
: `Step ${index + 1}`;
|
|
538
574
|
const normalized = {};
|
|
539
575
|
if (content !== undefined)
|
|
540
576
|
normalized.content = content;
|