@botbotgo/agent-harness 0.0.343 → 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.js +1 -1
- package/dist/cli/chat-workspace.js +5 -0
- package/dist/cli.js +1 -1
- 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/harness/run/stream-run.js +71 -6
- package/dist/runtime/harness.d.ts +1 -0
- package/dist/runtime/harness.js +19 -1
- package/package.json +1 -1
package/dist/cli/chat-stream.js
CHANGED
|
@@ -184,7 +184,7 @@ export async function streamChatMessage(input) {
|
|
|
184
184
|
};
|
|
185
185
|
const scheduleIdleProgress = () => {
|
|
186
186
|
clearIdleProgressTimer();
|
|
187
|
-
if (idleProgressMs <= 0
|
|
187
|
+
if (idleProgressMs <= 0) {
|
|
188
188
|
return;
|
|
189
189
|
}
|
|
190
190
|
idleProgressTimer = setTimeout(() => {
|
|
@@ -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
|
}
|
|
@@ -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);
|
|
@@ -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();
|