@agent-inspect/langchain 1.0.3 → 1.3.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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
2
- import { Redactor } from 'agent-inspect';
2
+ import { Redactor, getCurrentCorrelationMetadata, hasActiveContext, getTraceDirFromContext, resolveTraceDir, getCurrentRunId, createRunId, resolveTraceSafetyOptions, createStepId, initializeTraceFile, prepareTraceEventForDisk, writeTraceEvent } from 'agent-inspect';
3
3
 
4
4
  // packages/langchain/src/agent-inspect-callback.ts
5
5
 
@@ -146,6 +146,300 @@ function toPlainMetadata(value) {
146
146
  }
147
147
  }
148
148
 
149
+ // packages/langchain/src/streaming-metadata.ts
150
+ function createLlmStreamState() {
151
+ return {
152
+ chunkCount: 0,
153
+ streamedCharCount: 0,
154
+ previewChars: "",
155
+ previewTruncated: false
156
+ };
157
+ }
158
+ function recordLlmStreamToken(state, token, now, maxPreviewChars) {
159
+ state.chunkCount += 1;
160
+ if (state.firstChunkAt === void 0) {
161
+ state.firstChunkAt = now;
162
+ }
163
+ state.lastChunkAt = now;
164
+ if (typeof token === "string" && token.length > 0) {
165
+ state.streamedCharCount += token.length;
166
+ if (maxPreviewChars > 0) {
167
+ const remaining = maxPreviewChars - state.previewChars.length;
168
+ if (remaining > 0) {
169
+ const slice = token.slice(0, remaining);
170
+ state.previewChars += slice;
171
+ if (token.length > remaining) {
172
+ state.previewTruncated = true;
173
+ }
174
+ } else {
175
+ state.previewTruncated = true;
176
+ }
177
+ }
178
+ }
179
+ }
180
+ function streamMetadataFromState(state, options) {
181
+ if (!state || state.chunkCount === 0) {
182
+ return void 0;
183
+ }
184
+ const out = {
185
+ stream: true,
186
+ chunkCount: state.chunkCount,
187
+ streamedCharCount: state.streamedCharCount
188
+ };
189
+ if (state.firstChunkAt !== void 0) {
190
+ out.firstChunkAt = state.firstChunkAt;
191
+ }
192
+ if (state.lastChunkAt !== void 0) {
193
+ out.lastChunkAt = state.lastChunkAt;
194
+ }
195
+ if (state.firstChunkAt !== void 0 && state.lastChunkAt !== void 0 && state.lastChunkAt >= state.firstChunkAt) {
196
+ out.streamDurationMs = state.lastChunkAt - state.firstChunkAt;
197
+ }
198
+ if (state.previewTruncated) {
199
+ out.previewTruncated = true;
200
+ }
201
+ if (options.capturePreview && state.previewChars.length > 0) {
202
+ const preview = state.previewChars.length <= options.maxPreviewChars ? state.previewChars : `${state.previewChars.slice(0, options.maxPreviewChars)}\u2026`;
203
+ out.streamPreview = preview;
204
+ if (state.previewChars.length > options.maxPreviewChars) {
205
+ out.previewTruncated = true;
206
+ }
207
+ }
208
+ return out;
209
+ }
210
+ function kindToStepType(kind) {
211
+ switch (kind) {
212
+ case "LLM":
213
+ return "llm";
214
+ case "TOOL":
215
+ return "tool";
216
+ case "DECISION":
217
+ return "decision";
218
+ default:
219
+ return "logic";
220
+ }
221
+ }
222
+ function toStepMetadata(attrs) {
223
+ const out = {
224
+ adapter: "langchain",
225
+ confidence: "explicit"
226
+ };
227
+ for (const [k, v] of Object.entries(attrs)) {
228
+ out[k] = v;
229
+ }
230
+ return out;
231
+ }
232
+ var LangChainTracePersistence = class {
233
+ #traceDir;
234
+ #runId;
235
+ #runName;
236
+ #standalone;
237
+ #silent;
238
+ #safety;
239
+ #runStarted = false;
240
+ #runCompleted = false;
241
+ #runStartTime;
242
+ #rootLcRunId;
243
+ #lcToStepId = /* @__PURE__ */ new Map();
244
+ constructor(options = {}) {
245
+ const inContext = hasActiveContext();
246
+ this.#standalone = !inContext;
247
+ this.#silent = options.silent ?? false;
248
+ this.#traceDir = inContext ? getTraceDirFromContext() ?? resolveTraceDir({ dir: options.traceDir }) : resolveTraceDir({ dir: options.traceDir });
249
+ this.#runId = (inContext ? getCurrentRunId() : void 0) ?? options.runId ?? createRunId();
250
+ this.#runName = options.runName ?? "langchain-agent";
251
+ this.#safety = resolveTraceSafetyOptions({
252
+ redact: options.redact ? { rules: options.redact } : true,
253
+ maxPreviewLength: options.maxPreviewChars
254
+ });
255
+ }
256
+ get runId() {
257
+ return this.#runId;
258
+ }
259
+ get traceDir() {
260
+ return this.#traceDir;
261
+ }
262
+ reset() {
263
+ this.#runStarted = false;
264
+ this.#runCompleted = false;
265
+ this.#runStartTime = void 0;
266
+ this.#rootLcRunId = void 0;
267
+ this.#lcToStepId.clear();
268
+ }
269
+ noteRoot(lcRunId, parentRunId) {
270
+ if (!parentRunId && !this.#rootLcRunId) {
271
+ this.#rootLcRunId = lcRunId;
272
+ }
273
+ }
274
+ resolveParentId(lcParentRunId) {
275
+ if (!lcParentRunId) return void 0;
276
+ return this.#lcToStepId.get(lcParentRunId);
277
+ }
278
+ async onStepStart(params) {
279
+ try {
280
+ this.noteRoot(params.lcRunId, params.lcParentRunId);
281
+ if (this.#standalone && !this.#runStarted) {
282
+ await this.#ensureRunStarted(params.startTime, params.attributes);
283
+ }
284
+ const stepId = createStepId();
285
+ this.#lcToStepId.set(params.lcRunId, stepId);
286
+ const parentId = this.resolveParentId(params.lcParentRunId);
287
+ const event = {
288
+ schemaVersion: "0.1",
289
+ event: "step_started",
290
+ timestamp: params.startTime,
291
+ runId: this.#runId,
292
+ stepId,
293
+ ...parentId ? { parentId } : {},
294
+ name: params.name,
295
+ type: kindToStepType(params.kind),
296
+ startTime: params.startTime,
297
+ metadata: toStepMetadata(params.attributes)
298
+ };
299
+ await this.#write(event);
300
+ } catch (err) {
301
+ this.#warn(err);
302
+ }
303
+ }
304
+ async onStepEnd(params) {
305
+ try {
306
+ let stepId = this.#lcToStepId.get(params.lcRunId);
307
+ if (!stepId && params.completionAttributes) {
308
+ stepId = createStepId();
309
+ this.#lcToStepId.set(params.lcRunId, stepId);
310
+ const parentId = this.resolveParentId(params.lcParentRunId);
311
+ const startTime = params.endTime - (params.durationMs ?? 0);
312
+ const started = {
313
+ schemaVersion: "0.1",
314
+ event: "step_started",
315
+ timestamp: startTime,
316
+ runId: this.#runId,
317
+ stepId,
318
+ ...parentId ? { parentId } : {},
319
+ name: String(params.completionAttributes.name ?? "llm:llm"),
320
+ type: kindToStepType(
321
+ params.completionAttributes.kind ?? "LLM"
322
+ ),
323
+ startTime,
324
+ metadata: toStepMetadata(params.completionAttributes)
325
+ };
326
+ await this.#write(started);
327
+ }
328
+ if (!stepId) return;
329
+ 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));
330
+ const event = {
331
+ schemaVersion: "0.1",
332
+ event: "step_completed",
333
+ timestamp: params.endTime,
334
+ runId: this.#runId,
335
+ stepId,
336
+ status: params.status,
337
+ endTime: params.endTime,
338
+ durationMs,
339
+ ...params.status === "error" && params.errorMessage ? { error: { message: params.errorMessage } } : {}
340
+ };
341
+ await this.#write(event);
342
+ if (this.#standalone && !this.#runCompleted && this.#rootLcRunId === params.lcRunId && !params.lcParentRunId) {
343
+ await this.#ensureRunCompleted(
344
+ params.endTime,
345
+ params.status,
346
+ params.errorMessage
347
+ );
348
+ }
349
+ } catch (err) {
350
+ this.#warn(err);
351
+ }
352
+ }
353
+ /** Point-in-time adapter events (e.g. agent action) — writes start + completed pair. */
354
+ async onInstantStep(params) {
355
+ try {
356
+ this.noteRoot(params.lcRunId, params.lcParentRunId);
357
+ if (this.#standalone && !this.#runStarted) {
358
+ await this.#ensureRunStarted(params.timestamp, params.attributes);
359
+ }
360
+ const stepId = createStepId();
361
+ this.#lcToStepId.set(params.lcRunId, stepId);
362
+ const parentId = this.resolveParentId(params.lcParentRunId);
363
+ const started = {
364
+ schemaVersion: "0.1",
365
+ event: "step_started",
366
+ timestamp: params.timestamp,
367
+ runId: this.#runId,
368
+ stepId,
369
+ ...parentId ? { parentId } : {},
370
+ name: params.name,
371
+ type: kindToStepType(params.kind),
372
+ startTime: params.timestamp,
373
+ metadata: toStepMetadata(params.attributes)
374
+ };
375
+ await this.#write(started);
376
+ const completed = {
377
+ schemaVersion: "0.1",
378
+ event: "step_completed",
379
+ timestamp: params.timestamp,
380
+ runId: this.#runId,
381
+ stepId,
382
+ status: params.status,
383
+ endTime: params.timestamp,
384
+ durationMs: 0,
385
+ ...params.status === "error" && params.errorMessage ? { error: { message: params.errorMessage } } : {}
386
+ };
387
+ await this.#write(completed);
388
+ } catch (err) {
389
+ this.#warn(err);
390
+ }
391
+ }
392
+ async #ensureRunStarted(startTime, attrs) {
393
+ if (this.#runStarted) return;
394
+ this.#runStarted = true;
395
+ this.#runStartTime = startTime;
396
+ await initializeTraceFile(this.#runId, this.#traceDir);
397
+ const metadata = {
398
+ adapter: "langchain",
399
+ confidence: "explicit"
400
+ };
401
+ if (attrs.langchainRunId) metadata.langchainRunId = attrs.langchainRunId;
402
+ if (attrs.adapterRunName) metadata.adapterRunName = attrs.adapterRunName;
403
+ const event = {
404
+ schemaVersion: "0.1",
405
+ event: "run_started",
406
+ timestamp: startTime,
407
+ runId: this.#runId,
408
+ name: this.#runName,
409
+ startTime,
410
+ metadata
411
+ };
412
+ await this.#write(event);
413
+ }
414
+ async #ensureRunCompleted(endTime, stepStatus, errorMessage) {
415
+ if (this.#runCompleted || !this.#runStarted) return;
416
+ this.#runCompleted = true;
417
+ const startTime = this.#runStartTime ?? endTime;
418
+ const durationMs = Math.max(0, endTime - startTime);
419
+ const runStatus = stepStatus === "error" ? "error" : "success";
420
+ const event = {
421
+ schemaVersion: "0.1",
422
+ event: "run_completed",
423
+ timestamp: endTime,
424
+ runId: this.#runId,
425
+ status: runStatus,
426
+ endTime,
427
+ durationMs,
428
+ ...runStatus === "error" && errorMessage ? { error: { message: errorMessage } } : {}
429
+ };
430
+ await this.#write(event);
431
+ }
432
+ async #write(event) {
433
+ const safe = prepareTraceEventForDisk(event, this.#safety);
434
+ await writeTraceEvent(safe, this.#traceDir);
435
+ }
436
+ #warn(err) {
437
+ if (!this.#silent) {
438
+ console.error("[agent-inspect:langchain]", err);
439
+ }
440
+ }
441
+ };
442
+
149
443
  // packages/langchain/src/agent-inspect-callback.ts
