@botbotgo/agent-harness 0.0.392 → 0.0.394
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.
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.394";
|
|
2
2
|
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-05-02";
|
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.394";
|
|
2
2
|
export const AGENT_HARNESS_RELEASE_DATE = "2026-05-02";
|
|
@@ -5,6 +5,7 @@ import { buildRawModelMessages } from "../model/message-assembly.js";
|
|
|
5
5
|
import { projectRuntimeStreamEvent, createStreamEventProjectionState } from "../stream-event-projection.js";
|
|
6
6
|
import { projectTextStreamChunks } from "../stream-text-consumption.js";
|
|
7
7
|
import { computeRemainingTimeoutMs } from "../resilience.js";
|
|
8
|
+
import { stringifyToolOutput } from "../tool/tool-arguments.js";
|
|
8
9
|
import { UPSTREAM_REQUEST_CONFIG_KEY, UPSTREAM_SESSION_CONFIG_KEY } from "../upstream-configurable-keys.js";
|
|
9
10
|
export class ExecutionReconciliationError extends Error {
|
|
10
11
|
constructor(message) {
|
|
@@ -61,12 +62,48 @@ function hasIncompletePlanStateInExecutedToolResults(executedToolResults) {
|
|
|
61
62
|
}
|
|
62
63
|
return false;
|
|
63
64
|
}
|
|
65
|
+
function hasIncompleteTodosArray(value) {
|
|
66
|
+
if (!Array.isArray(value)) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return value.some((todo) => typeof todo === "object"
|
|
70
|
+
&& todo !== null
|
|
71
|
+
&& typeof todo.status === "string"
|
|
72
|
+
&& ["pending", "in_progress"].includes(todo.status.trim().toLowerCase()));
|
|
73
|
+
}
|
|
74
|
+
function hasIncompletePlanOutput(value) {
|
|
75
|
+
if (typeof value !== "object" || value === null) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const typed = value;
|
|
79
|
+
if (typeof typed.pending === "number" || typeof typed.inProgress === "number") {
|
|
80
|
+
return (typeof typed.pending === "number" ? typed.pending : 0) > 0
|
|
81
|
+
|| (typeof typed.inProgress === "number" ? typed.inProgress : 0) > 0;
|
|
82
|
+
}
|
|
83
|
+
const directTodos = hasIncompleteTodosArray(typed.todos);
|
|
84
|
+
if (directTodos !== null) {
|
|
85
|
+
return directTodos;
|
|
86
|
+
}
|
|
87
|
+
for (const nested of [typed.summary, typed.update, typed.data, typed.output]) {
|
|
88
|
+
const nestedCompleteness = hasIncompletePlanOutput(nested);
|
|
89
|
+
if (nestedCompleteness !== null) {
|
|
90
|
+
return nestedCompleteness;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
64
95
|
function isPlanToolName(toolName) {
|
|
65
96
|
return toolName === "write_todos"
|
|
66
97
|
|| toolName === "read_todos"
|
|
67
98
|
|| toolName === "tool_call_write_todos"
|
|
68
99
|
|| toolName === "tool_call_read_todos";
|
|
69
100
|
}
|
|
101
|
+
function isCompletedPlanToolResultChunk(chunk) {
|
|
102
|
+
if (chunk.kind !== "tool-result" || !isPlanToolName(chunk.toolName)) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return hasIncompletePlanOutput(chunk.output) === false;
|
|
106
|
+
}
|
|
70
107
|
function hasNonTodoToolEvidence(executedToolResults) {
|
|
71
108
|
return executedToolResults.some((item) => !isPlanToolName(item.toolName));
|
|
72
109
|
}
|
|
@@ -128,6 +165,26 @@ function hasCompletedPlanWithEvidence(evidence) {
|
|
|
128
165
|
&& !hasMissingDelegatedExecutionEvidence(evidence)
|
|
129
166
|
&& !hasMissingDelegatedFindings(evidence);
|
|
130
167
|
}
|
|
168
|
+
function buildDeterministicFinalFromStreamToolEvidence(executedToolResults) {
|
|
169
|
+
const evidence = executedToolResults
|
|
170
|
+
.filter((item) => item.isError !== true && !isPlanToolName(item.toolName))
|
|
171
|
+
.map((item) => {
|
|
172
|
+
const visible = toVisibleContent(item.output);
|
|
173
|
+
const raw = visible || stringifyToolOutput(item.output).trim();
|
|
174
|
+
const clipped = raw.length > 4000 ? `${raw.slice(0, 4000)}\n... [truncated]` : raw;
|
|
175
|
+
return `## ${item.toolName}\n${clipped}`;
|
|
176
|
+
});
|
|
177
|
+
return [
|
|
178
|
+
"Status: completed",
|
|
179
|
+
"",
|
|
180
|
+
"Summary:",
|
|
181
|
+
"- Completed the required TODO burn down after collecting tool evidence.",
|
|
182
|
+
"- Returning an evidence-grounded deterministic summary because the streamed model did not produce a clean final synthesis before the required plan completed.",
|
|
183
|
+
"",
|
|
184
|
+
"Evidence:",
|
|
185
|
+
evidence.length > 0 ? evidence.join("\n\n") : "(no non-planning tool evidence captured)",
|
|
186
|
+
].join("\n");
|
|
187
|
+
}
|
|
131
188
|
function readBindingExecutionParams(binding) {
|
|
132
189
|
const params = binding.execution?.params ?? binding.deepAgentParams ?? binding.langchainAgentParams;
|
|
133
190
|
return {
|
|
@@ -460,6 +517,9 @@ export async function* streamRuntimeExecution(options) {
|
|
|
460
517
|
if (shouldProfile)
|
|
461
518
|
yield streamEventsConsume.chunk;
|
|
462
519
|
try {
|
|
520
|
+
let sawCompletedPlanToolResult = false;
|
|
521
|
+
let sawSuccessfulNonTodoToolResult = false;
|
|
522
|
+
const streamedToolResults = [];
|
|
463
523
|
for await (const event of options.iterateWithTimeout(events, options.streamIdleTimeoutMs, "agent streamEvents", options.streamDeadlineAt, options.invokeTimeoutMs)) {
|
|
464
524
|
const projectedChunks = projectRuntimeStreamEvent({
|
|
465
525
|
event,
|
|
@@ -484,18 +544,46 @@ export async function* streamRuntimeExecution(options) {
|
|
|
484
544
|
if (chunk.kind === "tool-result" && chunk.isError === true && isRetrySafeInvalidToolSelectionError(chunk.output)) {
|
|
485
545
|
sawRetrySafeInvalidToolSelectionError = true;
|
|
486
546
|
}
|
|
547
|
+
if (chunk.kind === "tool-result") {
|
|
548
|
+
streamedToolResults.push({
|
|
549
|
+
toolName: chunk.toolName,
|
|
550
|
+
output: chunk.output,
|
|
551
|
+
isError: chunk.isError,
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
if (chunk.kind === "tool-result" && !isPlanToolName(chunk.toolName) && chunk.isError !== true) {
|
|
555
|
+
sawSuccessfulNonTodoToolResult = true;
|
|
556
|
+
}
|
|
557
|
+
if (isCompletedPlanToolResultChunk(chunk)) {
|
|
558
|
+
sawCompletedPlanToolResult = true;
|
|
559
|
+
}
|
|
487
560
|
if ((eventContainsNonTodoToolResult || eventContainsNonRetrySafeChunk) && deferredStreamContent.length > 0) {
|
|
488
561
|
yield* flushDeferredStreamContent();
|
|
489
562
|
}
|
|
490
563
|
if (eventContainsNonTodoToolResult || eventContainsNonRetrySafeChunk) {
|
|
491
564
|
emittedUnsafeStreamSideEffects = true;
|
|
492
565
|
}
|
|
493
|
-
|
|
566
|
+
const shouldDeferRequiredPlanContent = requiresPlanEvidence(options.binding)
|
|
567
|
+
&& projectionState.sawPlanState
|
|
568
|
+
&& !hasCompletedPlanWithEvidence(buildExecutionRecoveryEvidence({ projectionState }));
|
|
569
|
+
if (chunk.kind === "content"
|
|
570
|
+
&& (shouldDeferStreamContent() || projectionState.hasFailedTaskDelegation || shouldDeferRequiredPlanContent)) {
|
|
494
571
|
deferredStreamContent.push(chunk);
|
|
495
572
|
continue;
|
|
496
573
|
}
|
|
497
574
|
yield chunk;
|
|
498
575
|
}
|
|
576
|
+
if (requiresPlanEvidence(options.binding) && sawCompletedPlanToolResult && sawSuccessfulNonTodoToolResult) {
|
|
577
|
+
deferredStreamContent.length = 0;
|
|
578
|
+
yield { kind: "content", content: buildDeterministicFinalFromStreamToolEvidence(streamedToolResults) };
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
const eventExecutionEvidence = buildExecutionRecoveryEvidence({ projectionState });
|
|
582
|
+
if (requiresPlanEvidence(options.binding) && hasCompletedPlanWithEvidence(eventExecutionEvidence)) {
|
|
583
|
+
deferredStreamContent.length = 0;
|
|
584
|
+
yield { kind: "content", content: buildDeterministicFinalFromStreamToolEvidence(streamedToolResults) };
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
499
587
|
const terminalVisibleOutput = readTerminalEventVisibleOutput(event);
|
|
500
588
|
if (terminalVisibleOutput) {
|
|
501
589
|
const terminalExecutionEvidence = buildExecutionRecoveryEvidence({ projectionState });
|