@botbotgo/agent-harness 0.0.463 → 0.0.465
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/resources/prompts/runtime/write-todos-full-entry.md +1 -1
- package/dist/runtime/adapter/flow/stream-runtime.js +101 -6
- package/dist/runtime/adapter/invocation-result.js +15 -2
- package/dist/runtime/adapter/local-tool-invocation.js +49 -1
- package/dist/runtime/adapter/runtime-adapter-support.d.ts +0 -1
- package/dist/runtime/adapter/runtime-adapter-support.js +10 -7
- package/dist/runtime/adapter/stream-event-projection.d.ts +1 -0
- package/dist/runtime/adapter/stream-event-projection.js +75 -16
- package/dist/runtime/adapter/tool/builtin-middleware-tools.js +1 -9
- package/dist/runtime/adapter/tool/tool-arguments.js +145 -10
- package/dist/runtime/agent-runtime-adapter.d.ts +12 -0
- package/dist/runtime/agent-runtime-adapter.js +217 -29
- package/dist/runtime/parsing/output-recovery.js +2 -1
- package/dist/runtime/parsing/output-tool-args.js +20 -1
- package/dist/runtime/parsing/stream-event-parsing.js +0 -32
- package/package.json +1 -1
|
@@ -86,6 +86,19 @@ function readSchemaDescription(schemaPart) {
|
|
|
86
86
|
}
|
|
87
87
|
return readSchemaDescription(def?.innerType);
|
|
88
88
|
}
|
|
89
|
+
function schemaPartExpectsString(schemaPart) {
|
|
90
|
+
if (!isObject(schemaPart)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
if (schemaPart.type === "string") {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
const def = schemaPart._def ?? schemaPart.def;
|
|
97
|
+
if (def?.typeName === "ZodString" || def?.type === "string") {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
return schemaPartExpectsString(def?.innerType);
|
|
101
|
+
}
|
|
89
102
|
function fillLatestUserInputForQueryLikeFields(args, shape, latestUserInput) {
|
|
90
103
|
const userInput = typeof latestUserInput === "string" ? latestUserInput.trim() : "";
|
|
91
104
|
if (!userInput) {
|
|
@@ -100,7 +113,7 @@ function fillLatestUserInputForQueryLikeFields(args, shape, latestUserInput) {
|
|
|
100
113
|
const description = readSchemaDescription(schemaPart);
|
|
101
114
|
const keyIsQueryLike = ["query", "question", "prompt", "input", "text"].includes(normalizedKey);
|
|
102
115
|
const descriptionIsQueryLike = /\b(?:query|question|prompt|input|text)\b/iu.test(description);
|
|
103
|
-
if (!keyIsQueryLike && !descriptionIsQueryLike) {
|
|
116
|
+
if ((!keyIsQueryLike && !descriptionIsQueryLike) || !schemaPartExpectsString(schemaPart)) {
|
|
104
117
|
continue;
|
|
105
118
|
}
|
|
106
119
|
next = {
|
|
@@ -110,6 +123,27 @@ function fillLatestUserInputForQueryLikeFields(args, shape, latestUserInput) {
|
|
|
110
123
|
}
|
|
111
124
|
return next;
|
|
112
125
|
}
|
|
126
|
+
function fillLatestUserInputForResourceArrayFields(args, shape, latestUserInput) {
|
|
127
|
+
const userInput = typeof latestUserInput === "string" ? latestUserInput.trim() : "";
|
|
128
|
+
if (!userInput || !hasExplicitResourceReference(userInput)) {
|
|
129
|
+
return args;
|
|
130
|
+
}
|
|
131
|
+
const resourceRefs = extractExplicitResourceReferences(userInput);
|
|
132
|
+
if (resourceRefs.length === 0) {
|
|
133
|
+
return args;
|
|
134
|
+
}
|
|
135
|
+
let next = args;
|
|
136
|
+
for (const [key, schemaPart] of Object.entries(shape)) {
|
|
137
|
+
if (key in next || !schemaPartExpectsArray(schemaPart)) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const mapped = resourceRefs.map((ref) => inferDiscriminatedArrayObjectFromString(schemaPart, ref));
|
|
141
|
+
if (mapped.length > 0 && mapped.every((item) => item !== null)) {
|
|
142
|
+
next = { ...next, [key]: mapped };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return next;
|
|
146
|
+
}
|
|
113
147
|
function mapCommonArgumentAliases(args, shape) {
|
|
114
148
|
let next = args;
|
|
115
149
|
if ("args" in shape && !("args" in next) && Array.isArray(next.argv)) {
|
|
@@ -133,10 +167,96 @@ function schemaPartExpectsArray(schemaPart) {
|
|
|
133
167
|
}
|
|
134
168
|
return schemaPartExpectsArray(def?.innerType);
|
|
135
169
|
}
|
|
170
|
+
function readObjectShape(schemaPart) {
|
|
171
|
+
if (!isObject(schemaPart)) {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
const def = schemaPart._def ?? schemaPart.def;
|
|
175
|
+
if (!def) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
179
|
+
return isRecord(shape) ? shape : readObjectShape(def.innerType);
|
|
180
|
+
}
|
|
181
|
+
function readLiteralValue(schemaPart) {
|
|
182
|
+
if (!isObject(schemaPart)) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
const def = schemaPart._def ?? schemaPart.def;
|
|
186
|
+
if ((def?.typeName === "ZodLiteral" || def?.type === "literal") && typeof def.value === "string") {
|
|
187
|
+
return def.value;
|
|
188
|
+
}
|
|
189
|
+
if ((def?.typeName === "ZodLiteral" || def?.type === "literal") && Array.isArray(def.values) && typeof def.values[0] === "string") {
|
|
190
|
+
return def.values[0];
|
|
191
|
+
}
|
|
192
|
+
return readLiteralValue(def?.innerType);
|
|
193
|
+
}
|
|
194
|
+
function readArrayElementSchema(schemaPart) {
|
|
195
|
+
if (!isObject(schemaPart)) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
const def = schemaPart._def ?? schemaPart.def;
|
|
199
|
+
if (def?.typeName === "ZodArray" || def?.type === "array") {
|
|
200
|
+
return def.element ?? def.type;
|
|
201
|
+
}
|
|
202
|
+
return readArrayElementSchema(def?.innerType);
|
|
203
|
+
}
|
|
204
|
+
function inferDiscriminatedArrayObjectFromString(schemaPart, value) {
|
|
205
|
+
const raw = value.trim();
|
|
206
|
+
if (!raw) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
const elementSchema = readArrayElementSchema(schemaPart);
|
|
210
|
+
if (!isObject(elementSchema)) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
const def = elementSchema._def ?? elementSchema.def;
|
|
214
|
+
const options = Array.isArray(def?.options)
|
|
215
|
+
? def.options
|
|
216
|
+
: Array.isArray(elementSchema.options)
|
|
217
|
+
? elementSchema.options
|
|
218
|
+
: undefined;
|
|
219
|
+
if (def?.typeName !== "ZodDiscriminatedUnion"
|
|
220
|
+
&& !(def?.type === "union" && typeof def.discriminator === "string")) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
if (typeof def.discriminator !== "string" || !options) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
const looksLikeUrl = /^https?:\/\/\S+$/iu.test(raw);
|
|
227
|
+
for (const option of options) {
|
|
228
|
+
const optionShape = readObjectShape(option);
|
|
229
|
+
if (!optionShape) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const discriminatorValue = readLiteralValue(optionShape[def.discriminator]);
|
|
233
|
+
if (!discriminatorValue) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (looksLikeUrl && "url" in optionShape) {
|
|
237
|
+
return { [def.discriminator]: discriminatorValue, url: raw };
|
|
238
|
+
}
|
|
239
|
+
const looksLikePath = /^(?:\.{1,2}\/|\/|~\/|[A-Za-z]:[\\/])|\\|\.[A-Za-z0-9]{1,12}$/u.test(raw);
|
|
240
|
+
if (!looksLikeUrl && looksLikePath && "path" in optionShape && !raw.includes("\n")) {
|
|
241
|
+
return { [def.discriminator]: discriminatorValue, path: raw };
|
|
242
|
+
}
|
|
243
|
+
if ("text" in optionShape) {
|
|
244
|
+
return { [def.discriminator]: discriminatorValue, text: raw };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
136
249
|
function mapStringArrayFields(args, shape) {
|
|
137
250
|
let next = args;
|
|
138
251
|
for (const [key, schemaPart] of Object.entries(shape)) {
|
|
139
252
|
const value = next[key];
|
|
253
|
+
if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
|
|
254
|
+
const mapped = value.map((item) => inferDiscriminatedArrayObjectFromString(schemaPart, item));
|
|
255
|
+
if (mapped.length > 0 && mapped.every((item) => item !== null)) {
|
|
256
|
+
next = { ...next, [key]: mapped };
|
|
257
|
+
}
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
140
260
|
if (typeof value !== "string") {
|
|
141
261
|
continue;
|
|
142
262
|
}
|
|
@@ -175,6 +295,9 @@ function mapDelimitedListLikeArgs(args) {
|
|
|
175
295
|
}
|
|
176
296
|
return next;
|
|
177
297
|
}
|
|
298
|
+
function stripArgsToShape(args, shape) {
|
|
299
|
+
return Object.fromEntries(Object.entries(args).filter(([key]) => key in shape));
|
|
300
|
+
}
|
|
178
301
|
function dropDelimitedScalarPathArgs(args, shape) {
|
|
179
302
|
let next = args;
|
|
180
303
|
for (const [key, schemaPart] of Object.entries(shape)) {
|
|
@@ -199,7 +322,10 @@ function dropDelimitedScalarPathArgs(args, shape) {
|
|
|
199
322
|
return next;
|
|
200
323
|
}
|
|
201
324
|
export function normalizeToolArgsForSchema(args, schema, rawArgsInput, options = {}) {
|
|
202
|
-
const schemaDef = isObject(schema)
|
|
325
|
+
const schemaDef = isObject(schema)
|
|
326
|
+
? (schema._def
|
|
327
|
+
?? schema.def)
|
|
328
|
+
: undefined;
|
|
203
329
|
const zodShape = schemaDef
|
|
204
330
|
? isRecord(schemaDef.shape)
|
|
205
331
|
? schemaDef.shape
|
|
@@ -210,38 +336,47 @@ export function normalizeToolArgsForSchema(args, schema, rawArgsInput, options =
|
|
|
210
336
|
const jsonShape = isObject(schema) && isRecord(schema.properties)
|
|
211
337
|
? (schema.properties ?? undefined)
|
|
212
338
|
: undefined;
|
|
213
|
-
const
|
|
339
|
+
const plainShape = isObject(schema)
|
|
340
|
+
&& !("_def" in schema)
|
|
341
|
+
&& !("properties" in schema)
|
|
342
|
+
&& Object.values(schema).every((value) => isObject(value))
|
|
343
|
+
? schema
|
|
344
|
+
: undefined;
|
|
345
|
+
const shape = zodShape && isRecord(zodShape) ? zodShape : jsonShape ?? plainShape;
|
|
214
346
|
if (!shape || !isRecord(shape)) {
|
|
215
347
|
return mapDelimitedListLikeArgs(args);
|
|
216
348
|
}
|
|
217
|
-
const
|
|
349
|
+
const stripUnknownArgs = plainShape !== undefined && !zodShape && !jsonShape;
|
|
350
|
+
const aliasMappedArgs = dropDelimitedScalarPathArgs(fillLatestUserInputForResourceArrayFields(mapStringArrayFields(mapCommonArgumentAliases(args, shape), shape), shape, options.latestUserInput), shape);
|
|
218
351
|
const keys = Object.keys(shape);
|
|
219
352
|
if (keys.length !== 1) {
|
|
220
|
-
|
|
353
|
+
const filled = fillLatestUserInputForQueryLikeFields(aliasMappedArgs, shape, options.latestUserInput);
|
|
354
|
+
return stripUnknownArgs ? stripArgsToShape(filled, shape) : filled;
|
|
221
355
|
}
|
|
222
356
|
const [expectedKey] = keys;
|
|
223
357
|
if (expectedKey in aliasMappedArgs) {
|
|
224
|
-
return aliasMappedArgs;
|
|
358
|
+
return stripUnknownArgs ? stripArgsToShape(aliasMappedArgs, shape) : aliasMappedArgs;
|
|
225
359
|
}
|
|
226
360
|
const scalarMappedArgs = mapSingleFieldScalarArg(aliasMappedArgs, expectedKey, rawArgsInput);
|
|
227
361
|
if (expectedKey in scalarMappedArgs) {
|
|
228
|
-
return scalarMappedArgs;
|
|
362
|
+
return stripUnknownArgs ? stripArgsToShape(scalarMappedArgs, shape) : scalarMappedArgs;
|
|
229
363
|
}
|
|
230
364
|
if (Object.keys(scalarMappedArgs).length === 0 && typeof options.latestUserInput === "string") {
|
|
231
365
|
const userInput = options.latestUserInput.trim();
|
|
232
366
|
const resourceRefs = extractExplicitResourceReferences(userInput);
|
|
233
367
|
if (resourceRefs.length === 1 && hasExplicitResourceReference(userInput)) {
|
|
234
|
-
|
|
368
|
+
const filled = {
|
|
235
369
|
...scalarMappedArgs,
|
|
236
370
|
[expectedKey]: resourceRefs[0],
|
|
237
371
|
};
|
|
372
|
+
return stripUnknownArgs ? stripArgsToShape(filled, shape) : filled;
|
|
238
373
|
}
|
|
239
374
|
}
|
|
240
375
|
const genericScalarMappedArgs = mapSingleRemainingScalarArg(scalarMappedArgs, expectedKey);
|
|
241
376
|
if (expectedKey in genericScalarMappedArgs) {
|
|
242
|
-
return genericScalarMappedArgs;
|
|
377
|
+
return stripUnknownArgs ? stripArgsToShape(genericScalarMappedArgs, shape) : genericScalarMappedArgs;
|
|
243
378
|
}
|
|
244
|
-
return genericScalarMappedArgs;
|
|
379
|
+
return stripUnknownArgs ? stripArgsToShape(genericScalarMappedArgs, shape) : genericScalarMappedArgs;
|
|
245
380
|
}
|
|
246
381
|
export function extractToolCallsFromResult(result) {
|
|
247
382
|
const capturedToolCalls = readCapturedPromptedJsonToolCalls(result);
|
|
@@ -62,6 +62,11 @@ export declare class AgentRuntimeAdapter {
|
|
|
62
62
|
toolRuntimeContext?: Record<string, unknown>;
|
|
63
63
|
suppressInitialRequiredPlanInstruction?: boolean;
|
|
64
64
|
externalPlanEvidence?: boolean;
|
|
65
|
+
externalPlanEvidenceTools?: Array<{
|
|
66
|
+
name: string;
|
|
67
|
+
args?: Record<string, unknown>;
|
|
68
|
+
id?: string;
|
|
69
|
+
}>;
|
|
65
70
|
}): Promise<RequestResult>;
|
|
66
71
|
private tryDelegateWithCompactRouter;
|
|
67
72
|
private buildCompactDelegationReport;
|
|
@@ -75,6 +80,13 @@ export declare class AgentRuntimeAdapter {
|
|
|
75
80
|
memoryContext?: string;
|
|
76
81
|
profiling?: boolean;
|
|
77
82
|
toolRuntimeContext?: Record<string, unknown>;
|
|
83
|
+
suppressInitialRequiredPlanInstruction?: boolean;
|
|
84
|
+
externalPlanEvidence?: boolean;
|
|
85
|
+
externalPlanEvidenceTools?: Array<{
|
|
86
|
+
name: string;
|
|
87
|
+
args?: Record<string, unknown>;
|
|
88
|
+
id?: string;
|
|
89
|
+
}>;
|
|
78
90
|
}): AsyncGenerator<RuntimeStreamChunk | string>;
|
|
79
91
|
}
|
|
80
92
|
export { AgentRuntimeAdapter as RuntimeAdapter, AGENT_INTERRUPT_SENTINEL_PREFIX, AGENT_INTERRUPT_SENTINEL_PREFIX as INTERRUPT_SENTINEL_PREFIX, buildDeepAgentCreateParams, buildLangChainCreateParams, DEFAULT_DEEPAGENT_RECURSION_LIMIT, materializeModelExposedBuiltinMiddlewareTools, resolveLangChainInvocationConfig, resolveRunnableCheckpointer, resolveRunnableInterruptOn, RuntimeOperationTimeoutError, };
|
|
@@ -8,7 +8,9 @@ import { extractMessageText } from "../utils/message-content.js";
|
|
|
8
8
|
import { AGENT_INTERRUPT_SENTINEL_PREFIX, buildDeepAgentCreateParams, buildDeepAgentSystemPromptWithCapabilityCatalog, buildLangChainCreateParams, DEFAULT_DEEPAGENT_RECURSION_LIMIT, materializeModelExposedBuiltinMiddlewareTools, resolveLangChainInvocationConfig, resolveRunnableCheckpointer, resolveRunnableInterruptOn, shouldAttachDeepAgentBackend, shouldAttachDeepAgentCheckpointer, shouldAttachDeepAgentStore, } from "./agent-runtime-assembly.js";
|
|
9
9
|
import { resolveDeepAgentSkillSourcePaths, resolveDeepAgentSkillSourceRootPaths, } from "./adapter/compat/deepagent-compat.js";
|
|
10
10
|
import { buildToolNameMapping, } from "./adapter/tool/tool-name-mapping.js";
|
|
11
|
+
import { PROMPTED_JSON_TOOL_POLICY_KEY } from "./adapter/model/prompted-json-tool-policy.js";
|
|
11
12
|
import { executeRequestInvocation } from "./adapter/flow/invocation-flow.js";
|
|
13
|
+
import { extractExplicitResourceReferences } from "./harness/system/runtime-memory-policy.js";
|
|
12
14
|
import { streamRuntimeExecution } from "./adapter/flow/stream-runtime.js";
|
|
13
15
|
import { resolveDeterministicFinalOutput } from "./adapter/invocation-result.js";
|
|
14
16
|
import { applyToolRecoveryInstruction as applyToolRecoveryInstructionHelper, applyStrictToolJsonInstruction as applyStrictToolJsonInstructionHelper, callRuntimeWithToolParseRecovery as callRuntimeWithToolParseRecoveryHelper, createModelFallbackRunnable as createModelFallbackRunnableHelper, invokeWithProviderRetry as invokeWithProviderRetryHelper, iterateWithTimeout as iterateWithTimeoutHelper, materializeModelStream as materializeModelStreamHelper, RuntimeOperationTimeoutError, withRuntimeTimeout, } from "./adapter/runtime-shell.js";
|
|
@@ -243,6 +245,9 @@ function isDelegationOnlyDeepAgentBinding(binding) {
|
|
|
243
245
|
&& getBindingSkills(binding).length === 0;
|
|
244
246
|
}
|
|
245
247
|
function hasDelegatedPlanEvidence(result) {
|
|
248
|
+
if (result?.metadata?.externalPlanEvidence === true) {
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
246
251
|
const toolResults = result?.metadata?.executedToolResults;
|
|
247
252
|
return Array.isArray(toolResults)
|
|
248
253
|
&& toolResults.some((item) => isPlanToolName(item.toolName));
|
|
@@ -264,14 +269,62 @@ function hasIncompleteDelegatedTodos(value) {
|
|
|
264
269
|
|| hasIncompleteDelegatedTodos(record.stateSnapshot)
|
|
265
270
|
|| hasIncompleteDelegatedTodos(record.metadata);
|
|
266
271
|
}
|
|
272
|
+
function hasFailedDelegatedTodos(value) {
|
|
273
|
+
if (Array.isArray(value)) {
|
|
274
|
+
return value.some((item) => hasFailedDelegatedTodos(item));
|
|
275
|
+
}
|
|
276
|
+
if (typeof value !== "object" || value === null) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
const record = value;
|
|
280
|
+
const status = typeof record.status === "string" ? record.status.trim().toLowerCase() : "";
|
|
281
|
+
if (status === "failed") {
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
return hasFailedDelegatedTodos(record.todos)
|
|
285
|
+
|| hasFailedDelegatedTodos(record.update)
|
|
286
|
+
|| hasFailedDelegatedTodos(record.stateSnapshot)
|
|
287
|
+
|| hasFailedDelegatedTodos(record.metadata);
|
|
288
|
+
}
|
|
267
289
|
function hasIncompleteDelegatedPlanState(result) {
|
|
268
290
|
const toolResults = result?.metadata?.executedToolResults;
|
|
269
291
|
return Array.isArray(toolResults)
|
|
270
292
|
&& toolResults.some((item) => isPlanToolName(item.toolName) && hasIncompleteDelegatedTodos(item.output));
|
|
271
293
|
}
|
|
294
|
+
function hasFailedDelegatedPlanState(result) {
|
|
295
|
+
const toolResults = result?.metadata?.executedToolResults;
|
|
296
|
+
return Array.isArray(toolResults)
|
|
297
|
+
&& toolResults.some((item) => isPlanToolName(item.toolName) && hasFailedDelegatedTodos(item.output));
|
|
298
|
+
}
|
|
299
|
+
function hasDelegatedNonPlanToolEvidence(result) {
|
|
300
|
+
const toolResults = result?.metadata?.executedToolResults;
|
|
301
|
+
return Array.isArray(toolResults)
|
|
302
|
+
&& toolResults.some((item) => typeof item.toolName === "string" && !isPlanToolName(item.toolName) && item.isError !== true);
|
|
303
|
+
}
|
|
304
|
+
function hasNonPlanToolEvidenceItems(items) {
|
|
305
|
+
return items.some((item) => typeof item.toolName === "string" && !isPlanToolName(item.toolName) && item.isError !== true);
|
|
306
|
+
}
|
|
307
|
+
function buildDelegatedExternalPlanEvidenceSummary(items) {
|
|
308
|
+
const evidence = items
|
|
309
|
+
.filter((item) => typeof item.toolName === "string" && !isPlanToolName(item.toolName) && item.isError !== true)
|
|
310
|
+
.map((item) => {
|
|
311
|
+
const output = typeof item.output === "string" ? item.output : JSON.stringify(item.output ?? "");
|
|
312
|
+
return `## ${String(item.toolName)}\n${output}`;
|
|
313
|
+
});
|
|
314
|
+
return [
|
|
315
|
+
"Status: completed",
|
|
316
|
+
"Summary:",
|
|
317
|
+
"- Completed delegated recovery after collecting non-planning tool evidence.",
|
|
318
|
+
"",
|
|
319
|
+
"Evidence:",
|
|
320
|
+
evidence.length > 0 ? evidence.join("\n\n") : "(no non-planning tool evidence captured)",
|
|
321
|
+
].join("\n");
|
|
322
|
+
}
|
|
272
323
|
function needsDelegatedPlanRecovery(binding, result) {
|
|
273
324
|
return binding?.harnessRuntime.executionContract?.requiresPlan === true
|
|
274
|
-
&& (!hasDelegatedPlanEvidence(result)
|
|
325
|
+
&& (!hasDelegatedPlanEvidence(result)
|
|
326
|
+
|| hasIncompleteDelegatedPlanState(result)
|
|
327
|
+
|| (hasFailedDelegatedPlanState(result) && !hasDelegatedNonPlanToolEvidence(result)));
|
|
275
328
|
}
|
|
276
329
|
function readUpstreamToolEvidence(event) {
|
|
277
330
|
if (typeof event !== "object" || event === null) {
|
|
@@ -334,11 +387,87 @@ const DELEGATED_PLAN_EVIDENCE_RETRY_INSTRUCTION = [
|
|
|
334
387
|
"Then continue the task to completion, update TODO statuses after evidence steps, and close every TODO as completed or failed before the final answer.",
|
|
335
388
|
].join("\n");
|
|
336
389
|
const DELEGATED_PLAN_EVIDENCE_FINAL_RETRY_INSTRUCTION = [
|
|
337
|
-
"The delegated task still has no
|
|
338
|
-
"
|
|
339
|
-
"The next runtime event must be
|
|
340
|
-
"After
|
|
390
|
+
"The delegated task has already attempted TODO planning but still has no successful non-planning tool evidence.",
|
|
391
|
+
"Do not call write_todos or read_todos next.",
|
|
392
|
+
"The next runtime event must be one available non-planning evidence tool call.",
|
|
393
|
+
"After that tool returns, update or close the TODO board and provide the final answer required by the agent response format.",
|
|
341
394
|
].join("\n");
|
|
395
|
+
function buildDelegatedPlanEvidenceRecoveryOptions(binding, baseOptions, requestText = "") {
|
|
396
|
+
const nonPlanningTools = binding
|
|
397
|
+
? getBindingPrimaryTools(binding).filter((tool) => !isPlanToolName(tool.name))
|
|
398
|
+
: [];
|
|
399
|
+
const explicitlyRequestedTools = resolveExplicitlyRequestedToolNames(requestText, nonPlanningTools.map((tool) => tool.name));
|
|
400
|
+
const externalPlanEvidenceTools = explicitlyRequestedTools.length === 1
|
|
401
|
+
? [{
|
|
402
|
+
name: explicitlyRequestedTools[0],
|
|
403
|
+
args: buildExternalPlanEvidenceArgs(nonPlanningTools.find((tool) => tool.name === explicitlyRequestedTools[0]), requestText),
|
|
404
|
+
id: "delegated-plan-evidence-tool-1",
|
|
405
|
+
}]
|
|
406
|
+
: nonPlanningTools.length === 1
|
|
407
|
+
? [{
|
|
408
|
+
name: nonPlanningTools[0].name,
|
|
409
|
+
args: buildExternalPlanEvidenceArgs(nonPlanningTools[0], requestText),
|
|
410
|
+
id: "delegated-plan-evidence-tool-1",
|
|
411
|
+
}]
|
|
412
|
+
: nonPlanningTools.length > 1
|
|
413
|
+
? [{
|
|
414
|
+
name: nonPlanningTools[0].name,
|
|
415
|
+
args: buildExternalPlanEvidenceArgs(nonPlanningTools[0], requestText),
|
|
416
|
+
id: "delegated-plan-evidence-tool-1",
|
|
417
|
+
}]
|
|
418
|
+
: undefined;
|
|
419
|
+
return {
|
|
420
|
+
...baseOptions,
|
|
421
|
+
suppressInitialRequiredPlanInstruction: true,
|
|
422
|
+
externalPlanEvidence: true,
|
|
423
|
+
...(externalPlanEvidenceTools ? { externalPlanEvidenceTools } : {}),
|
|
424
|
+
state: {
|
|
425
|
+
...(typeof baseOptions.state === "object" && baseOptions.state !== null ? baseOptions.state : {}),
|
|
426
|
+
[PROMPTED_JSON_TOOL_POLICY_KEY]: "nonPlanningEvidence",
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
function buildExternalPlanEvidenceArgs(tool, requestText) {
|
|
431
|
+
const properties = tool?.modelSchema && typeof tool.modelSchema === "object"
|
|
432
|
+
&& tool.modelSchema !== null
|
|
433
|
+
&& typeof tool.modelSchema.properties === "object"
|
|
434
|
+
&& tool.modelSchema.properties !== null
|
|
435
|
+
? tool.modelSchema.properties
|
|
436
|
+
: {};
|
|
437
|
+
const refs = extractExplicitResourceReferences(requestText);
|
|
438
|
+
const args = {};
|
|
439
|
+
const firstUrl = refs.find((ref) => /^https?:\/\//iu.test(ref));
|
|
440
|
+
if ("url" in properties && firstUrl) {
|
|
441
|
+
args.url = firstUrl;
|
|
442
|
+
}
|
|
443
|
+
if ("sources" in properties && refs.length > 0) {
|
|
444
|
+
args.sources = refs.map((ref) => /^https?:\/\//iu.test(ref)
|
|
445
|
+
? { type: "url", url: ref }
|
|
446
|
+
: { type: "text", text: ref });
|
|
447
|
+
}
|
|
448
|
+
if ("question" in properties) {
|
|
449
|
+
args.question = requestText;
|
|
450
|
+
}
|
|
451
|
+
else if ("query" in properties) {
|
|
452
|
+
args.query = requestText;
|
|
453
|
+
}
|
|
454
|
+
return args;
|
|
455
|
+
}
|
|
456
|
+
function escapeRegExp(value) {
|
|
457
|
+
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
458
|
+
}
|
|
459
|
+
function resolveExplicitlyRequestedToolNames(text, availableToolNames) {
|
|
460
|
+
if (!text.trim() || availableToolNames.length === 0) {
|
|
461
|
+
return [];
|
|
462
|
+
}
|
|
463
|
+
return availableToolNames.filter((toolName) => {
|
|
464
|
+
const trimmed = toolName.trim();
|
|
465
|
+
if (!trimmed) {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
return new RegExp(`(^|[^A-Za-z0-9_])${escapeRegExp(trimmed)}([^A-Za-z0-9_]|$)`, "u").test(text);
|
|
469
|
+
});
|
|
470
|
+
}
|
|
342
471
|
function looksLikeRawCommandTranscript(value) {
|
|
343
472
|
const normalized = value.trim();
|
|
344
473
|
return /^(?:stdout|stderr)\s*:/iu.test(normalized)
|
|
@@ -505,18 +634,21 @@ export class AgentRuntimeAdapter {
|
|
|
505
634
|
if (!this.options.functionToolContextResolver) {
|
|
506
635
|
return undefined;
|
|
507
636
|
}
|
|
637
|
+
const publicRequestId = typeof options.requestId === "string" && options.requestId.includes(":")
|
|
638
|
+
? options.requestId.split(":")[0]
|
|
639
|
+
: options.requestId;
|
|
508
640
|
const backend = this.resolveBuiltinMiddlewareBackend(binding, options);
|
|
509
641
|
return {
|
|
510
642
|
...this.options.functionToolContextResolver({
|
|
511
643
|
binding,
|
|
512
644
|
sessionId: options.sessionId,
|
|
513
|
-
requestId:
|
|
645
|
+
requestId: publicRequestId,
|
|
514
646
|
}),
|
|
515
647
|
backend,
|
|
516
648
|
invocation: {
|
|
517
649
|
...(options.context ? { context: options.context } : {}),
|
|
518
650
|
...(options.sessionId ? { sessionId: options.sessionId } : {}),
|
|
519
|
-
...(
|
|
651
|
+
...(publicRequestId ? { requestId: publicRequestId } : {}),
|
|
520
652
|
},
|
|
521
653
|
};
|
|
522
654
|
}
|
|
@@ -1195,13 +1327,25 @@ export class AgentRuntimeAdapter {
|
|
|
1195
1327
|
if (!selectedBinding) {
|
|
1196
1328
|
return null;
|
|
1197
1329
|
}
|
|
1198
|
-
const runDelegatedRequest = (text, requestSuffix = "", delegatedOptions = {}) =>
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1330
|
+
const runDelegatedRequest = async (text, requestSuffix = "", delegatedOptions = {}) => {
|
|
1331
|
+
const result = await this.invoke(selectedBinding, text, sessionId, `${requestId}:${subagentType}${requestSuffix}`, undefined, [], {
|
|
1332
|
+
context: options.context,
|
|
1333
|
+
state: options.state,
|
|
1334
|
+
files: options.files,
|
|
1335
|
+
memoryContext: options.memoryContext,
|
|
1336
|
+
...delegatedOptions,
|
|
1337
|
+
});
|
|
1338
|
+
if (delegatedOptions.externalPlanEvidence === true) {
|
|
1339
|
+
return {
|
|
1340
|
+
...result,
|
|
1341
|
+
metadata: {
|
|
1342
|
+
...(result.metadata ?? {}),
|
|
1343
|
+
externalPlanEvidence: true,
|
|
1344
|
+
},
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
return result;
|
|
1348
|
+
};
|
|
1205
1349
|
let delegatedResult;
|
|
1206
1350
|
try {
|
|
1207
1351
|
delegatedResult = await runDelegatedRequest(requestText);
|
|
@@ -1261,6 +1405,25 @@ export class AgentRuntimeAdapter {
|
|
|
1261
1405
|
};
|
|
1262
1406
|
}
|
|
1263
1407
|
}
|
|
1408
|
+
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1409
|
+
const previousDelegatedResult = delegatedResult;
|
|
1410
|
+
try {
|
|
1411
|
+
delegatedResult = mergeDelegatedResultToolEvidence(await runDelegatedRequest([requestText, DELEGATED_PLAN_EVIDENCE_FINAL_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-final-retry", buildDelegatedPlanEvidenceRecoveryOptions(selectedBinding, options, requestText)), previousDelegatedResult);
|
|
1412
|
+
}
|
|
1413
|
+
catch (error) {
|
|
1414
|
+
const output = error instanceof Error ? error.message : String(error);
|
|
1415
|
+
return {
|
|
1416
|
+
toolOutput: output,
|
|
1417
|
+
delegatedSubagentType: subagentType,
|
|
1418
|
+
delegatedResult: {
|
|
1419
|
+
...delegatedResult,
|
|
1420
|
+
state: "failed",
|
|
1421
|
+
output,
|
|
1422
|
+
finalMessageText: output,
|
|
1423
|
+
},
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1264
1427
|
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1265
1428
|
const output = buildDelegatedPlanEvidenceBlocker(selectedBinding.agent.id);
|
|
1266
1429
|
return {
|
|
@@ -1318,9 +1481,10 @@ export class AgentRuntimeAdapter {
|
|
|
1318
1481
|
const state = compactDelegation.delegatedResult?.state === "failed" ? "failed" : "completed";
|
|
1319
1482
|
const uniqueToolNames = [...new Set(delegatedToolNames)];
|
|
1320
1483
|
const toolEvidence = uniqueToolNames.length > 0 ? uniqueToolNames.join(", ") : "none";
|
|
1484
|
+
const hasPlanEvidence = hasDelegatedPlanEvidence(compactDelegation.delegatedResult);
|
|
1321
1485
|
const fallbackTodoTrace = [
|
|
1322
1486
|
`1) TODO observed: delegated to ${delegatedSubagentType}.`,
|
|
1323
|
-
|
|
1487
|
+
hasPlanEvidence
|
|
1324
1488
|
? `2) ${delegatedSubagentType}: TODO evidence observed; delegated specialist invoked write_todos.`
|
|
1325
1489
|
: `2) ${delegatedSubagentType}: TODO evidence missing; delegated specialist did not expose write_todos in returned metadata.`,
|
|
1326
1490
|
state === "failed"
|
|
@@ -1563,7 +1727,7 @@ export class AgentRuntimeAdapter {
|
|
|
1563
1727
|
content: `Planned delegation tree: ${executableDelegations.map((item) => item.subagentType).join(" -> ")}.`,
|
|
1564
1728
|
agentId: binding.agent.id,
|
|
1565
1729
|
};
|
|
1566
|
-
const runPlannedDelegation = async function* (subagentType, text, requestIdSuffix = "") {
|
|
1730
|
+
const runPlannedDelegation = async function* (subagentType, text, requestIdSuffix = "", delegatedOptions = {}) {
|
|
1567
1731
|
const selectedBinding = this.options.bindingResolver?.(subagentType);
|
|
1568
1732
|
if (!selectedBinding) {
|
|
1569
1733
|
const output = `Configured subagent '${subagentType}' could not be resolved.`;
|
|
@@ -1582,11 +1746,14 @@ export class AgentRuntimeAdapter {
|
|
|
1582
1746
|
try {
|
|
1583
1747
|
for await (const chunk of this.stream(selectedBinding, text, sessionId, [], {
|
|
1584
1748
|
context: options.context,
|
|
1585
|
-
state: options.state,
|
|
1749
|
+
state: delegatedOptions.state ?? options.state,
|
|
1586
1750
|
files: options.files,
|
|
1587
1751
|
requestId: `${requestId}:${subagentType}${requestIdSuffix}`,
|
|
1588
1752
|
memoryContext: options.memoryContext,
|
|
1589
1753
|
profiling: options.profiling,
|
|
1754
|
+
suppressInitialRequiredPlanInstruction: delegatedOptions.suppressInitialRequiredPlanInstruction,
|
|
1755
|
+
externalPlanEvidence: delegatedOptions.externalPlanEvidence,
|
|
1756
|
+
externalPlanEvidenceTools: delegatedOptions.externalPlanEvidenceTools,
|
|
1590
1757
|
})) {
|
|
1591
1758
|
if (typeof chunk === "string") {
|
|
1592
1759
|
output += chunk;
|
|
@@ -1621,17 +1788,26 @@ export class AgentRuntimeAdapter {
|
|
|
1621
1788
|
state: "failed",
|
|
1622
1789
|
output,
|
|
1623
1790
|
finalMessageText: output,
|
|
1624
|
-
metadata: {
|
|
1791
|
+
metadata: {
|
|
1792
|
+
executedToolResults,
|
|
1793
|
+
...(delegatedOptions.externalPlanEvidence === true ? { externalPlanEvidence: true } : {}),
|
|
1794
|
+
},
|
|
1625
1795
|
};
|
|
1626
1796
|
}
|
|
1797
|
+
const finalOutput = delegatedOptions.externalPlanEvidence === true && hasNonPlanToolEvidenceItems(executedToolResults)
|
|
1798
|
+
? buildDelegatedExternalPlanEvidenceSummary(executedToolResults)
|
|
1799
|
+
: sanitizeVisibleText(output);
|
|
1627
1800
|
return {
|
|
1628
1801
|
sessionId,
|
|
1629
1802
|
requestId: `${requestId}:${subagentType}${requestIdSuffix}`,
|
|
1630
1803
|
agentId: selectedBinding.agent.id,
|
|
1631
1804
|
state: "completed",
|
|
1632
|
-
output:
|
|
1633
|
-
finalMessageText:
|
|
1634
|
-
metadata: {
|
|
1805
|
+
output: finalOutput,
|
|
1806
|
+
finalMessageText: finalOutput,
|
|
1807
|
+
metadata: {
|
|
1808
|
+
executedToolResults,
|
|
1809
|
+
...(delegatedOptions.externalPlanEvidence === true ? { externalPlanEvidence: true } : {}),
|
|
1810
|
+
},
|
|
1635
1811
|
};
|
|
1636
1812
|
}.bind(this);
|
|
1637
1813
|
for (const [index, planned] of executableDelegations.entries()) {
|
|
@@ -1658,7 +1834,7 @@ export class AgentRuntimeAdapter {
|
|
|
1658
1834
|
}
|
|
1659
1835
|
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1660
1836
|
const previousDelegatedResult = delegatedResult;
|
|
1661
|
-
delegatedResult = mergeDelegatedResultToolEvidence(yield* runPlannedDelegation(planned.subagentType, [delegatedText, DELEGATED_PLAN_EVIDENCE_FINAL_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-final-retry"), previousDelegatedResult);
|
|
1837
|
+
delegatedResult = mergeDelegatedResultToolEvidence(yield* runPlannedDelegation(planned.subagentType, [delegatedText, DELEGATED_PLAN_EVIDENCE_FINAL_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-final-retry", buildDelegatedPlanEvidenceRecoveryOptions(selectedBinding, options, delegatedText)), previousDelegatedResult);
|
|
1662
1838
|
}
|
|
1663
1839
|
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1664
1840
|
const output = buildDelegatedPlanEvidenceBlocker(selectedBinding?.agent.id ?? planned.subagentType);
|
|
@@ -1789,17 +1965,20 @@ export class AgentRuntimeAdapter {
|
|
|
1789
1965
|
agentId: selectedBinding.agent.id,
|
|
1790
1966
|
};
|
|
1791
1967
|
const childRequestId = `${requestId}:${subagentType}`;
|
|
1792
|
-
const runDelegatedStreamAttempt = async function* (text, requestIdSuffix = "") {
|
|
1968
|
+
const runDelegatedStreamAttempt = async function* (text, requestIdSuffix = "", delegatedOptions = {}) {
|
|
1793
1969
|
const executedToolResults = [];
|
|
1794
1970
|
let output = "";
|
|
1795
1971
|
try {
|
|
1796
1972
|
for await (const chunk of this.stream(selectedBinding, text, sessionId, [], {
|
|
1797
1973
|
context: options.context,
|
|
1798
|
-
state: options.state,
|
|
1974
|
+
state: delegatedOptions.state ?? options.state,
|
|
1799
1975
|
files: options.files,
|
|
1800
1976
|
requestId: `${childRequestId}${requestIdSuffix}`,
|
|
1801
1977
|
memoryContext: options.memoryContext,
|
|
1802
1978
|
profiling: options.profiling,
|
|
1979
|
+
suppressInitialRequiredPlanInstruction: delegatedOptions.suppressInitialRequiredPlanInstruction,
|
|
1980
|
+
externalPlanEvidence: delegatedOptions.externalPlanEvidence,
|
|
1981
|
+
externalPlanEvidenceTools: delegatedOptions.externalPlanEvidenceTools,
|
|
1803
1982
|
})) {
|
|
1804
1983
|
if (typeof chunk === "string") {
|
|
1805
1984
|
output += chunk;
|
|
@@ -1834,17 +2013,26 @@ export class AgentRuntimeAdapter {
|
|
|
1834
2013
|
state: "failed",
|
|
1835
2014
|
output,
|
|
1836
2015
|
finalMessageText: output,
|
|
1837
|
-
metadata: {
|
|
2016
|
+
metadata: {
|
|
2017
|
+
executedToolResults,
|
|
2018
|
+
...(delegatedOptions.externalPlanEvidence === true ? { externalPlanEvidence: true } : {}),
|
|
2019
|
+
},
|
|
1838
2020
|
};
|
|
1839
2021
|
}
|
|
2022
|
+
const finalOutput = delegatedOptions.externalPlanEvidence === true && hasNonPlanToolEvidenceItems(executedToolResults)
|
|
2023
|
+
? buildDelegatedExternalPlanEvidenceSummary(executedToolResults)
|
|
2024
|
+
: sanitizeVisibleText(output);
|
|
1840
2025
|
return {
|
|
1841
2026
|
sessionId,
|
|
1842
2027
|
requestId: `${childRequestId}${requestIdSuffix}`,
|
|
1843
2028
|
agentId: selectedBinding.agent.id,
|
|
1844
2029
|
state: "completed",
|
|
1845
|
-
output:
|
|
1846
|
-
finalMessageText:
|
|
1847
|
-
metadata: {
|
|
2030
|
+
output: finalOutput,
|
|
2031
|
+
finalMessageText: finalOutput,
|
|
2032
|
+
metadata: {
|
|
2033
|
+
executedToolResults,
|
|
2034
|
+
...(delegatedOptions.externalPlanEvidence === true ? { externalPlanEvidence: true } : {}),
|
|
2035
|
+
},
|
|
1848
2036
|
};
|
|
1849
2037
|
}.bind(this);
|
|
1850
2038
|
const delegatedText = buildDelegatedOwnedTaskInstruction({
|
|
@@ -1859,7 +2047,7 @@ export class AgentRuntimeAdapter {
|
|
|
1859
2047
|
}
|
|
1860
2048
|
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1861
2049
|
const previousDelegatedResult = delegatedResult;
|
|
1862
|
-
delegatedResult = mergeDelegatedResultToolEvidence(yield* runDelegatedStreamAttempt([delegatedText, DELEGATED_PLAN_EVIDENCE_FINAL_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-final-retry"), previousDelegatedResult);
|
|
2050
|
+
delegatedResult = mergeDelegatedResultToolEvidence(yield* runDelegatedStreamAttempt([delegatedText, DELEGATED_PLAN_EVIDENCE_FINAL_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-final-retry", buildDelegatedPlanEvidenceRecoveryOptions(selectedBinding, options, delegatedText)), previousDelegatedResult);
|
|
1863
2051
|
}
|
|
1864
2052
|
if (needsDelegatedPlanRecovery(selectedBinding, delegatedResult)) {
|
|
1865
2053
|
const output = buildDelegatedPlanEvidenceBlocker(selectedBinding.agent.id);
|
|
@@ -59,7 +59,8 @@ export function isToolCallValidationFailure(error) {
|
|
|
59
59
|
if (/Invalid input:\s*expected .* received undefined/i.test(message) && /"path"\s*:\s*\[/.test(message)) {
|
|
60
60
|
return true;
|
|
61
61
|
}
|
|
62
|
-
return /Received tool input did not match expected schema/i.test(message)
|
|
62
|
+
return /Received tool input did not match expected schema/i.test(message)
|
|
63
|
+
&& (/(?:→\s*at|at)\s+[\w[\].]+/i.test(message) || /\bDetails:/i.test(message));
|
|
63
64
|
}
|
|
64
65
|
function collectErrorMessages(error) {
|
|
65
66
|
if (!error)
|