150
444
  function serializedLabel(s) {
151
445
  if (typeof s.name === "string" && s.name.trim()) return s.name;
@@ -162,8 +456,11 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
162
456
  name = "agent-inspect";
163
457
  #opts;
164
458
  #redactor;
459
+ #persistence;
165
460
  #events = [];
166
461
  #starts = /* @__PURE__ */ new Map();
462
+ #streamState = /* @__PURE__ */ new Map();
463
+ #deferredPersistStart = /* @__PURE__ */ new Map();
167
464
  #rootRunId;
168
465
  constructor(options = {}) {
169
466
  super({});
@@ -171,9 +468,21 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
171
468
  capture: options.capture ?? "metadata-only",
172
469
  silent: options.silent ?? false,
173
470
  maxPreviewChars: options.maxPreviewChars ?? 200,
471
+ persist: options.persist ?? false,
472
+ runName: options.runName ?? "langchain-agent",
174
473
  ...options
175
474
  };
176
475
  this.#redactor = new Redactor({ rules: this.#opts.redact });
476
+ if (this.#opts.persist) {
477
+ this.#persistence = new LangChainTracePersistence({
478
+ runName: this.#opts.runName,
479
+ traceDir: this.#opts.traceDir,
480
+ runId: this.#opts.runId,
481
+ redact: this.#opts.redact,
482
+ silent: this.#opts.silent,
483
+ maxPreviewChars: this.#opts.maxPreviewChars
484
+ });
485
+ }
177
486
  }
