@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.
- package/dist/cli/chat-rendering.js +4 -7
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/adapter/flow/execution-context.js +6 -5
- package/dist/runtime/adapter/flow/invocation-flow.js +2 -2
- package/dist/runtime/adapter/flow/stream-runtime.js +12 -2
- package/dist/runtime/adapter/model/model-providers.js +27 -2
- package/dist/runtime/adapter/stream-event-projection.js +12 -1
- package/dist/runtime/adapter/tool/resolved-tool.js +1 -1
- package/dist/runtime/adapter/tool/tool-name-mapping.d.ts +2 -0
- package/dist/runtime/adapter/tool/tool-name-mapping.js +27 -0
- package/dist/runtime/adapter/tool-resolution.d.ts +1 -0
- package/dist/runtime/adapter/tool-resolution.js +28 -1
- package/dist/runtime/agent-runtime-adapter.d.ts +1 -0
- package/dist/runtime/agent-runtime-adapter.js +68 -15
- package/package.json +1 -1
|
@@ -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
|
-
|
|
20
|
-
return "completed";
|
|
21
|
-
}
|
|
22
|
-
return summarizeChatToolError(output);
|
|
19
|
+
return isError ? summarizeChatToolOutput(output, "failed") : summarizeChatToolOutput(output, "completed");
|
|
23
20
|
}
|
|
24
|
-
function
|
|
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) :
|
|
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
|
|
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.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.376";
|
|
2
2
|
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-30";
|
package/dist/package-version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
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
|
-
|
|
40
|
+
primaryTools.length === 0;
|
|
40
41
|
const langChainStreamModel = resolvedLangChainModel && canUseDirectModelStream
|
|
41
42
|
? resolvedLangChainModel
|
|
42
|
-
: resolvedLangChainModel &&
|
|
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,
|
|
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
|
-
|
|
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
|
|
488
|
-
|
|
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
|
-
|
|
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
|
}
|
|
@@ -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
|
|
534
|
-
|
|
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:
|
|
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
|
|
580
|
-
|
|
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:
|
|
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
|