@tangle-network/charts 0.21.14 → 0.21.15

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.
@@ -196,8 +196,10 @@
196
196
  .fw-root .fw-view-agents .fw-names { flex-direction: column; align-items: flex-start; gap: 0; }
197
197
  .fw-root .fw-view-agents .fw-span-name { font-weight: 600; line-height: 18px; }
198
198
  /* 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…". */
199
- .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 { display: flex; 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; }
200
200
  .fw-root .fw-view-agents .fw-subtitle-extra { flex: none; white-space: nowrap; }
201
+ /* Only the tail wraps, so the text is always first on its line and shrinks with an ellipsis; the tool count wraps out of sight. */
202
+ .fw-root .fw-view-agents .fw-subtitle-tail { display: flex; flex-wrap: wrap; column-gap: 4px; height: 16px; overflow: hidden; min-width: 0; flex: 0 1 auto; }
201
203
  .fw-root .fw-view-agents .fw-subtitle-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
202
204
  .fw-root .fw-view-agents .fw-detail-icon { flex: none; width: 16px; height: 16px; align-items: center; justify-content: center; overflow: hidden; }
203
205
  .fw-root .fw-view-agents .fw-detail { font-size: 12px; line-height: 16px; }
@@ -287,6 +289,12 @@
287
289
  agent's own hue (the rules above), so each agent stays one color. */
288
290
  .fw-root:is(.fw-fill-muted, .fw-fill-outcome) .fw-view-agents .fw-seg-model { background: var(--fw-kind-model); box-shadow: none; }
289
291
  .fw-root:is(.fw-fill-muted, .fw-fill-outcome) .fw-view-agents .fw-seg-tool { background: var(--fw-kind-tool); box-shadow: none; }
