@cognipeer/agent-sdk 0.16.0 → 0.17.0

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/index.d.cts CHANGED
@@ -1063,6 +1063,10 @@ type SubagentPendingRecord = {
1063
1063
  /** Maps the child's pending approval/question id -> parent-surfaced id. */
1064
1064
  pendingKind: "approval" | "user_question";
1065
1065
  pendingId: string;
1066
+ /** The run's id on `subagent` events and in its trace; the resumed run keeps it. */
1067
+ spawnId?: string;
1068
+ /** Iterations the child had opened when it paused; the resumed run numbers on from there. */
1069
+ iterations?: number;
1066
1070
  };
1067
1071
  type SubagentToolNames = {
1068
1072
  delegate: string;
@@ -2141,6 +2145,12 @@ type TraceSessionSummary = {
2141
2145
  totalBytesIn: number;
2142
2146
  totalBytesOut: number;
2143
2147
  eventCounts: Record<string, number>;
2148
+ /**
2149
+ * Iterations run by sub-agents recording into this session. They count in
2150
+ * `eventCounts.agent_iteration` too; the root agent subtracts them to number
2151
+ * its own iterations.
2152
+ */
2153
+ subagentIterations?: number;
2144
2154
  };
2145
2155
  /**
2146
2156
  * `paused`: the run stopped to wait for a tool approval or an answer from the
@@ -2893,6 +2903,12 @@ type ToolCallContext = {
2893
2903
  toolCallId?: string;
2894
2904
  cancellationToken?: any;
2895
2905
  signal?: AbortSignal;
2906
+ /**
2907
+ * Span id the tools node will give this call's `tool_call` trace event. Known
2908
+ * before the tool runs so that whatever it records (a sub-agent's spans) can
2909
+ * nest under it. Absent when the run is not traced.
2910
+ */
2911
+ traceSpanId?: string;
2896
2912
  };
2897
2913
  type SmartToolFn = (args: any, context?: ToolCallContext) => Promise<any> | any;
