@botbotgo/agent-harness 0.0.465 → 0.0.466

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.
@@ -211,6 +211,10 @@ export type CompiledBuiltinToolsConfig = {
211
211
  };
212
212
  export type CompiledExecutionContract = {
213
213
  requiresPlan?: boolean;
214
+ recoveryEvidenceTool?: {
215
+ name: string;
216
+ args?: Record<string, unknown>;
217
+ };
214
218
  };
215
219
  export type LangChainAgentParams = {
216
220
  model: CompiledModel;
@@ -1,2 +1,2 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.465";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.466";
2
2
  export declare const AGENT_HARNESS_RELEASE_DATE = "2026-05-04";
@@ -1,2 +1,2 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.465";
1
+ export const AGENT_HARNESS_VERSION = "0.0.466";
2
2
  export const AGENT_HARNESS_RELEASE_DATE = "2026-05-04";
@@ -396,26 +396,16 @@ function buildDelegatedPlanEvidenceRecoveryOptions(binding, baseOptions, request
396
396
  const nonPlanningTools = binding
397
397
  ? getBindingPrimaryTools(binding).filter((tool) => !isPlanToolName(tool.name))
398
398
  : [];
399
- const explicitlyRequestedTools = resolveExplicitlyRequestedToolNames(requestText, nonPlanningTools.map((tool) => tool.name));
400
- const externalPlanEvidenceTools = explicitlyRequestedTools.length === 1
401
- ? [{
402
- name: explicitlyRequestedTools[0],
403
- args: buildExternalPlanEvidenceArgs(nonPlanningTools.find((tool) => tool.name === explicitlyRequestedTools[0]), requestText),
404
- id: "delegated-plan-evidence-tool-1",
405
- }]
399
+ const configuredRecoveryTool = resolveConfiguredRecoveryEvidenceTool(binding, nonPlanningTools, requestText);
400
+ const externalPlanEvidenceTools = configuredRecoveryTool
401
+ ? [configuredRecoveryTool]
406
402
  : nonPlanningTools.length === 1
407
403
  ? [{
408
404
  name: nonPlanningTools[0].name,
409
405
  args: buildExternalPlanEvidenceArgs(nonPlanningTools[0], requestText),
410
406
  id: "delegated-plan-evidence-tool-1",
411
407
  }]
412
- : nonPlanningTools.length > 1
413
- ? [{
414
- name: nonPlanningTools[0].name,
415
- args: buildExternalPlanEvidenceArgs(nonPlanningTools[0], requestText),
416
- id: "delegated-plan-evidence-tool-1",
417
- }]
418
- : undefined;
408
+ : undefined;
419
409
  return {
420
410
  ...baseOptions,
421
411
  suppressInitialRequiredPlanInstruction: true,
@@ -427,6 +417,22 @@ function buildDelegatedPlanEvidenceRecoveryOptions(binding, baseOptions, request
427
417
  },
428
418
  };
429
419
  }
420
+ function resolveConfiguredRecoveryEvidenceTool(binding, nonPlanningTools, requestText) {
421
+ const configured = binding?.harnessRuntime.executionContract?.recoveryEvidenceTool;
422
+ const configuredName = typeof configured?.name === "string" ? configured.name.trim() : "";
423
+ if (!configuredName) {
424
+ return undefined;
425
+ }
426
+ const tool = nonPlanningTools.find((candidate) => candidate.name === configuredName);
427
+ if (!tool) {
428
+ return undefined;
429
+ }
430
+ return {
431
+ name: tool.name,
432
+ args: configured?.args ?? buildExternalPlanEvidenceArgs(tool, requestText),
433
+ id: "delegated-plan-evidence-tool-1",
434
+ };
435
+ }
430
436
  function buildExternalPlanEvidenceArgs(tool, requestText) {
431
437
  const properties = tool?.modelSchema && typeof tool.modelSchema === "object"
432
438
  && tool.modelSchema !== null
@@ -453,21 +459,6 @@ function buildExternalPlanEvidenceArgs(tool, requestText) {
453
459
  }
454
460
  return args;
455
461
  }
456
- function escapeRegExp(value) {
457
- return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
458
- }
459
- function resolveExplicitlyRequestedToolNames(text, availableToolNames) {
460
- if (!text.trim() || availableToolNames.length === 0) {
461
- return [];
462
- }
463
- return availableToolNames.filter((toolName) => {
464
- const trimmed = toolName.trim();
465
- if (!trimmed) {
466
- return false;
467
- }
468
- return new RegExp(`(^|[^A-Za-z0-9_])${escapeRegExp(trimmed)}([^A-Za-z0-9_]|$)`, "u").test(text);
469
- });
470
- }
471
462
  function looksLikeRawCommandTranscript(value) {
472
463
  const normalized = value.trim();
473
464
  return /^(?:stdout|stderr)\s*:/iu.test(normalized)
@@ -282,8 +282,30 @@ function resolveExecutionContract(agent) {
282
282
  if (!value) {
283
283
  return undefined;
284
284
  }
285
+ const recoveryEvidenceTool = typeof value.recoveryEvidenceTool === "string" && value.recoveryEvidenceTool.trim().length > 0
286
+ ? { name: value.recoveryEvidenceTool.trim() }
287
+ : typeof value.recoveryEvidenceTool === "object" && value.recoveryEvidenceTool && !Array.isArray(value.recoveryEvidenceTool)
288
+ ? value.recoveryEvidenceTool
289
+ : undefined;
290
+ const recoveryEvidenceToolName = recoveryEvidenceTool && typeof recoveryEvidenceTool.name === "string" && recoveryEvidenceTool.name.trim().length > 0
291
+ ? recoveryEvidenceTool.name.trim()
292
+ : undefined;
293
+ const recoveryEvidenceToolArgs = recoveryEvidenceTool
294
+ && typeof recoveryEvidenceTool.args === "object"
295
+ && recoveryEvidenceTool.args
296
+ && !Array.isArray(recoveryEvidenceTool.args)
297
+ ? recoveryEvidenceTool.args
298
+ : undefined;
285
299
  return {
286
300
  ...(value.requiresPlan === true ? { requiresPlan: true } : {}),
301
+ ...(recoveryEvidenceToolName
302
+ ? {
303
+ recoveryEvidenceTool: {
304
+ name: recoveryEvidenceToolName,
305
+ ...(recoveryEvidenceToolArgs ? { args: recoveryEvidenceToolArgs } : {}),
306
+ },
307
+ }
308
+ : {}),
287
309
  };
288
310
  }
289
311
  function resolveCompiledMiddleware(agent, models) {
@@ -50,6 +50,16 @@ function readExecutionContractConfig(agent) {
50
50
  ? value
51
51
  : undefined;
52
52
  }
53
+ function readRecoveryEvidenceToolName(value) {
54
+ if (typeof value === "string") {
55
+ return value.trim();
56
+ }
57
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
58
+ return "";
59
+ }
60
+ const name = value.name;
61
+ return typeof name === "string" ? name.trim() : "";
62
+ }
53
63
  function collectAgentToolNames(agent, tools, ownsDelegation) {
54
64
  const names = new Set(FRAMEWORK_EXECUTION_TOOL_NAMES);
55
65
  if (ownsDelegation) {
@@ -208,6 +218,13 @@ function validateAgentContract(agent, referencedSubagentIds, tools, refs, issues
208
218
  if (executionContract?.requiresPlan === true && builtinTools?.todos === false) {
209
219
  addIssue(issues, "agent.execution_contract.plan_without_todos", `Agent ${agent.id} requires plan evidence but disables todo tools. Enable todo tools or remove config.executionContract.requiresPlan.`);
210
220
  }
221
+ const recoveryEvidenceToolName = readRecoveryEvidenceToolName(executionContract?.recoveryEvidenceTool);
222
+ if (recoveryEvidenceToolName) {
223
+ const toolNames = collectAgentToolNames(agent, tools, ownsDelegation);
224
+ if (FRAMEWORK_EXECUTION_TOOL_NAMES.has(recoveryEvidenceToolName) || !toolNames.has(recoveryEvidenceToolName)) {
225
+ addIssue(issues, "agent.execution_contract.invalid_recovery_evidence_tool", `Agent ${agent.id} config.executionContract.recoveryEvidenceTool must name one declared non-planning tool.`);
226
+ }
227
+ }
211
228
  if (ownsDelegation) {
212
229
  if (hasTools) {
213
230
  addIssue(issues, "agent.orchestrator.mixed_tool_surface", `Delegating agent ${agent.id} defines both subagents and direct tools. Keep routing agents focused on delegation, and move execution tools to specialist agents.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.465",
3
+ "version": "0.0.466",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",