@tangle-network/charts 0.21.8 → 0.21.10

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.
@@ -22,6 +22,9 @@
22
22
  --fw-failed: light-dark(#d4304a, #ff5c74);
23
23
  --fw-ok: var(--status-running, light-dark(#0d8a5f, #34c48c));
24
24
  --fw-amber: light-dark(#a35d00, #f2b14c);
25
+ /* Step kinds inside an agent bar: two hues far from each other and from the outcome greens and reds. */
26
+ --fw-kind-model: light-dark(#4f46e5, #8f91f7);
27
+ --fw-kind-tool: light-dark(#0e8fb0, #4cc9e6);
25
28
  --fw-neutral-bar: color-mix(in oklab, var(--fw-text) 15%, var(--fw-surface));
26
29
  --fw-hatch: color-mix(in oklab, var(--fw-text) 22%, transparent);
27
30
  /* Root agent neutral, then five agent hues. Each passes 3:1 against both surfaces as a mark. */
@@ -126,7 +129,7 @@
126
129
  .fw-root .fw-marker-layer { position: absolute; top: 0; bottom: 0; left: var(--fw-label-col); right: 0; overflow: hidden; pointer-events: none; z-index: 2; }
127
130
  /* An event's line is drawn behind the rows, with the gridlines, so bars and labels cover it; its label stays on top. */
128
131
  .fw-root .fw-marker { --fw-marker: var(--fw-muted); position: absolute; top: 0; bottom: 0; width: 0; left: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px); }
129
- .fw-root .fw-marker-line { --fw-marker: var(--fw-muted); position: absolute; top: 0; bottom: 0; border-left: 1px dashed var(--fw-marker); left: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px); }
132
+ .fw-root .fw-marker-line { --fw-marker: var(--fw-muted); opacity: .4; position: absolute; top: 0; bottom: 0; border-left: 1px dashed var(--fw-marker); left: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px); }
130
133
  .fw-root .fw-marker-line[data-tone="ok"] { --fw-marker: var(--fw-ok); }
131
134
  .fw-root .fw-marker-line[data-tone="failed"] { --fw-marker: var(--fw-failed); }
132
135
  .fw-root .fw-marker[data-tone="ok"] { --fw-marker: var(--fw-ok); }
@@ -191,7 +194,9 @@
191
194
  .fw-root .fw-view-agents .fw-label { padding-left: 16px; gap: 12px; border-right: 0; }
192
195
  .fw-root .fw-view-agents .fw-names { flex-direction: column; align-items: flex-start; gap: 0; }
193
196
  .fw-root .fw-view-agents .fw-span-name { font-weight: 600; line-height: 18px; }
194
- .fw-root .fw-view-agents .fw-subtitle { display: flex; align-items: center; gap: 4px; max-width: 100%; min-width: 0; color: var(--fw-muted); font-size: 12px; line-height: 16px; }
197
+ /* One 16 px line that wraps its last part out of sight: when the line is full the tool count drops whole, never "7 to…". */
198
+ .fw-root .fw-view-agents .fw-subtitle { display: flex; flex-wrap: wrap; align-items: center; column-gap: 4px; height: 16px; overflow: hidden; max-width: 100%; min-width: 0; color: var(--fw-muted); font-size: 13px; line-height: 16px; }
199
+ .fw-root .fw-view-agents .fw-subtitle-extra { flex: none; white-space: nowrap; }
195
200
  .fw-root .fw-view-agents .fw-subtitle-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
196
201
  .fw-root .fw-view-agents .fw-detail-icon { flex: none; width: 16px; height: 16px; align-items: center; justify-content: center; overflow: hidden; }
197
202
  .fw-root .fw-view-agents .fw-detail { font-size: 12px; line-height: 16px; }
@@ -233,8 +238,8 @@
233
238
  .fw-root .fw-bar.fw-k-pipeline.fw-has-marks { background: color-mix(in oklab, var(--tone) 9%, transparent); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--tone) 18%, transparent); }
234
239
  .fw-root .fw-bar.fw-k-pipeline.fw-has-agents { background: repeating-linear-gradient(-45deg, var(--fw-hatch) 0 1px, transparent 1px 5px), color-mix(in oklab, var(--fw-text) 4%, transparent); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-text) 12%, transparent); }