2898
2914
  type ToolCachePolicy = {
@@ -5595,7 +5611,11 @@ declare function recordTraceEvent(session: TraceSessionRuntime | undefined, even
5595
5611
  status?: TraceEventRecord["status"];
5596
5612
  /** Explicit parent span ID. Falls back to session.currentIterationSpanId when omitted. */
5597
5613
  parentSpanId?: string;
5614
+ /** Pre-allocated span ID, for an event whose children are recorded before it is. */
5615
+ spanId?: string;
5598
5616
  durationMs?: number;
5617
+ /** False for a span that wraps events already counted, so the totals do not take the time twice. */
5618
+ countDuration?: boolean;
5599
5619
  inputTokens?: number;
5600
5620
  outputTokens?: number;
5601
5621
  totalTokens?: number;
@@ -5618,6 +5638,8 @@ declare function recordTraceEvent(session: TraceSessionRuntime | undefined, even
5618
5638
  messageList?: any[];
5619
5639
  /** Pre-built sections to use instead of auto-converting messageList */
5620
5640
  sections?: TraceDataSection[];
5641
+ /** Identity sections kept even when logData is off; the caller vouches they carry no payload. */
5642
+ alwaysSections?: TraceDataSection[];
5621
5643
  /**
5622
5644
  * Tool MENU bound to this model call (`ai_call` events). Appended as a
5623
5645
  * `tool_definitions` section AFTER messageList/sections resolution, so it
package/dist/index.d.ts CHANGED
@@ -1063,6 +1063,10 @@ type SubagentPendingRecord = {
1063
1063
  /** Maps the child's pending approval/question id -> parent-surfaced id. */
1064
1064
  pendingKind: "approval" | "user_question";
1065
1065
  pendingId: string;
1066
+ /** The run's id on `subagent` events and in its trace; the resumed run keeps it. */
1067
+ spawnId?: string;
1068
+ /** Iterations the child had opened when it paused; the resumed run numbers on from there. */
1069
+ iterations?: number;
1066
1070
  };
1067
1071
  type SubagentToolNames = {
1068
1072
  delegate: string;
@@ -2141,6 +2145,12 @@ type TraceSessionSummary = {
2141
2145
  totalBytesIn: number;
2142
2146
  totalBytesOut: number;
2143
2147
  eventCounts: Record<string, number>;
2148
+ /**
2149
+ * Iterations run by sub-agents recording into this session. They count in
2150
+ * `eventCounts.agent_iteration` too; the root agent subtracts them to number
2151
+ * its own iterations.
2152
+ */
2153
+ subagentIterations?: number;
2144
2154
  };
2145
2155
  /**
2146
2156
  * `paused`: the run stopped to wait for a tool approval or an answer from the
@@ -2893,6 +2903,12 @@ type ToolCallContext = {
2893
2903
  toolCallId?: string;
2894
2904
  cancellationToken?: any;
2895
2905
  signal?: AbortSignal;
2906
+ /**
2907
+ * Span id the tools node will give this call's `tool_call` trace event. Known
2908
+ * before the tool runs so that whatever it records (a sub-agent's spans) can
2909
+ * nest under it. Absent when the run is not traced.
2910
+ */
2911
+ traceSpanId?: string;
2896
2912
  };
2897
2913
  type SmartToolFn = (args: any, context?: ToolCallContext) => Promise<any> | any;
2898
2914
  type ToolCachePolicy = {
@@ -5595,7 +5611,11 @@ declare function recordTraceEvent(session: TraceSessionRuntime | undefined, even
5595
5611
  status?: TraceEventRecord["status"];
5596
5612
  /** Explicit parent span ID. Falls back to session.currentIterationSpanId when omitted. */
5597
5613
  parentSpanId?: string;
5614
+ /** Pre-allocated span ID, for an event whose children are recorded before it is. */
5615
+ spanId?: string;
5598
5616
  durationMs?: number;
5617
+ /** False for a span that wraps events already counted, so the totals do not take the time twice. */
5618
+ countDuration?: boolean;
5599
5619
  inputTokens?: number;
5600
5620
  outputTokens?: number;
5601
5621
  totalTokens?: number;
@@ -5618,6 +5638,8 @@ declare function recordTraceEvent(session: TraceSessionRuntime | undefined, even
5618
5638
  messageList?: any[];
5619
5639
  /** Pre-built sections to use instead of auto-converting messageList */
5620
5640
  sections?: TraceDataSection[];
5641
+ /** Identity sections kept even when logData is off; the caller vouches they carry no payload. */
5642
+ alwaysSections?: TraceDataSection[];
5621
5643
  /**
5622
5644
  * Tool MENU bound to this model call (`ai_call` events). Appended as a
5623
5645
  * `tool_definitions` section AFTER messageList/sections resolution, so it
package/dist/index.mjs CHANGED
@@ -2203,7 +2203,7 @@ function recordTraceEvent(session, event) {
2203
2203
  const baseLabel = event.label?.trim().length ? event.label.trim() : defaultEventLabel(event.type);
2204
2204
  const eventLabel = `${baseLabel} #${sequence}`;
2205
2205
  const durationMs = event.durationMs !== void 0 ? Number(event.durationMs) : void 0;
2206
- if (!Number.isNaN(durationMs ?? NaN) && durationMs !== void 0) {
2206
+ if (!Number.isNaN(durationMs ?? NaN) && durationMs !== void 0 && event.countDuration !== false && !isSubagentTraceScope(session)) {
2207
2207
  session.summary.totalDurationMs += durationMs;
2208
2208
  }
2209
2209
  const inputTokens = event.inputTokens !== void 0 ? Number(event.inputTokens) : void 0;
@@ -2252,10 +2252,13 @@ function recordTraceEvent(session, event) {
2252
2252
  }
2253
2253
  }
2254
2254
  }
2255
+ if (event.alwaysSections?.length) {
2256
+ sections = ensureUniqueSections(id, [...event.alwaysSections, ...sections ?? []]);
2257
+ }
2255
2258
  const resolvedModel = event.model ?? inferModelFromMessages(event.messageList);
2256
2259
  const resolvedProvider = event.provider ?? inferProviderFromMessages(event.messageList);
2257
2260
  const isAiCall = event.type === "ai_call";
2258
- const spanId = generateSpanId();
2261
+ const spanId = event.spanId || generateSpanId();
2259
2262
  const parentSpanId = event.parentSpanId || session.currentIterationSpanId || session.rootSpanId;
2260
2263
  const record = {
2261
2264
  sessionId: session.sessionId,
@@ -2349,6 +2352,58 @@ var DEFERRED_TRACE_EVENTS_KEY = "__deferredTraceEvents";
2349
2352
  function isTraceSessionOpen(session) {
2350
2353
  return Boolean(session) && !session.closed;
2351
2354
  }
2355
+ var SUBAGENT_TRACE_SCOPE = Symbol("subagentTraceScope");
2356
+ function createSubagentTraceScope(parent, info) {
2357
+ const scope = { ...info, iterations: info.iterations ?? 0 };
2358
+ let currentIterationSpanId;
2359
+ return new Proxy(parent, {
2360
+ get(target, prop) {
2361
+ if (prop === SUBAGENT_TRACE_SCOPE) return scope;
2362
+ if (prop === "rootSpanId") return scope.agentSpanId;
2363
+ if (prop === "currentIterationSpanId") return currentIterationSpanId;
2364
+ return Reflect.get(target, prop);
2365
+ },
2366
+ set(target, prop, value) {
2367
+ if (prop === "currentIterationSpanId") {
2368
+ currentIterationSpanId = value;
2369
+ return true;
2370
+ }
2371
+ return Reflect.set(target, prop, value);
2372
+ }
2373
+ });
2374
+ }
2375
+ function subagentTraceScopeOf(session) {
2376
+ if (!session) return void 0;
2377
+ return session[SUBAGENT_TRACE_SCOPE];
2378
+ }
2379
+ function canPauseForHuman(session) {
2380
+ return subagentTraceScopeOf(session)?.hitl !== false;
2381
+ }
2382
+ function isSubagentTraceScope(session) {
2383
+ return subagentTraceScopeOf(session) !== void 0;
2384
+ }
2385
+ function recordSubagentSpan(session, span) {
2386
+ const sections = [];
2387
+ if (session.resolvedConfig.logData) {
2388
+ if (span.task !== void 0) sections.push({ kind: "message", label: "Task", role: "user", content: span.task });
2389
+ if (span.result) sections.push({ kind: "message", label: "Result", role: "assistant", content: span.result });
2390
+ }
2391
+ recordTraceEvent(session, {
2392
+ type: "span",
2393
+ spanId: span.spanId,
2394
+ parentSpanId: span.parentSpanId,
2395
+ label: `Sub-agent ${span.name}`,
2396
+ actor: { scope: "agent", name: span.name, role: "subagent" },
2397
+ status: span.status,
2398
+ durationMs: span.durationMs,
2399
+ // The child's own calls and the delegating tool_call already hold this time.
2400
+ countDuration: false,
2401
+ ...span.error ? { error: { message: span.error } } : {},
2402
+ // The Console reads which sub-agent ran from here, so it survives logData off.
2403
+ alwaysSections: [{ kind: "metadata", label: "Sub-agent", data: sanitizeTracePayload(span.info) }],
2404
+ sections
2405
+ });
2406
+ }
2352
2407
  function recordOrDeferTraceEvent(ctx, event, options) {
2353
2408
  const session = ctx?.__traceSession;
2354
2409
  if (isTraceSessionOpen(session)) {
@@ -4926,6 +4981,9 @@ ${append}`;
4926
4981
 
4927
4982
  // src/utils/traceDecisions.ts
4928
4983
  var TRACED_KEY = "__outcomeTraced";
4984
+ function surfacedFromSubagent(entry) {
4985
+ return Boolean(entry.metadata?.__subagent);
4986
+ }
4929
4987
  function waitedMs(from, to) {
4930
4988
  if (!from || !to) return void 0;
4931
4989
  const ms = Date.parse(to) - Date.parse(from);
@@ -4939,7 +4997,7 @@ function sameJson(a, b) {
4939
4997
  }
4940
4998
  }
4941
4999
  function recordApprovalRequested(session, entry) {
4942
- if (!session) return;
5000
+ if (!session || surfacedFromSubagent(entry) || !canPauseForHuman(session)) return;
4943
5001
  const logData = session.resolvedConfig.logData;
4944
5002
  const sections = [
4945
5003
  {
@@ -4970,7 +5028,7 @@ function recordHumanDecisions(session, state) {
4970
5028
  if (!session) return;
4971
5029
  const logData = session.resolvedConfig.logData;
4972
5030
  for (const entry of state.pendingApprovals ?? []) {
4973
- if (!entry.decidedAt || entry.metadata?.[TRACED_KEY]) continue;
5031
+ if (!entry.decidedAt || entry.metadata?.[TRACED_KEY] || surfacedFromSubagent(entry)) continue;
4974
5032
  if (entry.status !== "approved" && entry.status !== "rejected") continue;
4975
5033
  const approved = entry.status === "approved";
4976
5034
  const edited = approved && entry.approvedArgs !== void 0 && !sameJson(entry.approvedArgs, entry.args);
@@ -5009,7 +5067,7 @@ function recordHumanDecisions(session, state) {
5009
5067
  entry.metadata = { ...entry.metadata || {}, [TRACED_KEY]: true };
5010
5068
  }
5011
5069
  for (const entry of state.pendingUserQuestions ?? []) {
5012
- if (!entry.answeredAt || entry.metadata?.[TRACED_KEY]) continue;
5070
+ if (!entry.answeredAt || entry.metadata?.[TRACED_KEY] || surfacedFromSubagent(entry)) continue;
5013
5071
  if (entry.status !== "answered" && entry.status !== "cancelled") continue;
5014
5072
  const clientTool = readClientTool(entry);
5015
5073
  if (clientTool) {
@@ -5055,7 +5113,7 @@ function recordHumanDecisions(session, state) {
5055
5113
  }
5056
5114
  }
5057
5115
  function recordClientToolRequested(session, entry) {
5058
- if (!session) return;
5116
+ if (!session || surfacedFromSubagent(entry) || !canPauseForHuman(session)) return;
5059
5117
  const clientTool = readClientTool(entry);
5060
5118
  if (!clientTool) return;
5061
5119
  const sections = [
@@ -5711,6 +5769,7 @@ function createToolsNode(initialTools, opts) {
5711
5769
  toolCount += 1;
5712
5770
  return { status: "error" };
5713
5771
  }
5772
+ let traceSpanId;
5714
5773
  try {
5715
5774
  if (cachedHit !== void 0) {
5716
5775
  const executionId2 = nanoid();
@@ -5790,7 +5849,8 @@ function createToolsNode(initialTools, opts) {
5790
5849
  onEvent?.({ type: "tool_call", phase: "start", name: toolName, id: tc.id, args });
5791
5850
  onProgress?.({ stage: "tools", message: `Running tool ${tc.name}` });
5792
5851
  const anyTool = tool;
5793
- const callOptions = { cancellationToken, signal: abortSignal, toolCallId };
5852
+ traceSpanId = traceSession ? generateSpanId() : void 0;
5853
+ const callOptions = { cancellationToken, signal: abortSignal, toolCallId, ...traceSpanId ? { traceSpanId } : {} };
5794
5854
  const invokeOnce = async () => {
5795
5855
  if (typeof anyTool.func === "function") return anyTool.func(args, callOptions);
5796
5856
  if (typeof anyTool.invoke === "function") return anyTool.invoke(args, callOptions);
@@ -5973,6 +6033,7 @@ function createToolsNode(initialTools, opts) {
5973
6033
  const outputBytes = traceSession?.resolvedConfig.logData ? estimatePayloadBytes(sanitizedOutput) : void 0;
5974
6034
  recordTraceEvent(traceSession, {
5975
6035
  type: "tool_call",
6036
+ spanId: traceSpanId,
5976
6037
  label: `Tool Execution - ${toolName}`,
5977
6038
  actor: { scope: "tool", name: toolName, role: "tool" },
5978
6039
  ...reportedFailure ? { status: "error", error: { message: reportedFailure } } : {},
@@ -6035,6 +6096,7 @@ function createToolsNode(initialTools, opts) {
6035
6096
  const errorOutput = { message, stack: host?.has("postToolUse") ? void 0 : error?.stack };
6036
6097
  recordTraceEvent(traceSession, {
6037
6098
  type: "tool_call",
6099
+ spanId: traceSpanId,
6038
6100
  label: `Tool Error - ${toolName}`,
6039
6101
  actor: { scope: "tool", name: toolName, role: "tool" },
6040
6102
  status: "error",
@@ -6995,7 +7057,7 @@ function createAskUserQuestionTool(stateRef, config) {
6995
7057
  questions: entry.questions,
6996
7058
  allowFreeText
6997
7059
  });
6998
- recordTraceEvent(ctx.__traceSession, {
7060
+ if (canPauseForHuman(ctx.__traceSession)) recordTraceEvent(ctx.__traceSession, {
6999
7061
  type: "user_question",
7000
7062
  label: "Question to user",
7001
7063
  timestamp: entry.requestedAt,
@@ -8278,19 +8340,22 @@ function createAgent(opts) {
8278
8340
  detail: { reason: budget.reason, iteration: iterations }
8279
8341
  });
8280
8342
  }
8343
+ recordHumanDecisions(state.ctx?.__traceSession, state);
8281
8344
  const ctx = { ...state.ctx || {}, __limitBreached: budget.reason };
8282
8345
  state = { ...state, ctx };
8283
8346
  break;
8284
8347
  }
8285
8348
  const traceSession = state.ctx?.__traceSession;
8286
8349
  if (traceSession) {
8287
- const iterationNumber = (traceSession.summary.eventCounts.agent_iteration ?? 0) + 1;
8350
+ const subagentScope = subagentTraceScopeOf(traceSession);
8351
+ const iterationNumber = subagentScope ? ++subagentScope.iterations : (traceSession.summary.eventCounts.agent_iteration ?? 0) - (traceSession.summary.subagentIterations ?? 0) + 1;
8288
8352
  const iterEvent = recordTraceEvent(traceSession, {
8289
8353
  type: "agent_iteration",
8290
8354
  label: `Iteration ${iterationNumber}`,
8291
8355
  actor: { scope: "agent", name: opts.name || "agent", role: "orchestrator" },
8292
8356
  parentSpanId: traceSession.rootSpanId
8293
8357
  });
8358
+ if (subagentScope) traceSession.summary.subagentIterations = (traceSession.summary.subagentIterations ?? 0) + 1;
8294
8359
  if (iterEvent) {
8295
8360
  traceSession.currentIterationSpanId = iterEvent.spanId;
8296
8361
  }
@@ -8600,7 +8665,9 @@ function createAgent(opts) {
8600
8665
  const inheritedSession = config?.__pluginSession;
8601
8666
  ctx.__runId = inheritedSession?.runId ?? traceSession?.sessionId ?? `run_${nanoid(10)}`;
8602
8667
  const stateHolder = inheritedSession?.stateHolder ?? { value: void 0 };
8603
- const traceRecorder = createPluginTraceRecorder(() => traceSession);
8668
+ const traceRecorder = createPluginTraceRecorder(
8669
+ () => traceSession ?? (subagentTraceScopeOf(ctx.__traceSession) ? ctx.__traceSession : void 0)
8670
+ );
8604
8671
  const runHost = inheritedSession?.host ?? (pluginHost.hasAny() ? pluginHost.beginRun({
8605
8672
  runId: ctx.__runId,
8606
8673
  agentName: opts.name,
@@ -8843,7 +8910,7 @@ function createAgent(opts) {
8843
8910
  name: toolName,
8844
8911
  description: description || `Delegate task to agent ${opts.name || "Agent"}`,
8845
8912
  schema,
8846
- func: async ({ input }) => {
8913
+ func: async ({ input }, context) => {
8847
8914
  const ref = delegatedTool._stateRef;
8848
8915
  const parentCtx = ref.ctx || {};
8849
8916
  const parentMessages = Array.isArray(ref.messages) ? ref.messages : [];
@@ -8876,6 +8943,33 @@ function createAgent(opts) {
8876
8943
  input
8877
8944
  );
8878
8945
  const childCtx = { __delegationDepth: currentDepth + 1 };
8946
+ const parentSession = parentCtx.__traceSession;
8947
+ const traced = isTraceSessionOpen(parentSession);
8948
+ const agentSpanId = generateSpanId();
8949
+ const parentIterationSpanId = traced ? parentSession.currentIterationSpanId : void 0;
8950
+ if (traced && !withDefaults(opts.tracing).enabled) {
8951
+ childCtx.__traceSession = createSubagentTraceScope(parentSession, {
8952
+ agentSpanId,
8953
+ name: opts.name || "agent",
8954
+ mode: "asTool",
8955
+ hitl: false
8956
+ });
8957
+ }
8958
+ const startedAt = Date.now();
8959
+ const recordSpan = (status, extra) => {
8960
+ if (!traced || !isTraceSessionOpen(parentSession)) return;
8961
+ recordSubagentSpan(parentSession, {
8962
+ spanId: agentSpanId,
8963
+ parentSpanId: context?.traceSpanId ?? parentIterationSpanId,
8964
+ name: opts.name || "agent",
8965
+ status,
8966
+ durationMs: Date.now() - startedAt,
8967
+ error: extra.error,
8968
+ info: { name: opts.name || "agent", mode: "asTool", depth: currentDepth + 1, parentToolCallId: context?.toolCallId, status: status === "success" ? "ok" : "error" },
8969
+ task: input,
8970
+ result: extra.result
8971
+ });
8972
+ };
8879
8973
  const childConfig = {
8880
8974
  onEvent: parentCtx.__onEvent ? (e) => {
8881
8975
  if (e?.type === "finalAnswer" || e?.type === "metadata") return;
@@ -8891,7 +8985,14 @@ function createAgent(opts) {
8891
8985
  stream: Boolean(parentCtx.__streaming),
8892
8986
  cancellationToken: parentCtx.__cancellationToken ?? parentCtx.__abortSignal
8893
8987
  };
8894
- const res = await instance.invoke({ messages: childMessages, ctx: childCtx }, childConfig);
8988
+ let res;
8989
+ try {
8990
+ res = await instance.invoke({ messages: childMessages, ctx: childCtx }, childConfig);
8991
+ } catch (err) {
8992
+ recordSpan("error", { error: err?.message || String(err) });
8993
+ throw err;
8994
+ }
8995
+ recordSpan("success", { result: res.content });
8895
8996
  return {
8896
8997
  content: res.content,
8897
8998
  output: res.output,
@@ -11054,11 +11155,42 @@ function mergeChildUsage(ref, childState, baseline, tag) {
11054
11155
  async function runChild(spec, input, deps, ref, opts) {
11055
11156
  const parentCtx = ref.ctx || {};
11056
11157
  const parentOnEvent = parentCtx.__onEvent;
11057
- const spawnId = `sa_${nanoid(6)}`;
11158
+ const spawnId = opts.record?.spawnId ?? `sa_${nanoid(6)}`;
11058
11159
  const start = Date.now();
11059
11160
  const usageTag = { name: spec.name, id: spawnId, mode: spec.mode };
11060
11161
  const parentHost = parentCtx.__plugins;
11061
11162
  const childDepth = (Number(parentCtx.__delegationDepth) || 0) + 1;
11163
+ const parentSession = parentCtx.__traceSession;
11164
+ const traced = isTraceSessionOpen(parentSession);
11165
+ const agentSpanId = generateSpanId();
11166
+ const parentIterationSpanId = traced ? parentSession.currentIterationSpanId : void 0;
11167
+ const traceScope = traced ? createSubagentTraceScope(parentSession, { agentSpanId, name: spec.name, spawnId, mode: spec.mode, hitl: opts.allowHITL, iterations: opts.record?.iterations }) : void 0;
11168
+ const recordSegment = (status, info) => {
11169
+ if (!traced || !isTraceSessionOpen(parentSession)) return;
11170
+ recordSubagentSpan(parentSession, {
11171
+ spanId: agentSpanId,
11172
+ // The tool_call span only exists once the tool returns; a paused child
11173
+ // has not returned, so its span hangs off the iteration.
11174
+ parentSpanId: status === "pending" ? parentIterationSpanId : opts.parentSpanId ?? parentIterationSpanId,
11175
+ name: spec.name,
11176
+ status,
11177
+ durationMs: Date.now() - start,
11178
+ error: info.error,
11179
+ info: {
11180
+ id: spawnId,
11181
+ name: spec.name,
11182
+ mode: spec.mode,
11183
+ parallel: opts.parallel,
11184
+ depth: childDepth,
11185
+ parentToolCallId: opts.parentToolCallId,
11186
+ status: info.subagentStatus,
11187
+ ...info.note ? { note: info.note } : {},
11188
+ ...spec.metadata ? { metadata: spec.metadata } : {}
11189
+ },
11190
+ task: info.input,
11191
+ result: info.content
11192
+ });
11193
+ };
11062
11194
  const emitStart = (task) => {
11063
11195
  parentOnEvent?.({ type: "subagent", phase: "start", name: spec.name, id: spawnId, mode: spec.mode, parallel: opts.parallel, parentToolCallId: opts.parentToolCallId, input: task });
11064
11196
  };
@@ -11066,6 +11198,15 @@ async function runChild(spec, input, deps, ref, opts) {
11066
11198
  result2.durationMs ?? (result2.durationMs = Date.now() - start);
11067
11199
  deps.registryRef.results.push(result2);
11068
11200
  const message = result2.error || result2.note || result2.status;
11201
+ const traceStatus = result2.status === "ok" || result2.status === "incomplete" ? "success" : result2.status === "blocked" ? "skipped" : "error";
11202
+ recordSegment(traceStatus, {
11203
+ subagentStatus: result2.status,
11204
+ input,
11205
+ // `message` falls back to the status itself ("ok"): only a failed or refused run has an error to show.
11206
+ error: traceStatus === "success" ? void 0 : message,
11207
+ note: result2.note,
11208
+ content: result2.content
11209
+ });
11069
11210
  parentOnEvent?.({
11070
11211
  type: "subagent",
11071
11212
  phase: FAILED_STATUSES.has(result2.status) ? "error" : "result",
@@ -11164,6 +11305,7 @@ async function runChild(spec, input, deps, ref, opts) {
11164
11305
  ctx: { __delegationDepth: currentDepth + 1 }
11165
11306
  };
11166
11307
  }
11308
+ if (traceScope) childInput = { ...childInput, ctx: { ...childInput.ctx || {}, __traceSession: traceScope } };
11167
11309
  const usageBaseline = childInput.usage?.perRequest?.length ?? 0;
11168
11310
  let res;
11169
11311
  try {
@@ -11204,8 +11346,11 @@ async function runChild(spec, input, deps, ref, opts) {
11204
11346
  input,
11205
11347
  childState: cleanChildState(childState),
11206
11348
  pendingKind: "approval",
11207
- pendingId: childEntry.id
11349
+ pendingId: childEntry.id,
11350
+ spawnId,
11351
+ iterations: traceScope ? subagentTraceScopeOf(traceScope)?.iterations : void 0
11208
11352
  };
11353
+ recordSegment("pending", { subagentStatus: "paused", input });
11209
11354
  parentOnEvent?.({ type: "subagent", phase: "paused", name: spec.name, id: spawnId, mode: spec.mode, parentToolCallId: opts.parentToolCallId });
11210
11355
  return { kind: "approval", toolCallId: surfaced.toolCallId, approvalId: surfaced.id };
11211
11356
  }
@@ -11227,8 +11372,11 @@ async function runChild(spec, input, deps, ref, opts) {
11227
11372
  input,
11228
11373
  childState: cleanChildState(childState),
11229
11374
  pendingKind: "user_question",
11230
- pendingId: childEntry.id
11375
+ pendingId: childEntry.id,
11376
+ spawnId,
11377
+ iterations: traceScope ? subagentTraceScopeOf(traceScope)?.iterations : void 0
11231
11378
  };
11379
+ recordSegment("pending", { subagentStatus: "paused", input });
11232
11380
  parentOnEvent?.({ type: "subagent", phase: "paused", name: spec.name, id: spawnId, mode: spec.mode, parentToolCallId: opts.parentToolCallId });
11233
11381
  return { kind: "user_question", toolCallId: surfaced.toolCallId, id: surfaced.id };
11234
11382
  }
@@ -11332,7 +11480,7 @@ function createDelegateTool(deps) {
11332
11480
  if (!budget.ok) return refusal(budget.reason);
11333
11481
  d.registryRef.spawnedCount += 1;
11334
11482
  }
11335
- return toToolReturn(await runChild(spec, record?.input ?? input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record }));
11483
+ return toToolReturn(await runChild(spec, record?.input ?? input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record, parentSpanId: context?.traceSpanId }));
11336
11484
  }
11337
11485
  });
11338
11486
  tool._deps = deps;
@@ -11377,7 +11525,7 @@ function createSpawnTool(deps) {
11377
11525
  if (!budget.ok) return refusal(budget.reason);
11378
11526
  d.registryRef.spawnedCount += 1;
11379
11527
  }
11380
- return toToolReturn(await runChild(spec, record?.input ?? args.input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record }));
11528
+ return toToolReturn(await runChild(spec, record?.input ?? args.input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record, parentSpanId: context?.traceSpanId }));
11381
11529
  }
11382
11530
  });
11383
11531
  tool._deps = deps;
@@ -11460,7 +11608,8 @@ function createParallelTool(deps) {
11460
11608
  allowHITL: false,
11461
11609
  parentToolCallId: `${parentToolCallId}#${i}`,
11462
11610
  parallel: true,
11463
- reserved: true
11611
+ reserved: true,
11612
+ parentSpanId: context?.traceSpanId
11464
11613
  });
11465
11614
  results[i] = outcome.kind === "result" ? outcome.result : { name: entry.spec.name, mode: entry.spec.mode, status: "error", input: entry.input, error: "Unexpected pause in parallel child." };
11466
11615
  }
@@ -15755,6 +15904,7 @@ function otelTracing(config) {
15755
15904
  sessionEnd: async ({ status, durationMs, error }, ctx) => {
15756
15905
  const state = ctx.state;
15757
15906
  const session = state.ctx?.__traceSession;
15907
+ if (isSubagentTraceScope(session)) return;
15758
15908
  if (!session) {
15759
15909
  const message = "otelTracing exported nothing: the agent has no trace session. Enable the SDK's tracing runtime with `tracing: { enabled: true }` \u2014 the plugin exports the session the runtime records, it does not record one itself.";
15760
15910
  ctx.logger.warn(message);