@tangle-network/sandbox-ui 7.0.0 → 7.0.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.
- package/README.md +8 -0
- package/dist/{AgentTree-abRugBMr.js → AgentTree-Dzy6lrfP.js} +1 -1
- package/dist/{ResearchReport-BPOmsUFI.js → ResearchReport-DKWDmzdK.js} +2 -2
- package/dist/{chat-BrlLa4rg.js → chat-B_5Lwevm.js} +2 -2
- package/dist/chat.d.ts +1 -1
- package/dist/chat.js +1 -1
- package/dist/globals.css +1514 -6964
- package/dist/{index-5zOVKgDT.d.ts → index-1Q4Jtlic.d.ts} +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -6
- package/dist/record/ResearchReport.js +1 -1
- package/dist/{record-hTSz-cf1.js → record-Cc_WNtG8.js} +2 -2
- package/dist/record.js +1 -1
- package/dist/report-viewer.js +90 -90
- package/dist/run/live.js +1 -1
- package/dist/run/record.js +3 -3
- package/dist/run-CpJ_COuz.js +5 -0
- package/dist/run.js +5 -5
- package/dist/runtime-viewer/AgentGraphCanvas-xHVW-YRV-Ch1fnK9k.js +957 -0
- package/dist/runtime-viewer/latest-events-CMbdBLcT-uhVN4JLh.js +17401 -0
- package/dist/styles.css +1514 -6967
- package/dist/tailwind.css +824 -7408
- package/dist/{trace-workspace-WJTjp2Id.js → trace-workspace-EArXc0uP.js} +37 -89
- package/dist/{use-follow-tail-Di1zlndg.js → use-follow-tail-Df965WQi.js} +41 -6
- package/dist/workspace-viewer.js +7688 -7751
- package/package.json +3 -3
- package/dist/runtime-viewer/AgentGraphCanvas-DGq7_u8--C6yDfIUT.js +0 -8555
- package/dist/runtime-viewer/latest-events-CRq9sGkK-CfoBl1dP.js +0 -9592
- package/dist/runtime-viewer/sandbox-ui-BEziPi7D.css +0 -2
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { t as cn$1 } from "./utils-BER_bdgE.js";
|
|
2
2
|
import { i as modelBrandFor, t as ModelBrandStack } from "./model-brand-BQlarCIo.js";
|
|
3
3
|
import { t as ProviderIcon } from "./provider-logo-CPKRPHcS.js";
|
|
4
|
-
import { t as AgentGraph
|
|
5
|
-
import { s as timelineItems, t as useFollowTail } from "./use-follow-tail-
|
|
6
|
-
import { SegmentedControl } from "@tangle-network/ui/primitives";
|
|
4
|
+
import { t as AgentGraph } from "./AgentGraph-BGWx9hhS.js";
|
|
5
|
+
import { s as timelineItems, t as useFollowTail } from "./use-follow-tail-Df965WQi.js";
|
|
6
|
+
import { Button, SegmentedControl } from "@tangle-network/ui/primitives";
|
|
7
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
9
9
|
import { ArrowLeft, ChevronRight, X } from "lucide-react";
|
|
10
10
|
import { formatCost, formatCount, formatSpanDuration } from "@tangle-network/ui/utils";
|
|
11
11
|
import { activityTiming } from "@tangle-network/charts/react/agent-graph/presentation";
|
|
12
|
-
import { AgentTimeline } from "@tangle-network/ui/chat";
|
|
12
|
+
import { AgentTimeline, AgentTimelineColumn } from "@tangle-network/ui/chat";
|
|
13
13
|
import { RunStatusIcon, runStatus } from "@tangle-network/ui/run";
|
|
14
14
|
import { FlowWaterfall, toolGlyph } from "@tangle-network/charts/react";
|
|
15
|
-
import { LatestEvents } from "@tangle-network/charts/react/agent-graph";
|
|
16
15
|
import { useEventStream } from "@tangle-network/ui/hooks";
|
|
17
16
|
// src/run/trace-waterfall.tsx
|
|
18
17
|
/** Agent and model spans show their lab/host mark; tool spans show their provider's mark. Unknown keeps the kind glyph. */
|
|
@@ -24,7 +23,7 @@ function traceSpanMark(span) {
|
|
|
24
23
|
size: "sm"
|
|
25
24
|
}) : void 0;
|
|
26
25
|
}
|
|
27
|
-
const provider = span.icon
|
|
26
|
+
const provider = span.icon;
|
|
28
27
|
return provider ? /* @__PURE__ */ jsx(ProviderIcon, {
|
|
29
28
|
id: provider,
|
|
30
29
|
displayName: provider,
|
|
@@ -506,49 +505,6 @@ function useSplit(root) {
|
|
|
506
505
|
}
|
|
507
506
|
};
|
|
508
507
|
}
|
|
509
|
-
/**
|
|
510
|
-
* The height the waterfall rows or graph may take so the run fills its pane: their own height plus the room left under
|
|
511
|
-
* the chart's last row (toolbar, axis and latest activity keep theirs). FlowWaterfall sizes its virtualized rows by `maxHeight`, so it is measured, not styled.
|
|
512
|
-
*/
|
|
513
|
-
function useFillHeight(pane) {
|
|
514
|
-
const [height, setHeight] = useState();
|
|
515
|
-
useEffect(() => {
|
|
516
|
-
const element = pane.current;
|
|
517
|
-
if (!element) return;
|
|
518
|
-
let frame = 0;
|
|
519
|
-
const measure = () => {
|
|
520
|
-
cancelAnimationFrame(frame);
|
|
521
|
-
frame = requestAnimationFrame(() => {
|
|
522
|
-
const root = element.querySelector(".fw-root");
|
|
523
|
-
const target = [...element.querySelectorAll("[data-trace-graph], .fw-scroller")].find((candidate) => candidate.offsetHeight > 0);
|
|
524
|
-
if (!root || !target) return;
|
|
525
|
-
const style = getComputedStyle(root), bottom = Math.max(...[...root.children].map((child) => child.getBoundingClientRect().bottom));
|
|
526
|
-
const slack = root.getBoundingClientRect().bottom - parseFloat(style.paddingBottom) - parseFloat(style.borderBottomWidth) - bottom;
|
|
527
|
-
const next = Math.floor(target.offsetHeight + slack);
|
|
528
|
-
if (next > 160) setHeight((prior) => prior !== void 0 && Math.abs(prior - next) < 2 ? prior : next);
|
|
529
|
-
});
|
|
530
|
-
};
|
|
531
|
-
const observer = new ResizeObserver(measure);
|
|
532
|
-
observer.observe(element);
|
|
533
|
-
const watch = new MutationObserver(() => {
|
|
534
|
-
const root = element.querySelector(".fw-root");
|
|
535
|
-
if (root) observer.observe(root);
|
|
536
|
-
measure();
|
|
537
|
-
});
|
|
538
|
-
watch.observe(element, {
|
|
539
|
-
childList: true,
|
|
540
|
-
subtree: true
|
|
541
|
-
});
|
|
542
|
-
const root = element.querySelector(".fw-root");
|
|
543
|
-
if (root) observer.observe(root);
|
|
544
|
-
return () => {
|
|
545
|
-
cancelAnimationFrame(frame);
|
|
546
|
-
observer.disconnect();
|
|
547
|
-
watch.disconnect();
|
|
548
|
-
};
|
|
549
|
-
}, [pane]);
|
|
550
|
-
return height;
|
|
551
|
-
}
|
|
552
508
|
/** Text held to a few lines with a control to read the rest; the control appears only when lines are hidden. */
|
|
553
509
|
function Clamped({ text, lines, className }) {
|
|
554
510
|
const [open, setOpen] = useState(false), [over, setOver] = useState(false), ref = useRef(null);
|
|
@@ -637,22 +593,24 @@ function metaOf(span) {
|
|
|
637
593
|
/** Facts the header already states are not repeated in Details. */
|
|
638
594
|
const IN_HEADER = /^(tokens|cost|duration|failure|model)$/i;
|
|
639
595
|
/** The selected agent: a compact header, its failure, its commission, then its conversation; recorded facts wait in Details. */
|
|
640
|
-
function AgentInspector({ name, model, status, span, live, failure, commission, facts, detail, children, scroller, unseen, onJump, onClose, mode, style }) {
|
|
596
|
+
function AgentInspector({ name, model, status, span, live, failure, silent, commission, facts, detail, children, scroller, unseen, onJump, onClose, mode, style }) {
|
|
641
597
|
const brand = model ? modelBrandFor(model) : null, meta = metaOf(span);
|
|
642
598
|
const details = facts.filter((fact) => !IN_HEADER.test(fact.label) && fact.value !== failure);
|
|
643
|
-
const
|
|
599
|
+
const sheetRef = useRef(null);
|
|
644
600
|
const sheet = mode === "sheet";
|
|
645
601
|
useEffect(() => {
|
|
646
602
|
if (!sheet) return;
|
|
647
603
|
const opener = document.activeElement, overflow = document.body.style.overflow;
|
|
648
604
|
document.body.style.overflow = "hidden";
|
|
649
|
-
|
|
605
|
+
sheetRef.current?.focus();
|
|
650
606
|
return () => {
|
|
651
607
|
document.body.style.overflow = overflow;
|
|
652
608
|
if (opener?.isConnected) opener.focus();
|
|
653
609
|
};
|
|
654
610
|
}, [sheet]);
|
|
655
611
|
return /* @__PURE__ */ jsxs("aside", {
|
|
612
|
+
ref: sheetRef,
|
|
613
|
+
tabIndex: sheet ? -1 : void 0,
|
|
656
614
|
role: sheet ? "dialog" : void 0,
|
|
657
615
|
"aria-modal": sheet || void 0,
|
|
658
616
|
"aria-label": `${name} conversation`,
|
|
@@ -663,24 +621,24 @@ function AgentInspector({ name, model, status, span, live, failure, commission,
|
|
|
663
621
|
onClose();
|
|
664
622
|
}
|
|
665
623
|
},
|
|
666
|
-
className: cn$1("relative flex min-h-0 flex-col overflow-hidden bg-card text-foreground", mode === "docked" && "shrink-0 rounded-xl border border-border", mode === "overlay" && "fixed inset-y-0 right-0 z-40 w-full max-w-[420px] border-l border-border shadow-2xl", sheet && "fixed inset-0 z-[1100] bg-background"),
|
|
624
|
+
className: cn$1("relative flex min-h-0 flex-col overflow-hidden bg-card text-foreground outline-none", mode === "docked" && "shrink-0 rounded-xl border border-border", mode === "overlay" && "fixed inset-y-0 right-0 z-40 w-full max-w-[420px] border-l border-border shadow-2xl", sheet && "fixed inset-0 z-[1100] bg-background"),
|
|
667
625
|
children: [
|
|
668
626
|
/* @__PURE__ */ jsxs("header", {
|
|
669
627
|
className: "flex shrink-0 items-start gap-2 border-b border-border px-3 py-2.5",
|
|
670
628
|
children: [
|
|
671
|
-
sheet && /* @__PURE__ */ jsxs(
|
|
672
|
-
|
|
673
|
-
|
|
629
|
+
sheet && /* @__PURE__ */ jsxs(Button, {
|
|
630
|
+
variant: "ghost",
|
|
631
|
+
size: "sm",
|
|
674
632
|
onClick: onClose,
|
|
675
633
|
"aria-label": "Back to the run",
|
|
676
|
-
className: "-ml-1
|
|
634
|
+
className: "-ml-1.5 shrink-0 gap-1 px-2",
|
|
677
635
|
children: [/* @__PURE__ */ jsx(ArrowLeft, {
|
|
678
636
|
"aria-hidden": true,
|
|
679
637
|
className: "h-4 w-4"
|
|
680
638
|
}), "Back"]
|
|
681
639
|
}),
|
|
682
640
|
/* @__PURE__ */ jsxs("div", {
|
|
683
|
-
className: cn$1("min-w-0 flex-1", sheet && "pt-
|
|
641
|
+
className: cn$1("min-w-0 flex-1", sheet && "pt-1.5"),
|
|
684
642
|
children: [
|
|
685
643
|
/* @__PURE__ */ jsxs("div", {
|
|
686
644
|
className: "flex min-w-0 items-start gap-2",
|
|
@@ -733,7 +691,7 @@ function AgentInspector({ name, model, status, span, live, failure, commission,
|
|
|
733
691
|
}),
|
|
734
692
|
failure && /* @__PURE__ */ jsx("section", {
|
|
735
693
|
"aria-label": "Failure",
|
|
736
|
-
className: "shrink-0 border-b border-border px-3 py-2 text-sm text-[var(--surface-danger-text)]",
|
|
694
|
+
className: "shrink-0 border-b border-border px-3 py-2.5 text-sm font-medium leading-5 text-[var(--surface-danger-text)]",
|
|
737
695
|
children: /* @__PURE__ */ jsx(Clamped, {
|
|
738
696
|
text: failure,
|
|
739
697
|
lines: 3
|
|
@@ -763,9 +721,10 @@ function AgentInspector({ name, model, status, span, live, failure, commission,
|
|
|
763
721
|
children: "New output"
|
|
764
722
|
}),
|
|
765
723
|
(details.length > 0 || detail) && /* @__PURE__ */ jsxs("details", {
|
|
724
|
+
open: silent || void 0,
|
|
766
725
|
className: "group max-h-[45%] shrink-0 overflow-y-auto border-t border-border text-sm",
|
|
767
726
|
children: [/* @__PURE__ */ jsxs("summary", {
|
|
768
|
-
className: "flex cursor-pointer list-none items-center gap-1.5 px-3 py-2 text-xs font-medium text-muted-foreground hover:text-foreground [&::-webkit-details-marker]:hidden",
|
|
727
|
+
className: "flex cursor-pointer list-none items-center gap-1.5 px-3 py-2 text-xs font-medium text-muted-foreground hover:text-foreground before:hidden before:content-none [&::-webkit-details-marker]:hidden",
|
|
769
728
|
children: [/* @__PURE__ */ jsx(ChevronRight, {
|
|
770
729
|
"aria-hidden": true,
|
|
771
730
|
className: "h-3.5 w-3.5 transition-transform group-open:rotate-90"
|
|
@@ -934,35 +893,31 @@ function TraceWorkspace({ trace, streamUrl, openEventSource, events, onTimeChang
|
|
|
934
893
|
identity: showConversation ? selected : void 0,
|
|
935
894
|
content: items
|
|
936
895
|
});
|
|
937
|
-
const root = useRef(null)
|
|
938
|
-
const phone = usePhone(), split = useSplit(root)
|
|
896
|
+
const root = useRef(null);
|
|
897
|
+
const phone = usePhone(), split = useSplit(root);
|
|
939
898
|
const mode = phone ? "sheet" : docked ? "docked" : "overlay";
|
|
940
899
|
const status = live ? "running" : selectedNode?.status ?? runStatus(agent?.status ?? "unknown");
|
|
941
900
|
const failure = facts.find((fact) => fact.label === "Failure")?.value ?? (status === "failed" ? selectedNode?.result ?? void 0 : void 0);
|
|
942
901
|
const said = (text) => !!text && shown.some((entry) => entry.kind === "message" && entry.role === "user" && entry.content.trim() === text.trim());
|
|
943
902
|
const silent = agentId && transcriptNote?.(agentId) || "No conversation was recorded for this agent.";
|
|
944
|
-
const
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
}) : /* @__PURE__ */ jsx(AgentTimeline, {
|
|
951
|
-
items,
|
|
952
|
-
isThinking: live && items.length === 0,
|
|
953
|
-
emptyState: /* @__PURE__ */ jsx("p", {
|
|
954
|
-
className: "p-4 text-sm text-muted-foreground",
|
|
955
|
-
"data-stream": stream.error ? "reconnecting" : ended ? "ended" : "empty",
|
|
956
|
-
children: stream.error ? ended ? stream.error : `Reconnecting… ${stream.error}` : ended ? silent : "No messages yet."
|
|
903
|
+
const note = !streamUrl ? silent : cursor !== null && origin === void 0 ? "This conversation has no timestamps to replay at the cursor." : items.length > 0 || live ? void 0 : stream.error ? ended ? stream.error : `Reconnecting… ${stream.error}` : ended ? silent : "No messages yet.";
|
|
904
|
+
const conversation = note === void 0 ? /* @__PURE__ */ jsx(AgentTimelineColumn, {
|
|
905
|
+
className: "max-w-[46rem] p-0",
|
|
906
|
+
children: /* @__PURE__ */ jsx(AgentTimeline, {
|
|
907
|
+
items,
|
|
908
|
+
isThinking: live && items.length === 0
|
|
957
909
|
})
|
|
910
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
911
|
+
className: "m-0 py-1 text-sm text-muted-foreground",
|
|
912
|
+
"data-stream": stream.error ? "reconnecting" : ended ? "ended" : "empty",
|
|
913
|
+
children: note
|
|
958
914
|
});
|
|
959
915
|
const left = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
960
916
|
/* @__PURE__ */ jsx("div", {
|
|
961
|
-
ref: pane,
|
|
962
917
|
className: cn$1("flex min-h-[320px] min-w-0 flex-1 flex-col", showConversation && mode === "overlay" && "lg:mr-[420px]"),
|
|
963
918
|
children: /* @__PURE__ */ jsx(TraceWaterfall, {
|
|
964
919
|
...waterfall,
|
|
965
|
-
maxHeight:
|
|
920
|
+
maxHeight: waterfall.maxHeight ?? "fill",
|
|
966
921
|
trace,
|
|
967
922
|
markers: events,
|
|
968
923
|
selectedId: agentId,
|
|
@@ -975,17 +930,9 @@ function TraceWorkspace({ trace, streamUrl, openEventSource, events, onTimeChang
|
|
|
975
930
|
setCursor(time);
|
|
976
931
|
onTimeChange?.(time);
|
|
977
932
|
},
|
|
978
|
-
latestEvents: /* @__PURE__ */ jsx(LatestEvents, {
|
|
979
|
-
agents: graph.nodes,
|
|
980
|
-
now: graphNow,
|
|
981
|
-
live: cursor === null,
|
|
982
|
-
selectedId: agentId,
|
|
983
|
-
onSelect: select
|
|
984
|
-
}),
|
|
985
933
|
graph: /* @__PURE__ */ jsxs("section", {
|
|
986
|
-
"
|
|
987
|
-
|
|
988
|
-
style: { height: fill ?? "max(60vh, 480px)" },
|
|
934
|
+
className: "relative flex min-h-[320px] flex-1 flex-col",
|
|
935
|
+
style: typeof waterfall.maxHeight === "number" ? { height: waterfall.maxHeight } : void 0,
|
|
989
936
|
"aria-label": "Agent graph",
|
|
990
937
|
children: [/* @__PURE__ */ jsx(SegmentedControl, {
|
|
991
938
|
"aria-label": "Graph layout",
|
|
@@ -999,7 +946,7 @@ function TraceWorkspace({ trace, streamUrl, openEventSource, events, onTimeChang
|
|
|
999
946
|
value: "hub",
|
|
1000
947
|
label: "Hub"
|
|
1001
948
|
}]
|
|
1002
|
-
}), /* @__PURE__ */ jsx(AgentGraph
|
|
949
|
+
}), /* @__PURE__ */ jsx(AgentGraph, {
|
|
1003
950
|
...graphOptions,
|
|
1004
951
|
layout: graphLayout,
|
|
1005
952
|
renderEventIcon: (event) => toolGlyph(event.label),
|
|
@@ -1051,6 +998,7 @@ function TraceWorkspace({ trace, streamUrl, openEventSource, events, onTimeChang
|
|
|
1051
998
|
span: agent,
|
|
1052
999
|
live,
|
|
1053
1000
|
failure,
|
|
1001
|
+
silent: note !== void 0 && note === silent,
|
|
1054
1002
|
commission: said(commission?.text) ? { by: commission?.by } : commission,
|
|
1055
1003
|
facts,
|
|
1056
1004
|
detail,
|
|
@@ -1064,4 +1012,4 @@ function TraceWorkspace({ trace, streamUrl, openEventSource, events, onTimeChang
|
|
|
1064
1012
|
})] })]
|
|
1065
1013
|
});
|
|
1066
1014
|
}
|
|
1067
|
-
export {
|
|
1015
|
+
export { TraceWaterfall as a, useEventStream as i, foldAgentRows as n, traceSpanMark as o, useAgentStream as r, TraceWorkspace as t };
|
|
@@ -3,6 +3,7 @@ import { HoverCard, HoverCardContent, HoverCardTrigger } from "@tangle-network/u
|
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { Brain, Settings, Timer } from "lucide-react";
|
|
5
5
|
import { getToolCategory, getToolDisplayMetadata } from "@tangle-network/ui/utils";
|
|
6
|
+
import { toolLabel } from "@tangle-network/charts/react/agent-graph";
|
|
6
7
|
import { formatCompact, formatCompact as fmt, formatCost as formatCost$1, formatSpanDuration as formatSpanDuration$1, formatSpanDuration as interval, formatUtcTime as utcTime, reportedCount, sumReportedCounts } from "@tangle-network/charts";
|
|
7
8
|
import { AgentTimelineStep, agentTimelineStepKind } from "@tangle-network/ui/chat/agent-timeline";
|
|
8
9
|
import { SpeakerHeader } from "@tangle-network/ui/chat/speaker";
|
|
@@ -853,7 +854,7 @@ function toolItem(id, call, output, state, durationMs, live, cost) {
|
|
|
853
854
|
}
|
|
854
855
|
};
|
|
855
856
|
const known = KIT_TOOLS.has(name.toLowerCase()), meta = getToolDisplayMetadata(part);
|
|
856
|
-
const detail = argsLabel(call.input) ?? (meta.description ||
|
|
857
|
+
const detail = argsLabel(call.input) ?? (known && meta.description || void 0);
|
|
857
858
|
return {
|
|
858
859
|
id,
|
|
859
860
|
kind: "tool",
|
|
@@ -861,7 +862,7 @@ function toolItem(id, call, output, state, durationMs, live, cost) {
|
|
|
861
862
|
call: {
|
|
862
863
|
id,
|
|
863
864
|
type: TYPES[name.toLowerCase()] ?? "unknown",
|
|
864
|
-
label: known ? meta.title : name
|
|
865
|
+
label: known ? meta.title : toolLabel(name),
|
|
865
866
|
status: status === "error" ? "error" : status === "running" ? "running" : "success",
|
|
866
867
|
...detail ? { detail } : {},
|
|
867
868
|
...duration !== void 0 ? { duration } : {}
|
|
@@ -907,7 +908,7 @@ function timelineItems(entries, streaming, opened) {
|
|
|
907
908
|
key: events[0].id,
|
|
908
909
|
events
|
|
909
910
|
}));
|
|
910
|
-
return rows.map((row, index) => {
|
|
911
|
+
return foldTools(rows.map((row, index) => {
|
|
911
912
|
const entry = row.kind === "event" ? row.event : row.events[0];
|
|
912
913
|
if (row.kind === "idle") return idleItem(entry.id, row.events.map((event) => ({
|
|
913
914
|
id: event.id,
|
|
@@ -923,7 +924,10 @@ function timelineItems(entries, streaming, opened) {
|
|
|
923
924
|
role: entry.role,
|
|
924
925
|
content: short ? `${body.slice(0, 280).trimEnd()}…` : body,
|
|
925
926
|
isStreaming: streaming && index === rows.length - 1,
|
|
926
|
-
...entry.role === "user"
|
|
927
|
+
...entry.role === "user" ? {
|
|
928
|
+
...opened ? {} : { collapsedLines: 6 },
|
|
929
|
+
...Number.isFinite(entry.at) ? { timestamp: new Date(entry.at) } : {}
|
|
930
|
+
} : {}
|
|
927
931
|
};
|
|
928
932
|
}
|
|
929
933
|
if (entry.kind === "tool") return toolItem(entry.id, {
|
|
@@ -947,7 +951,7 @@ function timelineItems(entries, streaming, opened) {
|
|
|
947
951
|
})
|
|
948
952
|
};
|
|
949
953
|
return {
|
|
950
|
-
id: entry.id
|
|
954
|
+
id: `reasoning:${entry.id}`,
|
|
951
955
|
kind: "custom",
|
|
952
956
|
content: /* @__PURE__ */ jsx(InlineThinkingItem, {
|
|
953
957
|
part: {
|
|
@@ -958,7 +962,38 @@ function timelineItems(entries, streaming, opened) {
|
|
|
958
962
|
openWhileActive: false
|
|
959
963
|
})
|
|
960
964
|
};
|
|
961
|
-
});
|
|
965
|
+
}), streaming);
|
|
966
|
+
}
|
|
967
|
+
/** Back-to-back tool calls (and the reasoning between them) fold into one row that names them, "Ran 6 tools · Read ×3,
|
|
968
|
+
* knowledge record"; their arguments and results open with it, so the agent's own words stay the conversation. A live
|
|
969
|
+
* agent's newest call stays its own row so the reader sees what is running now. */
|
|
970
|
+
function foldTools(items, streaming) {
|
|
971
|
+
const out = [];
|
|
972
|
+
let run = [];
|
|
973
|
+
const flush = (last) => {
|
|
974
|
+
const open = last && streaming ? run.splice(-1) : [];
|
|
975
|
+
const tools = run.filter((item) => item.kind === "tool");
|
|
976
|
+
if (tools.length > 1) {
|
|
977
|
+
const counts = /* @__PURE__ */ new Map();
|
|
978
|
+
for (const tool of tools) counts.set(tool.call.label, (counts.get(tool.call.label) ?? 0) + 1);
|
|
979
|
+
const names = [...counts].map(([name, n]) => n > 1 ? `${name} ×${n}` : name), more = names.length - 3;
|
|
980
|
+
out.push({
|
|
981
|
+
id: `fold:${run[0].id}`,
|
|
982
|
+
kind: "fold",
|
|
983
|
+
items: run,
|
|
984
|
+
summary: `Ran ${tools.length} tools · ${names.slice(0, 3).join(", ")}${more > 0 ? ` +${more} more` : ""}`
|
|
985
|
+
});
|
|
986
|
+
} else out.push(...run);
|
|
987
|
+
out.push(...open);
|
|
988
|
+
run = [];
|
|
989
|
+
};
|
|
990
|
+
for (const item of items) if (item.kind === "tool" || item.kind === "custom" && item.id.startsWith("reasoning:")) run.push(item);
|
|
991
|
+
else {
|
|
992
|
+
flush(false);
|
|
993
|
+
out.push(item);
|
|
994
|
+
}
|
|
995
|
+
flush(true);
|
|
996
|
+
return out;
|
|
962
997
|
}
|
|
963
998
|
const toolNote = (part) => {
|
|
964
999
|
const note = part.state.metadata?.note, time = part.state.time;
|