@botbotgo/agent-harness 0.0.401 → 0.0.402

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.401";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.402";
2
2
  export declare const AGENT_HARNESS_RELEASE_DATE = "2026-05-02";
@@ -1,2 +1,2 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.401";
1
+ export const AGENT_HARNESS_VERSION = "0.0.402";
2
2
  export const AGENT_HARNESS_RELEASE_DATE = "2026-05-02";
@@ -294,12 +294,19 @@ export async function runLocalToolInvocationLoop({ binding, request, primaryTool
294
294
  const hasIncompletePlanState = hasIncompleteExecutedPlan(executedToolResults);
295
295
  const shouldEnforceIncompletePlan = requiresPlanEvidence(binding) && hasIncompletePlanState;
296
296
  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
+ });
297
304
  const toolErrorRecoveryInstruction = latestToolErrorRecoveryInstruction(executedToolResults)
298
305
  ?? terminalToolErrorRecoveryInstruction(terminalText);
299
306
  const leakedJsonToolCallRecoveryInstruction = terminalText && salvageJsonToolCalls(terminalText).length > 0
300
307
  ? STRICT_TOOL_JSON_INSTRUCTION
301
308
  : null;
302
- const recoveryInstruction = toolErrorRecoveryInstruction ?? leakedJsonToolCallRecoveryInstruction ?? (terminalText
309
+ const recoveryInstruction = toolErrorRecoveryInstruction ?? leakedJsonToolCallRecoveryInstruction ?? missingInitialPlanRecoveryInstruction ?? (terminalText
303
310
  ? resolveExecutionWithoutToolEvidenceTextInstruction(activeRequest, terminalText, false, {
304
311
  hasWriteTodosEvidence: executedToolResults.some((item) => item.toolName === "write_todos"),
305
312
  hasToolResultEvidence: hasExecutionBeyondTodoPlanning,
@@ -253,6 +253,26 @@ 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
+ }
256
276
  function readBoundToolName(tool) {
257
277
  return typeof tool === "object" && tool !== null && typeof tool.name === "string"
258
278
  ? tool.name.trim()
@@ -280,6 +300,12 @@ function selectPlanningToolsForTurn(input, boundTools) {
280
300
  if (!shouldLimitToolsToPlanning(input)) {
281
301
  return boundTools;
282
302
  }
303
+ if (!boundTools.some((tool) => {
304
+ const name = readBoundToolName(tool);
305
+ return name && !isTodoPlanningToolName(name);
306
+ })) {
307
+ return [];
308
+ }
283
309
  const planningTools = boundTools.filter((tool) => isTodoPlanningToolName(readBoundToolName(tool)));
284
310
  return planningTools.length > 0 ? planningTools : boundTools;
285
311
  }
@@ -619,6 +645,10 @@ function buildFallbackPlanningToolCall(input, planningTools, allTools, rawText)
619
645
  }
620
646
  const modelPlannedItems = extractFallbackTodoContentsFromText(rawText);
621
647
  const hasUsefulModelPlan = modelPlannedItems.length >= 2 && !modelPlannedItems.every(isGenericFallbackTodoContent);
648
+ const hasEvidenceTool = selectFallbackEvidenceToolName(allTools, rawText) !== null;
649
+ if (!hasUsefulModelPlan && !hasEvidenceTool) {
650
+ return null;
651
+ }
622
652
  const fallbackItems = hasUsefulModelPlan
623
653
  ? modelPlannedItems
624
654
  : buildToolAwareFallbackTodoContents(allTools, rawText);
@@ -636,7 +666,7 @@ function buildFallbackPlanningToolCall(input, planningTools, allTools, rawText)
636
666
  }],
637
667
  });
638
668
  }