235
240
  /* An agent bar with no child marks says who it is by its lane color, never a neutral grey. */
236
- /* In the agent view the bar's own extent between steps is waiting: hatched in the outcome tone, under the step segments. */
237
- .fw-root .fw-view-agents .fw-bar.fw-k-pipeline.fw-has-marks { background: repeating-linear-gradient(-45deg, color-mix(in oklab, var(--tone) 28%, transparent) 0 1px, transparent 1px 5px), color-mix(in oklab, var(--tone) 9%, transparent); }
241
+ /* In the agent view the bar's own extent between steps is waiting: a flat faint fill under the step segments (long hatching read muddy). */
242
+ .fw-root .fw-view-agents .fw-bar.fw-k-pipeline.fw-has-marks { background: color-mix(in oklab, var(--tone) 12%, transparent); }
238
243
  /* An agent lane is a tint of its color; full saturation is kept for its model and tool segments and its status dot, so a run never
239
244
  reads as a wall of colored slabs. */
240
245
  .fw-root .fw-view-agents .fw-bar.fw-k-pipeline:not(.fw-has-marks, .fw-has-agents) { background: color-mix(in oklab, var(--tone) 30%, var(--fw-surface)); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--tone) 55%, transparent); }
@@ -251,10 +256,12 @@
251
256
  .fw-root [data-outcome="neutral"], .fw-root [data-outcome="neutral"] [data-tone] { --tone: var(--fw-muted); }
252
257
  .fw-root .fw-legend { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 8px 0 0; padding: 0; list-style: none; color: var(--fw-muted); font-size: 12px; line-height: 16px; }
253
258
  .fw-root .fw-legend li { display: inline-flex; align-items: center; gap: 8px; }
254
- .fw-root .fw-kinds { margin: 0; padding: 4px 24px 8px; justify-content: flex-start; color: var(--fw-text); }
255
- .fw-root .fw-kinds .fw-swatch-model { width: 12px; height: 8px; border-radius: 2px; background: color-mix(in oklab, var(--fw-text) 40%, var(--fw-surface)); }
256
- .fw-root .fw-kinds .fw-swatch-tool { width: 12px; height: 8px; border-radius: 2px; background: color-mix(in oklab, var(--fw-text) 16%, var(--fw-surface)); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-text) 30%, transparent); }
257
- .fw-root .fw-kinds .fw-swatch-wait { width: 12px; height: 8px; border-radius: 2px; background: repeating-linear-gradient(-45deg, var(--fw-hatch) 0 1px, transparent 1px 4px); box-shadow: inset 0 0 0 1px var(--fw-hatch); }
259
+ .fw-root .fw-legends { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 24px; margin-top: 8px; }
260
+ .fw-root .fw-legends .fw-legend { margin: 0; }
261
+ .fw-root .fw-kinds { margin: 0; padding: 0; justify-content: flex-start; color: var(--fw-muted); }
262
+ .fw-root .fw-kinds .fw-swatch-model { width: 12px; height: 8px; border-radius: 2px; background: var(--fw-kind-model); }
263
+ .fw-root .fw-kinds .fw-swatch-tool { width: 12px; height: 8px; border-radius: 2px; background: var(--fw-kind-tool); }
264
+ .fw-root .fw-kinds .fw-swatch-wait { width: 12px; height: 8px; border-radius: 2px; background: color-mix(in oklab, var(--fw-text) 12%, transparent); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-text) 18%, transparent); }
258
265
  .fw-root .fw-kinds .fw-swatch-handoff { width: 10px; height: 8px; border-left: 1.5px solid var(--fw-muted); border-bottom: 1.5px solid var(--fw-muted); border-bottom-left-radius: 3px; }
259
266
  .fw-root .fw-kinds .fw-swatch-failed { width: 12px; height: 8px; border-radius: 2px; box-shadow: inset 0 0 0 1px var(--fw-failed); }
