@botbotgo/agent-harness 0.0.350 → 0.0.351

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.350";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.351";
2
2
  export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-24";
@@ -1,2 +1,2 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.350";
1
+ export const AGENT_HARNESS_VERSION = "0.0.351";
2
2
  export const AGENT_HARNESS_RELEASE_DATE = "2026-04-24";
@@ -9,7 +9,7 @@ import { resolveDeclaredMiddleware } from "./tool/declared-middleware.js";
9
9
  import { UPSTREAM_SESSION_CONFIG_KEY } from "./upstream-configurable-keys.js";
10
10
  import { bindingHasLangChainSubagentSupport, bindingHasMiddlewareKind, getBindingBuiltinToolsConfig, getBindingExecutionKind, getBindingGeneralPurposeAgent, getBindingDeepAgentSubagents, getBindingInterruptCompatibilityRules, getBindingMiddlewareConfigs, getBindingMemorySources, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSkills, getBindingSubagents, getBindingTaskDescription, isDeepAgentBinding, isLangChainBinding, } from "../support/compiled-binding.js";
11
11
  import { materializeDeepAgentSkillSourcePaths } from "./compat/deepagent-compat.js";
12
- import { DEFAULT_SUBAGENT_PROMPT } from "../prompts/runtime-prompts.js";
12
+ import { DEFAULT_SUBAGENT_PROMPT, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, } from "../prompts/runtime-prompts.js";
13
13
  import { createContextHygieneMiddleware } from "./middleware/context-hygiene.js";
14
14
  const INVALID_TOOL_MESSAGE_BLOCK_TYPES = new Set(["tool_use", "thinking", "redacted_thinking"]);
15
15
  function extractDeepAgentTaskContent(result) {
@@ -32,6 +32,92 @@ function extractDeepAgentTaskContent(result) {
32
32
  }
33
33
  return undefined;
34
34
  }
35
+ function readMessageType(message) {
36
+ if (typeof message !== "object" || message === null) {
37
+ return "";
38
+ }
39
+ if (typeof message._getType === "function") {
40
+ const typeName = message._getType();
41
+ return typeof typeName === "string" ? typeName : "";
42
+ }
43
+ const typed = message;
44
+ if (typeof typed.type === "string") {
45
+ return typed.type;
46
+ }
47
+ const kwargs = typeof typed.kwargs === "object" && typed.kwargs !== null
48
+ ? typed.kwargs
49
+ : undefined;
50
+ if (typeof kwargs?.type === "string") {
51
+ return kwargs.type;
52
+ }
53
+ const lcKwargs = typeof typed.lc_kwargs === "object" && typed.lc_kwargs !== null
54
+ ? typed.lc_kwargs
55
+ : undefined;
56
+ return typeof lcKwargs?.type === "string" ? lcKwargs.type : "";
57
+ }
58
+ function readMessageName(message) {
59
+ if (typeof message !== "object" || message === null) {
60
+ return "";
61
+ }
62
+ const typed = message;
63
+ if (typeof typed.name === "string") {
64
+ return typed.name;
65
+ }
66
+ const kwargs = typeof typed.kwargs === "object" && typed.kwargs !== null
67
+ ? typed.kwargs
68
+ : undefined;
69
+ if (typeof kwargs?.name === "string") {
70
+ return kwargs.name;
71
+ }
72
+ const lcKwargs = typeof typed.lc_kwargs === "object" && typed.lc_kwargs !== null
73
+ ? typed.lc_kwargs
74
+ : undefined;
75
+ return typeof lcKwargs?.name === "string" ? lcKwargs.name : "";
76
+ }
77
+ function readMessages(result) {
78
+ if (typeof result !== "object" || result === null) {
79
+ return [];
80
+ }
81
+ const messages = result.messages;
82
+ return Array.isArray(messages) ? messages : [];
83
+ }
84
+ function readToolNames(tools) {
85
+ if (!Array.isArray(tools)) {
86
+ return new Set();
87
+ }
88
+ return new Set(tools
89
+ .map((tool) => {
90
+ if (typeof tool !== "object" || tool === null) {
91
+ return "";
92
+ }
93
+ const name = tool.name;
94
+ return typeof name === "string" ? name : "";
95
+ })
96
+ .filter((name) => name.length > 0));
97
+ }
98
+ function hasSubagentExecutionToolEvidence(result, resolvedTools, configuredTools) {
99
+ const requiredToolNames = new Set([
100
+ ...readToolNames(configuredTools),
101
+ ...readToolNames(resolvedTools),
102
+ ]);
103
+ if (requiredToolNames.size === 0) {
104
+ return true;
105
+ }
106
+ for (const message of readMessages(result)) {
107
+ const typeName = readMessageType(message);
108
+ if (typeName !== "tool" && typeName !== "ToolMessage") {
109
+ continue;
110
+ }
111
+ const name = readMessageName(message);
112
+ if (name === "write_todos" || name === "read_todos") {
113
+ continue;
114
+ }
115
+ if (requiredToolNames.has(name)) {
116
+ return true;
117
+ }
118
+ }
119
+ return false;
120
+ }
35
121
  export function extractSubagentRequestText(state) {
36
122
  if (!isRecord(state)) {
37
123
  return "";
@@ -257,6 +343,7 @@ export async function invokeBuiltinTaskTool(input) {
257
343
  const builtinBackend = input.resolveBuiltinMiddlewareBackend(input.binding, input.options);
258
344
  const resolvedSubagents = await input.resolveSubagents(compiledSubagents, input.binding);
259
345
  const selectedSubagent = resolvedSubagents.find((subagent) => subagent.name === subagentType);
346
+ const selectedCompiledSubagent = compiledSubagents.find((subagent) => subagent.name === subagentType);
260
347
  if (!selectedSubagent) {
261
348
  const allowed = resolvedSubagents.map((subagent) => subagent.name);
262
349
  throw new Error(`Error: invoked agent of type ${subagentType}, the only allowed types are ${allowed.map((name) => `\`${name}\``).join(", ")}`);
@@ -282,9 +369,16 @@ export async function invokeBuiltinTaskTool(input) {
282
369
  configurable: { [UPSTREAM_SESSION_CONFIG_KEY]: `${input.binding.agent.id}:builtin-task` },
283
370
  ...(input.options?.context ? { context: input.options.context } : {}),
284
371
  };
285
- const result = await runnable.invoke({
286
- messages: [new HumanMessage({ content: description })],
372
+ const invokeSubagent = (content) => runnable.invoke({
373
+ messages: [new HumanMessage({ content })],
287
374
  }, invokeConfig);
375
+ let result = await invokeSubagent(description);
376
+ if (!hasSubagentExecutionToolEvidence(result, resolvedSubagentTools, selectedCompiledSubagent?.tools)) {
377
+ result = await invokeSubagent([description, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"));
378
+ if (!hasSubagentExecutionToolEvidence(result, resolvedSubagentTools, selectedCompiledSubagent?.tools)) {
379
+ throw new Error(`Delegated agent ${selectedSubagent.name} completed without tool execution evidence.`);
380
+ }
381
+ }
288
382
  const structuredResponse = typeof result === "object" && result !== null && "structuredResponse" in result
289
383
  ? result.structuredResponse
290
384
  : undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.350",
3
+ "version": "0.0.351",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",