639
- function buildFallbackEvidenceToolArgs(tool) {
669
+ function buildFallbackEvidenceToolArgs(tool, latestUserInput) {
640
670
  const schema = normalizeModelFacingToolSchema(tool);
641
671
  if (typeof schema.properties !== "object" || schema.properties === null || Array.isArray(schema.properties)) {
642
672
  return {};
@@ -660,6 +690,12 @@ function buildFallbackEvidenceToolArgs(tool) {
660
690
  }
661
691
  if (required.includes(key) && Array.isArray(property.enum) && property.enum.length > 0) {
662
692
  values[key] = property.enum[0];
693
+ continue;
694
+ }
695
+ if (latestUserInput
696
+ && !values[key]
697
+ && /(?:query|question|prompt|input|text)/iu.test(`${key} ${typeof property.description === "string" ? property.description : ""}`)) {
698
+ values[key] = latestUserInput;
663
699
  }
664
700
  }
665
701
  return values;
@@ -682,7 +718,7 @@ function buildFallbackEvidenceToolCall(input, tools, rawText = "") {
682
718
  tool_calls: [{
683
719
  id: `fallback-evidence-${Math.random().toString(36).slice(2, 10)}`,
684
720
  name: boundToolName,
685
- args: buildFallbackEvidenceToolArgs(boundTool),
721
+ args: buildFallbackEvidenceToolArgs(boundTool, readLatestUserContent(input)),
686
722
  type: "tool_call",
687
723
  }],
688
724
  });
@@ -38,6 +38,8 @@ export declare class AgentRuntimeAdapter {
38
38
  private invokeBuiltinTaskTool;
39
39
  private resolveBuiltinMiddlewareTools;
40
40
  private materializeProviderAliasBuiltinTools;
41
+ private shouldExposeBuiltinToolsToModel;
42
+ private resolveEffectiveModelExposedBuiltins;
41
43
  private materializeAutomaticSummarizationMiddleware;
42
44
  private resolveLangChainRuntimeExtensionMiddleware;
43
45
  private resolveMiddleware;
@@ -694,12 +694,47 @@ export class AgentRuntimeAdapter {
694
694
  invokeBuiltinTaskTool: assembly.invokeBuiltinTaskTool,
695
695
  });
696
696
  }
697
- materializeProviderAliasBuiltinTools(builtinTools) {
697
+ materializeProviderAliasBuiltinTools(builtinTools, modelExposed) {
698
+ if (modelExposed === false) {
699
+ return [];
700
+ }
701
+ const allowedToolNames = Array.isArray(modelExposed) ? new Set(modelExposed) : undefined;
698
702
  const aliasableTools = ["write_todos", "read_todos", "task"]
703
+ .filter((name) => !allowedToolNames || allowedToolNames.has(name))
699
704
  .map((name) => builtinTools.get(name))
700
705
  .filter((tool) => tool !== undefined);
701
706
  return appendProviderToolCallAliasTools(aliasableTools).slice(aliasableTools.length);
702
707
  }
708
+ shouldExposeBuiltinToolsToModel(binding, primaryTools) {
709
+ const modelExposed = getBindingBuiltinToolsConfig(binding)?.modelExposed;
710
+ if (binding.harnessRuntime.executionContract?.requiresPlan === true) {
711
+ return true;
712
+ }
713
+ if (modelExposed === false) {
714
+ return false;
715
+ }
716
+ if (Array.isArray(modelExposed)) {
717
+ return modelExposed.length > 0;
718
+ }
719
+ return (primaryTools.length > 0
720
+ || getBindingSubagents(binding).length > 0
721
+ || getBindingDeepAgentSubagents(binding).length > 0);
722
+ }
723
+ resolveEffectiveModelExposedBuiltins(binding) {
724
+ const configured = getBindingBuiltinToolsConfig(binding)?.modelExposed;
725
+ const requiredNames = new Set();
726
+ if (binding.harnessRuntime.executionContract?.requiresPlan === true) {
727
+ requiredNames.add("write_todos");
728
+ requiredNames.add("read_todos");
729
+ }
730
+ if (configured === false) {
731
+ return requiredNames.size > 0 ? [...requiredNames] : false;
732
+ }
733
+ if (Array.isArray(configured)) {
734
+ return [...new Set([...configured, ...requiredNames])];
735
+ }
736
+ return configured;
737
+ }
703
738
  async materializeAutomaticSummarizationMiddleware(binding) {
704
739
  const assembly = this.createAssemblyResolvers(binding);
705
740
  return materializeAutomaticSummarizationMiddlewareHelper({
@@ -818,12 +853,18 @@ export class AgentRuntimeAdapter {
818
853
  sessionId: options.sessionId ?? options.legacySessionId,
819
854
  }),
820
855
  });
821
- const builtinMiddlewareTools = materializeModelExposedBuiltinMiddlewareTools({
822
- builtinTools: builtinExecutableTools,
823
- explicitToolNames: primaryTools.map((tool) => tool.name),
824
- modelExposed: getBindingBuiltinToolsConfig(binding)?.modelExposed,
825
- });
826
- const providerAliasBuiltinTools = this.materializeProviderAliasBuiltinTools(builtinExecutableTools);
856
+ const modelExposedBuiltins = this.resolveEffectiveModelExposedBuiltins(binding);
857
+ const shouldExposeBuiltinTools = this.shouldExposeBuiltinToolsToModel(binding, primaryTools);
858
+ const builtinMiddlewareTools = shouldExposeBuiltinTools
859
+ ? materializeModelExposedBuiltinMiddlewareTools({
860
+ builtinTools: builtinExecutableTools,
861
+ explicitToolNames: primaryTools.map((tool) => tool.name),
862
+ modelExposed: modelExposedBuiltins,
863
+ })
864
+ : [];
865
+ const providerAliasBuiltinTools = shouldExposeBuiltinTools
866
+ ? this.materializeProviderAliasBuiltinTools(builtinExecutableTools, modelExposedBuiltins)
867
+ : [];
827
868
  const resolvedMiddleware = await this.resolveMiddleware(binding, interruptOn, { sessionId: options.sessionId ?? options.legacySessionId });
828
869
  const resolvedCheckpointer = resolveRunnableCheckpointer(this.options, binding);
829
870
  const resolvedStore = this.options.storeResolver?.(binding);
@@ -870,12 +911,18 @@ export class AgentRuntimeAdapter {
870
911
  sessionId: options.sessionId ?? options.legacySessionId,
871
912
  }),
