@cognipeer/agent-sdk 0.18.0 → 0.20.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.cjs CHANGED
@@ -1258,7 +1258,7 @@ function cacheWriteTokensOf(raw) {
1258
1258
  init_content();
1259
1259
 
1260
1260
  // src/version.ts
1261
- var SDK_VERSION = "0.18.0";
1261
+ var SDK_VERSION = "0.20.0";
1262
1262
 
1263
1263
  // src/utils/otlp/content.ts
1264
1264
  init_content();
@@ -1752,7 +1752,7 @@ function sessionToOtlp(file, options) {
1752
1752
  const agentName = file.agent?.name;
1753
1753
  const everyEvent = file.events;
1754
1754
  const exportedEvents = foldSupersededSpans(everyEvent).filter(
1755
- (event) => options.terminal || !(event.type === "span" && event.status === "pending")
1755
+ (event) => options.terminal || !(event.type === "span" && (event.status === "pending" || event.status === "running"))
1756
1756
  );
1757
1757
  const startMs = parseMs(file.startedAt);
1758
1758
  const nodes = exportedEvents.map((event) => {
@@ -3766,7 +3766,9 @@ function foldSupersededSpans(events) {
3766
3766
  const current = winner.get(id);
3767
3767
  if (current === void 0 || rank(events[i], i) >= rank(events[current], current)) winner.set(id, i);
3768
3768
  }
3769
- return events.filter((event, i) => !(event.spanId && event.status === "pending" && winner.get(event.spanId) !== i));
3769
+ return events.filter(
3770
+ (event, i) => !(event.spanId && (event.status === "pending" || event.status === "running") && winner.get(event.spanId) !== i)
3771
+ );
3770
3772
  }
3771
3773
  function recordOrDeferTraceEvent(ctx, event, options) {
3772
3774
  const session = ctx?.__traceSession;
@@ -10544,14 +10546,16 @@ function createAgent(opts) {
10544
10546
  const startedAt = Date.now();
10545
10547
  const recordSpan = (status, extra) => {
10546
10548
  if (!traced || !isTraceSessionOpen(parentSession)) return;
10549
+ const running = status === "running";
10547
10550
  recordSubagentSpan(parentSession, {
10548
10551
  spanId: agentSpanId,
10549
- parentSpanId: context?.traceSpanId ?? parentIterationSpanId,
10552
+ // The delegating tool_call span only exists once the tool returns.
10553
+ parentSpanId: running ? parentIterationSpanId : context?.traceSpanId ?? parentIterationSpanId,
10550
10554
  name: opts.name || "agent",
10551
10555
  status,
10552
- durationMs: Date.now() - startedAt,
10556
+ durationMs: running ? void 0 : Date.now() - startedAt,
10553
10557
  error: extra.error,
10554
- info: { name: opts.name || "agent", mode: "asTool", depth: currentDepth + 1, parentToolCallId: context?.toolCallId, status: status === "success" ? "ok" : "error" },
10558
+ info: { name: opts.name || "agent", mode: "asTool", depth: currentDepth + 1, parentToolCallId: context?.toolCallId, status: running ? "running" : status === "success" ? "ok" : "error" },
10555
10559
  task: input,
10556
10560
  result: extra.result
10557
10561
  });
@@ -10571,6 +10575,7 @@ function createAgent(opts) {
10571
10575
  stream: Boolean(parentCtx.__streaming),
10572
10576
  cancellationToken: parentCtx.__cancellationToken ?? parentCtx.__abortSignal
10573
10577
  };
10578
+ recordSpan("running", {});
10574
10579
  let res;
10575
10580
  try {
10576
10581
  res = await instance.invoke({ messages: childMessages, ctx: childCtx }, childConfig);
@@ -10870,6 +10875,13 @@ function buildModelMessages(state, config) {
10870
10875
  var systemMessage = (content) => ({ role: "system", content });
10871
10876
  var humanMessage = (content) => ({ role: "user", content });
10872
10877
  var LAST_SUMMARIZATION_CALL_KEY = "__lastSummarizationCall";
10878
+ var SUMMARIZATION_TRIGGER_KEY = "__summarizationTrigger";
10879
+ var SUMMARIZATION_TRIGGERS = ["pre_leg", "mid_leg", "post_tools"];
10880
+ var MAX_EVENT_ERROR_CHARS = 300;
10881
+ function eventErrorText(message) {
10882
+ if (!message) return void 0;
10883
+ return message.length > MAX_EVENT_ERROR_CHARS ? `${message.slice(0, MAX_EVENT_ERROR_CHARS - 3)}...` : message;
10884
+ }
10873
10885
  var MAX_MESSAGE_CHARS = 2e3;
10874
10886
  var MAX_USER_MESSAGE_CHARS = 4e3;
10875
10887
  function validateMessageSequence(messages) {
@@ -11196,7 +11208,7 @@ function repairStructuredSummary(previous, current, integrity) {
11196
11208
  return { ...current, user_directives: directives, stable_facts: filteredFacts };
11197
11209
  }
11198
11210
  function createContextSummarizeNode(opts) {
11199
- return async (state) => {
11211
+ const summarizePass = async (state, events) => {
11200
11212
  const resolved = getResolvedSmartConfig(opts, state.agent);
11201
11213
  const config = resolved.summarization;
11202
11214
  if (!config.enable) return {};
@@ -11387,11 +11399,25 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
11387
11399
  ...summaryPrompt,
11388
11400
  ...rawModelOutput !== void 0 ? [{ role: "assistant", content: rawModelOutput, name: "summarization_result" }] : []
11389
11401
  ]));
11402
+ const summaryToolCallId = `call_summary_${Date.now()}_${nanoid.nanoid(6)}`;
11403
+ const passNumber = (Array.isArray(state.summaries) ? state.summaries.length : 0) + 1;
11404
+ const rawTrigger = state.ctx?.[SUMMARIZATION_TRIGGER_KEY];
11405
+ const trigger = SUMMARIZATION_TRIGGERS.includes(rawTrigger) ? rawTrigger : void 0;
11406
+ const passIdentity = {
11407
+ id: summaryToolCallId,
11408
+ pass: passNumber,
11409
+ ...trigger ? { trigger } : {}
11410
+ };
11390
11411
  const startTime = Date.now();
11391
11412
  try {
11392
11413
  if (!model || typeof model.invoke !== "function") {
11393
11414
  throw new Error("Summarization model is unavailable.");
11394
11415
  }
11416
+ events.started = passIdentity;
11417
+ try {
11418
+ onEvent?.({ type: "summarization", phase: "start", ...passIdentity, summary: "" });
11419
+ } catch {
11420
+ }
11395
11421
  const langchainRunOptions = model?._lc ? { runName: "summarize_context", tags: ["cognipeer:summarization"], metadata: { cognipeer_event: "summarization" } } : void 0;
11396
11422
  const response = langchainRunOptions ? await model.invoke(summaryPrompt, langchainRunOptions) : await model.invoke(summaryPrompt);
11397
11423
  durationMs = Date.now() - startTime;
@@ -11433,24 +11459,9 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
11433
11459
  structuredSummary = groundDirectives(structuredSummary);
11434
11460
  integrity = noteDroppedDirectives({ passed: true, criticalFactLoss: false, obsoleteFactRevived: false, notes: ["Fallback summary generated locally."] });
11435
11461
  summaryText = renderStructuredSummary(structuredSummary);
11436
- const errorEvent = {
11437
- type: "summarization",
11438
- summary: summaryText,
11439
- messagesCompressed: compressableMessages.length,
11440
- inputTokens: inputTokensEstimate,
11441
- outputTokens: countApproxTokens(summaryText),
11442
- durationMs,
11443
- previousSummary: previousSummary || void 0,
11444
- tokenCountBefore,
11445
- tokenCountAfter: tokenCountBefore,
11446
- structuredSummary,
11447
- integrity,
11448
- ...modelName ? { model: modelName } : {},
11449
- ...droppedDirectives.length > 0 ? { droppedDirectives } : {}
11450
- };
11451
- onEvent?.(errorEvent);
11452
11462
  summarizerError = traceErrorOf(err);
11453
11463
  }
11464
+ const eventError = eventErrorText(summarizerError?.message);
11454
11465
  const toolCallIdToAssistantIdx = /* @__PURE__ */ new Map();
11455
11466
  messages.forEach((m, idx) => {
11456
11467
  if (m.role === "assistant" && m.tool_calls && Array.isArray(m.tool_calls)) {
@@ -11542,10 +11553,19 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
11542
11553
  (m) => m.role === "tool" && isSummarizedToolPlaceholder(m.content) && !messages.some((orig) => orig.tool_call_id === m.tool_call_id && isSummarizedToolPlaceholder(orig.content))
11543
11554
  );
11544
11555
  if (actuallyCompressed.length === 0) {
11556
+ if (events.started) {
11557
+ events.ended = true;
11558
+ onEvent?.({
11559
+ type: "summarization",
11560
+ phase: "skipped",
11561
+ ...passIdentity,
11562
+ summary: "",
11563
+ ...fallback ? { status: "fallback", ...eventError ? { error: eventError } : {} } : {}
11564
+ });
11565
+ }
11545
11566
  return {};
11546
11567
  }
11547
11568
  const validatedMessages = validateMessageSequence(newMessages);
11548
- const summaryToolCallId = `call_summary_${Date.now()}`;
11549
11569
  const assistantSummaryCall = {
11550
11570
  role: "assistant",
11551
11571
  // "assistant"
@@ -11574,6 +11594,11 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
11574
11594
  const tokenCountAfter = countMessagesTokens(finalMessages);
11575
11595
  const summarizationEvent = {
11576
11596
  type: "summarization",
11597
+ phase: "done",
11598
+ ...passIdentity,
11599
+ status: fallback ? "fallback" : "ok",
11600
+ ...fallback && eventError ? { error: eventError } : {},
11601
+ compactedTools: actuallyCompressed.filter((m) => typeof m.tool_call_id === "string" && m.tool_call_id).map((m) => ({ toolCallId: m.tool_call_id, toolName: m.name || "" })),
11577
11602
  summary: summaryText,
11578
11603
  messagesCompressed: compressableMessages.length,
11579
11604
  inputTokens: inputTokensActual ?? inputTokensEstimate,
@@ -11591,6 +11616,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
11591
11616
  ...modelName ? { model: modelName } : {},
11592
11617
  ...droppedDirectives.length > 0 ? { droppedDirectives } : {}
11593
11618
  };
11619
+ events.ended = true;
11594
11620
  onEvent?.(summarizationEvent);
11595
11621
  traceSummarization({
11596
11622
  type: "summarization",
@@ -11653,6 +11679,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
11653
11679
  fallback
11654
11680
  }
11655
11681
  });
11682
+ const { [SUMMARIZATION_TRIGGER_KEY]: _passTrigger, ...carriedCtx } = ctxWithDeferredTrace ?? state.ctx ?? {};
11656
11683
  return {
11657
11684
  messages: finalMessages,
11658
11685
  summaries,
@@ -11662,7 +11689,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
11662
11689
  // held for the next leg. The smart driver merges ctx and removes the
11663
11690
  // call record once the hook has seen it.
11664
11691
  ctx: {
11665
- ...ctxWithDeferredTrace ?? state.ctx ?? {},
11692
+ ...carriedCtx,
11666
11693
  [LAST_SUMMARIZATION_CALL_KEY]: {
11667
11694
  ...modelName ? { model: modelName } : {},
11668
11695
  durationMs,
@@ -11680,6 +11707,30 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
11680
11707
  }
11681
11708
  };
11682
11709
  };
11710
+ return async (state) => {
11711
+ const events = {};
11712
+ try {
11713
+ return await summarizePass(state, events);
11714
+ } catch (err) {
11715
+ if (events.started && !events.ended) {
11716
+ events.ended = true;
11717
+ const onEvent = state.ctx?.__onEvent;
11718
+ const error = eventErrorText(traceErrorOf(err).message);
11719
+ try {
11720
+ onEvent?.({
11721
+ type: "summarization",
11722
+ phase: "skipped",
11723
+ ...events.started,
11724
+ summary: "",
11725
+ status: "error",
11726
+ ...error ? { error } : {}
11727
+ });
11728
+ } catch {
11729
+ }
11730
+ }
11731
+ throw err;
11732
+ }
11733
+ };
11683
11734
  }
11684
11735
 
11685
11736
  // src/index.ts
@@ -11848,9 +11899,10 @@ function createPlanTool(stateRef, toolName, description) {
11848
11899
  expectedVersion: zod.z.number().int().min(0).optional(),
11849
11900
  todoList: zod.z.array(todoItemWireSchema).optional()
11850
11901
  }),
11851
- func: async ({ operation, expectedVersion, todoList }) => {
11902
+ func: async ({ operation, expectedVersion, todoList }, context) => {
11852
11903
  const toolStateRef = manageTodo._stateRef;
11853
11904
  const onEvent = toolStateRef?.__onEvent;
11905
+ const toolCallId = context?.toolCallId || toolStateRef?.__currentToolCallId || void 0;
11854
11906
  const emitPlanEvent = (list) => {
11855
11907
  const version = stateRef.planVersion || 1;
11856
11908
  const adherenceScore = stateRef.adherenceScore || 0;
@@ -11859,7 +11911,8 @@ function createPlanTool(stateRef, toolName, description) {
11859
11911
  operation,
11860
11912
  version,
11861
11913
  adherenceScore,
11862
- count: Array.isArray(list) ? list.length : 0
11914
+ count: Array.isArray(list) ? list.length : 0,
11915
+ ...toolCallId ? { toolCallId } : {}
11863
11916
  };
11864
11917
  onEvent?.({ type: "plan", todoList: list, ...planData });
11865
11918
  const traceSession = toolStateRef?.ctx?.__traceSession;
@@ -12771,14 +12824,16 @@ async function runChild(spec, input, deps, ref, opts) {
12771
12824
  const traceScope = traced ? createSubagentTraceScope(parentSession, { agentSpanId, name: spec.name, spawnId, mode: spec.mode, hitl: opts.allowHITL, iterations: opts.record?.iterations }) : void 0;
12772
12825
  const recordSegment = (status, info) => {
12773
12826
  if (!traced || !isTraceSessionOpen(parentSession)) return;
12827
+ const unfinished = status === "pending" || status === "running";
12774
12828
  recordSubagentSpan(parentSession, {
12775
12829
  spanId: agentSpanId,
12776
- // The tool_call span only exists once the tool returns; a paused child
12777
- // has not returned, so its span hangs off the iteration.
12778
- parentSpanId: status === "pending" ? parentIterationSpanId : opts.parentSpanId ?? parentIterationSpanId,
12830
+ // The tool_call span only exists once the tool returns; a running or
12831
+ // paused child has not returned, so its span hangs off the iteration.
12832
+ parentSpanId: unfinished ? parentIterationSpanId : opts.parentSpanId ?? parentIterationSpanId,
12779
12833
  name: spec.name,
12780
12834
  status,
12781
- durationMs: elapsedMs(),
12835
+ // A starting segment has no extent yet; a reader draws it over its children.
12836
+ durationMs: status === "running" ? void 0 : elapsedMs(),
12782
12837
  error: info.error,
12783
12838
  info: {
12784
12839
  id: spawnId,
@@ -12789,7 +12844,7 @@ async function runChild(spec, input, deps, ref, opts) {
12789
12844
  parentToolCallId: opts.parentToolCallId,
12790
12845
  status: info.subagentStatus,
12791
12846
  // Only a run that paused has more than one segment to tell about.
12792
- ...segment > 1 || status === "pending" ? { segments: segment } : {},
12847
+ ...segment > 1 || unfinished ? { segments: segment } : {},
12793
12848
  ...info.note ? { note: info.note } : {},
12794
12849
  ...spec.metadata ? { metadata: spec.metadata } : {}
12795
12850
  },
@@ -12913,6 +12968,7 @@ async function runChild(spec, input, deps, ref, opts) {
12913
12968
  }
12914
12969
  if (traceScope) childInput = { ...childInput, ctx: { ...childInput.ctx || {}, __traceSession: traceScope } };
12915
12970
  const usageBaseline = childInput.usage?.perRequest?.length ?? 0;
12971
+ recordSegment("running", { subagentStatus: "running", input });
12916
12972
  let res;
12917
12973
  try {
12918
12974
  res = await child.invoke(childInput, childConfig);
@@ -13517,7 +13573,7 @@ ${pluginAppend}`;
13517
13573
  const toolCalls = Array.isArray(lastAssistant.tool_calls) ? lastAssistant.tool_calls : [];
13518
13574
  return toolCalls.length === 0;
13519
13575
  }
13520
- async function trySummarize(currentState, currentRawMessages, ref) {
13576
+ async function trySummarize(currentState, currentRawMessages, ref, trigger) {
13521
13577
  if (!summarizer) return { state: currentState, rawMessages: currentRawMessages, compressed: false };
13522
13578
  const compactHost = currentState.ctx?.__plugins;
13523
13579
  const tokensBefore = countMessagesTokens(currentState.messages || []);
@@ -13537,7 +13593,9 @@ ${pluginAppend}`;
13537
13593
  return { state: { ...currentState, ctx: ctx2 }, rawMessages: currentRawMessages, compressed: false };
13538
13594
  }
13539
13595
  }
13540
- const delta = await summarizer(currentState);
13596
+ const nodeState = { ...currentState, ctx: { ...currentState.ctx || {}, [SUMMARIZATION_TRIGGER_KEY]: trigger } };
13597
+ const delta = await summarizer(nodeState);
13598
+ if (nodeState.usage !== currentState.usage) currentState.usage = nodeState.usage;
13541
13599
  if (!delta || Object.keys(delta).length === 0) {
13542
13600
  const ctx2 = {
13543
13601
  ...currentState.ctx || {},
@@ -13549,6 +13607,7 @@ ${pluginAppend}`;
13549
13607
  const ctx = { ...currentState.ctx || {}, ...delta.ctx || {} };
13550
13608
  const summarizationCall = ctx[LAST_SUMMARIZATION_CALL_KEY];
13551
13609
  delete ctx[LAST_SUMMARIZATION_CALL_KEY];
13610
+ delete ctx[SUMMARIZATION_TRIGGER_KEY];
13552
13611
  delete ctx.__summarizationExhausted;
13553
13612
  delete ctx.__summarizationExhaustedAtToolCount;
13554
13613
  const updated = await persistLatestSummary(syncPlanStateWith(ref, { ...currentState, ...delta, ctx }));
@@ -13772,7 +13831,7 @@ ${pluginAppend}`;
13772
13831
  state = syncRuntimeTools({ ...state, messages: rawMessages }, rawMessages, toolSet);
13773
13832
  const next = summarizationEnabled ? decideBefore(state) : "agent";
13774
13833
  if (next === "contextSummarize" && summarizer) {
13775
- const result = await trySummarize(state, rawMessages, stateRef);
13834
+ const result = await trySummarize(state, rawMessages, stateRef, "pre_leg");
13776
13835
  state = result.state;
13777
13836
  rawMessages = result.rawMessages;
13778
13837
  noteTraceHandoff(state);
@@ -13807,7 +13866,7 @@ ${pluginAppend}`;
13807
13866
  const ctx = { ...state.ctx || {} };
13808
13867
  delete ctx.__needsSummarization;
13809
13868
  state = { ...state, ctx };
13810
- const result = await trySummarize(state, rawMessages, stateRef);
13869
+ const result = await trySummarize(state, rawMessages, stateRef, "mid_leg");
13811
13870
  state = result.state;
13812
13871
  rawMessages = result.rawMessages;
13813
13872
  noteTraceHandoff(state);
@@ -13819,7 +13878,7 @@ ${pluginAppend}`;
13819
13878
  if (summarizationEnabled) {
13820
13879
  const after = decideAfter(state);
13821
13880
  if (after === "contextSummarize" && summarizer) {
13822
- const result = await trySummarize(state, rawMessages, stateRef);
13881
+ const result = await trySummarize(state, rawMessages, stateRef, "post_tools");
13823
13882
  state = result.state;
13824
13883
  rawMessages = result.rawMessages;
13825
13884
  noteTraceHandoff(state);
@@ -22070,6 +22129,7 @@ exports.OpenAIProvider = OpenAIProvider;
22070
22129
  exports.PREOPEN_TOOL_CALL_PREFIX = PREOPEN_TOOL_CALL_PREFIX;
22071
22130
  exports.ProviderError = ProviderError;
22072
22131
  exports.SMALL_TIER_SKILL_POLICY = SMALL_TIER_SKILL_POLICY;
22132
+ exports.SUMMARIZATION_TRIGGER_KEY = SUMMARIZATION_TRIGGER_KEY;
22073
22133
  exports.StructuredOutputManager = StructuredOutputManager;
22074
22134
  exports.TOOL_INPUT_DIGEST_KEY = TOOL_INPUT_DIGEST_KEY;
22075
22135
  exports.ToolBasedStrategy = ToolBasedStrategy;