@botbotgo/agent-harness 0.0.341 → 0.0.343

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.
@@ -16,6 +16,7 @@ export declare function streamChatMessage(input: {
16
16
  colorRequestTree?: boolean;
17
17
  showToolResults?: boolean;
18
18
  showRunningState?: boolean;
19
+ idleProgressMs?: number;
19
20
  }): Promise<{
20
21
  sessionId?: string;
21
22
  requestId?: string;
@@ -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;
@@ -22,9 +23,13 @@ export async function streamChatMessage(input) {
22
23
  let liveRequestAnnotations = [];
23
24
  let persistedRequestTreeEventCount = 0;
24
25
  let persistedRequestTreeTodoSignature = "";
26
+ let previousTodoStatuses = new Map();
27
+ const renderedTodoTransitionLines = new Set();
25
28
  const requestTreeRenderThrottleMs = 75;
26
29
  let suppressRequestTreeRendering = false;
27
30
  let lastStableRequestTreeKey;
31
+ let idleProgressTimer;
32
+ let lastRuntimeProgressAt = requestStartedAt;
28
33
  let stdoutWriteChain = Promise.resolve();
29
34
  let stderrWriteChain = Promise.resolve();
30
35
  const enqueueChatWrite = (sink, _stream, chain, message) => chain.then(async () => {
@@ -171,6 +176,27 @@ export async function streamChatMessage(input) {
171
176
  }
172
177
  stderrWriteChain = enqueueChatWrite(input.stderr, input.stderrStream, stderrWriteChain, message);
173
178
  };
179
+ const clearIdleProgressTimer = () => {
180
+ if (idleProgressTimer) {
181
+ clearTimeout(idleProgressTimer);
182
+ idleProgressTimer = undefined;
183
+ }
184
+ };
185
+ const scheduleIdleProgress = () => {
186
+ clearIdleProgressTimer();
187
+ if (idleProgressMs <= 0 || wroteContent || wroteRenderableBlocks) {
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
+ };
174
200
  const suspendRequestTreeRendering = () => {
175
201
  if (!input.requestEvents || !input.liveRequestTree) {
176
202
  return;
@@ -193,6 +219,46 @@ export async function streamChatMessage(input) {
193
219
  return true;
194
220
  };
195
221
  const formatAgentProgressLabel = (agentId) => agentId && agentId.trim().length > 0 ? ` agent:${agentId}` : "";
222
+ const buildTodoTransitionKey = (todo) => todo.key || todo.id || `content:${todo.content.trim().toLowerCase()}`;
223
+ const readTerminalTodoTransitionLabel = (status) => {
224
+ if (status === "completed") {
225
+ return "completed";
226
+ }
227
+ if (status === "failed") {
228
+ return "failed";
229
+ }
230
+ if (status === "cancelled") {
231
+ return "cancelled";
232
+ }
233
+ return null;
234
+ };
235
+ const writeTodoTransitionProgress = (snapshot) => {
236
+ const nextStatuses = new Map();
237
+ const lines = [];
238
+ for (const todo of snapshot.plan.items) {
239
+ const key = buildTodoTransitionKey(todo);
240
+ nextStatuses.set(key, todo.status);
241
+ const label = readTerminalTodoTransitionLabel(todo.status);
242
+ if (!label) {
243
+ continue;
244
+ }
245
+ const previousStatus = previousTodoStatuses.get(key);
246
+ if (!previousStatus || previousStatus === todo.status) {
247
+ continue;
248
+ }
249
+ const text = `TODO ${label}: ${todo.content}.`;
250
+ if (renderedTodoTransitionLines.has(text)) {
251
+ continue;
252
+ }
253
+ renderedTodoTransitionLines.add(text);
254
+ lines.push(`[${formatPerfClock(Date.now())} +${formatElapsed(Date.now())}]${formatAgentProgressLabel(snapshot.agentId)} ${text}\n`);
255
+ }
256
+ previousTodoStatuses = nextStatuses;
257
+ if (lines.length === 0) {
258
+ return;
259
+ }
260
+ writeChatStderr(lines.join(""));
261
+ };
196
262
  const renderContentBlocks = (contentBlocks, agentId) => {
197
263
  latestAgentId = agentId || latestAgentId;
198
264
  const rendered = contentBlocks
@@ -216,11 +282,15 @@ export async function streamChatMessage(input) {
216
282
  ...(input.sessionId ? { sessionId: input.sessionId } : {}),
217
283
  input: input.message,
218
284
  eventListener(snapshot) {
285
+ markRuntimeProgress();
219
286
  latestSessionId = snapshot.sessionId || latestSessionId;
220
287
  latestRequestId = snapshot.requestId || latestRequestId;
221
288
  latestAgentId = snapshot.agentId || latestAgentId;
222
289
  latestSnapshot = snapshot;
223
290
  firstSnapshotAt ??= Date.now();
291
+ if (!input.requestEvents) {
292
+ writeTodoTransitionProgress(snapshot);
293
+ }
224
294
  if (input.requestEvents && !suppressRequestTreeRendering) {
225
295
  const now = Date.now();
226
296
  const nextTreeKey = buildRequestSnapshotRenderKey(snapshot);
@@ -258,6 +328,7 @@ export async function streamChatMessage(input) {
258
328
  }
259
329
  },
260
330
  dataListener(delta) {
331
+ markRuntimeProgress();
261
332
  latestSessionId = delta.sessionId || latestSessionId;
262
333
  latestRequestId = delta.requestId || latestRequestId;
263
334
  firstDataAt ??= Date.now();
@@ -283,6 +354,9 @@ export async function streamChatMessage(input) {
283
354
  if (wroteContent || wroteRenderableBlocks) {
284
355
  return;
285
356
  }
357
+ if (renderedTodoTransitionLines.has(delta.text)) {
358
+ return;
359
+ }
286
360
  const progressLine = `[${formatPerfClock(Date.now())} +${formatElapsed(Date.now())}]${formatAgentProgressLabel(delta.agentId)} ${delta.text}\n`;
287
361
  if (input.requestEvents && input.liveRequestTree && !suppressRequestTreeRendering && lastRenderedRequestTree) {
288
362
  liveRequestAnnotations.push(progressLine);
@@ -294,6 +368,7 @@ export async function streamChatMessage(input) {
294
368
  }
295
369
  },
296
370
  });
371
+ clearIdleProgressTimer();
297
372
  if (!result) {
298
373
  throw new Error("chat request completed without a terminal result");
299
374
  }
@@ -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.341";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.343";
2
2
  export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-24";
@@ -1,2 +1,2 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.341";
1
+ export const AGENT_HARNESS_VERSION = "0.0.343";
2
2
  export const AGENT_HARNESS_RELEASE_DATE = "2026-04-24";
@@ -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
- ...filterBuiltinMiddlewareToolDescriptors(getBindingBuiltinToolsConfig(binding))
113
- .filter((descriptor) => !declaredTools.some((tool) => tool.name === descriptor.name)),
122
+ ...builtinToolDescriptors,
114
123
  ]
115
- : declaredTools;
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 ? {
@@ -363,6 +363,32 @@ function summarizePlanState(planState) {
363
363
  const suffix = planState.items.length > items.length ? ` | +${planState.items.length - items.length} more` : "";
364
364
  return `TODO: ${items.join(" | ")}${suffix}`;
365
365
  }
366
+ function summarizePlanStateTerminalTransitions(previousPlanState, nextPlanState) {
367
+ const previousByKey = new Map((previousPlanState?.items ?? []).map((item) => [normalizePlanItemKey(item), item]));
368
+ const terminalLabel = (status) => {
369
+ switch (status) {
370
+ case "completed":
371
+ return "completed";
372
+ case "failed":
373
+ return "failed";
374
+ case "cancelled":
375
+ return "cancelled";
376
+ default:
377
+ return null;
378
+ }
379
+ };
380
+ return nextPlanState.items.flatMap((item) => {
381
+ const label = terminalLabel(item.status);
382
+ if (!label) {
383
+ return [];
384
+ }
385
+ const previousStatus = previousByKey.get(normalizePlanItemKey(item))?.status;
386
+ if (previousStatus === item.status) {
387
+ return [];
388
+ }
389
+ return [`TODO ${label}: ${item.content}.`];
390
+ });
391
+ }
366
392
  function createSurfaceCommentary(surfaceItem) {
367
393
  const name = normalizeCommentaryText(surfaceItem.name);
368
394
  if (!name) {
@@ -574,12 +600,16 @@ export async function* streamHarnessRun(options) {
574
600
  const mergedPlanState = mergePartialPlanState(currentPlanState, upstreamPlanState);
575
601
  const signature = buildPlanStateSignature(mergedPlanState);
576
602
  if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, mergedPlanState)) {
603
+ const previousPlanState = currentPlanState;
577
604
  planStateVersion = mergedPlanState.version;
578
605
  lastPlanStateSignature = signature;
579
606
  currentPlanState = mergedPlanState;
580
607
  for (const item of await emitPlanStateUpdate(options, currentAgentId, mergedPlanState)) {
581
608
  yield item;
582
609
  }
610
+ for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, mergedPlanState)) {
611
+ yield* emitCommentary(commentary);
612
+ }
583
613
  const commentary = summarizePlanState(mergedPlanState);
584
614
  if (commentary) {
585
615
  yield* emitCommentary(commentary);
@@ -733,11 +763,15 @@ export async function* streamHarnessRun(options) {
733
763
  const mergedPlanState = mergePartialPlanState(currentPlanState, planState);
734
764
  const signature = buildPlanStateSignature(mergedPlanState);
735
765
  if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, mergedPlanState)) {
766
+ const previousPlanState = currentPlanState;
736
767
  lastPlanStateSignature = signature;
737
768
  currentPlanState = mergedPlanState;
738
769
  for (const item of await emitPlanStateUpdate(options, currentAgentId, mergedPlanState)) {
739
770
  yield item;
740
771
  }
772
+ for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, mergedPlanState)) {
773
+ yield* emitCommentary(commentary);
774
+ }
741
775
  const commentary = summarizePlanState(mergedPlanState);
742
776
  if (commentary) {
743
777
  yield* emitCommentary(commentary);
@@ -751,12 +785,16 @@ export async function* streamHarnessRun(options) {
751
785
  const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, terminalStructuredStatus, new Date().toISOString());
752
786
  const signature = buildPlanStateSignature(reconciledPlanState);
753
787
  if (signature !== lastPlanStateSignature) {
788
+ const previousPlanState = currentPlanState;
754
789
  planStateVersion = reconciledPlanState.version;
755
790
  lastPlanStateSignature = signature;
756
791
  currentPlanState = reconciledPlanState;
757
792
  for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
758
793
  yield item;
759
794
  }
795
+ for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, reconciledPlanState)) {
796
+ yield* emitCommentary(commentary);
797
+ }
760
798
  const commentary = summarizePlanState(reconciledPlanState);
761
799
  if (commentary) {
762
800
  yield* emitCommentary(commentary);
@@ -816,12 +854,16 @@ export async function* streamHarnessRun(options) {
816
854
  const mergedPlanState = mergePartialPlanState(currentPlanState, finalPlanState);
817
855
  const signature = buildPlanStateSignature(mergedPlanState);
818
856
  if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, mergedPlanState)) {
857
+ const previousPlanState = currentPlanState;
819
858
  planStateVersion = mergedPlanState.version;
820
859
  lastPlanStateSignature = signature;
821
860
  currentPlanState = mergedPlanState;
822
861
  for (const item of await emitPlanStateUpdate(options, currentAgentId, mergedPlanState)) {
823
862
  yield item;
824
863
  }
864
+ for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, mergedPlanState)) {
865
+ yield* emitCommentary(commentary);
866
+ }
825
867
  const commentary = summarizePlanState(mergedPlanState);
826
868
  if (commentary) {
827
869
  yield* emitCommentary(commentary);
@@ -834,12 +876,16 @@ export async function* streamHarnessRun(options) {
834
876
  const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, terminalStructuredStatus, new Date().toISOString());
835
877
  const signature = buildPlanStateSignature(reconciledPlanState);
836
878
  if (signature !== lastPlanStateSignature) {
879
+ const previousPlanState = currentPlanState;
837
880
  planStateVersion = reconciledPlanState.version;
838
881
  lastPlanStateSignature = signature;
839
882
  currentPlanState = reconciledPlanState;
840
883
  for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
841
884
  yield item;
842
885
  }
886
+ for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, reconciledPlanState)) {
887
+ yield* emitCommentary(commentary);
888
+ }
843
889
  const commentary = summarizePlanState(reconciledPlanState);
844
890
  if (commentary) {
845
891
  yield* emitCommentary(commentary);
@@ -852,12 +898,16 @@ export async function* streamHarnessRun(options) {
852
898
  const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, "completed", new Date().toISOString());
853
899
  const signature = buildPlanStateSignature(reconciledPlanState);
854
900
  if (signature !== lastPlanStateSignature) {
901
+ const previousPlanState = currentPlanState;
855
902
  planStateVersion = reconciledPlanState.version;
856
903
  lastPlanStateSignature = signature;
857
904
  currentPlanState = reconciledPlanState;
858
905
  for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
859
906
  yield item;
860
907
  }
908
+ for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, reconciledPlanState)) {
909
+ yield* emitCommentary(commentary);
910
+ }
861
911
  const commentary = summarizePlanState(reconciledPlanState);
862
912
  if (commentary) {
863
913
  yield* emitCommentary(commentary);
@@ -916,12 +966,16 @@ export async function* streamHarnessRun(options) {
916
966
  const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, terminalStructuredStatus, new Date().toISOString());
917
967
  const signature = buildPlanStateSignature(reconciledPlanState);
918
968
  if (signature !== lastPlanStateSignature) {
969
+ const previousPlanState = currentPlanState;
919
970
  planStateVersion = reconciledPlanState.version;
920
971
  lastPlanStateSignature = signature;
921
972
  currentPlanState = reconciledPlanState;
922
973
  for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
923
974
  yield item;
924
975
  }
976
+ for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, reconciledPlanState)) {
977
+ yield* emitCommentary(commentary);
978
+ }
925
979
  const commentary = summarizePlanState(reconciledPlanState);
926
980
  if (commentary) {
927
981
  yield* emitCommentary(commentary);
@@ -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({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.341",
3
+ "version": "0.0.343",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",