@botbotgo/agent-harness 0.0.342 → 0.0.344
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/chat-stream.d.ts +1 -0
- package/dist/cli/chat-stream.js +27 -0
- package/dist/cli/chat-workspace.js +5 -0
- package/dist/cli.js +1 -1
- package/dist/contracts/workspace.d.ts +8 -4
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/adapter/flow/stream-runtime.js +20 -1
- package/dist/runtime/adapter/resilience.js +4 -0
- package/dist/runtime/adapter/tool/builtin-middleware-tools.d.ts +1 -0
- package/dist/runtime/adapter/tool/builtin-middleware-tools.js +18 -0
- package/dist/runtime/agent-runtime-adapter.js +2 -0
- package/dist/runtime/agent-runtime-assembly.d.ts +1 -0
- package/dist/runtime/agent-runtime-assembly.js +8 -1
- package/dist/runtime/harness/run/inspection.js +17 -3
- package/dist/runtime/harness/run/stream-run.js +71 -6
- package/dist/runtime/harness.d.ts +1 -0
- package/dist/runtime/harness.js +19 -1
- package/dist/runtime/support/compiled-binding.d.ts +2 -5
- package/dist/workspace/agent-binding-compiler.js +1 -0
- package/package.json +1 -1
package/dist/cli/chat-stream.js
CHANGED
|
@@ -3,6 +3,7 @@ import { countRenderedLines, renderChatRequestRunning, renderChatTextChunk, summ
|
|
|
3
3
|
import { buildTerminalRequestSnapshot, buildTodoContinuationSignature, flattenRequestExecutionSteps, renderRequestEventContinuation, renderRequestSnapshotTree, renderRequestTodoContinuation, } from "./request-tree.js";
|
|
4
4
|
export async function streamChatMessage(input) {
|
|
5
5
|
const requestStartedAt = Date.now();
|
|
6
|
+
const idleProgressMs = input.idleProgressMs ?? 30_000;
|
|
6
7
|
let firstSnapshotAt;
|
|
7
8
|
let firstDataAt;
|
|
8
9
|
let latestSnapshot;
|
|
@@ -27,6 +28,8 @@ export async function streamChatMessage(input) {
|
|
|
27
28
|
const requestTreeRenderThrottleMs = 75;
|
|
28
29
|
let suppressRequestTreeRendering = false;
|
|
29
30
|
let lastStableRequestTreeKey;
|
|
31
|
+
let idleProgressTimer;
|
|
32
|
+
let lastRuntimeProgressAt = requestStartedAt;
|
|
30
33
|
let stdoutWriteChain = Promise.resolve();
|
|
31
34
|
let stderrWriteChain = Promise.resolve();
|
|
32
35
|
const enqueueChatWrite = (sink, _stream, chain, message) => chain.then(async () => {
|
|
@@ -173,6 +176,27 @@ export async function streamChatMessage(input) {
|
|
|
173
176
|
}
|
|
174
177
|
stderrWriteChain = enqueueChatWrite(input.stderr, input.stderrStream, stderrWriteChain, message);
|
|
175
178
|
};
|
|
179
|
+
const clearIdleProgressTimer = () => {
|
|
180
|
+
if (idleProgressTimer) {
|
|
181
|
+
clearTimeout(idleProgressTimer);
|
|
182
|
+
idleProgressTimer = undefined;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const scheduleIdleProgress = () => {
|
|
186
|
+
clearIdleProgressTimer();
|
|
187
|
+
if (idleProgressMs <= 0) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
idleProgressTimer = setTimeout(() => {
|
|
191
|
+
const idleSeconds = Math.max(1, Math.round((Date.now() - lastRuntimeProgressAt) / 1000));
|
|
192
|
+
writeChatStderr(`[${formatPerfClock(Date.now())} +${formatElapsed(Date.now())}]${formatAgentProgressLabel(latestAgentId)} Still working; no runtime update for ${idleSeconds}s.\n`);
|
|
193
|
+
scheduleIdleProgress();
|
|
194
|
+
}, idleProgressMs);
|
|
195
|
+
};
|
|
196
|
+
const markRuntimeProgress = () => {
|
|
197
|
+
lastRuntimeProgressAt = Date.now();
|
|
198
|
+
scheduleIdleProgress();
|
|
199
|
+
};
|
|
176
200
|
const suspendRequestTreeRendering = () => {
|
|
177
201
|
if (!input.requestEvents || !input.liveRequestTree) {
|
|
178
202
|
return;
|
|
@@ -258,6 +282,7 @@ export async function streamChatMessage(input) {
|
|
|
258
282
|
...(input.sessionId ? { sessionId: input.sessionId } : {}),
|
|
259
283
|
input: input.message,
|
|
260
284
|
eventListener(snapshot) {
|
|
285
|
+
markRuntimeProgress();
|
|
261
286
|
latestSessionId = snapshot.sessionId || latestSessionId;
|
|
262
287
|
latestRequestId = snapshot.requestId || latestRequestId;
|
|
263
288
|
latestAgentId = snapshot.agentId || latestAgentId;
|
|
@@ -303,6 +328,7 @@ export async function streamChatMessage(input) {
|
|
|
303
328
|
}
|
|
304
329
|
},
|
|
305
330
|
dataListener(delta) {
|
|
331
|
+
markRuntimeProgress();
|
|
306
332
|
latestSessionId = delta.sessionId || latestSessionId;
|
|
307
333
|
latestRequestId = delta.requestId || latestRequestId;
|
|
308
334
|
firstDataAt ??= Date.now();
|
|
@@ -342,6 +368,7 @@ export async function streamChatMessage(input) {
|
|
|
342
368
|
}
|
|
343
369
|
},
|
|
344
370
|
});
|
|
371
|
+
clearIdleProgressTimer();
|
|
345
372
|
if (!result) {
|
|
346
373
|
throw new Error("chat request completed without a terminal result");
|
|
347
374
|
}
|
|
@@ -161,10 +161,12 @@ export function renderChatRuntimeFailure(output, modelInfo) {
|
|
|
161
161
|
if (!normalized.includes("fetch failed") &&
|
|
162
162
|
!normalized.includes("connection error") &&
|
|
163
163
|
!normalized.includes("timed out") &&
|
|
164
|
+
!normalized.includes("error 524") &&
|
|
164
165
|
!normalized.includes("404 page not found")) {
|
|
165
166
|
return output;
|
|
166
167
|
}
|
|
167
168
|
const lines = [trimmed];
|
|
169
|
+
const isTimeoutStyleError = /(\berror 524\b|\btimeout\b|\btimed out\b)/i.test(trimmed);
|
|
168
170
|
if (modelInfo?.provider || modelInfo?.model) {
|
|
169
171
|
lines.push(`provider=${modelInfo?.provider ?? "unknown"}${modelInfo?.model ? ` model=${modelInfo.model}` : ""}`);
|
|
170
172
|
}
|
|
@@ -178,6 +180,9 @@ export function renderChatRuntimeFailure(output, modelInfo) {
|
|
|
178
180
|
if (hint) {
|
|
179
181
|
lines.push(hint);
|
|
180
182
|
}
|
|
183
|
+
if (isTimeoutStyleError) {
|
|
184
|
+
lines.push("Hint: this usually indicates the model endpoint dropped the connection before producing a full answer.");
|
|
185
|
+
}
|
|
181
186
|
return lines.join("\n");
|
|
182
187
|
}
|
|
183
188
|
export async function probeChatWorkspace(input) {
|
package/dist/cli.js
CHANGED
|
@@ -4,5 +4,5 @@ import { runCli, resolveInvokedCliHref } from "./cli/main.js";
|
|
|
4
4
|
const invokedPath = resolveInvokedCliHref(process.argv[1]);
|
|
5
5
|
if (import.meta.url === invokedPath) {
|
|
6
6
|
const exitCode = await runCli(process.argv.slice(2));
|
|
7
|
-
process.exitCode
|
|
7
|
+
process.exit(exitCode);
|
|
8
8
|
}
|
|
@@ -187,6 +187,7 @@ export type CompiledSubAgent = {
|
|
|
187
187
|
builtinTools?: {
|
|
188
188
|
filesystem?: boolean;
|
|
189
189
|
todos?: boolean;
|
|
190
|
+
modelExposed?: boolean | string[];
|
|
190
191
|
};
|
|
191
192
|
};
|
|
192
193
|
export type CompiledAsyncSubAgent = {
|
|
@@ -197,6 +198,11 @@ export type CompiledAsyncSubAgent = {
|
|
|
197
198
|
headers?: Record<string, string>;
|
|
198
199
|
};
|
|
199
200
|
export type CompiledDeepAgentSubAgent = CompiledSubAgent | CompiledAsyncSubAgent;
|
|
201
|
+
export type CompiledBuiltinToolsConfig = {
|
|
202
|
+
filesystem?: boolean;
|
|
203
|
+
todos?: boolean;
|
|
204
|
+
modelExposed?: boolean | string[];
|
|
205
|
+
};
|
|
200
206
|
export type LangChainAgentParams = {
|
|
201
207
|
model: CompiledModel;
|
|
202
208
|
tools: CompiledTool[];
|
|
@@ -209,6 +215,7 @@ export type LangChainAgentParams = {
|
|
|
209
215
|
version?: "v1" | "v2";
|
|
210
216
|
name?: string;
|
|
211
217
|
description: string;
|
|
218
|
+
builtinTools?: CompiledBuiltinToolsConfig;
|
|
212
219
|
};
|
|
213
220
|
export type DeepAgentParams = {
|
|
214
221
|
model: CompiledModel;
|
|
@@ -225,10 +232,7 @@ export type DeepAgentParams = {
|
|
|
225
232
|
memory: string[];
|
|
226
233
|
skills: string[];
|
|
227
234
|
interactionMode?: "stream" | "invoke";
|
|
228
|
-
builtinTools?:
|
|
229
|
-
filesystem?: boolean;
|
|
230
|
-
todos?: boolean;
|
|
231
|
-
};
|
|
235
|
+
builtinTools?: CompiledBuiltinToolsConfig;
|
|
232
236
|
};
|
|
233
237
|
export type LegacyLangChainAgentParams = LangChainAgentParams & {
|
|
234
238
|
passthrough?: Record<string, unknown>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.344";
|
|
2
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.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.344";
|
|
2
2
|
export const AGENT_HARNESS_RELEASE_DATE = "2026-04-24";
|
|
@@ -84,6 +84,19 @@ function hasMissingDelegatedExecutionEvidence(evidence) {
|
|
|
84
84
|
function hasMissingDelegatedFindings(evidence) {
|
|
85
85
|
return evidence.hasDelegatedAgentWithConfiguredTools && evidence.hasOnlyPlaceholderTaskCompletion;
|
|
86
86
|
}
|
|
87
|
+
function isRuntimeFailureOutput(value) {
|
|
88
|
+
return value.trim().startsWith("runtime_error=");
|
|
89
|
+
}
|
|
90
|
+
function resolveStreamedRuntimeFailureRecoveryInstruction(output, evidence) {
|
|
91
|
+
if (!isRuntimeFailureOutput(output)) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const hasExecutionEvidence = evidence.hasToolResultEvidence
|
|
95
|
+
|| evidence.hasPlanStateEvidence
|
|
96
|
+
|| evidence.hasOpenTaskDelegation
|
|
97
|
+
|| evidence.hasDelegatedExecutionToolEvidence;
|
|
98
|
+
return hasExecutionEvidence ? null : EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION;
|
|
99
|
+
}
|
|
87
100
|
function resolveDelegatedExecutionRecoveryInstruction(evidence) {
|
|
88
101
|
if (hasMissingDelegatedFindings(evidence)
|
|
89
102
|
|| (evidence.hasOpenTaskDelegation
|
|
@@ -442,6 +455,9 @@ export async function* streamRuntimeExecution(options) {
|
|
|
442
455
|
hasMissingDelegatedExecutionEvidence: hasMissingDelegatedExecutionEvidence(streamedExecutionEvidence),
|
|
443
456
|
})
|
|
444
457
|
: null;
|
|
458
|
+
const streamedRuntimeFailureRecoveryInstruction = projectionState.emittedOutput
|
|
459
|
+
? resolveStreamedRuntimeFailureRecoveryInstruction(projectionState.emittedOutput, streamedExecutionEvidence)
|
|
460
|
+
: null;
|
|
445
461
|
const missingPlanRecoveryInstruction = !hasUnresolvedExecution(streamedExecutionEvidence) && !delegatedExecutionRecoveryInstruction
|
|
446
462
|
? resolveMissingPlanRecoveryInstruction({
|
|
447
463
|
request,
|
|
@@ -453,7 +469,10 @@ export async function* streamRuntimeExecution(options) {
|
|
|
453
469
|
: null;
|
|
454
470
|
const retryInstruction = !emittedUnsafeStreamSideEffects && sawRetrySafeInvalidToolSelectionError
|
|
455
471
|
? INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION
|
|
456
|
-
: delegatedExecutionRecoveryInstruction
|
|
472
|
+
: delegatedExecutionRecoveryInstruction
|
|
473
|
+
?? streamedRuntimeFailureRecoveryInstruction
|
|
474
|
+
?? missingPlanRecoveryInstruction
|
|
475
|
+
?? executionWithoutToolEvidenceInstruction;
|
|
457
476
|
if (retryInstruction) {
|
|
458
477
|
let retried;
|
|
459
478
|
retried = await options.invoke(options.applyToolRecoveryInstruction(options.binding, retryInstruction), options.input, options.sessionId, options.runtimeOptions.requestId ?? options.sessionId, undefined, options.history, options.runtimeOptions);
|
|
@@ -32,6 +32,10 @@ export function resolveStreamIdleTimeout(binding) {
|
|
|
32
32
|
}
|
|
33
33
|
const BUILTIN_RETRYABLE_PROVIDER_MESSAGES = [
|
|
34
34
|
"unexpected eof",
|
|
35
|
+
"other side closed",
|
|
36
|
+
"socket hang up",
|
|
37
|
+
"connection reset",
|
|
38
|
+
"econnreset",
|
|
35
39
|
];
|
|
36
40
|
function isEmptyFinalAiMessageError(error) {
|
|
37
41
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -246,6 +246,7 @@ export declare const BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS: readonly [{
|
|
|
246
246
|
export declare function filterBuiltinMiddlewareToolDescriptors(options?: {
|
|
247
247
|
filesystem?: boolean;
|
|
248
248
|
todos?: boolean;
|
|
249
|
+
modelExposed?: boolean | string[];
|
|
249
250
|
}): Array<{
|
|
250
251
|
name: string;
|
|
251
252
|
description: string;
|
|
@@ -29,6 +29,16 @@ export const BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS = [
|
|
|
29
29
|
{ name: "task", description: "Delegate a bounded task to a subagent." },
|
|
30
30
|
];
|
|
31
31
|
export function filterBuiltinMiddlewareToolDescriptors(options) {
|
|
32
|
+
const modelExposedNames = new Set([
|
|
33
|
+
"fetch_url",
|
|
34
|
+
"http_request",
|
|
35
|
+
"send_message",
|
|
36
|
+
"request_approval",
|
|
37
|
+
"schedule_task",
|
|
38
|
+
]);
|
|
39
|
+
const allowedModelExposedNames = Array.isArray(options?.modelExposed)
|
|
40
|
+
? new Set(options.modelExposed)
|
|
41
|
+
: undefined;
|
|
32
42
|
return BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS.filter((descriptor) => {
|
|
33
43
|
if (options?.todos === false
|
|
34
44
|
&& (descriptor.name === "write_todos" || descriptor.name === "read_todos")) {
|
|
@@ -49,6 +59,14 @@ export function filterBuiltinMiddlewareToolDescriptors(options) {
|
|
|
49
59
|
].includes(descriptor.name)) {
|
|
50
60
|
return false;
|
|
51
61
|
}
|
|
62
|
+
if (modelExposedNames.has(descriptor.name)) {
|
|
63
|
+
if (options?.modelExposed === false) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (allowedModelExposedNames && !allowedModelExposedNames.has(descriptor.name)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
52
70
|
return true;
|
|
53
71
|
}).map((descriptor) => ({ ...descriptor }));
|
|
54
72
|
}
|
|
@@ -360,6 +360,7 @@ export class AgentRuntimeAdapter {
|
|
|
360
360
|
}),
|
|
361
361
|
}),
|
|
362
362
|
explicitToolNames: primaryTools.map((tool) => tool.name),
|
|
363
|
+
modelExposed: getBindingBuiltinToolsConfig(binding)?.modelExposed,
|
|
363
364
|
});
|
|
364
365
|
const resolvedMiddleware = await this.resolveMiddleware(binding, interruptOn, { sessionId: options.sessionId ?? options.legacySessionId });
|
|
365
366
|
const resolvedCheckpointer = resolveRunnableCheckpointer(this.options, binding);
|
|
@@ -405,6 +406,7 @@ export class AgentRuntimeAdapter {
|
|
|
405
406
|
}),
|
|
406
407
|
}),
|
|
407
408
|
explicitToolNames: primaryTools.map((tool) => tool.name),
|
|
409
|
+
modelExposed: getBindingBuiltinToolsConfig(binding)?.modelExposed,
|
|
408
410
|
});
|
|
409
411
|
const resolvedMiddleware = await this.resolveMiddleware(binding);
|
|
410
412
|
const resolvedSubagents = await this.resolveDeepAgentSubagents(getBindingDeepAgentSubagents(binding), binding, { sessionId: options.sessionId ?? options.legacySessionId });
|
|
@@ -6,6 +6,7 @@ export declare const DEFAULT_DEEPAGENT_RECURSION_LIMIT = 100;
|
|
|
6
6
|
export declare function materializeModelExposedBuiltinMiddlewareTools(input: {
|
|
7
7
|
builtinTools: Map<string, ExecutableTool>;
|
|
8
8
|
explicitToolNames?: string[];
|
|
9
|
+
modelExposed?: boolean | string[];
|
|
9
10
|
}): unknown[];
|
|
10
11
|
export declare function resolveRunnableCheckpointer(options: RuntimeAdapterOptions, binding: CompiledAgentBinding): unknown;
|
|
11
12
|
export declare function resolveRunnableInterruptOn(binding: CompiledAgentBinding): Record<string, {
|
|
@@ -18,12 +18,19 @@ const MODEL_EXPOSED_BUILTIN_MIDDLEWARE_TOOL_NAMES = new Set([
|
|
|
18
18
|
"schedule_task",
|
|
19
19
|
]);
|
|
20
20
|
export function materializeModelExposedBuiltinMiddlewareTools(input) {
|
|
21
|
+
if (input.modelExposed === false) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
21
24
|
const explicitToolNames = new Set(input.explicitToolNames ?? []);
|
|
25
|
+
const allowedToolNames = Array.isArray(input.modelExposed)
|
|
26
|
+
? new Set(input.modelExposed)
|
|
27
|
+
: undefined;
|
|
22
28
|
const tools = [];
|
|
23
29
|
for (const [toolName, tool] of input.builtinTools.entries()) {
|
|
24
30
|
if (explicitToolNames.has(toolName)
|
|
25
31
|
|| BUILTIN_MIDDLEWARE_ALIAS_TOOL_NAMES.has(toolName)
|
|
26
|
-
|| !MODEL_EXPOSED_BUILTIN_MIDDLEWARE_TOOL_NAMES.has(toolName)
|
|
32
|
+
|| !MODEL_EXPOSED_BUILTIN_MIDDLEWARE_TOOL_NAMES.has(toolName)
|
|
33
|
+
|| (allowedToolNames && !allowedToolNames.has(toolName))) {
|
|
27
34
|
continue;
|
|
28
35
|
}
|
|
29
36
|
tools.push(asStructuredExecutableTool(tool, toolName, tool.name));
|
|
@@ -11,6 +11,13 @@ function asObject(value) {
|
|
|
11
11
|
function readStringArray(value) {
|
|
12
12
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
|
|
13
13
|
}
|
|
14
|
+
const MODEL_EXPOSED_BUILTIN_TOOL_NAMES = new Set([
|
|
15
|
+
"fetch_url",
|
|
16
|
+
"http_request",
|
|
17
|
+
"send_message",
|
|
18
|
+
"request_approval",
|
|
19
|
+
"schedule_task",
|
|
20
|
+
]);
|
|
14
21
|
function getBindingSkillNames(binding) {
|
|
15
22
|
if (!binding) {
|
|
16
23
|
return [];
|
|
@@ -106,13 +113,20 @@ export function buildRequestRuntimeSnapshot(binding, options) {
|
|
|
106
113
|
name: tool.name,
|
|
107
114
|
description: tool.description,
|
|
108
115
|
}));
|
|
116
|
+
const builtinToolsConfig = getBindingBuiltinToolsConfig(binding);
|
|
117
|
+
const builtinToolDescriptors = filterBuiltinMiddlewareToolDescriptors(builtinToolsConfig)
|
|
118
|
+
.filter((descriptor) => !declaredTools.some((tool) => tool.name === descriptor.name));
|
|
109
119
|
const tools = isDeepAgentBinding(binding)
|
|
110
120
|
? [
|
|
111
121
|
...declaredTools,
|
|
112
|
-
...
|
|
113
|
-
.filter((descriptor) => !declaredTools.some((tool) => tool.name === descriptor.name)),
|
|
122
|
+
...builtinToolDescriptors,
|
|
114
123
|
]
|
|
115
|
-
:
|
|
124
|
+
: builtinToolsConfig !== undefined
|
|
125
|
+
? [
|
|
126
|
+
...declaredTools,
|
|
127
|
+
...builtinToolDescriptors.filter((descriptor) => MODEL_EXPOSED_BUILTIN_TOOL_NAMES.has(descriptor.name)),
|
|
128
|
+
]
|
|
129
|
+
: declaredTools;
|
|
116
130
|
return {
|
|
117
131
|
agentId: binding.agent.id,
|
|
118
132
|
...(model ? {
|
|
@@ -332,7 +332,16 @@ function normalizeStreamChunk(chunk) {
|
|
|
332
332
|
return { kind: "content", content: chunk.content ?? "" };
|
|
333
333
|
}
|
|
334
334
|
function normalizeCommentaryText(value) {
|
|
335
|
-
return value
|
|
335
|
+
return value
|
|
336
|
+
.split("\n")
|
|
337
|
+
.map((line) => {
|
|
338
|
+
const leading = /^\s*/.exec(line)?.[0] ?? "";
|
|
339
|
+
const body = line.slice(leading.length).replace(/[^\S\n]+/g, " ").trimEnd();
|
|
340
|
+
return `${leading}${body}`;
|
|
341
|
+
})
|
|
342
|
+
.join("\n")
|
|
343
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
344
|
+
.trim();
|
|
336
345
|
}
|
|
337
346
|
function ensureCommentarySentence(value) {
|
|
338
347
|
const normalized = normalizeCommentaryText(value);
|
|
@@ -359,9 +368,9 @@ function summarizePlanState(planState) {
|
|
|
359
368
|
return "[ ]";
|
|
360
369
|
}
|
|
361
370
|
};
|
|
362
|
-
const items = planState.items.slice(0, 6).map((item) =>
|
|
363
|
-
const suffix = planState.items.length > items.length ? `
|
|
364
|
-
return
|
|
371
|
+
const items = planState.items.slice(0, 6).map((item) => ` ${statusMarker(item.status)} ${item.content}`);
|
|
372
|
+
const suffix = planState.items.length > items.length ? [` ... ${planState.items.length - items.length} more`] : [];
|
|
373
|
+
return ["TODO", ...items, ...suffix].join("\n");
|
|
365
374
|
}
|
|
366
375
|
function summarizePlanStateTerminalTransitions(previousPlanState, nextPlanState) {
|
|
367
376
|
const previousByKey = new Map((previousPlanState?.items ?? []).map((item) => [normalizePlanItemKey(item), item]));
|
|
@@ -523,6 +532,45 @@ function createRuntimeMemoryRecallSteps(sessionId, requestId, items) {
|
|
|
523
532
|
},
|
|
524
533
|
];
|
|
525
534
|
}
|
|
535
|
+
function readObject(value) {
|
|
536
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
537
|
+
}
|
|
538
|
+
function isFallbackSafeUpstreamStartupEvent(event, rootAgentId) {
|
|
539
|
+
const typed = readObject(event);
|
|
540
|
+
const eventName = typeof typed?.event === "string" ? typed.event : "";
|
|
541
|
+
if (eventName.startsWith("on_chat_model_") || eventName.startsWith("on_llm_")) {
|
|
542
|
+
return true;
|
|
543
|
+
}
|
|
544
|
+
if (!eventName.startsWith("on_chain_")) {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
if (typed?.run_type === "tool") {
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
const name = typeof typed?.name === "string" ? typed.name : "";
|
|
551
|
+
const metadata = readObject(typed?.metadata);
|
|
552
|
+
const langgraphNode = typeof metadata?.langgraph_node === "string" ? metadata.langgraph_node : "";
|
|
553
|
+
const langchainAgentName = typeof metadata?.lc_agent_name === "string" ? metadata.lc_agent_name : "";
|
|
554
|
+
return (name === "__start__"
|
|
555
|
+
|| langgraphNode === "__start__"
|
|
556
|
+
|| langgraphNode === "model_request"
|
|
557
|
+
|| name.endsWith(".before_agent")
|
|
558
|
+
|| name.endsWith(".before_model")
|
|
559
|
+
|| (name === rootAgentId && langchainAgentName === rootAgentId));
|
|
560
|
+
}
|
|
561
|
+
function planStateHasAnyItems(planState) {
|
|
562
|
+
return (planState?.items.length ?? 0) > 0;
|
|
563
|
+
}
|
|
564
|
+
function isStartupRuntimeFailureOutput(value) {
|
|
565
|
+
const normalized = value.trim().toLowerCase();
|
|
566
|
+
if (!normalized.startsWith("runtime_error=")) {
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
return ((normalized.includes("terminated") && normalized.includes("other side closed"))
|
|
570
|
+
|| normalized.includes("socket hang up")
|
|
571
|
+
|| normalized.includes("connection reset")
|
|
572
|
+
|| normalized.includes("econnreset"));
|
|
573
|
+
}
|
|
526
574
|
export async function* streamHarnessRun(options) {
|
|
527
575
|
const priorHistoryPromise = Promise.resolve(options.isNewSession ? [] : undefined).then((historyHint) => historyHint ?? options.loadPriorHistory(options.sessionId, options.requestId));
|
|
528
576
|
yield { type: "event", event: await options.requestCreatedEventPromise };
|
|
@@ -533,6 +581,7 @@ export async function* streamHarnessRun(options) {
|
|
|
533
581
|
let emitted = false;
|
|
534
582
|
let streamActivityObserved = false;
|
|
535
583
|
let nonUpstreamStreamActivityObserved = false;
|
|
584
|
+
let observedOnlyFallbackSafeUpstreamEvents = true;
|
|
536
585
|
let assistantOutput = "";
|
|
537
586
|
let assistantOutputCameFromInvokeFallback = false;
|
|
538
587
|
const bufferAssistantTextUntilCompletion = true;
|
|
@@ -589,6 +638,9 @@ export async function* streamHarnessRun(options) {
|
|
|
589
638
|
streamActivityObserved = true;
|
|
590
639
|
const normalizedChunk = normalizeStreamChunk(rawChunk);
|
|
591
640
|
if (normalizedChunk.kind === "upstream-event") {
|
|
641
|
+
if (!isFallbackSafeUpstreamStartupEvent(normalizedChunk.event, options.selectedAgentId)) {
|
|
642
|
+
observedOnlyFallbackSafeUpstreamEvents = false;
|
|
643
|
+
}
|
|
592
644
|
const upstreamPlanState = getPlanStateFromUpstreamEvent({
|
|
593
645
|
sessionId: options.sessionId,
|
|
594
646
|
requestId: options.requestId,
|
|
@@ -833,6 +885,15 @@ export async function* streamHarnessRun(options) {
|
|
|
833
885
|
emitted = emitted || assistantOutput.length > 0;
|
|
834
886
|
}
|
|
835
887
|
currentPlanState = await refreshPlanStateFromPersistence(options, currentPlanState);
|
|
888
|
+
if (assistantOutput
|
|
889
|
+
&& isStartupRuntimeFailureOutput(assistantOutput)
|
|
890
|
+
&& executedToolResults.length === 0
|
|
891
|
+
&& !sawSuccessfulToolResult
|
|
892
|
+
&& observedOnlyFallbackSafeUpstreamEvents
|
|
893
|
+
&& !planStateHasAnyItems(currentPlanState)) {
|
|
894
|
+
assistantOutput = "";
|
|
895
|
+
emitted = false;
|
|
896
|
+
}
|
|
836
897
|
if (!assistantOutput) {
|
|
837
898
|
const actual = await options.invokeWithHistory(options.binding, options.input, options.sessionId, options.requestId);
|
|
838
899
|
if (Array.isArray(actual.contentBlocks) && actual.contentBlocks.length > 0) {
|
|
@@ -1019,8 +1080,12 @@ export async function* streamHarnessRun(options) {
|
|
|
1019
1080
|
}
|
|
1020
1081
|
const shouldRetryAfterStreamingCompatibilityError = !assistantOutput &&
|
|
1021
1082
|
isOpenAICompatibleStreamingCompatibilityError(options.binding, error);
|
|
1022
|
-
|
|
1023
|
-
|
|
1083
|
+
const streamHadExecutionSideEffects = emitted
|
|
1084
|
+
|| nonUpstreamStreamActivityObserved
|
|
1085
|
+
|| sawSuccessfulToolResult
|
|
1086
|
+
|| executedToolResults.length > 0
|
|
1087
|
+
|| !observedOnlyFallbackSafeUpstreamEvents;
|
|
1088
|
+
if (streamHadExecutionSideEffects && !shouldRetryAfterStreamingCompatibilityError) {
|
|
1024
1089
|
const runtimeFailure = renderRuntimeFailure(error);
|
|
1025
1090
|
const detailedError = describeRuntimeError(error);
|
|
1026
1091
|
yield {
|
|
@@ -132,6 +132,7 @@ export declare class AgentHarnessRuntime {
|
|
|
132
132
|
private emit;
|
|
133
133
|
private trackBackgroundTask;
|
|
134
134
|
private scheduleBackgroundStartupTask;
|
|
135
|
+
private drainBackgroundTasksForClose;
|
|
135
136
|
private resolveToolMcpServerTools;
|
|
136
137
|
private loadPriorHistory;
|
|
137
138
|
private loadRequestInput;
|
package/dist/runtime/harness.js
CHANGED
|
@@ -46,6 +46,7 @@ import { defaultRequestedAgentId, prepareRunStart } from "./harness/run/start-ru
|
|
|
46
46
|
import { buildRequestInspectionRecord, buildSessionInspectionRecord, deleteSessionRecord, getPublicApproval, listPublicApprovals, } from "./harness/run/session-records.js";
|
|
47
47
|
import { createKnowledgeModule } from "../knowledge/index.js";
|
|
48
48
|
import { createProceduralMemoryManager, ProceduralMemoryFormationSync, readProceduralMemoryRuntimeConfig, } from "../knowledge/procedural/index.js";
|
|
49
|
+
const BACKGROUND_TASK_CLOSE_DRAIN_TIMEOUT_MS = 1_000;
|
|
49
50
|
const ACTIVE_REQUEST_STATES = [
|
|
50
51
|
"queued",
|
|
51
52
|
"claimed",
|
|
@@ -945,6 +946,23 @@ export class AgentHarnessRuntime {
|
|
|
945
946
|
scheduleBackgroundStartupTask(task) {
|
|
946
947
|
this.trackBackgroundTask(task.then(() => undefined).catch(() => undefined));
|
|
947
948
|
}
|
|
949
|
+
async drainBackgroundTasksForClose() {
|
|
950
|
+
const tasks = Array.from(this.backgroundTasks);
|
|
951
|
+
if (tasks.length === 0) {
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
let timeoutHandle;
|
|
955
|
+
await Promise.race([
|
|
956
|
+
Promise.allSettled(tasks),
|
|
957
|
+
new Promise((resolve) => {
|
|
958
|
+
timeoutHandle = setTimeout(resolve, BACKGROUND_TASK_CLOSE_DRAIN_TIMEOUT_MS);
|
|
959
|
+
timeoutHandle.unref?.();
|
|
960
|
+
}),
|
|
961
|
+
]);
|
|
962
|
+
if (timeoutHandle) {
|
|
963
|
+
clearTimeout(timeoutHandle);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
948
966
|
resolveToolMcpServerTools(agentId) {
|
|
949
967
|
return resolveWorkspaceAgentTools({
|
|
950
968
|
workspace: this.workspace,
|
|
@@ -1375,7 +1393,7 @@ export class AgentHarnessRuntime {
|
|
|
1375
1393
|
this.unregisterMem0IngestionSync();
|
|
1376
1394
|
this.unregisterRuntimeMemoryFormationSync();
|
|
1377
1395
|
this.unregisterProceduralMemoryFormationSync();
|
|
1378
|
-
await
|
|
1396
|
+
await this.drainBackgroundTasksForClose();
|
|
1379
1397
|
await this.sessionMemorySync?.close();
|
|
1380
1398
|
await this.runtimeMemorySync?.close();
|
|
1381
1399
|
await this.mem0IngestionSync?.close();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CompiledAgentBinding, CompiledDeepAgentSubAgent, CompiledExecutionBinding, CompiledModel, CompiledSubAgent, CompiledTool, DeepAgentParams, LegacyDeepAgentParams, LegacyLangChainAgentParams, LangChainAgentParams } from "../../contracts/types.js";
|
|
1
|
+
import type { CompiledAgentBinding, CompiledBuiltinToolsConfig, CompiledDeepAgentSubAgent, CompiledExecutionBinding, CompiledModel, CompiledSubAgent, CompiledTool, DeepAgentParams, LegacyDeepAgentParams, LegacyLangChainAgentParams, LangChainAgentParams } from "../../contracts/types.js";
|
|
2
2
|
export type BindingExecutionView = {
|
|
3
3
|
adapterKind: string;
|
|
4
4
|
langchainParams?: LegacyLangChainAgentParams;
|
|
@@ -32,10 +32,7 @@ export declare function getBindingGeneralPurposeAgent(binding: CompiledAgentBind
|
|
|
32
32
|
export declare function getBindingTaskDescription(binding: CompiledAgentBinding): string | undefined;
|
|
33
33
|
export declare function getBindingBackendConfig(binding: CompiledAgentBinding): Record<string, unknown> | undefined;
|
|
34
34
|
export declare function getBindingInteractionMode(binding: CompiledAgentBinding): "stream" | "invoke" | undefined;
|
|
35
|
-
export declare function getBindingBuiltinToolsConfig(binding: CompiledAgentBinding):
|
|
36
|
-
filesystem?: boolean;
|
|
37
|
-
todos?: boolean;
|
|
38
|
-
} | undefined;
|
|
35
|
+
export declare function getBindingBuiltinToolsConfig(binding: CompiledAgentBinding): CompiledBuiltinToolsConfig | undefined;
|
|
39
36
|
export declare function getBindingFilesystemConfig(binding: CompiledAgentBinding): Record<string, unknown> | undefined;
|
|
40
37
|
export declare function isLangChainBinding(binding: CompiledAgentBinding): boolean;
|
|
41
38
|
export declare function isDeepAgentBinding(binding: CompiledAgentBinding): boolean;
|
|
@@ -463,6 +463,7 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
463
463
|
: undefined,
|
|
464
464
|
name: resolveAgentRuntimeName(agent),
|
|
465
465
|
description: agent.description,
|
|
466
|
+
builtinTools: getAgentExecutionObject(agent, "builtinTools"),
|
|
466
467
|
},
|
|
467
468
|
};
|
|
468
469
|
return attachLegacyExecutionAliases({
|