@tangle-network/charts 0.21.16 → 0.21.18
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/react/flow-waterfall.css +28 -11
- package/dist/react/index.d.ts +85 -1
- package/dist/react/index.js +60 -17
- package/package.json +1 -1
|
@@ -259,7 +259,8 @@
|
|
|
259
259
|
/* Muted agents (the default): one quiet tone for every agent bar, its steps and handoffs; the slowest agent alone takes amber, and
|
|
260
260
|
failure keeps its red glyph, so color only ever means state. */
|
|
261
261
|
.fw-root.fw-fill-muted .fw-view-agents [data-tone] { --tone: var(--fw-h0); }
|
|
262
|
-
|
|
262
|
+
/* With per-agent hues the slowest agent keeps its own hue and says so with the amber pill (round 27: an amber-brown bar read "muddy"). */
|
|
263
|
+
.fw-root.fw-fill-muted .fw-view-agents .fw-row[data-slowest], .fw-root.fw-fill-muted .fw-view-agents .fw-row[data-slowest] [data-tone] { --tone: var(--fw-amber); }
|
|
263
264
|
.fw-root [data-outcome="ok"], .fw-root [data-outcome="ok"] [data-tone] { --tone: var(--fw-ok); }
|
|
264
265
|
.fw-root [data-outcome="failed"], .fw-root [data-outcome="failed"] [data-tone] { --tone: var(--fw-failed); }
|
|
265
266
|
.fw-root [data-outcome="warn"], .fw-root [data-outcome="warn"] [data-tone] { --tone: var(--fw-amber); }
|
|
@@ -291,14 +292,30 @@
|
|
|
291
292
|
.fw-root:is(.fw-fill-muted, .fw-fill-outcome) .fw-view-agents .fw-seg-model { background: var(--fw-kind-model); box-shadow: none; }
|
|
292
293
|
.fw-root:is(.fw-fill-muted, .fw-fill-outcome) .fw-view-agents .fw-seg-tool { background: var(--fw-kind-tool); box-shadow: none; }
|
|
293
294
|
/* Per-agent hues at full saturation (blind round 26: muted per-agent bars "blur together", "wash out on white"): kind is a darker or
|
|
294
|
-
lighter step of the agent's own saturated hue
|
|
295
|
-
|
|
296
|
-
.fw-root.fw-fill-agent .fw-view-agents .fw-seg-
|
|
295
|
+
lighter step of the agent's own saturated hue; waiting stays the only pale fill. Light theme sits one step softer (round 27: the
|
|
296
|
+
saturated light bars read "heavy"). */
|
|
297
|
+
.fw-root.fw-fill-agent .fw-view-agents .fw-seg-model { background: light-dark(color-mix(in oklab, var(--tone) 88%, var(--fw-text)), var(--tone)); box-shadow: none; }
|
|
298
|
+
.fw-root.fw-fill-agent .fw-view-agents .fw-seg-tool { background: light-dark(color-mix(in oklab, var(--tone) 84%, var(--fw-surface)), color-mix(in oklab, var(--tone) 72%, var(--fw-text))); box-shadow: none; }
|
|
297
299
|
/* 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. */
|
|
298
|
-
.fw-root.fw-fill-agent .fw-view-agents .fw-seg-failed { background: light-dark(var(--tone), color-mix(in oklab, var(--tone) 72%, var(--fw-text))); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-failed) 55%, transparent); }
|
|
299
|
-
.fw-root .fw-view-agents .fw-seg
|
|
300
|
-
.fw-root .fw-
|
|
301
|
-
|
|
300
|
+
.fw-root.fw-fill-agent .fw-view-agents .fw-seg-failed { background: light-dark(color-mix(in oklab, var(--tone) 84%, var(--fw-surface)), color-mix(in oklab, var(--tone) 72%, var(--fw-text))); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-failed) 55%, transparent); }
|
|
301
|
+
.fw-root .fw-view-agents .fw-seg { container-type: inline-size; justify-content: flex-start; gap: 4px; white-space: nowrap; font-size: 12px; line-height: 16px; color: light-dark(var(--fw-surface), hsl(var(--hsl-background))); }
|
|
302
|
+
.fw-root .fw-view-agents .fw-seg > * { pointer-events: none; }
|
|
303
|
+
/* The inset is the first part's margin, not the segment's padding, so a short step keeps its true width (padding set a 12 px floor). */
|
|
304
|
+
.fw-root .fw-view-agents .fw-seg > :first-child { margin-left: 6px; }
|
|
305
|
+
.fw-root .fw-seg-icon { display: inline-flex; flex: none; }
|
|
306
|
+
.fw-root .fw-seg-icon svg { width: 12px; height: 12px; stroke-width: 1.75; }
|
|
307
|
+
.fw-root .fw-seg-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; font-weight: 600; }
|
|
308
|
+
.fw-root .fw-seg-chip { flex: none; padding: 0 4px; border-radius: var(--radius-pill); background: color-mix(in oklab, currentColor 24%, transparent); font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
309
|
+
.fw-root .fw-seg-meta { flex: none; opacity: .85; font-variant-numeric: tabular-nums; }
|
|
310
|
+
/* A narrowing step drops its cost first, then its duration, then its name and count, then its icon. */
|
|
311
|
+
@container (max-width: 180px) { .fw-root .fw-seg-cost { display: none; } }
|
|
312
|
+
@container (max-width: 96px) { .fw-root .fw-seg-meta { display: none; } }
|
|
313
|
+
@container (max-width: 56px) { .fw-root :is(.fw-seg-name, .fw-seg-chip) { display: none; } }
|
|
314
|
+
@container (max-width: 24px) { .fw-root :is(.fw-seg-icon, .fw-view-agents .fw-seg .fw-glyph) { display: none; } }
|
|
315
|
+
/* Fail and retry read as filled chips inside the bar, red and amber, as the references draw them. */
|
|
316
|
+
.fw-root .fw-view-agents .fw-seg .fw-glyph { flex: none; display: grid; place-items: center; width: 14px; height: 14px; border-radius: 50%; background: var(--fw-failed); color: light-dark(var(--fw-surface), hsl(var(--hsl-background))); }
|
|
317
|
+
.fw-root .fw-view-agents .fw-seg .fw-glyph[data-glyph="retry"] { background: var(--fw-amber); }
|
|
318
|
+
.fw-root .fw-view-agents .fw-seg .fw-glyph svg { width: 9px; height: 9px; stroke-width: 2.5; }
|
|
302
319
|
.fw-root:is(.fw-fill-muted, .fw-fill-outcome) .fw-view-agents :is(.fw-seg-alt.fw-seg-model, .fw-seg-alt.fw-seg-tool) { filter: brightness(.88); }
|
|
303
320
|
.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); }
|
|
304
321
|
/* 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. */
|
|
@@ -320,15 +337,15 @@
|
|
|
320
337
|
.fw-root .fw-links { position: absolute; top: 0; bottom: 0; left: var(--fw-label-col); right: 0; overflow: hidden; pointer-events: none; z-index: 0; }
|
|
321
338
|
.fw-root .fw-link {
|
|
322
339
|
--x: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px);
|
|
323
|
-
position: absolute; width:
|
|
340
|
+
position: absolute; width: 12px; border: 0 solid var(--line); border-bottom-width: 1.5px; translate: 0 var(--fw-bar-shift);
|
|
324
341
|
opacity: clamp(0, (var(--fw-t) - var(--s)) * 1000, 1);
|
|
325
342
|
}
|
|
326
343
|
.fw-root .fw-view-spans .fw-link { opacity: calc(clamp(0, (var(--fw-t) - var(--s)) * 1000, 1) * .7); }
|
|
327
344
|
/* Agent-view connectors rest faint, one curved elbow per spawn in the agent's hue (they show who started whom), and come to
|
|
328
345
|
full strength for the agent under the pointer, pinned or focused. */
|
|
329
|
-
.fw-root .fw-view-agents .fw-link:not(.fw-link-hot) { opacity: calc(clamp(0, (var(--fw-t) - var(--s)) * 1000, 1) * .
|
|
346
|
+
.fw-root .fw-view-agents .fw-link:not(.fw-link-hot) { opacity: calc(clamp(0, (var(--fw-t) - var(--s)) * 1000, 1) * .8); }
|
|
330
347
|
.fw-root .fw-link { transition: opacity 160ms var(--fw-ease); }
|
|
331
|
-
.fw-root .fw-link-down { left: calc(var(--x) -
|
|
348
|
+
.fw-root .fw-link-down { left: calc(var(--x) - 12px); border-left-width: 1.5px; border-bottom-left-radius: 12px; }
|
|
332
349
|
.fw-root .fw-link-up { left: var(--x); border-right-width: 1.5px; border-bottom-right-radius: 12px; }
|
|
333
350
|
.fw-root .fw-link::before { content: ""; position: absolute; top: -3.5px; width: 5px; height: 5px; border-radius: 50%; background: var(--line); box-shadow: 0 0 0 1.5px var(--fw-surface); }
|
|
334
351
|
.fw-root .fw-link-down::before { left: -3.25px; }
|
package/dist/react/index.d.ts
CHANGED
|
@@ -373,6 +373,90 @@ interface DotMapProps {
|
|
|
373
373
|
export declare const DOT_MAP_CATEGORIES: readonly string[];
|
|
374
374
|
export declare function DotMap({ positions, radii, colors, palette, extent, rects, labels, dimmed, selected, minPixelRadius, onHover, onSelect, describe, height, ariaLabel }: DotMapProps): import("react").JSX.Element;
|
|
375
375
|
//#endregion
|
|
376
|
+
//#region src/react/flow-waterfall-model.d.ts
|
|
377
|
+
/** A minimap mark on a parent row: merged descendant activity of one kind. */
|
|
378
|
+
interface FlowSegment {
|
|
379
|
+
startMs: number;
|
|
380
|
+
/** Infinity while running; the presentation clips it at the clock. */
|
|
381
|
+
endMs: number;
|
|
382
|
+
kind: 'model' | 'tool' | 'failed';
|
|
383
|
+
tone: number;
|
|
384
|
+
/** The first span merged into this mark, and how many were merged. */
|
|
385
|
+
id: string;
|
|
386
|
+
count: number;
|
|
387
|
+
retry: boolean;
|
|
388
|
+
/** In a family row, every other member's marks take a darker shade of the family's one hue. */
|
|
389
|
+
alt?: boolean;
|
|
390
|
+
/** The first merged span's name, e.g. a tool's: shown in the segment's tooltip, and in the bar when one step fits it. */
|
|
391
|
+
name?: string;
|
|
392
|
+
/** The tool every merged step shares (the name before " · "); undefined once the merged steps differ. */
|
|
393
|
+
tool?: string;
|
|
394
|
+
/** What the merged steps cost, when any of them recorded a cost. */
|
|
395
|
+
costUsd?: number;
|
|
396
|
+
/** A failed mark that was a model call, so it draws the model's icon and no tool name. */
|
|
397
|
+
modelCall?: boolean;
|
|
398
|
+
}
|
|
399
|
+
/** A row's direct steps: model and tool calls (failed ones included), the failed and retrying ones, and tool calls by tool. */
|
|
400
|
+
interface StepCounts {
|
|
401
|
+
model: number;
|
|
402
|
+
tool: number;
|
|
403
|
+
failed: number;
|
|
404
|
+
retried: number;
|
|
405
|
+
tools: Record<string, number>;
|
|
406
|
+
}
|
|
407
|
+
/** Tokens in, out and cached; a field nobody recorded stays undefined. */
|
|
408
|
+
interface TokenCounts {
|
|
409
|
+
prompt?: number;
|
|
410
|
+
completion?: number;
|
|
411
|
+
cached?: number;
|
|
412
|
+
}
|
|
413
|
+
interface FlowWaterfallRow {
|
|
414
|
+
id: string;
|
|
415
|
+
parentId?: string;
|
|
416
|
+
name: string;
|
|
417
|
+
kind: FlowSpan['kind'];
|
|
418
|
+
durationLabel: string;
|
|
419
|
+
approx: boolean;
|
|
420
|
+
ok: boolean;
|
|
421
|
+
depth: number;
|
|
422
|
+
hasChildren: boolean;
|
|
423
|
+
span: FlowSpan;
|
|
424
|
+
/** Agent hue: the index of the nearest pipeline ancestor (or self), in first-start order. */
|
|
425
|
+
tone: number;
|
|
426
|
+
/** All descendants, for the collapsed "+N" count. */
|
|
427
|
+
descendants: number;
|
|
428
|
+
/** Parent rows only: merged descendant activity, drawn as the row's minimap. */
|
|
429
|
+
segments: FlowSegment[];
|
|
430
|
+
/** Direct non-agent children: the row's own thinking and tool work, drawn over its waiting extent. */
|
|
431
|
+
own: FlowSegment[];
|
|
432
|
+
/** Direct steps counted from the spans, before marks merge for display (merging depends on zoom). */
|
|
433
|
+
counts?: StepCounts;
|
|
434
|
+
/** Durations of its finished direct model calls, ascending: the card's latency. */
|
|
435
|
+
modelMs?: number[];
|
|
436
|
+
/** The span's own tokens, else the sum of its children's, as its cost rolls up. */
|
|
437
|
+
tokens?: TokenCounts;
|
|
438
|
+
/** Its cost is a floor ("≥"): its own bound, its trace's, or a family with unpriced members. */
|
|
439
|
+
costFloor?: boolean;
|
|
440
|
+
/** The span retries a failed one; its bar carries a retry glyph. */
|
|
441
|
+
retry: boolean;
|
|
442
|
+
/** The row delegates to child agents, so the gaps in its own work are waiting. */
|
|
443
|
+
hasAgents: boolean;
|
|
444
|
+
/** Recorded cost of the row and its descendants, only when every model call below it has a recorded cost. */
|
|
445
|
+
rollupCostUsd?: number;
|
|
446
|
+
/** Agent view: the family row this agent belongs to, when agents sharing a role are folded together. */
|
|
447
|
+
family?: string;
|
|
448
|
+
/** Agent view: the agent whose steps this row is, shown nested under it. */
|
|
449
|
+
stepOf?: string;
|
|
450
|
+
/** Agent view: indent level (members under a family, steps under an agent). */
|
|
451
|
+
inset?: number;
|
|
452
|
+
}
|
|
453
|
+
/** Hierarchy only; presentation owns geometry.
|
|
454
|
+
* Orphaned parents become roots; cycles are broken without dropping any span. */
|
|
455
|
+
export declare function flowWaterfallRows(trace: FlowTrace, resolutionMs?: number): FlowWaterfallRow[];
|
|
456
|
+
/** The chain of steps that gates the trace's end: from each root, descend into the latest-ending child until a leaf; the root whose
|
|
457
|
+
* chain ends last wins. Cutting latency anywhere else leaves the trace's end unchanged. */
|
|
458
|
+
export declare function criticalPathIds(rows: readonly FlowWaterfallRow[]): ReadonlySet<string>;
|
|
459
|
+
//#endregion
|
|
376
460
|
//#region src/react/flow-waterfall-row.d.ts
|
|
377
461
|
type FlowView = 'spans' | 'agents';
|
|
378
462
|
//#endregion
|
|
@@ -436,4 +520,4 @@ interface FlowWaterfallProps {
|
|
|
436
520
|
* Data remains producer-owned; playback, zoom and folding change presentation only. */
|
|
437
521
|
export declare function FlowWaterfall({ trace, live, startedAt, label, defaultCollapsed, defaultView, renderIcon, maxHeight, onSelect, markers, onTimeChange, agentFill: fillProp, selectedId, onDeselect, description, summary: showSummary, criticalPath, query: queryProp, onQueryChange, collapsed: collapsedProp, onCollapsedChange, zoom: zoomProp, onZoomChange, matchSpan }: FlowWaterfallProps): import("react").JSX.Element;
|
|
438
522
|
//#endregion
|
|
439
|
-
export type { BandKind, ChartBand, ChartMark, DotMapLabel, DotMapProps, DotMapRect, Figure, FigureAtWidth, FigureViewProps, FlowWaterfallProps, ViewWindow as FlowWaterfallWindow, GapBand, GapProps, LineSeries, MarkKind, MarkVerdict, MarkerShape, MeterSegment, PointFields, PointGlyph, Refusal, SparklineDirection, SparklineGeometry, SparklineGeometryOptions, SparklineLabelOptions, SparklinePoint, SparklineProps, SparklineValues, StackedBarBucket, StackedBarChartProps, StackedBarSegment, StackedBarSeries, TickOutcome, TimelineLane, TimelineOptions, TimelineSpan, TimelineTick, TimelineViewProps, WaterfallBarProps, WaterfallHeaderProps, WaterfallRowProps, WaterfallSpanGeometry, WaterfallTimeAxisProps, WaterfallWindow, XCategory, YScale, YTarget, YTick };
|
|
523
|
+
export type { BandKind, ChartBand, ChartMark, DotMapLabel, DotMapProps, DotMapRect, Figure, FigureAtWidth, FigureViewProps, FlowWaterfallProps, FlowWaterfallRow, ViewWindow as FlowWaterfallWindow, GapBand, GapProps, LineSeries, MarkKind, MarkVerdict, MarkerShape, MeterSegment, PointFields, PointGlyph, Refusal, SparklineDirection, SparklineGeometry, SparklineGeometryOptions, SparklineLabelOptions, SparklinePoint, SparklineProps, SparklineValues, StackedBarBucket, StackedBarChartProps, StackedBarSegment, StackedBarSeries, TickOutcome, TimelineLane, TimelineOptions, TimelineSpan, TimelineTick, TimelineViewProps, WaterfallBarProps, WaterfallHeaderProps, WaterfallRowProps, WaterfallSpanGeometry, WaterfallTimeAxisProps, WaterfallWindow, XCategory, YScale, YTarget, YTick };
|
package/dist/react/index.js
CHANGED
|
@@ -2476,6 +2476,7 @@ function mergeSegments(marks, gapMs, cap = 240) {
|
|
|
2476
2476
|
last.endMs = Math.max(last.endMs, mark.endMs);
|
|
2477
2477
|
last.count += mark.count;
|
|
2478
2478
|
if (last.tool !== mark.tool) last.tool = void 0;
|
|
2479
|
+
if (mark.costUsd !== void 0) last.costUsd = (last.costUsd ?? 0) + mark.costUsd;
|
|
2479
2480
|
last.kind = share.model >= share.tool ? "model" : "tool";
|
|
2480
2481
|
} else out.push({ ...mark });
|
|
2481
2482
|
}
|
|
@@ -2656,7 +2657,9 @@ function segmentOf(row) {
|
|
|
2656
2657
|
count: 1,
|
|
2657
2658
|
retry: row.retry,
|
|
2658
2659
|
name: row.name,
|
|
2659
|
-
tool: toolOf(row.name)
|
|
2660
|
+
tool: toolOf(row.name),
|
|
2661
|
+
...row.span.costUsd === void 0 ? {} : { costUsd: row.span.costUsd },
|
|
2662
|
+
...!row.ok && row.kind === "model" ? { modelCall: true } : {}
|
|
2660
2663
|
};
|
|
2661
2664
|
}
|
|
2662
2665
|
/** The rows a search term matches by themselves, before ancestor context is added. */
|
|
@@ -3374,25 +3377,51 @@ const at = (startMs, endMs) => ({
|
|
|
3374
3377
|
});
|
|
3375
3378
|
const endLabelWidth = (label, slowest, costliest) => label.length * 7 + 8 + (slowest ? 80 : 0) + (costliest ? 90 : 0);
|
|
3376
3379
|
function Segment({ mark, events, agentView, ending }) {
|
|
3377
|
-
const glyph = mark.kind === "failed" ? agentView && !ending ? null :
|
|
3378
|
-
const
|
|
3379
|
-
|
|
3380
|
+
const glyph = mark.kind === "failed" ? agentView && !ending ? null : "fail" : mark.retry ? "retry" : null;
|
|
3381
|
+
const model = mark.kind === "model" || mark.modelCall;
|
|
3382
|
+
const name = model ? void 0 : mark.count === 1 ? mark.name : mark.tool;
|
|
3383
|
+
const duration = Number.isFinite(mark.endMs) ? formatSpanDuration(mark.endMs - mark.startMs) : "";
|
|
3384
|
+
const meta = [duration, mark.costUsd ? formatCost(mark.costUsd) : ""].filter(Boolean).join(" · ");
|
|
3385
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
3380
3386
|
className: `fw-seg fw-seg-${mark.kind}${mark.alt ? " fw-seg-alt" : ""}`,
|
|
3381
3387
|
"data-tone": toneKey(mark.tone),
|
|
3382
3388
|
style: at(mark.startMs, mark.endMs),
|
|
3383
|
-
title: mark.name ? `${mark.name}${mark.count > 1 ? ` +${mark.count - 1} more` : ""}` : void 0,
|
|
3389
|
+
title: mark.name ? `${mark.name}${mark.count > 1 ? ` +${mark.count - 1} more` : ""}${meta ? ` · ${meta}` : ""}` : void 0,
|
|
3384
3390
|
onPointerEnter: agentView ? (event) => events.onInspect(mark.id, event.currentTarget, event.clientX) : void 0,
|
|
3385
3391
|
onClick: agentView ? (event) => {
|
|
3386
3392
|
event.stopPropagation();
|
|
3387
3393
|
events.onPin(mark.id, event.currentTarget, event.clientX);
|
|
3388
3394
|
} : void 0,
|
|
3389
|
-
children: glyph
|
|
3395
|
+
children: [glyph && /* @__PURE__ */ jsx("span", {
|
|
3390
3396
|
className: "fw-glyph",
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3397
|
+
"data-glyph": glyph,
|
|
3398
|
+
children: glyph === "fail" ? /* @__PURE__ */ jsx(FailGlyph, {}) : /* @__PURE__ */ jsx(RetryGlyph, {})
|
|
3399
|
+
}), agentView && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3400
|
+
/* @__PURE__ */ jsx("span", {
|
|
3401
|
+
className: "fw-seg-icon",
|
|
3402
|
+
"aria-hidden": true,
|
|
3403
|
+
children: /* @__PURE__ */ jsx(KindGlyph, {
|
|
3404
|
+
kind: model ? "model" : "tool",
|
|
3405
|
+
name: mark.tool ?? mark.name
|
|
3406
|
+
})
|
|
3407
|
+
}),
|
|
3408
|
+
name && /* @__PURE__ */ jsx("span", {
|
|
3409
|
+
className: "fw-seg-name",
|
|
3410
|
+
children: name
|
|
3411
|
+
}),
|
|
3412
|
+
mark.count > 1 && /* @__PURE__ */ jsxs("span", {
|
|
3413
|
+
className: "fw-seg-chip",
|
|
3414
|
+
children: ["×", mark.count]
|
|
3415
|
+
}),
|
|
3416
|
+
duration && /* @__PURE__ */ jsx("span", {
|
|
3417
|
+
className: "fw-seg-meta",
|
|
3418
|
+
children: duration
|
|
3419
|
+
}),
|
|
3420
|
+
mark.costUsd ? /* @__PURE__ */ jsx("span", {
|
|
3421
|
+
className: "fw-seg-meta fw-seg-cost",
|
|
3422
|
+
children: formatCost(mark.costUsd)
|
|
3423
|
+
}) : null
|
|
3424
|
+
] })]
|
|
3396
3425
|
});
|
|
3397
3426
|
}
|
|
3398
3427
|
/** A span the clock is inside: it grows live, or playback has not reached its end. */
|
|
@@ -3418,7 +3447,7 @@ const FlowRow = memo(function FlowRow(props) {
|
|
|
3418
3447
|
const kind = !row.ok ? "failed" : row.kind;
|
|
3419
3448
|
const marks = isAgent || row.hasChildren || row.id.startsWith("run:") ? folded && !agentView ? row.segments : row.own : [];
|
|
3420
3449
|
const label = endLabel(row, clockMs);
|
|
3421
|
-
const summary = [...span.detail && span.detail !== props.sharedDetail ? [span.detail] : [], ...agentSummary(row)];
|
|
3450
|
+
const summary = [...span.detail && span.detail !== props.sharedDetail ? [span.detail] : [], ...agentSummary(row).filter((part) => part !== props.sharedOutcome)];
|
|
3422
3451
|
const inspect = (event) => props.onInspect(row.id, event.currentTarget, event.clientX);
|
|
3423
3452
|
const family = agentView && row.id.startsWith("family:");
|
|
3424
3453
|
const step = agentView && row.stepOf !== void 0;
|
|
@@ -3554,6 +3583,11 @@ const FlowRow = memo(function FlowRow(props) {
|
|
|
3554
3583
|
"aria-label": `${row.descendants} hidden steps`,
|
|
3555
3584
|
children: ["+", row.descendants]
|
|
3556
3585
|
}),
|
|
3586
|
+
family && !props.expanded && /* @__PURE__ */ jsxs("span", {
|
|
3587
|
+
className: "fw-count",
|
|
3588
|
+
"aria-label": `${row.descendants} agents folded`,
|
|
3589
|
+
children: ["+", row.descendants]
|
|
3590
|
+
}),
|
|
3557
3591
|
!row.ok && !agentView && /* @__PURE__ */ jsx("span", {
|
|
3558
3592
|
className: "fw-alert",
|
|
3559
3593
|
children: /* @__PURE__ */ jsx(AlertGlyph, { label: "failed" })
|
|
@@ -3622,7 +3656,7 @@ const FlowRow = memo(function FlowRow(props) {
|
|
|
3622
3656
|
] })
|
|
3623
3657
|
})]
|
|
3624
3658
|
});
|
|
3625
|
-
}, (a, b) => a.row === b.row && a.view === b.view && a.top === b.top && a.collapsed === b.collapsed && a.searching === b.searching && a.slowest === b.slowest && a.costliest === b.costliest && a.critical === b.critical && a.matched === b.matched && a.active === b.active && a.focusable === b.focusable && a.selected === b.selected && a.sticky === b.sticky && a.motion === b.motion && a.renderIcon === b.renderIcon && a.fillByAgent === b.fillByAgent && a.sharedDetail === b.sharedDetail && a.expanded === b.expanded && (a.clockMs === b.clockMs || !open(a.row, a.clockMs) && !open(b.row, b.clockMs)));
|
|
3659
|
+
}, (a, b) => a.row === b.row && a.view === b.view && a.top === b.top && a.collapsed === b.collapsed && a.searching === b.searching && a.slowest === b.slowest && a.costliest === b.costliest && a.critical === b.critical && a.matched === b.matched && a.active === b.active && a.focusable === b.focusable && a.selected === b.selected && a.sticky === b.sticky && a.motion === b.motion && a.renderIcon === b.renderIcon && a.fillByAgent === b.fillByAgent && a.sharedDetail === b.sharedDetail && a.sharedOutcome === b.sharedOutcome && a.expanded === b.expanded && (a.clockMs === b.clockMs || !open(a.row, a.clockMs) && !open(b.row, b.clockMs)));
|
|
3626
3660
|
/** An elbow connector between two rows at one moment, drawn in the row's tone; appears when the clock reaches it. */
|
|
3627
3661
|
function LinkMark({ link, rowHeight, hot }) {
|
|
3628
3662
|
const upper = Math.min(link.from, link.to), lower = Math.max(link.from, link.to);
|
|
@@ -4095,6 +4129,7 @@ function FlowBody(props) {
|
|
|
4095
4129
|
renderIcon: props.renderIcon,
|
|
4096
4130
|
fillByAgent: props.fillByAgent,
|
|
4097
4131
|
sharedDetail: props.sharedDetail,
|
|
4132
|
+
sharedOutcome: props.sharedOutcome,
|
|
4098
4133
|
expanded: props.expandedIds?.has(item.id),
|
|
4099
4134
|
onToggle: props.onToggle,
|
|
4100
4135
|
onInspect: props.onInspect,
|
|
@@ -4481,6 +4516,13 @@ function useHostable(value, onChange, initial) {
|
|
|
4481
4516
|
}, [controlled])];
|
|
4482
4517
|
}
|
|
4483
4518
|
const CARD_WIDTH = 320;
|
|
4519
|
+
/** The value at least half of several agents share, if one does. */
|
|
4520
|
+
function usual(values) {
|
|
4521
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4522
|
+
for (const value of values) if (value) counts.set(value, (counts.get(value) ?? 0) + 1);
|
|
4523
|
+
const [top, n] = [...counts].sort((a, b) => b[1] - a[1])[0] ?? [];
|
|
4524
|
+
return values.length > 1 && n !== void 0 && n >= 2 && n * 2 >= values.length ? top : void 0;
|
|
4525
|
+
}
|
|
4484
4526
|
/** The summary strip: as of the playhead while scrubbing, the producer's totals otherwise. */
|
|
4485
4527
|
function summaryCells(trace, at, durationMs) {
|
|
4486
4528
|
const cost = costSummary(at ? at.costUsd : trace.costUsd, trace);
|
|
@@ -4658,8 +4700,8 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
4658
4700
|
const pipelines = rows.filter((row) => row.kind === "pipeline");
|
|
4659
4701
|
return pipelines.length ? pipelines : rows.filter((row) => !row.parentId);
|
|
4660
4702
|
}, [rows]);
|
|
4661
|
-
const
|
|
4662
|
-
const
|
|
4703
|
+
const sharedDetail = usual(agents.map((row) => row.span.detail));
|
|
4704
|
+
const sharedOutcome = usual(agents.map((row) => row.span.outcome?.label));
|
|
4663
4705
|
const [flippedFamilies, setFlippedFamilies] = useState(/* @__PURE__ */ new Set());
|
|
4664
4706
|
const openFamilies = useMemo(() => defaultOpenFamilies(agents, UNFOLD_ROWS, flippedFamilies), [agents, flippedFamilies]);
|
|
4665
4707
|
const [openSteps, setOpenSteps] = useState(/* @__PURE__ */ new Set());
|
|
@@ -4982,7 +5024,7 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
4982
5024
|
agents.length,
|
|
4983
5025
|
" ",
|
|
4984
5026
|
agents.length === 1 ? "agent" : "agents",
|
|
4985
|
-
sharedDetail ? ` · ${sharedDetail}` : "",
|
|
5027
|
+
sharedDetail ? ` · ${agents.every((row) => row.span.detail === sharedDetail) ? "" : "mostly "}${sharedDetail}` : "",
|
|
4986
5028
|
done && speedup >= 1.05 ? ` · ${speedup.toFixed(1)}x parallel` : ""
|
|
4987
5029
|
]
|
|
4988
5030
|
}),
|
|
@@ -5068,6 +5110,7 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
5068
5110
|
pauses: trace.pauses,
|
|
5069
5111
|
cursorLine: position !== null || playing,
|
|
5070
5112
|
sharedDetail,
|
|
5113
|
+
sharedOutcome,
|
|
5071
5114
|
expandedIds: view === "agents" ? /* @__PURE__ */ new Set([...openFamilies, ...openSteps]) : void 0,
|
|
5072
5115
|
holdHeight: isLive,
|
|
5073
5116
|
slowestId: slowest?.id ?? callouts.slowestId,
|
|
@@ -5125,4 +5168,4 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
5125
5168
|
});
|
|
5126
5169
|
}
|
|
5127
5170
|
//#endregion
|
|
5128
|
-
export { DEFAULT_SPARKLINE_EMPTY_LABEL, DEFAULT_SPARKLINE_HEIGHT, DEFAULT_SPARKLINE_LABEL, DEFAULT_SPARKLINE_UNAVAILABLE_LABEL, DEFAULT_SPARKLINE_WIDTH, DOT_MAP_CATEGORIES, DayBars, DotMap, Events, FigureView, FlowWaterfall, Gantt, Gap, HBars, Histogram, LIVE_SERIES, Lines, Meter, Spark, Sparkline, StackedBarChart, TimelineView, WaterfallBar, WaterfallHeader, WaterfallRow, WaterfallTimeAxis, formatCompact, formatSparklineValue, formatWaterfallDuration, sparklineGeometry, sparklineLabel, sparklinePointsAttribute, sparklineReadings, waterfallSpanGeometry, waterfallTicks };
|
|
5171
|
+
export { DEFAULT_SPARKLINE_EMPTY_LABEL, DEFAULT_SPARKLINE_HEIGHT, DEFAULT_SPARKLINE_LABEL, DEFAULT_SPARKLINE_UNAVAILABLE_LABEL, DEFAULT_SPARKLINE_WIDTH, DOT_MAP_CATEGORIES, DayBars, DotMap, Events, FigureView, FlowWaterfall, Gantt, Gap, HBars, Histogram, LIVE_SERIES, Lines, Meter, Spark, Sparkline, StackedBarChart, TimelineView, WaterfallBar, WaterfallHeader, WaterfallRow, WaterfallTimeAxis, criticalPathIds, flowWaterfallRows, formatCompact, formatSparklineValue, formatWaterfallDuration, sparklineGeometry, sparklineLabel, sparklinePointsAttribute, sparklineReadings, waterfallSpanGeometry, waterfallTicks };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/charts",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.18",
|
|
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",
|