@botbotgo/agent-harness 0.0.378 → 0.0.380
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.380";
|
|
2
2
|
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-30";
|
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.380";
|
|
2
2
|
export const AGENT_HARNESS_RELEASE_DATE = "2026-04-30";
|
|
@@ -212,14 +212,14 @@ function isTodoPlanningToolName(name) {
|
|
|
212
212
|
|| name === "tool_call_write_todos"
|
|
213
213
|
|| name === "tool_call_read_todos";
|
|
214
214
|
}
|
|
215
|
-
function
|
|
215
|
+
function shouldLimitToolsToPlanning(input) {
|
|
216
216
|
const text = stringifyNodeLlamaCppInput(input);
|
|
217
217
|
return text.includes("required visible planning contract")
|
|
218
218
|
&& !hasPriorToolResultForToolName(input, "write_todos")
|
|
219
219
|
&& !hasPriorToolResultForToolName(input, "tool_call_write_todos");
|
|
220
220
|
}
|
|
221
|
-
function
|
|
222
|
-
if (!
|
|
221
|
+
function selectPlanningToolsForTurn(input, boundTools) {
|
|
222
|
+
if (!shouldLimitToolsToPlanning(input)) {
|
|
223
223
|
return boundTools;
|
|
224
224
|
}
|
|
225
225
|
const planningTools = boundTools.filter((tool) => isTodoPlanningToolName(readBoundToolName(tool)));
|
|
@@ -270,26 +270,52 @@ function normalizeProviderFacingInput(input) {
|
|
|
270
270
|
}
|
|
271
271
|
return input;
|
|
272
272
|
}
|
|
273
|
-
function createProviderToolMessageCompatModel(model) {
|
|
273
|
+
function createProviderToolMessageCompatModel(model, boundTools = []) {
|
|
274
|
+
const resolveTargetForTurn = (input) => {
|
|
275
|
+
if (boundTools.length === 0 || typeof model.bindTools !== "function") {
|
|
276
|
+
return model;
|
|
277
|
+
}
|
|
278
|
+
const effectiveBoundTools = selectPlanningToolsForTurn(input, boundTools);
|
|
279
|
+
return model.bindTools.call(model, effectiveBoundTools);
|
|
280
|
+
};
|
|
274
281
|
return new Proxy(model, {
|
|
275
282
|
has(target, prop) {
|
|
276
|
-
if (prop === "bindTools" || prop === "invoke" || prop === "stream" || prop === "withConfig") {
|
|
283
|
+
if (prop === "bindTools" || prop === "invoke" || prop === "stream" || prop === "streamEvents" || prop === "withConfig") {
|
|
277
284
|
return true;
|
|
278
285
|
}
|
|
279
286
|
return prop in target;
|
|
280
287
|
},
|
|
281
288
|
get(target, prop, receiver) {
|
|
282
289
|
if (prop === "bindTools") {
|
|
283
|
-
return (tools) =>
|
|
284
|
-
const bound = target.bindTools.call(target, tools);
|
|
285
|
-
return createProviderToolMessageCompatModel(bound);
|
|
286
|
-
};
|
|
290
|
+
return (tools) => createProviderToolMessageCompatModel(target, tools);
|
|
287
291
|
}
|
|
288
292
|
if (prop === "invoke") {
|
|
289
|
-
return (input, config) =>
|
|
293
|
+
return (input, config) => {
|
|
294
|
+
const effectiveTarget = resolveTargetForTurn(input);
|
|
295
|
+
return effectiveTarget.invoke.call(effectiveTarget, normalizeProviderFacingInput(input), config);
|
|
296
|
+
};
|
|
290
297
|
}
|
|
291
298
|
if (prop === "stream") {
|
|
292
|
-
return (input, config) =>
|
|
299
|
+
return (input, config) => {
|
|
300
|
+
const effectiveTarget = resolveTargetForTurn(input);
|
|
301
|
+
return effectiveTarget.stream.call(effectiveTarget, normalizeProviderFacingInput(input), config);
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
if (prop === "streamEvents") {
|
|
305
|
+
return (input, config) => {
|
|
306
|
+
const effectiveTarget = resolveTargetForTurn(input);
|
|
307
|
+
if (typeof effectiveTarget.streamEvents === "function") {
|
|
308
|
+
return effectiveTarget.streamEvents.call(effectiveTarget, normalizeProviderFacingInput(input), config);
|
|
309
|
+
}
|
|
310
|
+
return (async function* () {
|
|
311
|
+
const output = await effectiveTarget.invoke.call(effectiveTarget, normalizeProviderFacingInput(input), config);
|
|
312
|
+
yield {
|
|
313
|
+
event: "on_chat_model_end",
|
|
314
|
+
name: typeof effectiveTarget.constructor?.name === "string" ? effectiveTarget.constructor.name : "ChatModel",
|
|
315
|
+
data: { output },
|
|
316
|
+
};
|
|
317
|
+
})();
|
|
318
|
+
};
|
|
293
319
|
}
|
|
294
320
|
if (prop === "withConfig" && typeof target.withConfig === "function") {
|
|
295
321
|
return (config) => createProviderToolMessageCompatModel(target.withConfig.call(target, config));
|
|
@@ -485,11 +511,20 @@ function withPromptedJsonToolPrompt(input, tools, options = {}) {
|
|
|
485
511
|
if (toolInstructions.length === 0) {
|
|
486
512
|
return stringifyNodeLlamaCppInput(input);
|
|
487
513
|
}
|
|
514
|
+
const forcedPlanningInstruction = options.forcePlanningToolCall
|
|
515
|
+
? [
|
|
516
|
+
"Required planning tool call:",
|
|
517
|
+
"You must call write_todos now before any domain tool or final answer.",
|
|
518
|
+
"Return exactly one JSON object for write_todos with concrete todo items and statuses.",
|
|
519
|
+
"Do not write prose, markdown, analysis, or a plain-text plan.",
|
|
520
|
+
].join("\n")
|
|
521
|
+
: "";
|
|
488
522
|
const systemContent = `${NODE_LLAMA_CPP_TOOL_CALL_INSTRUCTION}\n\n${toolInstructions.join("\n\n")}`;
|
|
489
523
|
const prompt = stringifyNodeLlamaCppInput(input);
|
|
490
524
|
return [
|
|
491
525
|
options.suppressThinking ? NO_THINK_CONTROL_TOKEN : "",
|
|
492
526
|
systemContent,
|
|
527
|
+
forcedPlanningInstruction,
|
|
493
528
|
prompt,
|
|
494
529
|
PROMPTED_JSON_FINAL_TOOL_CALL_REMINDER,
|
|
495
530
|
].filter(Boolean).join("\n\n");
|
|
@@ -497,7 +532,7 @@ function withPromptedJsonToolPrompt(input, tools, options = {}) {
|
|
|
497
532
|
function createPromptedJsonToolBindableModel(model, boundTools = [], options = {}) {
|
|
498
533
|
return new Proxy(model, {
|
|
499
534
|
has(target, prop) {
|
|
500
|
-
if (prop === "bindTools" || prop === "invoke" || prop === "stream" || prop === "withConfig") {
|
|
535
|
+
if (prop === "bindTools" || prop === "invoke" || prop === "stream" || prop === "streamEvents" || prop === "withConfig") {
|
|
501
536
|
return true;
|
|
502
537
|
}
|
|
503
538
|
return prop in target;
|
|
@@ -508,8 +543,11 @@ function createPromptedJsonToolBindableModel(model, boundTools = [], options = {
|
|
|
508
543
|
}
|
|
509
544
|
if (prop === "invoke") {
|
|
510
545
|
return async (input, config) => {
|
|
511
|
-
const effectiveBoundTools =
|
|
512
|
-
const
|
|
546
|
+
const effectiveBoundTools = selectPlanningToolsForTurn(input, boundTools);
|
|
547
|
+
const forcePlanningToolCall = shouldLimitToolsToPlanning(input);
|
|
548
|
+
const rawResult = await target.invoke(effectiveBoundTools.length > 0
|
|
549
|
+
? withPromptedJsonToolPrompt(input, effectiveBoundTools, { ...options, forcePlanningToolCall })
|
|
550
|
+
: input, config);
|
|
513
551
|
if (effectiveBoundTools.length === 0) {
|
|
514
552
|
return rawResult;
|
|
515
553
|
}
|
|
@@ -540,6 +578,18 @@ function createPromptedJsonToolBindableModel(model, boundTools = [], options = {
|
|
|
540
578
|
})();
|
|
541
579
|
};
|
|
542
580
|
}
|
|
581
|
+
if (prop === "streamEvents") {
|
|
582
|
+
return async (input, config) => {
|
|
583
|
+
const value = await receiver.invoke(input, config);
|
|
584
|
+
return (async function* () {
|
|
585
|
+
yield {
|
|
586
|
+
event: "on_chat_model_end",
|
|
587
|
+
name: typeof target.constructor?.name === "string" ? target.constructor.name : "ChatModel",
|
|
588
|
+
data: { output: value },
|
|
589
|
+
};
|
|
590
|
+
})();
|
|
591
|
+
};
|
|
592
|
+
}
|
|
543
593
|
if (prop === "withConfig" && typeof target.withConfig === "function") {
|
|
544
594
|
return (config) => createPromptedJsonToolBindableModel(target.withConfig(config), boundTools, options);
|
|
545
595
|
}
|
|
@@ -547,7 +597,7 @@ function createPromptedJsonToolBindableModel(model, boundTools = [], options = {
|
|
|
547
597
|
return typeof member === "function" ? member.bind(target) : member;
|
|
548
598
|
},
|
|
549
599
|
getOwnPropertyDescriptor(target, prop) {
|
|
550
|
-
if (prop === "bindTools" || prop === "invoke" || prop === "stream" || prop === "withConfig") {
|
|
600
|
+
if (prop === "bindTools" || prop === "invoke" || prop === "stream" || prop === "streamEvents" || prop === "withConfig") {
|
|
551
601
|
return {
|
|
552
602
|
configurable: true,
|
|
553
603
|
enumerable: false,
|
|
@@ -236,7 +236,10 @@ function getPlanStateFromUpstreamEvent(input) {
|
|
|
236
236
|
return null;
|
|
237
237
|
}
|
|
238
238
|
const typed = input.event;
|
|
239
|
-
const
|
|
239
|
+
const isWriteTodosStart = typed.event === "on_tool_start"
|
|
240
|
+
&& typed.name === "write_todos";
|
|
241
|
+
const todos = (isWriteTodosStart ? extractTodosArray(typed.data?.input) : null)
|
|
242
|
+
?? extractTodosArray(typed.data?.output)
|
|
240
243
|
?? extractTodosArray(typed.data?.chunk);
|
|
241
244
|
if (!todos) {
|
|
242
245
|
return null;
|