178
487
  getEvents() {
179
488
  return this.#events.map((e) => ({
@@ -185,7 +494,70 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
185
494
  clear() {
186
495
  this.#events = [];
187
496
  this.#starts.clear();
497
+ this.#streamState.clear();
498
+ this.#deferredPersistStart.clear();
188
499
  this.#rootRunId = void 0;
500
+ this.#persistence?.reset();
501
+ }
502
+ #streamPreviewLimit() {
503
+ if (this.#opts.capture !== "preview") return 0;
504
+ return this.#opts.maxStreamPreviewChars ?? this.#opts.maxPreviewChars ?? 200;
505
+ }
506
+ #attachStreamMetadata(attrs, lcRunId) {
507
+ const meta = streamMetadataFromState(this.#streamState.get(lcRunId), {
508
+ capturePreview: this.#opts.capture === "preview",
509
+ maxPreviewChars: this.#streamPreviewLimit()
510
+ });
511
+ if (meta) {
512
+ Object.assign(attrs, meta);
513
+ }
514
+ }
515
+ #clearStreamState(lcRunId) {
516
+ this.#streamState.delete(lcRunId);
517
+ this.#deferredPersistStart.delete(lcRunId);
518
+ }
519
+ #mergeCorrelation(attrs) {
520
+ if (this.#opts.capture === "none") return;
521
+ try {
522
+ const corr = getCurrentCorrelationMetadata();
523
+ if (!corr) return;
524
+ for (const [key, value] of Object.entries(corr)) {
525
+ if (typeof value === "string" && value.length > 0) {
526
+ attrs[key] = value;
527
+ }
528
+ }
529
+ } catch {
530
+ }
531
+ }
532
+ async #persistLlmStepStart(lcRunId, lcParentRunId, name, kind, startTime, attributes) {
533
+ if (this.#opts.stream && this.#opts.persist) {
534
+ this.#deferredPersistStart.set(lcRunId, {
535
+ lcParentRunId,
536
+ name,
537
+ kind,
538
+ startTime,
539
+ attributes: { ...attributes }
540
+ });
541
+ return;
542
+ }
543
+ await this.#persistStepStart(lcRunId, lcParentRunId, name, kind, attributes, startTime);
544
+ }
545
+ async #flushDeferredPersistStart(lcRunId, completionAttributes) {
546
+ const pending = this.#deferredPersistStart.get(lcRunId);
547
+ if (!pending || !this.#opts.persist) return;
548
+ const merged = {
549
+ ...pending.attributes,
550
+ ...completionAttributes
551
+ };
552
+ await this.#persistStepStart(
553
+ lcRunId,
554
+ pending.lcParentRunId,
555
+ pending.name,
556
+ pending.kind,
557
+ merged,
558
+ pending.startTime
559
+ );
560
+ this.#deferredPersistStart.delete(lcRunId);
189
561
  }
