@botbotgo/agent-harness 0.0.366 → 0.0.367

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.366";
2
- export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-28";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.367";
2
+ export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-30";
@@ -1,2 +1,2 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.366";
2
- export const AGENT_HARNESS_RELEASE_DATE = "2026-04-28";
1
+ export const AGENT_HARNESS_VERSION = "0.0.367";
2
+ export const AGENT_HARNESS_RELEASE_DATE = "2026-04-30";
@@ -8,6 +8,19 @@ import { appendToolRecoveryInstruction, extractVisibleOutput, tryParseJson } fro
8
8
  import { salvageJsonToolCalls } from "../../parsing/output-tool-args.js";
9
9
  import { isEmptyFinalAiMessageError } from "../resilience.js";
10
10
  import { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, } from "../../prompts/runtime-prompts.js";
11
+ const CLOSE_REQUIRED_PLAN_RECOVERY_INSTRUCTION = [
12
+ "The current required todo board still has unfinished work.",
13
+ "Do not broaden the investigation, restart planning, or ask the user what to do next.",
14
+ "Use the existing tool evidence already available in this run.",
15
+ "Your next action must be write_todos: update every remaining pending or in_progress item to completed if evidence was gathered, or failed if it cannot be completed with the available tools.",
16
+ "After that write_todos call, provide the final answer required by the agent response format.",
17
+ ].join("\n");
18
+ const INITIAL_REQUIRED_PLAN_INSTRUCTION = [
19
+ "This agent has a required visible planning contract.",
20
+ "Your first action for this request must be write_todos with concrete task steps and statuses.",
21
+ "Do not call any domain/evidence tool and do not provide a final answer before the initial write_todos call succeeds.",
22
+ "After each evidence step, update the todo board. Before the final answer, close every todo as completed or failed.",
23
+ ].join("\n");
11
24
  function readBindingExecutionParams(binding) {
12
25
  const params = binding.execution?.params ?? binding.deepAgentParams ?? binding.langchainAgentParams;
13
26
  return {
@@ -280,9 +293,13 @@ function appendUserRecoveryInstruction(input, instruction) {
280
293
  export async function executeRequestInvocation(options) {
281
294
  const history = options.history ?? [];
282
295
  const invokeOptions = options.invokeOptions ?? {};
283
- const request = options.resumePayload === undefined
296
+ let request = options.resumePayload === undefined
284
297
  ? buildInvocationRequest(options.binding, history, options.input, invokeOptions)
285
298
  : new Command({ resume: options.resumePayload });
299
+ if (options.resumePayload === undefined
300
+ && options.binding.harnessRuntime.executionContract?.requiresPlan === true) {
301
+ request = appendToolRecoveryInstruction(request, INITIAL_REQUIRED_PLAN_INSTRUCTION);
302
+ }
286
303
  const { primaryTools, toolNameMapping, executableTools, defersToUpstreamHitlExecution, } = buildBindingToolExecutionContext({
287
304
  binding: options.binding,
288
305
  resolveTools: options.resolveTools,
@@ -335,7 +352,7 @@ export async function executeRequestInvocation(options) {
335
352
  ? result.messages
336
353
  : undefined;
337
354
  const recoveryBase = messages ? { messages } : request;
338
- const recoveredRequest = appendToolRecoveryInstruction(recoveryBase, AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION);
355
+ const recoveredRequest = appendToolRecoveryInstruction(recoveryBase, CLOSE_REQUIRED_PLAN_RECOVERY_INSTRUCTION);
339
356
  const recoveredInvocation = await invokeOnce(recoveredRequest);
340
357
  localOrUpstreamInvocation = recoveredInvocation;
341
358
  result = recoveredInvocation.result;
@@ -343,8 +360,7 @@ export async function executeRequestInvocation(options) {
343
360
  }
344
361
  if (options.resumePayload === undefined
345
362
  && options.binding.harnessRuntime.executionContract?.requiresPlan === true
346
- && hasIncompleteUpstreamPlan(result)
347
- && !extractVisibleOutput(result).trim()) {
363
+ && hasIncompleteUpstreamPlan(result)) {
348
364
  const messages = Array.isArray(result.messages)
349
365
  ? result.messages
350
366
  : undefined;
@@ -164,6 +164,11 @@ function hasDelegatedPlanEvidence(result) {
164
164
  return Array.isArray(toolResults)
165
165
  && toolResults.some((item) => item.toolName === "write_todos" || item.toolName === "read_todos");
166
166
  }
167
+ const DELEGATED_PLAN_EVIDENCE_RETRY_INSTRUCTION = [
168
+ "The delegated task requires visible TODO planning evidence.",
169
+ "Before any other tool call or final answer, call write_todos with concrete task steps and statuses.",
170
+ "Then continue the task to completion, update TODO statuses after evidence steps, and close every TODO as completed or failed before the final answer.",
171
+ ].join("\n");
167
172
  function resolveDelegatedResultOutput(result) {
168
173
  const executedToolResults = Array.isArray(result.metadata?.executedToolResults)
169
174
  ? result.metadata.executedToolResults
@@ -936,21 +941,62 @@ export class AgentRuntimeAdapter {
936
941
  delegatedResult = await runDelegatedRequest(requestText);
937
942
  }
938
943
  catch (error) {
939
- const output = error instanceof Error ? error.message : String(error);
940
- return {
941
- toolOutput: output,
942
- delegatedSubagentType: subagentType,
943
- delegatedResult: {
944
- sessionId,
945
- requestId,
946
- agentId: selectedBinding.agent.id,
947
- state: "failed",
948
- output,
949
- finalMessageText: output,
950
- },
951
- };
944
+ if (selectedBinding.harnessRuntime.executionContract?.requiresPlan === true) {
945
+ try {
946
+ delegatedResult = await runDelegatedRequest([requestText, DELEGATED_PLAN_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-retry");
947
+ }
948
+ catch (recoveryError) {
949
+ const output = recoveryError instanceof Error ? recoveryError.message : String(recoveryError);
950
+ return {
951
+ toolOutput: output,
952
+ delegatedSubagentType: subagentType,
953
+ delegatedResult: {
954
+ sessionId,
955
+ requestId,
956
+ agentId: selectedBinding.agent.id,
957
+ state: "failed",
958
+ output,
959
+ finalMessageText: output,
960
+ },
961
+ };
962
+ }
963
+ }
964
+ else {
965
+ const output = error instanceof Error ? error.message : String(error);
966
+ return {
967
+ toolOutput: output,
968
+ delegatedSubagentType: subagentType,
969
+ delegatedResult: {
970
+ sessionId,
971
+ requestId,
972
+ agentId: selectedBinding.agent.id,
973
+ state: "failed",
974
+ output,
975
+ finalMessageText: output,
976
+ },
977
+ };
978
+ }
952
979
  }
953
980
  const targetRequiresExecutionToolEvidence = getBindingPrimaryTools(selectedBinding).length > 0;
981
+ if (selectedBinding.harnessRuntime.executionContract?.requiresPlan === true
982
+ && !hasDelegatedPlanEvidence(delegatedResult)) {
983
+ try {
984
+ delegatedResult = await runDelegatedRequest([requestText, DELEGATED_PLAN_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-retry");
985
+ }
986
+ catch (error) {
987
+ const output = error instanceof Error ? error.message : String(error);
988
+ return {
989
+ toolOutput: output,
990
+ delegatedSubagentType: subagentType,
991
+ delegatedResult: {
992
+ ...delegatedResult,
993
+ state: "failed",
994
+ output,
995
+ finalMessageText: output,
996
+ },
997
+ };
998
+ }
999
+ }
954
1000
  if (targetRequiresExecutionToolEvidence && !hasDelegatedExecutionToolEvidence(delegatedResult)) {
955
1001
  try {
956
1002
  delegatedResult = await runDelegatedRequest([requestText, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":tool-evidence-retry");
@@ -969,8 +1015,9 @@ export class AgentRuntimeAdapter {
969
1015
  };
970
1016
  }
971
1017
  }
972
- if (targetRequiresExecutionToolEvidence && !hasDelegatedExecutionToolEvidence(delegatedResult)) {
973
- const output = `runtime_error=Delegated agent ${selectedBinding.agent.id} completed without tool execution evidence.`;
1018
+ if (selectedBinding.harnessRuntime.executionContract?.requiresPlan === true
1019
+ && !hasDelegatedPlanEvidence(delegatedResult)) {
1020
+ const output = "runtime_error=Delegated agent ended before producing required plan evidence.";
974
1021
  return {
975
1022
  toolOutput: output,
976
1023
  delegatedSubagentType: subagentType,
@@ -982,10 +1029,8 @@ export class AgentRuntimeAdapter {
982
1029
  },
983
1030
  };
984
1031
  }
985
- if (selectedBinding.harnessRuntime.executionContract?.requiresPlan === true
986
- && !hasDelegatedPlanEvidence(delegatedResult)
987
- && !hasDelegatedExecutionToolEvidence(delegatedResult)) {
988
- const output = "runtime_error=Delegated agent ended before producing required plan evidence.";
1032
+ if (targetRequiresExecutionToolEvidence && !hasDelegatedExecutionToolEvidence(delegatedResult)) {
1033
+ const output = `runtime_error=Delegated agent ${selectedBinding.agent.id} completed without tool execution evidence.`;
989
1034
  return {
990
1035
  toolOutput: output,
991
1036
  delegatedSubagentType: subagentType,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.366",
3
+ "version": "0.0.367",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",