@botbotgo/agent-harness 0.0.373 → 0.0.376

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.
@@ -16,21 +16,18 @@ export function renderChatRequestRunning(input) {
16
16
  return `\n${parts.join(" ")}\n`;
17
17
  }
18
18
  export function summarizeChatToolResult(output, isError) {
19
- if (!isError) {
20
- return "completed";
21
- }
22
- return summarizeChatToolError(output);
19
+ return isError ? summarizeChatToolOutput(output, "failed") : summarizeChatToolOutput(output, "completed");
23
20
  }
24
- function summarizeChatToolError(output) {
21
+ function summarizeChatToolOutput(output, fallback) {
25
22
  if (typeof output === "string") {
26
23
  const trimmed = output.trim();
27
- return trimmed.length > 0 ? truncateChatToolPreview(trimmed, 240) : "failed";
24
+ return trimmed.length > 0 ? truncateChatToolPreview(trimmed, 240) : fallback;
28
25
  }
29
26
  if (typeof output === "number" || typeof output === "boolean") {
30
27
  return String(output);
31
28
  }
32
29
  if (!output || typeof output !== "object") {
33
- return "failed";
30
+ return fallback;
34
31
  }
35
32
  const typed = output;
36
33
  const content = extractChatToolTextContent(output);
@@ -1,2 +1,2 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.373";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.376";
2
2
  export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-30";
@@ -1,2 +1,2 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.373";
1
+ export const AGENT_HARNESS_VERSION = "0.0.376";
2
2
  export const AGENT_HARNESS_RELEASE_DATE = "2026-04-30";
@@ -28,18 +28,19 @@ export function buildBindingToolExecutionContext(input) {
28
28
  export async function resolveLangChainStreamContext(input) {
29
29
  const primaryTools = getBindingPrimaryTools(input.binding);
30
30
  const primaryModel = getBindingPrimaryModel(input.binding);
31
- const forceInvokeFallback = isLangChainBinding(input.binding) &&
32
- primaryTools.length > 0 &&
33
- primaryModel?.provider === "openai-compatible";
34
31
  const resolvedLangChainModel = primaryModel
35
32
  ? (await input.resolveModel(primaryModel))
36
33
  : undefined;
37
34
  const resolvedLangChainTools = primaryTools.length > 0 ? input.resolveTools(primaryTools, input.binding) : [];
35
+ const modelSupportsToolBinding = typeof resolvedLangChainModel?.bindTools === "function";
36
+ const forceInvokeFallback = isLangChainBinding(input.binding) &&
37
+ primaryTools.length > 0 &&
38
+ primaryModel?.provider === "openai-compatible";
38
39
  const canUseDirectModelStream = !!resolvedLangChainModel &&
39
- (resolvedLangChainTools.length === 0 || typeof resolvedLangChainModel.bindTools !== "function");
40
+ primaryTools.length === 0;
40
41
  const langChainStreamModel = resolvedLangChainModel && canUseDirectModelStream
41
42
  ? resolvedLangChainModel
42
- : resolvedLangChainModel && typeof resolvedLangChainModel.bindTools === "function" && resolvedLangChainTools.length > 0
43
+ : resolvedLangChainModel && modelSupportsToolBinding && resolvedLangChainTools.length > 0
43
44
  ? resolvedLangChainModel.bindTools(resolvedLangChainTools)
44
45
  : undefined;
45
46
  return {
@@ -7,7 +7,7 @@ import { UPSTREAM_REQUEST_CONFIG_KEY, UPSTREAM_SESSION_CONFIG_KEY } from "../ups
7
7
  import { appendToolRecoveryInstruction, extractVisibleOutput, tryParseJson } from "../../parsing/output-parsing.js";
8
8
  import { salvageJsonToolCalls } from "../../parsing/output-tool-args.js";
9
9
  import { isEmptyFinalAiMessageError } from "../resilience.js";
10
- import { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, } from "../../prompts/runtime-prompts.js";
10
+ import { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, WRITE_TODOS_REQUIRED_PLAN_INSTRUCTION, } from "../../prompts/runtime-prompts.js";
11
11
  const CLOSE_REQUIRED_PLAN_RECOVERY_INSTRUCTION = [
12
12
  "The current required todo board still has unfinished work.",
13
13
  "Do not broaden the investigation, restart planning, or ask the user what to do next.",
@@ -352,7 +352,7 @@ export async function executeRequestInvocation(options) {
352
352
  ? result.messages
353
353
  : undefined;
354
354
  const recoveryBase = messages ? { messages } : request;
355
- const recoveredRequest = appendToolRecoveryInstruction(recoveryBase, CLOSE_REQUIRED_PLAN_RECOVERY_INSTRUCTION);
355
+ const recoveredRequest = appendToolRecoveryInstruction(recoveryBase, WRITE_TODOS_REQUIRED_PLAN_INSTRUCTION);
356
356
  const recoveredInvocation = await invokeOnce(recoveredRequest);
357
357
  localOrUpstreamInvocation = recoveredInvocation;
358
358
  result = recoveredInvocation.result;
@@ -1,4 +1,4 @@
1
- import { extractVisibleOutput, isToolCallRecoveryFailure, isRetrySafeInvalidToolSelectionError, resolveMissingPlanRecoveryInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, shouldValidateExecutionWithoutToolEvidence, resolveToolCallRecoveryInstruction, sanitizeVisibleText, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, } from "../../parsing/output-parsing.js";
1
+ import { extractVisibleOutput, isToolCallRecoveryFailure, isRetrySafeInvalidToolSelectionError, appendToolRecoveryInstruction, resolveMissingPlanRecoveryInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, shouldValidateExecutionWithoutToolEvidence, resolveToolCallRecoveryInstruction, sanitizeVisibleText, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, } from "../../parsing/output-parsing.js";
2
2
  import { DELEGATED_TASK_FAILURE_RECOVERY_INSTRUCTION, DELEGATION_ONLY_RECOVERY_INSTRUCTION, } from "../../prompts/runtime-prompts.js";
3
3
  import { buildInvocationRequest } from "../model/invocation-request.js";
4
4
  import { buildRawModelMessages } from "../model/message-assembly.js";
@@ -19,6 +19,13 @@ const CLOSE_REQUIRED_PLAN_RECOVERY_INSTRUCTION = [
19
19
  "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.",
20
20
  "After that write_todos call, provide the final answer required by the agent response format.",
21
21
  ].join("\n");
22
+ const INITIAL_REQUIRED_PLAN_INSTRUCTION = [
23
+ "This agent has a required visible planning contract.",
24
+ "Your first action for this request must be write_todos with concrete task steps and statuses.",
25
+ "Do not call any domain/evidence tool and do not provide a final answer before the initial write_todos call succeeds.",
26
+ "Do not use placeholders like '1', '2', '3', 'step 1', or generic labels. Each todo must name the concrete work it represents.",
27
+ "After each evidence step, update the todo board. Before the final answer, close every todo as completed or failed.",
28
+ ].join("\n");
22
29
  function toVisibleContent(value) {
23
30
  const extracted = extractVisibleOutput(value);
24
31
  return extracted ? sanitizeVisibleText(extracted) : "";
@@ -231,7 +238,10 @@ function finishProfileStep(input) {
231
238
  });
232
239
  }
233
240
  export async function* streamRuntimeExecution(options) {
234
- const request = buildInvocationRequest(options.binding, options.history, options.input, options.runtimeOptions);
241
+ let request = buildInvocationRequest(options.binding, options.history, options.input, options.runtimeOptions);
242
+ if (requiresPlanEvidence(options.binding)) {
243
+ request = appendToolRecoveryInstruction(request, INITIAL_REQUIRED_PLAN_INSTRUCTION);
244
+ }
235
245
  let emittedUnsafeStreamSideEffects = false;
236
246
  const shouldProfile = options.runtimeOptions.profiling === true;
237
247
  const shouldValidateStreamOutput = shouldValidateExecutionWithoutToolEvidence(request);
@@ -201,6 +201,30 @@ function hasPriorToolResultForToolName(input, toolName) {
201
201
  }
202
202
  return false;
203
203
  }
204
+ function readBoundToolName(tool) {
205
+ return typeof tool === "object" && tool !== null && typeof tool.name === "string"
206
+ ? tool.name.trim()
207
+ : "";
208
+ }
209
+ function isTodoPlanningToolName(name) {
210
+ return name === "write_todos"
211
+ || name === "read_todos"
212
+ || name === "tool_call_write_todos"
213
+ || name === "tool_call_read_todos";
214
+ }
215
+ function shouldLimitPromptedJsonToolsToPlanning(input) {
216
+ const text = stringifyNodeLlamaCppInput(input);
217
+ return text.includes("required visible planning contract")
218
+ && !hasPriorToolResultForToolName(input, "write_todos")
219
+ && !hasPriorToolResultForToolName(input, "tool_call_write_todos");
220
+ }
221
+ function selectPromptedJsonToolsForTurn(input, boundTools) {
222
+ if (!shouldLimitPromptedJsonToolsToPlanning(input)) {
223
+ return boundTools;
224
+ }
225
+ const planningTools = boundTools.filter((tool) => isTodoPlanningToolName(readBoundToolName(tool)));
226
+ return planningTools.length > 0 ? planningTools : boundTools;
227
+ }
204
228
  function normalizeReadFileToolContent(name, content) {
205
229
  if (name !== "read_file") {
206
230
  return content;
@@ -484,8 +508,9 @@ function createPromptedJsonToolBindableModel(model, boundTools = [], options = {
484
508
  }
485
509
  if (prop === "invoke") {
486
510
  return async (input, config) => {
487
- const rawResult = await target.invoke(boundTools.length > 0 ? withPromptedJsonToolPrompt(input, boundTools, options) : input, config);
488
- if (boundTools.length === 0) {
511
+ const effectiveBoundTools = selectPromptedJsonToolsForTurn(input, boundTools);
512
+ const rawResult = await target.invoke(effectiveBoundTools.length > 0 ? withPromptedJsonToolPrompt(input, effectiveBoundTools, options) : input, config);
513
+ if (effectiveBoundTools.length === 0) {
489
514
  return rawResult;
490
515
  }
491
516
  const text = readModelText(rawResult);
@@ -1,5 +1,6 @@
1
1
  import { extractToolFallbackContext, extractVisibleOutput, readTextContent, sanitizeVisibleText } from "../parsing/output-parsing.js";
2
2
  import { salvageFunctionLikeToolCall } from "../parsing/output-tool-args.js";
3
+ import { isLowSignalTodoContent, summarizeBuiltinWriteTodosArgs } from "./runtime-adapter-support.js";
3
4
  import { computeIncrementalOutput, extractInterruptPayload, extractReasoningStreamOutput, sanitizeRetainedUpstreamEvent, extractStateStreamOutput, extractTerminalStreamOutput, extractToolResult, extractVisibleStreamOutput, normalizeTerminalOutputKey, } from "../parsing/stream-event-parsing.js";
4
5
  import { resolveModelFacingToolName } from "./tool/tool-name-mapping.js";
5
6
  export function createStreamEventProjectionState() {
@@ -299,7 +300,17 @@ function extractTodoToolStart(event) {
299
300
  if (!isToolStart || (toolName !== "write_todos" && toolName !== "read_todos")) {
300
301
  return null;
301
302
  }
302
- return { toolName, input: unwrapPossibleToolInput(typed.data?.input) };
303
+ const input = unwrapPossibleToolInput(typed.data?.input);
304
+ if (toolName === "write_todos" && typeof input === "object" && input !== null && !Array.isArray(input)) {
305
+ const summary = summarizeBuiltinWriteTodosArgs(input);
306
+ if (summary.summary.total === 0) {
307
+ throw new Error("Error invoking tool 'write_todos' with kwargs {\"todos\":[]} with error: Error: Initial write_todos call cannot use an empty todo list. Send the concrete task steps with both content and status.");
308
+ }
309
+ if (summary.items.every((item) => isLowSignalTodoContent(item.content))) {
310
+ throw new Error("Error invoking tool 'write_todos' with placeholder todo content with error: Error: Initial write_todos call must use descriptive task content. Do not use placeholder entries like '1', '2', or 'step 1'.");
311
+ }
312
+ }
313
+ return { toolName, input };
303
314
  }
304
315
  export function projectRuntimeStreamEvent(params) {
305
316
  const { event, allowVisibleStreamDeltas, includeStateStreamOutput, rootAgentId, countConfiguredToolsForAgentId, toolNameMapping, primaryTools, state, } = params;
@@ -217,7 +217,7 @@ export function asStructuredExecutableTool(resolvedTool, modelFacingName, descri
217
217
  if (typeof handler !== "function") {
218
218
  return resolvedTool;
219
219
  }
220
- return createLangChainTool(async (input, config) => handler(input, config), {
220
+ return createLangChainTool(async (input, config) => handler.call(resolvedTool, input, config), {
221
221
  name: modelFacingName,
222
222
  description,
223
223
  schema: normalizeModelFacingToolSchema(resolvedTool),
@@ -2,6 +2,8 @@ export type ToolNameMapping = {
2
2
  originalToModelFacing: Map<string, string>;
3
3
  modelFacingToOriginal: Map<string, string>;
4
4
  };
5
+ export declare function stripProviderToolCallPrefix(toolName: string): string | null;
6
+ export declare function createProviderToolCallAliasName(toolName: string): string;
5
7
  export declare function sanitizeToolNameForModel(name: string): string;
6
8
  export declare function buildToolNameMapping(tools: Array<{
7
9
  name: string;
@@ -1,4 +1,17 @@
1
1
  const MODEL_SAFE_TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
2
+ const PROVIDER_TOOL_CALL_PREFIXES = ["tool_call_", "tool_call.", "tool_call-", "tool.call_", "tool.call.", "tool-call-"];
3
+ export function stripProviderToolCallPrefix(toolName) {
4
+ const trimmed = toolName.trim();
5
+ for (const prefix of PROVIDER_TOOL_CALL_PREFIXES) {
6
+ if (trimmed.startsWith(prefix)) {
7
+ return trimmed.substring(prefix.length);
8
+ }
9
+ }
10
+ return null;
11
+ }
12
+ export function createProviderToolCallAliasName(toolName) {
13
+ return `tool_call_${sanitizeToolNameForModel(toolName)}`;
14
+ }
2
15
  export function sanitizeToolNameForModel(name) {
3
16
  const withoutNamespace = name.includes(".") ? name.split(".").at(-1) ?? name : name;
4
17
  const sanitized = withoutNamespace
@@ -59,16 +72,26 @@ export function createModelFacingToolNameLookupCandidates(toolName) {
59
72
  add(stripped);
60
73
  }
61
74
  };
75
+ const addProviderPrefixStripped = (value) => {
76
+ const stripped = stripProviderToolCallPrefix(value);
77
+ if (stripped) {
78
+ add(stripped);
79
+ addSuffixStripped(stripped);
80
+ }
81
+ };
62
82
  add(trimmed);
83
+ addProviderPrefixStripped(trimmed);
63
84
  if (trimmed.startsWith("functions.")) {
64
85
  const stripped = trimmed.substring("functions.".length);
65
86
  add(stripped);
66
87
  addSuffixStripped(stripped);
88
+ addProviderPrefixStripped(stripped);
67
89
  }
68
90
  else if (trimmed.startsWith("function.")) {
69
91
  const stripped = trimmed.substring("function.".length);
70
92
  add(stripped);
71
93
  addSuffixStripped(stripped);
94
+ addProviderPrefixStripped(stripped);
72
95
  }
73
96
  else {
74
97
  addSuffixStripped(trimmed);
@@ -97,5 +120,9 @@ export function resolveModelFacingToolName(toolName, mapping, tools) {
97
120
  if (candidateMatches.length === 1) {
98
121
  return candidateMatches[0].name;
99
122
  }
123
+ const providerPrefixStripped = stripProviderToolCallPrefix(toolName);
124
+ if (providerPrefixStripped) {
125
+ return sanitizeToolNameForModel(providerPrefixStripped);
126
+ }
100
127
  return toolName;
101
128
  }
@@ -13,3 +13,4 @@ export declare function buildExecutableToolMap(input: {
13
13
  toolConfig?: Record<string, unknown>;
14
14
  context?: Record<string, unknown>;
15
15
  }): Map<string, ExecutableTool>;
16
+ export declare function appendProviderToolCallAliasTools(tools: unknown[]): unknown[];
@@ -1,6 +1,6 @@
1
1
  import { instantiateProviderTool } from "./tool/provider-tool.js";
2
2
  import { asStructuredExecutableTool, hasCallableToolHandler, normalizeResolvedToolSchema, wrapResolvedToolWithModelFacingName, } from "./tool/resolved-tool.js";
3
- import { buildToolNameMapping } from "./tool/tool-name-mapping.js";
3
+ import { buildToolNameMapping, createProviderToolCallAliasName } from "./tool/tool-name-mapping.js";
4
4
  import { wrapToolForExecution } from "./tool/tool-hitl.js";
5
5
  export function resolveAdapterTools(input) {
6
6
  const resolved = input.resolveToolValues ? input.resolveToolValues(input.tools.map((tool) => tool.id), input.binding) : [];
@@ -57,3 +57,30 @@ export function buildExecutableToolMap(input) {
57
57
  }
58
58
  return executableTools;
59
59
  }
60
+ function readResolvedToolName(tool) {
61
+ return typeof tool === "object" && tool !== null && typeof tool.name === "string"
62
+ ? tool.name
63
+ : undefined;
64
+ }
65
+ function readResolvedToolDescription(tool) {
66
+ return typeof tool === "object" && tool !== null && typeof tool.description === "string"
67
+ ? tool.description
68
+ : "";
69
+ }
70
+ export function appendProviderToolCallAliasTools(tools) {
71
+ const existingNames = new Set(tools.map(readResolvedToolName).filter((name) => !!name));
72
+ const aliases = [];
73
+ for (const tool of tools) {
74
+ const name = readResolvedToolName(tool);
75
+ if (!name || !hasCallableToolHandler(tool)) {
76
+ continue;
77
+ }
78
+ const aliasName = createProviderToolCallAliasName(name);
79
+ if (existingNames.has(aliasName)) {
80
+ continue;
81
+ }
82
+ existingNames.add(aliasName);
83
+ aliases.push(asStructuredExecutableTool(tool, aliasName, readResolvedToolDescription(tool) || name));
84
+ }
85
+ return [...tools, ...aliases];
86
+ }
@@ -37,6 +37,7 @@ export declare class AgentRuntimeAdapter {
37
37
  private createAssemblyResolvers;
38
38
  private invokeBuiltinTaskTool;
39
39
  private resolveBuiltinMiddlewareTools;
40
+ private materializeProviderAliasBuiltinTools;
40
41
  private materializeAutomaticSummarizationMiddleware;
41
42
  private resolveLangChainRuntimeExtensionMiddleware;
42
43
  private resolveMiddleware;
@@ -16,7 +16,7 @@ import { extractSubagentRequestText, invokeBuiltinTaskTool as invokeBuiltinTaskT
16
16
  import { isEmptyFinalAiMessageError, resolveBindingTimeout, resolveStreamIdleTimeout, } from "./adapter/resilience.js";
17
17
  import { createResolvedModel } from "./adapter/model/model-providers.js";
18
18
  import { renderDirectWorkspaceListing, shouldDirectlyListWorkspaceFiles } from "./adapter/direct-builtin-utility.js";
19
- import { resolveAdapterTools } from "./adapter/tool-resolution.js";
19
+ import { appendProviderToolCallAliasTools, resolveAdapterTools } from "./adapter/tool-resolution.js";
20
20
  import { resolveRuntimeStreamExecutionContext, } from "./adapter/flow/execution-context.js";
21
21
  import { isRetryableProviderError } from "./adapter/resilience.js";
22
22
  import { UPSTREAM_REQUEST_CONFIG_KEY, UPSTREAM_SESSION_CONFIG_KEY } from "./adapter/upstream-configurable-keys.js";
@@ -153,6 +153,39 @@ function parseCompactRouterSelection(value, subagentNames) {
153
153
  }
154
154
  return null;
155
155
  }
156
+ function inferCompactRouterSelectionFromRequest(requestText, subagents) {
157
+ const normalized = requestText.toLowerCase();
158
+ const score = (subagent) => {
159
+ const name = subagent.name.toLowerCase();
160
+ const description = (subagent.description ?? "").toLowerCase();
161
+ let value = 0;
162
+ if (normalized.includes(name))
163
+ value += 4;
164
+ const keywordGroups = {
165
+ k8s: ["k8s", "kubernetes", "kubectl", "cluster", "pod", "node", "节点", "集群", "调度"],
166
+ software: ["code", "repo", "implementation", "debug", "代码", "仓库", "实现", "配置"],
167
+ ops: ["ci", "cd", "github actions", "disk", "storage", "deploy", "磁盘", "存储", "运维"],
168
+ qa: ["test", "coverage", "regression", "验证", "测试", "回归"],
169
+ release: ["release", "publish", "version", "tag", "发版", "发布", "版本"],
170
+ research: ["research", "web", "latest", "调查资料", "外部", "搜索"],
171
+ secretary: ["summary", "transcript", "youtube", "brief", "摘要", "讲稿", "转写"],
172
+ };
173
+ const keywords = keywordGroups[name] ?? [];
174
+ for (const keyword of keywords) {
175
+ if (normalized.includes(keyword))
176
+ value += description.includes(keyword) || name.includes(keyword) ? 3 : 1;
177
+ }
178
+ return value;
179
+ };
180
+ const ranked = subagents
181
+ .map((subagent) => ({ name: subagent.name, score: score(subagent) }))
182
+ .filter((item) => item.score > 0)
183
+ .sort((left, right) => right.score - left.score);
184
+ if (ranked.length === 0 || (ranked[1] && ranked[1].score === ranked[0].score)) {
185
+ return null;
186
+ }
187
+ return ranked[0].name;
188
+ }
156
189
  function isDelegationOnlyDeepAgentBinding(binding) {
157
190
  return isDeepAgentBinding(binding)
158
191
  && getBindingSubagents(binding).length > 0
@@ -418,6 +451,12 @@ export class AgentRuntimeAdapter {
418
451
  invokeBuiltinTaskTool: assembly.invokeBuiltinTaskTool,
419
452
  });
420
453
  }
454
+ materializeProviderAliasBuiltinTools(builtinTools) {
455
+ const aliasableTools = ["write_todos", "read_todos", "task"]
456
+ .map((name) => builtinTools.get(name))
457
+ .filter((tool) => tool !== undefined);
458
+ return appendProviderToolCallAliasTools(aliasableTools).slice(aliasableTools.length);
459
+ }
421
460
  async materializeAutomaticSummarizationMiddleware(binding) {
422
461
  const assembly = this.createAssemblyResolvers(binding);
423
462
  return materializeAutomaticSummarizationMiddlewareHelper({
@@ -530,16 +569,18 @@ export class AgentRuntimeAdapter {
530
569
  const interruptOn = resolveRunnableInterruptOn(binding);
531
570
  const resolvedModel = await this.resolveModel(primaryModel);
532
571
  const resolvedTools = this.resolveTools(primaryTools, binding);
533
- const builtinMiddlewareTools = materializeModelExposedBuiltinMiddlewareTools({
534
- builtinTools: await this.resolveBuiltinMiddlewareTools(binding, {
572
+ const builtinExecutableTools = await this.resolveBuiltinMiddlewareTools(binding, {
573
+ sessionId: options.sessionId ?? options.legacySessionId,
574
+ toolRuntimeContext: this.buildFunctionToolRuntimeContext(binding, {
535
575
  sessionId: options.sessionId ?? options.legacySessionId,
536
- toolRuntimeContext: this.buildFunctionToolRuntimeContext(binding, {
537
- sessionId: options.sessionId ?? options.legacySessionId,
538
- }),
539
576
  }),
577
+ });
578
+ const builtinMiddlewareTools = materializeModelExposedBuiltinMiddlewareTools({
579
+ builtinTools: builtinExecutableTools,
540
580
  explicitToolNames: primaryTools.map((tool) => tool.name),
541
581
  modelExposed: getBindingBuiltinToolsConfig(binding)?.modelExposed,
542
582
  });
583
+ const providerAliasBuiltinTools = this.materializeProviderAliasBuiltinTools(builtinExecutableTools);
543
584
  const resolvedMiddleware = await this.resolveMiddleware(binding, interruptOn, { sessionId: options.sessionId ?? options.legacySessionId });
544
585
  const resolvedCheckpointer = resolveRunnableCheckpointer(this.options, binding);
545
586
  const resolvedStore = this.options.storeResolver?.(binding);
@@ -547,10 +588,14 @@ export class AgentRuntimeAdapter {
547
588
  if (resolvedTools.length + builtinMiddlewareTools.length > 0 && typeof model.bindTools !== "function") {
548
589
  throw new Error(`Agent ${binding.agent.id} configures ${resolvedTools.length + builtinMiddlewareTools.length} tool(s), but resolved model ${primaryModel.id} does not support tool binding.`);
549
590
  }
591
+ const modelTools = [
592
+ ...appendProviderToolCallAliasTools([...resolvedTools, ...builtinMiddlewareTools]),
593
+ ...providerAliasBuiltinTools,
594
+ ];
550
595
  return createAgent(buildLangChainCreateParams({
551
596
  binding,
552
597
  resolvedModel: model,
553
- resolvedTools: [...resolvedTools, ...builtinMiddlewareTools],
598
+ resolvedTools: modelTools,
554
599
  resolvedMiddleware,
555
600
  resolvedCheckpointer,
556
601
  resolvedStore,
@@ -576,16 +621,22 @@ export class AgentRuntimeAdapter {
576
621
  }
577
622
  const resolvedModel = await this.resolveModel(primaryModel);
578
623
  const resolvedTools = this.resolveTools(primaryTools, binding);
579
- const builtinMiddlewareTools = materializeModelExposedBuiltinMiddlewareTools({
580
- builtinTools: await this.resolveBuiltinMiddlewareTools(binding, {
624
+ const builtinExecutableTools = await this.resolveBuiltinMiddlewareTools(binding, {
625
+ sessionId: options.sessionId ?? options.legacySessionId,
626
+ toolRuntimeContext: this.buildFunctionToolRuntimeContext(binding, {
581
627
  sessionId: options.sessionId ?? options.legacySessionId,
582
- toolRuntimeContext: this.buildFunctionToolRuntimeContext(binding, {
583
- sessionId: options.sessionId ?? options.legacySessionId,
584
- }),
585
628
  }),
629
+ });
630
+ const builtinMiddlewareTools = materializeModelExposedBuiltinMiddlewareTools({
631
+ builtinTools: builtinExecutableTools,
586
632
  explicitToolNames: primaryTools.map((tool) => tool.name),
587
633
  modelExposed: getBindingBuiltinToolsConfig(binding)?.modelExposed,
588
634
  });
635
+ const providerAliasBuiltinTools = this.materializeProviderAliasBuiltinTools(builtinExecutableTools);
636
+ const modelTools = [
637
+ ...appendProviderToolCallAliasTools([...resolvedTools, ...builtinMiddlewareTools]),
638
+ ...providerAliasBuiltinTools,
639
+ ];
589
640
  const resolvedMiddleware = await this.resolveMiddleware(binding);
590
641
  const resolvedSubagents = await this.resolveDeepAgentSubagents(getBindingDeepAgentSubagents(binding), binding, { sessionId: options.sessionId ?? options.legacySessionId });
591
642
  const resolvedInterruptOn = resolveRunnableInterruptOn(binding);
@@ -607,7 +658,7 @@ export class AgentRuntimeAdapter {
607
658
  if (shouldUseConfigurableDeepAgentAssembly(binding)) {
608
659
  return this.createConfigurableDeepAgentRunnable(binding, {
609
660
  resolvedModel,
610
- resolvedTools: [...resolvedTools, ...builtinMiddlewareTools],
661
+ resolvedTools: modelTools,
611
662
  resolvedMiddleware,
612
663
  resolvedSubagents,
613
664
  resolvedInterruptOn,
@@ -828,6 +879,8 @@ export class AgentRuntimeAdapter {
828
879
  }
829
880
  const subagents = getBindingSubagents(binding);
830
881
  const subagentNames = new Set(subagents.map((subagent) => subagent.name));
882
+ const inferredSubagent = inferCompactRouterSelectionFromRequest(requestText, subagents);
883
+ let selection = inferredSubagent ? { subagentType: inferredSubagent } : null;
831
884
  const subagentCatalog = subagents
832
885
  .map((subagent) => `- ${subagent.name}: ${subagent.description}`)
833
886
  .join("\n");
@@ -889,7 +942,6 @@ export class AgentRuntimeAdapter {
889
942
  requestText,
890
943
  ].filter(Boolean).join("\n\n"),
891
944
  ];
892
- let selection = null;
893
945
  let previousRawText = "";
894
946
  for (let index = 0; index < routerPrompts.length && !selection; index += 1) {
895
947
  const activePrompt = index <= 1 || !previousRawText
@@ -1193,6 +1245,8 @@ export class AgentRuntimeAdapter {
1193
1245
  }
1194
1246
  const subagents = getBindingSubagents(binding);
1195
1247
  const subagentNames = new Set(subagents.map((subagent) => subagent.name));
1248
+ const inferredSubagent = inferCompactRouterSelectionFromRequest(requestText, subagents);
1249
+ let selection = inferredSubagent ? { subagentType: inferredSubagent } : null;
1196
1250
  const subagentCatalog = subagents
1197
1251
  .map((subagent) => `- ${subagent.name}: ${subagent.description}`)
1198
1252
  .join("\n");
@@ -1254,7 +1308,6 @@ export class AgentRuntimeAdapter {
1254
1308
  requestText,
1255
1309
  ].filter(Boolean).join("\n\n"),
1256
1310
  ];
1257
- let selection = null;
1258
1311
  let previousRawText = "";
1259
1312
  for (let index = 0; index < routerPrompts.length && !selection; index += 1) {
1260
1313
  const activePrompt = index <= 1 || !previousRawText
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.373",
3
+ "version": "0.0.376",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",