@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
|
@@ -928,13 +928,23 @@ function useSSE(onDone) {
|
|
|
928
928
|
if (err.name !== "AbortError") {
|
|
929
929
|
setError(String(err));
|
|
930
930
|
}
|
|
931
|
-
setStreaming(false);
|
|
932
|
-
setStreamingContent("");
|
|
933
|
-
setThinkingContent("");
|
|
934
|
-
closeActivity();
|
|
935
931
|
return {
|
|
936
932
|
accepted: false
|
|
937
933
|
};
|
|
934
|
+
} finally{
|
|
935
|
+
// Always release the gate when the stream ends — defends against the
|
|
936
|
+
// consume() loop returning without ever observing a terminal `done`
|
|
937
|
+
// event (e.g. the EventSource closed cleanly with zero events). If
|
|
938
|
+
// we relied solely on the `done` branch inside consume(), the chat
|
|
939
|
+
// would stay locked behind the Stop button forever.
|
|
940
|
+
//
|
|
941
|
+
// We intentionally do NOT clear streamingContent / thinkingContent
|
|
942
|
+
// here — the consumer (ChatView) swaps them for the persisted
|
|
943
|
+
// assistant bubble once the refetch lands; clearing now would yank
|
|
944
|
+
// the text out from under the user. The next start()/attach() resets
|
|
945
|
+
// them.
|
|
946
|
+
setStreaming(false);
|
|
947
|
+
closeActivity();
|
|
938
948
|
}
|
|
939
949
|
}, [
|
|
940
950
|
consume,
|
|
@@ -987,15 +997,18 @@ function useSSE(onDone) {
|
|
|
987
997
|
try {
|
|
988
998
|
await consume((0,client/* subscribeRun */._C)(threadId, ctrl.signal));
|
|
989
999
|
} catch (err) {
|
|
990
|
-
// Attach failures are non-fatal — clear the gate and let the consumer
|
|
991
|
-
// drain anything queued during session load. The common case is
|
|
992
|
-
// "no run to attach to" (server returns 404, EventSource fails to
|
|
993
|
-
// open) — completely normal when navigating into an idle session.
|
|
994
|
-
setStreaming(false);
|
|
995
|
-
closeActivity();
|
|
996
1000
|
if (err.name !== "AbortError") {
|
|
997
1001
|
onDone?.();
|
|
998
1002
|
}
|
|
1003
|
+
} finally{
|
|
1004
|
+
// Always release the optimistic gate when the stream ends — whether
|
|
1005
|
+
// via terminal `done`/`error` event, a thrown failure, or a clean
|
|
1006
|
+
// EventSource close with no events (idle thread, server returned 404
|
|
1007
|
+
// so the iterator exited without yielding). Without this, navigating
|
|
1008
|
+
// into an idle thread leaves streaming=true forever: the Stop button
|
|
1009
|
+
// hangs in the composer and the "Reconnecting…" badge never clears.
|
|
1010
|
+
setStreaming(false);
|
|
1011
|
+
closeActivity();
|
|
999
1012
|
}
|
|
1000
1013
|
}, [
|
|
1001
1014
|
consume,
|
|
@@ -2838,6 +2851,123 @@ function UserAvatar({ profile }) {
|
|
|
2838
2851
|
// lines at the top of every bubble. Format is fixed by dispatcher; if either
|
|
2839
2852
|
// side changes, update both.
|
|
2840
2853
|
const parseBridgeContext = parseBridgePrompt;
|
|
2854
|
+
const SILENT_TRIGGER_RE = /\n+\[SILENT_TRIGGER\][^\n]*(?:\n(?!\n).*)*$/;
|
|
2855
|
+
// Strip the `[SILENT_TRIGGER] …` envelope that runTriggerAgent appends
|
|
2856
|
+
// in silent mode so the card can render the user's original prompt and
|
|
2857
|
+
// surface a separate "Silent" pill instead of leaking framework prose.
|
|
2858
|
+
function stripSilentEnvelope(text) {
|
|
2859
|
+
const m = SILENT_TRIGGER_RE.exec(text);
|
|
2860
|
+
if (!m) return {
|
|
2861
|
+
text,
|
|
2862
|
+
silent: false
|
|
2863
|
+
};
|
|
2864
|
+
return {
|
|
2865
|
+
text: text.slice(0, m.index).trimEnd(),
|
|
2866
|
+
silent: true
|
|
2867
|
+
};
|
|
2868
|
+
}
|
|
2869
|
+
function parseTriggerMessage(category, raw) {
|
|
2870
|
+
if (category === "scheduled_task") {
|
|
2871
|
+
const { text, silent } = stripSilentEnvelope(raw);
|
|
2872
|
+
return {
|
|
2873
|
+
kind: "scheduled_task",
|
|
2874
|
+
prompt: text,
|
|
2875
|
+
silent
|
|
2876
|
+
};
|
|
2877
|
+
}
|
|
2878
|
+
if (category === "watcher") {
|
|
2879
|
+
const { text, silent } = stripSilentEnvelope(raw);
|
|
2880
|
+
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]*)$/;
|
|
2881
|
+
const m = headerRe.exec(text);
|
|
2882
|
+
if (!m) return null;
|
|
2883
|
+
return {
|
|
2884
|
+
kind: "watcher",
|
|
2885
|
+
label: m[1],
|
|
2886
|
+
tool: m[2].trim(),
|
|
2887
|
+
args: m[3].trim(),
|
|
2888
|
+
diff: m[4].trim(),
|
|
2889
|
+
directive: m[5].trim(),
|
|
2890
|
+
silent
|
|
2891
|
+
};
|
|
2892
|
+
}
|
|
2893
|
+
return null;
|
|
2894
|
+
}
|
|
2895
|
+
// Compact header card for trigger-originated user messages (scheduled
|
|
2896
|
+
// tasks + watchers, ADR-0027/ADR-0032). Surfaces the trigger type with
|
|
2897
|
+
// an icon + label so the operator can tell at a glance that the prompt
|
|
2898
|
+
// came from automation and not from them. Watchers additionally expose
|
|
2899
|
+
// the diff context in a collapsed section to keep large diffs out of
|
|
2900
|
+
// the main bubble height.
|
|
2901
|
+
function TriggerMessageCard({ data }) {
|
|
2902
|
+
const [diffOpen, setDiffOpen] = (0,react.useState)(false);
|
|
2903
|
+
const Icon = data.kind === "scheduled_task" ? clock/* default */.A : eye/* default */.A;
|
|
2904
|
+
const label = data.kind === "scheduled_task" ? "Scheduled task" : `Watcher: ${data.label || "(unnamed)"}`;
|
|
2905
|
+
return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
|
|
2906
|
+
className: "flex flex-col gap-1.5 min-w-0",
|
|
2907
|
+
children: [
|
|
2908
|
+
/*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
|
|
2909
|
+
className: "flex items-center gap-1.5 text-[11px] text-white/85 min-w-0",
|
|
2910
|
+
children: [
|
|
2911
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)(Icon, {
|
|
2912
|
+
size: 11,
|
|
2913
|
+
className: "shrink-0"
|
|
2914
|
+
}),
|
|
2915
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
|
|
2916
|
+
className: "font-medium truncate",
|
|
2917
|
+
children: label
|
|
2918
|
+
}),
|
|
2919
|
+
data.kind === "watcher" && /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
|
|
2920
|
+
className: "px-1.5 py-0.5 rounded-full bg-white/15 text-[9.5px] uppercase tracking-wide shrink-0",
|
|
2921
|
+
children: data.tool
|
|
2922
|
+
}),
|
|
2923
|
+
data.silent && /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
|
|
2924
|
+
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",
|
|
2925
|
+
title: "Silent trigger: reply only if material",
|
|
2926
|
+
children: [
|
|
2927
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)(eye_off/* default */.A, {
|
|
2928
|
+
size: 9
|
|
2929
|
+
}),
|
|
2930
|
+
"silent"
|
|
2931
|
+
]
|
|
2932
|
+
})
|
|
2933
|
+
]
|
|
2934
|
+
}),
|
|
2935
|
+
data.kind === "watcher" && /*#__PURE__*/ (0,jsx_runtime.jsxs)("button", {
|
|
2936
|
+
type: "button",
|
|
2937
|
+
onClick: ()=>setDiffOpen((v)=>!v),
|
|
2938
|
+
className: "flex items-center gap-1 text-left text-[11px] text-white/75 hover:text-white/95",
|
|
2939
|
+
"aria-expanded": diffOpen,
|
|
2940
|
+
title: diffOpen ? "Hide diff" : "Show diff",
|
|
2941
|
+
children: [
|
|
2942
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)(chevron_right/* default */.A, {
|
|
2943
|
+
size: 11,
|
|
2944
|
+
className: `shrink-0 transition-transform ${diffOpen ? "rotate-90" : ""}`
|
|
2945
|
+
}),
|
|
2946
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
|
|
2947
|
+
children: "Change context"
|
|
2948
|
+
})
|
|
2949
|
+
]
|
|
2950
|
+
}),
|
|
2951
|
+
data.kind === "watcher" && diffOpen && /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
|
|
2952
|
+
className: "ml-4 flex flex-col gap-1",
|
|
2953
|
+
children: [
|
|
2954
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("pre", {
|
|
2955
|
+
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",
|
|
2956
|
+
children: data.args
|
|
2957
|
+
}),
|
|
2958
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("pre", {
|
|
2959
|
+
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",
|
|
2960
|
+
children: data.diff
|
|
2961
|
+
})
|
|
2962
|
+
]
|
|
2963
|
+
}),
|
|
2964
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
|
|
2965
|
+
className: "whitespace-pre-wrap text-[13.5px] leading-relaxed",
|
|
2966
|
+
children: data.kind === "scheduled_task" ? data.prompt : data.directive
|
|
2967
|
+
})
|
|
2968
|
+
]
|
|
2969
|
+
});
|
|
2970
|
+
}
|
|
2841
2971
|
// Compact header card for inbound bridge messages. Shows sender + chat
|
|
2842
2972
|
// context as a single line of metadata above the actual message text, so a
|
|
2843
2973
|
// WhatsApp DM looks like "Alice • DM\n<text>" and a group message looks
|
|
@@ -3654,6 +3784,11 @@ const MessageBubble = /*#__PURE__*/ (0,react.memo)(function MessageBubble({ mess
|
|
|
3654
3784
|
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"}`,
|
|
3655
3785
|
children: [
|
|
3656
3786
|
typeof parsed === "string" ? isUser ? (()=>{
|
|
3787
|
+
const category = "category" in message ? message.category : null;
|
|
3788
|
+
const trigger = parseTriggerMessage(category, parsed);
|
|
3789
|
+
if (trigger) return /*#__PURE__*/ (0,jsx_runtime.jsx)(TriggerMessageCard, {
|
|
3790
|
+
data: trigger
|
|
3791
|
+
});
|
|
3657
3792
|
const bridge = parseBridgeContext(parsed);
|
|
3658
3793
|
if (bridge) return /*#__PURE__*/ (0,jsx_runtime.jsx)(BridgeMessageCard, {
|
|
3659
3794
|
ctx: bridge
|
|
@@ -10015,7 +10150,9 @@ function ToolGroupBlock({ group, categories, advancedMode, selected, onToggleToo
|
|
|
10015
10150
|
const selectedInGroup = allTools.filter((t)=>selected.includes(t.name)).length;
|
|
10016
10151
|
const allOn = selectedInGroup === allTools.length;
|
|
10017
10152
|
const someOn = selectedInGroup > 0 && !allOn;
|
|
10018
|
-
|
|
10153
|
+
// Collapsed by default to keep the editor compact on small / PWA viewports;
|
|
10154
|
+
// the header still surfaces the selected/total count.
|
|
10155
|
+
const [open, setOpen] = (0,react.useState)(false);
|
|
10019
10156
|
const headerRef = (0,react.useRef)(null);
|
|
10020
10157
|
(0,react.useEffect)(()=>{
|
|
10021
10158
|
if (headerRef.current) headerRef.current.indeterminate = someOn;
|
|
@@ -10045,13 +10182,14 @@ function ToolGroupBlock({ group, categories, advancedMode, selected, onToggleToo
|
|
|
10045
10182
|
}
|
|
10046
10183
|
// Collapsible per-category block with a tri-state header checkbox. The
|
|
10047
10184
|
// header toggle flips the entire category on/off; individual tool checkboxes
|
|
10048
|
-
// stay available for fine-grained control. Collapsed
|
|
10049
|
-
//
|
|
10185
|
+
// stay available for fine-grained control. Collapsed by default to keep the
|
|
10186
|
+
// editor short on mobile / PWA viewports.
|
|
10050
10187
|
function ToolCategoryBlock({ category, tools, advancedMode, selected, onToggleTool, onToggleCategory, onToggleCategoryPermission }) {
|
|
10051
10188
|
const selectedInCat = tools.filter((t)=>selected.includes(t.name)).length;
|
|
10052
10189
|
const allOn = selectedInCat === tools.length;
|
|
10053
10190
|
const someOn = selectedInCat > 0 && !allOn;
|
|
10054
|
-
|
|
10191
|
+
// Collapsed by default — see ToolGroupBlock comment.
|
|
10192
|
+
const [open, setOpen] = (0,react.useState)(false);
|
|
10055
10193
|
const headerRef = (0,react.useRef)(null);
|
|
10056
10194
|
// Render the tri-state indeterminate dash via the DOM property (React
|
|
10057
10195
|
// doesn't expose it as a JSX attribute).
|
|
@@ -20348,20 +20486,6 @@ function DashboardPanel() {
|
|
|
20348
20486
|
className: "text-[11px] text-[var(--text-secondary)]",
|
|
20349
20487
|
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."
|
|
20350
20488
|
}),
|
|
20351
|
-
/*#__PURE__*/ (0,jsx_runtime.jsxs)("section", {
|
|
20352
|
-
className: "rounded-2xl border border-[var(--border)] bg-[var(--bg-secondary)]/90 p-4 shadow-sm",
|
|
20353
|
-
children: [
|
|
20354
|
-
/*#__PURE__*/ (0,jsx_runtime.jsx)("h3", {
|
|
20355
|
-
className: "text-sm font-medium text-[var(--text-primary)] mb-3",
|
|
20356
|
-
children: "Token usage over time"
|
|
20357
|
-
}),
|
|
20358
|
-
/*#__PURE__*/ (0,jsx_runtime.jsx)(InteractiveTokenChart, {
|
|
20359
|
-
series: series,
|
|
20360
|
-
selectedDay: selectedDay,
|
|
20361
|
-
onSelectDay: (day)=>setSelectedDay((prev)=>prev === day ? null : day)
|
|
20362
|
-
})
|
|
20363
|
-
]
|
|
20364
|
-
}),
|
|
20365
20489
|
/*#__PURE__*/ (0,jsx_runtime.jsxs)("section", {
|
|
20366
20490
|
className: "rounded-2xl border border-[var(--border)] bg-[var(--bg-secondary)]/90 p-4 shadow-sm",
|
|
20367
20491
|
children: [
|
|
@@ -20370,7 +20494,7 @@ function DashboardPanel() {
|
|
|
20370
20494
|
children: [
|
|
20371
20495
|
/*#__PURE__*/ (0,jsx_runtime.jsx)("h3", {
|
|
20372
20496
|
className: "text-sm font-medium text-[var(--text-primary)]",
|
|
20373
|
-
children: "
|
|
20497
|
+
children: "Tokens & cost over time"
|
|
20374
20498
|
}),
|
|
20375
20499
|
selectedDay ? /*#__PURE__*/ (0,jsx_runtime.jsxs)("button", {
|
|
20376
20500
|
type: "button",
|
|
@@ -20391,11 +20515,19 @@ function DashboardPanel() {
|
|
|
20391
20515
|
})
|
|
20392
20516
|
]
|
|
20393
20517
|
}),
|
|
20394
|
-
/*#__PURE__*/ (0,jsx_runtime.jsx)(
|
|
20518
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)(InteractiveTokenChart, {
|
|
20395
20519
|
series: series,
|
|
20396
|
-
currencyInfo: currencyInfo,
|
|
20397
20520
|
selectedDay: selectedDay,
|
|
20398
20521
|
onSelectDay: (day)=>setSelectedDay((prev)=>prev === day ? null : day)
|
|
20522
|
+
}),
|
|
20523
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
|
|
20524
|
+
className: "mt-3 border-t border-[var(--border)]/60 pt-3",
|
|
20525
|
+
children: /*#__PURE__*/ (0,jsx_runtime.jsx)(InteractiveCostChart, {
|
|
20526
|
+
series: series,
|
|
20527
|
+
currencyInfo: currencyInfo,
|
|
20528
|
+
selectedDay: selectedDay,
|
|
20529
|
+
onSelectDay: (day)=>setSelectedDay((prev)=>prev === day ? null : day)
|
|
20530
|
+
})
|
|
20399
20531
|
})
|
|
20400
20532
|
]
|
|
20401
20533
|
}),
|
|
@@ -20790,6 +20922,13 @@ function InsightChip({ label, value, hint }) {
|
|
|
20790
20922
|
]
|
|
20791
20923
|
});
|
|
20792
20924
|
}
|
|
20925
|
+
// Per-tier breakdown colors shared by the stacked token chart legend.
|
|
20926
|
+
const TIER_COLORS = {
|
|
20927
|
+
hot: "#22d3ee",
|
|
20928
|
+
warm: "#f59e0b",
|
|
20929
|
+
facts: "#a78bfa",
|
|
20930
|
+
overhead: "#94a3b8"
|
|
20931
|
+
};
|
|
20793
20932
|
function SharedDonutChart({ ariaLabel, size, centerAmount, slices, hovered, onHoverChange }) {
|
|
20794
20933
|
const uid = (0,react.useId)().replace(/:/g, "");
|
|
20795
20934
|
const [animCycle, setAnimCycle] = (0,react.useState)(0);
|
|
@@ -21199,6 +21338,15 @@ function InteractiveTokenChart({ series, selectedDay, onSelectDay }) {
|
|
|
21199
21338
|
const totalHeight = hasData && maxTotal > 0 ? Math.max(4, Math.round(total / maxTotal * 150)) : 0;
|
|
21200
21339
|
const inputHeight = hasData ? Math.round(point.input_tokens_est / total * totalHeight) : 0;
|
|
21201
21340
|
const outputHeight = hasData ? Math.max(0, totalHeight - inputHeight) : 0;
|
|
21341
|
+
// Subdivide the input portion by measured tier breakdown when the
|
|
21342
|
+
// day has at least one snapshotted assistant turn. Legacy days
|
|
21343
|
+
// (measured_input_tokens === 0) fall back to a solid violet block.
|
|
21344
|
+
const tier = point.tier_tokens;
|
|
21345
|
+
const tierTotal = tier?.measured_input_tokens ?? 0;
|
|
21346
|
+
const hotPx = tierTotal > 0 ? Math.round(tier.hot_tokens / tierTotal * inputHeight) : 0;
|
|
21347
|
+
const warmPx = tierTotal > 0 ? Math.round(tier.warm_tokens / tierTotal * inputHeight) : 0;
|
|
21348
|
+
const factsPx = tierTotal > 0 ? Math.round(tier.facts_tokens / tierTotal * inputHeight) : 0;
|
|
21349
|
+
const overheadPx = tierTotal > 0 ? Math.max(0, inputHeight - hotPx - warmPx - factsPx) : 0;
|
|
21202
21350
|
const isActive = idx === hovered;
|
|
21203
21351
|
const isSelected = selectedDay === point.day;
|
|
21204
21352
|
const clickable = !!onSelectDay && hasData;
|
|
@@ -21229,7 +21377,42 @@ function InteractiveTokenChart({ series, selectedDay, onSelectDay }) {
|
|
|
21229
21377
|
transition: `height 420ms cubic-bezier(0.2, 0.8, 0.2, 1) ${idx * 18}ms`
|
|
21230
21378
|
}
|
|
21231
21379
|
}),
|
|
21232
|
-
/*#__PURE__*/ (0,jsx_runtime.
|
|
21380
|
+
tierTotal > 0 ? /*#__PURE__*/ (0,jsx_runtime.jsxs)(jsx_runtime.Fragment, {
|
|
21381
|
+
children: [
|
|
21382
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
|
|
21383
|
+
className: "w-full",
|
|
21384
|
+
style: {
|
|
21385
|
+
background: TIER_COLORS.hot,
|
|
21386
|
+
height: barsReady ? `${hotPx}px` : "0px",
|
|
21387
|
+
transition: `height 420ms cubic-bezier(0.2, 0.8, 0.2, 1) ${idx * 18 + 30}ms`
|
|
21388
|
+
}
|
|
21389
|
+
}),
|
|
21390
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
|
|
21391
|
+
className: "w-full",
|
|
21392
|
+
style: {
|
|
21393
|
+
background: TIER_COLORS.warm,
|
|
21394
|
+
height: barsReady ? `${warmPx}px` : "0px",
|
|
21395
|
+
transition: `height 420ms cubic-bezier(0.2, 0.8, 0.2, 1) ${idx * 18 + 42}ms`
|
|
21396
|
+
}
|
|
21397
|
+
}),
|
|
21398
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
|
|
21399
|
+
className: "w-full",
|
|
21400
|
+
style: {
|
|
21401
|
+
background: TIER_COLORS.facts,
|
|
21402
|
+
height: barsReady ? `${factsPx}px` : "0px",
|
|
21403
|
+
transition: `height 420ms cubic-bezier(0.2, 0.8, 0.2, 1) ${idx * 18 + 54}ms`
|
|
21404
|
+
}
|
|
21405
|
+
}),
|
|
21406
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
|
|
21407
|
+
className: "w-full",
|
|
21408
|
+
style: {
|
|
21409
|
+
background: TIER_COLORS.overhead,
|
|
21410
|
+
height: barsReady ? `${overheadPx}px` : "0px",
|
|
21411
|
+
transition: `height 420ms cubic-bezier(0.2, 0.8, 0.2, 1) ${idx * 18 + 66}ms`
|
|
21412
|
+
}
|
|
21413
|
+
})
|
|
21414
|
+
]
|
|
21415
|
+
}) : /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
|
|
21233
21416
|
className: "w-full bg-gradient-to-t from-indigo-500 to-violet-400",
|
|
21234
21417
|
style: {
|
|
21235
21418
|
height: barsReady ? `${inputHeight}px` : "0px",
|
|
@@ -21252,13 +21435,61 @@ function InteractiveTokenChart({ series, selectedDay, onSelectDay }) {
|
|
|
21252
21435
|
/*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
|
|
21253
21436
|
className: "mt-2 flex flex-wrap items-center gap-3 text-[11px] text-[var(--text-secondary)]",
|
|
21254
21437
|
children: [
|
|
21438
|
+
/*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
|
|
21439
|
+
className: "inline-flex items-center gap-1",
|
|
21440
|
+
children: [
|
|
21441
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
|
|
21442
|
+
className: "w-2 h-2 rounded-sm",
|
|
21443
|
+
style: {
|
|
21444
|
+
background: TIER_COLORS.hot
|
|
21445
|
+
}
|
|
21446
|
+
}),
|
|
21447
|
+
"hot"
|
|
21448
|
+
]
|
|
21449
|
+
}),
|
|
21450
|
+
/*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
|
|
21451
|
+
className: "inline-flex items-center gap-1",
|
|
21452
|
+
children: [
|
|
21453
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
|
|
21454
|
+
className: "w-2 h-2 rounded-sm",
|
|
21455
|
+
style: {
|
|
21456
|
+
background: TIER_COLORS.warm
|
|
21457
|
+
}
|
|
21458
|
+
}),
|
|
21459
|
+
"warm"
|
|
21460
|
+
]
|
|
21461
|
+
}),
|
|
21462
|
+
/*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
|
|
21463
|
+
className: "inline-flex items-center gap-1",
|
|
21464
|
+
children: [
|
|
21465
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
|
|
21466
|
+
className: "w-2 h-2 rounded-sm",
|
|
21467
|
+
style: {
|
|
21468
|
+
background: TIER_COLORS.facts
|
|
21469
|
+
}
|
|
21470
|
+
}),
|
|
21471
|
+
"facts"
|
|
21472
|
+
]
|
|
21473
|
+
}),
|
|
21474
|
+
/*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
|
|
21475
|
+
className: "inline-flex items-center gap-1",
|
|
21476
|
+
children: [
|
|
21477
|
+
/*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
|
|
21478
|
+
className: "w-2 h-2 rounded-sm",
|
|
21479
|
+
style: {
|
|
21480
|
+
background: TIER_COLORS.overhead
|
|
21481
|
+
}
|
|
21482
|
+
}),
|
|
21483
|
+
"overhead"
|
|
21484
|
+
]
|
|
21485
|
+
}),
|
|
21255
21486
|
/*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
|
|
21256
21487
|
className: "inline-flex items-center gap-1",
|
|
21257
21488
|
children: [
|
|
21258
21489
|
/*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
|
|
21259
21490
|
className: "w-2 h-2 rounded-full bg-violet-400"
|
|
21260
21491
|
}),
|
|
21261
|
-
"input"
|
|
21492
|
+
"input (est)"
|
|
21262
21493
|
]
|
|
21263
21494
|
}),
|
|
21264
21495
|
/*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
|
|
@@ -21270,14 +21501,9 @@ function InteractiveTokenChart({ series, selectedDay, onSelectDay }) {
|
|
|
21270
21501
|
"output"
|
|
21271
21502
|
]
|
|
21272
21503
|
}),
|
|
21273
|
-
active && /*#__PURE__*/ (0,jsx_runtime.
|
|
21504
|
+
active && /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
|
|
21274
21505
|
className: "ml-auto text-[var(--text-primary)]",
|
|
21275
|
-
children:
|
|
21276
|
-
"in ",
|
|
21277
|
-
formatInt(active.input_tokens_est),
|
|
21278
|
-
" \xb7 out ",
|
|
21279
|
-
formatInt(active.output_tokens_est)
|
|
21280
|
-
]
|
|
21506
|
+
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)}`
|
|
21281
21507
|
})
|
|
21282
21508
|
]
|
|
21283
21509
|
})
|
|
@@ -21946,4 +22172,4 @@ Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_re
|
|
|
21946
22172
|
/******/ _N_E = __webpack_exports__;
|
|
21947
22173
|
/******/ }
|
|
21948
22174
|
]);
|
|
21949
|
-
//# sourceMappingURL=page-
|
|
22175
|
+
//# sourceMappingURL=page-318743bf47fac345.js.map
|