@botbotgo/agent-harness 0.0.404 → 0.0.406
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.
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.406";
|
|
2
2
|
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-05-02";
|
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.406";
|
|
2
2
|
export const AGENT_HARNESS_RELEASE_DATE = "2026-05-02";
|
|
@@ -708,7 +708,9 @@ export async function* streamRuntimeExecution(options) {
|
|
|
708
708
|
}
|
|
709
709
|
const streamedDelegatedRecoveryInstruction = resolveDelegatedExecutionRecoveryInstruction(streamedExecutionEvidence);
|
|
710
710
|
const streamedDelegationOnlyRecoveryInstruction = resolveDelegationOnlyRecoveryInstruction(options.binding, streamedExecutionEvidence);
|
|
711
|
-
const streamedIncompletePlanRecoveryInstruction = requiresPlanEvidence(options.binding)
|
|
711
|
+
const streamedIncompletePlanRecoveryInstruction = requiresPlanEvidence(options.binding)
|
|
712
|
+
&& streamedExecutionEvidence.hasIncompletePlanState
|
|
713
|
+
&& streamedExecutionEvidence.hasSuccessfulNonTodoToolResultEvidence
|
|
712
714
|
? CLOSE_REQUIRED_PLAN_RECOVERY_INSTRUCTION
|
|
713
715
|
: null;
|
|
714
716
|
const streamedPrematurePlanCloseRecoveryInstruction = requiresPlanEvidence(options.binding)
|
|
@@ -721,7 +723,8 @@ export async function* streamRuntimeExecution(options) {
|
|
|
721
723
|
: null;
|
|
722
724
|
if (hasUnresolvedExecution(streamedExecutionEvidence)
|
|
723
725
|
&& !delegatedExecutionRecoveryInstruction
|
|
724
|
-
&& !streamedIncompletePlanRecoveryInstruction
|
|
726
|
+
&& !streamedIncompletePlanRecoveryInstruction
|
|
727
|
+
&& !streamedPrematurePlanCloseRecoveryInstruction) {
|
|
725
728
|
throw createUnresolvedExecutionError(streamedExecutionEvidence);
|
|
726
729
|
}
|
|
727
730
|
const executionWithoutToolEvidenceInstruction = projectionState.emittedOutput
|
|
@@ -968,10 +971,18 @@ export async function* streamRuntimeExecution(options) {
|
|
|
968
971
|
})
|
|
969
972
|
: null;
|
|
970
973
|
const invokeFallbackDelegationOnlyRecoveryInstruction = resolveDelegationOnlyRecoveryInstruction(options.binding, invokeExecutionEvidence);
|
|
971
|
-
const invokeFallbackIncompletePlanRecoveryInstruction = requiresPlanEvidence(options.binding)
|
|
974
|
+
const invokeFallbackIncompletePlanRecoveryInstruction = requiresPlanEvidence(options.binding)
|
|
975
|
+
&& invokeExecutionEvidence.hasIncompletePlanState
|
|
976
|
+
&& invokeExecutionEvidence.hasSuccessfulNonTodoToolResultEvidence
|
|
972
977
|
? CLOSE_REQUIRED_PLAN_RECOVERY_INSTRUCTION
|
|
973
978
|
: null;
|
|
979
|
+
const invokeFallbackPlanWithoutEvidenceRecoveryInstruction = requiresPlanEvidence(options.binding)
|
|
980
|
+
&& invokeExecutionEvidence.hasPlanStateEvidence
|
|
981
|
+
&& !invokeExecutionEvidence.hasSuccessfulNonTodoToolResultEvidence
|
|
982
|
+
? RUN_EVIDENCE_AFTER_PREMATURE_PLAN_CLOSE_INSTRUCTION
|
|
983
|
+
: null;
|
|
974
984
|
const effectiveInvokeFallbackRecoveryInstruction = invokeFallbackIncompletePlanRecoveryInstruction
|
|
985
|
+
?? invokeFallbackPlanWithoutEvidenceRecoveryInstruction
|
|
975
986
|
?? invokeFallbackMissingPlanRecoveryInstruction
|
|
976
987
|
?? invokeFallbackDelegationOnlyRecoveryInstruction
|
|
977
988
|
?? invokeFallbackRecoveryInstruction;
|
|
@@ -10,9 +10,6 @@ import { appendToolRecoveryInstruction, extractVisibleOutput, resolveMissingPlan
|
|
|
10
10
|
import { salvageJsonToolCalls } from "../parsing/output-tool-args.js";
|
|
11
11
|
import { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION } from "../prompts/runtime-prompts.js";
|
|
12
12
|
const TOOL_FOLLOW_UP_INSTRUCTION = "One or more tool results are already available in this conversation. Answer the user's current request directly from the existing context and tool results. Do not ask the user to repeat inputs that are already present above.";
|
|
13
|
-
function isObject(value) {
|
|
14
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15
|
-
}
|
|
16
13
|
function readPlanStateSummary(output) {
|
|
17
14
|
if (typeof output !== "object" || output === null) {
|
|
18
15
|
return null;
|
|
@@ -61,159 +58,6 @@ function isFallbackTodoCompletionToolCall(toolCall) {
|
|
|
61
58
|
&& toolCall.id.startsWith("fallback-complete-")
|
|
62
59
|
&& (toolCall.name === "write_todos" || toolCall.name === "tool_call_write_todos");
|
|
63
60
|
}
|
|
64
|
-
function isTerminalTodoUpdateToolCall(toolCall) {
|
|
65
|
-
if (!isPlanToolName(toolCall.name) || normalizeToolName(toolCall.name).includes("read_todos")) {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
if (typeof toolCall.args !== "object" || toolCall.args === null || !Array.isArray(toolCall.args.todos)) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
const todos = toolCall.args.todos;
|
|
72
|
-
return todos.length > 0 && todos.every((todo) => {
|
|
73
|
-
if (typeof todo !== "object" || todo === null || typeof todo.status !== "string") {
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
const status = todo.status.trim().toLowerCase();
|
|
77
|
-
return status !== "pending" && status !== "in_progress";
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
function readSchemaShape(schema) {
|
|
81
|
-
if (!isObject(schema)) {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
if (isObject(schema.properties)) {
|
|
85
|
-
return schema.properties;
|
|
86
|
-
}
|
|
87
|
-
if (isObject(schema.shape)) {
|
|
88
|
-
return schema.shape;
|
|
89
|
-
}
|
|
90
|
-
const def = schema._def;
|
|
91
|
-
if (!def) {
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
95
|
-
return isObject(shape) ? shape : null;
|
|
96
|
-
}
|
|
97
|
-
function readSchemaDescription(schemaPart) {
|
|
98
|
-
if (!isObject(schemaPart)) {
|
|
99
|
-
return "";
|
|
100
|
-
}
|
|
101
|
-
const direct = schemaPart.description;
|
|
102
|
-
if (typeof direct === "string") {
|
|
103
|
-
return direct;
|
|
104
|
-
}
|
|
105
|
-
const nested = schemaPart._def;
|
|
106
|
-
if (typeof nested?.description === "string") {
|
|
107
|
-
return nested.description;
|
|
108
|
-
}
|
|
109
|
-
return readSchemaDescription(nested?.innerType);
|
|
110
|
-
}
|
|
111
|
-
function readSchemaDefault(schemaPart) {
|
|
112
|
-
if (!isObject(schemaPart)) {
|
|
113
|
-
return undefined;
|
|
114
|
-
}
|
|
115
|
-
const typed = schemaPart;
|
|
116
|
-
const hasJsonDefault = Object.prototype.hasOwnProperty.call(schemaPart, "default") && typeof typed.default !== "function";
|
|
117
|
-
if (hasJsonDefault) {
|
|
118
|
-
return typed.default;
|
|
119
|
-
}
|
|
120
|
-
if (Object.prototype.hasOwnProperty.call(schemaPart, "const")) {
|
|
121
|
-
return typed.const;
|
|
122
|
-
}
|
|
123
|
-
const def = schemaPart._def;
|
|
124
|
-
if (!def) {
|
|
125
|
-
return undefined;
|
|
126
|
-
}
|
|
127
|
-
if (def.defaultValue !== undefined) {
|
|
128
|
-
return typeof def.defaultValue === "function" ? def.defaultValue() : def.defaultValue;
|
|
129
|
-
}
|
|
130
|
-
return readSchemaDefault(def.innerType);
|
|
131
|
-
}
|
|
132
|
-
function parseFirstStringArrayExample(description) {
|
|
133
|
-
const arrayMatch = description.match(/\[[^\]]+\]/u);
|
|
134
|
-
if (!arrayMatch) {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
const values = [...arrayMatch[0].matchAll(/["']([^"']+)["']/gu)].map((match) => match[1]).filter(Boolean);
|
|
138
|
-
return values.length > 0 ? values : null;
|
|
139
|
-
}
|
|
140
|
-
function buildGenericFallbackArgsFromSchema(schema, latestUserInput) {
|
|
141
|
-
const shape = readSchemaShape(schema);
|
|
142
|
-
if (!shape) {
|
|
143
|
-
return {};
|
|
144
|
-
}
|
|
145
|
-
const args = {};
|
|
146
|
-
for (const [key, schemaPart] of Object.entries(shape)) {
|
|
147
|
-
const defaultValue = readSchemaDefault(schemaPart);
|
|
148
|
-
if (defaultValue !== undefined) {
|
|
149
|
-
args[key] = defaultValue;
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
const description = readSchemaDescription(schemaPart);
|
|
153
|
-
const arrayExample = parseFirstStringArrayExample(description);
|
|
154
|
-
if (arrayExample) {
|
|
155
|
-
args[key] = arrayExample;
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
if (latestUserInput
|
|
159
|
-
&& !args[key]
|
|
160
|
-
&& /(?:query|question|prompt|input|text)/iu.test(`${key} ${description}`)) {
|
|
161
|
-
args[key] = latestUserInput;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return args;
|
|
165
|
-
}
|
|
166
|
-
function readTodoPlanTextFromToolCalls(toolCalls) {
|
|
167
|
-
const fragments = [];
|
|
168
|
-
for (const toolCall of toolCalls) {
|
|
169
|
-
if (typeof toolCall.args !== "object" || toolCall.args === null) {
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
const todos = toolCall.args.todos;
|
|
173
|
-
if (!Array.isArray(todos)) {
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
for (const todo of todos) {
|
|
177
|
-
if (typeof todo === "object" && todo !== null && typeof todo.content === "string") {
|
|
178
|
-
fragments.push(todo.content);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return fragments.join("\n");
|
|
183
|
-
}
|
|
184
|
-
function selectGenericFallbackEvidenceTool(params) {
|
|
185
|
-
const candidates = [];
|
|
186
|
-
const appendCandidate = (name) => {
|
|
187
|
-
if (isPlanToolName(name)) {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
const resolved = resolveModelFacingToolName(name, params.toolNameMapping, params.primaryTools);
|
|
191
|
-
const executable = params.executableTools.get(name)
|
|
192
|
-
?? params.executableTools.get(resolved)
|
|
193
|
-
?? params.builtinExecutableTools.get(name)
|
|
194
|
-
?? params.builtinExecutableTools.get(resolved);
|
|
195
|
-
if (!executable || candidates.some((candidate) => candidate.executable.name === executable.name)) {
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
candidates.push({ requestedName: name, executable });
|
|
199
|
-
};
|
|
200
|
-
for (const tool of params.primaryTools) {
|
|
201
|
-
appendCandidate(tool.name);
|
|
202
|
-
const modelFacing = params.toolNameMapping.originalToModelFacing.get(tool.name);
|
|
203
|
-
if (modelFacing) {
|
|
204
|
-
appendCandidate(modelFacing);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
for (const name of [...params.executableTools.keys(), ...params.builtinExecutableTools.keys()]) {
|
|
208
|
-
appendCandidate(name);
|
|
209
|
-
}
|
|
210
|
-
if (candidates.length === 0) {
|
|
211
|
-
return null;
|
|
212
|
-
}
|
|
213
|
-
const normalizedPlanText = params.planText.toLowerCase();
|
|
214
|
-
return candidates.find((candidate) => normalizedPlanText.includes(candidate.requestedName.toLowerCase())
|
|
215
|
-
|| normalizedPlanText.includes(candidate.executable.name.toLowerCase())) ?? candidates[0];
|
|
216
|
-
}
|
|
217
61
|
function buildDeterministicFinalFromToolEvidence(executedToolResults) {
|
|
218
62
|
const evidence = executedToolResults
|
|
219
63
|
.filter((item) => item.isError !== true && item.toolName !== "write_todos" && item.toolName !== "read_todos")
|
|
@@ -294,19 +138,12 @@ export async function runLocalToolInvocationLoop({ binding, request, primaryTool
|
|
|
294
138
|
const hasIncompletePlanState = hasIncompleteExecutedPlan(executedToolResults);
|
|
295
139
|
const shouldEnforceIncompletePlan = requiresPlanEvidence(binding) && hasIncompletePlanState;
|
|
296
140
|
const hasExecutionBeyondTodoPlanning = hasNonTodoToolEvidence(executedToolResults);
|
|
297
|
-
const missingInitialPlanRecoveryInstruction = resolveMissingPlanRecoveryInstruction({
|
|
298
|
-
request: activeRequest,
|
|
299
|
-
requiresPlan: requiresPlanEvidence(binding),
|
|
300
|
-
hasPlanStateEvidence: hasPlanStateEvidence(executedToolResults),
|
|
301
|
-
hasWriteTodosEvidence: executedToolResults.some((item) => item.toolName === "write_todos"),
|
|
302
|
-
hasToolResultEvidence: hasExecutionBeyondTodoPlanning,
|
|
303
|
-
});
|
|
304
141
|
const toolErrorRecoveryInstruction = latestToolErrorRecoveryInstruction(executedToolResults)
|
|
305
142
|
?? terminalToolErrorRecoveryInstruction(terminalText);
|
|
306
143
|
const leakedJsonToolCallRecoveryInstruction = terminalText && salvageJsonToolCalls(terminalText).length > 0
|
|
307
144
|
? STRICT_TOOL_JSON_INSTRUCTION
|
|
308
145
|
: null;
|
|
309
|
-
const recoveryInstruction = toolErrorRecoveryInstruction ?? leakedJsonToolCallRecoveryInstruction ??
|
|
146
|
+
const recoveryInstruction = toolErrorRecoveryInstruction ?? leakedJsonToolCallRecoveryInstruction ?? (terminalText
|
|
310
147
|
? resolveExecutionWithoutToolEvidenceTextInstruction(activeRequest, terminalText, false, {
|
|
311
148
|
hasWriteTodosEvidence: executedToolResults.some((item) => item.toolName === "write_todos"),
|
|
312
149
|
hasToolResultEvidence: hasExecutionBeyondTodoPlanning,
|
|
@@ -415,53 +252,6 @@ export async function runLocalToolInvocationLoop({ binding, request, primaryTool
|
|
|
415
252
|
content: stringifyToolOutput(safeToolResult),
|
|
416
253
|
}));
|
|
417
254
|
}
|
|
418
|
-
if (requiresPlanEvidence(binding)
|
|
419
|
-
&& !hadNonTodoEvidenceBeforeToolReplay
|
|
420
|
-
&& !hasNonTodoToolEvidence(executedToolResults)
|
|
421
|
-
&& toolCalls.length > 0
|
|
422
|
-
&& toolCalls.every((toolCall) => isPlanToolName(toolCall.name))
|
|
423
|
-
&& toolCalls.some(isTerminalTodoUpdateToolCall)) {
|
|
424
|
-
const fallbackEvidenceTool = selectGenericFallbackEvidenceTool({
|
|
425
|
-
planText: readTodoPlanTextFromToolCalls(toolCalls),
|
|
426
|
-
primaryTools,
|
|
427
|
-
toolNameMapping,
|
|
428
|
-
executableTools,
|
|
429
|
-
builtinExecutableTools,
|
|
430
|
-
});
|
|
431
|
-
if (fallbackEvidenceTool) {
|
|
432
|
-
const fallbackArgs = buildGenericFallbackArgsFromSchema(fallbackEvidenceTool.executable.schema, latestUserInput);
|
|
433
|
-
const normalizedArgs = normalizeToolArgsForSchema(fallbackArgs, fallbackEvidenceTool.executable.schema, undefined, {
|
|
434
|
-
latestUserInput,
|
|
435
|
-
});
|
|
436
|
-
const compiledTool = toolCatalog.get(fallbackEvidenceTool.requestedName) ?? toolCatalog.get(fallbackEvidenceTool.executable.name);
|
|
437
|
-
const gateway = validateToolGatewayInput({
|
|
438
|
-
toolName: fallbackEvidenceTool.executable.name,
|
|
439
|
-
schema: fallbackEvidenceTool.executable.schema,
|
|
440
|
-
args: normalizedArgs,
|
|
441
|
-
requiresApproval: compiledTool ? toolRequiresRuntimeApproval(compiledTool) : false,
|
|
442
|
-
});
|
|
443
|
-
if (gateway.ok) {
|
|
444
|
-
const toolResult = toolRuntimeContext
|
|
445
|
-
? await fallbackEvidenceTool.executable.invoke(gateway.input, { toolRuntimeContext })
|
|
446
|
-
: await fallbackEvidenceTool.executable.invoke(gateway.input);
|
|
447
|
-
const memoryCandidates = compiledTool ? extractMemoryCandidatesFromToolOutput(compiledTool, toolResult) : [];
|
|
448
|
-
const safeToolResult = await maybePersistLargeToolOutput({
|
|
449
|
-
toolName: fallbackEvidenceTool.executable.name,
|
|
450
|
-
output: toolResult,
|
|
451
|
-
toolRuntimeContext: toolRuntimeContext,
|
|
452
|
-
});
|
|
453
|
-
executedToolResults.push({
|
|
454
|
-
toolName: fallbackEvidenceTool.executable.name,
|
|
455
|
-
output: safeToolResult,
|
|
456
|
-
...(memoryCandidates.length > 0 ? { memoryCandidates } : {}),
|
|
457
|
-
});
|
|
458
|
-
return {
|
|
459
|
-
result: buildDeterministicFinalFromToolEvidence(executedToolResults),
|
|
460
|
-
executedToolResults,
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
255
|
if (requiresPlanEvidence(binding)
|
|
466
256
|
&& toolCalls.length > 0
|
|
467
257
|
&& toolCalls.every((toolCall) => isPlanToolName(toolCall.name))
|
|
@@ -253,26 +253,6 @@ function readLatestToolResultContent(input) {
|
|
|
253
253
|
}
|
|
254
254
|
return null;
|
|
255
255
|
}
|
|
256
|
-
function readLatestUserContent(input) {
|
|
257
|
-
if (Array.isArray(input)) {
|
|
258
|
-
for (let index = input.length - 1; index >= 0; index -= 1) {
|
|
259
|
-
const message = input[index];
|
|
260
|
-
if (mapMessageRole(message) !== "USER") {
|
|
261
|
-
continue;
|
|
262
|
-
}
|
|
263
|
-
const content = readPromptContent(message).trim();
|
|
264
|
-
if (content) {
|
|
265
|
-
return content;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
return undefined;
|
|
269
|
-
}
|
|
270
|
-
if (typeof input === "object" && input !== null && Array.isArray(input.messages)) {
|
|
271
|
-
return readLatestUserContent(input.messages);
|
|
272
|
-
}
|
|
273
|
-
const content = readPromptContent(input).trim();
|
|
274
|
-
return content || undefined;
|
|
275
|
-
}
|
|
276
256
|
function readBoundToolName(tool) {
|
|
277
257
|
return typeof tool === "object" && tool !== null && typeof tool.name === "string"
|
|
278
258
|
? tool.name.trim()
|
|
@@ -598,33 +578,10 @@ function isLowSignalPlanningLine(value) {
|
|
|
598
578
|
|| /^#+\s*/.test(normalized)
|
|
599
579
|
|| /^(?:ok|okay|sure|understood|got it|plan|todo|steps?)\.?$/.test(normalized));
|
|
600
580
|
}
|
|
601
|
-
function
|
|
602
|
-
return name.startsWith("tool_call_") ? name.slice("tool_call_".length) : name;
|
|
603
|
-
}
|
|
604
|
-
function selectFallbackEvidenceToolName(tools, rawText = "") {
|
|
605
|
-
const normalizedRawText = rawText.toLowerCase();
|
|
606
|
-
const available = tools
|
|
607
|
-
.map((tool) => normalizeDomainToolName(readBoundToolName(tool)))
|
|
608
|
-
.filter((name) => name && !isTodoPlanningToolName(name) && !isTodoPlanningToolName(`tool_call_${name}`));
|
|
609
|
-
if (available.length === 0) {
|
|
610
|
-
return null;
|
|
611
|
-
}
|
|
612
|
-
const mentioned = available.find((name) => normalizedRawText.includes(name.toLowerCase()));
|
|
613
|
-
return mentioned ?? available[0] ?? null;
|
|
614
|
-
}
|
|
615
|
-
function buildToolAwareFallbackTodoContents(tools, rawText = "") {
|
|
616
|
-
const evidenceToolName = selectFallbackEvidenceToolName(tools, rawText);
|
|
617
|
-
if (!evidenceToolName) {
|
|
618
|
-
return [
|
|
619
|
-
"Identify the concrete evidence tool required for this request",
|
|
620
|
-
"Run the selected non-planning evidence tool and inspect its result",
|
|
621
|
-
"Update TODO status from the observed evidence",
|
|
622
|
-
"Return the final answer grounded in tool output",
|
|
623
|
-
];
|
|
624
|
-
}
|
|
581
|
+
function buildFallbackTodoContents() {
|
|
625
582
|
return [
|
|
626
|
-
|
|
627
|
-
|
|
583
|
+
"Identify the concrete evidence tool required for this request",
|
|
584
|
+
"Run the selected non-planning evidence tool and inspect its result",
|
|
628
585
|
"Update TODO status from the observed evidence",
|
|
629
586
|
"Return the final answer grounded in tool output",
|
|
630
587
|
];
|
|
@@ -632,7 +589,7 @@ function buildToolAwareFallbackTodoContents(tools, rawText = "") {
|
|
|
632
589
|
function isGenericFallbackTodoContent(value) {
|
|
633
590
|
return /^(?:gather concrete evidence|inspect the most relevant runtime signals|analyze (?:the )?evidence|produce the final rca)/i.test(value.trim());
|
|
634
591
|
}
|
|
635
|
-
function buildFallbackPlanningToolCall(input, planningTools,
|
|
592
|
+
function buildFallbackPlanningToolCall(input, planningTools, rawText) {
|
|
636
593
|
const toolName = planningTools.map((tool) => readBoundToolName(tool)).find((name) => name === "write_todos" || name === "tool_call_write_todos");
|
|
637
594
|
if (!toolName) {
|
|
638
595
|
return null;
|
|
@@ -641,7 +598,7 @@ function buildFallbackPlanningToolCall(input, planningTools, allTools, rawText)
|
|
|
641
598
|
const hasUsefulModelPlan = modelPlannedItems.length >= 2 && !modelPlannedItems.every(isGenericFallbackTodoContent);
|
|
642
599
|
const fallbackItems = hasUsefulModelPlan
|
|
643
600
|
? modelPlannedItems
|
|
644
|
-
:
|
|
601
|
+
: buildFallbackTodoContents();
|
|
645
602
|
const todos = fallbackItems.map((content, index) => ({
|
|
646
603
|
content,
|
|
647
604
|
status: index === 0 ? "in_progress" : "pending",
|
|
@@ -656,63 +613,6 @@ function buildFallbackPlanningToolCall(input, planningTools, allTools, rawText)
|
|
|
656
613
|
}],
|
|
657
614
|
});
|
|
658
615
|
}
|
|
659
|
-
function buildFallbackEvidenceToolArgs(tool, latestUserInput) {
|
|
660
|
-
const schema = normalizeModelFacingToolSchema(tool);
|
|
661
|
-
if (typeof schema.properties !== "object" || schema.properties === null || Array.isArray(schema.properties)) {
|
|
662
|
-
return {};
|
|
663
|
-
}
|
|
664
|
-
const required = Array.isArray(schema.required)
|
|
665
|
-
? schema.required.filter((name) => typeof name === "string")
|
|
666
|
-
: [];
|
|
667
|
-
const values = {};
|
|
668
|
-
for (const [key, value] of Object.entries(schema.properties)) {
|
|
669
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
670
|
-
continue;
|
|
671
|
-
}
|
|
672
|
-
const property = value;
|
|
673
|
-
if ("default" in property) {
|
|
674
|
-
values[key] = property.default;
|
|
675
|
-
continue;
|
|
676
|
-
}
|
|
677
|
-
if ("const" in property) {
|
|
678
|
-
values[key] = property.const;
|
|
679
|
-
continue;
|
|
680
|
-
}
|
|
681
|
-
if (required.includes(key) && Array.isArray(property.enum) && property.enum.length > 0) {
|
|
682
|
-
values[key] = property.enum[0];
|
|
683
|
-
continue;
|
|
684
|
-
}
|
|
685
|
-
if (latestUserInput
|
|
686
|
-
&& !values[key]
|
|
687
|
-
&& /(?:query|question|prompt|input|text)/iu.test(`${key} ${typeof property.description === "string" ? property.description : ""}`)) {
|
|
688
|
-
values[key] = latestUserInput;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
return values;
|
|
692
|
-
}
|
|
693
|
-
function buildFallbackEvidenceToolCall(input, tools, rawText = "") {
|
|
694
|
-
if (!hasPriorToolResultForToolName(input, "write_todos") && !hasPriorToolResultForToolName(input, "tool_call_write_todos")) {
|
|
695
|
-
return null;
|
|
696
|
-
}
|
|
697
|
-
const evidenceToolName = selectFallbackEvidenceToolName(tools, rawText);
|
|
698
|
-
if (!evidenceToolName) {
|
|
699
|
-
return null;
|
|
700
|
-
}
|
|
701
|
-
const boundTool = tools.find((tool) => normalizeDomainToolName(readBoundToolName(tool)) === evidenceToolName);
|
|
702
|
-
const boundToolName = readBoundToolName(boundTool);
|
|
703
|
-
if (!boundTool || !boundToolName || hasPriorToolResultForToolName(input, boundToolName) || hasPriorToolResultForToolName(input, evidenceToolName)) {
|
|
704
|
-
return null;
|
|
705
|
-
}
|
|
706
|
-
return new AIMessage({
|
|
707
|
-
content: "",
|
|
708
|
-
tool_calls: [{
|
|
709
|
-
id: `fallback-evidence-${Math.random().toString(36).slice(2, 10)}`,
|
|
710
|
-
name: boundToolName,
|
|
711
|
-
args: buildFallbackEvidenceToolArgs(boundTool, readLatestUserContent(input)),
|
|
712
|
-
type: "tool_call",
|
|
713
|
-
}],
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
616
|
function buildFallbackTodoCompletionToolCall(input, tools) {
|
|
717
617
|
const prompt = stringifyNodeLlamaCppInput(input);
|
|
718
618
|
if (/TODO completed:|\[x\]/i.test(prompt)) {
|
|
@@ -722,17 +622,10 @@ function buildFallbackTodoCompletionToolCall(input, tools) {
|
|
|
722
622
|
if (!planningToolName) {
|
|
723
623
|
return null;
|
|
724
624
|
}
|
|
725
|
-
|
|
726
|
-
if (!evidenceToolName) {
|
|
727
|
-
return null;
|
|
728
|
-
}
|
|
729
|
-
const hasEvidenceResult = hasPriorToolResultForToolName(input, evidenceToolName)
|
|
730
|
-
|| hasPriorToolResultForToolName(input, `tool_call_${evidenceToolName}`)
|
|
731
|
-
|| hasPriorNonPlanningToolResult(input, tools);
|
|
732
|
-
if (!hasEvidenceResult) {
|
|
625
|
+
if (!hasPriorNonPlanningToolResult(input, tools)) {
|
|
733
626
|
return null;
|
|
734
627
|
}
|
|
735
|
-
const todos =
|
|
628
|
+
const todos = buildFallbackTodoContents().map((content) => ({
|
|
736
629
|
content,
|
|
737
630
|
status: "completed",
|
|
738
631
|
}));
|
|
@@ -848,7 +741,7 @@ function createPromptedJsonToolBindableModel(model, boundTools = [], options = {
|
|
|
848
741
|
const parsedToolCall = normalizeParsedToolCall(extractToolCallPayload(text));
|
|
849
742
|
if (!parsedToolCall) {
|
|
850
743
|
if (forcePlanningToolCall) {
|
|
851
|
-
const fallbackToolCall = buildFallbackPlanningToolCall(input, effectiveBoundTools,
|
|
744
|
+
const fallbackToolCall = buildFallbackPlanningToolCall(input, effectiveBoundTools, text);
|
|
852
745
|
if (fallbackToolCall) {
|
|
853
746
|
return fallbackToolCall;
|
|
854
747
|
}
|
|
@@ -858,23 +751,12 @@ function createPromptedJsonToolBindableModel(model, boundTools = [], options = {
|
|
|
858
751
|
if (fallbackCompletionToolCall) {
|
|
859
752
|
return fallbackCompletionToolCall;
|
|
860
753
|
}
|
|
861
|
-
const fallbackToolCall = buildFallbackEvidenceToolCall(input, effectiveBoundTools, text);
|
|
862
|
-
if (fallbackToolCall) {
|
|
863
|
-
return fallbackToolCall;
|
|
864
|
-
}
|
|
865
754
|
}
|
|
866
755
|
return rawResult;
|
|
867
756
|
}
|
|
868
757
|
const effectiveParsedToolCall = forcePlanningToolCall
|
|
869
758
|
? normalizeInitialTodoPlanToolCall(parsedToolCall)
|
|
870
759
|
: parsedToolCall;
|
|
871
|
-
if (parsedToolCallCompletesTodoPlan(effectiveParsedToolCall)
|
|
872
|
-
&& !hasPriorNonPlanningToolResult(input, effectiveBoundTools)) {
|
|
873
|
-
const fallbackToolCall = buildFallbackEvidenceToolCall(input, effectiveBoundTools, text);
|
|
874
|
-
if (fallbackToolCall) {
|
|
875
|
-
return fallbackToolCall;
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
760
|
if (hasPriorToolResultForToolName(input, effectiveParsedToolCall.name) || hasAnyPriorToolResult(input)) {
|
|
879
761
|
return rawResult;
|
|
880
762
|
}
|