190
562
  #ensureRoot(lcRunId, parentRunId) {
191
563
  if (parentRunId) return;
@@ -239,6 +611,39 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
239
611
  }
240
612
  }
241
613
  }
614
+ async #persistStepStart(lcRunId, lcParentRunId, name, kind, attrs, startTime) {
615
+ await this.#persistence?.onStepStart({
616
+ lcRunId,
617
+ lcParentRunId,
618
+ name,
619
+ kind,
620
+ startTime,
621
+ attributes: attrs
622
+ });
623
+ }
624
+ async #persistStepEnd(lcRunId, lcParentRunId, status, endTime, durationMs, errorMessage, completionAttributes) {
625
+ await this.#persistence?.onStepEnd({
626
+ lcRunId,
627
+ lcParentRunId,
628
+ endTime,
629
+ durationMs,
630
+ status,
631
+ errorMessage,
632
+ completionAttributes
633
+ });
634
+ }
635
+ async #persistInstant(lcRunId, lcParentRunId, name, kind, attrs, status, errorMessage) {
636
+ await this.#persistence?.onInstantStep({
637
+ lcRunId,
638
+ lcParentRunId,
639
+ name,
640
+ kind,
641
+ timestamp: Date.now(),
642
+ attributes: attrs,
643
+ status,
644
+ errorMessage
645
+ });
646
+ }
242
647
  async handleChainStart(chain, inputs, runId, runType, tags, metadata, runName, parentRunId, _extra) {
243
648
  this.#ensureRoot(runId, parentRunId);
244
649
  this.#rememberStart(runId, "CHAIN");
@@ -250,18 +655,20 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
250
655
  };
