@agent-inspect/langchain 1.1.0 → 1.4.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
@@ -147,6 +147,68 @@ function toPlainMetadata(value) {
147
147
  return {};
148
148
  }
149
149
  }
150
+
151
+ // packages/langchain/src/streaming-metadata.ts
152
+ function createLlmStreamState() {
153
+ return {
154
+ chunkCount: 0,
155
+ streamedCharCount: 0,
156
+ previewChars: "",
157
+ previewTruncated: false
158
+ };
159
+ }
160
+ function recordLlmStreamToken(state, token, now, maxPreviewChars) {
161
+ state.chunkCount += 1;
162
+ if (state.firstChunkAt === void 0) {
163
+ state.firstChunkAt = now;
164
+ }
165
+ state.lastChunkAt = now;
166
+ if (typeof token === "string" && token.length > 0) {
167
+ state.streamedCharCount += token.length;
168
+ if (maxPreviewChars > 0) {
169
+ const remaining = maxPreviewChars - state.previewChars.length;
170
+ if (remaining > 0) {
171
+ const slice = token.slice(0, remaining);
172
+ state.previewChars += slice;
173
+ if (token.length > remaining) {
174
+ state.previewTruncated = true;
175
+ }
176
+ } else {
177
+ state.previewTruncated = true;
178
+ }
179
+ }
180
+ }
181
+ }
182
+ function streamMetadataFromState(state, options) {
183
+ if (!state || state.chunkCount === 0) {
184
+ return void 0;
185
+ }
186
+ const out = {
187
+ stream: true,
188
+ chunkCount: state.chunkCount,
189
+ streamedCharCount: state.streamedCharCount
190
+ };
191
+ if (state.firstChunkAt !== void 0) {
192
+ out.firstChunkAt = state.firstChunkAt;
193
+ }
194
+ if (state.lastChunkAt !== void 0) {
195
+ out.lastChunkAt = state.lastChunkAt;
196
+ }
197
+ if (state.firstChunkAt !== void 0 && state.lastChunkAt !== void 0 && state.lastChunkAt >= state.firstChunkAt) {
198
+ out.streamDurationMs = state.lastChunkAt - state.firstChunkAt;
199
+ }
200
+ if (state.previewTruncated) {
201
+ out.previewTruncated = true;
202
+ }
203
+ if (options.capturePreview && state.previewChars.length > 0) {
204
+ const preview = state.previewChars.length <= options.maxPreviewChars ? state.previewChars : `${state.previewChars.slice(0, options.maxPreviewChars)}\u2026`;
205
+ out.streamPreview = preview;
206
+ if (state.previewChars.length > options.maxPreviewChars) {
207
+ out.previewTruncated = true;
208
+ }
209
+ }
210
+ return out;
211
+ }
150
212
  function kindToStepType(kind) {
151
213
  switch (kind) {
152
214
  case "LLM":
@@ -243,7 +305,28 @@ var LangChainTracePersistence = class {
243
305
  }
244
306
  async onStepEnd(params) {
245
307
  try {
246
- const stepId = this.#lcToStepId.get(params.lcRunId);
308
+ let stepId = this.#lcToStepId.get(params.lcRunId);
309
+ if (!stepId && params.completionAttributes) {
310
+ stepId = agentInspect.createStepId();
311
+ this.#lcToStepId.set(params.lcRunId, stepId);
312
+ const parentId = this.resolveParentId(params.lcParentRunId);
313
+ const startTime = params.endTime - (params.durationMs ?? 0);
314
+ const started = {
315
+ schemaVersion: "0.1",
316
+ event: "step_started",
317
+ timestamp: startTime,
318
+ runId: this.#runId,
319
+ stepId,
320
+ ...parentId ? { parentId } : {},
321
+ name: String(params.completionAttributes.name ?? "llm:llm"),
322
+ type: kindToStepType(
323
+ params.completionAttributes.kind ?? "LLM"
324
+ ),
325
+ startTime,
326
+ metadata: toStepMetadata(params.completionAttributes)
327
+ };
328
+ await this.#write(started);
329
+ }
247
330
  if (!stepId) return;
248
331
  const durationMs = typeof params.durationMs === "number" && Number.isFinite(params.durationMs) ? Math.max(0, Math.floor(params.durationMs)) : Math.max(0, params.endTime - (this.#runStartTime ?? params.endTime));
249
332
  const event = {
@@ -378,6 +461,8 @@ var AgentInspectCallback = class extends base.BaseCallbackHandler {
378
461
  #persistence;
379
462
  #events = [];
380
463
  #starts = /* @__PURE__ */ new Map();
464
+ #streamState = /* @__PURE__ */ new Map();
465
+ #deferredPersistStart = /* @__PURE__ */ new Map();
381
466
  #rootRunId;
382
467
  constructor(options = {}) {
383
468
  super({});
@@ -411,9 +496,71 @@ var AgentInspectCallback = class extends base.BaseCallbackHandler {
411
496
  clear() {
412
497
  this.#events = [];
413
498
  this.#starts.clear();
499
+ this.#streamState.clear();
500
+ this.#deferredPersistStart.clear();
414
501
  this.#rootRunId = void 0;
415
502
  this.#persistence?.reset();
416
503
  }
504
+ #streamPreviewLimit() {
505
+ if (this.#opts.capture !== "preview") return 0;
506
+ return this.#opts.maxStreamPreviewChars ?? this.#opts.maxPreviewChars ?? 200;
507
+ }
508
+ #attachStreamMetadata(attrs, lcRunId) {
509
+ const meta = streamMetadataFromState(this.#streamState.get(lcRunId), {
510
+ capturePreview: this.#opts.capture === "preview",
511
+ maxPreviewChars: this.#streamPreviewLimit()
512
+ });
513
+ if (meta) {
514
+ Object.assign(attrs, meta);
515
+ }
516
+ }
517
+ #clearStreamState(lcRunId) {
518
+ this.#streamState.delete(lcRunId);
519
+ this.#deferredPersistStart.delete(lcRunId);
520
+ }
521
+ #mergeCorrelation(attrs) {
522
+ if (this.#opts.capture === "none") return;
523
+ try {
524
+ const corr = agentInspect.getCurrentCorrelationMetadata();
525
+ if (!corr) return;
526
+ for (const [key, value] of Object.entries(corr)) {
527
+ if (typeof value === "string" && value.length > 0) {
528
+ attrs[key] = value;
529
+ }
530
+ }
531
+ } catch {
532
+ }
533
+ }
534
+ async #persistLlmStepStart(lcRunId, lcParentRunId, name, kind, startTime, attributes) {
535
+ if (this.#opts.stream && this.#opts.persist) {
536
+ this.#deferredPersistStart.set(lcRunId, {
537
+ lcParentRunId,
538
+ name,
539
+ kind,
540
+ startTime,
541
+ attributes: { ...attributes }
542
+ });
543
+ return;
544
+ }
545
+ await this.#persistStepStart(lcRunId, lcParentRunId, name, kind, attributes, startTime);
546
+ }
547
+ async #flushDeferredPersistStart(lcRunId, completionAttributes) {
548
+ const pending = this.#deferredPersistStart.get(lcRunId);
549
+ if (!pending || !this.#opts.persist) return;
550
+ const merged = {
551
+ ...pending.attributes,
552
+ ...completionAttributes
553
+ };
554
+ await this.#persistStepStart(
555
+ lcRunId,
556
+ pending.lcParentRunId,
557
+ pending.name,
558
+ pending.kind,
559
+ merged,
560
+ pending.startTime
561
+ );
562
+ this.#deferredPersistStart.delete(lcRunId);
563
+ }
417
564
  #ensureRoot(lcRunId, parentRunId) {
418
565
  if (parentRunId) return;
419
566
  if (!this.#rootRunId) this.#rootRunId = lcRunId;
@@ -476,14 +623,15 @@ var AgentInspectCallback = class extends base.BaseCallbackHandler {
476
623
  attributes: attrs
477
624
  });
478
625
  }
479
- async #persistStepEnd(lcRunId, lcParentRunId, status, endTime, durationMs, errorMessage) {
626
+ async #persistStepEnd(lcRunId, lcParentRunId, status, endTime, durationMs, errorMessage, completionAttributes) {
480
627
  await this.#persistence?.onStepEnd({
481
628
  lcRunId,
482
629
  lcParentRunId,
483
630
  endTime,
484
631
  durationMs,
485
632
  status,
486
- errorMessage
633
+ errorMessage,
634
+ completionAttributes
487
635
  });
