@warlock.js/ai-panoptic 5.32.0 → 5.33.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/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to `@warlock.js/ai-panoptic` are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
6
6
 
7
+ ## 5.33.0 - 2026-10-19
8
+
9
+ ### Added
10
+
11
+ - `subscribeTraces(listener)` and `TraceListener` for process-local adapters observing finalized traces from every built-in collector before exporter dispatch, with isolated listener failures and independent teardown.
12
+ - Optional `Trace.requestId` and exact `TraceQuery.requestId` filters for both in-memory and cache-backed query/aggregate APIs.
13
+ - Content-free retry-attempt timings, provider cache-hit and truncated-trip counts, agent compaction decisions and provider compaction-block counts on trace attributes, surfaced by the devtools AI panel.
14
+
7
15
  ## 5.32.0 - 2026-10-18
8
16
 
9
17
  ### Changed
package/cjs/index.cjs CHANGED
@@ -99,7 +99,16 @@ function pickString(value) {
99
99
  function extractSpanAttributes(report) {
100
100
  const extensions = report;
101
101
  const attributes = {};
102
- if (report.attempts !== void 0 && report.attempts.length > 0) attributes["retries"] = report.attempts.length;
102
+ if (report.attempts !== void 0 && report.attempts.length > 0) {
103
+ attributes["retries"] = report.attempts.length;
104
+ attributes["retry.attempts"] = report.attempts.map((attempt) => ({
105
+ index: attempt.index,
106
+ startedAt: attempt.startedAt,
107
+ endedAt: attempt.endedAt,
108
+ duration: attempt.duration,
109
+ status: attempt.status
110
+ }));
111
+ }
103
112
  switch (report.type) {
104
113
  case "agent":
105
114
  addAgentAttributes(attributes, extensions);
@@ -120,7 +129,25 @@ function extractSpanAttributes(report) {
120
129
  return attributes;
121
130
  }
122
131
  function addAgentAttributes(attributes, extensions) {
123
- if (Array.isArray(extensions.trips)) attributes["agent.trips"] = extensions.trips.length;
132
+ if (Array.isArray(extensions.trips)) {
133
+ attributes["agent.trips"] = extensions.trips.length;
134
+ if (extensions.trips.some((trip) => trip.usage?.cachedTokens !== void 0)) attributes["agent.cacheHits"] = extensions.trips.filter((trip) => (trip.usage?.cachedTokens ?? 0) > 0).length;
135
+ const truncatedTrips = extensions.trips.filter((trip) => trip.finishReason === "length" || trip.finishReason === "context_exceeded").length;
136
+ if (truncatedTrips > 0) attributes["agent.truncatedTrips"] = truncatedTrips;
137
+ const providerCompactions = extensions.trips.reduce((count, trip) => count + (trip.blocks?.filter((block) => block.type === "compaction").length ?? 0), 0);
138
+ if (providerCompactions > 0) attributes["agent.providerCompactions"] = providerCompactions;
139
+ }
140
+ if (extensions.compactions?.length) attributes["agent.compactions"] = extensions.compactions.map((record) => ({
141
+ type: record.type,
142
+ tripIndex: record.tripIndex,
143
+ inputTokens: record.inputTokens,
144
+ counting: record.counting,
145
+ reason: record.reason,
146
+ ...record.compaction ? {
147
+ replacesFromIndex: record.compaction.replacesFromIndex,
148
+ replacesToIndex: record.compaction.replacesToIndex
149
+ } : {}
150
+ }));
124
151
  if (extensions.model?.name !== void 0) attributes["agent.model.name"] = extensions.model.name;
125
152
  if (extensions.model?.provider !== void 0) attributes["agent.model.provider"] = extensions.model.provider;
126
153
  if (extensions.promptName !== void 0) attributes["agent.promptName"] = extensions.promptName;
@@ -331,6 +358,30 @@ function reportToTrace(report, rootError, options) {
331
358
  return trace;
332
359
  }
333
360
 
361
+ //#endregion
362
+ //#region ../../packages/ai-panoptic/src/collector/trace-subscriptions.ts
363
+ const listeners = /* @__PURE__ */ new Set();
364
+ /**
365
+ * Subscribe to traces from every built-in collector in this process, including
366
+ * collectors created before subscribing. No replay or retention. Called before
367
+ * exporter dispatch, so adapters can read request-local context synchronously.
368
+ * Listener failures are isolated; async listeners are not awaited. The returned
369
+ * disposer removes only this subscription. Does not enable flow observation.
370
+ */
371
+ function subscribeTraces(listener) {
372
+ const subscription = (trace) => listener(trace);
373
+ listeners.add(subscription);
374
+ return () => {
375
+ listeners.delete(subscription);
376
+ };
377
+ }
378
+ /** Internal collector notification; pure toTrace projections never publish. */
379
+ function publishTrace(trace) {
380
+ for (const listener of listeners) try {
381
+ Promise.resolve(listener(trace)).catch(() => {});
382
+ } catch {}
383
+ }
384
+
334
385
  //#endregion
335
386
  //#region ../../packages/ai-panoptic/src/collector/collector.ts
336
387
  /**
@@ -382,6 +433,7 @@ var Collector = class {
382
433
  }
383
434
  async collect(report, rootError) {
384
435
  const trace = this.toTrace(report, rootError);
436
+ publishTrace(trace);
385
437
  await this.dispatch(trace);
386
438
  }
387
439
  async flush() {
@@ -472,6 +524,7 @@ function createCollector(options = {}) {
472
524
  */
473
525
  function matchTrace(trace, filter) {
474
526
  if (!filter) return true;
527
+ if (filter.requestId !== void 0 && trace.requestId !== filter.requestId) return false;
475
528
  if (filter.traceId !== void 0 && trace.traceId !== filter.traceId) return false;
476
529
  if (filter.sessionId !== void 0 && trace.sessionId !== filter.sessionId) return false;
477
530
  if (filter.status !== void 0 && !statusMatches(trace.root.status, filter.status)) return false;
@@ -4244,6 +4297,7 @@ exports.percentile = percentile;
4244
4297
  exports.reportToSpan = reportToSpan;
4245
4298
  exports.reportToTrace = reportToTrace;
4246
4299
  exports.rollupCost = rollupCost;
4300
+ exports.subscribeTraces = subscribeTraces;
4247
4301
  exports.sumUsage = sumUsage;
4248
4302
  exports.toGenAiAttributes = toGenAiAttributes;
4249
4303
  exports.totalCostUsd = totalCostUsd;