251
656
  this.#mergeMetadata(attrs, metadata);
252
657
  this.#applyPreview(attrs, previews);
658
+ const ts = Date.now();
253
659
  this.#pushEvent({
254
660
  eventId: `${runId}:CHAIN:start`,
255
661
  runId: this.#traceRunId(runId),
256
662
  parentId: parentRunId,
257
663
  name: `chain:${runName ?? label}`,
258
664
  kind: "CHAIN",
259
- timestamp: Date.now(),
665
+ timestamp: ts,
260
666
  status: "running",
261
667
  attributes: attrs,
262
668
  confidence: "explicit",
263
669
  source: { type: "adapter" }
264
670
  });
671
+ await this.#persistStepStart(runId, parentRunId, `chain:${runName ?? label}`, "CHAIN", attrs, ts);
265
672
  }
266
673
  async handleChainEnd(outputs, runId, parentRunId, tags, _kwargs) {
267
674
  this.#ensureRoot(runId, parentRunId);
@@ -273,19 +680,21 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
273
680
  ...this.#baseAttrs(runId, parentRunId, tags, void 0)
274
681
  };
275
682
  this.#applyPreview(attrs, previews);
683
+ const ts = Date.now();
276
684
  this.#pushEvent({
277
685
  eventId: `${runId}:CHAIN:end`,
278
686
  runId: this.#traceRunId(runId),
279
687
  parentId: parentRunId,
280
688
  name: "chain:end",
281
689
  kind: "CHAIN",
282
- timestamp: Date.now(),
690
+ timestamp: ts,
283
691
  status: "ok",
284
692
  durationMs,
285
693
  attributes: attrs,
286
694
  confidence: "explicit",
287
695
  source: { type: "adapter" }
288
696
  });
697
+ await this.#persistStepEnd(runId, parentRunId, "success", ts, durationMs);
289
698
  }
290
699
  async handleChainError(err, runId, parentRunId, tags, _kwargs) {
291
700
  this.#ensureRoot(runId, parentRunId);
@@ -297,19 +706,21 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
297
706
  errorName,
298
707
  errorMessage
299
708
  };
709
+ const ts = Date.now();
300
710
  this.#pushEvent({
301
711
  eventId: `${runId}:CHAIN:error`,
302
712
  runId: this.#traceRunId(runId),
303
713
  parentId: parentRunId,
304
714
  name: "chain:error",
305
715
  kind: "CHAIN",
306
- timestamp: Date.now(),
716
+ timestamp: ts,
307
717
  status: "error",
308
718
  durationMs,
309
719
  attributes: attrs,
310
720
  confidence: "explicit",
311
721
  source: { type: "adapter" }
312
722
  });
723
+ await this.#persistStepEnd(runId, parentRunId, "error", ts, durationMs, errorMessage);
313
724
  }
