@botbotgo/agent-harness 0.0.416 → 0.0.419
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/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/adapter/compat/openai-compatible.js +12 -0
- package/dist/runtime/adapter/flow/invocation-flow.d.ts +2 -0
- package/dist/runtime/adapter/flow/invocation-flow.js +13 -5
- package/dist/runtime/adapter/flow/invoke-runtime.d.ts +1 -0
- package/dist/runtime/adapter/flow/invoke-runtime.js +1 -0
- package/dist/runtime/adapter/flow/stream-runtime.d.ts +4 -0
- package/dist/runtime/adapter/flow/stream-runtime.js +177 -14
- package/dist/runtime/adapter/invocation-result.js +17 -6
- package/dist/runtime/adapter/local-tool-invocation.d.ts +2 -1
- package/dist/runtime/adapter/local-tool-invocation.js +241 -21
- package/dist/runtime/adapter/model/model-providers.js +261 -58
- package/dist/runtime/adapter/model/prompted-json-tool-call-capture.d.ts +9 -0
- package/dist/runtime/adapter/model/prompted-json-tool-call-capture.js +40 -0
- package/dist/runtime/adapter/runtime-adapter-support.js +58 -12
- package/dist/runtime/adapter/runtime-shell.js +3 -2
- package/dist/runtime/adapter/stream-event-projection.js +22 -5
- package/dist/runtime/adapter/tool/tool-arguments.js +157 -67
- package/dist/runtime/adapter/tool/tool-replay.js +0 -4
- package/dist/runtime/agent-runtime-adapter.d.ts +3 -0
- package/dist/runtime/agent-runtime-adapter.js +217 -73
- package/dist/runtime/harness/run/stream-run.js +20 -1
- package/dist/workspace/resource-compilers.js +17 -4
- package/package.json +1 -1
|
@@ -382,6 +382,24 @@ function updateDelegationState(state, event, countConfiguredToolsForAgentId) {
|
|
|
382
382
|
}
|
|
383
383
|
}
|
|
384
384
|
}
|
|
385
|
+
function normalizePlanToolName(toolName) {
|
|
386
|
+
return typeof toolName === "string" ? toolName.trim().toLowerCase().replace(/[\s-]+/gu, "_") : "";
|
|
387
|
+
}
|
|
388
|
+
function isPlanToolName(toolName) {
|
|
389
|
+
const normalized = normalizePlanToolName(toolName);
|
|
390
|
+
return normalized === "write_todos"
|
|
391
|
+
|| normalized === "read_todos"
|
|
392
|
+
|| normalized === "tool_call_write_todos"
|
|
393
|
+
|| normalized === "tool_call_read_todos"
|
|
394
|
+
|| normalized === "call_write_todos"
|
|
395
|
+
|| normalized === "call_read_todos";
|
|
396
|
+
}
|
|
397
|
+
function isWriteTodosToolName(toolName) {
|
|
398
|
+
const normalized = normalizePlanToolName(toolName);
|
|
399
|
+
return normalized === "write_todos"
|
|
400
|
+
|| normalized === "tool_call_write_todos"
|
|
401
|
+
|| normalized === "call_write_todos";
|
|
402
|
+
}
|
|
385
403
|
function extractTodoToolStart(event) {
|
|
386
404
|
if (typeof event !== "object" || event === null) {
|
|
387
405
|
return null;
|
|
@@ -391,11 +409,11 @@ function extractTodoToolStart(event) {
|
|
|
391
409
|
const runType = typeof typed.run_type === "string" ? typed.run_type : "";
|
|
392
410
|
const toolName = typeof typed.name === "string" ? typed.name : "";
|
|
393
411
|
const isToolStart = eventName === "on_tool_start" || (eventName === "on_chain_start" && runType === "tool");
|
|
394
|
-
if (!isToolStart || (toolName
|
|
412
|
+
if (!isToolStart || !isPlanToolName(toolName)) {
|
|
395
413
|
return null;
|
|
396
414
|
}
|
|
397
415
|
const input = unwrapPossibleToolInput(typed.data?.input);
|
|
398
|
-
if (toolName
|
|
416
|
+
if (isWriteTodosToolName(toolName) && typeof input === "object" && input !== null && !Array.isArray(input)) {
|
|
399
417
|
const summary = summarizeBuiltinWriteTodosArgs(input);
|
|
400
418
|
if (summary.summary.total === 0) {
|
|
401
419
|
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.");
|
|
@@ -472,7 +490,7 @@ export function projectRuntimeStreamEvent(params) {
|
|
|
472
490
|
});
|
|
473
491
|
}
|
|
474
492
|
if (toolResult) {
|
|
475
|
-
const isTodoTool = toolResult.toolName
|
|
493
|
+
const isTodoTool = isPlanToolName(toolResult.toolName);
|
|
476
494
|
const salvagedTaskErrorFindings = toolResult.toolName === "task"
|
|
477
495
|
&& toolResult.isError === true
|
|
478
496
|
&& !!state.lastCompletedTaskDelegationFindings
|
|
@@ -485,8 +503,7 @@ export function projectRuntimeStreamEvent(params) {
|
|
|
485
503
|
: toolResult.isError === true;
|
|
486
504
|
const isSuccessfulTaskResult = toolResult.toolName === "task" && effectiveToolIsError !== true;
|
|
487
505
|
const isDelegatedExecutionTool = (isDelegatedAgentEvent || state.openToolCapableTaskDelegations > 0)
|
|
488
|
-
&& toolResult.toolName
|
|
489
|
-
&& toolResult.toolName !== "read_todos"
|
|
506
|
+
&& !isPlanToolName(toolResult.toolName)
|
|
490
507
|
&& toolResult.toolName !== "task";
|
|
491
508
|
if (isDelegatedExecutionTool && toolResult.isError !== true) {
|
|
492
509
|
recordDelegatedFindings(state, toolResult.output, "tool");
|
|
@@ -2,6 +2,7 @@ import { salvageToolArgs } from "../../parsing/output-parsing.js";
|
|
|
2
2
|
import { salvageJsonToolCalls } from "../../parsing/output-tool-args.js";
|
|
3
3
|
import { isRecord } from "../../../utils/object.js";
|
|
4
4
|
import { extractExplicitResourceReferences, hasExplicitResourceReference } from "../../harness/system/runtime-memory-policy.js";
|
|
5
|
+
import { readCapturedPromptedJsonToolCalls } from "../model/prompted-json-tool-call-capture.js";
|
|
5
6
|
function isObject(value) {
|
|
6
7
|
return isRecord(value);
|
|
7
8
|
}
|
|
@@ -109,6 +110,71 @@ function fillLatestUserInputForQueryLikeFields(args, shape, latestUserInput) {
|
|
|
109
110
|
}
|
|
110
111
|
return next;
|
|
111
112
|
}
|
|
113
|
+
function mapCommonArgumentAliases(args, shape) {
|
|
114
|
+
let next = args;
|
|
115
|
+
if ("args" in shape && !("args" in next) && Array.isArray(next.argv)) {
|
|
116
|
+
next = { ...next, args: next.argv };
|
|
117
|
+
}
|
|
118
|
+
if ("arguments" in shape && !("arguments" in next) && Array.isArray(next.args)) {
|
|
119
|
+
next = { ...next, arguments: next.args };
|
|
120
|
+
}
|
|
121
|
+
return next;
|
|
122
|
+
}
|
|
123
|
+
function schemaPartExpectsArray(schemaPart) {
|
|
124
|
+
if (!isObject(schemaPart)) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
if (schemaPart.type === "array") {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
const def = schemaPart._def;
|
|
131
|
+
if (def?.typeName === "ZodArray" || def?.type === "array") {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return schemaPartExpectsArray(def?.innerType);
|
|
135
|
+
}
|
|
136
|
+
function mapStringArrayFields(args, shape) {
|
|
137
|
+
let next = args;
|
|
138
|
+
for (const [key, schemaPart] of Object.entries(shape)) {
|
|
139
|
+
const value = next[key];
|
|
140
|
+
if (typeof value !== "string") {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const raw = value.trim();
|
|
144
|
+
if (!raw) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const looksLikeDelimitedList = /[,;\n]/u.test(raw) && /(?:s|list|items|areas|paths|files)$/iu.test(key);
|
|
148
|
+
if (!schemaPartExpectsArray(schemaPart) && !looksLikeDelimitedList) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const items = raw
|
|
152
|
+
.split(/[,;\n]/u)
|
|
153
|
+
.map((item) => item.trim())
|
|
154
|
+
.filter(Boolean);
|
|
155
|
+
if (items.length > 0) {
|
|
156
|
+
next = { ...next, [key]: items };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return next;
|
|
160
|
+
}
|
|
161
|
+
function mapDelimitedListLikeArgs(args) {
|
|
162
|
+
let next = args;
|
|
163
|
+
for (const [key, value] of Object.entries(args)) {
|
|
164
|
+
if (typeof value !== "string") {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const raw = value.trim();
|
|
168
|
+
if (!/[,;\n]/u.test(raw) || !/(?:s|list|items|areas|paths|files)$/iu.test(key)) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const items = raw.split(/[,;\n]/u).map((item) => item.trim()).filter(Boolean);
|
|
172
|
+
if (items.length > 0) {
|
|
173
|
+
next = { ...next, [key]: items };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return next;
|
|
177
|
+
}
|
|
112
178
|
export function normalizeToolArgsForSchema(args, schema, rawArgsInput, options = {}) {
|
|
113
179
|
const schemaDef = isObject(schema) ? schema._def : undefined;
|
|
114
180
|
const zodShape = schemaDef
|
|
@@ -123,17 +189,18 @@ export function normalizeToolArgsForSchema(args, schema, rawArgsInput, options =
|
|
|
123
189
|
: undefined;
|
|
124
190
|
const shape = zodShape && isRecord(zodShape) ? zodShape : jsonShape;
|
|
125
191
|
if (!shape || !isRecord(shape)) {
|
|
126
|
-
return args;
|
|
192
|
+
return mapDelimitedListLikeArgs(args);
|
|
127
193
|
}
|
|
194
|
+
const aliasMappedArgs = mapStringArrayFields(mapCommonArgumentAliases(args, shape), shape);
|
|
128
195
|
const keys = Object.keys(shape);
|
|
129
196
|
if (keys.length !== 1) {
|
|
130
|
-
return fillLatestUserInputForQueryLikeFields(
|
|
197
|
+
return fillLatestUserInputForQueryLikeFields(aliasMappedArgs, shape, options.latestUserInput);
|
|
131
198
|
}
|
|
132
199
|
const [expectedKey] = keys;
|
|
133
|
-
if (expectedKey in
|
|
134
|
-
return
|
|
200
|
+
if (expectedKey in aliasMappedArgs) {
|
|
201
|
+
return aliasMappedArgs;
|
|
135
202
|
}
|
|
136
|
-
const scalarMappedArgs = mapSingleFieldScalarArg(
|
|
203
|
+
const scalarMappedArgs = mapSingleFieldScalarArg(aliasMappedArgs, expectedKey, rawArgsInput);
|
|
137
204
|
if (expectedKey in scalarMappedArgs) {
|
|
138
205
|
return scalarMappedArgs;
|
|
139
206
|
}
|
|
@@ -154,67 +221,90 @@ export function normalizeToolArgsForSchema(args, schema, rawArgsInput, options =
|
|
|
154
221
|
return genericScalarMappedArgs;
|
|
155
222
|
}
|
|
156
223
|
export function extractToolCallsFromResult(result) {
|
|
224
|
+
const capturedToolCalls = readCapturedPromptedJsonToolCalls(result);
|
|
225
|
+
if (capturedToolCalls.length > 0) {
|
|
226
|
+
return [capturedToolCalls[capturedToolCalls.length - 1]];
|
|
227
|
+
}
|
|
157
228
|
const messages = isRecord(result) && Array.isArray(result.messages) ? result.messages : [];
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (!isObject(
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
const
|
|
174
|
-
const
|
|
175
|
-
?
|
|
176
|
-
:
|
|
177
|
-
?
|
|
178
|
-
:
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
?
|
|
210
|
-
:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
229
|
+
const answeredToolCallIds = new Set();
|
|
230
|
+
for (const message of messages) {
|
|
231
|
+
if (!isObject(message)) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
const id = message.tool_call_id;
|
|
235
|
+
if (typeof id === "string" && id.length > 0) {
|
|
236
|
+
answeredToolCallIds.add(id);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
240
|
+
const message = messages[index];
|
|
241
|
+
if (!isObject(message)) {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const messageKwargs = isObject(message.kwargs) ? message.kwargs : undefined;
|
|
245
|
+
const rawToolCalls = Array.isArray(message.tool_calls)
|
|
246
|
+
? (message.tool_calls ?? [])
|
|
247
|
+
: Array.isArray(messageKwargs?.tool_calls)
|
|
248
|
+
? messageKwargs.tool_calls
|
|
249
|
+
: [];
|
|
250
|
+
const extracted = rawToolCalls
|
|
251
|
+
.map((toolCall) => {
|
|
252
|
+
if (!isObject(toolCall)) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
const functionPayload = isObject(toolCall.function) ? toolCall.function : undefined;
|
|
256
|
+
const name = typeof toolCall.name === "string"
|
|
257
|
+
? toolCall.name
|
|
258
|
+
: typeof functionPayload?.name === "string"
|
|
259
|
+
? functionPayload.name
|
|
260
|
+
: null;
|
|
261
|
+
if (!name) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
const rawArgsInput = toolCall.args ?? functionPayload?.arguments;
|
|
265
|
+
const rawArgs = salvageToolArgs(rawArgsInput) ?? {};
|
|
266
|
+
if (!isObject(rawArgs)) {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
const id = typeof toolCall.id === "string" ? toolCall.id : undefined;
|
|
270
|
+
if (id && answeredToolCallIds.has(id)) {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
return { id, name, args: rawArgs, rawArgsInput };
|
|
274
|
+
})
|
|
275
|
+
.filter((item) => item !== null);
|
|
276
|
+
if (extracted.length > 0) {
|
|
277
|
+
return extracted;
|
|
278
|
+
}
|
|
279
|
+
const directRole = typeof message.role === "string"
|
|
280
|
+
? message.role.trim().toLowerCase()
|
|
281
|
+
: undefined;
|
|
282
|
+
const messageType = typeof message._getType === "function"
|
|
283
|
+
? String(message._getType())
|
|
284
|
+
: undefined;
|
|
285
|
+
const constructorType = Array.isArray(message.id)
|
|
286
|
+
? message.id.at(-1)
|
|
287
|
+
: undefined;
|
|
288
|
+
if (directRole === "tool" || messageType === "tool" || constructorType === "ToolMessage") {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
const content = typeof message.content === "string"
|
|
292
|
+
? message.content
|
|
293
|
+
: typeof messageKwargs?.content === "string"
|
|
294
|
+
? messageKwargs.content
|
|
295
|
+
: "";
|
|
296
|
+
if (!content.trim()) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
const salvaged = salvageJsonToolCalls(content);
|
|
300
|
+
if (salvaged.length > 0) {
|
|
301
|
+
return salvaged.map((toolCall, salvageIndex) => ({
|
|
302
|
+
id: `salvaged-json-${salvageIndex + 1}`,
|
|
303
|
+
name: toolCall.name,
|
|
304
|
+
args: toolCall.args,
|
|
305
|
+
rawArgsInput: content,
|
|
306
|
+
}));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return [];
|
|
220
310
|
}
|
|
@@ -12,10 +12,6 @@ export function canReplayToolCallsLocally(binding, toolCalls, primaryTools, tool
|
|
|
12
12
|
if (resolvedToolName === "task" || toolCall.name === "task") {
|
|
13
13
|
return false;
|
|
14
14
|
}
|
|
15
|
-
const executable = executableTools.get(toolCall.name) ?? executableTools.get(resolvedToolName);
|
|
16
|
-
if (executable) {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
15
|
const builtinExecutable = builtinExecutableTools.get(toolCall.name) ??
|
|
20
16
|
builtinExecutableTools.get(resolvedToolName) ??
|
|
21
17
|
createModelFacingToolNameLookupCandidates(toolCall.name)
|
|
@@ -59,6 +59,9 @@ export declare class AgentRuntimeAdapter {
|
|
|
59
59
|
state?: Record<string, unknown>;
|
|
60
60
|
files?: Record<string, unknown>;
|
|
61
61
|
memoryContext?: string;
|
|
62
|
+
toolRuntimeContext?: Record<string, unknown>;
|
|
63
|
+
suppressInitialRequiredPlanInstruction?: boolean;
|
|
64
|
+
externalPlanEvidence?: boolean;
|
|
62
65
|
}): Promise<RequestResult>;
|
|
63
66
|
private tryDelegateWithCompactRouter;
|
|
64
67
|
private buildCompactDelegationReport;
|