@circuitwall/jarela 0.9.3 → 0.10.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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +2 -2
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +2 -2
- package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/v1/dashboard/metrics/route.js +72 -5
- package/.next/standalone/.next/server/app/api/v1/dashboard/metrics/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/extensions/route.js +2 -2
- package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/secrets/route.js +2 -2
- package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/run/route.js +136 -26
- package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/run/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/tools/route.js +2 -2
- package/.next/standalone/.next/server/app/index.html +2 -2
- package/.next/standalone/.next/server/app/index.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page.js +266 -40
- package/.next/standalone/.next/server/app/page.js.map +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/setup.html +1 -1
- package/.next/standalone/.next/server/app/setup.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/setup.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/setup.segments/setup.segment.rsc +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +2 -2
- package/.next/standalone/.next/server/chunks/210.js +1 -1
- package/.next/standalone/.next/server/chunks/2151.js +60 -2
- package/.next/standalone/.next/server/chunks/2151.js.map +1 -1
- package/.next/standalone/.next/server/chunks/614.js +336 -93
- package/.next/standalone/.next/server/chunks/614.js.map +1 -1
- package/.next/standalone/.next/server/chunks/6765.js +35 -0
- package/.next/standalone/.next/server/chunks/6765.js.map +1 -1
- package/.next/standalone/.next/server/chunks/8697.js +15246 -15002
- package/.next/standalone/.next/server/chunks/8697.js.map +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +2 -2
- package/.next/standalone/.next/server/pages/404.html +2 -2
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/{3741-344e2bfc5028b9c8.js → 3741-2d64471ff763b8fa.js} +36 -1
- package/.next/standalone/.next/static/chunks/3741-2d64471ff763b8fa.js.map +1 -0
- package/.next/standalone/.next/static/chunks/app/{page-c77ab600642bbfc2.js → page-318743bf47fac345.js} +267 -41
- package/.next/standalone/.next/static/chunks/app/page-318743bf47fac345.js.map +1 -0
- package/.next/standalone/.next/static/css/b6b85b0f13bc0e98.css +5 -0
- package/.next/standalone/.next/static/css/b6b85b0f13bc0e98.css.map +1 -0
- package/.next/standalone/package.json +1 -1
- package/CHANGELOG.md +48 -0
- package/README.md +2 -0
- package/api/client.ts +37 -1
- package/api/types.ts +18 -0
- package/app/api/v1/threads/[thread_id]/run/route.ts +69 -22
- package/components/agents/AgentEditor.tsx +7 -4
- package/components/chat/MessageBubble.tsx +108 -1
- package/components/dashboard/DashboardPanel.tsx +79 -21
- package/hooks/useSSE.ts +22 -9
- package/lib/agents/prepare/system-prompt.ts +30 -0
- package/lib/agents/run-registry.test.ts +94 -0
- package/lib/agents/run-registry.ts +60 -1
- package/lib/stores/dashboard-metrics.test.ts +33 -0
- package/lib/stores/dashboard-metrics.ts +93 -1
- package/lib/tools/exec.ts +9 -5
- package/lib/tools/files.ts +6 -0
- package/lib/tools/safety.test.ts +95 -0
- package/lib/tools/safety.ts +147 -0
- package/package.json +1 -1
- package/.next/standalone/.next/static/chunks/3741-344e2bfc5028b9c8.js.map +0 -1
- package/.next/standalone/.next/static/chunks/app/page-c77ab600642bbfc2.js.map +0 -1
- package/.next/standalone/.next/static/css/53f85613a5500253.css +0 -5
- package/.next/standalone/.next/static/css/53f85613a5500253.css.map +0 -1
- /package/.next/standalone/.next/static/{6uLoytvvEtLKIblEB53e0 → 8qTBpUDFnSMYwe3Zc0bGV}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{6uLoytvvEtLKIblEB53e0 → 8qTBpUDFnSMYwe3Zc0bGV}/_ssgManifest.js +0 -0
|
@@ -2434,13 +2434,23 @@ function useSSE(onDone) {
|
|
|
2434
2434
|
if (err.name !== "AbortError") {
|
|
2435
2435
|
setError(String(err));
|
|
2436
2436
|
}
|
|
2437
|
-
setStreaming(false);
|
|
2438
|
-
setStreamingContent("");
|
|
2439
|
-
setThinkingContent("");
|
|
2440
|
-
closeActivity();
|
|
2441
2437
|
return {
|
|
2442
2438
|
accepted: false
|
|
2443
2439
|
};
|
|
2440
|
+
} finally{
|
|
2441
|
+
// Always release the gate when the stream ends — defends against the
|
|
2442
|
+
// consume() loop returning without ever observing a terminal `done`
|
|
2443
|
+
// event (e.g. the EventSource closed cleanly with zero events). If
|
|
2444
|
+
// we relied solely on the `done` branch inside consume(), the chat
|
|
2445
|
+
// would stay locked behind the Stop button forever.
|
|
2446
|
+
//
|
|
2447
|
+
// We intentionally do NOT clear streamingContent / thinkingContent
|
|
2448
|
+
// here — the consumer (ChatView) swaps them for the persisted
|
|
2449
|
+
// assistant bubble once the refetch lands; clearing now would yank
|
|
2450
|
+
// the text out from under the user. The next start()/attach() resets
|
|
2451
|
+
// them.
|
|
2452
|
+
setStreaming(false);
|
|
2453
|
+
closeActivity();
|
|
2444
2454
|
}
|
|
2445
2455
|
}, [
|
|
2446
2456
|
consume,
|
|
@@ -2493,15 +2503,18 @@ function useSSE(onDone) {
|
|
|
2493
2503
|
try {
|
|
2494
2504
|
await consume((0,client/* subscribeRun */._C)(threadId, ctrl.signal));
|
|
2495
2505
|
} catch (err) {
|
|
2496
|
-
// Attach failures are non-fatal — clear the gate and let the consumer
|
|
2497
|
-
// drain anything queued during session load. The common case is
|
|
2498
|
-
// "no run to attach to" (server returns 404, EventSource fails to
|
|
2499
|
-
// open) — completely normal when navigating into an idle session.
|
|
2500
|
-
setStreaming(false);
|
|
2501
|
-
closeActivity();
|
|
2502
2506
|
if (err.name !== "AbortError") {
|
|
2503
2507
|
onDone?.();
|
|
2504
2508
|
}
|
|
2509
|
+
} finally{
|
|
2510
|
+
// Always release the optimistic gate when the stream ends — whether
|
|
2511
|
+
// via terminal `done`/`error` event, a thrown failure, or a clean
|
|
2512
|
+
// EventSource close with no events (idle thread, server returned 404
|
|
2513
|
+
// so the iterator exited without yielding). Without this, navigating
|
|
2514
|
+
// into an idle thread leaves streaming=true forever: the Stop button
|
|
2515
|
+
// hangs in the composer and the "Reconnecting…" badge never clears.
|
|
2516
|
+
setStreaming(false);
|
|
2517
|
+
closeActivity();
|
|
2505
2518
|
}
|
|
2506
2519
|
}, [
|
|
2507
2520
|
consume,
|
|
@@ -32860,6 +32873,123 @@ function UserAvatar({ profile }) {
|
|
|
32860
32873
|
// lines at the top of every bubble. Format is fixed by dispatcher; if either
|
|
32861
32874
|
// side changes, update both.
|
|
32862
32875
|
const parseBridgeContext = parseBridgePrompt;
|
|
32876
|
+
const SILENT_TRIGGER_RE = /\n+\[SILENT_TRIGGER\][^\n]*(?:\n(?!\n).*)*$/;
|
|
32877
|
+
// Strip the `[SILENT_TRIGGER] …` envelope that runTriggerAgent appends
|
|
32878
|
+
// in silent mode so the card can render the user's original prompt and
|
|
32879
|
+
// surface a separate "Silent" pill instead of leaking framework prose.
|
|
32880
|
+
function stripSilentEnvelope(text) {
|
|
32881
|
+
const m = SILENT_TRIGGER_RE.exec(text);
|
|
32882
|
+
if (!m) return {
|
|
32883
|
+
text,
|
|
32884
|
+
silent: false
|
|
32885
|
+
};
|
|
32886
|
+
return {
|
|
32887
|
+
text: text.slice(0, m.index).trimEnd(),
|
|
32888
|
+
silent: true
|
|
32889
|
+
};
|
|
32890
|
+
}
|
|
32891
|
+
function parseTriggerMessage(category, raw) {
|
|
32892
|
+
if (category === "scheduled_task") {
|
|
32893
|
+
const { text, silent } = stripSilentEnvelope(raw);
|
|
32894
|
+
return {
|
|
32895
|
+
kind: "scheduled_task",
|
|
32896
|
+
prompt: text,
|
|
32897
|
+
silent
|
|
32898
|
+
};
|
|
32899
|
+
}
|
|
32900
|
+
if (category === "watcher") {
|
|
32901
|
+
const { text, silent } = stripSilentEnvelope(raw);
|
|
32902
|
+
const headerRe = /^Watcher\s+"([^"]*)"\s+detected a change\.\s*\n+Tool:\s*([^\n]+)\s*\nArgs:\s*([\s\S]*?)\n+---\s*Diff[^\n]*---\s*\n([\s\S]*?)\n\n([\s\S]*)$/;
|
|
32903
|
+
const m = headerRe.exec(text);
|
|
32904
|
+
if (!m) return null;
|
|
32905
|
+
return {
|
|
32906
|
+
kind: "watcher",
|
|
32907
|
+
label: m[1],
|
|
32908
|
+
tool: m[2].trim(),
|
|
32909
|
+
args: m[3].trim(),
|
|
32910
|
+
diff: m[4].trim(),
|
|
32911
|
+
directive: m[5].trim(),
|
|
32912
|
+
silent
|
|
32913
|
+
};
|
|
32914
|
+
}
|
|
32915
|
+
return null;
|
|
32916
|
+
}
|
|
32917
|
+
// Compact header card for trigger-originated user messages (scheduled
|
|
32918
|
+
// tasks + watchers, ADR-0027/ADR-0032). Surfaces the trigger type with
|
|
32919
|
+
// an icon + label so the operator can tell at a glance that the prompt
|
|
32920
|
+
// came from automation and not from them. Watchers additionally expose
|
|
32921
|
+
// the diff context in a collapsed section to keep large diffs out of
|
|
32922
|
+
// the main bubble height.
|
|
32923
|
+
function TriggerMessageCard({ data }) {
|
|
32924
|
+
const [diffOpen, setDiffOpen] = (0,react.useState)(false);
|
|
32925
|
+
const Icon = data.kind === "scheduled_task" ? Clock : eye/* default */.A;
|
|
32926
|
+
const label = data.kind === "scheduled_task" ? "Scheduled task" : `Watcher: ${data.label || "(unnamed)"}`;
|
|
32927
|
+
return /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", {
|
|
32928
|
+
className: "flex flex-col gap-1.5 min-w-0",
|
|
32929
|
+
children: [
|
|
32930
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", {
|
|
32931
|
+
className: "flex items-center gap-1.5 text-[11px] text-white/85 min-w-0",
|
|
32932
|
+
children: [
|
|
32933
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)(Icon, {
|
|
32934
|
+
size: 11,
|
|
32935
|
+
className: "shrink-0"
|
|
32936
|
+
}),
|
|
32937
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", {
|
|
32938
|
+
className: "font-medium truncate",
|
|
32939
|
+
children: label
|
|
32940
|
+
}),
|
|
32941
|
+
data.kind === "watcher" && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", {
|
|
32942
|
+
className: "px-1.5 py-0.5 rounded-full bg-white/15 text-[9.5px] uppercase tracking-wide shrink-0",
|
|
32943
|
+
children: data.tool
|
|
32944
|
+
}),
|
|
32945
|
+
data.silent && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", {
|
|
32946
|
+
className: "flex items-center gap-1 px-1.5 py-0.5 rounded-full bg-white/15 text-[9.5px] uppercase tracking-wide shrink-0",
|
|
32947
|
+
title: "Silent trigger: reply only if material",
|
|
32948
|
+
children: [
|
|
32949
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)(EyeOff, {
|
|
32950
|
+
size: 9
|
|
32951
|
+
}),
|
|
32952
|
+
"silent"
|
|
32953
|
+
]
|
|
32954
|
+
})
|
|
32955
|
+
]
|
|
32956
|
+
}),
|
|
32957
|
+
data.kind === "watcher" && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", {
|
|
32958
|
+
type: "button",
|
|
32959
|
+
onClick: ()=>setDiffOpen((v)=>!v),
|
|
32960
|
+
className: "flex items-center gap-1 text-left text-[11px] text-white/75 hover:text-white/95",
|
|
32961
|
+
"aria-expanded": diffOpen,
|
|
32962
|
+
title: diffOpen ? "Hide diff" : "Show diff",
|
|
32963
|
+
children: [
|
|
32964
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)(ChevronRight, {
|
|
32965
|
+
size: 11,
|
|
32966
|
+
className: `shrink-0 transition-transform ${diffOpen ? "rotate-90" : ""}`
|
|
32967
|
+
}),
|
|
32968
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", {
|
|
32969
|
+
children: "Change context"
|
|
32970
|
+
})
|
|
32971
|
+
]
|
|
32972
|
+
}),
|
|
32973
|
+
data.kind === "watcher" && diffOpen && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", {
|
|
32974
|
+
className: "ml-4 flex flex-col gap-1",
|
|
32975
|
+
children: [
|
|
32976
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("pre", {
|
|
32977
|
+
className: "m-0 px-2 py-1.5 rounded bg-black/25 text-[11px] leading-snug whitespace-pre-wrap break-words text-white/90 max-h-72 overflow-auto",
|
|
32978
|
+
children: data.args
|
|
32979
|
+
}),
|
|
32980
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("pre", {
|
|
32981
|
+
className: "m-0 px-2 py-1.5 rounded bg-black/25 text-[11px] leading-snug whitespace-pre-wrap break-words text-white/90 max-h-96 overflow-auto",
|
|
32982
|
+
children: data.diff
|
|
32983
|
+
})
|
|
32984
|
+
]
|
|
32985
|
+
}),
|
|
32986
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", {
|
|
32987
|
+
className: "whitespace-pre-wrap text-[13.5px] leading-relaxed",
|
|
32988
|
+
children: data.kind === "scheduled_task" ? data.prompt : data.directive
|
|
32989
|
+
})
|
|
32990
|
+
]
|
|
32991
|
+
});
|
|
32992
|
+
}
|
|
32863
32993
|
// Compact header card for inbound bridge messages. Shows sender + chat
|
|
32864
32994
|
// context as a single line of metadata above the actual message text, so a
|
|
32865
32995
|
// WhatsApp DM looks like "Alice • DM\n<text>" and a group message looks
|
|
@@ -33667,6 +33797,11 @@ const MessageBubble = /*#__PURE__*/ (0,react.memo)(function MessageBubble({ mess
|
|
|
33667
33797
|
className: `rounded-2xl px-4 py-3 text-sm leading-relaxed max-w-full overflow-hidden ${isUser ? "glass-bubble-accent text-white rounded-br-sm" : "glass-bubble text-fg rounded-bl-sm"}`,
|
|
33668
33798
|
children: [
|
|
33669
33799
|
typeof parsed === "string" ? isUser ? (()=>{
|
|
33800
|
+
const category = "category" in message ? message.category : null;
|
|
33801
|
+
const trigger = parseTriggerMessage(category, parsed);
|
|
33802
|
+
if (trigger) return /*#__PURE__*/ (0,react_jsx_runtime.jsx)(TriggerMessageCard, {
|
|
33803
|
+
data: trigger
|
|
33804
|
+
});
|
|
33670
33805
|
const bridge = parseBridgeContext(parsed);
|
|
33671
33806
|
if (bridge) return /*#__PURE__*/ (0,react_jsx_runtime.jsx)(BridgeMessageCard, {
|
|
33672
33807
|
ctx: bridge
|
|
@@ -40569,7 +40704,9 @@ function ToolGroupBlock({ group, categories, advancedMode, selected, onToggleToo
|
|
|
40569
40704
|
const selectedInGroup = allTools.filter((t)=>selected.includes(t.name)).length;
|
|
40570
40705
|
const allOn = selectedInGroup === allTools.length;
|
|
40571
40706
|
const someOn = selectedInGroup > 0 && !allOn;
|
|
40572
|
-
|
|
40707
|
+
// Collapsed by default to keep the editor compact on small / PWA viewports;
|
|
40708
|
+
// the header still surfaces the selected/total count.
|
|
40709
|
+
const [open, setOpen] = (0,react.useState)(false);
|
|
40573
40710
|
const headerRef = (0,react.useRef)(null);
|
|
40574
40711
|
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{
|
|
40575
40712
|
if (headerRef.current) headerRef.current.indeterminate = someOn;
|
|
@@ -40599,13 +40736,14 @@ function ToolGroupBlock({ group, categories, advancedMode, selected, onToggleToo
|
|
|
40599
40736
|
}
|
|
40600
40737
|
// Collapsible per-category block with a tri-state header checkbox. The
|
|
40601
40738
|
// header toggle flips the entire category on/off; individual tool checkboxes
|
|
40602
|
-
// stay available for fine-grained control. Collapsed
|
|
40603
|
-
//
|
|
40739
|
+
// stay available for fine-grained control. Collapsed by default to keep the
|
|
40740
|
+
// editor short on mobile / PWA viewports.
|
|
40604
40741
|
function ToolCategoryBlock({ category, tools, advancedMode, selected, onToggleTool, onToggleCategory, onToggleCategoryPermission }) {
|
|
40605
40742
|
const selectedInCat = tools.filter((t)=>selected.includes(t.name)).length;
|
|
40606
40743
|
const allOn = selectedInCat === tools.length;
|
|
40607
40744
|
const someOn = selectedInCat > 0 && !allOn;
|
|
40608
|
-
|
|
40745
|
+
// Collapsed by default — see ToolGroupBlock comment.
|
|
40746
|
+
const [open, setOpen] = (0,react.useState)(false);
|
|
40609
40747
|
const headerRef = (0,react.useRef)(null);
|
|
40610
40748
|
// Render the tri-state indeterminate dash via the DOM property (React
|
|
40611
40749
|
// doesn't expose it as a JSX attribute).
|
|
@@ -52043,20 +52181,6 @@ function DashboardPanel() {
|
|
|
52043
52181
|
className: "text-[11px] text-[var(--text-secondary)]",
|
|
52044
52182
|
children: currencyInfo.source === "manual" ? `Currency manually set to ${currencyInfo.currency}.` : currencyInfo.source === "location" ? `Currency converted from USD to ${currencyInfo.currency} based on saved location.` : "Currency defaults to USD because no location-based currency is available."
|
|
52045
52183
|
}),
|
|
52046
|
-
/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("section", {
|
|
52047
|
-
className: "rounded-2xl border border-[var(--border)] bg-[var(--bg-secondary)]/90 p-4 shadow-sm",
|
|
52048
|
-
children: [
|
|
52049
|
-
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("h3", {
|
|
52050
|
-
className: "text-sm font-medium text-[var(--text-primary)] mb-3",
|
|
52051
|
-
children: "Token usage over time"
|
|
52052
|
-
}),
|
|
52053
|
-
/*#__PURE__*/ (0,react_jsx_runtime.jsx)(InteractiveTokenChart, {
|
|
52054
|
-
series: series,
|
|
52055
|
-
selectedDay: selectedDay,
|
|
52056
|
-
onSelectDay: (day)=>setSelectedDay((prev)=>prev === day ? null : day)
|
|
52057
|
-
})
|
|
52058
|
-
]
|
|
52059
|
-
}),
|
|
52060
52184
|
/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("section", {
|
|
52061
52185
|
className: "rounded-2xl border border-[var(--border)] bg-[var(--bg-secondary)]/90 p-4 shadow-sm",
|
|
52062
52186
|
children: [
|
|
@@ -52065,7 +52189,7 @@ function DashboardPanel() {
|
|
|
52065
52189
|
children: [
|
|
52066
52190
|
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("h3", {
|
|
52067
52191
|
className: "text-sm font-medium text-[var(--text-primary)]",
|
|
52068
|
-
children: "
|
|
52192
|
+
children: "Tokens & cost over time"
|
|
52069
52193
|
}),
|
|
52070
52194
|
selectedDay ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", {
|
|
52071
52195
|
type: "button",
|
|
@@ -52086,11 +52210,19 @@ function DashboardPanel() {
|
|
|
52086
52210
|
})
|
|
52087
52211
|
]
|
|
52088
52212
|
}),
|
|
52089
|
-
/*#__PURE__*/ (0,react_jsx_runtime.jsx)(
|
|
52213
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)(InteractiveTokenChart, {
|
|
52090
52214
|
series: series,
|
|
52091
|
-
currencyInfo: currencyInfo,
|
|
52092
52215
|
selectedDay: selectedDay,
|
|
52093
52216
|
onSelectDay: (day)=>setSelectedDay((prev)=>prev === day ? null : day)
|
|
52217
|
+
}),
|
|
52218
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", {
|
|
52219
|
+
className: "mt-3 border-t border-[var(--border)]/60 pt-3",
|
|
52220
|
+
children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)(InteractiveCostChart, {
|
|
52221
|
+
series: series,
|
|
52222
|
+
currencyInfo: currencyInfo,
|
|
52223
|
+
selectedDay: selectedDay,
|
|
52224
|
+
onSelectDay: (day)=>setSelectedDay((prev)=>prev === day ? null : day)
|
|
52225
|
+
})
|
|
52094
52226
|
})
|
|
52095
52227
|
]
|
|
52096
52228
|
}),
|
|
@@ -52485,6 +52617,13 @@ function InsightChip({ label, value, hint }) {
|
|
|
52485
52617
|
]
|
|
52486
52618
|
});
|
|
52487
52619
|
}
|
|
52620
|
+
// Per-tier breakdown colors shared by the stacked token chart legend.
|
|
52621
|
+
const TIER_COLORS = {
|
|
52622
|
+
hot: "#22d3ee",
|
|
52623
|
+
warm: "#f59e0b",
|
|
52624
|
+
facts: "#a78bfa",
|
|
52625
|
+
overhead: "#94a3b8"
|
|
52626
|
+
};
|
|
52488
52627
|
function SharedDonutChart({ ariaLabel, size, centerAmount, slices, hovered, onHoverChange }) {
|
|
52489
52628
|
const uid = (0,react.useId)().replace(/:/g, "");
|
|
52490
52629
|
const [animCycle, setAnimCycle] = (0,react.useState)(0);
|
|
@@ -52894,6 +53033,15 @@ function InteractiveTokenChart({ series, selectedDay, onSelectDay }) {
|
|
|
52894
53033
|
const totalHeight = hasData && maxTotal > 0 ? Math.max(4, Math.round(total / maxTotal * 150)) : 0;
|
|
52895
53034
|
const inputHeight = hasData ? Math.round(point.input_tokens_est / total * totalHeight) : 0;
|
|
52896
53035
|
const outputHeight = hasData ? Math.max(0, totalHeight - inputHeight) : 0;
|
|
53036
|
+
// Subdivide the input portion by measured tier breakdown when the
|
|
53037
|
+
// day has at least one snapshotted assistant turn. Legacy days
|
|
53038
|
+
// (measured_input_tokens === 0) fall back to a solid violet block.
|
|
53039
|
+
const tier = point.tier_tokens;
|
|
53040
|
+
const tierTotal = tier?.measured_input_tokens ?? 0;
|
|
53041
|
+
const hotPx = tierTotal > 0 ? Math.round(tier.hot_tokens / tierTotal * inputHeight) : 0;
|
|
53042
|
+
const warmPx = tierTotal > 0 ? Math.round(tier.warm_tokens / tierTotal * inputHeight) : 0;
|
|
53043
|
+
const factsPx = tierTotal > 0 ? Math.round(tier.facts_tokens / tierTotal * inputHeight) : 0;
|
|
53044
|
+
const overheadPx = tierTotal > 0 ? Math.max(0, inputHeight - hotPx - warmPx - factsPx) : 0;
|
|
52897
53045
|
const isActive = idx === hovered;
|
|
52898
53046
|
const isSelected = selectedDay === point.day;
|
|
52899
53047
|
const clickable = !!onSelectDay && hasData;
|
|
@@ -52924,7 +53072,42 @@ function InteractiveTokenChart({ series, selectedDay, onSelectDay }) {
|
|
|
52924
53072
|
transition: `height 420ms cubic-bezier(0.2, 0.8, 0.2, 1) ${idx * 18}ms`
|
|
52925
53073
|
}
|
|
52926
53074
|
}),
|
|
52927
|
-
/*#__PURE__*/ (0,react_jsx_runtime.
|
|
53075
|
+
tierTotal > 0 ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, {
|
|
53076
|
+
children: [
|
|
53077
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", {
|
|
53078
|
+
className: "w-full",
|
|
53079
|
+
style: {
|
|
53080
|
+
background: TIER_COLORS.hot,
|
|
53081
|
+
height: barsReady ? `${hotPx}px` : "0px",
|
|
53082
|
+
transition: `height 420ms cubic-bezier(0.2, 0.8, 0.2, 1) ${idx * 18 + 30}ms`
|
|
53083
|
+
}
|
|
53084
|
+
}),
|
|
53085
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", {
|
|
53086
|
+
className: "w-full",
|
|
53087
|
+
style: {
|
|
53088
|
+
background: TIER_COLORS.warm,
|
|
53089
|
+
height: barsReady ? `${warmPx}px` : "0px",
|
|
53090
|
+
transition: `height 420ms cubic-bezier(0.2, 0.8, 0.2, 1) ${idx * 18 + 42}ms`
|
|
53091
|
+
}
|
|
53092
|
+
}),
|
|
53093
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", {
|
|
53094
|
+
className: "w-full",
|
|
53095
|
+
style: {
|
|
53096
|
+
background: TIER_COLORS.facts,
|
|
53097
|
+
height: barsReady ? `${factsPx}px` : "0px",
|
|
53098
|
+
transition: `height 420ms cubic-bezier(0.2, 0.8, 0.2, 1) ${idx * 18 + 54}ms`
|
|
53099
|
+
}
|
|
53100
|
+
}),
|
|
53101
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", {
|
|
53102
|
+
className: "w-full",
|
|
53103
|
+
style: {
|
|
53104
|
+
background: TIER_COLORS.overhead,
|
|
53105
|
+
height: barsReady ? `${overheadPx}px` : "0px",
|
|
53106
|
+
transition: `height 420ms cubic-bezier(0.2, 0.8, 0.2, 1) ${idx * 18 + 66}ms`
|
|
53107
|
+
}
|
|
53108
|
+
})
|
|
53109
|
+
]
|
|
53110
|
+
}) : /*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", {
|
|
52928
53111
|
className: "w-full bg-gradient-to-t from-indigo-500 to-violet-400",
|
|
52929
53112
|
style: {
|
|
52930
53113
|
height: barsReady ? `${inputHeight}px` : "0px",
|
|
@@ -52947,13 +53130,61 @@ function InteractiveTokenChart({ series, selectedDay, onSelectDay }) {
|
|
|
52947
53130
|
/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", {
|
|
52948
53131
|
className: "mt-2 flex flex-wrap items-center gap-3 text-[11px] text-[var(--text-secondary)]",
|
|
52949
53132
|
children: [
|
|
53133
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", {
|
|
53134
|
+
className: "inline-flex items-center gap-1",
|
|
53135
|
+
children: [
|
|
53136
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", {
|
|
53137
|
+
className: "w-2 h-2 rounded-sm",
|
|
53138
|
+
style: {
|
|
53139
|
+
background: TIER_COLORS.hot
|
|
53140
|
+
}
|
|
53141
|
+
}),
|
|
53142
|
+
"hot"
|
|
53143
|
+
]
|
|
53144
|
+
}),
|
|
53145
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", {
|
|
53146
|
+
className: "inline-flex items-center gap-1",
|
|
53147
|
+
children: [
|
|
53148
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", {
|
|
53149
|
+
className: "w-2 h-2 rounded-sm",
|
|
53150
|
+
style: {
|
|
53151
|
+
background: TIER_COLORS.warm
|
|
53152
|
+
}
|
|
53153
|
+
}),
|
|
53154
|
+
"warm"
|
|
53155
|
+
]
|
|
53156
|
+
}),
|
|
53157
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", {
|
|
53158
|
+
className: "inline-flex items-center gap-1",
|
|
53159
|
+
children: [
|
|
53160
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", {
|
|
53161
|
+
className: "w-2 h-2 rounded-sm",
|
|
53162
|
+
style: {
|
|
53163
|
+
background: TIER_COLORS.facts
|
|
53164
|
+
}
|
|
53165
|
+
}),
|
|
53166
|
+
"facts"
|
|
53167
|
+
]
|
|
53168
|
+
}),
|
|
53169
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", {
|
|
53170
|
+
className: "inline-flex items-center gap-1",
|
|
53171
|
+
children: [
|
|
53172
|
+
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", {
|
|
53173
|
+
className: "w-2 h-2 rounded-sm",
|
|
53174
|
+
style: {
|
|
53175
|
+
background: TIER_COLORS.overhead
|
|
53176
|
+
}
|
|
53177
|
+
}),
|
|
53178
|
+
"overhead"
|
|
53179
|
+
]
|
|
53180
|
+
}),
|
|
52950
53181
|
/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", {
|
|
52951
53182
|
className: "inline-flex items-center gap-1",
|
|
52952
53183
|
children: [
|
|
52953
53184
|
/*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", {
|
|
52954
53185
|
className: "w-2 h-2 rounded-full bg-violet-400"
|
|
52955
53186
|
}),
|
|
52956
|
-
"input"
|
|
53187
|
+
"input (est)"
|
|
52957
53188
|
]
|
|
52958
53189
|
}),
|
|
52959
53190
|
/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", {
|
|
@@ -52965,14 +53196,9 @@ function InteractiveTokenChart({ series, selectedDay, onSelectDay }) {
|
|
|
52965
53196
|
"output"
|
|
52966
53197
|
]
|
|
52967
53198
|
}),
|
|
52968
|
-
active && /*#__PURE__*/ (0,react_jsx_runtime.
|
|
53199
|
+
active && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", {
|
|
52969
53200
|
className: "ml-auto text-[var(--text-primary)]",
|
|
52970
|
-
children:
|
|
52971
|
-
"in ",
|
|
52972
|
-
formatInt(active.input_tokens_est),
|
|
52973
|
-
" \xb7 out ",
|
|
52974
|
-
formatInt(active.output_tokens_est)
|
|
52975
|
-
]
|
|
53201
|
+
children: active.tier_tokens.measured_input_tokens > 0 ? `hot ${formatInt(active.tier_tokens.hot_tokens)} · warm ${formatInt(active.tier_tokens.warm_tokens)} · facts ${formatInt(active.tier_tokens.facts_tokens)} · overhead ${formatInt(active.tier_tokens.overhead_tokens)} · out ${formatInt(active.output_tokens_est)}` : `in ${formatInt(active.input_tokens_est)} · out ${formatInt(active.output_tokens_est)}`
|
|
52976
53202
|
})
|
|
52977
53203
|
]
|
|
52978
53204
|
})
|