314
725
  async handleLLMStart(llm, prompts, runId, parentRunId, _extraParams, tags, metadata, runName) {
315
726
  this.#ensureRoot(runId, parentRunId);
@@ -324,19 +735,23 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
324
735
  };
325
736
  if (model && this.#opts.capture !== "none") attrs.model = model;
326
737
  this.#mergeMetadata(attrs, metadata);
738
+ this.#mergeCorrelation(attrs);
327
739
  this.#applyPreview(attrs, previews);
740
+ const ts = Date.now();
741
+ const stepName = `llm:${model ?? "llm"}`;
328
742
  this.#pushEvent({
329
743
  eventId: `${runId}:LLM:start`,
330
744
  runId: this.#traceRunId(runId),
331
745
  parentId: parentRunId,
332
- name: `llm:${model ?? "llm"}`,
746
+ name: stepName,
333
747
  kind: "LLM",
334
- timestamp: Date.now(),
748
+ timestamp: ts,
335
749
  status: "running",
336
750
  attributes: attrs,
337
751
  confidence: "explicit",
338
752
  source: { type: "adapter" }
339
753
  });
754
+ await this.#persistLlmStepStart(runId, parentRunId, stepName, "LLM", ts, attrs);
340
755
  }
341
756
  async handleChatModelStart(llm, messages, runId, parentRunId, _extraParams, tags, metadata, runName) {
342
757
  this.#ensureRoot(runId, parentRunId);
@@ -349,19 +764,38 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
349
764
  };
350
765
  if (model && this.#opts.capture !== "none") attrs.model = model;
351
766
  this.#mergeMetadata(attrs, metadata);
767
+ this.#mergeCorrelation(attrs);
352
768
  this.#applyPreview(attrs, previews);
769
+ const ts = Date.now();
770
+ const stepName = `llm:${model ?? "llm"}`;
353
771
  this.#pushEvent({
354
772
  eventId: `${runId}:CHAT:start`,
355
773
  runId: this.#traceRunId(runId),
356
774
  parentId: parentRunId,
357
- name: `llm:${model ?? "llm"}`,
775
+ name: stepName,
358
776
  kind: "LLM",
359
- timestamp: Date.now(),
777
+ timestamp: ts,
360
778
  status: "running",
361
779
  attributes: attrs,
362
780
  confidence: "explicit",
363
781
  source: { type: "adapter" }
364
782
  });
783
+ await this.#persistLlmStepStart(runId, parentRunId, stepName, "LLM", ts, attrs);
784
+ }
785
+ handleLLMNewToken(token, _idx, runId, _parentRunId, _tags, _fields) {
786
+ try {
787
+ if (!this.#opts.stream) return;
788
+ let state = this.#streamState.get(runId);
789
+ if (!state) {
790
+ state = createLlmStreamState();
791
+ this.#streamState.set(runId, state);
792
+ }
793
+ recordLlmStreamToken(state, token, Date.now(), this.#streamPreviewLimit());
794
+ } catch (err) {
795
+ if (!this.#opts.silent) {
796
+ console.error("[agent-inspect:langchain]", err);
797
+ }
798
+ }
365
799
  }
366
800
  async handleLLMEnd(output, runId, parentRunId, tags, _extraParams) {
367
801
  this.#ensureRoot(runId, parentRunId);
@@ -376,20 +810,30 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
376
810
  };
377
811
  if (model && this.#opts.capture !== "none") attrs.model = model;
378
812
  if (tokens && this.#opts.capture !== "none") attrs.tokens = tokens;
813
+ this.#attachStreamMetadata(attrs, runId);
814
+ this.#mergeCorrelation(attrs);
379
815
  this.#applyPreview(attrs, previews);
816
+ const ts = Date.now();
380
817
  this.#pushEvent({
381
818
  eventId: `${runId}:LLM:end`,
382
819
  runId: this.#traceRunId(runId),
383
820
  parentId: parentRunId,
384
821
  name: `llm:${model ?? "llm"}`,
385
822
  kind: "LLM",
386
- timestamp: Date.now(),
823
+ timestamp: ts,
387
824
  status: "ok",
388
825
  durationMs,
389
826
  attributes: attrs,
390
827
  confidence: "explicit",
391
828
  source: { type: "adapter" }
392
829
  });
830
+ await this.#flushDeferredPersistStart(runId, attrs);
831
+ await this.#persistStepEnd(runId, parentRunId, "success", ts, durationMs, void 0, {
832
+ ...attrs,
833
+ name: `llm:${model ?? "llm"}`,
834
+ kind: "LLM"
835
+ });
836
+ this.#clearStreamState(runId);
393
837
  }