488
636
  }
489
637
  async #persistInstant(lcRunId, lcParentRunId, name, kind, attrs, status, errorMessage) {
@@ -589,6 +737,7 @@ var AgentInspectCallback = class extends base.BaseCallbackHandler {
589
737
  };
590
738
  if (model && this.#opts.capture !== "none") attrs.model = model;
591
739
  this.#mergeMetadata(attrs, metadata);
740
+ this.#mergeCorrelation(attrs);
592
741
  this.#applyPreview(attrs, previews);
593
742
  const ts = Date.now();
594
743
  const stepName = `llm:${model ?? "llm"}`;
@@ -604,7 +753,7 @@ var AgentInspectCallback = class extends base.BaseCallbackHandler {
604
753
  confidence: "explicit",
605
754
  source: { type: "adapter" }
606
755
  });
607
- await this.#persistStepStart(runId, parentRunId, stepName, "LLM", attrs, ts);
756
+ await this.#persistLlmStepStart(runId, parentRunId, stepName, "LLM", ts, attrs);
608
757
  }
609
758
  async handleChatModelStart(llm, messages, runId, parentRunId, _extraParams, tags, metadata, runName) {
610
759
  this.#ensureRoot(runId, parentRunId);
@@ -617,6 +766,7 @@ var AgentInspectCallback = class extends base.BaseCallbackHandler {
617
766
  };
618
767
  if (model && this.#opts.capture !== "none") attrs.model = model;
619
768
  this.#mergeMetadata(attrs, metadata);
769
+ this.#mergeCorrelation(attrs);
620
770
  this.#applyPreview(attrs, previews);
621
771
  const ts = Date.now();
622
772
  const stepName = `llm:${model ?? "llm"}`;
@@ -632,7 +782,22 @@ var AgentInspectCallback = class extends base.BaseCallbackHandler {
632
782
  confidence: "explicit",
633
783
  source: { type: "adapter" }
634
784
  });
635
- await this.#persistStepStart(runId, parentRunId, stepName, "LLM", attrs, ts);
785
+ await this.#persistLlmStepStart(runId, parentRunId, stepName, "LLM", ts, attrs);
786
+ }
787
+ handleLLMNewToken(token, _idx, runId, _parentRunId, _tags, _fields) {
788
+ try {
789
+ if (!this.#opts.stream) return;
790
+ let state = this.#streamState.get(runId);
791
+ if (!state) {
792
+ state = createLlmStreamState();
793
+ this.#streamState.set(runId, state);
794
+ }
795
+ recordLlmStreamToken(state, token, Date.now(), this.#streamPreviewLimit());
796
+ } catch (err) {
797
+ if (!this.#opts.silent) {
798
+ console.error("[agent-inspect:langchain]", err);
799
+ }
800
+ }
636
801
  }
637
802
  async handleLLMEnd(output, runId, parentRunId, tags, _extraParams) {
638
803
  this.#ensureRoot(runId, parentRunId);
@@ -647,6 +812,8 @@ var AgentInspectCallback = class extends base.BaseCallbackHandler {
647
812
  };
648
813
  if (model && this.#opts.capture !== "none") attrs.model = model;
649
814
  if (tokens && this.#opts.capture !== "none") attrs.tokens = tokens;
815
+ this.#attachStreamMetadata(attrs, runId);
816
+ this.#mergeCorrelation(attrs);
650
817
  this.#applyPreview(attrs, previews);
651
818
  const ts = Date.now();
652
819
  this.#pushEvent({
@@ -662,7 +829,13 @@ var AgentInspectCallback = class extends base.BaseCallbackHandler {
662
829
  confidence: "explicit",
663
830
  source: { type: "adapter" }
664
831
  });
665
- await this.#persistStepEnd(runId, parentRunId, "success", ts, durationMs);
832
+ await this.#flushDeferredPersistStart(runId, attrs);
833
+ await this.#persistStepEnd(runId, parentRunId, "success", ts, durationMs, void 0, {
834
+ ...attrs,
835
+ name: `llm:${model ?? "llm"}`,
836
+ kind: "LLM"
837
+ });
838
+ this.#clearStreamState(runId);
666
839
  }
667
840
  async handleLLMError(err, runId, parentRunId, tags, _extraParams) {
668
841
  this.#ensureRoot(runId, parentRunId);
@@ -674,6 +847,8 @@ var AgentInspectCallback = class extends base.BaseCallbackHandler {
674
847
  errorName,
675
848
  errorMessage
676
849
  };
850
+ this.#attachStreamMetadata(attrs, runId);
851
+ this.#mergeCorrelation(attrs);
677
852
  const ts = Date.now();
678
853
  this.#pushEvent({
679
854
  eventId: `${runId}:LLM:error`,
@@ -688,7 +863,13 @@ var AgentInspectCallback = class extends base.BaseCallbackHandler {
688
863
  confidence: "explicit",
689
864
  source: { type: "adapter" }
690
865
  });
691
- await this.#persistStepEnd(runId, parentRunId, "error", ts, durationMs, errorMessage);
866
+ await this.#flushDeferredPersistStart(runId, attrs);
867
+ await this.#persistStepEnd(runId, parentRunId, "error", ts, durationMs, errorMessage, {
868
+ ...attrs,
869
+ name: "llm:error",
870
+ kind: "LLM"
871
+ });
872
+ this.#clearStreamState(runId);
692
873
  }
693
874
  async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName, _toolCallId) {
694
875
  this.#ensureRoot(runId, parentRunId);