@botbotgo/agent-harness 0.0.249 → 0.0.251

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/api.d.ts CHANGED
@@ -33,6 +33,7 @@ export type RequestUpstreamEventItem = {
33
33
  requestId: string;
34
34
  agentId: string;
35
35
  agentName?: string;
36
+ surfaceItems?: import("./contracts/types.js").RuntimeSurfaceItem[];
36
37
  event: unknown;
37
38
  };
38
39
  export type PublicRunListeners = {
package/dist/api.js CHANGED
@@ -66,6 +66,7 @@ function toPublicRunListeners(listeners) {
66
66
  requestId: item.runId,
67
67
  agentId: item.agentId,
68
68
  agentName: item.agentName,
69
+ surfaceItems: item.surfaceItems,
69
70
  event: item.event,
70
71
  })
71
72
  : undefined,
@@ -98,6 +98,17 @@ export type RuntimeHistoryItem = {
98
98
  isError?: boolean;
99
99
  key: string;
100
100
  };
101
+ export type RuntimeSurfaceKind = "agent" | "llm" | "memory" | "skill" | "tool";
102
+ export type RuntimeSurfaceItem = {
103
+ kind: RuntimeSurfaceKind;
104
+ id: string;
105
+ name: string;
106
+ label: string;
107
+ status: "started" | "completed" | "failed";
108
+ ownerAgentId?: string;
109
+ ownerAgentName?: string;
110
+ sourceEventId?: string;
111
+ };
101
112
  export type AgentReference = {
102
113
  id: string;
103
114
  name: string;
@@ -419,6 +430,7 @@ export type UpstreamRuntimeEventItem = {
419
430
  runId: string;
420
431
  agentId: string;
421
432
  agentName?: string;
433
+ surfaceItems?: RuntimeSurfaceItem[];
422
434
  event: UpstreamRuntimeEvent;
423
435
  };
424
436
  export type RuntimeListeners = {
@@ -467,6 +479,7 @@ export type HarnessStreamItem = {
467
479
  runId: string;
468
480
  agentId: string;
469
481
  agentName?: string;
482
+ surfaceItems?: RuntimeSurfaceItem[];
470
483
  event: UpstreamRuntimeEvent;
471
484
  } | {
472
485
  type: "result";
@@ -507,6 +520,7 @@ export type RequestSummary = Omit<ThreadRunRecord, "threadId" | "runId"> & {
507
520
  };
508
521
  export type RequestRecord = RequestSummary & {
509
522
  history?: RuntimeHistoryItem[];
523
+ runtimeSurface?: RuntimeSurfaceItem[];
510
524
  upstreamEvents?: unknown[];
511
525
  runtimeTimeline?: RuntimeTimelineItem[];
512
526
  };
@@ -519,6 +533,7 @@ export type RunSummary = Omit<RequestSummary, "sessionId" | "requestId"> & {
519
533
  };
520
534
  export type RunRecord = RunSummary & {
521
535
  history?: RuntimeHistoryItem[];
536
+ runtimeSurface?: RuntimeSurfaceItem[];
522
537
  upstreamEvents?: unknown[];
523
538
  runtimeTimeline?: RuntimeTimelineItem[];
524
539
  };
@@ -50,6 +50,9 @@ function slugify(value) {
50
50
  .replace(/^-+|-+$/g, "")
51
51
  .slice(0, 80) || "node";
52
52
  }
53
+ function buildSurfaceId(kind, value) {
54
+ return `${kind}:${slugify(value)}`;
55
+ }
53
56
  function titleCase(value) {
54
57
  return value
55
58
  .replace(/[_-]+/g, " ")
@@ -765,6 +768,36 @@ export function buildFlowGraph(input) {
765
768
  }))
766
769
  : upstreamContext.projections;
767
770
  const { nodes: attemptNodes, edges: attemptEdges, groups: attemptGroups } = buildAttempts(projectionRecords, upstreamContext.delegationNodes, runtimeGroups, sessionId, requestId);
771
+ const runtimeSurface = [...upstreamContext.delegationNodes, ...attemptNodes]
772
+ .filter((node) => node.layer !== "detail"
773
+ && (node.kind === "agent" || node.kind === "llm" || node.kind === "memory" || node.kind === "skill" || node.kind === "tool"))
774
+ .map((node) => ({
775
+ kind: node.kind,
776
+ id: buildSurfaceId(node.kind, node.kind === "agent" ? (node.agentId ?? node.agentName ?? "agent") : node.label),
777
+ name: node.kind === "agent"
778
+ ? (node.agentName ?? node.agentId ?? "Agent")
779
+ : normalizeLabel(node.label)
780
+ .replace(/^Delegate to\s+/i, "")
781
+ .replace(/^Calling LLM\s+/i, "")
782
+ .replace(/^Completed LLM\s+/i, "")
783
+ .replace(/^Calling tool\s+/i, "")
784
+ .replace(/^Completed tool\s+/i, "")
785
+ .replace(/^Tool\s+/i, "")
786
+ .replace(/\s+failed$/i, "")
787
+ .replace(/^Calling skill\s+/i, "")
788
+ .replace(/^Completed skill\s+/i, "")
789
+ .replace(/^Accessing memory\s+/i, "")
790
+ .replace(/^Completed memory\s+/i, ""),
791
+ label: node.label,
792
+ status: node.status === "resolved" ? "completed" : node.status,
793
+ ownerAgentId: node.kind === "agent"
794
+ ? (typeof node.detail.fromAgentId === "string" ? node.detail.fromAgentId : node.agentId)
795
+ : node.agentId,
796
+ ownerAgentName: node.kind === "agent"
797
+ ? (typeof node.detail.fromAgentName === "string" ? node.detail.fromAgentName : node.agentName)
798
+ : node.agentName,
799
+ sourceEventId: node.sourceEventIds[0],
800
+ }));
768
801
  return {
769
802
  graphId: `${sessionId}/${requestId}`,
770
803
  scope: input.scope ?? "run",
@@ -779,6 +812,7 @@ export function buildFlowGraph(input) {
779
812
  runtimeTimelineCount: runtimeTimeline.length,
780
813
  upstreamProjectionCount: upstreamProjections.length,
781
814
  delegationCount: upstreamContext.delegationNodes.length,
815
+ runtimeSurface,
782
816
  ...(input.metadata ?? {}),
783
817
  },
784
818
  };
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.248";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.250";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.248";
1
+ export const AGENT_HARNESS_VERSION = "0.0.250";
@@ -418,10 +418,7 @@ async function runFunctionToolInSubprocess(config, input, context) {
418
418
  return await new Promise((resolve, reject) => {
419
419
  const child = spawn(config.command, config.args, {
420
420
  cwd: config.cwd,
421
- env: {
422
- ...process.env,
423
- ...(config.env ?? {}),
424
- },
421
+ env: createRuntimeEnv(config.env, process.env),
425
422
  stdio: ["pipe", "pipe", "pipe"],
426
423
  });
427
424
  let stdout = "";
@@ -47,6 +47,7 @@ export async function dispatchRunListeners(stream, listeners, options) {
47
47
  runId: item.runId,
48
48
  agentId: item.agentId,
49
49
  agentName: item.agentName,
50
+ surfaceItems: item.surfaceItems,
50
51
  event: item.event,
51
52
  });
52
53
  continue;
@@ -1,4 +1,4 @@
1
- import type { CompiledAgentBinding, RuntimeSnapshot } from "../../../contracts/types.js";
1
+ import type { CompiledAgentBinding, RuntimeSnapshot, RuntimeSurfaceItem } from "../../../contracts/types.js";
2
2
  export declare function buildRunRuntimeSnapshot(binding: CompiledAgentBinding, options?: {
3
3
  runId?: string;
4
4
  }): RuntimeSnapshot;
@@ -11,3 +11,19 @@ export declare function consumeRunInspectionUpstreamEvent(input: {
11
11
  currentAgentId: string;
12
12
  delegationChain: string[];
13
13
  };
14
+ export declare function projectRuntimeSurfaceFromUpstreamEvents(input: {
15
+ upstreamEvents: unknown[];
16
+ binding?: CompiledAgentBinding;
17
+ initialAgentId: string;
18
+ }): RuntimeSurfaceItem[];
19
+ export declare function projectRuntimeSurfaceFromSingleUpstreamEvent(input: {
20
+ event: unknown;
21
+ binding?: CompiledAgentBinding;
22
+ currentAgentId: string;
23
+ currentAgentName?: string;
24
+ sourceEventId: string;
25
+ }): {
26
+ currentAgentId: string;
27
+ currentAgentName: string;
28
+ items: RuntimeSurfaceItem[];
29
+ };
@@ -1,4 +1,6 @@
1
1
  import { readSkillMetadata } from "../../support/skill-metadata.js";
2
+ import { createUpstreamTimelineReducer } from "../../../upstream-events.js";
3
+ import { formatAgentName } from "../../../utils/agent-display.js";
2
4
  import { getBindingMemorySources, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSkills, getBindingSubagents, } from "../../support/compiled-binding.js";
3
5
  import { buildRuntimeGovernanceBundles } from "./governance.js";
4
6
  function asObject(value) {
@@ -7,6 +9,32 @@ function asObject(value) {
7
9
  function readStringArray(value) {
8
10
  return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
9
11
  }
12
+ function normalizeLabel(value) {
13
+ return value.replace(/\s+/g, " ").trim();
14
+ }
15
+ function slugify(value) {
16
+ return value
17
+ .toLowerCase()
18
+ .replace(/[^a-z0-9]+/g, "-")
19
+ .replace(/^-+|-+$/g, "")
20
+ .slice(0, 80) || "item";
21
+ }
22
+ function stripStepPrefix(label) {
23
+ return normalizeLabel(label)
24
+ .replace(/^Calling LLM\s+/i, "")
25
+ .replace(/^Completed LLM\s+/i, "")
26
+ .replace(/^Calling tool\s+/i, "")
27
+ .replace(/^Completed tool\s+/i, "")
28
+ .replace(/^Tool\s+/i, "")
29
+ .replace(/\s+failed$/i, "")
30
+ .replace(/^Calling skill\s+/i, "")
31
+ .replace(/^Completed skill\s+/i, "")
32
+ .replace(/^Accessing memory\s+/i, "")
33
+ .replace(/^Completed memory\s+/i, "");
34
+ }
35
+ function buildSurfaceId(kind, value) {
36
+ return `${kind}:${slugify(value)}`;
37
+ }
10
38
  function readTracingConfig(binding) {
11
39
  const deepAgentTracing = asObject(binding.harnessRuntime?.deepagent?.passthrough)?.tracing;
12
40
  const langchainTracing = asObject(binding.harnessRuntime?.langchain?.passthrough)?.tracing;
@@ -158,3 +186,121 @@ export function consumeRunInspectionUpstreamEvent(input) {
158
186
  delegationChain: maybeAppendAgent(input.delegationChain, delegatedAgentId),
159
187
  };
160
188
  }
189
+ function unwrapUpstreamEvent(event) {
190
+ const typed = asObject(event);
191
+ if (!typed) {
192
+ return { event };
193
+ }
194
+ const nestedEvent = asObject(typed.event);
195
+ if (nestedEvent) {
196
+ return {
197
+ event: nestedEvent,
198
+ ...(typeof typed.agentId === "string" ? { agentId: typed.agentId } : {}),
199
+ ...(typeof typed.agentName === "string" ? { agentName: typed.agentName } : {}),
200
+ };
201
+ }
202
+ return { event };
203
+ }
204
+ function toSurfaceKind(category) {
205
+ switch (category) {
206
+ case "llm":
207
+ case "memory":
208
+ case "skill":
209
+ case "tool":
210
+ return category;
211
+ default:
212
+ return null;
213
+ }
214
+ }
215
+ export function projectRuntimeSurfaceFromUpstreamEvents(input) {
216
+ const items = [];
217
+ let currentAgentId = input.initialAgentId;
218
+ let currentAgentName = formatAgentName(currentAgentId);
219
+ for (const [index, rawEvent] of input.upstreamEvents.entries()) {
220
+ const projected = projectRuntimeSurfaceFromSingleUpstreamEvent({
221
+ event: rawEvent,
222
+ binding: input.binding,
223
+ currentAgentId,
224
+ currentAgentName,
225
+ sourceEventId: `upstream:${index + 1}`,
226
+ });
227
+ currentAgentId = projected.currentAgentId;
228
+ currentAgentName = projected.currentAgentName;
229
+ items.push(...projected.items);
230
+ }
231
+ return items;
232
+ }
233
+ export function projectRuntimeSurfaceFromSingleUpstreamEvent(input) {
234
+ const reducer = createUpstreamTimelineReducer();
235
+ const items = [];
236
+ let currentAgentId = input.currentAgentId;
237
+ let currentAgentName = input.currentAgentName ?? formatAgentName(currentAgentId);
238
+ const unwrapped = unwrapUpstreamEvent(input.event);
239
+ if (unwrapped.agentId) {
240
+ if (unwrapped.agentId !== currentAgentId) {
241
+ const nextAgentName = unwrapped.agentName ?? formatAgentName(unwrapped.agentId);
242
+ items.push({
243
+ kind: "agent",
244
+ id: buildSurfaceId("agent", unwrapped.agentId),
245
+ name: nextAgentName,
246
+ label: `Delegate to ${nextAgentName}`,
247
+ status: "completed",
248
+ ownerAgentId: currentAgentId,
249
+ ownerAgentName: currentAgentName,
250
+ sourceEventId: input.sourceEventId,
251
+ });
252
+ }
253
+ currentAgentId = unwrapped.agentId;
254
+ currentAgentName = unwrapped.agentName ?? formatAgentName(currentAgentId);
255
+ }
256
+ else if (unwrapped.agentName) {
257
+ currentAgentName = unwrapped.agentName;
258
+ }
259
+ const typed = asObject(unwrapped.event);
260
+ if (typed && input.binding) {
261
+ const next = consumeRunInspectionUpstreamEvent({
262
+ event: typed,
263
+ currentAgentId,
264
+ delegationChain: [currentAgentId],
265
+ binding: input.binding,
266
+ });
267
+ if (next.currentAgentId !== currentAgentId) {
268
+ currentAgentId = next.currentAgentId;
269
+ currentAgentName = formatAgentName(currentAgentId);
270
+ items.push({
271
+ kind: "agent",
272
+ id: buildSurfaceId("agent", currentAgentId),
273
+ name: currentAgentName,
274
+ label: `Delegate to ${currentAgentName}`,
275
+ status: "completed",
276
+ ownerAgentId: next.delegationChain.at(-2),
277
+ ownerAgentName: next.delegationChain.at(-2) ? formatAgentName(next.delegationChain.at(-2)) : undefined,
278
+ sourceEventId: input.sourceEventId,
279
+ });
280
+ }
281
+ }
282
+ for (const projection of reducer.consume(unwrapped.event)) {
283
+ if (projection.type !== "step") {
284
+ continue;
285
+ }
286
+ const kind = toSurfaceKind(projection.category);
287
+ if (!kind) {
288
+ continue;
289
+ }
290
+ items.push({
291
+ kind,
292
+ id: buildSurfaceId(kind, stripStepPrefix(projection.step) || projection.step),
293
+ name: stripStepPrefix(projection.step) || formatAgentName(kind),
294
+ label: projection.step,
295
+ status: projection.status,
296
+ ownerAgentId: currentAgentId,
297
+ ownerAgentName: currentAgentName,
298
+ sourceEventId: input.sourceEventId,
299
+ });
300
+ }
301
+ return {
302
+ currentAgentId,
303
+ currentAgentName,
304
+ items,
305
+ };
306
+ }
@@ -2,7 +2,7 @@ import { AGENT_INTERRUPT_SENTINEL_PREFIX, RuntimeOperationTimeoutError } from ".
2
2
  import { renderRuntimeFailure, renderToolFailure } from "../../support/harness-support.js";
3
3
  import { getBindingPrimaryModel } from "../../support/compiled-binding.js";
4
4
  import { createContentBlocksItem, createToolResultKey, } from "../events/streaming.js";
5
- import { consumeRunInspectionUpstreamEvent } from "./inspection.js";
5
+ import { consumeRunInspectionUpstreamEvent, projectRuntimeSurfaceFromSingleUpstreamEvent } from "./inspection.js";
6
6
  import { formatAgentName } from "../../../utils/agent-display.js";
7
7
  function normalizeStreamChunk(chunk) {
8
8
  if (typeof chunk === "string") {
@@ -48,6 +48,7 @@ export async function* streamHarnessRun(options) {
48
48
  let currentAgentId = options.selectedAgentId;
49
49
  let currentAgentName = formatAgentName(options.selectedAgentId);
50
50
  let delegationChain = [options.selectedAgentId];
51
+ let upstreamEventOrdinal = 0;
51
52
  let syntheticFallback;
52
53
  try {
53
54
  const [priorHistory, acquiredReleaseRunSlot] = await Promise.all([
@@ -71,6 +72,18 @@ export async function* streamHarnessRun(options) {
71
72
  streamActivityObserved = true;
72
73
  const normalizedChunk = normalizeStreamChunk(rawChunk);
73
74
  if (normalizedChunk.kind === "upstream-event") {
75
+ upstreamEventOrdinal += 1;
76
+ const surfaceProjection = projectRuntimeSurfaceFromSingleUpstreamEvent({
77
+ event: {
78
+ agentId: currentAgentId,
79
+ agentName: currentAgentName,
80
+ event: normalizedChunk.event,
81
+ },
82
+ binding: options.binding,
83
+ currentAgentId,
84
+ currentAgentName,
85
+ sourceEventId: `upstream:${upstreamEventOrdinal}`,
86
+ });
74
87
  const inspection = consumeRunInspectionUpstreamEvent({
75
88
  event: normalizedChunk.event,
76
89
  currentAgentId,
@@ -95,6 +108,7 @@ export async function* streamHarnessRun(options) {
95
108
  runId: options.runId,
96
109
  agentId: currentAgentId,
97
110
  agentName: currentAgentName,
111
+ surfaceItems: surfaceProjection.items,
98
112
  event: normalizedChunk.event,
99
113
  };
100
114
  continue;
@@ -1,6 +1,7 @@
1
1
  import { isTerminalRunState, toInspectableApprovalRecord } from "./helpers.js";
2
2
  import { projectRuntimeTimeline } from "../events/timeline.js";
3
3
  import { createUpstreamTimelineReducer } from "../../../upstream-events.js";
4
+ import { projectRuntimeSurfaceFromUpstreamEvents } from "./inspection.js";
4
5
  function unwrapPersistedUpstreamEvent(event) {
5
6
  if (typeof event !== "object" || event === null || Array.isArray(event)) {
6
7
  return event;
@@ -31,6 +32,10 @@ export async function buildRequestInspectionRecord(persistence, request) {
31
32
  const inspection = await persistence.getRunInspection(request.threadId, request.runId);
32
33
  const runtimeEvents = await persistence.listRunEvents(request.threadId, request.runId);
33
34
  const { upstreamEvents, history } = buildRunInspectionProjection(inspection.upstreamEvents);
35
+ const runtimeSurface = projectRuntimeSurfaceFromUpstreamEvents({
36
+ upstreamEvents,
37
+ initialAgentId: request.agentId ?? inspection.currentAgentId ?? "agent",
38
+ });
34
39
  return {
35
40
  requestId: request.runId,
36
41
  sessionId: request.threadId,
@@ -51,6 +56,7 @@ export async function buildRequestInspectionRecord(persistence, request) {
51
56
  runtimeSnapshot: request.runtimeSnapshot,
52
57
  upstreamEvents,
53
58
  history,
59
+ runtimeSurface,
54
60
  runtimeTimeline: projectRuntimeTimeline(runtimeEvents, {
55
61
  threadId: request.threadId,
56
62
  runId: request.runId,
@@ -78,6 +84,7 @@ function toRunRecord(request) {
78
84
  runtimeSnapshot: request.runtimeSnapshot,
79
85
  upstreamEvents: request.upstreamEvents,
80
86
  history: request.history,
87
+ runtimeSurface: request.runtimeSurface,
81
88
  runtimeTimeline: request.runtimeTimeline,
82
89
  };
83
90
  }
@@ -38,6 +38,7 @@ import { consolidateStructuredMemoryScope } from "./harness/system/runtime-memor
38
38
  import { normalizeLangMemMemoryKind, readRuntimeMemoryMaintenanceConfig, readRuntimeMemoryPolicyConfig, resolveMemoryNamespace, scoreMemoryText, } from "./harness/system/runtime-memory-policy.js";
39
39
  import { resolveRuntimeAdapterOptions } from "./support/runtime-adapter-options.js";
40
40
  import { initializeHarnessRuntime, reclaimExpiredClaimedRuns as reclaimHarnessExpiredClaimedRuns, recoverStartupRuns as recoverHarnessStartupRuns, isStaleRunningRun as isHarnessStaleRunningRun, } from "./harness/run/startup-runtime.js";
41
+ import { normalizeProcessExecutablePath } from "./support/runtime-env.js";
41
42
  import { streamHarnessRun } from "./harness/run/stream-run.js";
42
43
  import { defaultRequestedAgentId, prepareRunStart } from "./harness/run/start-run.js";
43
44
  import { buildRequestInspectionRecord, buildSessionInspectionRecord, deleteSessionRecord, deleteThreadRecord, getPublicApproval, listPublicApprovals, } from "./harness/run/thread-records.js";
@@ -180,6 +181,7 @@ export class AgentHarnessRuntime {
180
181
  constructor(workspace, runtimeAdapterOptions = {}) {
181
182
  this.workspace = workspace;
182
183
  this.runtimeAdapterOptions = runtimeAdapterOptions;
184
+ normalizeProcessExecutablePath();
183
185
  this.runtimeEntryBindings = inferRoutingBindings(this.workspace).runtimeEntryBindings;
184
186
  this.defaultRuntimeEntryBinding = this.runtimeEntryBindings[0];
185
187
  this.defaultRunRootValue = this.defaultRuntimeEntryBinding?.harnessRuntime.runRoot ?? `${this.workspace.workspaceRoot}/run-data`;
@@ -1837,6 +1839,7 @@ function toRequestRecord(record) {
1837
1839
  ...toRequestSummary(record),
1838
1840
  upstreamEvents: record.upstreamEvents,
1839
1841
  history: record.history,
1842
+ runtimeSurface: record.runtimeSurface,
1840
1843
  runtimeTimeline: record.runtimeTimeline,
1841
1844
  };
1842
1845
  }
@@ -1,2 +1,3 @@
1
1
  export declare function augmentExecutablePath(pathValue: string | undefined, env?: Record<string, string | undefined> | NodeJS.ProcessEnv): string;
2
2
  export declare function createRuntimeEnv(env: Record<string, string> | undefined, baseEnv?: Record<string, string | undefined> | NodeJS.ProcessEnv): Record<string, string>;
3
+ export declare function normalizeProcessExecutablePath(env?: NodeJS.ProcessEnv): string;
@@ -55,3 +55,8 @@ export function createRuntimeEnv(env, baseEnv = process.env) {
55
55
  merged.PATH = augmentExecutablePath(combinedPath, { ...base, ...(env ?? {}) });
56
56
  return merged;
57
57
  }
58
+ export function normalizeProcessExecutablePath(env = process.env) {
59
+ const normalized = augmentExecutablePath(env.PATH, env);
60
+ env.PATH = normalized;
61
+ return normalized;
62
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.249",
3
+ "version": "0.0.251",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",