394
838
  async handleLLMError(err, runId, parentRunId, tags, _extraParams) {
395
839
  this.#ensureRoot(runId, parentRunId);
@@ -401,19 +845,29 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
401
845
  errorName,
402
846
  errorMessage
403
847
  };
848
+ this.#attachStreamMetadata(attrs, runId);
849
+ this.#mergeCorrelation(attrs);
850
+ const ts = Date.now();
404
851
  this.#pushEvent({
405
852
  eventId: `${runId}:LLM:error`,
406
853
  runId: this.#traceRunId(runId),
407
854
  parentId: parentRunId,
408
855
  name: "llm:error",
409
856
  kind: "LLM",
410
- timestamp: Date.now(),
857
+ timestamp: ts,
411
858
  status: "error",
412
859
  durationMs,
413
860
  attributes: attrs,
414
861
  confidence: "explicit",
415
862
  source: { type: "adapter" }
416
863
  });
864
+ await this.#flushDeferredPersistStart(runId, attrs);
865
+ await this.#persistStepEnd(runId, parentRunId, "error", ts, durationMs, errorMessage, {
866
+ ...attrs,
867
+ name: "llm:error",
868
+ kind: "LLM"
869
+ });
870
+ this.#clearStreamState(runId);
417
871
  }
418
872
  async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName, _toolCallId) {
419
873
  this.#ensureRoot(runId, parentRunId);
@@ -427,18 +881,21 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
427
881
  };
428
882
  this.#mergeMetadata(attrs, metadata);
429
883
  this.#applyPreview(attrs, previews);
884
+ const ts = Date.now();
885
+ const stepName = `tool:${toolName}`;
430
886
  this.#pushEvent({
431
887
  eventId: `${runId}:TOOL:start`,
432
888
  runId: this.#traceRunId(runId),
433
889
  parentId: parentRunId,
434
- name: `tool:${toolName}`,
890
+ name: stepName,
435
891
  kind: "TOOL",
436
- timestamp: Date.now(),
892
+ timestamp: ts,
437
893
  status: "running",
438
894
  attributes: attrs,
439
895
  confidence: "explicit",
440
896
  source: { type: "adapter" }
441
897
  });
898
+ await this.#persistStepStart(runId, parentRunId, stepName, "TOOL", attrs, ts);
442
899
  }
443
900
  async handleToolEnd(output, runId, parentRunId, tags) {
444
901
  this.#ensureRoot(runId, parentRunId);
@@ -450,19 +907,21 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
450
907
  ...this.#baseAttrs(runId, parentRunId, tags, void 0)
451
908
  };
452
909
  this.#applyPreview(attrs, previews);
910
+ const ts = Date.now();
453
911
  this.#pushEvent({
454
912
  eventId: `${runId}:TOOL:end`,
455
913
  runId: this.#traceRunId(runId),
456
914
  parentId: parentRunId,
457
915
  name: "tool:end",
458
916
  kind: "TOOL",
459
- timestamp: Date.now(),
917
+ timestamp: ts,
460
918
  status: "ok",
461
919
  durationMs,
462
920
  attributes: attrs,
463
921
  confidence: "explicit",
464
922
  source: { type: "adapter" }
465
923
  });
924
+ await this.#persistStepEnd(runId, parentRunId, "success", ts, durationMs);
466
925
  }
467
926
  async handleToolError(err, runId, parentRunId, tags) {
468
927
  this.#ensureRoot(runId, parentRunId);
@@ -474,19 +933,21 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
474
933
  errorName,
475
934
  errorMessage
476
935
  };
936
+ const ts = Date.now();
477
937
  this.#pushEvent({
478
938
  eventId: `${runId}:TOOL:error`,
479
939
  runId: this.#traceRunId(runId),
480
940
  parentId: parentRunId,
481
941
  name: "tool:error",
482
942
  kind: "TOOL",
483
- timestamp: Date.now(),
943
+ timestamp: ts,
484
944
  status: "error",
485
945
  durationMs,
486
946
  attributes: attrs,