292
+ /* Per-agent hues at full saturation (blind round 26: muted per-agent bars "blur together", "wash out on white"): kind is a darker or
293
+ lighter step of the agent's own saturated hue, every solid segment at least 3:1 against the card; waiting stays the only pale fill. */
294
+ .fw-root.fw-fill-agent .fw-view-agents .fw-seg-model { background: light-dark(color-mix(in oklab, var(--tone) 78%, #000), var(--tone)); box-shadow: none; }
295
+ .fw-root.fw-fill-agent .fw-view-agents .fw-seg-tool { background: light-dark(var(--tone), color-mix(in oklab, var(--tone) 72%, #fff)); box-shadow: none; }
296
+ /* A failed turn is still the agent's work: it keeps the agent's saturated hue, and the red cross on the ending turn says it failed. */
297
+ .fw-root.fw-fill-agent .fw-view-agents .fw-seg-failed { background: light-dark(var(--tone), color-mix(in oklab, var(--tone) 72%, #fff)); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-failed) 55%, transparent); }
290
298
  .fw-root .fw-view-agents .fw-seg-tool { container-type: inline-size; justify-content: flex-start; }
291
299
  .fw-root .fw-seg-name { padding: 0 6px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 11px; line-height: 16px; font-weight: 600; color: light-dark(#fff, #06222b); pointer-events: none; }
292
300
  @container (max-width: 56px) { .fw-root .fw-seg-name { display: none; } }
@@ -2422,6 +2422,7 @@ function DotMap({ positions, radii, colors, palette, extent, rects, labels, dimm
2422
2422
  }
2423
2423
  //#endregion
2424
2424
  //#region src/react/flow-waterfall-model.ts
2425
+ const toolOf = (name) => name?.split(" · ")[0];
2425
2426
  /** The CSS hue slot: 0 is the root agent's neutral, then five agent hues cycle. */
2426
2427
  const toneKey = (tone) => tone <= 0 ? 0 : (tone - 1) % 5 + 1;
2427
2428
  const spanFailed = (span) => span.status === "failed";
@@ -2474,6 +2475,7 @@ function mergeSegments(marks, gapMs, cap = 240) {
2474
2475
  covered.set(last, share);
2475
2476
  last.endMs = Math.max(last.endMs, mark.endMs);
2476
2477
  last.count += mark.count;
2478
+ if (last.tool !== mark.tool) last.tool = void 0;
2477
2479
  last.kind = share.model >= share.tool ? "model" : "tool";
2478
2480
  } else out.push({ ...mark });
2479
2481
  }
@@ -2587,7 +2589,8 @@ function segmentOf(row) {
2587
2589
  id: row.id,
2588
2590
  count: 1,
2589
2591
  retry: row.retry,
2590
- name: row.name
2592
+ name: row.name,
2593
+ tool: toolOf(row.name)
2591
2594
  };
2592
2595
  }
2593
2596
  /** The rows a search term matches by themselves, before ancestor context is added. */
@@ -2786,7 +2789,7 @@ function agentFamilies(agents, open) {
2786
2789
  const endMs = Math.max(...members.map((row) => row.span.endMs));
2787
2790
  const running = members.some((row) => spanRunning(row.span));
2788
2791
  const known = members.map((row) => row.span.costUsd ?? row.rollupCostUsd).filter((cost) => cost !== void 0);
2789
- const failed = members.filter((row) => !row.ok).length;
2792
+ const failed = members.filter((row) => row.span.outcome ? row.span.outcome.tone === "failed" : !row.ok).length;
2790
2793
  const outcome = members.every((row) => row.span.outcome && row.span.outcome.tone === members[0].span.outcome?.tone) ? members[0].span.outcome : void 0;
2791
2794
  out.push({
2792
2795
  costFloor: known.length < members.length || members.some((row) => row.costFloor),
@@ -2857,7 +2860,7 @@ function agentSummary(row) {
2857
2860
  };
2858
2861
  const turns = counts.model + counts.failed;
2859
2862
  const tools = counts.tool;
2860
- const state = row.span.outcome?.label ?? (spanRunning(row.span) ? "running" : row.ok ? "done" : "failed");
2863
+ const state = row.span.outcome?.label ?? (spanRunning(row.span) ? "running" : !row.ok ? "failed" : row.kind === "pipeline" ? "" : "done");
2861
2864
  const unit = row.kind === "pipeline" ? ["turn", "turns"] : ["model call", "model calls"];
2862
2865
  return [
2863
2866
  state,
@@ -2928,7 +2931,8 @@ function stepRuns(steps) {
2928
2931
  id: step.id,
2929
2932
  count: 1,
2930
2933
  retry: step.retry,
2931
- name: step.name
2934
+ name: step.name,
2935
+ tool: toolOf(step.name)
2932
2936
  })),
2933
2937
  ...costs.length ? { rollupCostUsd: costs.reduce((sum, cost) => sum + cost, 0) } : {},
2934
2938
  span: {
@@ -3322,7 +3326,7 @@ const at = (startMs, endMs) => ({
3322
3326
  const endLabelWidth = (label, slowest, costliest) => label.length * 7 + 8 + (slowest ? 74 : 0) + (costliest ? 84 : 0);
3323
3327
  function Segment({ mark, events, agentView, ending }) {
3324
3328
  const glyph = mark.kind === "failed" ? agentView && !ending ? null : /* @__PURE__ */ jsx(FailGlyph, {}) : mark.retry ? /* @__PURE__ */ jsx(RetryGlyph, {}) : null;
3325
- const named = agentView && mark.kind === "tool" && mark.count === 1 && mark.name;
3329
+ const named = agentView && mark.kind === "tool" && (mark.count === 1 ? mark.name : mark.tool && `${mark.tool} ×${mark.count}`);
3326
3330
  return /* @__PURE__ */ jsx("span", {
3327
3331
  className: `fw-seg fw-seg-${mark.kind}${mark.alt ? " fw-seg-alt" : ""}`,
3328
3332
  "data-tone": toneKey(mark.tone),
@@ -3338,7 +3342,7 @@ function Segment({ mark, events, agentView, ending }) {
3338
3342
  children: glyph
3339
3343
  }) : named && /* @__PURE__ */ jsx("span", {
3340
3344
  className: "fw-seg-name",
3341
- children: mark.name
3345
+ children: named
3342
3346
  })
3343
3347
  });
3344
3348
  }
@@ -3479,21 +3483,20 @@ const FlowRow = memo(function FlowRow(props) {
3479
3483
  ]
3480
3484
  }), agentView && /* @__PURE__ */ jsxs("span", {
3481
3485
  className: "fw-subtitle",
3482
- children: [
3483
- renderIcon && /* @__PURE__ */ jsx("span", {
3484
- className: "fw-detail-icon",
3485
- "aria-hidden": true,
3486
- children: renderIcon(span)
3487
- }),
3488
- /* @__PURE__ */ jsx("span", {
3486
+ children: [renderIcon && /* @__PURE__ */ jsx("span", {
3487
+ className: "fw-detail-icon",
3488
+ "aria-hidden": true,
3489
+ children: renderIcon(span)
3490
+ }), /* @__PURE__ */ jsxs("span", {
3491
+ className: "fw-subtitle-tail",
3492
+ children: [/* @__PURE__ */ jsx("span", {
3489
3493
  className: "fw-subtitle-text",
3490
3494
  children: span.detail && span.detail !== props.sharedDetail ? `${span.detail} · ${summary[0]}` : summary[0]
3491
- }),
3492
- summary[1] && /* @__PURE__ */ jsxs("span", {
3495
+ }), summary[1] && /* @__PURE__ */ jsxs("span", {
3493
3496
  className: "fw-subtitle-extra",
3494
3497
  children: ["· ", summary[1]]
3495
- })
3496
- ]
3498
+ })]
3499
+ })]
3497
3500
  })]
3498
3501
  }),
3499
3502
  folded && /* @__PURE__ */ jsxs("span", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/charts",
3
- "version": "0.21.14",
3
+ "version": "0.21.15",
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",