@botbotgo/agent-harness 0.0.325 → 0.0.327

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,3 +1,4 @@
1
+ import { computeIncrementalOutput } from "../runtime/parsing/stream-event-parsing.js";
1
2
  import { countRenderedLines, renderChatRequestRunning, renderChatTextChunk, summarizeChatToolResult } from "./chat-rendering.js";
2
3
  import { buildTerminalRequestSnapshot, buildTodoContinuationSignature, flattenRequestExecutionSteps, renderRequestEventContinuation, renderRequestSnapshotTree, renderRequestTodoContinuation, } from "./request-tree.js";
3
4
  export async function streamChatMessage(input) {
@@ -10,6 +11,7 @@ export async function streamChatMessage(input) {
10
11
  let latestAgentId = input.agentId;
11
12
  let wroteContent = false;
12
13
  let wroteRenderableBlocks = false;
14
+ let renderedAssistantOutput = "";
13
15
  let lastRenderedRequestTreeKey;
14
16
  let lastRenderedRequestTree = "";
15
17
  let lastRenderedRequestTreeLineCount = 0;
@@ -177,28 +179,36 @@ export async function streamChatMessage(input) {
177
179
  suppressRequestTreeRendering = true;
178
180
  clearLiveRequestTree();
179
181
  };
182
+ const writeAssistantOutput = (nextOutput) => {
183
+ const incremental = computeIncrementalOutput(renderedAssistantOutput, nextOutput);
184
+ renderedAssistantOutput = incremental.accumulated;
185
+ if (!incremental.delta) {
186
+ return false;
187
+ }
188
+ if (input.requestEvents) {
189
+ suspendRequestTreeRendering();
190
+ }
191
+ writeChatStdout(renderChatTextChunk(incremental.delta, input.modelInfo));
192
+ wroteContent = true;
193
+ return true;
194
+ };
195
+ const formatAgentProgressLabel = (agentId) => agentId && agentId.trim().length > 0 ? ` agent:${agentId}` : "";
180
196
  const renderContentBlocks = (contentBlocks, agentId) => {
181
197
  latestAgentId = agentId || latestAgentId;
182
- if (!wroteContent) {
183
- const rendered = contentBlocks
184
- .map((block) => {
185
- if (typeof block === "string") {
186
- return block;
187
- }
188
- if (block && typeof block === "object" && "text" in block && typeof block.text === "string") {
189
- return block.text;
190
- }
191
- return "";
192
- })
193
- .filter((block) => block.trim().length > 0)
194
- .join("");
195
- if (rendered) {
196
- if (input.requestEvents) {
197
- suspendRequestTreeRendering();
198
- }
199
- writeChatStdout(renderChatTextChunk(rendered, input.modelInfo));
200
- wroteRenderableBlocks = true;
198
+ const rendered = contentBlocks
199
+ .map((block) => {
200
+ if (typeof block === "string") {
201
+ return block;
202
+ }
203
+ if (block && typeof block === "object" && "text" in block && typeof block.text === "string") {
204
+ return block.text;
201
205
  }
206
+ return "";
207
+ })
208
+ .filter((block) => block.trim().length > 0)
209
+ .join("");
210
+ if (rendered && writeAssistantOutput(rendered)) {
211
+ wroteRenderableBlocks = true;
202
212
  }
203
213
  };
204
214
  const result = await input.client.request({
@@ -253,11 +263,7 @@ export async function streamChatMessage(input) {
253
263
  firstDataAt ??= Date.now();
254
264
  if (delta.type === "output.text.delta") {
255
265
  latestAgentId = delta.agentId || latestAgentId;
256
- if (input.requestEvents) {
257
- suspendRequestTreeRendering();
258
- }
259
- writeChatStdout(renderChatTextChunk(delta.text, input.modelInfo));
260
- wroteContent = true;
266
+ writeAssistantOutput(delta.text);
261
267
  return;
262
268
  }
263
269
  if (delta.type === "output.content-blocks") {
@@ -268,7 +274,7 @@ export async function streamChatMessage(input) {
268
274
  if (delta.type === "tool.result") {
269
275
  latestAgentId = delta.agentId || latestAgentId;
270
276
  if ((input.showToolResults ?? true) && !input.requestEvents) {
271
- writeChatStderr(`\n[${formatPerfClock(Date.now())} +${formatElapsed(Date.now())}] [tool:${delta.toolName}] ${summarizeChatToolResult(delta.output, delta.isError === true)}${delta.isError ? " (error)" : ""}\n`);
277
+ writeChatStderr(`\n[${formatPerfClock(Date.now())} +${formatElapsed(Date.now())}]${formatAgentProgressLabel(delta.agentId)} [tool:${delta.toolName}] ${summarizeChatToolResult(delta.output, delta.isError === true)}${delta.isError ? " (error)" : ""}\n`);
272
278
  }
273
279
  return;
274
280
  }
@@ -277,7 +283,7 @@ export async function streamChatMessage(input) {
277
283
  if (wroteContent || wroteRenderableBlocks) {
278
284
  return;
279
285
  }
280
- const progressLine = `[${formatPerfClock(Date.now())} +${formatElapsed(Date.now())}] ${delta.text}\n`;
286
+ const progressLine = `[${formatPerfClock(Date.now())} +${formatElapsed(Date.now())}]${formatAgentProgressLabel(delta.agentId)} ${delta.text}\n`;
281
287
  if (input.requestEvents && input.liveRequestTree && !suppressRequestTreeRendering && lastRenderedRequestTree) {
282
288
  liveRequestAnnotations.push(progressLine);
283
289
  clearLiveRequestTree();
@@ -317,7 +323,7 @@ export async function streamChatMessage(input) {
317
323
  }
318
324
  }
319
325
  if (!wroteContent && !wroteRenderableBlocks && result.output.trim().length > 0) {
320
- writeChatStdout(renderChatTextChunk(result.output, input.modelInfo));
326
+ writeAssistantOutput(result.output);
321
327
  }
322
328
  if (result.state === "waiting_for_approval") {
323
329
  writeChatStderr(`\nRequest is waiting for approval${result.approvalId ? ` (${result.approvalId})` : ""}.\n`);
@@ -1,2 +1,2 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.324";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.326";
2
2
  export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-22";
@@ -1,2 +1,2 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.324";
1
+ export const AGENT_HARNESS_VERSION = "0.0.326";
2
2
  export const AGENT_HARNESS_RELEASE_DATE = "2026-04-22";
@@ -553,7 +553,7 @@ export async function* streamHarnessRun(options) {
553
553
  type: "tool-result",
554
554
  sessionId: options.sessionId,
555
555
  requestId: options.requestId,
556
- agentId: options.selectedAgentId,
556
+ agentId: currentAgentId,
557
557
  toolName: normalizedChunk.toolName,
558
558
  output: normalizedChunk.output,
559
559
  isError: normalizedChunk.isError,
@@ -196,7 +196,16 @@ function isErrorLikeToolOutput(value) {
196
196
  if (!message) {
197
197
  return false;
198
198
  }
199
- return /(^|\b)(error|exception|failed|failure|denied|timed out|timeout|not permitted|eperm|eacces)(\b|:)/i.test(message);
199
+ const firstNonEmptyLine = message
200
+ .split("\n")
201
+ .map((line) => line.trim())
202
+ .find((line) => line.length > 0) ?? "";
203
+ if (!firstNonEmptyLine) {
204
+ return false;
205
+ }
206
+ return /^(error|exception|failed|failure|denied|timed out|timeout|not permitted|eperm|eacces)\b:?/i.test(firstNonEmptyLine)
207
+ || /^command failed:/i.test(firstNonEmptyLine)
208
+ || /^stderr:/i.test(firstNonEmptyLine);
200
209
  }
201
210
  function isEmptyInitialWriteTodosResult(value) {
202
211
  if (typeof value !== "object" || !value || Array.isArray(value)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.325",
3
+ "version": "0.0.327",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",