487
947
  confidence: "explicit",
488
948
  source: { type: "adapter" }
489
949
  });
950
+ await this.#persistStepEnd(runId, parentRunId, "error", ts, durationMs, errorMessage);
490
951
  }
491
952
  async handleRetrieverStart(retriever, _query, runId, parentRunId, tags, metadata, name) {
492
953
  this.#ensureRoot(runId, parentRunId);
@@ -497,18 +958,21 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
497
958
  retriever: rname
498
959
  };
499
960
  this.#mergeMetadata(attrs, metadata);
961
+ const ts = Date.now();
962
+ const stepName = `retriever:${rname}`;
500
963
  this.#pushEvent({
501
964
  eventId: `${runId}:RETRIEVER:start`,
502
965
  runId: this.#traceRunId(runId),
503
966
  parentId: parentRunId,
504
- name: `retriever:${rname}`,
967
+ name: stepName,
505
968
  kind: "RETRIEVER",
506
- timestamp: Date.now(),
969
+ timestamp: ts,
507
970
  status: "running",
508
971
  attributes: attrs,
509
972
  confidence: "explicit",
510
973
  source: { type: "adapter" }
511
974
  });
975
+ await this.#persistStepStart(runId, parentRunId, stepName, "RETRIEVER", attrs, ts);
512
976
  }
513
977
  async handleRetrieverEnd(documents, runId, parentRunId, tags) {
514
978
  this.#ensureRoot(runId, parentRunId);
@@ -523,19 +987,21 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
523
987
  documentCount: documents.length
524
988
  };
525
989
  this.#applyPreview(attrs, previews);
990
+ const ts = Date.now();
526
991
  this.#pushEvent({
527
992
  eventId: `${runId}:RETRIEVER:end`,
528
993
  runId: this.#traceRunId(runId),
529
994
  parentId: parentRunId,
530
995
  name: "retriever:end",
531
996
  kind: "RETRIEVER",
532
- timestamp: Date.now(),
997
+ timestamp: ts,
533
998
  status: "ok",
534
999
  durationMs,
535
1000
  attributes: attrs,
536
1001
  confidence: "explicit",
537
1002
  source: { type: "adapter" }
538
1003
  });
1004
+ await this.#persistStepEnd(runId, parentRunId, "success", ts, durationMs);
539
1005
  }
540
1006
  async handleRetrieverError(err, runId, parentRunId, tags) {
541
1007
  this.#ensureRoot(runId, parentRunId);
@@ -547,19 +1013,21 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
547
1013
  errorName,
548
1014
  errorMessage
549
1015
  };
1016
+ const ts = Date.now();
550
1017
  this.#pushEvent({
551
1018
  eventId: `${runId}:RETRIEVER:error`,
552
1019
  runId: this.#traceRunId(runId),
553
1020
  parentId: parentRunId,
554
1021
  name: "retriever:error",
555
1022
  kind: "RETRIEVER",
556
- timestamp: Date.now(),
1023
+ timestamp: ts,
557
1024
  status: "error",
558
1025
  durationMs,
559
1026
  attributes: attrs,
560
1027
  confidence: "explicit",
561
1028
  source: { type: "adapter" }
562
1029
  });
1030
+ await this.#persistStepEnd(runId, parentRunId, "error", ts, durationMs, errorMessage);
563
1031
  }
564
1032
  async handleAgentAction(action, runId, parentRunId, tags) {
565
1033
  this.#ensureRoot(runId, parentRunId);
@@ -585,6 +1053,7 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
585
1053
  confidence: "explicit",
586
1054
  source: { type: "adapter" }
587
1055
  });
1056
+ await this.#persistInstant(runId, parentRunId, "agent:action", "DECISION", attrs, "success");
588
1057
  }
589
1058
  async handleAgentEnd(finish, runId, parentRunId, tags) {
590
1059
  this.#ensureRoot(runId, parentRunId);
@@ -609,6 +1078,7 @@ var AgentInspectCallback = class extends BaseCallbackHandler {
609
1078
  confidence: "explicit",
610
1079
  source: { type: "adapter" }
611
1080
  });
1081
+ await this.#persistInstant(runId, parentRunId, "agent:end", "AGENT", attrs, "success");
612
1082
  }
613
1083
  };
614
1084