260
267
  .fw-root .fw-description { margin: 0; color: var(--fw-muted); font-size: 14px; line-height: 20px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@@ -267,6 +274,13 @@
267
274
  .fw-root .fw-view-agents .fw-seg { pointer-events: auto; }
268
275
  .fw-root .fw-seg-model { background: var(--fill); box-shadow: inset 0 0 0 1px var(--line); }
269
276
  .fw-root .fw-seg-tool { background: var(--dim); box-shadow: inset 0 0 0 1px var(--dim-line); }
277
+ /* In the agent view a step's kind owns its color, strong on both themes; the agent's outcome stays on its lane tint, dot and end label. */
278
+ .fw-root .fw-view-agents .fw-seg-model { background: var(--fw-kind-model); box-shadow: none; }
279
+ .fw-root .fw-view-agents .fw-seg-tool { background: var(--fw-kind-tool); box-shadow: none; }
280
+ .fw-root .fw-view-agents .fw-seg-tool { container-type: inline-size; justify-content: flex-start; }
281
+ .fw-root .fw-seg-name { padding: 0 6px; overflow: hidden; white-space: nowrap; text-overflow: clip; font-size: 11px; line-height: 16px; font-weight: 600; color: light-dark(#fff, #06222b); pointer-events: none; }
282
+ @container (max-width: 56px) { .fw-root .fw-seg-name { display: none; } }
283
+ .fw-root .fw-view-agents .fw-seg-alt.fw-seg-model, .fw-root .fw-view-agents .fw-seg-alt.fw-seg-tool { filter: brightness(.88); }
270
284
  .fw-root .fw-seg-failed { background: color-mix(in oklab, var(--fw-failed) 18%, var(--fw-surface)); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-failed) 70%, transparent); color: var(--fw-failed); }
271
285
  /* In the agent view a failed turn draws like any turn; the agent's own failure shows once, by its name and its end label. */
272
286
  .fw-root .fw-view-agents .fw-seg-failed { background: var(--dim); box-shadow: inset 0 0 0 1px var(--dim-line); }
@@ -308,8 +322,8 @@
308
322
  .fw-root.fw-root-agents .fw-card, .fw-root.fw-root-agents .fw-card-above .fw-card { position: relative; left: auto !important; top: auto !important; transform: none; animation-name: fw-arrive; width: auto; max-width: 560px; }
309
323
  .fw-root .fw-seg-alt { filter: brightness(.78); }
310
324
  /* Agent view: the scrubber track shows how far the run has played, so at rest it reads full, not empty. */
311
- .fw-root.fw-root-agents .fw-slider { background: linear-gradient(90deg, var(--fw-accent) var(--fw-progress), var(--fw-well) var(--fw-progress)) 0 50% / 100% 6px no-repeat; }
312
- /* The playhead: a round knob on a filled track, visible at rest as the references show it. */
325
+ .fw-root.fw-root-agents .fw-slider { background: linear-gradient(90deg, color-mix(in oklab, var(--fw-text) 32%, transparent) var(--fw-progress), var(--fw-well) var(--fw-progress)) 0 50% / 100% 4px no-repeat; }
326
+ /* The playhead: a round knob on a thin neutral track, visible at rest without outweighing the chart. */
313
327
  .fw-root.fw-root-agents .fw-slider::-webkit-slider-thumb { width: 14px; height: 14px; border-radius: 50%; background: var(--fw-text); box-shadow: 0 0 0 3px var(--fw-surface); }
314
328
  .fw-root.fw-root-agents .fw-slider::-moz-range-thumb { width: 14px; height: 14px; border-radius: 50%; background: var(--fw-text); box-shadow: 0 0 0 3px var(--fw-surface); }
315
329
  .fw-root .fw-card { position: absolute; z-index: 20; width: 320px; padding: 12px; border-radius: 12px; background: var(--fw-raised); border: 1px solid var(--fw-border);
@@ -2586,7 +2586,8 @@ function segmentOf(row) {
2586
2586
  tone: row.tone,
2587
2587
  id: row.id,
2588
2588
  count: 1,
2589
- retry: row.retry
2589
+ retry: row.retry,
2590
+ name: row.name
2590
2591
  };
2591
2592
  }
2592
2593
  /** Search keeps ancestor context and deliberately reveals matches inside collapsed branches. */
@@ -2760,7 +2761,7 @@ function agentFamilies(agents, open) {
2760
2761
  costFloor: known.length < members.length || members.some((row) => row.costFloor),
2761
2762
  id,
2762
2763
  parentId: members[0].parentId,
2763
- name: `${role} ×${members.length}`,
2764
+ name: role,
2764
2765
  kind: "pipeline",
2765
2766
  durationLabel: formatSpanDuration(endMs - startMs),
2766
2767
  approx: members.some((row) => row.approx),
@@ -2833,6 +2834,11 @@ function agentSummary(row) {
2833
2834
  tools ? `${tools} tool ${tools === 1 ? "call" : "calls"}` : ""
2834
2835
  ].filter(Boolean).join(" · ");
2835
2836
  }
2837
+ /** The summary split where it may be cut: the tool count goes first when the line does not fit, never half a word. */
2838
+ function agentSummaryParts(row) {
2839
+ const tools = / · (\d+ tool calls?)$/.exec(agentSummary(row));
2840
+ return tools ? [agentSummary(row).slice(0, tools.index), tools[1]] : [agentSummary(row)];
2841
+ }
2836
2842
  /**
2837
2843
  * The agent view's rows: families folded until opened, and an opened agent's own steps (its turns and tool calls, not its
2838
2844
  * child agents) nested beneath it with their icons, durations and costs, as a reader drills from the run into one agent.
@@ -2890,7 +2896,8 @@ function stepRuns(steps) {
2890
2896
  tone: first.tone,
2891
2897
  id: step.id,
2892
2898
  count: 1,
2893
- retry: step.retry
2899
+ retry: step.retry,
2900
+ name: step.name
2894
2901
  })),
2895
2902
  ...costs.length ? { rollupCostUsd: costs.reduce((sum, cost) => sum + cost, 0) } : {},
2896
2903
  span: {
@@ -3284,18 +3291,23 @@ const at = (startMs, endMs) => ({
3284
3291
  const endLabelWidth = (label, slowest, costliest) => label.length * 7 + 8 + (slowest ? 74 : 0) + (costliest ? 84 : 0);
3285
3292
  function Segment({ mark, events, agentView, ending }) {
3286
3293
  const glyph = mark.kind === "failed" ? agentView && !ending ? null : /* @__PURE__ */ jsx(FailGlyph, {}) : mark.retry ? /* @__PURE__ */ jsx(RetryGlyph, {}) : null;
3294
+ const named = agentView && mark.kind === "tool" && mark.count === 1 && mark.name;
3287
3295
  return /* @__PURE__ */ jsx("span", {
3288
3296
  className: `fw-seg fw-seg-${mark.kind}${mark.alt ? " fw-seg-alt" : ""}`,
3289
3297
  "data-tone": toneKey(mark.tone),
3290
3298
  style: at(mark.startMs, mark.endMs),
3299
+ title: mark.name ? `${mark.name}${mark.count > 1 ? ` +${mark.count - 1} more` : ""}` : void 0,
3291
3300
  onPointerEnter: agentView ? (event) => events.onInspect(mark.id, event.currentTarget) : void 0,
3292
3301
  onClick: agentView ? (event) => {
3293
3302
  event.stopPropagation();
3294
3303
  events.onPin(mark.id, event.currentTarget);
3295
3304
  } : void 0,
3296
- children: glyph && /* @__PURE__ */ jsx("span", {
3305
+ children: glyph ? /* @__PURE__ */ jsx("span", {
3297
3306
  className: "fw-glyph",
3298
3307
  children: glyph
3308
+ }) : named && /* @__PURE__ */ jsx("span", {
3309
+ className: "fw-seg-name",
3310
+ children: mark.name
3299
3311
  })
3300
3312
  });
3301
3313
  }
@@ -3322,6 +3334,7 @@ const FlowRow = memo(function FlowRow(props) {
3322
3334
  const kind = !row.ok ? "failed" : row.kind;
3323
3335
  const marks = isAgent || row.hasChildren || row.id.startsWith("run:") ? folded && !agentView ? row.segments : row.own : [];
3324
3336
  const label = endLabel(row, clockMs);
3337
+ const summary = agentSummaryParts(row);
3325
3338
  const inspect = (event) => props.onInspect(row.id, event.currentTarget);
3326
3339
  const family = agentView && row.id.startsWith("family:");
3327
3340
  const step = agentView && row.stepOf !== void 0;
@@ -3393,6 +3406,10 @@ const FlowRow = memo(function FlowRow(props) {
3393
3406
  className: "fw-toggle-space",
3394
3407
  "aria-hidden": true
3395
3408
  })),
3409
+ agentView && !opens && /* @__PURE__ */ jsx("span", {
3410
+ className: "fw-toggle-space",
3411
+ "aria-hidden": true
3412
+ }),
3396
3413
  (!agentView || step) && /* @__PURE__ */ jsx("span", {
3397
3414
  className: "fw-icon-tile",
3398
3415
  "aria-hidden": true,
@@ -3429,14 +3446,21 @@ const FlowRow = memo(function FlowRow(props) {
3429
3446
  ]
3430
3447
  }), agentView && /* @__PURE__ */ jsxs("span", {
3431
3448
  className: "fw-subtitle",
3432
- children: [renderIcon && /* @__PURE__ */ jsx("span", {
3433
- className: "fw-detail-icon",
3434
- "aria-hidden": true,
3435
- children: renderIcon(span)
3436
- }), /* @__PURE__ */ jsx("span", {
3437
- className: "fw-subtitle-text",
3438
- children: span.detail && span.detail !== props.sharedDetail ? `${span.detail} · ${agentSummary(row)}` : agentSummary(row)
3439
- })]
3449
+ children: [
3450
+ renderIcon && /* @__PURE__ */ jsx("span", {
3451
+ className: "fw-detail-icon",
3452
+ "aria-hidden": true,
3453
+ children: renderIcon(span)
3454
+ }),
3455
+ /* @__PURE__ */ jsx("span", {
3456
+ className: "fw-subtitle-text",
3457
+ children: span.detail && span.detail !== props.sharedDetail ? `${span.detail} · ${summary[0]}` : summary[0]
3458
+ }),
3459
+ summary[1] && /* @__PURE__ */ jsxs("span", {
3460
+ className: "fw-subtitle-extra",
3461
+ children: ["· ", summary[1]]
3462
+ })
3463
+ ]
3440
3464
  })]
3441
3465
  }),
3442
3466
  folded && /* @__PURE__ */ jsxs("span", {
@@ -4832,7 +4856,10 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
4832
4856
  done && speedup >= 1.05 ? ` · ${speedup.toFixed(1)}x parallel` : ""
4833
4857
  ]
4834
4858
  }),
4835
- /* @__PURE__ */ jsx(OutcomeLegend, { agents })
4859
+ /* @__PURE__ */ jsxs("div", {
4860
+ className: "fw-legends",
4861
+ children: [/* @__PURE__ */ jsx(OutcomeLegend, { agents }), view === "agents" && /* @__PURE__ */ jsx(KindLegend, { rows })]
4862
+ })
4836
4863
  ]
4837
4864
  }), /* @__PURE__ */ jsxs("div", {
4838
4865
  className: "fw-tools",
@@ -4898,7 +4925,6 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
4898
4925
  }, name))
4899
4926
  }),
4900
4927
  view === "agents" && playback,
4901
- view === "agents" && /* @__PURE__ */ jsx(KindLegend, { rows }),
4902
4928
  /* @__PURE__ */ jsx(FlowBody, {
4903
4929
  rows: visible,
4904
4930
  byId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/charts",
3
- "version": "0.21.8",
3
+ "version": "0.21.10",
4
4
  "description": "Static SVG and HTML figures for benchmarks and operational timing. Draws from producer data and refuses what it cannot draw honestly.",
5
5
  "type": "module",
6
6
  "license": "MIT",