@botbotgo/agent-harness 0.0.338 → 0.0.341
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/contracts/workspace.d.ts +10 -0
- package/dist/package-version.d.ts +2 -2
- package/dist/package-version.js +2 -2
- package/dist/runtime/adapter/flow/execution-context.js +3 -2
- package/dist/runtime/adapter/flow/stream-runtime.d.ts +6 -0
- package/dist/runtime/adapter/flow/stream-runtime.js +54 -15
- package/dist/runtime/adapter/invocation-result.js +111 -9
- package/dist/runtime/adapter/local-tool-invocation.js +21 -1
- package/dist/runtime/adapter/middleware/context-hygiene.d.ts +5 -0
- package/dist/runtime/adapter/middleware/context-hygiene.js +83 -0
- package/dist/runtime/adapter/middleware-assembly.d.ts +11 -0
- package/dist/runtime/adapter/middleware-assembly.js +154 -178
- package/dist/runtime/adapter/model/invocation-request.js +39 -1
- package/dist/runtime/adapter/runtime-adapter-support.js +33 -3
- package/dist/runtime/adapter/stream-event-projection.js +6 -5
- package/dist/runtime/adapter/tool/builtin-middleware-tools.d.ts +7 -0
- package/dist/runtime/adapter/tool/builtin-middleware-tools.js +31 -24
- package/dist/runtime/agent-runtime-adapter.d.ts +3 -2
- package/dist/runtime/agent-runtime-adapter.js +128 -9
- package/dist/runtime/agent-runtime-assembly.d.ts +1 -0
- package/dist/runtime/agent-runtime-assembly.js +10 -2
- package/dist/runtime/harness/run/inspection.js +4 -5
- package/dist/runtime/harness/run/stream-run.js +180 -50
- package/dist/runtime/parsing/output-parsing.d.ts +1 -1
- package/dist/runtime/parsing/output-parsing.js +1 -1
- package/dist/runtime/parsing/output-recovery.d.ts +9 -0
- package/dist/runtime/parsing/output-recovery.js +46 -1
- package/dist/runtime/support/compiled-binding.d.ts +5 -0
- package/dist/runtime/support/compiled-binding.js +12 -0
- package/dist/workspace/agent-binding-compiler.js +8 -0
- package/dist/workspace/object-loader.js +6 -0
- package/package.json +1 -1
|
@@ -174,6 +174,7 @@ export type CompiledTool = {
|
|
|
174
174
|
};
|
|
175
175
|
};
|
|
176
176
|
export type CompiledSubAgent = {
|
|
177
|
+
agentId?: string;
|
|
177
178
|
name: string;
|
|
178
179
|
description: string;
|
|
179
180
|
systemPrompt: string;
|
|
@@ -183,6 +184,10 @@ export type CompiledSubAgent = {
|
|
|
183
184
|
skills?: string[];
|
|
184
185
|
responseFormat?: unknown;
|
|
185
186
|
middleware?: Array<Record<string, unknown>>;
|
|
187
|
+
builtinTools?: {
|
|
188
|
+
filesystem?: boolean;
|
|
189
|
+
todos?: boolean;
|
|
190
|
+
};
|
|
186
191
|
};
|
|
187
192
|
export type CompiledAsyncSubAgent = {
|
|
188
193
|
name: string;
|
|
@@ -219,6 +224,11 @@ export type DeepAgentParams = {
|
|
|
219
224
|
name: string;
|
|
220
225
|
memory: string[];
|
|
221
226
|
skills: string[];
|
|
227
|
+
interactionMode?: "stream" | "invoke";
|
|
228
|
+
builtinTools?: {
|
|
229
|
+
filesystem?: boolean;
|
|
230
|
+
todos?: boolean;
|
|
231
|
+
};
|
|
222
232
|
};
|
|
223
233
|
export type LegacyLangChainAgentParams = LangChainAgentParams & {
|
|
224
234
|
passthrough?: Record<string, unknown>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
2
|
-
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.341";
|
|
2
|
+
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-24";
|
package/dist/package-version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
2
|
-
export const AGENT_HARNESS_RELEASE_DATE = "2026-04-
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.341";
|
|
2
|
+
export const AGENT_HARNESS_RELEASE_DATE = "2026-04-24";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildExecutableToolMap } from "../tool-resolution.js";
|
|
2
|
-
import { getBindingPrimaryModel, getBindingPrimaryTools, isLangChainBinding } from "../../support/compiled-binding.js";
|
|
2
|
+
import { getBindingInteractionMode, getBindingPrimaryModel, getBindingPrimaryTools, isLangChainBinding } from "../../support/compiled-binding.js";
|
|
3
3
|
export function buildBindingToolCatalog(input) {
|
|
4
4
|
const primaryTools = getBindingPrimaryTools(input.binding);
|
|
5
5
|
const toolNameMapping = input.getToolNameMapping(input.binding);
|
|
@@ -54,6 +54,7 @@ export async function resolveRuntimeStreamExecutionContext(input) {
|
|
|
54
54
|
binding: input.binding,
|
|
55
55
|
getToolNameMapping: input.getToolNameMapping,
|
|
56
56
|
});
|
|
57
|
+
const interactionMode = getBindingInteractionMode(input.binding) ?? "stream";
|
|
57
58
|
const { forceInvokeFallback, canUseDirectModelStream, langChainStreamModel, } = await resolveLangChainStreamContext({
|
|
58
59
|
binding: input.binding,
|
|
59
60
|
resolveModel: input.resolveModel,
|
|
@@ -62,7 +63,7 @@ export async function resolveRuntimeStreamExecutionContext(input) {
|
|
|
62
63
|
return {
|
|
63
64
|
primaryTools,
|
|
64
65
|
toolNameMapping,
|
|
65
|
-
forceInvokeFallback,
|
|
66
|
+
forceInvokeFallback: interactionMode === "invoke" ? true : forceInvokeFallback,
|
|
66
67
|
canUseDirectModelStream,
|
|
67
68
|
langChainStreamModel,
|
|
68
69
|
};
|
|
@@ -30,6 +30,12 @@ export declare function streamRuntimeExecution(options: {
|
|
|
30
30
|
stream?: (input: unknown) => Promise<AsyncIterable<unknown>>;
|
|
31
31
|
};
|
|
32
32
|
createRunnable: () => Promise<RunnableLike>;
|
|
33
|
+
resolveInvocationConfig?: (binding: CompiledAgentBinding, options: {
|
|
34
|
+
sessionId: string;
|
|
35
|
+
requestId: string;
|
|
36
|
+
context?: Record<string, unknown>;
|
|
37
|
+
toolRuntimeContext?: Record<string, unknown>;
|
|
38
|
+
}) => Record<string, unknown>;
|
|
33
39
|
withTimeout: <T>(producer: () => T | Promise<T>, timeoutMs: number | undefined, operation: string, stage?: "stream" | "invoke") => Promise<T>;
|
|
34
40
|
iterateWithTimeout: <T>(iterable: AsyncIterable<T>, timeoutMs: number | undefined, operation: string, deadlineAt?: number, deadlineTimeoutMs?: number) => AsyncGenerator<T>;
|
|
35
41
|
invokeTimeoutMs?: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { extractVisibleOutput, isToolCallRecoveryFailure, isRetrySafeInvalidToolSelectionError, 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, resolveMissingPlanRecoveryInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, shouldValidateExecutionWithoutToolEvidence, resolveToolCallRecoveryInstruction, sanitizeVisibleText, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, } from "../../parsing/output-parsing.js";
|
|
2
2
|
import { buildInvocationRequest } from "../model/invocation-request.js";
|
|
3
3
|
import { buildRawModelMessages } from "../model/message-assembly.js";
|
|
4
4
|
import { projectRuntimeStreamEvent, createStreamEventProjectionState } from "../stream-event-projection.js";
|
|
@@ -152,6 +152,22 @@ export async function* streamRuntimeExecution(options) {
|
|
|
152
152
|
const deferredStreamContent = [];
|
|
153
153
|
let sawRetrySafeInvalidToolSelectionError = false;
|
|
154
154
|
const projectionState = createStreamEventProjectionState();
|
|
155
|
+
const requestId = options.runtimeOptions.requestId ?? options.sessionId;
|
|
156
|
+
const buildRunnableConfig = (extra) => ({
|
|
157
|
+
...(options.resolveInvocationConfig
|
|
158
|
+
? options.resolveInvocationConfig(options.binding, {
|
|
159
|
+
sessionId: options.sessionId,
|
|
160
|
+
requestId,
|
|
161
|
+
...(options.runtimeOptions.context ? { context: options.runtimeOptions.context } : {}),
|
|
162
|
+
...(options.runtimeOptions.toolRuntimeContext ? { toolRuntimeContext: options.runtimeOptions.toolRuntimeContext } : {}),
|
|
163
|
+
})
|
|
164
|
+
: {
|
|
165
|
+
configurable: { [UPSTREAM_SESSION_CONFIG_KEY]: options.sessionId, [UPSTREAM_REQUEST_CONFIG_KEY]: requestId },
|
|
166
|
+
...(options.runtimeOptions.context ? { context: options.runtimeOptions.context } : {}),
|
|
167
|
+
...(options.runtimeOptions.toolRuntimeContext ? { toolRuntimeContext: options.runtimeOptions.toolRuntimeContext } : {}),
|
|
168
|
+
}),
|
|
169
|
+
...(extra ?? {}),
|
|
170
|
+
});
|
|
155
171
|
const shouldDeferStreamContent = () => shouldValidateStreamOutput && !emittedUnsafeStreamSideEffects;
|
|
156
172
|
const flushDeferredStreamContent = async function* () {
|
|
157
173
|
while (deferredStreamContent.length > 0) {
|
|
@@ -293,12 +309,7 @@ export async function* streamRuntimeExecution(options) {
|
|
|
293
309
|
yield streamEventsStart.chunk;
|
|
294
310
|
let events;
|
|
295
311
|
try {
|
|
296
|
-
events = await options.withTimeout(() => runnable.streamEvents(request, {
|
|
297
|
-
configurable: { [UPSTREAM_SESSION_CONFIG_KEY]: options.sessionId, [UPSTREAM_REQUEST_CONFIG_KEY]: options.runtimeOptions.requestId },
|
|
298
|
-
version: "v2",
|
|
299
|
-
...(options.runtimeOptions.context ? { context: options.runtimeOptions.context } : {}),
|
|
300
|
-
...(options.runtimeOptions.toolRuntimeContext ? { toolRuntimeContext: options.runtimeOptions.toolRuntimeContext } : {}),
|
|
301
|
-
}), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "agent streamEvents start", "stream");
|
|
312
|
+
events = await options.withTimeout(() => runnable.streamEvents(request, buildRunnableConfig({ version: "v2" })), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "agent streamEvents start", "stream");
|
|
302
313
|
if (shouldProfile)
|
|
303
314
|
yield finishProfileStep({
|
|
304
315
|
id: "profile:agent:stream-events-start",
|
|
@@ -370,12 +381,24 @@ export async function* streamRuntimeExecution(options) {
|
|
|
370
381
|
const terminalVisibleOutput = readTerminalEventVisibleOutput(event);
|
|
371
382
|
if (terminalVisibleOutput) {
|
|
372
383
|
const terminalExecutionEvidence = buildExecutionRecoveryEvidence({ projectionState });
|
|
384
|
+
const terminalMissingPlanRecoveryInstruction = !terminalExecutionEvidence.hasDelegatedAgentWithConfiguredTools
|
|
385
|
+
&& !terminalExecutionEvidence.hasOpenTaskDelegation
|
|
386
|
+
&& !projectionState.emittedSuccessfulTaskResult
|
|
387
|
+
? resolveMissingPlanRecoveryInstruction({
|
|
388
|
+
request,
|
|
389
|
+
assistantText: terminalVisibleOutput,
|
|
390
|
+
hasPlanStateEvidence: terminalExecutionEvidence.hasPlanStateEvidence,
|
|
391
|
+
hasWriteTodosEvidence: terminalExecutionEvidence.hasPlanStateEvidence,
|
|
392
|
+
hasToolResultEvidence: terminalExecutionEvidence.hasSuccessfulNonTodoToolResultEvidence,
|
|
393
|
+
})
|
|
394
|
+
: null;
|
|
373
395
|
if (!shouldDeferStreamContent()
|
|
374
396
|
&& !terminalExecutionEvidence.hasIncompletePlanState
|
|
375
397
|
&& !terminalExecutionEvidence.hasFailedTaskDelegation
|
|
376
398
|
&& !terminalExecutionEvidence.hasOpenTaskDelegation
|
|
377
399
|
&& !hasMissingDelegatedExecutionEvidence(terminalExecutionEvidence)
|
|
378
|
-
&& !hasMissingDelegatedFindings(terminalExecutionEvidence)
|
|
400
|
+
&& !hasMissingDelegatedFindings(terminalExecutionEvidence)
|
|
401
|
+
&& !terminalMissingPlanRecoveryInstruction) {
|
|
379
402
|
if (deferredStreamContent.length > 0) {
|
|
380
403
|
yield* flushDeferredStreamContent();
|
|
381
404
|
}
|
|
@@ -419,9 +442,18 @@ export async function* streamRuntimeExecution(options) {
|
|
|
419
442
|
hasMissingDelegatedExecutionEvidence: hasMissingDelegatedExecutionEvidence(streamedExecutionEvidence),
|
|
420
443
|
})
|
|
421
444
|
: null;
|
|
445
|
+
const missingPlanRecoveryInstruction = !hasUnresolvedExecution(streamedExecutionEvidence) && !delegatedExecutionRecoveryInstruction
|
|
446
|
+
? resolveMissingPlanRecoveryInstruction({
|
|
447
|
+
request,
|
|
448
|
+
assistantText: projectionState.emittedOutput,
|
|
449
|
+
hasPlanStateEvidence: streamedExecutionEvidence.hasPlanStateEvidence,
|
|
450
|
+
hasWriteTodosEvidence: streamedExecutionEvidence.hasPlanStateEvidence,
|
|
451
|
+
hasToolResultEvidence: streamedExecutionEvidence.hasSuccessfulNonTodoToolResultEvidence,
|
|
452
|
+
})
|
|
453
|
+
: null;
|
|
422
454
|
const retryInstruction = !emittedUnsafeStreamSideEffects && sawRetrySafeInvalidToolSelectionError
|
|
423
455
|
? INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION
|
|
424
|
-
: delegatedExecutionRecoveryInstruction ?? executionWithoutToolEvidenceInstruction;
|
|
456
|
+
: delegatedExecutionRecoveryInstruction ?? missingPlanRecoveryInstruction ?? executionWithoutToolEvidenceInstruction;
|
|
425
457
|
if (retryInstruction) {
|
|
426
458
|
let retried;
|
|
427
459
|
retried = await options.invoke(options.applyToolRecoveryInstruction(options.binding, retryInstruction), options.input, options.sessionId, options.runtimeOptions.requestId ?? options.sessionId, undefined, options.history, options.runtimeOptions);
|
|
@@ -499,10 +531,7 @@ export async function* streamRuntimeExecution(options) {
|
|
|
499
531
|
yield streamStart.chunk;
|
|
500
532
|
let stream;
|
|
501
533
|
try {
|
|
502
|
-
stream = await options.withTimeout(() => runnable.stream(request,
|
|
503
|
-
configurable: { [UPSTREAM_SESSION_CONFIG_KEY]: options.sessionId, [UPSTREAM_REQUEST_CONFIG_KEY]: options.runtimeOptions.requestId },
|
|
504
|
-
...(options.runtimeOptions.toolRuntimeContext ? { toolRuntimeContext: options.runtimeOptions.toolRuntimeContext } : {}),
|
|
505
|
-
}), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "agent stream start", "stream");
|
|
534
|
+
stream = await options.withTimeout(() => runnable.stream(request, buildRunnableConfig()), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "agent stream start", "stream");
|
|
506
535
|
if (shouldProfile)
|
|
507
536
|
yield finishProfileStep({
|
|
508
537
|
id: "profile:agent:stream-start",
|
|
@@ -620,8 +649,18 @@ export async function* streamRuntimeExecution(options) {
|
|
|
620
649
|
hasMissingDelegatedExecutionEvidence: hasMissingDelegatedExecutionEvidence(invokeExecutionEvidence),
|
|
621
650
|
})
|
|
622
651
|
: resolveDelegatedExecutionRecoveryInstruction(invokeExecutionEvidence);
|
|
623
|
-
|
|
624
|
-
|
|
652
|
+
const invokeFallbackMissingPlanRecoveryInstruction = !hasUnresolvedExecution(invokeExecutionEvidence) && !invokeFallbackRecoveryInstruction
|
|
653
|
+
? resolveMissingPlanRecoveryInstruction({
|
|
654
|
+
request,
|
|
655
|
+
assistantText: typeof result.output === "string" ? result.output : "",
|
|
656
|
+
hasPlanStateEvidence: invokeExecutionEvidence.hasPlanStateEvidence,
|
|
657
|
+
hasWriteTodosEvidence: invokeExecutionEvidence.hasPlanStateEvidence,
|
|
658
|
+
hasToolResultEvidence: invokeExecutionEvidence.hasSuccessfulNonTodoToolResultEvidence,
|
|
659
|
+
})
|
|
660
|
+
: null;
|
|
661
|
+
const effectiveInvokeFallbackRecoveryInstruction = invokeFallbackMissingPlanRecoveryInstruction ?? invokeFallbackRecoveryInstruction;
|
|
662
|
+
if (effectiveInvokeFallbackRecoveryInstruction) {
|
|
663
|
+
const recovered = await options.invoke(options.applyToolRecoveryInstruction(options.binding, effectiveInvokeFallbackRecoveryInstruction), options.input, options.sessionId, options.runtimeOptions.requestId ?? options.sessionId, undefined, options.history, options.runtimeOptions);
|
|
625
664
|
const recoveredToolResults = Array.isArray(recovered.metadata?.executedToolResults)
|
|
626
665
|
? recovered.metadata.executedToolResults
|
|
627
666
|
: [];
|
|
@@ -2,6 +2,7 @@ import { containsLikelySkillDocument, extractContentBlocks, extractEmptyAssistan
|
|
|
2
2
|
import { salvageFunctionLikeToolCall } from "../parsing/output-tool-args.js";
|
|
3
3
|
import { buildStateSnapshot } from "./model/message-assembly.js";
|
|
4
4
|
import { asRecord } from "./tool/resolved-tool.js";
|
|
5
|
+
import { renderToolFailure } from "../support/harness-support.js";
|
|
5
6
|
function looksLikeLeakedToolCallText(value) {
|
|
6
7
|
const normalized = sanitizeVisibleText(value).trim();
|
|
7
8
|
if (!normalized) {
|
|
@@ -24,6 +25,16 @@ function isLowSignalStructuredCompletion(value) {
|
|
|
24
25
|
}
|
|
25
26
|
return /Status:\s*completed[\s\S]*Summary:\s*-\s*none[\s\S]*Likely Causes:\s*-\s*none[\s\S]*Blockers:\s*-\s*none[\s\S]*Next Commands:\s*-\s*none/i.test(normalized);
|
|
26
27
|
}
|
|
28
|
+
function looksLikeToolBlocker(value) {
|
|
29
|
+
const normalized = sanitizeVisibleText(value).trim();
|
|
30
|
+
if (!normalized) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return /^Blocked:\s*/iu.test(normalized)
|
|
34
|
+
|| /error parsing tool call/iu.test(normalized)
|
|
35
|
+
|| /invalid tool call/iu.test(normalized)
|
|
36
|
+
|| /tool call.*schema/iu.test(normalized);
|
|
37
|
+
}
|
|
27
38
|
function normalizeToolOutputText(output) {
|
|
28
39
|
const directText = typeof output === "string"
|
|
29
40
|
? sanitizeVisibleText(output).trim()
|
|
@@ -56,14 +67,35 @@ function extractLatestSuccessfulTaskResultText(executedToolResults) {
|
|
|
56
67
|
continue;
|
|
57
68
|
}
|
|
58
69
|
const normalized = normalizeToolOutputText(toolResult.output);
|
|
59
|
-
if (normalized) {
|
|
70
|
+
if (normalized && !looksLikeToolBlocker(normalized)) {
|
|
60
71
|
return normalized;
|
|
61
72
|
}
|
|
62
73
|
}
|
|
63
74
|
return "";
|
|
64
75
|
}
|
|
76
|
+
function looksLikeReportOutput(value) {
|
|
77
|
+
const normalized = sanitizeVisibleText(value).trim();
|
|
78
|
+
if (!normalized) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return /(?:^|\n)\s*Status\s*:/iu.test(normalized)
|
|
82
|
+
|| /(?:^|\n)\s*Summary\s*:/iu.test(normalized)
|
|
83
|
+
|| /(?:^|\n)\s*Likely Causes\s*:/iu.test(normalized)
|
|
84
|
+
|| /(?:^|\n)\s*Blockers\s*:/iu.test(normalized)
|
|
85
|
+
|| /(?:^|\n)\s*Next Commands\s*:/iu.test(normalized);
|
|
86
|
+
}
|
|
87
|
+
function looksLikeRawCommandTranscript(value) {
|
|
88
|
+
const normalized = sanitizeVisibleText(value).trim();
|
|
89
|
+
if (!normalized) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
return /^(?:stdout|stderr)\s*:/iu.test(normalized)
|
|
93
|
+
|| /(?:^|\n)\s*(?:stdout|stderr)\s*:/iu.test(normalized)
|
|
94
|
+
|| /(?:^|\n)\s*exitCode\s*:\s*-?\d+\s*$/iu.test(normalized);
|
|
95
|
+
}
|
|
65
96
|
function extractLatestSuccessfulNonTodoToolResultText(executedToolResults) {
|
|
66
|
-
|
|
97
|
+
const candidates = [];
|
|
98
|
+
for (const toolResult of executedToolResults) {
|
|
67
99
|
if (toolResult.isError === true) {
|
|
68
100
|
continue;
|
|
69
101
|
}
|
|
@@ -72,32 +104,102 @@ function extractLatestSuccessfulNonTodoToolResultText(executedToolResults) {
|
|
|
72
104
|
}
|
|
73
105
|
const normalized = normalizeToolOutputText(toolResult.output);
|
|
74
106
|
if (normalized) {
|
|
75
|
-
|
|
107
|
+
candidates.push(normalized);
|
|
76
108
|
}
|
|
77
109
|
}
|
|
78
|
-
return
|
|
110
|
+
return [...candidates].reverse().find(looksLikeReportOutput)
|
|
111
|
+
?? [...candidates].reverse().find((candidate) => !looksLikeRawCommandTranscript(candidate))
|
|
112
|
+
?? candidates.at(-1)
|
|
113
|
+
?? "";
|
|
114
|
+
}
|
|
115
|
+
function hasDelegationBlocker(executedToolResults) {
|
|
116
|
+
return executedToolResults.some((toolResult) => {
|
|
117
|
+
if (toolResult.toolName !== "task") {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
if (toolResult.isError === true) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
const normalized = normalizeToolOutputText(toolResult.output);
|
|
124
|
+
return looksLikeToolBlocker(normalized);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function looksLikeClarificationQuestion(value) {
|
|
128
|
+
const normalized = sanitizeVisibleText(value).trim();
|
|
129
|
+
if (!normalized) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
return /[??]\s*$/u.test(normalized)
|
|
133
|
+
|| /^(?:could you|can you|please provide|please share|i need|what is|which )/iu.test(normalized)
|
|
134
|
+
|| /^(?:请问|请提供|能否提供|能不能提供)/u.test(normalized);
|
|
135
|
+
}
|
|
136
|
+
function looksLikeNonEvidenceApology(value) {
|
|
137
|
+
const normalized = sanitizeVisibleText(value).trim();
|
|
138
|
+
if (!normalized) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return /(?:i(?:'|’)m sorry|sorry)[\s\S]*(?:couldn(?:'|’)t|cannot|can(?:'|’)t|unable to)\s+(?:complete|proceed|finish|continue)/iu.test(normalized)
|
|
142
|
+
|| /(?:system limitation|technical limitation|internal limitation|recursion limit)/iu.test(normalized)
|
|
143
|
+
|| /(?:抱歉|对不起)[\s\S]*(?:无法|不能|未能)(?:完成|继续|处理)/u.test(normalized);
|
|
144
|
+
}
|
|
145
|
+
function extractDeterministicToolFailureReport(executedToolResults) {
|
|
146
|
+
const hasSuccessfulSubstantiveTool = executedToolResults.some((toolResult) => (toolResult.isError !== true
|
|
147
|
+
&& toolResult.toolName !== "write_todos"
|
|
148
|
+
&& toolResult.toolName !== "read_todos"));
|
|
149
|
+
if (hasSuccessfulSubstantiveTool) {
|
|
150
|
+
return "";
|
|
151
|
+
}
|
|
152
|
+
const failures = executedToolResults.filter((toolResult) => toolResult.isError === true);
|
|
153
|
+
if (failures.length === 0) {
|
|
154
|
+
return "";
|
|
155
|
+
}
|
|
156
|
+
const blockerLines = failures
|
|
157
|
+
.slice(-3)
|
|
158
|
+
.map((toolResult) => `- ${renderToolFailure(toolResult.toolName, toolResult.output)}`);
|
|
159
|
+
return [
|
|
160
|
+
"Status: failed",
|
|
161
|
+
"Summary:",
|
|
162
|
+
"- The investigation could not proceed because required tools failed before any concrete evidence was gathered.",
|
|
163
|
+
"Likely Causes:",
|
|
164
|
+
"- none",
|
|
165
|
+
"Blockers:",
|
|
166
|
+
...blockerLines,
|
|
167
|
+
"Next Commands:",
|
|
168
|
+
"- none",
|
|
169
|
+
].join("\n");
|
|
79
170
|
}
|
|
80
171
|
export function resolveDeterministicFinalOutput(params) {
|
|
81
172
|
const visibleOutput = params.visibleOutput ?? "";
|
|
82
173
|
const toolFallback = params.toolFallback ?? "";
|
|
83
174
|
const executedToolResults = params.executedToolResults ?? [];
|
|
84
|
-
const delegatedTaskOutput = extractLatestSuccessfulTaskResultText(executedToolResults);
|
|
85
|
-
if (delegatedTaskOutput) {
|
|
86
|
-
return delegatedTaskOutput;
|
|
87
|
-
}
|
|
88
175
|
const sanitizedVisibleOutput = visibleOutput && !looksLikeLeakedToolCallText(visibleOutput)
|
|
89
176
|
? sanitizeVisibleText(visibleOutput).trim()
|
|
90
177
|
: "";
|
|
178
|
+
const deterministicFailureReport = extractDeterministicToolFailureReport(executedToolResults);
|
|
179
|
+
const delegatedTaskOutput = extractLatestSuccessfulTaskResultText(executedToolResults);
|
|
180
|
+
const successfulToolOutput = extractLatestSuccessfulNonTodoToolResultText(executedToolResults);
|
|
181
|
+
if (sanitizedVisibleOutput && successfulToolOutput && hasDelegationBlocker(executedToolResults)) {
|
|
182
|
+
return deterministicFailureReport || delegatedTaskOutput || successfulToolOutput;
|
|
183
|
+
}
|
|
184
|
+
if (sanitizedVisibleOutput
|
|
185
|
+
&& (looksLikeClarificationQuestion(sanitizedVisibleOutput) || looksLikeNonEvidenceApology(sanitizedVisibleOutput))) {
|
|
186
|
+
return deterministicFailureReport || delegatedTaskOutput || successfulToolOutput || sanitizedVisibleOutput;
|
|
187
|
+
}
|
|
91
188
|
if (sanitizedVisibleOutput && !isLowSignalStructuredCompletion(sanitizedVisibleOutput)) {
|
|
92
189
|
return sanitizedVisibleOutput;
|
|
93
190
|
}
|
|
94
|
-
|
|
191
|
+
if (delegatedTaskOutput) {
|
|
192
|
+
return delegatedTaskOutput;
|
|
193
|
+
}
|
|
95
194
|
if (successfulToolOutput) {
|
|
96
195
|
return successfulToolOutput;
|
|
97
196
|
}
|
|
98
197
|
const sanitizedToolFallback = toolFallback && !looksLikeLeakedToolCallText(toolFallback)
|
|
99
198
|
? sanitizeVisibleText(toolFallback).trim()
|
|
100
199
|
: "";
|
|
200
|
+
if (deterministicFailureReport) {
|
|
201
|
+
return deterministicFailureReport;
|
|
202
|
+
}
|
|
101
203
|
return isLowSignalStructuredCompletion(sanitizedToolFallback) ? "" : sanitizedToolFallback;
|
|
102
204
|
}
|
|
103
205
|
export function extractDelegatedFindingsText(executedToolResults) {
|
|
@@ -4,7 +4,7 @@ import { canReplayToolCallsLocally } from "./tool/tool-replay.js";
|
|
|
4
4
|
import { extractToolCallsFromResult, normalizeToolArgsForSchema, stringifyToolOutput } from "./tool/tool-arguments.js";
|
|
5
5
|
import { extractMemoryCandidatesFromToolOutput } from "../harness/system/runtime-memory-candidates.js";
|
|
6
6
|
import { maybePersistLargeToolOutput } from "./tool/tool-output-artifacts.js";
|
|
7
|
-
import { appendToolRecoveryInstruction, extractVisibleOutput, resolveExecutionWithoutToolEvidenceTextInstruction, sanitizeVisibleText, } from "../parsing/output-parsing.js";
|
|
7
|
+
import { appendToolRecoveryInstruction, extractVisibleOutput, resolveMissingPlanRecoveryInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, sanitizeVisibleText, } from "../parsing/output-parsing.js";
|
|
8
8
|
import { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION } from "../prompts/runtime-prompts.js";
|
|
9
9
|
const TOOL_FOLLOW_UP_INSTRUCTION = "One or more tool results are already available in this conversation. Answer the user's current request directly from the existing context and tool results. Do not ask the user to repeat inputs that are already present above.";
|
|
10
10
|
function readPlanStateSummary(output) {
|
|
@@ -40,6 +40,9 @@ function hasIncompleteExecutedPlan(executedToolResults) {
|
|
|
40
40
|
function hasNonTodoToolEvidence(executedToolResults) {
|
|
41
41
|
return executedToolResults.some((item) => item.toolName !== "write_todos" && item.toolName !== "read_todos");
|
|
42
42
|
}
|
|
43
|
+
function hasPlanStateEvidence(executedToolResults) {
|
|
44
|
+
return executedToolResults.some((item) => item.toolName === "write_todos" || item.toolName === "read_todos" || readPlanStateSummary(item.output) !== null);
|
|
45
|
+
}
|
|
43
46
|
function extractLatestUserInput(request) {
|
|
44
47
|
const typedRequest = request;
|
|
45
48
|
const messages = Array.isArray(typedRequest.messages) ? typedRequest.messages : [];
|
|
@@ -80,7 +83,9 @@ export async function runLocalToolInvocationLoop({ binding, request, primaryTool
|
|
|
80
83
|
const hasExecutionBeyondTodoPlanning = hasNonTodoToolEvidence(executedToolResults);
|
|
81
84
|
const recoveryInstruction = terminalText
|
|
82
85
|
? resolveExecutionWithoutToolEvidenceTextInstruction(activeRequest, terminalText, false, {
|
|
86
|
+
hasWriteTodosEvidence: executedToolResults.some((item) => item.toolName === "write_todos"),
|
|
83
87
|
hasToolResultEvidence: hasExecutionBeyondTodoPlanning,
|
|
88
|
+
hasPlanStateEvidence: hasPlanStateEvidence(executedToolResults),
|
|
84
89
|
hasIncompletePlanState: hasExecutionBeyondTodoPlanning && hasIncompletePlanState,
|
|
85
90
|
})
|
|
86
91
|
: hasIncompletePlanState && hasExecutionBeyondTodoPlanning
|
|
@@ -95,6 +100,21 @@ export async function runLocalToolInvocationLoop({ binding, request, primaryTool
|
|
|
95
100
|
}
|
|
96
101
|
break;
|
|
97
102
|
}
|
|
103
|
+
const missingPlanRecoveryInstruction = resolveMissingPlanRecoveryInstruction({
|
|
104
|
+
request: activeRequest,
|
|
105
|
+
hasPlanStateEvidence: hasPlanStateEvidence(executedToolResults),
|
|
106
|
+
hasWriteTodosEvidence: executedToolResults.some((item) => item.toolName === "write_todos"),
|
|
107
|
+
hasToolResultEvidence: executedToolResults.length > 0 || toolCalls.length > 0,
|
|
108
|
+
});
|
|
109
|
+
if (missingPlanRecoveryInstruction
|
|
110
|
+
&& toolCalls.some((toolCall) => {
|
|
111
|
+
const resolvedToolName = resolveModelFacingToolName(toolCall.name, toolNameMapping, primaryTools);
|
|
112
|
+
return resolvedToolName !== "write_todos" && resolvedToolName !== "read_todos" && toolCall.name !== "write_todos" && toolCall.name !== "read_todos";
|
|
113
|
+
})) {
|
|
114
|
+
activeRequest = appendToolRecoveryInstruction(activeRequest, missingPlanRecoveryInstruction);
|
|
115
|
+
pendingResult = undefined;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
98
118
|
if (!canReplayToolCallsLocally(binding, toolCalls, primaryTools, toolNameMapping, executableTools, builtinExecutableTools)) {
|
|
99
119
|
break;
|
|
100
120
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createMiddleware } from "langchain";
|
|
2
|
+
import { isRecord } from "../../../utils/object.js";
|
|
3
|
+
const REASONING_METADATA_KEYS = new Set([
|
|
4
|
+
"reasoning",
|
|
5
|
+
"reasoning_content",
|
|
6
|
+
"thinking",
|
|
7
|
+
"redacted_thinking",
|
|
8
|
+
]);
|
|
9
|
+
const REASONING_CONTENT_BLOCK_TYPES = new Set([
|
|
10
|
+
"reasoning",
|
|
11
|
+
"thinking",
|
|
12
|
+
"redacted_thinking",
|
|
13
|
+
]);
|
|
14
|
+
function pruneReasoningValue(value) {
|
|
15
|
+
if (Array.isArray(value)) {
|
|
16
|
+
let changed = false;
|
|
17
|
+
const next = [];
|
|
18
|
+
for (const item of value) {
|
|
19
|
+
if (isRecord(item) && typeof item.type === "string" && REASONING_CONTENT_BLOCK_TYPES.has(item.type)) {
|
|
20
|
+
changed = true;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const pruned = pruneReasoningValue(item);
|
|
24
|
+
changed = changed || pruned.changed;
|
|
25
|
+
next.push(pruned.value);
|
|
26
|
+
}
|
|
27
|
+
return changed ? { value: next, changed } : { value, changed: false };
|
|
28
|
+
}
|
|
29
|
+
if (!isRecord(value)) {
|
|
30
|
+
return { value, changed: false };
|
|
31
|
+
}
|
|
32
|
+
let changed = false;
|
|
33
|
+
const next = {};
|
|
34
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
35
|
+
if (REASONING_METADATA_KEYS.has(key)) {
|
|
36
|
+
changed = true;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const pruned = pruneReasoningValue(entry);
|
|
40
|
+
changed = changed || pruned.changed;
|
|
41
|
+
next[key] = pruned.value;
|
|
42
|
+
}
|
|
43
|
+
return changed ? { value: next, changed } : { value, changed: false };
|
|
44
|
+
}
|
|
45
|
+
function pruneMessageReasoningMetadata(message) {
|
|
46
|
+
if (!isRecord(message)) {
|
|
47
|
+
return { message, changed: false };
|
|
48
|
+
}
|
|
49
|
+
let changed = false;
|
|
50
|
+
const next = Object.assign(Object.create(Object.getPrototypeOf(message)), message);
|
|
51
|
+
for (const key of ["additional_kwargs", "response_metadata", "content", "lc_kwargs", "kwargs"]) {
|
|
52
|
+
const pruned = pruneReasoningValue(message[key]);
|
|
53
|
+
if (pruned.changed) {
|
|
54
|
+
next[key] = pruned.value;
|
|
55
|
+
changed = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return changed ? { message: next, changed } : { message, changed: false };
|
|
59
|
+
}
|
|
60
|
+
export function pruneReasoningMetadataFromMessages(messages) {
|
|
61
|
+
if (!Array.isArray(messages)) {
|
|
62
|
+
return { messages, changed: false };
|
|
63
|
+
}
|
|
64
|
+
let changed = false;
|
|
65
|
+
const next = messages.map((message) => {
|
|
66
|
+
const pruned = pruneMessageReasoningMetadata(message);
|
|
67
|
+
changed = changed || pruned.changed;
|
|
68
|
+
return pruned.message;
|
|
69
|
+
});
|
|
70
|
+
return changed ? { messages: next, changed } : { messages, changed: false };
|
|
71
|
+
}
|
|
72
|
+
export function createContextHygieneMiddleware() {
|
|
73
|
+
return createMiddleware({
|
|
74
|
+
name: "HarnessContextHygieneMiddleware",
|
|
75
|
+
beforeModel: (state) => {
|
|
76
|
+
if (!isRecord(state)) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const pruned = pruneReasoningMetadataFromMessages(state.messages);
|
|
80
|
+
return pruned.changed ? { messages: pruned.messages } : undefined;
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { FilesystemBackend } from "deepagents";
|
|
2
2
|
import type { CompiledAgentBinding, CompiledModel, CompiledSubAgent, DeepAgentParams, RuntimeAdapterOptions } from "../../contracts/types.js";
|
|
3
3
|
import type { ExecutableTool } from "./flow/invoke-runtime.js";
|
|
4
|
+
type RunnableLike = {
|
|
5
|
+
invoke: (input: unknown, config?: Record<string, unknown>) => Promise<unknown>;
|
|
6
|
+
};
|
|
4
7
|
export type LangChainRuntimeExtensionPlan = {
|
|
5
8
|
includePatchToolCalls: boolean;
|
|
6
9
|
includeAutomaticSummarization: boolean;
|
|
@@ -27,7 +30,13 @@ export type UpstreamSubagentConfig = {
|
|
|
27
30
|
}>;
|
|
28
31
|
responseFormat?: unknown;
|
|
29
32
|
middleware?: unknown[];
|
|
33
|
+
runnable?: RunnableLike;
|
|
30
34
|
};
|
|
35
|
+
export declare function extractSubagentRequestText(state: unknown): string;
|
|
36
|
+
export declare function wrapRequestResultAsSubagentResponse(result: {
|
|
37
|
+
output: string;
|
|
38
|
+
structuredResponse?: unknown;
|
|
39
|
+
}): Record<string, unknown>;
|
|
31
40
|
export declare function buildBuiltinTaskSubagentMiddleware(input: {
|
|
32
41
|
selectedSubagent: UpstreamSubagentConfig;
|
|
33
42
|
builtinBackend: unknown;
|
|
@@ -49,6 +58,7 @@ export declare function resolveSubagents(input: {
|
|
|
49
58
|
resolveModel: (model: CompiledModel) => Promise<unknown>;
|
|
50
59
|
resolveTools: (tools: Parameters<DeepAgentParams["tools"]["slice"]>[0] extends never ? never : any, binding?: CompiledAgentBinding) => unknown[];
|
|
51
60
|
createDeclaredMiddlewareResolverOptions: (binding?: CompiledAgentBinding) => unknown;
|
|
61
|
+
resolveBackend?: (binding?: CompiledAgentBinding) => unknown;
|
|
52
62
|
}): Promise<UpstreamSubagentConfig[]>;
|
|
53
63
|
export declare function invokeBuiltinTaskTool(input: {
|
|
54
64
|
binding: CompiledAgentBinding;
|
|
@@ -118,3 +128,4 @@ export declare function resolveMiddleware(input: {
|
|
|
118
128
|
createDeclaredMiddlewareResolverOptions: (binding?: CompiledAgentBinding) => unknown;
|
|
119
129
|
resolveLangChainRuntimeExtensionMiddleware: (binding: CompiledAgentBinding) => Promise<unknown[]>;
|
|
120
130
|
}): Promise<unknown[]>;
|
|
131
|
+
export {};
|