872
913
  });
873
- const builtinMiddlewareTools = materializeModelExposedBuiltinMiddlewareTools({
874
- builtinTools: builtinExecutableTools,
875
- explicitToolNames: primaryTools.map((tool) => tool.name),
876
- modelExposed: getBindingBuiltinToolsConfig(binding)?.modelExposed,
877
- });
878
- const providerAliasBuiltinTools = this.materializeProviderAliasBuiltinTools(builtinExecutableTools);
914
+ const modelExposedBuiltins = this.resolveEffectiveModelExposedBuiltins(binding);
915
+ const shouldExposeBuiltinTools = this.shouldExposeBuiltinToolsToModel(binding, primaryTools);
916
+ const builtinMiddlewareTools = shouldExposeBuiltinTools
917
+ ? materializeModelExposedBuiltinMiddlewareTools({
918
+ builtinTools: builtinExecutableTools,
919
+ explicitToolNames: primaryTools.map((tool) => tool.name),
920
+ modelExposed: modelExposedBuiltins,
921
+ })
922
+ : [];
923
+ const providerAliasBuiltinTools = shouldExposeBuiltinTools
924
+ ? this.materializeProviderAliasBuiltinTools(builtinExecutableTools, modelExposedBuiltins)
925
+ : [];
879
926
  const modelTools = [
880
927
  ...appendProviderToolCallAliasTools([...resolvedTools, ...builtinMiddlewareTools]),
881
928
  ...providerAliasBuiltinTools,
@@ -118,10 +118,7 @@ export function resolveMissingPlanRecoveryInstruction(params) {
118
118
  if (params.requiresPlan !== true || hasPlanEvidence) {
119
119
  return null;
120
120
  }
121
- if (params.hasToolResultEvidence === true) {
122
- return WRITE_TODOS_REQUIRED_PLAN_INSTRUCTION;
123
- }
124
- return null;
121
+ return WRITE_TODOS_REQUIRED_PLAN_INSTRUCTION;
125
122
  }
126
123
  export function resolveExecutionWithoutToolEvidenceInstruction(request, result) {
127
124
  const assistantText = readTextContent(result).trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.401",
3
+ "version": "0.0.402",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",