@tangle-network/charts 0.21.0 → 0.21.2
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.
|
@@ -323,6 +323,8 @@ interface FlowSpan {
|
|
|
323
323
|
icon?: string;
|
|
324
324
|
/** Recorded values only. Absent means unknown and is shown as Unknown, never as zero. */
|
|
325
325
|
costUsd?: number;
|
|
326
|
+
/** `lower`: `costUsd` is a floor and prints "≥". Spans inherit a trace's `costBound: 'lower'`. */
|
|
327
|
+
costBound?: 'lower' | 'upper';
|
|
326
328
|
promptTokens?: number;
|
|
327
329
|
completionTokens?: number;
|
|
328
330
|
/** Short producer summaries shown in the span card. */
|
|
@@ -354,7 +356,10 @@ interface FlowSpanMark {
|
|
|
354
356
|
interface FlowPause {
|
|
355
357
|
startMs: number;
|
|
356
358
|
endMs: number;
|
|
359
|
+
/** A few words on the band, such as 'Paused 4 h 40 m'. */
|
|
357
360
|
label: string;
|
|
361
|
+
/** The full reason, shown on hover and focus of the label rather than printed across the rows. */
|
|
362
|
+
detail?: string;
|
|
358
363
|
}
|
|
359
364
|
/** A host verdict: `label` is the legend text, `tone` the status color. */
|
|
360
365
|
interface FlowOutcome {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as BreakdownInput, B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, H as Tier, I as Interval, L as IntervalMethod, M as CostBasis, N as Estimate, O as YTarget, P as Exclusion, R as MatrixCell, S as ChartMark, T as MarkerShape, U as TierCounts, V as Setup, W as isRefusal, _ as checkerColor, a as TimelineLane, b as BandKind, c as TimelineTick, d as ENDING_COLORS, f as ENDING_ORDER, g as TickOutcome, h as RunEnding, i as FlowTrace, j as ComparisonRow, k as YTick, l as timeline, m as OUTCOME_ORDER, n as FlowOutcome, o as TimelineOptions, p as OUTCOME_COLORS, r as FlowSpan, s as TimelineSpan, t as FlowMarker, u as CHECKER_HUES, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph, z as RateRow } from "./flow-trace-
|
|
1
|
+
import { A as BreakdownInput, B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, H as Tier, I as Interval, L as IntervalMethod, M as CostBasis, N as Estimate, O as YTarget, P as Exclusion, R as MatrixCell, S as ChartMark, T as MarkerShape, U as TierCounts, V as Setup, W as isRefusal, _ as checkerColor, a as TimelineLane, b as BandKind, c as TimelineTick, d as ENDING_COLORS, f as ENDING_ORDER, g as TickOutcome, h as RunEnding, i as FlowTrace, j as ComparisonRow, k as YTick, l as timeline, m as OUTCOME_ORDER, n as FlowOutcome, o as TimelineOptions, p as OUTCOME_COLORS, r as FlowSpan, s as TimelineSpan, t as FlowMarker, u as CHECKER_HUES, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph, z as RateRow } from "./flow-trace-DBJY1YAA.js";
|
|
2
2
|
//#region src/block.d.ts
|
|
3
3
|
interface RenderFigureOptions {
|
|
4
4
|
/** Chart uses a closed data disclosure; plot keeps only the SVG and accessible data. */
|
|
@@ -132,6 +132,8 @@
|
|
|
132
132
|
border-inline: 1px dashed color-mix(in oklab, var(--fw-text) 24%, transparent); }
|
|
133
133
|
.fw-root .fw-pause-label { position: sticky; top: 4px; display: block; width: max-content; max-width: calc(100% - 8px); margin: 4px auto 0; padding: 0 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
134
134
|
border-radius: 4px; font-size: 12px; line-height: 20px; color: var(--fw-muted); background: var(--fw-surface); box-shadow: inset 0 0 0 1px var(--fw-border); }
|
|
135
|
+
/* The label alone takes the pointer, for its reason; the band stays click-through to the rows. */
|
|
136
|
+
.fw-root .fw-pause-label[title] { pointer-events: auto; cursor: help; }
|
|
135
137
|
.fw-root .fw-marker-label { position: absolute; top: 2px; left: 3px; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 4px; border-radius: 4px; font-size: 12px; line-height: 16px; color: var(--fw-marker); background: var(--fw-surface); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-marker) 40%, transparent); }
|
|
136
138
|
.fw-root .fw-marker-label-left { left: auto; right: 3px; }
|
|
137
139
|
.fw-root .fw-marker[data-tone="warn"], .fw-root .fw-event[data-tone="warn"] { --fw-marker: var(--fw-amber); }
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, O as YTarget, S as ChartMark, T as MarkerShape, a as TimelineLane, b as BandKind, c as TimelineTick, g as TickOutcome, i as FlowTrace, k as YTick, o as TimelineOptions, r as FlowSpan, s as TimelineSpan, t as FlowMarker, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph } from "../flow-trace-
|
|
1
|
+
import { B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, O as YTarget, S as ChartMark, T as MarkerShape, a as TimelineLane, b as BandKind, c as TimelineTick, g as TickOutcome, i as FlowTrace, k as YTick, o as TimelineOptions, r as FlowSpan, s as TimelineSpan, t as FlowMarker, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph } from "../flow-trace-DBJY1YAA.js";
|
|
2
2
|
import { CSSProperties, ReactElement, ReactNode } from "react";
|
|
3
3
|
//#region src/react/sparkline.d.ts
|
|
4
4
|
type SparklineDirection = "rising" | "falling" | "flat";
|
package/dist/react/index.js
CHANGED
|
@@ -2509,7 +2509,8 @@ function flowWaterfallRows(trace, resolutionMs) {
|
|
|
2509
2509
|
segments: [],
|
|
2510
2510
|
own: [],
|
|
2511
2511
|
retry: span.retryOf !== void 0,
|
|
2512
|
-
hasAgents: false
|
|
2512
|
+
hasAgents: false,
|
|
2513
|
+
...span.costBound === "lower" || span.costBound === void 0 && trace.costBound === "lower" ? { costFloor: true } : {}
|
|
2513
2514
|
};
|
|
2514
2515
|
});
|
|
2515
2516
|
const byId = new Map(rows.map((row) => [row.id, row]));
|
|
@@ -2628,13 +2629,16 @@ function slowestRow(rows, clockMs) {
|
|
|
2628
2629
|
}
|
|
2629
2630
|
/** The agents a reader should look at first: the longest one by the clock, and the costliest when two or more are priced. */
|
|
2630
2631
|
function agentCallouts(agents, clockMs) {
|
|
2631
|
-
let slowest, slowestMs = -1, costliest, top = -1, priced = 0;
|
|
2632
|
+
let slowest, slowestMs = -1, costliest, top = -1, priced = 0, timed = 0;
|
|
2632
2633
|
for (const row of agents) {
|
|
2633
2634
|
if (row.durationLabel === "—" || row.span.startMs > clockMs) continue;
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
slowestMs
|
|
2635
|
+
if (row.kind === "pipeline" && row.parentId !== void 0) {
|
|
2636
|
+
const ms = (spanRunning(row.span) ? Math.max(row.span.endMs, clockMs) : Math.min(row.span.endMs, clockMs)) - row.span.startMs;
|
|
2637
|
+
timed += 1;
|
|
2638
|
+
if (ms > slowestMs) {
|
|
2639
|
+
slowest = row;
|
|
2640
|
+
slowestMs = ms;
|
|
2641
|
+
}
|
|
2638
2642
|
}
|
|
2639
2643
|
const cost = row.span.costUsd ?? row.rollupCostUsd;
|
|
2640
2644
|
if (cost === void 0) continue;
|
|
@@ -2645,7 +2649,7 @@ function agentCallouts(agents, clockMs) {
|
|
|
2645
2649
|
}
|
|
2646
2650
|
}
|
|
2647
2651
|
return {
|
|
2648
|
-
slowestId:
|
|
2652
|
+
slowestId: timed > 1 ? slowest?.id : void 0,
|
|
2649
2653
|
costliestId: priced > 1 && top > 0 ? costliest?.id : void 0
|
|
2650
2654
|
};
|
|
2651
2655
|
}
|
|
@@ -2745,6 +2749,7 @@ function agentFamilies(agents, open) {
|
|
|
2745
2749
|
const known = members.map((row) => row.span.costUsd ?? row.rollupCostUsd).filter((cost) => cost !== void 0);
|
|
2746
2750
|
const failed = members.filter((row) => !row.ok).length;
|
|
2747
2751
|
out.push({
|
|
2752
|
+
costFloor: known.length < members.length || members.some((row) => row.costFloor),
|
|
2748
2753
|
id,
|
|
2749
2754
|
parentId: members[0].parentId,
|
|
2750
2755
|
name: `${role} ×${members.length}`,
|
|
@@ -2903,6 +2908,8 @@ function drawnRow(row, visible) {
|
|
|
2903
2908
|
tone: family.tone
|
|
2904
2909
|
} : row;
|
|
2905
2910
|
}
|
|
2911
|
+
/** A row's cost as printed: "≥" when it is a floor. */
|
|
2912
|
+
const rowCostText = (row, cost) => `${row.costFloor ? "≥" : ""}${formatCost(cost)}`;
|
|
2906
2913
|
//#endregion
|
|
2907
2914
|
//#region src/react/flow-waterfall-icons.tsx
|
|
2908
2915
|
const svg = (children, label) => /* @__PURE__ */ jsx("svg", {
|
|
@@ -3086,7 +3093,7 @@ function SpanCard({ id, row, agent, clockMs, left, top, pinned, onClose, renderI
|
|
|
3086
3093
|
for (const fact of (subject.facts ?? []).slice(0, 3)) cells.push([fact.label, fact.value]);
|
|
3087
3094
|
cells.push(["Started", `+${formatSpanDuration(Math.max(0, subject.startMs))}`]);
|
|
3088
3095
|
if (tokenCount !== void 0) cells.push(["Tokens", count(tokenCount)]);
|
|
3089
|
-
if (cost !== void 0) cells.push(["Cost",
|
|
3096
|
+
if (cost !== void 0) cells.push(["Cost", rowCostText(who, cost)]);
|
|
3090
3097
|
cells.splice(6);
|
|
3091
3098
|
const kind = span.kind === "model" ? "Thinking" : KIND_LABEL[span.kind];
|
|
3092
3099
|
const step = owner && span.endMs > span.startMs ? `${kind}${span.name && span.name !== kind && span.name.toLowerCase() !== span.kind ? ` ${span.name}` : ""} · ${duration}${row.ok ? "" : " · failed"}` : void 0;
|
|
@@ -3233,7 +3240,7 @@ function SpanCard({ id, row, agent, clockMs, left, top, pinned, onClose, renderI
|
|
|
3233
3240
|
children: [
|
|
3234
3241
|
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: "Duration" }), /* @__PURE__ */ jsx("dd", { children: duration })] }),
|
|
3235
3242
|
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: "Started" }), /* @__PURE__ */ jsxs("dd", { children: ["+", formatSpanDuration(Math.max(0, span.startMs))] })] }),
|
|
3236
|
-
span.costUsd !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: "Cost" }), /* @__PURE__ */ jsx("dd", { children:
|
|
3243
|
+
span.costUsd !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: "Cost" }), /* @__PURE__ */ jsx("dd", { children: rowCostText(row, span.costUsd) })] }),
|
|
3237
3244
|
tokens && span.promptTokens !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: "Tokens in" }), /* @__PURE__ */ jsx("dd", { children: count(span.promptTokens) })] }),
|
|
3238
3245
|
tokens && span.completionTokens !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: "Tokens out" }), /* @__PURE__ */ jsx("dd", { children: count(span.completionTokens) })] }),
|
|
3239
3246
|
(span.facts ?? []).slice(0, 3).map((fact) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: fact.label }), /* @__PURE__ */ jsx("dd", { children: fact.value })] }, fact.label)),
|
|
@@ -3287,11 +3294,11 @@ const open = (row, clockMs) => spanRunning(row.span) || row.span.startMs <= cloc
|
|
|
3287
3294
|
function endLabel(row, clockMs) {
|
|
3288
3295
|
const span = row.span;
|
|
3289
3296
|
if (row.durationLabel === "—") return "—";
|
|
3290
|
-
if (row.approx && span.endMs === span.startMs && !spanRunning(span)) return span.costUsd === void 0 ? "" :
|
|
3297
|
+
if (row.approx && span.endMs === span.startMs && !spanRunning(span)) return span.costUsd === void 0 ? "" : rowCostText(row, span.costUsd);
|
|
3291
3298
|
if (!spanRunning(span) && clockMs < span.endMs) return `${formatSpanDuration(Math.max(0, clockMs - span.startMs))}${row.approx ? "~" : ""}`;
|
|
3292
3299
|
const duration = spanRunning(span) ? `${formatSpanDuration(Math.max(span.endMs, clockMs) - span.startMs)}${row.approx ? "~" : ""}` : row.durationLabel;
|
|
3293
3300
|
const cost = span.costUsd ?? (row.rollupCostUsd ? row.rollupCostUsd : void 0);
|
|
3294
|
-
return cost === void 0 ? duration : `${duration} · ${
|
|
3301
|
+
return cost === void 0 ? duration : `${duration} · ${rowCostText(row, cost)}`;
|
|
3295
3302
|
}
|
|
3296
3303
|
/** One trace row. Geometry comes from CSS variables, so a row re-renders only when its own state changes. */
|
|
3297
3304
|
const FlowRow = memo(function FlowRow(props) {
|
|
@@ -3893,6 +3900,10 @@ function FlowBody(props) {
|
|
|
3893
3900
|
"aria-pressed": jumped === marker,
|
|
3894
3901
|
onPointerDown: (event) => event.stopPropagation(),
|
|
3895
3902
|
onClick: () => {
|
|
3903
|
+
if (jumped === marker) {
|
|
3904
|
+
setJumped(void 0);
|
|
3905
|
+
return;
|
|
3906
|
+
}
|
|
3896
3907
|
setJumped(marker);
|
|
3897
3908
|
props.onScrub(marker.at);
|
|
3898
3909
|
}
|
|
@@ -4002,6 +4013,9 @@ function FlowBody(props) {
|
|
|
4002
4013
|
title: pause.label,
|
|
4003
4014
|
children: /* @__PURE__ */ jsx("span", {
|
|
4004
4015
|
className: "fw-pause-label",
|
|
4016
|
+
title: pause.detail,
|
|
4017
|
+
tabIndex: pause.detail ? 0 : void 0,
|
|
4018
|
+
"aria-label": pause.detail ? `${pause.label}: ${pause.detail}` : void 0,
|
|
4005
4019
|
children: pause.label
|
|
4006
4020
|
})
|
|
4007
4021
|
}, `p-${pause.startMs}`)), props.markers?.map((marker) => /* @__PURE__ */ jsx("span", {
|
|
@@ -4636,6 +4650,10 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
4636
4650
|
return () => document.removeEventListener("pointermove", move);
|
|
4637
4651
|
}, [card, leave]);
|
|
4638
4652
|
latest.current.pin = (target, element) => {
|
|
4653
|
+
if (card?.pinned && card.target === target) {
|
|
4654
|
+
closeCard();
|
|
4655
|
+
return;
|
|
4656
|
+
}
|
|
4639
4657
|
place(target, element, true);
|
|
4640
4658
|
const row = byId.get(target);
|
|
4641
4659
|
if (row) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/charts",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.2",
|
|
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",
|