@tangle-network/agent-app 0.45.49 → 0.45.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assistant/index.d.ts +17 -1
- package/dist/assistant/index.js +38 -7
- package/dist/assistant/index.js.map +1 -1
- package/dist/{chunk-ZAKKG6WI.js → chunk-CXPWUCXC.js} +1124 -409
- package/dist/chunk-CXPWUCXC.js.map +1 -0
- package/dist/theme/tokens.css +45 -1
- package/dist/web-react/index.d.ts +370 -3
- package/dist/web-react/index.js +42 -1
- package/package.json +1 -1
- package/dist/chunk-ZAKKG6WI.js.map +0 -1
|
@@ -13,6 +13,9 @@ import {
|
|
|
13
13
|
usePending,
|
|
14
14
|
usePopover
|
|
15
15
|
} from "./chunk-CJHIAZKK.js";
|
|
16
|
+
import {
|
|
17
|
+
AsyncView
|
|
18
|
+
} from "./chunk-3UBAO3N5.js";
|
|
16
19
|
import {
|
|
17
20
|
UNTITLED_SESSION_LABEL,
|
|
18
21
|
mergeSessionPages,
|
|
@@ -37,7 +40,7 @@ import {
|
|
|
37
40
|
} from "./chunk-YJMCRXQQ.js";
|
|
38
41
|
|
|
39
42
|
// src/web-react/index.tsx
|
|
40
|
-
import { useEffect as
|
|
43
|
+
import { useEffect as useEffect12, useId as useId4, useMemo as useMemo7, useRef as useRef12, useState as useState16, memo } from "react";
|
|
41
44
|
import { InlineToolItem } from "@tangle-network/ui/run";
|
|
42
45
|
|
|
43
46
|
// src/web-react/smooth-text.ts
|
|
@@ -80,6 +83,22 @@ function useSmoothText(target, enabled, opts) {
|
|
|
80
83
|
return target.slice(0, Math.floor(shownRef.current));
|
|
81
84
|
}
|
|
82
85
|
|
|
86
|
+
// src/web-react/inert.ts
|
|
87
|
+
function inertProps(inert) {
|
|
88
|
+
if (!inert) return {};
|
|
89
|
+
return { inert: "1" };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/web-react/motion.ts
|
|
93
|
+
import { useState as useState2 } from "react";
|
|
94
|
+
function staggerStyle(index, base) {
|
|
95
|
+
return { ...base, "--stagger-index": index };
|
|
96
|
+
}
|
|
97
|
+
function useArrivalStyle(index) {
|
|
98
|
+
const [frozen] = useState2(index);
|
|
99
|
+
return staggerStyle(frozen);
|
|
100
|
+
}
|
|
101
|
+
|
|
83
102
|
// src/web-react/brand-mark.tsx
|
|
84
103
|
import { lazy, Suspense } from "react";
|
|
85
104
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -99,10 +118,10 @@ function BrandMark({ size = 24, className }) {
|
|
|
99
118
|
}
|
|
100
119
|
|
|
101
120
|
// src/web-react/durable-plan-card.tsx
|
|
102
|
-
import { useEffect as useEffect3, useLayoutEffect, useRef as useRef3, useState as
|
|
121
|
+
import { useEffect as useEffect3, useLayoutEffect, useRef as useRef3, useState as useState4 } from "react";
|
|
103
122
|
|
|
104
123
|
// src/web-react/interaction-question-card.tsx
|
|
105
|
-
import { useEffect as useEffect2, useMemo, useRef as useRef2, useState as
|
|
124
|
+
import { useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState3 } from "react";
|
|
106
125
|
|
|
107
126
|
// src/web-react/interaction-card-support.ts
|
|
108
127
|
function interactionStatusLabels(labels) {
|
|
@@ -310,7 +329,8 @@ function QuestionOptionList({
|
|
|
310
329
|
"label",
|
|
311
330
|
{
|
|
312
331
|
htmlFor: inputId,
|
|
313
|
-
|
|
332
|
+
style: staggerStyle(optionIndex),
|
|
333
|
+
className: `agent-arrive flex gap-2 rounded-lg border p-3 transition-colors ${highlighted ? "border-primary bg-primary/5" : "border-strong"} ${disabled ? "cursor-default" : "cursor-pointer hover:bg-accent"}`,
|
|
314
334
|
children: [
|
|
315
335
|
/* @__PURE__ */ jsx2(
|
|
316
336
|
"input",
|
|
@@ -376,13 +396,13 @@ function InteractionQuestionCard({
|
|
|
376
396
|
renderMarkdown,
|
|
377
397
|
className
|
|
378
398
|
}) {
|
|
379
|
-
const [values, setValues] =
|
|
380
|
-
const [submitting, setSubmitting] =
|
|
381
|
-
const [localStatus, setLocalStatus] =
|
|
382
|
-
const [lateAnswerSent, setLateAnswerSent] =
|
|
383
|
-
const [error, setError] =
|
|
399
|
+
const [values, setValues] = useState3(() => fieldValuesFromAnswers(interaction.fields, interaction.answers));
|
|
400
|
+
const [submitting, setSubmitting] = useState3(false);
|
|
401
|
+
const [localStatus, setLocalStatus] = useState3(null);
|
|
402
|
+
const [lateAnswerSent, setLateAnswerSent] = useState3(false);
|
|
403
|
+
const [error, setError] = useState3(null);
|
|
384
404
|
const submitInFlightRef = useRef2(false);
|
|
385
|
-
const [askId, setAskId] =
|
|
405
|
+
const [askId, setAskId] = useState3(interaction.id);
|
|
386
406
|
if (askId !== interaction.id) {
|
|
387
407
|
setAskId(interaction.id);
|
|
388
408
|
setValues(fieldValuesFromAnswers(interaction.fields, interaction.answers));
|
|
@@ -468,10 +488,17 @@ function InteractionQuestionCard({
|
|
|
468
488
|
submitLabel = "Submitting\u2026";
|
|
469
489
|
}
|
|
470
490
|
return (
|
|
491
|
+
// The card LANDS. This is the moment the run stopped and handed the turn
|
|
492
|
+
// back — a surface that blinks into place reads as chrome that was always
|
|
493
|
+
// there, which is exactly the wrong reading for the one thing on screen
|
|
494
|
+
// waiting on the reader. `.agent-arrive` runs once on mount; a status
|
|
495
|
+
// change (answered, expired, a failed submit) re-renders the same DOM node
|
|
496
|
+
// and therefore does NOT replay it.
|
|
497
|
+
//
|
|
471
498
|
// `dark:[color-scheme:dark]` keeps the native radios/checkboxes on the
|
|
472
499
|
// dark control scheme — without it they paint light-scheme white on the
|
|
473
500
|
// dark card.
|
|
474
|
-
/* @__PURE__ */ jsxs("div", { className: `rounded-xl border border-card-edge bg-card p-4 dark:[color-scheme:dark] ${className ?? ""}`, children: [
|
|
501
|
+
/* @__PURE__ */ jsxs("div", { className: `agent-arrive rounded-xl border border-card-edge bg-card p-4 dark:[color-scheme:dark] ${className ?? ""}`, children: [
|
|
475
502
|
/* @__PURE__ */ jsxs("div", { className: "mb-3 flex flex-wrap items-center gap-2", children: [
|
|
476
503
|
/* @__PURE__ */ jsx2(InteractionBadge, { variant: "outline", children: kindLabel ?? "Question" }),
|
|
477
504
|
/* @__PURE__ */ jsx2(InteractionBadge, { variant: answered ? "default" : status === "expired" || status === "declined" ? "destructive" : "outline", children: STATUS_LABELS[status] })
|
|
@@ -607,14 +634,14 @@ function DurablePlanCard({
|
|
|
607
634
|
renderMarkdown,
|
|
608
635
|
className
|
|
609
636
|
}) {
|
|
610
|
-
const [feedback, setFeedback] =
|
|
611
|
-
const [expanded, setExpanded] =
|
|
612
|
-
const [localError, setLocalError] =
|
|
637
|
+
const [feedback, setFeedback] = useState4("");
|
|
638
|
+
const [expanded, setExpanded] = useState4(false);
|
|
639
|
+
const [localError, setLocalError] = useState4(null);
|
|
613
640
|
useEffect3(() => setLocalError(null), [plan.planId, plan.revision, plan.status]);
|
|
614
641
|
const actionable = plan.status === "pending";
|
|
615
642
|
const disabled = !canWrite || !actionable || deciding !== null;
|
|
616
643
|
const bodyRef = useRef3(null);
|
|
617
|
-
const [overflows, setOverflows] =
|
|
644
|
+
const [overflows, setOverflows] = useState4(false);
|
|
618
645
|
useLayoutEffect(() => {
|
|
619
646
|
const el = bodyRef.current;
|
|
620
647
|
if (el) setOverflows(el.scrollHeight > COLLAPSED_MAX_HEIGHT);
|
|
@@ -685,7 +712,7 @@ function DurablePlanCard({
|
|
|
685
712
|
}
|
|
686
713
|
|
|
687
714
|
// src/web-react/interaction-plan-card.tsx
|
|
688
|
-
import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo2, useRef as useRef4, useState as
|
|
715
|
+
import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo2, useRef as useRef4, useState as useState5 } from "react";
|
|
689
716
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
690
717
|
function CheckGlyph2({ className }) {
|
|
691
718
|
return /* @__PURE__ */ jsx4("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx4("path", { d: "M20 6 9 17l-5-5" }) });
|
|
@@ -714,7 +741,7 @@ function submittedFieldText(field, values) {
|
|
|
714
741
|
}
|
|
715
742
|
function useBodyOverflows(body, renderMarkdown) {
|
|
716
743
|
const bodyRef = useRef4(null);
|
|
717
|
-
const [overflows, setOverflows] =
|
|
744
|
+
const [overflows, setOverflows] = useState5(false);
|
|
718
745
|
useLayoutEffect2(() => {
|
|
719
746
|
const el = bodyRef.current;
|
|
720
747
|
if (el) setOverflows(el.scrollHeight > COLLAPSED_MAX_HEIGHT2);
|
|
@@ -731,12 +758,12 @@ function InteractionPlanCard({
|
|
|
731
758
|
renderMarkdown,
|
|
732
759
|
className
|
|
733
760
|
}) {
|
|
734
|
-
const [values, setValues] =
|
|
735
|
-
const [expanded, setExpanded] =
|
|
736
|
-
const [submitting, setSubmitting] =
|
|
737
|
-
const [localStatus, setLocalStatus] =
|
|
738
|
-
const [reRequested, setReRequested] =
|
|
739
|
-
const [error, setError] =
|
|
761
|
+
const [values, setValues] = useState5({});
|
|
762
|
+
const [expanded, setExpanded] = useState5(false);
|
|
763
|
+
const [submitting, setSubmitting] = useState5(null);
|
|
764
|
+
const [localStatus, setLocalStatus] = useState5(null);
|
|
765
|
+
const [reRequested, setReRequested] = useState5(false);
|
|
766
|
+
const [error, setError] = useState5(null);
|
|
740
767
|
const submitInFlightRef = useRef4(false);
|
|
741
768
|
const { bodyRef, overflows } = useBodyOverflows(interaction.body, renderMarkdown);
|
|
742
769
|
const status = isTerminalInteractionStatus(interaction.status) ? interaction.status : localStatus ?? interaction.status;
|
|
@@ -800,85 +827,105 @@ function InteractionPlanCard({
|
|
|
800
827
|
const terminalNote = TERMINAL_NOTES2[status];
|
|
801
828
|
const approved = status === "answered";
|
|
802
829
|
const submittedValues = interaction.answers ? fieldValuesFromAnswers(interaction.fields, interaction.answers) : values;
|
|
803
|
-
return
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
"
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
830
|
+
return (
|
|
831
|
+
// Same arrival as the question card: an approval is the run stopping, and
|
|
832
|
+
// the card that carries it should land rather than appear. Once on screen
|
|
833
|
+
// it never re-animates — approving, rejecting or a 410 changes state on the
|
|
834
|
+
// same DOM node, and a CSS animation does not replay on a re-render.
|
|
835
|
+
/* @__PURE__ */ jsxs3("div", { className: `agent-arrive rounded-xl border border-card-edge bg-card p-4 ${className ?? ""}`, children: [
|
|
836
|
+
/* @__PURE__ */ jsxs3("div", { className: "mb-3 flex flex-wrap items-center gap-2", children: [
|
|
837
|
+
/* @__PURE__ */ jsx4(InteractionBadge, { variant: "outline", children: "Plan" }),
|
|
838
|
+
/* @__PURE__ */ jsx4(InteractionBadge, { variant: approved ? "default" : status === "expired" || status === "declined" ? "destructive" : "outline", children: STATUS_LABELS2[status] })
|
|
839
|
+
] }),
|
|
840
|
+
interaction.title.trim() && /* @__PURE__ */ jsx4("p", { className: "mb-3 text-[15px] font-semibold leading-snug text-foreground", children: interaction.title }),
|
|
841
|
+
interaction.body && /* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
842
|
+
/* @__PURE__ */ jsx4(
|
|
843
|
+
"div",
|
|
844
|
+
{
|
|
845
|
+
ref: bodyRef,
|
|
846
|
+
className: "overflow-hidden text-sm text-foreground",
|
|
847
|
+
style: expanded || !overflows ? void 0 : { maxHeight: COLLAPSED_MAX_HEIGHT2 },
|
|
848
|
+
children: renderMarkdown ? renderMarkdown(interaction.body) : /* @__PURE__ */ jsx4("p", { className: "whitespace-pre-wrap leading-5", children: interaction.body })
|
|
849
|
+
}
|
|
850
|
+
),
|
|
851
|
+
overflows && !expanded && /* @__PURE__ */ jsx4("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 h-12 bg-gradient-to-t from-card to-transparent" }),
|
|
852
|
+
overflows && /* @__PURE__ */ jsxs3(
|
|
853
|
+
"button",
|
|
854
|
+
{
|
|
855
|
+
type: "button",
|
|
856
|
+
onClick: () => setExpanded((prev) => !prev),
|
|
857
|
+
className: "relative z-10 mt-1 inline-flex items-center gap-1 text-xs text-muted-foreground transition hover:text-foreground",
|
|
858
|
+
children: [
|
|
859
|
+
/* @__PURE__ */ jsx4(ChevronDownGlyph, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` }),
|
|
860
|
+
expanded ? "Collapse plan" : "Show full plan"
|
|
861
|
+
]
|
|
862
|
+
}
|
|
863
|
+
)
|
|
864
|
+
] }),
|
|
865
|
+
interaction.fields.length > 0 && status === "pending" && // The fields do NOT carry their own `.agent-arrive`. One level per
|
|
866
|
+
// surface: the card is the thing that was not there a moment ago, and a
|
|
867
|
+
// second entrance nested inside a travelling parent composes two
|
|
868
|
+
// translations and two opacity ramps over the same pixels — the card
|
|
869
|
+
// lands while its contents are still arriving into it, which reads as
|
|
870
|
+
// instability rather than as sequence.
|
|
871
|
+
//
|
|
872
|
+
// The card level is the one that survives, because a stagger is a claim
|
|
873
|
+
// that these appeared one after another and inside a landing card that
|
|
874
|
+
// claim is false — they all appeared with it. The question card keeps
|
|
875
|
+
// its option rows staggered for the opposite reason: those are the
|
|
876
|
+
// CHOICES being offered, and telling the eye there are three of them
|
|
877
|
+
// before it has read any is information about the decision. A form's
|
|
878
|
+
// fields carry no such count to announce.
|
|
879
|
+
/* @__PURE__ */ jsx4("div", { className: "mt-3 space-y-4", children: interaction.fields.map((field) => /* @__PURE__ */ jsxs3("fieldset", { className: "space-y-2", children: [
|
|
880
|
+
/* @__PURE__ */ jsx4("p", { className: "text-sm font-medium leading-5 text-foreground", children: field.label }),
|
|
881
|
+
fieldAcceptsFreeText(field) ? /* @__PURE__ */ jsx4(
|
|
882
|
+
"textarea",
|
|
883
|
+
{
|
|
884
|
+
value: values[field.name]?.text ?? "",
|
|
885
|
+
disabled,
|
|
886
|
+
"aria-label": field.label,
|
|
887
|
+
onChange: (event) => setValues((prev) => ({ ...prev, [field.name]: { ...prev[field.name], text: event.target.value } })),
|
|
888
|
+
rows: 2,
|
|
889
|
+
placeholder: field.type === "text" ? field.placeholder ?? "Optional feedback for the agent" : void 0,
|
|
890
|
+
className: "w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground focus:border-primary disabled:opacity-50"
|
|
891
|
+
}
|
|
892
|
+
) : /* @__PURE__ */ jsx4(
|
|
893
|
+
"input",
|
|
894
|
+
{
|
|
895
|
+
type: "text",
|
|
896
|
+
value: values[field.name]?.text ?? "",
|
|
897
|
+
disabled,
|
|
898
|
+
"aria-label": field.label,
|
|
899
|
+
onChange: (event) => setValues((prev) => ({ ...prev, [field.name]: { ...prev[field.name], text: event.target.value } })),
|
|
900
|
+
className: "w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground focus:border-primary disabled:opacity-50"
|
|
901
|
+
}
|
|
902
|
+
)
|
|
903
|
+
] }, field.name)) }),
|
|
904
|
+
interaction.fields.length > 0 && status !== "pending" && /* @__PURE__ */ jsx4("div", { className: "mt-3 space-y-2", children: interaction.fields.map((field) => {
|
|
905
|
+
const text = submittedFieldText(field, submittedValues);
|
|
906
|
+
if (!text) return null;
|
|
907
|
+
return /* @__PURE__ */ jsxs3("div", { children: [
|
|
908
|
+
/* @__PURE__ */ jsx4("p", { className: "text-xs font-medium text-muted-foreground", children: field.label }),
|
|
909
|
+
/* @__PURE__ */ jsx4("p", { className: "mt-0.5 whitespace-pre-wrap text-sm text-foreground", children: text })
|
|
910
|
+
] }, field.name);
|
|
911
|
+
}) }),
|
|
912
|
+
error && /* @__PURE__ */ jsx4("p", { className: "mt-3 text-xs text-destructive", children: error }),
|
|
913
|
+
terminalNote && /* @__PURE__ */ jsx4("p", { className: "mt-3 text-xs text-muted-foreground", children: terminalNote }),
|
|
914
|
+
canReRequest && /* @__PURE__ */ jsx4("div", { className: "mt-4 flex items-center justify-end", children: /* @__PURE__ */ jsx4(InteractionActionButton, { variant: "outline", onClick: () => void requestReSubmission(), disabled: submitting !== null, children: submitting === "requesting" ? "Asking\u2026" : reRequestLabel ?? DEFAULT_RE_REQUEST_LABEL }) }),
|
|
915
|
+
reRequested && /* @__PURE__ */ jsx4("div", { className: "mt-4 flex items-center justify-end", children: /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
916
|
+
/* @__PURE__ */ jsx4(CheckGlyph2, { className: "h-3 w-3" }),
|
|
917
|
+
"Re-submission requested"
|
|
918
|
+
] }) }),
|
|
919
|
+
status === "pending" && /* @__PURE__ */ jsxs3("div", { className: "mt-4 flex items-center justify-end gap-2", children: [
|
|
920
|
+
/* @__PURE__ */ jsx4(InteractionActionButton, { variant: "outline", onClick: () => void submit("declined"), disabled, children: submitting === "reject" ? "Sending\u2026" : "Request changes" }),
|
|
921
|
+
/* @__PURE__ */ jsx4(InteractionActionButton, { onClick: () => void submit("accepted"), disabled: disabled || approveData === null, children: submitting === "approve" ? "Approving\u2026" : "Approve plan" })
|
|
922
|
+
] }),
|
|
923
|
+
approved && /* @__PURE__ */ jsx4("div", { className: "mt-4 flex items-center justify-end", children: /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
924
|
+
/* @__PURE__ */ jsx4(CheckGlyph2, { className: "h-3 w-3" }),
|
|
925
|
+
"Approved"
|
|
926
|
+
] }) })
|
|
927
|
+
] })
|
|
928
|
+
);
|
|
882
929
|
}
|
|
883
930
|
|
|
884
931
|
// src/web-react/durable-chat-cards.tsx
|
|
@@ -968,7 +1015,7 @@ function DurableChatCards({
|
|
|
968
1015
|
}
|
|
969
1016
|
|
|
970
1017
|
// src/web-react/message-attachments.tsx
|
|
971
|
-
import { useCallback, useEffect as useEffect4, useState as
|
|
1018
|
+
import { useCallback, useEffect as useEffect4, useState as useState6 } from "react";
|
|
972
1019
|
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
973
1020
|
function FileGlyph({ className }) {
|
|
974
1021
|
return /* @__PURE__ */ jsxs4("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
@@ -1043,7 +1090,7 @@ function triggerAttachmentDownload(name, blob) {
|
|
|
1043
1090
|
}
|
|
1044
1091
|
}
|
|
1045
1092
|
function useAttachmentObjectUrl(blob) {
|
|
1046
|
-
const [url, setUrl] =
|
|
1093
|
+
const [url, setUrl] = useState6(null);
|
|
1047
1094
|
useEffect4(() => {
|
|
1048
1095
|
if (!blob) {
|
|
1049
1096
|
setUrl(null);
|
|
@@ -1090,7 +1137,7 @@ function AttachmentUnavailable({ shape }) {
|
|
|
1090
1137
|
function AttachmentThumbnail({ part, resolveFileUrl, fetchFile }) {
|
|
1091
1138
|
const url = resolveFileUrl(part);
|
|
1092
1139
|
const displayName = attachmentDisplayName(part);
|
|
1093
|
-
const [result, setResult] =
|
|
1140
|
+
const [result, setResult] = useState6(null);
|
|
1094
1141
|
useEffect4(() => {
|
|
1095
1142
|
if (!displayName) return;
|
|
1096
1143
|
let cancelled = false;
|
|
@@ -1129,8 +1176,8 @@ function AttachmentThumbnail({ part, resolveFileUrl, fetchFile }) {
|
|
|
1129
1176
|
}
|
|
1130
1177
|
function AttachmentChip({ part, resolveFileUrl, fetchFile }) {
|
|
1131
1178
|
const displayName = attachmentDisplayName(part);
|
|
1132
|
-
const [status, setStatus] =
|
|
1133
|
-
const [errorMessage, setErrorMessage] =
|
|
1179
|
+
const [status, setStatus] = useState6("idle");
|
|
1180
|
+
const [errorMessage, setErrorMessage] = useState6(null);
|
|
1134
1181
|
const handleClick = useCallback(() => {
|
|
1135
1182
|
if (!displayName || status === "loading") return;
|
|
1136
1183
|
setStatus("loading");
|
|
@@ -1369,7 +1416,7 @@ import {
|
|
|
1369
1416
|
useCallback as useCallback2,
|
|
1370
1417
|
useEffect as useEffect5,
|
|
1371
1418
|
useRef as useRef5,
|
|
1372
|
-
useState as
|
|
1419
|
+
useState as useState7
|
|
1373
1420
|
} from "react";
|
|
1374
1421
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1375
1422
|
var IS_APPLE_PLATFORM = typeof navigator !== "undefined" && /Mac|iPhone|iPad|iPod/i.test(navigator.platform);
|
|
@@ -1441,14 +1488,14 @@ function ChatComposer({
|
|
|
1441
1488
|
className
|
|
1442
1489
|
}) {
|
|
1443
1490
|
const isControlled = value !== void 0;
|
|
1444
|
-
const [internal, setInternal] =
|
|
1491
|
+
const [internal, setInternal] = useState7(initialValue ?? "");
|
|
1445
1492
|
const text = isControlled ? value : internal;
|
|
1446
1493
|
const textRef = useRef5(text);
|
|
1447
1494
|
textRef.current = text;
|
|
1448
1495
|
const textareaRef = useRef5(null);
|
|
1449
1496
|
const fileInputRef = useRef5(null);
|
|
1450
1497
|
const folderInputRef = useRef5(null);
|
|
1451
|
-
const [dragOver, setDragOver] =
|
|
1498
|
+
const [dragOver, setDragOver] = useState7(false);
|
|
1452
1499
|
const dragDepth = useRef5(0);
|
|
1453
1500
|
const setText = useCallback2(
|
|
1454
1501
|
(next) => {
|
|
@@ -1514,7 +1561,7 @@ function ChatComposer({
|
|
|
1514
1561
|
const readyFileCount = pendingFiles.filter((f) => f.status === "ready").length;
|
|
1515
1562
|
const hasSendable = text.trim().length > 0 || readyFileCount > 0;
|
|
1516
1563
|
const canSend = hasSendable && !isStreaming && !disabled;
|
|
1517
|
-
const [failedSend, setFailedSend] =
|
|
1564
|
+
const [failedSend, setFailedSend] = useState7(null);
|
|
1518
1565
|
const failSend = useCallback2(
|
|
1519
1566
|
(error, draft, trimmed, parts, caret) => {
|
|
1520
1567
|
const message = sendFailureText(error, sendFailureMessage);
|
|
@@ -1822,7 +1869,7 @@ function ChatComposer({
|
|
|
1822
1869
|
}
|
|
1823
1870
|
|
|
1824
1871
|
// src/web-react/durable-plan-flow.ts
|
|
1825
|
-
import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef6, useState as
|
|
1872
|
+
import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef6, useState as useState8 } from "react";
|
|
1826
1873
|
var DurablePlanClientError = class extends Error {
|
|
1827
1874
|
constructor(message, status, code, currentPlan) {
|
|
1828
1875
|
super(message);
|
|
@@ -1909,10 +1956,10 @@ function createDurablePlanDecisionClient(options) {
|
|
|
1909
1956
|
};
|
|
1910
1957
|
}
|
|
1911
1958
|
function useDurablePlanFlow(options) {
|
|
1912
|
-
const [plan, setPlan] =
|
|
1913
|
-
const [deciding, setDeciding] =
|
|
1914
|
-
const [restoring, setRestoring] =
|
|
1915
|
-
const [error, setError] =
|
|
1959
|
+
const [plan, setPlan] = useState8(options.plan);
|
|
1960
|
+
const [deciding, setDeciding] = useState8(null);
|
|
1961
|
+
const [restoring, setRestoring] = useState8(false);
|
|
1962
|
+
const [error, setError] = useState8(null);
|
|
1916
1963
|
const attachments = useRef6(/* @__PURE__ */ new Map());
|
|
1917
1964
|
const decisionInFlight = useRef6(false);
|
|
1918
1965
|
useEffect6(() => setPlan(options.plan), [options.plan]);
|
|
@@ -2084,7 +2131,7 @@ function createDurableInteractionAnswerSubmitter(options) {
|
|
|
2084
2131
|
}
|
|
2085
2132
|
|
|
2086
2133
|
// src/web-react/use-chat-interactions.ts
|
|
2087
|
-
import { useCallback as useCallback4, useMemo as useMemo3, useState as
|
|
2134
|
+
import { useCallback as useCallback4, useMemo as useMemo3, useState as useState9 } from "react";
|
|
2088
2135
|
function hasPendingContentDuplicate(list, interaction) {
|
|
2089
2136
|
if (interaction.status !== "pending") return false;
|
|
2090
2137
|
const signature = questionInteractionContentSignature(interaction);
|
|
@@ -2163,7 +2210,7 @@ function hydrateChatInteractions(list, persisted) {
|
|
|
2163
2210
|
return persisted.reduce(upsertChatInteraction, list);
|
|
2164
2211
|
}
|
|
2165
2212
|
function useChatInteractions(options = {}) {
|
|
2166
|
-
const [interactions, setInteractions] =
|
|
2213
|
+
const [interactions, setInteractions] = useState9([]);
|
|
2167
2214
|
const upsert = useCallback4((interaction) => {
|
|
2168
2215
|
setInteractions((prev) => upsertChatInteraction(prev, interaction));
|
|
2169
2216
|
}, []);
|
|
@@ -2190,7 +2237,7 @@ function useChatInteractions(options = {}) {
|
|
|
2190
2237
|
}
|
|
2191
2238
|
|
|
2192
2239
|
// src/web-react/use-file-mentions.ts
|
|
2193
|
-
import { useCallback as useCallback5, useMemo as useMemo4, useRef as useRef7, useState as
|
|
2240
|
+
import { useCallback as useCallback5, useMemo as useMemo4, useRef as useRef7, useState as useState10 } from "react";
|
|
2194
2241
|
var FILE_MENTION_KIND = "file";
|
|
2195
2242
|
function toMentionItem(file) {
|
|
2196
2243
|
return { id: file.path, label: file.name, detail: file.path, kind: FILE_MENTION_KIND };
|
|
@@ -2248,11 +2295,11 @@ function useFileMentions(options) {
|
|
|
2248
2295
|
emptyText = DEFAULT_MENTION_EMPTY_TEXT
|
|
2249
2296
|
} = options;
|
|
2250
2297
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
2251
|
-
const [state, setState] =
|
|
2298
|
+
const [state, setState] = useState10({ kind: "idle" });
|
|
2252
2299
|
const stateRef = useRef7(state);
|
|
2253
2300
|
stateRef.current = state;
|
|
2254
2301
|
const inFlightRef = useRef7(null);
|
|
2255
|
-
const [mentions, setMentions] =
|
|
2302
|
+
const [mentions, setMentions] = useState10([]);
|
|
2256
2303
|
const load = useCallback5(() => {
|
|
2257
2304
|
if (inFlightRef.current) return inFlightRef.current;
|
|
2258
2305
|
if (stateRef.current.kind === "idle") {
|
|
@@ -2361,7 +2408,7 @@ function segmentMentionContent(content, parts) {
|
|
|
2361
2408
|
}
|
|
2362
2409
|
|
|
2363
2410
|
// src/web-react/mission-activity.tsx
|
|
2364
|
-
import { useCallback as useCallback6, useEffect as useEffect7, useState as
|
|
2411
|
+
import { useCallback as useCallback6, useEffect as useEffect7, useState as useState11 } from "react";
|
|
2365
2412
|
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2366
2413
|
var LIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "running"]);
|
|
2367
2414
|
var OK_STATUSES = /* @__PURE__ */ new Set(["completed", "done", "succeeded"]);
|
|
@@ -2421,7 +2468,7 @@ function CopyGlyph({ className }) {
|
|
|
2421
2468
|
] });
|
|
2422
2469
|
}
|
|
2423
2470
|
function TraceIdCopy({ traceId }) {
|
|
2424
|
-
const [copied, setCopied] =
|
|
2471
|
+
const [copied, setCopied] = useState11(false);
|
|
2425
2472
|
const copy = useCallback6(() => {
|
|
2426
2473
|
void navigator.clipboard?.writeText(traceId).then(
|
|
2427
2474
|
() => {
|
|
@@ -2454,12 +2501,21 @@ function StatusDot({ tone }) {
|
|
|
2454
2501
|
"span",
|
|
2455
2502
|
{
|
|
2456
2503
|
"aria-hidden": true,
|
|
2457
|
-
className: `h-2 w-2 shrink-0 rounded-full ${tone === "live" ? "
|
|
2504
|
+
className: `h-2 w-2 shrink-0 rounded-full ${tone === "live" ? "bg-warning" : tone === "ok" ? "bg-success" : tone === "error" ? "bg-destructive" : "bg-muted-foreground/40"}`
|
|
2458
2505
|
}
|
|
2459
2506
|
),
|
|
2460
2507
|
/* @__PURE__ */ jsx8("span", { className: "sr-only", children: tone })
|
|
2461
2508
|
] });
|
|
2462
2509
|
}
|
|
2510
|
+
function RunLabel({ tool, detail, live }) {
|
|
2511
|
+
return /* @__PURE__ */ jsxs6("span", { className: "min-w-0 flex-1 truncate", children: [
|
|
2512
|
+
/* @__PURE__ */ jsx8("span", { className: live ? "agent-shimmer font-medium" : "font-medium", "data-motion": live ? "essential" : void 0, children: tool }),
|
|
2513
|
+
/* @__PURE__ */ jsxs6("span", { className: "text-muted-foreground", children: [
|
|
2514
|
+
" \u2014 ",
|
|
2515
|
+
detail
|
|
2516
|
+
] })
|
|
2517
|
+
] });
|
|
2518
|
+
}
|
|
2463
2519
|
var BAR_CLASS = {
|
|
2464
2520
|
pipeline: "bg-muted-foreground/30",
|
|
2465
2521
|
model: "bg-primary/60",
|
|
@@ -2488,31 +2544,27 @@ function FlowWaterfall({ trace }) {
|
|
|
2488
2544
|
] })
|
|
2489
2545
|
] });
|
|
2490
2546
|
}
|
|
2547
|
+
function LaneRow({ run, staggerIndex }) {
|
|
2548
|
+
const arrival = useArrivalStyle(staggerIndex);
|
|
2549
|
+
const tone = activityTone(run.status);
|
|
2550
|
+
const cost = formatActivityCost(run.costUsd);
|
|
2551
|
+
const duration = formatActivityDuration(run.durationMs);
|
|
2552
|
+
return /* @__PURE__ */ jsxs6("div", { className: "agent-arrive flex items-center gap-2 py-1 text-xs", style: arrival, children: [
|
|
2553
|
+
/* @__PURE__ */ jsx8(StatusDot, { tone }),
|
|
2554
|
+
/* @__PURE__ */ jsx8(RunLabel, { tool: run.tool, detail: run.detail, live: tone === "live" }),
|
|
2555
|
+
tone === "live" && (run.iteration !== void 0 || run.phase !== void 0) && /* @__PURE__ */ jsx8("span", { className: "shrink-0 rounded-full bg-warning/10 px-1.5 py-0.5 font-mono text-xs text-warning", children: [run.iteration !== void 0 ? `iter ${run.iteration}` : null, run.phase ?? null].filter(Boolean).join(" \xB7 ") }),
|
|
2556
|
+
/* @__PURE__ */ jsxs6("span", { className: "flex shrink-0 items-center gap-1.5 font-mono text-xs tabular-nums text-muted-foreground/70", children: [
|
|
2557
|
+
tone !== "live" && tone !== "ok" && /* @__PURE__ */ jsx8("span", { children: run.status }),
|
|
2558
|
+
cost && /* @__PURE__ */ jsx8("span", { children: cost }),
|
|
2559
|
+
duration && /* @__PURE__ */ jsx8("span", { children: duration })
|
|
2560
|
+
] })
|
|
2561
|
+
] });
|
|
2562
|
+
}
|
|
2491
2563
|
function MissionActivityLane({ activity, startedAt, nowMs }) {
|
|
2492
|
-
const [expanded, setExpanded] =
|
|
2564
|
+
const [expanded, setExpanded] = useState11(false);
|
|
2493
2565
|
if (activity.length === 0) return null;
|
|
2494
2566
|
return /* @__PURE__ */ jsxs6("div", { className: "mt-1 border-l border-border pl-3", children: [
|
|
2495
|
-
activity.map((run) => {
|
|
2496
|
-
const tone = activityTone(run.status);
|
|
2497
|
-
const cost = formatActivityCost(run.costUsd);
|
|
2498
|
-
const duration = formatActivityDuration(run.durationMs);
|
|
2499
|
-
return /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 py-1 text-xs", children: [
|
|
2500
|
-
/* @__PURE__ */ jsx8(StatusDot, { tone }),
|
|
2501
|
-
/* @__PURE__ */ jsxs6("span", { className: "min-w-0 flex-1 truncate", children: [
|
|
2502
|
-
/* @__PURE__ */ jsx8("span", { className: "font-medium", children: run.tool }),
|
|
2503
|
-
/* @__PURE__ */ jsxs6("span", { className: "text-muted-foreground", children: [
|
|
2504
|
-
" \u2014 ",
|
|
2505
|
-
run.detail
|
|
2506
|
-
] })
|
|
2507
|
-
] }),
|
|
2508
|
-
tone === "live" && (run.iteration !== void 0 || run.phase !== void 0) && /* @__PURE__ */ jsx8("span", { className: "shrink-0 rounded-full bg-warning/10 px-1.5 py-0.5 font-mono text-xs text-warning", children: [run.iteration !== void 0 ? `iter ${run.iteration}` : null, run.phase ?? null].filter(Boolean).join(" \xB7 ") }),
|
|
2509
|
-
/* @__PURE__ */ jsxs6("span", { className: "flex shrink-0 items-center gap-1.5 font-mono text-xs tabular-nums text-muted-foreground/70", children: [
|
|
2510
|
-
tone !== "live" && tone !== "ok" && /* @__PURE__ */ jsx8("span", { children: run.status }),
|
|
2511
|
-
cost && /* @__PURE__ */ jsx8("span", { children: cost }),
|
|
2512
|
-
duration && /* @__PURE__ */ jsx8("span", { children: duration })
|
|
2513
|
-
] })
|
|
2514
|
-
] }, run.taskId);
|
|
2515
|
-
}),
|
|
2567
|
+
activity.map((run, index) => /* @__PURE__ */ jsx8(LaneRow, { run, staggerIndex: index }, run.taskId)),
|
|
2516
2568
|
/* @__PURE__ */ jsxs6(
|
|
2517
2569
|
"button",
|
|
2518
2570
|
{
|
|
@@ -2538,22 +2590,18 @@ function MissionActivityLane({ activity, startedAt, nowMs }) {
|
|
|
2538
2590
|
}
|
|
2539
2591
|
function ActivityRow({
|
|
2540
2592
|
record,
|
|
2541
|
-
renderMissionRef
|
|
2593
|
+
renderMissionRef,
|
|
2594
|
+
staggerIndex
|
|
2542
2595
|
}) {
|
|
2543
|
-
const
|
|
2596
|
+
const arrival = useArrivalStyle(staggerIndex);
|
|
2597
|
+
const [open, setOpen] = useState11(false);
|
|
2544
2598
|
const tone = activityTone(record.status);
|
|
2545
2599
|
const cost = formatActivityCost(record.costUsd);
|
|
2546
2600
|
const duration = formatActivityDuration(record.durationMs);
|
|
2547
|
-
return /* @__PURE__ */ jsxs6("div", { className: "rounded-lg border border-card-edge bg-card", children: [
|
|
2601
|
+
return /* @__PURE__ */ jsxs6("div", { className: "agent-arrive rounded-lg border border-card-edge bg-card", style: arrival, children: [
|
|
2548
2602
|
/* @__PURE__ */ jsxs6("button", { type: "button", onClick: () => setOpen((v) => !v), className: "flex w-full items-center gap-2.5 px-3 py-2 text-left text-sm", children: [
|
|
2549
2603
|
/* @__PURE__ */ jsx8(StatusDot, { tone }),
|
|
2550
|
-
/* @__PURE__ */
|
|
2551
|
-
/* @__PURE__ */ jsx8("span", { className: "font-medium", children: record.tool }),
|
|
2552
|
-
/* @__PURE__ */ jsxs6("span", { className: "text-muted-foreground", children: [
|
|
2553
|
-
" \u2014 ",
|
|
2554
|
-
record.detail
|
|
2555
|
-
] })
|
|
2556
|
-
] }),
|
|
2604
|
+
/* @__PURE__ */ jsx8(RunLabel, { tool: record.tool, detail: record.detail, live: tone === "live" }),
|
|
2557
2605
|
tone === "live" && (record.iteration !== void 0 || record.phase !== void 0) && /* @__PURE__ */ jsx8("span", { className: "shrink-0 rounded-full bg-warning/10 px-2 py-0.5 font-mono text-xs text-warning", children: [record.iteration !== void 0 ? `iter ${record.iteration}` : null, record.phase ?? null].filter(Boolean).join(" \xB7 ") }),
|
|
2558
2606
|
/* @__PURE__ */ jsx8(
|
|
2559
2607
|
"span",
|
|
@@ -2586,10 +2634,10 @@ function ActivityRow({
|
|
|
2586
2634
|
] });
|
|
2587
2635
|
}
|
|
2588
2636
|
function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent activity", emptyLabel = "No agent runs yet." }) {
|
|
2589
|
-
const [rows, setRows] =
|
|
2590
|
-
const [cursor, setCursor] =
|
|
2591
|
-
const [status, setStatus] =
|
|
2592
|
-
const [error, setError] =
|
|
2637
|
+
const [rows, setRows] = useState11([]);
|
|
2638
|
+
const [cursor, setCursor] = useState11(void 0);
|
|
2639
|
+
const [status, setStatus] = useState11("loading");
|
|
2640
|
+
const [error, setError] = useState11(null);
|
|
2593
2641
|
const load = useCallback6(
|
|
2594
2642
|
async (from) => {
|
|
2595
2643
|
setStatus("loading");
|
|
@@ -2628,7 +2676,7 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
|
|
|
2628
2676
|
status === "error" && /* @__PURE__ */ jsx8("p", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: error }),
|
|
2629
2677
|
status === "ready" && rows.length === 0 && /* @__PURE__ */ jsx8("p", { className: "px-1 text-sm text-muted-foreground", children: emptyLabel }),
|
|
2630
2678
|
/* @__PURE__ */ jsx8("span", { role: "status", "aria-live": "polite", "aria-busy": loading, className: "sr-only", children: loading ? "Loading activity\u2026" : "" }),
|
|
2631
|
-
/* @__PURE__ */ jsx8("div", { className: "space-y-1.5", "aria-busy": loading, children: rows.map((record) => /* @__PURE__ */ jsx8(ActivityRow, { record, renderMissionRef }, record.taskId)) }),
|
|
2679
|
+
/* @__PURE__ */ jsx8("div", { className: "space-y-1.5", "aria-busy": loading, children: rows.map((record, index) => /* @__PURE__ */ jsx8(ActivityRow, { record, renderMissionRef, staggerIndex: index }, record.taskId)) }),
|
|
2632
2680
|
cursor && /* @__PURE__ */ jsx8(
|
|
2633
2681
|
"button",
|
|
2634
2682
|
{
|
|
@@ -2643,7 +2691,7 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
|
|
|
2643
2691
|
}
|
|
2644
2692
|
|
|
2645
2693
|
// src/web-react/provenance.tsx
|
|
2646
|
-
import { useCallback as useCallback7, useEffect as useEffect8, useId, useRef as useRef8, useState as
|
|
2694
|
+
import { useCallback as useCallback7, useEffect as useEffect8, useId, useRef as useRef8, useState as useState12 } from "react";
|
|
2647
2695
|
|
|
2648
2696
|
// src/web-react/provenance-model.ts
|
|
2649
2697
|
var PROVENANCE_BASES = ["extracted", "entered", "computed", "asserted"];
|
|
@@ -2937,7 +2985,7 @@ function ProvenanceValue({
|
|
|
2937
2985
|
missingValueLabel = DEFAULT_MISSING_VALUE_LABEL,
|
|
2938
2986
|
className
|
|
2939
2987
|
}) {
|
|
2940
|
-
const [open, setOpen] =
|
|
2988
|
+
const [open, setOpen] = useState12(defaultOpen);
|
|
2941
2989
|
const triggerRef = useRef8(null);
|
|
2942
2990
|
const rootRef = useRef8(null);
|
|
2943
2991
|
const panelId = useId();
|
|
@@ -3223,7 +3271,7 @@ import {
|
|
|
3223
3271
|
useId as useId2,
|
|
3224
3272
|
useMemo as useMemo5,
|
|
3225
3273
|
useRef as useRef9,
|
|
3226
|
-
useState as
|
|
3274
|
+
useState as useState13
|
|
3227
3275
|
} from "react";
|
|
3228
3276
|
import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3229
3277
|
function rethrowAsync(error) {
|
|
@@ -3232,7 +3280,7 @@ function rethrowAsync(error) {
|
|
|
3232
3280
|
});
|
|
3233
3281
|
}
|
|
3234
3282
|
function useInfiniteScroll(onLoadMore, { enabled, root, rootMargin = "300px" }) {
|
|
3235
|
-
const [sentinel, setSentinel] =
|
|
3283
|
+
const [sentinel, setSentinel] = useState13(null);
|
|
3236
3284
|
const sentinelRef = useCallback8((node) => setSentinel(node), []);
|
|
3237
3285
|
const onLoadMoreRef = useRef9(onLoadMore);
|
|
3238
3286
|
useEffect9(() => {
|
|
@@ -3267,10 +3315,10 @@ function useSessionHistory({
|
|
|
3267
3315
|
initialPage,
|
|
3268
3316
|
defaultSort = "newest"
|
|
3269
3317
|
}) {
|
|
3270
|
-
const [items, setItems] =
|
|
3271
|
-
const [nextCursor, setNextCursor] =
|
|
3272
|
-
const [phase, setPhase] =
|
|
3273
|
-
const [reloadKey, setReloadKey] =
|
|
3318
|
+
const [items, setItems] = useState13(initialPage.items);
|
|
3319
|
+
const [nextCursor, setNextCursor] = useState13(initialPage.nextCursor ?? null);
|
|
3320
|
+
const [phase, setPhase] = useState13("idle");
|
|
3321
|
+
const [reloadKey, setReloadKey] = useState13(0);
|
|
3274
3322
|
const seqRef = useRef9(0);
|
|
3275
3323
|
const resetAbortRef = useRef9(null);
|
|
3276
3324
|
const loadMoreAbortRef = useRef9(null);
|
|
@@ -3388,11 +3436,11 @@ function useSessionActions({
|
|
|
3388
3436
|
labels
|
|
3389
3437
|
}) {
|
|
3390
3438
|
const text = { ...DEFAULT_LABELS, ...labels };
|
|
3391
|
-
const [renameTarget, setRenameTarget] =
|
|
3392
|
-
const [renameValue, setRenameValue] =
|
|
3393
|
-
const [deleteTarget, setDeleteTarget] =
|
|
3394
|
-
const [busy, setBusy] =
|
|
3395
|
-
const [error, setError] =
|
|
3439
|
+
const [renameTarget, setRenameTarget] = useState13(null);
|
|
3440
|
+
const [renameValue, setRenameValue] = useState13("");
|
|
3441
|
+
const [deleteTarget, setDeleteTarget] = useState13(null);
|
|
3442
|
+
const [busy, setBusy] = useState13(false);
|
|
3443
|
+
const [error, setError] = useState13(null);
|
|
3396
3444
|
const openRename = useCallback8((session) => {
|
|
3397
3445
|
setError(null);
|
|
3398
3446
|
setRenameTarget(session);
|
|
@@ -3618,11 +3666,11 @@ function SessionHistoryPanel({
|
|
|
3618
3666
|
const searchTerm = query.trim();
|
|
3619
3667
|
const isSearching = searchTerm.length > 0;
|
|
3620
3668
|
const column = contentWidth === "full" ? "w-full" : "mx-auto w-full max-w-4xl";
|
|
3621
|
-
const [selectedIds, setSelectedIds] =
|
|
3622
|
-
const [ageDays, setAgeDays] =
|
|
3623
|
-
const [bulkTarget, setBulkTarget] =
|
|
3624
|
-
const [bulkBusy, setBulkBusy] =
|
|
3625
|
-
const [bulkError, setBulkError] =
|
|
3669
|
+
const [selectedIds, setSelectedIds] = useState13(/* @__PURE__ */ new Set());
|
|
3670
|
+
const [ageDays, setAgeDays] = useState13("30");
|
|
3671
|
+
const [bulkTarget, setBulkTarget] = useState13(null);
|
|
3672
|
+
const [bulkBusy, setBulkBusy] = useState13(false);
|
|
3673
|
+
const [bulkError, setBulkError] = useState13(null);
|
|
3626
3674
|
useEffect9(() => {
|
|
3627
3675
|
setSelectedIds(/* @__PURE__ */ new Set());
|
|
3628
3676
|
}, [searchTerm, sort]);
|
|
@@ -3902,7 +3950,7 @@ function SessionRow({
|
|
|
3902
3950
|
selected,
|
|
3903
3951
|
onSelectedChange
|
|
3904
3952
|
}) {
|
|
3905
|
-
const [menuOpen, setMenuOpen] =
|
|
3953
|
+
const [menuOpen, setMenuOpen] = useState13(false);
|
|
3906
3954
|
const panelId = useId2();
|
|
3907
3955
|
const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(menuOpen, setMenuOpen);
|
|
3908
3956
|
const extras = extraActions?.(session) ?? [];
|
|
@@ -4011,7 +4059,7 @@ import {
|
|
|
4011
4059
|
useId as useId3,
|
|
4012
4060
|
useMemo as useMemo6,
|
|
4013
4061
|
useRef as useRef10,
|
|
4014
|
-
useState as
|
|
4062
|
+
useState as useState14
|
|
4015
4063
|
} from "react";
|
|
4016
4064
|
|
|
4017
4065
|
// src/web-react/record-grid-model.ts
|
|
@@ -4396,19 +4444,19 @@ function RecordGrid({
|
|
|
4396
4444
|
className
|
|
4397
4445
|
}) {
|
|
4398
4446
|
const fieldPrefix = useId3();
|
|
4399
|
-
const [overlay, setOverlay] =
|
|
4400
|
-
const [editing, setEditingState] =
|
|
4401
|
-
const [cellErrors, setCellErrors] =
|
|
4402
|
-
const [rowErrors, setRowErrors] =
|
|
4403
|
-
const [pendingRows, setPendingRows] =
|
|
4404
|
-
const [focus, setFocus] =
|
|
4405
|
-
const [openSource, setOpenSource] =
|
|
4406
|
-
const [confirmDelete, setConfirmDelete] =
|
|
4407
|
-
const [adding, setAdding] =
|
|
4408
|
-
const [draft, setDraft] =
|
|
4409
|
-
const [draftErrors, setDraftErrors] =
|
|
4410
|
-
const [draftError, setDraftError] =
|
|
4411
|
-
const [creating, setCreating] =
|
|
4447
|
+
const [overlay, setOverlay] = useState14(EMPTY_RECORD_GRID_OVERLAY);
|
|
4448
|
+
const [editing, setEditingState] = useState14(null);
|
|
4449
|
+
const [cellErrors, setCellErrors] = useState14({});
|
|
4450
|
+
const [rowErrors, setRowErrors] = useState14({});
|
|
4451
|
+
const [pendingRows, setPendingRows] = useState14({});
|
|
4452
|
+
const [focus, setFocus] = useState14(null);
|
|
4453
|
+
const [openSource, setOpenSource] = useState14(null);
|
|
4454
|
+
const [confirmDelete, setConfirmDelete] = useState14(null);
|
|
4455
|
+
const [adding, setAdding] = useState14(false);
|
|
4456
|
+
const [draft, setDraft] = useState14({ ...newRowDefaults ?? {} });
|
|
4457
|
+
const [draftErrors, setDraftErrors] = useState14({});
|
|
4458
|
+
const [draftError, setDraftError] = useState14(null);
|
|
4459
|
+
const [creating, setCreating] = useState14(false);
|
|
4412
4460
|
const cellRefs = useRef10(/* @__PURE__ */ new Map());
|
|
4413
4461
|
const settling = useRef10(false);
|
|
4414
4462
|
const draftCounter = useRef10(0);
|
|
@@ -5243,8 +5291,594 @@ function DraftField({ column, id, value, invalid, describedBy, onValue }) {
|
|
|
5243
5291
|
);
|
|
5244
5292
|
}
|
|
5245
5293
|
|
|
5294
|
+
// src/web-react/class-names.ts
|
|
5295
|
+
function joinClasses(...parts) {
|
|
5296
|
+
const kept = [];
|
|
5297
|
+
for (const part of parts) {
|
|
5298
|
+
if (typeof part !== "string") continue;
|
|
5299
|
+
const trimmed = part.trim();
|
|
5300
|
+
if (trimmed.length > 0) kept.push(trimmed);
|
|
5301
|
+
}
|
|
5302
|
+
return kept.join(" ");
|
|
5303
|
+
}
|
|
5304
|
+
|
|
5305
|
+
// src/web-react/sparkline.tsx
|
|
5306
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
5307
|
+
var DEFAULT_SPARKLINE_WIDTH = 96;
|
|
5308
|
+
var DEFAULT_SPARKLINE_HEIGHT = 24;
|
|
5309
|
+
var DEFAULT_INSET = 2.5;
|
|
5310
|
+
var STROKE_WIDTH = 1.5;
|
|
5311
|
+
var DOT_RADIUS = 1.75;
|
|
5312
|
+
var DEFAULT_SPARKLINE_LABEL = "Trend";
|
|
5313
|
+
var DEFAULT_SPARKLINE_EMPTY_LABEL = "No history yet";
|
|
5314
|
+
var DEFAULT_SPARKLINE_UNAVAILABLE_LABEL = "No readings available";
|
|
5315
|
+
var NUMBER_FORMAT = new Intl.NumberFormat("en-US", { maximumFractionDigits: 2 });
|
|
5316
|
+
function formatSparklineValue(value) {
|
|
5317
|
+
return NUMBER_FORMAT.format(value);
|
|
5318
|
+
}
|
|
5319
|
+
function isReading(value) {
|
|
5320
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
5321
|
+
}
|
|
5322
|
+
function sparklineReadings(values) {
|
|
5323
|
+
return values.filter(isReading);
|
|
5324
|
+
}
|
|
5325
|
+
function round(value) {
|
|
5326
|
+
return Math.round(value * 100) / 100;
|
|
5327
|
+
}
|
|
5328
|
+
function sparklineGeometry(values, { width = DEFAULT_SPARKLINE_WIDTH, height = DEFAULT_SPARKLINE_HEIGHT, inset = DEFAULT_INSET } = {}) {
|
|
5329
|
+
const samples = values.length;
|
|
5330
|
+
const plotted = [];
|
|
5331
|
+
for (let index = 0; index < samples; index += 1) {
|
|
5332
|
+
const value = values[index];
|
|
5333
|
+
if (isReading(value)) plotted.push({ index, value });
|
|
5334
|
+
}
|
|
5335
|
+
const readings = plotted.map((entry) => entry.value);
|
|
5336
|
+
const gaps = samples - readings.length;
|
|
5337
|
+
if (readings.length === 0) {
|
|
5338
|
+
return { readings, points: [], segments: [], gaps, min: 0, max: 0, first: 0, last: 0, direction: "flat" };
|
|
5339
|
+
}
|
|
5340
|
+
let min = readings[0];
|
|
5341
|
+
let max = readings[0];
|
|
5342
|
+
for (const value of readings) {
|
|
5343
|
+
if (value < min) min = value;
|
|
5344
|
+
if (value > max) max = value;
|
|
5345
|
+
}
|
|
5346
|
+
const first = readings[0];
|
|
5347
|
+
const last = readings[readings.length - 1];
|
|
5348
|
+
const span = max - min;
|
|
5349
|
+
const top = inset;
|
|
5350
|
+
const bottom = height - inset;
|
|
5351
|
+
const left = inset;
|
|
5352
|
+
const right = width - inset;
|
|
5353
|
+
const points = plotted.map(({ index, value }) => ({
|
|
5354
|
+
// A series of ONE SAMPLE sits in the middle rather than at the left edge,
|
|
5355
|
+
// where it reads as the start of a line whose rest failed to render. A
|
|
5356
|
+
// single reading among several samples keeps its own position — that is the
|
|
5357
|
+
// one thing that says where in the window the reading is.
|
|
5358
|
+
x: round(samples <= 1 ? width / 2 : left + (right - left) * index / (samples - 1)),
|
|
5359
|
+
// `span === 0` is the stable metric. Mid-height is the honest render of it;
|
|
5360
|
+
// dividing by the span here is the NaN that erases the whole polyline.
|
|
5361
|
+
y: round(span === 0 ? height / 2 : bottom - (bottom - top) * (value - min) / span)
|
|
5362
|
+
}));
|
|
5363
|
+
const segments = [];
|
|
5364
|
+
let run = [];
|
|
5365
|
+
let previous = Number.NEGATIVE_INFINITY;
|
|
5366
|
+
plotted.forEach(({ index }, position) => {
|
|
5367
|
+
if (index !== previous + 1 && run.length > 0) {
|
|
5368
|
+
segments.push(run);
|
|
5369
|
+
run = [];
|
|
5370
|
+
}
|
|
5371
|
+
run.push(points[position]);
|
|
5372
|
+
previous = index;
|
|
5373
|
+
});
|
|
5374
|
+
if (run.length > 0) segments.push(run);
|
|
5375
|
+
return {
|
|
5376
|
+
readings,
|
|
5377
|
+
points,
|
|
5378
|
+
segments,
|
|
5379
|
+
gaps,
|
|
5380
|
+
min,
|
|
5381
|
+
max,
|
|
5382
|
+
first,
|
|
5383
|
+
last,
|
|
5384
|
+
direction: last > first ? "rising" : last < first ? "falling" : "flat"
|
|
5385
|
+
};
|
|
5386
|
+
}
|
|
5387
|
+
function sparklinePointsAttribute(points) {
|
|
5388
|
+
return points.map((point) => `${point.x},${point.y}`).join(" ");
|
|
5389
|
+
}
|
|
5390
|
+
function sparklineLabel(values, { label = DEFAULT_SPARKLINE_LABEL, format = formatSparklineValue } = {}) {
|
|
5391
|
+
const { readings, gaps, min, max, first, last, direction } = sparklineGeometry(values);
|
|
5392
|
+
const missing = gaps === 0 ? "" : `, ${gaps} not available`;
|
|
5393
|
+
if (readings.length === 0) return gaps === 0 ? `${label}: no readings yet` : `${label}: no readings${missing}`;
|
|
5394
|
+
if (readings.length === 1) return `${label}: one reading${missing}, ${format(first)}`;
|
|
5395
|
+
if (max === min) return `${label}: ${readings.length} readings${missing}, unchanged at ${format(first)}`;
|
|
5396
|
+
const movement = direction === "flat" ? "net unchanged" : direction;
|
|
5397
|
+
return `${label}: ${readings.length} readings${missing}, range ${format(min)} to ${format(max)}, ${movement} from ${format(first)} to ${format(last)}`;
|
|
5398
|
+
}
|
|
5399
|
+
function Sparkline({
|
|
5400
|
+
values,
|
|
5401
|
+
label = DEFAULT_SPARKLINE_LABEL,
|
|
5402
|
+
format = formatSparklineValue,
|
|
5403
|
+
width = DEFAULT_SPARKLINE_WIDTH,
|
|
5404
|
+
height = DEFAULT_SPARKLINE_HEIGHT,
|
|
5405
|
+
emptyLabel = DEFAULT_SPARKLINE_EMPTY_LABEL,
|
|
5406
|
+
unavailableLabel = DEFAULT_SPARKLINE_UNAVAILABLE_LABEL,
|
|
5407
|
+
className
|
|
5408
|
+
}) {
|
|
5409
|
+
const geometry = sparklineGeometry(values, { width, height });
|
|
5410
|
+
const accessibleName = sparklineLabel(values, { label, format });
|
|
5411
|
+
if (geometry.points.length === 0) {
|
|
5412
|
+
return /* @__PURE__ */ jsxs11(
|
|
5413
|
+
"span",
|
|
5414
|
+
{
|
|
5415
|
+
"data-sparkline": geometry.gaps > 0 ? "unavailable" : "empty",
|
|
5416
|
+
className: joinClasses("text-[11px] text-muted-foreground", className),
|
|
5417
|
+
children: [
|
|
5418
|
+
/* @__PURE__ */ jsx13("span", { className: "sr-only", children: accessibleName }),
|
|
5419
|
+
/* @__PURE__ */ jsx13("span", { "aria-hidden": "true", children: geometry.gaps > 0 ? unavailableLabel : emptyLabel })
|
|
5420
|
+
]
|
|
5421
|
+
}
|
|
5422
|
+
);
|
|
5423
|
+
}
|
|
5424
|
+
const drawsLine = geometry.segments.some((segment) => segment.length > 1);
|
|
5425
|
+
const end = geometry.points[geometry.points.length - 1];
|
|
5426
|
+
return /* @__PURE__ */ jsxs11(
|
|
5427
|
+
"svg",
|
|
5428
|
+
{
|
|
5429
|
+
role: "img",
|
|
5430
|
+
"aria-label": accessibleName,
|
|
5431
|
+
"data-sparkline": drawsLine ? "line" : "point",
|
|
5432
|
+
"data-direction": geometry.direction,
|
|
5433
|
+
"data-gaps": geometry.gaps > 0 ? geometry.gaps : void 0,
|
|
5434
|
+
width,
|
|
5435
|
+
height,
|
|
5436
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
5437
|
+
className,
|
|
5438
|
+
focusable: "false",
|
|
5439
|
+
children: [
|
|
5440
|
+
geometry.segments.map((segment, index) => {
|
|
5441
|
+
const key = `segment-${index}`;
|
|
5442
|
+
if (segment.length > 1) {
|
|
5443
|
+
return /* @__PURE__ */ jsx13(
|
|
5444
|
+
"polyline",
|
|
5445
|
+
{
|
|
5446
|
+
points: sparklinePointsAttribute(segment),
|
|
5447
|
+
fill: "none",
|
|
5448
|
+
stroke: "currentColor",
|
|
5449
|
+
strokeWidth: STROKE_WIDTH,
|
|
5450
|
+
strokeLinecap: "round",
|
|
5451
|
+
strokeLinejoin: "round",
|
|
5452
|
+
vectorEffect: "non-scaling-stroke"
|
|
5453
|
+
},
|
|
5454
|
+
key
|
|
5455
|
+
);
|
|
5456
|
+
}
|
|
5457
|
+
const only = segment[0];
|
|
5458
|
+
if (only.x === end.x && only.y === end.y) return null;
|
|
5459
|
+
return /* @__PURE__ */ jsx13("circle", { cx: only.x, cy: only.y, r: DOT_RADIUS, fill: "currentColor" }, key);
|
|
5460
|
+
}),
|
|
5461
|
+
/* @__PURE__ */ jsx13("circle", { cx: end.x, cy: end.y, r: DOT_RADIUS, fill: "currentColor" })
|
|
5462
|
+
]
|
|
5463
|
+
}
|
|
5464
|
+
);
|
|
5465
|
+
}
|
|
5466
|
+
|
|
5467
|
+
// src/web-react/insight-card.tsx
|
|
5468
|
+
import {
|
|
5469
|
+
isValidElement as isValidElement2,
|
|
5470
|
+
useCallback as useCallback10,
|
|
5471
|
+
useEffect as useEffect11,
|
|
5472
|
+
useRef as useRef11,
|
|
5473
|
+
useState as useState15
|
|
5474
|
+
} from "react";
|
|
5475
|
+
import { Fragment as Fragment7, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
5476
|
+
function insightDelta(value, previous) {
|
|
5477
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return null;
|
|
5478
|
+
if (typeof previous !== "number" || !Number.isFinite(previous)) return null;
|
|
5479
|
+
const absolute = value - previous;
|
|
5480
|
+
return {
|
|
5481
|
+
previous,
|
|
5482
|
+
absolute,
|
|
5483
|
+
percent: previous === 0 ? null : absolute / previous,
|
|
5484
|
+
direction: absolute > 0 ? "up" : absolute < 0 ? "down" : "flat"
|
|
5485
|
+
};
|
|
5486
|
+
}
|
|
5487
|
+
function insightDeltaTone(direction, polarity = "neutral") {
|
|
5488
|
+
if (direction === "flat" || polarity === "neutral") return "neutral";
|
|
5489
|
+
const welcome = polarity === "higher-is-better" ? "up" : "down";
|
|
5490
|
+
return direction === welcome ? "positive" : "negative";
|
|
5491
|
+
}
|
|
5492
|
+
function formatInsightDelta(delta, format = formatSparklineValue) {
|
|
5493
|
+
const from = format(delta.previous);
|
|
5494
|
+
if (delta.direction === "flat") return `No change from ${from}`;
|
|
5495
|
+
const word = delta.direction === "up" ? "Up" : "Down";
|
|
5496
|
+
const magnitude = delta.percent === null ? format(Math.abs(delta.absolute)) : `${(Math.abs(delta.percent) * 100).toFixed(1)}%`;
|
|
5497
|
+
return `${word} ${magnitude} from ${from}`;
|
|
5498
|
+
}
|
|
5499
|
+
var TONE_CLASS = {
|
|
5500
|
+
positive: "text-success",
|
|
5501
|
+
negative: "text-destructive",
|
|
5502
|
+
neutral: "text-muted-foreground"
|
|
5503
|
+
};
|
|
5504
|
+
var DIRECTION_GLYPH = { up: "\u2191", down: "\u2193", flat: "\u2192" };
|
|
5505
|
+
var INSIGHT_UNAVAILABLE_GLYPH = "\u2014";
|
|
5506
|
+
var INSIGHT_UNAVAILABLE_LABEL = "Not available";
|
|
5507
|
+
function InsightCard({
|
|
5508
|
+
title,
|
|
5509
|
+
value,
|
|
5510
|
+
unit,
|
|
5511
|
+
previous,
|
|
5512
|
+
polarity = "neutral",
|
|
5513
|
+
format = formatSparklineValue,
|
|
5514
|
+
series,
|
|
5515
|
+
seriesLabel,
|
|
5516
|
+
description,
|
|
5517
|
+
action,
|
|
5518
|
+
live = false,
|
|
5519
|
+
liveLabel = "Updating",
|
|
5520
|
+
className,
|
|
5521
|
+
style
|
|
5522
|
+
}) {
|
|
5523
|
+
const delta = insightDelta(value, previous);
|
|
5524
|
+
const tone = delta ? insightDeltaTone(delta.direction, polarity) : "neutral";
|
|
5525
|
+
const unavailable = typeof value === "number" && !Number.isFinite(value);
|
|
5526
|
+
const shown = typeof value === "number" ? format(value) : value;
|
|
5527
|
+
return /* @__PURE__ */ jsxs12(
|
|
5528
|
+
"article",
|
|
5529
|
+
{
|
|
5530
|
+
"data-insight-card": "",
|
|
5531
|
+
"data-tone": tone,
|
|
5532
|
+
className: joinClasses("agent-arrive flex h-full flex-col rounded-xl border border-card-edge bg-card p-4", className),
|
|
5533
|
+
style,
|
|
5534
|
+
children: [
|
|
5535
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-baseline justify-between gap-2", children: [
|
|
5536
|
+
/* @__PURE__ */ jsx14("h3", { className: "text-[13px] font-medium text-muted-foreground", children: title }),
|
|
5537
|
+
live ? (
|
|
5538
|
+
// No `data-motion` opt-out: the word is the signal and the sweep is
|
|
5539
|
+
// emphasis, so the reduced-motion floor reaches this like everything
|
|
5540
|
+
// else and leaves a static, legible label.
|
|
5541
|
+
/* @__PURE__ */ jsx14("span", { className: "agent-shimmer shrink-0 text-[11px] font-medium", "data-insight-live": "", children: liveLabel })
|
|
5542
|
+
) : null
|
|
5543
|
+
] }),
|
|
5544
|
+
/* @__PURE__ */ jsx14("p", { className: "mt-1 flex items-baseline gap-1", children: unavailable ? /* @__PURE__ */ jsxs12("span", { "data-insight-value": "unavailable", className: "text-xl font-semibold text-muted-foreground", children: [
|
|
5545
|
+
/* @__PURE__ */ jsx14("span", { "aria-hidden": "true", children: INSIGHT_UNAVAILABLE_GLYPH }),
|
|
5546
|
+
/* @__PURE__ */ jsx14("span", { className: "sr-only", children: INSIGHT_UNAVAILABLE_LABEL })
|
|
5547
|
+
] }) : /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
5548
|
+
/* @__PURE__ */ jsx14("span", { className: "text-xl font-semibold tabular-nums text-foreground", children: shown }),
|
|
5549
|
+
unit ? /* @__PURE__ */ jsx14("span", { className: "text-[11px] text-muted-foreground", children: unit }) : null
|
|
5550
|
+
] }) }),
|
|
5551
|
+
delta ? /* @__PURE__ */ jsxs12("p", { "data-insight-delta": delta.direction, className: `mt-0.5 text-[11px] font-medium ${TONE_CLASS[tone]}`, children: [
|
|
5552
|
+
/* @__PURE__ */ jsxs12("span", { "aria-hidden": "true", children: [
|
|
5553
|
+
DIRECTION_GLYPH[delta.direction],
|
|
5554
|
+
" "
|
|
5555
|
+
] }),
|
|
5556
|
+
formatInsightDelta(delta, format)
|
|
5557
|
+
] }) : null,
|
|
5558
|
+
description ? /* @__PURE__ */ jsx14("p", { className: "mt-1 text-[11px] text-muted-foreground", children: description }) : null,
|
|
5559
|
+
series ? /* @__PURE__ */ jsx14("div", { className: "mt-2 text-muted-foreground", children: /* @__PURE__ */ jsx14(Sparkline, { values: series, label: seriesLabel ?? title, format }) }) : null,
|
|
5560
|
+
action ? /* @__PURE__ */ jsx14("div", { className: "mt-3", children: renderInsightAction(action) }) : null
|
|
5561
|
+
]
|
|
5562
|
+
}
|
|
5563
|
+
);
|
|
5564
|
+
}
|
|
5565
|
+
function renderInsightAction(action) {
|
|
5566
|
+
if (isValidElement2(action)) return action;
|
|
5567
|
+
return /* @__PURE__ */ jsx14(
|
|
5568
|
+
"button",
|
|
5569
|
+
{
|
|
5570
|
+
type: "button",
|
|
5571
|
+
onClick: action.onClick,
|
|
5572
|
+
className: "h-8 rounded-md border border-border px-3 text-xs font-medium text-foreground transition hover:bg-accent",
|
|
5573
|
+
children: action.label
|
|
5574
|
+
}
|
|
5575
|
+
);
|
|
5576
|
+
}
|
|
5577
|
+
var DEFAULT_INSIGHT_PAGE_SIZE = 3;
|
|
5578
|
+
var MAX_PAGE_DOTS = 8;
|
|
5579
|
+
var PAGE_SIZE_FAULT_REASON = {
|
|
5580
|
+
"not-a-number": "A page size that is not a number cannot count cards at all.",
|
|
5581
|
+
"below-one": "A page size below one card gives the deck a page nothing fits on.",
|
|
5582
|
+
fractional: "A fractional page size hides cards on no page at all."
|
|
5583
|
+
};
|
|
5584
|
+
var MAX_NAMED_PAGE_SIZES = 8;
|
|
5585
|
+
var warnedPageSizes = {
|
|
5586
|
+
"not-a-number": { named: /* @__PURE__ */ new Set(), latched: false },
|
|
5587
|
+
"below-one": { named: /* @__PURE__ */ new Set(), latched: false },
|
|
5588
|
+
fractional: { named: /* @__PURE__ */ new Set(), latched: false }
|
|
5589
|
+
};
|
|
5590
|
+
function pageSizeFault(pageSize) {
|
|
5591
|
+
if (!Number.isFinite(pageSize)) return "not-a-number";
|
|
5592
|
+
if (pageSize < 1) return "below-one";
|
|
5593
|
+
return "fractional";
|
|
5594
|
+
}
|
|
5595
|
+
function warnPageSize(pageSize) {
|
|
5596
|
+
const fault = pageSizeFault(pageSize);
|
|
5597
|
+
const record = warnedPageSizes[fault];
|
|
5598
|
+
if (record.latched || record.named.has(pageSize)) return;
|
|
5599
|
+
record.named.add(pageSize);
|
|
5600
|
+
console.warn(
|
|
5601
|
+
`[insight-card] pageSize must be a whole number of cards, 1 or more \u2014 received ${String(pageSize)}. Using ${DEFAULT_INSIGHT_PAGE_SIZE}. ${PAGE_SIZE_FAULT_REASON[fault]}`
|
|
5602
|
+
);
|
|
5603
|
+
if (record.named.size >= MAX_NAMED_PAGE_SIZES) {
|
|
5604
|
+
record.named.clear();
|
|
5605
|
+
record.latched = true;
|
|
5606
|
+
console.warn(`[insight-card] further "${fault}" pageSize warnings are suppressed.`);
|
|
5607
|
+
}
|
|
5608
|
+
}
|
|
5609
|
+
function insightPageSize(pageSize = DEFAULT_INSIGHT_PAGE_SIZE) {
|
|
5610
|
+
if (Number.isInteger(pageSize) && pageSize >= 1) return pageSize;
|
|
5611
|
+
warnPageSize(pageSize);
|
|
5612
|
+
return DEFAULT_INSIGHT_PAGE_SIZE;
|
|
5613
|
+
}
|
|
5614
|
+
function insightPageCount(total, pageSize = DEFAULT_INSIGHT_PAGE_SIZE) {
|
|
5615
|
+
const size = insightPageSize(pageSize);
|
|
5616
|
+
const counted = Number.isFinite(total) && total > 0 ? total : 0;
|
|
5617
|
+
return Math.max(1, Math.ceil(counted / size));
|
|
5618
|
+
}
|
|
5619
|
+
function insightPageSlice(items, page, pageSize = DEFAULT_INSIGHT_PAGE_SIZE) {
|
|
5620
|
+
const size = insightPageSize(pageSize);
|
|
5621
|
+
const count = insightPageCount(items.length, size);
|
|
5622
|
+
const requested = Number.isFinite(page) ? Math.floor(page) : 0;
|
|
5623
|
+
const safe = Math.min(Math.max(requested, 0), count - 1);
|
|
5624
|
+
return items.slice(safe * size, safe * size + size);
|
|
5625
|
+
}
|
|
5626
|
+
function InsightDeck({
|
|
5627
|
+
state,
|
|
5628
|
+
empty,
|
|
5629
|
+
label = "Insights",
|
|
5630
|
+
pageSize = DEFAULT_INSIGHT_PAGE_SIZE,
|
|
5631
|
+
loadingLabel = "Loading insights\u2026",
|
|
5632
|
+
retryLabel,
|
|
5633
|
+
className,
|
|
5634
|
+
onPageChange
|
|
5635
|
+
}) {
|
|
5636
|
+
const [page, setPage] = useState15(0);
|
|
5637
|
+
const [held, setHeld] = useState15(null);
|
|
5638
|
+
const answered = state.status === "error" || state.status === "empty";
|
|
5639
|
+
const carried = state.status === "ready" ? state.value : answered ? null : held;
|
|
5640
|
+
if (carried !== held) setHeld(carried);
|
|
5641
|
+
const shown = carried !== null && state.status !== "ready" ? { status: "ready", value: carried, retry: state.retry } : state;
|
|
5642
|
+
const refreshing = shown !== state;
|
|
5643
|
+
const reported = useRef11(0);
|
|
5644
|
+
const settlePage = useCallback10(
|
|
5645
|
+
(next) => {
|
|
5646
|
+
if (reported.current === next) return;
|
|
5647
|
+
reported.current = next;
|
|
5648
|
+
onPageChange?.(next);
|
|
5649
|
+
},
|
|
5650
|
+
[onPageChange]
|
|
5651
|
+
);
|
|
5652
|
+
return /* @__PURE__ */ jsx14(
|
|
5653
|
+
AsyncView,
|
|
5654
|
+
{
|
|
5655
|
+
state: shown,
|
|
5656
|
+
empty,
|
|
5657
|
+
loadingLabel,
|
|
5658
|
+
retryLabel,
|
|
5659
|
+
className,
|
|
5660
|
+
children: (insights) => /* @__PURE__ */ jsx14(
|
|
5661
|
+
InsightPages,
|
|
5662
|
+
{
|
|
5663
|
+
insights,
|
|
5664
|
+
label,
|
|
5665
|
+
pageSize,
|
|
5666
|
+
className,
|
|
5667
|
+
page,
|
|
5668
|
+
busy: refreshing,
|
|
5669
|
+
onSelectPage: setPage,
|
|
5670
|
+
onPageSettled: settlePage
|
|
5671
|
+
}
|
|
5672
|
+
)
|
|
5673
|
+
}
|
|
5674
|
+
);
|
|
5675
|
+
}
|
|
5676
|
+
var EDITABLE_TAG = /^(INPUT|TEXTAREA|SELECT)$/;
|
|
5677
|
+
var ARROW_KEY_ROLES = /* @__PURE__ */ new Set([
|
|
5678
|
+
"application",
|
|
5679
|
+
"combobox",
|
|
5680
|
+
"grid",
|
|
5681
|
+
"gridcell",
|
|
5682
|
+
"listbox",
|
|
5683
|
+
"menu",
|
|
5684
|
+
"menubar",
|
|
5685
|
+
"menuitem",
|
|
5686
|
+
"menuitemcheckbox",
|
|
5687
|
+
"menuitemradio",
|
|
5688
|
+
"option",
|
|
5689
|
+
"radiogroup",
|
|
5690
|
+
"row",
|
|
5691
|
+
"scrollbar",
|
|
5692
|
+
"searchbox",
|
|
5693
|
+
"slider",
|
|
5694
|
+
"spinbutton",
|
|
5695
|
+
"tab",
|
|
5696
|
+
"tablist",
|
|
5697
|
+
"textbox",
|
|
5698
|
+
"tree",
|
|
5699
|
+
"treegrid",
|
|
5700
|
+
"treeitem"
|
|
5701
|
+
]);
|
|
5702
|
+
function ownsArrowKeys(target, boundary) {
|
|
5703
|
+
let node = target instanceof Element ? target : null;
|
|
5704
|
+
while (node !== null && node !== boundary) {
|
|
5705
|
+
if (EDITABLE_TAG.test(node.tagName)) return true;
|
|
5706
|
+
if (node instanceof HTMLElement && node.isContentEditable) return true;
|
|
5707
|
+
const role = node.getAttribute("role");
|
|
5708
|
+
if (role !== null && role.split(/\s+/).some((token) => ARROW_KEY_ROLES.has(token))) return true;
|
|
5709
|
+
node = node.parentElement;
|
|
5710
|
+
}
|
|
5711
|
+
return false;
|
|
5712
|
+
}
|
|
5713
|
+
function InsightPages({
|
|
5714
|
+
insights,
|
|
5715
|
+
label,
|
|
5716
|
+
pageSize,
|
|
5717
|
+
className,
|
|
5718
|
+
page,
|
|
5719
|
+
busy,
|
|
5720
|
+
onSelectPage,
|
|
5721
|
+
onPageSettled
|
|
5722
|
+
}) {
|
|
5723
|
+
const size = insightPageSize(pageSize);
|
|
5724
|
+
const pageCount = insightPageCount(insights.length, size);
|
|
5725
|
+
const current = Math.min(Math.max(page, 0), pageCount - 1);
|
|
5726
|
+
const visible = insightPageSlice(insights, current, size);
|
|
5727
|
+
const sectionRef = useRef11(null);
|
|
5728
|
+
const listRef = useRef11(null);
|
|
5729
|
+
const recoverFocus = useRef11(false);
|
|
5730
|
+
useEffect11(() => {
|
|
5731
|
+
onPageSettled(current);
|
|
5732
|
+
}, [current, onPageSettled]);
|
|
5733
|
+
useEffect11(() => {
|
|
5734
|
+
if (!recoverFocus.current) return;
|
|
5735
|
+
recoverFocus.current = false;
|
|
5736
|
+
sectionRef.current?.focus();
|
|
5737
|
+
}, [current]);
|
|
5738
|
+
const goTo = useCallback10(
|
|
5739
|
+
(next) => {
|
|
5740
|
+
const clamped = Math.min(Math.max(next, 0), pageCount - 1);
|
|
5741
|
+
if (clamped === current) return false;
|
|
5742
|
+
const active = typeof document === "undefined" ? null : document.activeElement;
|
|
5743
|
+
recoverFocus.current = active instanceof Node && (listRef.current?.contains(active) ?? false);
|
|
5744
|
+
onSelectPage(clamped);
|
|
5745
|
+
return true;
|
|
5746
|
+
},
|
|
5747
|
+
[current, onSelectPage, pageCount]
|
|
5748
|
+
);
|
|
5749
|
+
const onKeyDown = (event) => {
|
|
5750
|
+
if (event.defaultPrevented) return;
|
|
5751
|
+
if (ownsArrowKeys(event.target, event.currentTarget)) return;
|
|
5752
|
+
let moved = false;
|
|
5753
|
+
switch (event.key) {
|
|
5754
|
+
case "ArrowRight":
|
|
5755
|
+
case "PageDown":
|
|
5756
|
+
moved = goTo(current + 1);
|
|
5757
|
+
break;
|
|
5758
|
+
case "ArrowLeft":
|
|
5759
|
+
case "PageUp":
|
|
5760
|
+
moved = goTo(current - 1);
|
|
5761
|
+
break;
|
|
5762
|
+
case "Home":
|
|
5763
|
+
moved = goTo(0);
|
|
5764
|
+
break;
|
|
5765
|
+
case "End":
|
|
5766
|
+
moved = goTo(pageCount - 1);
|
|
5767
|
+
break;
|
|
5768
|
+
default:
|
|
5769
|
+
return;
|
|
5770
|
+
}
|
|
5771
|
+
if (moved) event.preventDefault();
|
|
5772
|
+
};
|
|
5773
|
+
return /* @__PURE__ */ jsxs12(
|
|
5774
|
+
"section",
|
|
5775
|
+
{
|
|
5776
|
+
ref: sectionRef,
|
|
5777
|
+
"aria-label": label,
|
|
5778
|
+
"data-insight-deck": "",
|
|
5779
|
+
"aria-busy": busy,
|
|
5780
|
+
className: joinClasses("space-y-3", className),
|
|
5781
|
+
onKeyDown,
|
|
5782
|
+
tabIndex: pageCount > 1 ? 0 : void 0,
|
|
5783
|
+
"aria-keyshortcuts": pageCount > 1 ? "ArrowLeft ArrowRight PageUp PageDown Home End" : void 0,
|
|
5784
|
+
children: [
|
|
5785
|
+
/* @__PURE__ */ jsx14("ul", { ref: listRef, className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-3", children: visible.map(({ id, style, ...card }, index) => (
|
|
5786
|
+
// The page index is in the key on purpose: a page turn is an arrival,
|
|
5787
|
+
// and reusing the node would swap the text under a card that never
|
|
5788
|
+
// moved. Remounting replays `.agent-arrive` with the new stagger.
|
|
5789
|
+
//
|
|
5790
|
+
// A REFRESH is the other case and the key is why it behaves the other
|
|
5791
|
+
// way: the page has not changed and the id is stable, so the key
|
|
5792
|
+
// matches, React keeps the node, and a card that was already settled
|
|
5793
|
+
// does not arrive a second time. The key does BOTH jobs — but only
|
|
5794
|
+
// because the deck now keeps this subtree mounted across a reload
|
|
5795
|
+
// (see `InsightDeck`); a key is never compared across a teardown.
|
|
5796
|
+
/* @__PURE__ */ jsx14("li", { children: /* @__PURE__ */ jsx14(InsightCard, { ...card, style: staggerStyle(index, style) }) }, `${current}:${id}`)
|
|
5797
|
+
)) }),
|
|
5798
|
+
/* @__PURE__ */ jsxs12("div", { className: pageCount > 1 ? "flex items-center justify-between gap-2" : void 0, children: [
|
|
5799
|
+
/* @__PURE__ */ jsxs12(
|
|
5800
|
+
"p",
|
|
5801
|
+
{
|
|
5802
|
+
role: "status",
|
|
5803
|
+
"aria-live": "polite",
|
|
5804
|
+
className: pageCount > 1 ? "text-[11px] text-muted-foreground" : "sr-only",
|
|
5805
|
+
children: [
|
|
5806
|
+
"Page ",
|
|
5807
|
+
current + 1,
|
|
5808
|
+
" of ",
|
|
5809
|
+
pageCount
|
|
5810
|
+
]
|
|
5811
|
+
}
|
|
5812
|
+
),
|
|
5813
|
+
pageCount > 1 ? /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1", children: [
|
|
5814
|
+
/* @__PURE__ */ jsx14(PagerButton, { label: "Previous insights", glyph: "\u2039", atEnd: current === 0, onClick: () => goTo(current - 1) }),
|
|
5815
|
+
pageCount <= MAX_PAGE_DOTS ? Array.from({ length: pageCount }, (_, index) => (
|
|
5816
|
+
// WCAG 2.2 SC 2.5.8 wants a 24x24 CSS px target. The dot stays
|
|
5817
|
+
// 8px because a 24px dot is a different control; the BUTTON
|
|
5818
|
+
// around it carries the target, so the padding is the hit area
|
|
5819
|
+
// and the span is the graphic. The Spacing exception cannot
|
|
5820
|
+
// rescue the bare dot — at a 12px pitch the 24px circle around
|
|
5821
|
+
// each centre overlaps its neighbour's.
|
|
5822
|
+
/* @__PURE__ */ jsx14(
|
|
5823
|
+
"button",
|
|
5824
|
+
{
|
|
5825
|
+
type: "button",
|
|
5826
|
+
"aria-label": `Page ${index + 1} of ${pageCount}`,
|
|
5827
|
+
"aria-current": index === current ? "page" : void 0,
|
|
5828
|
+
onClick: () => goTo(index),
|
|
5829
|
+
className: "group flex h-6 w-6 shrink-0 items-center justify-center rounded-full",
|
|
5830
|
+
children: /* @__PURE__ */ jsx14(
|
|
5831
|
+
"span",
|
|
5832
|
+
{
|
|
5833
|
+
"aria-hidden": "true",
|
|
5834
|
+
className: joinClasses(
|
|
5835
|
+
"block rounded-full transition",
|
|
5836
|
+
index === current ? "h-2 w-4 bg-foreground" : "h-2 w-2 bg-muted-foreground group-hover:bg-foreground"
|
|
5837
|
+
)
|
|
5838
|
+
}
|
|
5839
|
+
)
|
|
5840
|
+
},
|
|
5841
|
+
index
|
|
5842
|
+
)
|
|
5843
|
+
)) : null,
|
|
5844
|
+
/* @__PURE__ */ jsx14(
|
|
5845
|
+
PagerButton,
|
|
5846
|
+
{
|
|
5847
|
+
label: "Next insights",
|
|
5848
|
+
glyph: "\u203A",
|
|
5849
|
+
atEnd: current === pageCount - 1,
|
|
5850
|
+
onClick: () => goTo(current + 1)
|
|
5851
|
+
}
|
|
5852
|
+
)
|
|
5853
|
+
] }) : null
|
|
5854
|
+
] })
|
|
5855
|
+
]
|
|
5856
|
+
}
|
|
5857
|
+
);
|
|
5858
|
+
}
|
|
5859
|
+
function PagerButton({
|
|
5860
|
+
label,
|
|
5861
|
+
glyph,
|
|
5862
|
+
atEnd,
|
|
5863
|
+
onClick
|
|
5864
|
+
}) {
|
|
5865
|
+
return /* @__PURE__ */ jsx14(
|
|
5866
|
+
"button",
|
|
5867
|
+
{
|
|
5868
|
+
type: "button",
|
|
5869
|
+
"aria-label": label,
|
|
5870
|
+
"aria-disabled": atEnd,
|
|
5871
|
+
onClick: () => {
|
|
5872
|
+
if (!atEnd) onClick();
|
|
5873
|
+
},
|
|
5874
|
+
className: `flex h-6 w-6 items-center justify-center rounded-md border border-border text-xs text-muted-foreground transition ${atEnd ? "opacity-40" : "hover:bg-accent hover:text-foreground"}`,
|
|
5875
|
+
children: /* @__PURE__ */ jsx14("span", { "aria-hidden": "true", children: glyph })
|
|
5876
|
+
}
|
|
5877
|
+
);
|
|
5878
|
+
}
|
|
5879
|
+
|
|
5246
5880
|
// src/web-react/index.tsx
|
|
5247
|
-
import { Fragment as
|
|
5881
|
+
import { Fragment as Fragment8, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
5248
5882
|
function formatModelCost(msg, models) {
|
|
5249
5883
|
if (msg.promptTokens == null && msg.completionTokens == null) return null;
|
|
5250
5884
|
const pricing = models.find((m) => m.id === msg.modelUsed)?.pricing;
|
|
@@ -5258,41 +5892,41 @@ function formatTokensPerSecond(msg) {
|
|
|
5258
5892
|
return `${Math.round(msg.completionTokens / (msg.durationMs / 1e3))} tok/s`;
|
|
5259
5893
|
}
|
|
5260
5894
|
function RunDrillIn({ run, onClose }) {
|
|
5261
|
-
return /* @__PURE__ */
|
|
5262
|
-
/* @__PURE__ */
|
|
5263
|
-
/* @__PURE__ */
|
|
5895
|
+
return /* @__PURE__ */ jsxs13("div", { className: `fixed inset-y-0 right-0 z-50 flex w-[480px] max-w-full flex-col border-l border-card-edge bg-popover ${OVERLAY_SHADOW}`, children: [
|
|
5896
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
|
|
5897
|
+
/* @__PURE__ */ jsx15(
|
|
5264
5898
|
"span",
|
|
5265
5899
|
{
|
|
5266
5900
|
className: `h-2 w-2 shrink-0 rounded-full ${run.status === "running" ? "bg-warning" : run.status === "error" ? "bg-destructive" : "bg-success"}`
|
|
5267
5901
|
}
|
|
5268
5902
|
),
|
|
5269
|
-
/* @__PURE__ */
|
|
5270
|
-
/* @__PURE__ */
|
|
5271
|
-
/* @__PURE__ */
|
|
5903
|
+
/* @__PURE__ */ jsxs13("div", { className: "min-w-0 flex-1", children: [
|
|
5904
|
+
/* @__PURE__ */ jsx15("p", { className: "truncate text-[15px] font-semibold", children: run.title }),
|
|
5905
|
+
/* @__PURE__ */ jsx15("p", { className: "truncate font-mono text-xs text-muted-foreground", children: run.toolName })
|
|
5272
5906
|
] }),
|
|
5273
|
-
/* @__PURE__ */
|
|
5907
|
+
/* @__PURE__ */ jsx15(
|
|
5274
5908
|
"button",
|
|
5275
5909
|
{
|
|
5276
5910
|
type: "button",
|
|
5277
5911
|
onClick: onClose,
|
|
5278
5912
|
"aria-label": "Close",
|
|
5279
5913
|
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent hover:text-foreground",
|
|
5280
|
-
children: /* @__PURE__ */
|
|
5914
|
+
children: /* @__PURE__ */ jsx15("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx15("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
5281
5915
|
}
|
|
5282
5916
|
)
|
|
5283
5917
|
] }),
|
|
5284
|
-
/* @__PURE__ */
|
|
5285
|
-
run.steps.length === 0 && /* @__PURE__ */
|
|
5286
|
-
run.steps.map((step, i) => /* @__PURE__ */
|
|
5287
|
-
/* @__PURE__ */
|
|
5288
|
-
/* @__PURE__ */
|
|
5289
|
-
/* @__PURE__ */
|
|
5290
|
-
/* @__PURE__ */
|
|
5918
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
|
|
5919
|
+
run.steps.length === 0 && /* @__PURE__ */ jsx15("p", { className: "text-sm text-muted-foreground", children: "No steps recorded yet." }),
|
|
5920
|
+
run.steps.map((step, i) => /* @__PURE__ */ jsxs13("div", { className: "rounded-lg border border-card-edge bg-card", children: [
|
|
5921
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-baseline gap-2 border-b border-border px-3 py-1.5", children: [
|
|
5922
|
+
/* @__PURE__ */ jsx15("span", { className: `font-mono text-xs ${step.status === "error" ? "text-destructive" : "text-muted-foreground"}`, children: step.status === "error" ? "\u2717" : "$" }),
|
|
5923
|
+
/* @__PURE__ */ jsx15("code", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: step.label }),
|
|
5924
|
+
/* @__PURE__ */ jsx15("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", children: new Date(step.at).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) })
|
|
5291
5925
|
] }),
|
|
5292
|
-
step.detail && /* @__PURE__ */
|
|
5926
|
+
step.detail && /* @__PURE__ */ jsx15("pre", { className: "max-h-48 overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-xs leading-relaxed text-muted-foreground", children: step.detail })
|
|
5293
5927
|
] }, i))
|
|
5294
5928
|
] }),
|
|
5295
|
-
/* @__PURE__ */
|
|
5929
|
+
/* @__PURE__ */ jsx15("p", { className: "border-t border-border px-4 py-2 text-xs text-muted-foreground", children: "Read-only transcript \u2014 reply in the main chat." })
|
|
5296
5930
|
] });
|
|
5297
5931
|
}
|
|
5298
5932
|
function pendingApprovalOf(call) {
|
|
@@ -5308,23 +5942,23 @@ function ChatEmptyState({
|
|
|
5308
5942
|
}) {
|
|
5309
5943
|
const doorCount = Math.min(doors?.length ?? 0, 3);
|
|
5310
5944
|
const doorsGridClass = doorCount === 1 ? "mx-auto max-w-sm sm:grid-cols-1" : doorCount === 2 ? "sm:grid-cols-2" : "sm:grid-cols-3";
|
|
5311
|
-
return /* @__PURE__ */
|
|
5312
|
-
/* @__PURE__ */
|
|
5313
|
-
/* @__PURE__ */
|
|
5314
|
-
/* @__PURE__ */
|
|
5315
|
-
subline && /* @__PURE__ */
|
|
5316
|
-
doors && doors.length > 0 && /* @__PURE__ */
|
|
5945
|
+
return /* @__PURE__ */ jsxs13("div", { className: "mx-auto flex w-full max-w-2xl flex-col items-center px-6 py-12 text-center sm:py-20", children: [
|
|
5946
|
+
/* @__PURE__ */ jsx15("span", { className: "mb-5 inline-flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 ring-1 ring-primary/15", children: /* @__PURE__ */ jsx15(BrandMark, { size: 32, className: "shrink-0" }) }),
|
|
5947
|
+
/* @__PURE__ */ jsx15("p", { className: "text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground", children: productName }),
|
|
5948
|
+
/* @__PURE__ */ jsx15("h2", { className: "mt-1.5 text-balance text-2xl font-semibold leading-tight text-foreground", children: headline }),
|
|
5949
|
+
subline && /* @__PURE__ */ jsx15("p", { className: "mt-3 max-w-md text-[15px] leading-relaxed text-muted-foreground", children: subline }),
|
|
5950
|
+
doors && doors.length > 0 && /* @__PURE__ */ jsx15("div", { className: `mt-7 grid w-full gap-2.5 ${doorsGridClass}`, children: doors.slice(0, 3).map((door, i) => /* @__PURE__ */ jsxs13(
|
|
5317
5951
|
"button",
|
|
5318
5952
|
{
|
|
5319
5953
|
type: "button",
|
|
5320
5954
|
onClick: door.onSelect,
|
|
5321
5955
|
className: "group flex min-h-[44px] flex-col items-start rounded-xl border border-border bg-card px-4 py-3 text-left transition hover:border-primary/40 hover:bg-accent",
|
|
5322
5956
|
children: [
|
|
5323
|
-
/* @__PURE__ */
|
|
5957
|
+
/* @__PURE__ */ jsxs13("span", { className: "flex items-center gap-2 text-sm font-semibold text-foreground", children: [
|
|
5324
5958
|
door.icon,
|
|
5325
5959
|
door.label
|
|
5326
5960
|
] }),
|
|
5327
|
-
door.description && /* @__PURE__ */
|
|
5961
|
+
door.description && /* @__PURE__ */ jsx15("span", { className: "mt-0.5 text-[12px] leading-snug text-muted-foreground", children: door.description })
|
|
5328
5962
|
]
|
|
5329
5963
|
},
|
|
5330
5964
|
i
|
|
@@ -5333,26 +5967,26 @@ function ChatEmptyState({
|
|
|
5333
5967
|
}
|
|
5334
5968
|
function ToolGlyph({ name, className }) {
|
|
5335
5969
|
if (name.startsWith("sandbox_")) {
|
|
5336
|
-
return /* @__PURE__ */
|
|
5337
|
-
/* @__PURE__ */
|
|
5338
|
-
/* @__PURE__ */
|
|
5970
|
+
return /* @__PURE__ */ jsxs13("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
5971
|
+
/* @__PURE__ */ jsx15("polyline", { points: "4 17 10 11 4 5" }),
|
|
5972
|
+
/* @__PURE__ */ jsx15("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
|
|
5339
5973
|
] });
|
|
5340
5974
|
}
|
|
5341
5975
|
if (name === "submit_proposal") {
|
|
5342
|
-
return /* @__PURE__ */
|
|
5343
|
-
/* @__PURE__ */
|
|
5344
|
-
/* @__PURE__ */
|
|
5976
|
+
return /* @__PURE__ */ jsxs13("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
5977
|
+
/* @__PURE__ */ jsx15("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
5978
|
+
/* @__PURE__ */ jsx15("path", { d: "M14 2v6h6M9 15l2 2 4-4" })
|
|
5345
5979
|
] });
|
|
5346
5980
|
}
|
|
5347
5981
|
if (name === "schedule_followup") {
|
|
5348
|
-
return /* @__PURE__ */
|
|
5349
|
-
/* @__PURE__ */
|
|
5350
|
-
/* @__PURE__ */
|
|
5982
|
+
return /* @__PURE__ */ jsxs13("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: [
|
|
5983
|
+
/* @__PURE__ */ jsx15("circle", { cx: "12", cy: "12", r: "9" }),
|
|
5984
|
+
/* @__PURE__ */ jsx15("path", { d: "M12 7v5l3 3" })
|
|
5351
5985
|
] });
|
|
5352
5986
|
}
|
|
5353
|
-
return /* @__PURE__ */
|
|
5354
|
-
/* @__PURE__ */
|
|
5355
|
-
/* @__PURE__ */
|
|
5987
|
+
return /* @__PURE__ */ jsxs13("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
5988
|
+
/* @__PURE__ */ jsx15("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3" }),
|
|
5989
|
+
/* @__PURE__ */ jsx15("circle", { cx: "12", cy: "12", r: "4" })
|
|
5356
5990
|
] });
|
|
5357
5991
|
}
|
|
5358
5992
|
function toolOutcomeOf(call) {
|
|
@@ -5438,40 +6072,40 @@ function truncate(v, max = 240) {
|
|
|
5438
6072
|
function KvRows({ data }) {
|
|
5439
6073
|
const entries = Object.entries(data).filter(([, v]) => v !== void 0 && v !== null && v !== "");
|
|
5440
6074
|
if (!entries.length) return null;
|
|
5441
|
-
return /* @__PURE__ */
|
|
5442
|
-
/* @__PURE__ */
|
|
5443
|
-
/* @__PURE__ */
|
|
6075
|
+
return /* @__PURE__ */ jsx15("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: entries.map(([k, v]) => /* @__PURE__ */ jsxs13("div", { className: "contents", children: [
|
|
6076
|
+
/* @__PURE__ */ jsx15("dt", { className: "font-mono text-xs text-muted-foreground", children: k }),
|
|
6077
|
+
/* @__PURE__ */ jsx15("dd", { className: "min-w-0 whitespace-pre-wrap break-words font-mono text-xs text-muted-foreground", children: truncate(v) })
|
|
5444
6078
|
] }, k)) });
|
|
5445
6079
|
}
|
|
5446
6080
|
function ShellDetail({ call }) {
|
|
5447
6081
|
const outcome = toolOutcomeOf(call);
|
|
5448
6082
|
const r = outcome?.result ?? {};
|
|
5449
|
-
return /* @__PURE__ */
|
|
5450
|
-
/* @__PURE__ */
|
|
5451
|
-
/* @__PURE__ */
|
|
5452
|
-
/* @__PURE__ */
|
|
5453
|
-
r.exitCode != null && /* @__PURE__ */
|
|
6083
|
+
return /* @__PURE__ */ jsxs13("div", { className: "overflow-hidden rounded-md bg-zinc-900 font-mono text-xs leading-relaxed", children: [
|
|
6084
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 px-3 pt-2 text-zinc-400", children: [
|
|
6085
|
+
/* @__PURE__ */ jsx15("span", { className: "select-none text-zinc-500", children: "$" }),
|
|
6086
|
+
/* @__PURE__ */ jsx15("span", { className: "min-w-0 flex-1 truncate text-zinc-200", children: String(call.args?.command ?? "") }),
|
|
6087
|
+
r.exitCode != null && /* @__PURE__ */ jsxs13("span", { className: r.exitCode === 0 ? "text-success" : "text-destructive", children: [
|
|
5454
6088
|
"exit ",
|
|
5455
6089
|
r.exitCode
|
|
5456
6090
|
] })
|
|
5457
6091
|
] }),
|
|
5458
|
-
/* @__PURE__ */
|
|
6092
|
+
/* @__PURE__ */ jsx15("pre", { className: "max-h-56 overflow-auto whitespace-pre-wrap px-3 pb-2.5 pt-1.5 text-zinc-300", children: outcome?.ok === false ? outcome.message ?? "failed" : [r.stdout, r.stderr].filter(Boolean).join("\n") || "(no output)" })
|
|
5459
6093
|
] });
|
|
5460
6094
|
}
|
|
5461
6095
|
function DefaultToolDetail({ call }) {
|
|
5462
6096
|
const result = call.result;
|
|
5463
6097
|
const envelope = typeof result === "object" && result !== null ? result : null;
|
|
5464
|
-
return /* @__PURE__ */
|
|
5465
|
-
call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */
|
|
5466
|
-
/* @__PURE__ */
|
|
5467
|
-
/* @__PURE__ */
|
|
6098
|
+
return /* @__PURE__ */ jsxs13("div", { className: "space-y-2", children: [
|
|
6099
|
+
call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */ jsxs13("div", { children: [
|
|
6100
|
+
/* @__PURE__ */ jsx15("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Called with" }),
|
|
6101
|
+
/* @__PURE__ */ jsx15(KvRows, { data: call.args })
|
|
5468
6102
|
] }),
|
|
5469
|
-
envelope ? /* @__PURE__ */
|
|
5470
|
-
/* @__PURE__ */
|
|
5471
|
-
envelope.ok === false ? /* @__PURE__ */
|
|
5472
|
-
] }) : result != null ? /* @__PURE__ */
|
|
5473
|
-
/* @__PURE__ */
|
|
5474
|
-
/* @__PURE__ */
|
|
6103
|
+
envelope ? /* @__PURE__ */ jsxs13("div", { children: [
|
|
6104
|
+
/* @__PURE__ */ jsx15("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: envelope.ok === false ? "Failed" : "Result" }),
|
|
6105
|
+
envelope.ok === false ? /* @__PURE__ */ jsx15("p", { className: "text-xs text-destructive", children: envelope.message ?? "Tool failed" }) : envelope.result && typeof envelope.result === "object" ? /* @__PURE__ */ jsx15(KvRows, { data: envelope.result }) : envelope.result != null ? /* @__PURE__ */ jsx15("p", { className: "font-mono text-xs text-muted-foreground", children: truncate(envelope.result) }) : null
|
|
6106
|
+
] }) : result != null ? /* @__PURE__ */ jsxs13("div", { children: [
|
|
6107
|
+
/* @__PURE__ */ jsx15("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Result" }),
|
|
6108
|
+
/* @__PURE__ */ jsx15("p", { className: "font-mono text-xs text-muted-foreground", children: truncate(result) })
|
|
5475
6109
|
] }) : null
|
|
5476
6110
|
] });
|
|
5477
6111
|
}
|
|
@@ -5482,24 +6116,24 @@ function ProposalCard({
|
|
|
5482
6116
|
approval,
|
|
5483
6117
|
renderers
|
|
5484
6118
|
}) {
|
|
5485
|
-
const [expanded, setExpanded] =
|
|
6119
|
+
const [expanded, setExpanded] = useState16(false);
|
|
5486
6120
|
const { summary, meta, typeSlug } = proposalPreview(call);
|
|
5487
6121
|
const custom = renderers?.[call.name]?.(call, message);
|
|
5488
6122
|
const { pending: deciding, run: decide } = usePending();
|
|
5489
|
-
return /* @__PURE__ */
|
|
5490
|
-
/* @__PURE__ */
|
|
5491
|
-
/* @__PURE__ */
|
|
5492
|
-
/* @__PURE__ */
|
|
5493
|
-
/* @__PURE__ */
|
|
5494
|
-
/* @__PURE__ */
|
|
5495
|
-
summary && /* @__PURE__ */
|
|
5496
|
-
typeSlug && /* @__PURE__ */
|
|
5497
|
-
meta.length > 0 && /* @__PURE__ */
|
|
6123
|
+
return /* @__PURE__ */ jsxs13("div", { className: "w-full max-w-full rounded-xl border border-warning/50 bg-warning/[0.06] text-sm shadow-sm ring-1 ring-warning/10", children: [
|
|
6124
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-start gap-2.5 px-4 pt-3.5", children: [
|
|
6125
|
+
/* @__PURE__ */ jsx15("span", { className: "mt-0.5 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-warning/15 text-warning", children: /* @__PURE__ */ jsx15(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5" }) }),
|
|
6126
|
+
/* @__PURE__ */ jsxs13("div", { className: "min-w-0 flex-1", children: [
|
|
6127
|
+
/* @__PURE__ */ jsx15("p", { className: "text-xs font-semibold uppercase tracking-[0.05em] text-warning-strong", children: approval ? "Needs your approval" : "Awaiting approval" }),
|
|
6128
|
+
/* @__PURE__ */ jsx15("p", { className: "mt-0.5 text-[15px] font-semibold leading-snug text-foreground", children: friendlyToolTitle(call) }),
|
|
6129
|
+
summary && /* @__PURE__ */ jsx15("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: summary }),
|
|
6130
|
+
typeSlug && /* @__PURE__ */ jsx15("p", { className: "mt-1 font-mono text-xs text-muted-foreground", children: typeSlug }),
|
|
6131
|
+
meta.length > 0 && /* @__PURE__ */ jsx15("div", { className: "mt-1.5 flex flex-wrap items-center gap-1.5", children: meta.map((m, i) => /* @__PURE__ */ jsx15("span", { className: "rounded-full bg-secondary px-2 py-0.5 text-xs font-medium text-muted-foreground", children: m }, i)) })
|
|
5498
6132
|
] })
|
|
5499
6133
|
] }),
|
|
5500
|
-
/* @__PURE__ */
|
|
5501
|
-
approval && /* @__PURE__ */
|
|
5502
|
-
/* @__PURE__ */
|
|
6134
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap items-center gap-2 px-4 pb-3.5 pt-3", children: [
|
|
6135
|
+
approval && /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
6136
|
+
/* @__PURE__ */ jsx15(
|
|
5503
6137
|
"button",
|
|
5504
6138
|
{
|
|
5505
6139
|
type: "button",
|
|
@@ -5509,7 +6143,7 @@ function ProposalCard({
|
|
|
5509
6143
|
children: "Approve & run"
|
|
5510
6144
|
}
|
|
5511
6145
|
),
|
|
5512
|
-
/* @__PURE__ */
|
|
6146
|
+
/* @__PURE__ */ jsx15(
|
|
5513
6147
|
"button",
|
|
5514
6148
|
{
|
|
5515
6149
|
type: "button",
|
|
@@ -5520,7 +6154,7 @@ function ProposalCard({
|
|
|
5520
6154
|
}
|
|
5521
6155
|
)
|
|
5522
6156
|
] }),
|
|
5523
|
-
/* @__PURE__ */
|
|
6157
|
+
/* @__PURE__ */ jsxs13(
|
|
5524
6158
|
"button",
|
|
5525
6159
|
{
|
|
5526
6160
|
type: "button",
|
|
@@ -5529,12 +6163,12 @@ function ProposalCard({
|
|
|
5529
6163
|
className: "ml-auto inline-flex items-center gap-1 rounded text-[12px] font-medium text-muted-foreground transition hover:text-foreground",
|
|
5530
6164
|
children: [
|
|
5531
6165
|
expanded ? "Hide details" : "View details",
|
|
5532
|
-
/* @__PURE__ */
|
|
6166
|
+
/* @__PURE__ */ jsx15(ChevronDown, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` })
|
|
5533
6167
|
]
|
|
5534
6168
|
}
|
|
5535
6169
|
)
|
|
5536
6170
|
] }),
|
|
5537
|
-
expanded && /* @__PURE__ */
|
|
6171
|
+
expanded && /* @__PURE__ */ jsx15("div", { className: "border-t border-warning/20 px-4 py-3 text-xs", children: custom ?? /* @__PURE__ */ jsx15(DefaultToolDetail, { call }) })
|
|
5538
6172
|
] });
|
|
5539
6173
|
}
|
|
5540
6174
|
function formatFollowupWhen(when) {
|
|
@@ -5549,14 +6183,14 @@ function FollowupCard({ call }) {
|
|
|
5549
6183
|
const when = typeof a.when === "string" ? a.when : typeof a.at === "string" ? a.at : typeof a.schedule === "string" ? a.schedule : null;
|
|
5550
6184
|
const failed = toolCallFailed(call);
|
|
5551
6185
|
const errorText = failed ? toolOutcomeOf(call)?.message ?? "Scheduling failed" : null;
|
|
5552
|
-
return /* @__PURE__ */
|
|
5553
|
-
/* @__PURE__ */
|
|
5554
|
-
/* @__PURE__ */
|
|
5555
|
-
/* @__PURE__ */
|
|
5556
|
-
when && /* @__PURE__ */
|
|
5557
|
-
/* @__PURE__ */
|
|
6186
|
+
return /* @__PURE__ */ jsx15("div", { className: "flex items-start gap-2", children: /* @__PURE__ */ jsxs13("div", { className: "min-w-0 flex-1 overflow-hidden rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--md3-surface-container)]", children: [
|
|
6187
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex w-full items-center gap-2.5 px-3 py-2", children: [
|
|
6188
|
+
/* @__PURE__ */ jsx15("span", { className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-border bg-muted text-muted-foreground", children: /* @__PURE__ */ jsx15(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5" }) }),
|
|
6189
|
+
/* @__PURE__ */ jsx15("span", { className: "shrink-0 whitespace-nowrap text-xs font-medium text-foreground", children: friendlyToolTitle(call) }),
|
|
6190
|
+
when && /* @__PURE__ */ jsx15("span", { title: when, className: "hidden min-w-0 flex-1 truncate font-mono text-xs tabular-nums text-muted-foreground sm:inline", children: formatFollowupWhen(when) }),
|
|
6191
|
+
/* @__PURE__ */ jsx15("span", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: call.status === "running" ? /* @__PURE__ */ jsx15("svg", { className: "h-3 w-3 shrink-0 animate-spin text-[var(--accent-text)]", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx15("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }) : /* @__PURE__ */ jsx15("span", { className: `h-1.5 w-1.5 shrink-0 rounded-full ${failed ? "bg-[var(--surface-danger-text)]" : "bg-[var(--surface-success-text)]"}` }) })
|
|
5558
6192
|
] }),
|
|
5559
|
-
errorText && /* @__PURE__ */
|
|
6193
|
+
errorText && /* @__PURE__ */ jsx15("div", { className: "border-t border-border px-3 py-2 text-xs text-[var(--surface-danger-text)]", children: errorText })
|
|
5560
6194
|
] }) });
|
|
5561
6195
|
}
|
|
5562
6196
|
function toolRowTitle(call) {
|
|
@@ -5573,52 +6207,59 @@ function ToolCallCard({
|
|
|
5573
6207
|
message,
|
|
5574
6208
|
approval,
|
|
5575
6209
|
onOpenRun,
|
|
5576
|
-
renderers
|
|
6210
|
+
renderers,
|
|
6211
|
+
staggerIndex
|
|
5577
6212
|
}) {
|
|
6213
|
+
const arrival = useArrivalStyle(staggerIndex ?? 0);
|
|
5578
6214
|
const pending = call.status === "done" ? pendingApprovalOf(call) : null;
|
|
5579
6215
|
const kind = blockKindOf(call);
|
|
6216
|
+
const arrive = (row) => /* @__PURE__ */ jsx15("div", { className: "agent-arrive", style: arrival, children: row });
|
|
5580
6217
|
if (pending) {
|
|
5581
|
-
return
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
6218
|
+
return arrive(
|
|
6219
|
+
/* @__PURE__ */ jsx15(
|
|
6220
|
+
ProposalCard,
|
|
6221
|
+
{
|
|
6222
|
+
call,
|
|
6223
|
+
message,
|
|
6224
|
+
pending,
|
|
6225
|
+
approval,
|
|
6226
|
+
renderers
|
|
6227
|
+
}
|
|
6228
|
+
)
|
|
5590
6229
|
);
|
|
5591
6230
|
}
|
|
5592
6231
|
if (kind === "followup") {
|
|
5593
|
-
return /* @__PURE__ */
|
|
6232
|
+
return arrive(/* @__PURE__ */ jsx15(FollowupCard, { call }));
|
|
5594
6233
|
}
|
|
5595
6234
|
const custom = renderers?.[call.name]?.(call, message);
|
|
5596
|
-
return
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
"
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
/* @__PURE__ */
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
6235
|
+
return arrive(
|
|
6236
|
+
/* @__PURE__ */ jsx15(
|
|
6237
|
+
InlineToolItem,
|
|
6238
|
+
{
|
|
6239
|
+
part: chatToolCallPart(call),
|
|
6240
|
+
title: toolRowTitle(call),
|
|
6241
|
+
description: toolRowDescription(call),
|
|
6242
|
+
renderToolDetail: () => custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */ jsx15(ShellDetail, { call }) : /* @__PURE__ */ jsx15(DefaultToolDetail, { call })),
|
|
6243
|
+
actions: onOpenRun && call.name.startsWith("sandbox_") ? /* @__PURE__ */ jsx15(
|
|
6244
|
+
"button",
|
|
6245
|
+
{
|
|
6246
|
+
type: "button",
|
|
6247
|
+
onClick: () => onOpenRun(call, message),
|
|
6248
|
+
"aria-label": "Open full transcript",
|
|
6249
|
+
title: "Open full transcript",
|
|
6250
|
+
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent hover:text-foreground",
|
|
6251
|
+
children: /* @__PURE__ */ jsxs13("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
6252
|
+
/* @__PURE__ */ jsx15("path", { d: "M7 17 17 7" }),
|
|
6253
|
+
/* @__PURE__ */ jsx15("path", { d: "M7 7h10v10" })
|
|
6254
|
+
] })
|
|
6255
|
+
}
|
|
6256
|
+
) : void 0
|
|
6257
|
+
}
|
|
6258
|
+
)
|
|
5618
6259
|
);
|
|
5619
6260
|
}
|
|
5620
6261
|
function StreamingCaret() {
|
|
5621
|
-
return /* @__PURE__ */
|
|
6262
|
+
return /* @__PURE__ */ jsx15(
|
|
5622
6263
|
"span",
|
|
5623
6264
|
{
|
|
5624
6265
|
className: "ml-0.5 inline-block h-[1.1em] w-[3px] translate-y-[2px] animate-[agent-caret_1s_step-end_infinite] rounded-sm bg-foreground/70",
|
|
@@ -5643,9 +6284,9 @@ function SegmentText({
|
|
|
5643
6284
|
// the container on top of that makes the paragraph shimmer while it types.
|
|
5644
6285
|
// The distinction is what separates "the answer materialised" from "the
|
|
5645
6286
|
// log was appended to".
|
|
5646
|
-
/* @__PURE__ */
|
|
6287
|
+
/* @__PURE__ */ jsxs13("div", { className: `${messageClassName}${streaming ? "" : " agent-stream-in"}`, children: [
|
|
5647
6288
|
body,
|
|
5648
|
-
showCaret && /* @__PURE__ */
|
|
6289
|
+
showCaret && /* @__PURE__ */ jsx15(StreamingCaret, {})
|
|
5649
6290
|
] })
|
|
5650
6291
|
);
|
|
5651
6292
|
}
|
|
@@ -5670,14 +6311,15 @@ function SegmentedBody({
|
|
|
5670
6311
|
const leftoverToolCalls = (msg.toolCalls ?? []).filter(
|
|
5671
6312
|
(tc) => !segmentToolIds.has(tc.id)
|
|
5672
6313
|
);
|
|
5673
|
-
const renderToolCard = (call) => /* @__PURE__ */
|
|
6314
|
+
const renderToolCard = (call, index) => /* @__PURE__ */ jsx15(
|
|
5674
6315
|
ToolCallCard,
|
|
5675
6316
|
{
|
|
5676
6317
|
call,
|
|
5677
6318
|
message: msg,
|
|
5678
6319
|
approval,
|
|
5679
6320
|
onOpenRun: onToolCallClick,
|
|
5680
|
-
renderers: toolRenderers
|
|
6321
|
+
renderers: toolRenderers,
|
|
6322
|
+
staggerIndex: index
|
|
5681
6323
|
},
|
|
5682
6324
|
`tool-${call.id}`
|
|
5683
6325
|
);
|
|
@@ -5693,34 +6335,44 @@ function SegmentedBody({
|
|
|
5693
6335
|
else groups.push({ kind: "tools", index: i, calls: [seg.call] });
|
|
5694
6336
|
}
|
|
5695
6337
|
}
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
6338
|
+
const children = [];
|
|
6339
|
+
for (const g of groups) {
|
|
6340
|
+
if (g.kind === "text") {
|
|
6341
|
+
children.push(
|
|
6342
|
+
/* @__PURE__ */ jsx15(
|
|
6343
|
+
SegmentText,
|
|
6344
|
+
{
|
|
6345
|
+
content: g.content,
|
|
6346
|
+
streaming: streaming && g.index === lastIndex,
|
|
6347
|
+
showCaret: streaming && g.index === lastIndex,
|
|
6348
|
+
renderBody,
|
|
6349
|
+
messageClassName
|
|
6350
|
+
},
|
|
6351
|
+
`text-${g.index}`
|
|
6352
|
+
)
|
|
6353
|
+
);
|
|
6354
|
+
continue;
|
|
6355
|
+
}
|
|
6356
|
+
if (!streaming && g.calls.length >= COLLAPSE_TOOL_RUN_AT && !g.calls.some(isImportantTool)) {
|
|
6357
|
+
children.push(
|
|
6358
|
+
/* @__PURE__ */ jsxs13("details", { children: [
|
|
6359
|
+
/* @__PURE__ */ jsxs13("summary", { className: "cursor-pointer select-none rounded-md py-0.5 text-xs font-medium text-muted-foreground [transition:color_var(--motion-control)] hover:text-foreground", children: [
|
|
5713
6360
|
"Worked through ",
|
|
5714
6361
|
g.calls.length,
|
|
5715
6362
|
" steps"
|
|
5716
6363
|
] }),
|
|
5717
|
-
/* @__PURE__ */
|
|
5718
|
-
] }, `tools-${g.index}`)
|
|
5719
|
-
)
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
6364
|
+
/* @__PURE__ */ jsx15("div", { className: "mt-1.5 flex flex-col gap-1.5", children: g.calls.map(renderToolCard) })
|
|
6365
|
+
] }, `tools-fold-${g.index}`)
|
|
6366
|
+
);
|
|
6367
|
+
continue;
|
|
6368
|
+
}
|
|
6369
|
+
g.calls.forEach((call, index) => children.push(renderToolCard(call, index)));
|
|
6370
|
+
}
|
|
6371
|
+
leftoverToolCalls.forEach((call, index) => children.push(renderToolCard(call, index)));
|
|
6372
|
+
if (streaming && segments[lastIndex]?.kind === "tool") {
|
|
6373
|
+
children.push(/* @__PURE__ */ jsx15(StreamingCaret, {}, "streaming-caret"));
|
|
6374
|
+
}
|
|
6375
|
+
return /* @__PURE__ */ jsx15("div", { className: "flex flex-col gap-2", children });
|
|
5724
6376
|
}
|
|
5725
6377
|
var QUIET_META_LANE_CLASS = "mt-1 flex h-[18px] items-center gap-2 text-xs tabular-nums text-muted-foreground opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100 motion-reduce:transition-none [@media(hover:none)]:opacity-100";
|
|
5726
6378
|
function copyTextOf(msg) {
|
|
@@ -5729,9 +6381,9 @@ function copyTextOf(msg) {
|
|
|
5729
6381
|
return msg.content;
|
|
5730
6382
|
}
|
|
5731
6383
|
function CopyMessageButton({ text }) {
|
|
5732
|
-
const [copied, setCopied] =
|
|
5733
|
-
const timerRef =
|
|
5734
|
-
|
|
6384
|
+
const [copied, setCopied] = useState16(false);
|
|
6385
|
+
const timerRef = useRef12(null);
|
|
6386
|
+
useEffect12(
|
|
5735
6387
|
() => () => {
|
|
5736
6388
|
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
5737
6389
|
},
|
|
@@ -5750,7 +6402,7 @@ function CopyMessageButton({ text }) {
|
|
|
5750
6402
|
}
|
|
5751
6403
|
);
|
|
5752
6404
|
};
|
|
5753
|
-
return /* @__PURE__ */
|
|
6405
|
+
return /* @__PURE__ */ jsx15(
|
|
5754
6406
|
"button",
|
|
5755
6407
|
{
|
|
5756
6408
|
type: "button",
|
|
@@ -5758,9 +6410,9 @@ function CopyMessageButton({ text }) {
|
|
|
5758
6410
|
"aria-label": "Copy message",
|
|
5759
6411
|
title: "Copy message",
|
|
5760
6412
|
className: "rounded p-0.5 text-muted-foreground transition hover:bg-accent hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
5761
|
-
children: copied ? /* @__PURE__ */
|
|
5762
|
-
/* @__PURE__ */
|
|
5763
|
-
/* @__PURE__ */
|
|
6413
|
+
children: copied ? /* @__PURE__ */ jsx15("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx15("polyline", { points: "20 6 9 17 4 12" }) }) : /* @__PURE__ */ jsxs13("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
6414
|
+
/* @__PURE__ */ jsx15("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
|
|
6415
|
+
/* @__PURE__ */ jsx15("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
5764
6416
|
] })
|
|
5765
6417
|
}
|
|
5766
6418
|
);
|
|
@@ -5786,46 +6438,88 @@ function AssistantMessageImpl({
|
|
|
5786
6438
|
const body = useMemo7(() => renderBody(content), [renderBody, content]);
|
|
5787
6439
|
const segments = msg.segments;
|
|
5788
6440
|
const hasAnswerText = content !== "" || (segments?.some((s) => s.kind === "text" && s.content.trim() !== "") ?? false);
|
|
5789
|
-
const reasoningScrollRef =
|
|
5790
|
-
const thinkStartRef =
|
|
5791
|
-
const thinkMsRef =
|
|
6441
|
+
const reasoningScrollRef = useRef12(null);
|
|
6442
|
+
const thinkStartRef = useRef12(null);
|
|
6443
|
+
const thinkMsRef = useRef12(null);
|
|
5792
6444
|
if (streaming && reasoning && !hasAnswerText && thinkStartRef.current === null) {
|
|
5793
6445
|
thinkStartRef.current = performance.now();
|
|
5794
6446
|
}
|
|
5795
6447
|
if (hasAnswerText && thinkStartRef.current !== null && thinkMsRef.current === null) {
|
|
5796
6448
|
thinkMsRef.current = performance.now() - thinkStartRef.current;
|
|
5797
6449
|
}
|
|
5798
|
-
|
|
6450
|
+
useEffect12(() => {
|
|
5799
6451
|
const el = reasoningScrollRef.current;
|
|
5800
6452
|
if (el && streaming && !hasAnswerText) el.scrollTop = el.scrollHeight;
|
|
5801
6453
|
}, [reasoning, streaming, hasAnswerText]);
|
|
5802
6454
|
const thinkingSeconds = useThinkingSeconds(
|
|
5803
6455
|
streaming && !!reasoning && !hasAnswerText
|
|
5804
6456
|
);
|
|
6457
|
+
const reasoningId = useId4();
|
|
6458
|
+
const [reasoningToggled, setReasoningToggled] = useState16(null);
|
|
6459
|
+
const reasoningOpen = reasoningToggled ?? !hasAnswerText;
|
|
5805
6460
|
const quiet = chrome === "quiet";
|
|
5806
|
-
return /* @__PURE__ */
|
|
5807
|
-
!quiet && /* @__PURE__ */
|
|
5808
|
-
/* @__PURE__ */
|
|
5809
|
-
msg.modelUsed && /* @__PURE__ */
|
|
5810
|
-
formatTokensPerSecond(msg) && /* @__PURE__ */
|
|
5811
|
-
formatModelCost(msg, models) && /* @__PURE__ */
|
|
6461
|
+
return /* @__PURE__ */ jsxs13("div", { className: `mx-auto w-full max-w-3xl px-6 ${quiet ? "group pb-1 pt-3" : "py-3"}`, children: [
|
|
6462
|
+
!quiet && /* @__PURE__ */ jsxs13("div", { className: "mb-1 flex items-baseline gap-2 text-xs tabular-nums text-muted-foreground", children: [
|
|
6463
|
+
/* @__PURE__ */ jsx15("span", { className: "font-semibold uppercase tracking-[0.05em]", children: agentLabel }),
|
|
6464
|
+
msg.modelUsed && /* @__PURE__ */ jsx15("span", { className: "font-mono normal-case", children: msg.modelUsed }),
|
|
6465
|
+
formatTokensPerSecond(msg) && /* @__PURE__ */ jsx15("span", { children: formatTokensPerSecond(msg) }),
|
|
6466
|
+
formatModelCost(msg, models) && /* @__PURE__ */ jsx15("span", { children: formatModelCost(msg, models) })
|
|
5812
6467
|
] }),
|
|
5813
|
-
reasoning &&
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
6468
|
+
reasoning && // A button + `.agent-disclose` rather than `<details>`: a native
|
|
6469
|
+
// disclosure has no transition to give, so the trace SNAPPED to full
|
|
6470
|
+
// height the moment the answer arrived — the single largest layout jump
|
|
6471
|
+
// in a turn, at the exact moment the reader is trying to start reading.
|
|
6472
|
+
// The grid row animates the content's REAL height (0fr → 1fr), which a
|
|
6473
|
+
// max-height guess cannot do without either clipping a long trace or
|
|
6474
|
+
// easing toward a number it never reaches. The keyboard contract
|
|
6475
|
+
// `<details>` supplied for free is restated explicitly: a real
|
|
6476
|
+
// `<button>` (Enter/Space, focusable, in the tab order) carrying
|
|
6477
|
+
// `aria-expanded` and `aria-controls` — which also announces the state
|
|
6478
|
+
// that a `<summary>` leaves to the browser.
|
|
6479
|
+
/* @__PURE__ */ jsxs13("div", { className: "mb-2 rounded-lg border-l-2 border-border bg-secondary px-3 py-2", children: [
|
|
6480
|
+
/* @__PURE__ */ jsxs13(
|
|
6481
|
+
"button",
|
|
6482
|
+
{
|
|
6483
|
+
type: "button",
|
|
6484
|
+
onClick: () => setReasoningToggled(!reasoningOpen),
|
|
6485
|
+
"aria-expanded": reasoningOpen,
|
|
6486
|
+
"aria-controls": reasoningId,
|
|
6487
|
+
className: "flex w-full select-none items-center gap-1.5 text-left text-xs font-medium text-muted-foreground [transition:color_var(--motion-control)] hover:text-foreground",
|
|
6488
|
+
children: [
|
|
6489
|
+
/* @__PURE__ */ jsx15(ChevronDown, { className: `h-3 w-3 shrink-0 [transition:transform_var(--motion-surface)] ${reasoningOpen ? "" : "-rotate-90"}` }),
|
|
6490
|
+
!hasAnswerText ? (
|
|
6491
|
+
// A pulse dims the whole word on a loop, which is the same cue a
|
|
6492
|
+
// skeleton placeholder uses — it reads as "nothing here yet". A
|
|
6493
|
+
// sweep travels THROUGH the glyphs, which reads as work in
|
|
6494
|
+
// flight, and the elapsed seconds say how much. `essential`
|
|
6495
|
+
// because it is the only signal separating a working agent from
|
|
6496
|
+
// a stuck one — and `essential` is an exemption from the blanket
|
|
6497
|
+
// floor, never a licence to sweep forever at someone who asked
|
|
6498
|
+
// for less motion: under `prefers-reduced-motion` tokens.css
|
|
6499
|
+
// stops this animation and leaves a dotted rule under the word
|
|
6500
|
+
// that the settled label ("Thought for 12s") does not carry. The
|
|
6501
|
+
// rule is the only difference — measured in Chromium, both labels
|
|
6502
|
+
// compute this button's own `text-muted-foreground`, so tone
|
|
6503
|
+
// separates neither.
|
|
6504
|
+
/* @__PURE__ */ jsxs13("span", { className: "agent-shimmer", "data-motion": "essential", children: [
|
|
6505
|
+
"Thinking",
|
|
6506
|
+
thinkingSeconds >= 1 ? ` \xB7 ${thinkingSeconds}s` : "\u2026"
|
|
6507
|
+
] })
|
|
6508
|
+
) : thinkMsRef.current != null ? `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1e3))}s` : "Thought process"
|
|
6509
|
+
]
|
|
6510
|
+
}
|
|
6511
|
+
),
|
|
6512
|
+
/* @__PURE__ */ jsx15("div", { className: "agent-disclose", "data-open": reasoningOpen ? "true" : "false", children: /* @__PURE__ */ jsx15("div", { ...inertProps(!reasoningOpen), children: /* @__PURE__ */ jsx15(
|
|
6513
|
+
"div",
|
|
6514
|
+
{
|
|
6515
|
+
id: reasoningId,
|
|
6516
|
+
ref: reasoningScrollRef,
|
|
6517
|
+
className: "mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-xs leading-relaxed text-muted-foreground",
|
|
6518
|
+
children: reasoning
|
|
6519
|
+
}
|
|
6520
|
+
) }) })
|
|
5827
6521
|
] }),
|
|
5828
|
-
segments && segments.length > 0 ? /* @__PURE__ */
|
|
6522
|
+
segments && segments.length > 0 ? /* @__PURE__ */ jsx15(
|
|
5829
6523
|
SegmentedBody,
|
|
5830
6524
|
{
|
|
5831
6525
|
segments,
|
|
@@ -5837,24 +6531,25 @@ function AssistantMessageImpl({
|
|
|
5837
6531
|
toolRenderers,
|
|
5838
6532
|
messageClassName
|
|
5839
6533
|
}
|
|
5840
|
-
) : /* @__PURE__ */
|
|
5841
|
-
/* @__PURE__ */
|
|
6534
|
+
) : /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
6535
|
+
/* @__PURE__ */ jsxs13("div", { className: messageClassName, children: [
|
|
5842
6536
|
body,
|
|
5843
|
-
streaming && content && !msg.toolCalls?.length && /* @__PURE__ */
|
|
6537
|
+
streaming && content && !msg.toolCalls?.length && /* @__PURE__ */ jsx15(StreamingCaret, {})
|
|
5844
6538
|
] }),
|
|
5845
|
-
msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */
|
|
6539
|
+
msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx15("div", { className: "mt-2 flex flex-col gap-1.5", children: msg.toolCalls.map((tc, index) => /* @__PURE__ */ jsx15(
|
|
5846
6540
|
ToolCallCard,
|
|
5847
6541
|
{
|
|
5848
6542
|
call: tc,
|
|
5849
6543
|
message: msg,
|
|
5850
6544
|
approval,
|
|
5851
6545
|
onOpenRun: onToolCallClick,
|
|
5852
|
-
renderers: toolRenderers
|
|
6546
|
+
renderers: toolRenderers,
|
|
6547
|
+
staggerIndex: index
|
|
5853
6548
|
},
|
|
5854
6549
|
tc.id
|
|
5855
6550
|
)) })
|
|
5856
6551
|
] }),
|
|
5857
|
-
durableCards && msg.parts && /* @__PURE__ */
|
|
6552
|
+
durableCards && msg.parts && /* @__PURE__ */ jsx15(
|
|
5858
6553
|
DurableChatCards,
|
|
5859
6554
|
{
|
|
5860
6555
|
...durableCards,
|
|
@@ -5863,7 +6558,7 @@ function AssistantMessageImpl({
|
|
|
5863
6558
|
className: "mt-3"
|
|
5864
6559
|
}
|
|
5865
6560
|
),
|
|
5866
|
-
workProductCards && workProductPartsFromMessageParts(msg.parts).map((part) => /* @__PURE__ */
|
|
6561
|
+
workProductCards && workProductPartsFromMessageParts(msg.parts).map((part) => /* @__PURE__ */ jsx15(
|
|
5867
6562
|
WorkProductCard,
|
|
5868
6563
|
{
|
|
5869
6564
|
part,
|
|
@@ -5873,7 +6568,7 @@ function AssistantMessageImpl({
|
|
|
5873
6568
|
`${part.ref.id}:${part.ref.version}`
|
|
5874
6569
|
)),
|
|
5875
6570
|
renderExtras?.(msg),
|
|
5876
|
-
resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && /* @__PURE__ */
|
|
6571
|
+
resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && /* @__PURE__ */ jsx15("div", { className: "mt-2", children: /* @__PURE__ */ jsx15(
|
|
5877
6572
|
MessageAttachments,
|
|
5878
6573
|
{
|
|
5879
6574
|
parts: attachmentPartsFromMessageParts(msg.parts),
|
|
@@ -5881,18 +6576,18 @@ function AssistantMessageImpl({
|
|
|
5881
6576
|
justify: "start"
|
|
5882
6577
|
}
|
|
5883
6578
|
) }),
|
|
5884
|
-
quiet && /* @__PURE__ */
|
|
5885
|
-
/* @__PURE__ */
|
|
5886
|
-
msg.modelUsed && /* @__PURE__ */
|
|
5887
|
-
formatTokensPerSecond(msg) && /* @__PURE__ */
|
|
5888
|
-
formatModelCost(msg, models) && /* @__PURE__ */
|
|
6579
|
+
quiet && /* @__PURE__ */ jsxs13("div", { "data-testid": "message-meta-lane", className: QUIET_META_LANE_CLASS, children: [
|
|
6580
|
+
/* @__PURE__ */ jsx15(CopyMessageButton, { text: copyTextOf(msg) }),
|
|
6581
|
+
msg.modelUsed && /* @__PURE__ */ jsx15("span", { className: "font-mono", children: msg.modelUsed }),
|
|
6582
|
+
formatTokensPerSecond(msg) && /* @__PURE__ */ jsx15("span", { children: formatTokensPerSecond(msg) }),
|
|
6583
|
+
formatModelCost(msg, models) && /* @__PURE__ */ jsx15("span", { children: formatModelCost(msg, models) })
|
|
5889
6584
|
] })
|
|
5890
6585
|
] });
|
|
5891
6586
|
}
|
|
5892
6587
|
var AssistantMessage = memo(AssistantMessageImpl);
|
|
5893
6588
|
function useThinkingSeconds(active) {
|
|
5894
|
-
const [seconds, setSeconds] =
|
|
5895
|
-
|
|
6589
|
+
const [seconds, setSeconds] = useState16(0);
|
|
6590
|
+
useEffect12(() => {
|
|
5896
6591
|
if (!active) return;
|
|
5897
6592
|
setSeconds(0);
|
|
5898
6593
|
const id = setInterval(() => setSeconds((s) => s + 1), 1e3);
|
|
@@ -5902,23 +6597,23 @@ function useThinkingSeconds(active) {
|
|
|
5902
6597
|
}
|
|
5903
6598
|
function ThinkingRow({ agentLabel, chrome = "labeled" }) {
|
|
5904
6599
|
const seconds = useThinkingSeconds(true);
|
|
5905
|
-
return /* @__PURE__ */
|
|
5906
|
-
chrome !== "quiet" && /* @__PURE__ */
|
|
5907
|
-
/* @__PURE__ */
|
|
5908
|
-
/* @__PURE__ */
|
|
6600
|
+
return /* @__PURE__ */ jsxs13("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
|
|
6601
|
+
chrome !== "quiet" && /* @__PURE__ */ jsx15("p", { className: "mb-1 text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground", children: agentLabel }),
|
|
6602
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 text-[15px] text-muted-foreground", children: [
|
|
6603
|
+
/* @__PURE__ */ jsx15("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx15("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
|
|
5909
6604
|
"Thinking",
|
|
5910
6605
|
seconds >= 3 ? ` \xB7 ${seconds}s` : "..."
|
|
5911
6606
|
] })
|
|
5912
6607
|
] });
|
|
5913
6608
|
}
|
|
5914
6609
|
function StreamErrorRow({ message, onRetry }) {
|
|
5915
|
-
return /* @__PURE__ */
|
|
5916
|
-
/* @__PURE__ */
|
|
5917
|
-
/* @__PURE__ */
|
|
5918
|
-
/* @__PURE__ */
|
|
6610
|
+
return /* @__PURE__ */ jsx15("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs13("div", { role: "alert", className: "flex items-start gap-2.5 rounded-lg border border-destructive/40 bg-destructive/5 px-3 py-2.5 text-sm text-destructive", children: [
|
|
6611
|
+
/* @__PURE__ */ jsxs13("svg", { className: "mt-0.5 h-4 w-4 shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
6612
|
+
/* @__PURE__ */ jsx15("circle", { cx: "12", cy: "12", r: "9" }),
|
|
6613
|
+
/* @__PURE__ */ jsx15("path", { d: "M12 8v4m0 4h.01" })
|
|
5919
6614
|
] }),
|
|
5920
|
-
/* @__PURE__ */
|
|
5921
|
-
onRetry && /* @__PURE__ */
|
|
6615
|
+
/* @__PURE__ */ jsx15("span", { className: "min-w-0 flex-1 break-words", children: message }),
|
|
6616
|
+
onRetry && /* @__PURE__ */ jsx15(
|
|
5922
6617
|
"button",
|
|
5923
6618
|
{
|
|
5924
6619
|
type: "button",
|
|
@@ -5953,32 +6648,32 @@ function ChatMessages({
|
|
|
5953
6648
|
}) {
|
|
5954
6649
|
const messageClassName = messageSize === "large" ? "agent-app-message-copy text-[17px] leading-[1.6]" : "agent-app-message-copy text-base leading-[1.6]";
|
|
5955
6650
|
const renderBody = useMemo7(
|
|
5956
|
-
() => renderMarkdown ?? ((content) => /* @__PURE__ */
|
|
6651
|
+
() => renderMarkdown ?? ((content) => /* @__PURE__ */ jsx15("p", { className: "whitespace-pre-wrap", children: content })),
|
|
5957
6652
|
[renderMarkdown]
|
|
5958
6653
|
);
|
|
5959
6654
|
const lastIsUser = messages[messages.length - 1]?.role === "user";
|
|
5960
6655
|
const quiet = chrome === "quiet";
|
|
5961
6656
|
if (messages.length === 0 && !loading && !error) {
|
|
5962
|
-
const empty = renderEmpty ? renderEmpty() : /* @__PURE__ */
|
|
5963
|
-
return /* @__PURE__ */
|
|
6657
|
+
const empty = renderEmpty ? renderEmpty() : /* @__PURE__ */ jsx15(ChatEmptyState, { ...emptyState });
|
|
6658
|
+
return /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
5964
6659
|
header,
|
|
5965
6660
|
empty
|
|
5966
6661
|
] });
|
|
5967
6662
|
}
|
|
5968
|
-
return /* @__PURE__ */
|
|
6663
|
+
return /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
5969
6664
|
header,
|
|
5970
6665
|
messages.map(
|
|
5971
|
-
(msg) => msg.role === "user" ? /* @__PURE__ */
|
|
5972
|
-
/* @__PURE__ */
|
|
5973
|
-
!quiet && /* @__PURE__ */
|
|
5974
|
-
/* @__PURE__ */
|
|
6666
|
+
(msg) => msg.role === "user" ? /* @__PURE__ */ jsxs13("div", { className: `mx-auto w-full max-w-3xl px-6 ${quiet ? "group pb-1 pt-3" : "py-3"}`, children: [
|
|
6667
|
+
/* @__PURE__ */ jsxs13("div", { className: `ml-auto w-fit ${quiet ? "max-w-[72%]" : "max-w-[85%]"}`, children: [
|
|
6668
|
+
!quiet && /* @__PURE__ */ jsx15("p", { className: "mb-1 text-right text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground", children: userLabel }),
|
|
6669
|
+
/* @__PURE__ */ jsx15(
|
|
5975
6670
|
"div",
|
|
5976
6671
|
{
|
|
5977
6672
|
className: quiet ? `rounded-2xl bg-[color-mix(in_srgb,hsl(var(--secondary))_65%,hsl(var(--background)))] px-4 py-2.5 ${messageClassName}` : `rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 ${messageClassName}`,
|
|
5978
|
-
children: /* @__PURE__ */
|
|
6673
|
+
children: /* @__PURE__ */ jsx15("p", { className: "whitespace-pre-wrap", children: msg.content })
|
|
5979
6674
|
}
|
|
5980
6675
|
),
|
|
5981
|
-
resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && /* @__PURE__ */
|
|
6676
|
+
resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && /* @__PURE__ */ jsx15("div", { className: "mt-1.5", children: /* @__PURE__ */ jsx15(
|
|
5982
6677
|
MessageAttachments,
|
|
5983
6678
|
{
|
|
5984
6679
|
parts: attachmentPartsFromMessageParts(msg.parts),
|
|
@@ -5987,8 +6682,8 @@ function ChatMessages({
|
|
|
5987
6682
|
}
|
|
5988
6683
|
) })
|
|
5989
6684
|
] }),
|
|
5990
|
-
quiet && /* @__PURE__ */
|
|
5991
|
-
] }, msg.id) : /* @__PURE__ */
|
|
6685
|
+
quiet && /* @__PURE__ */ jsx15("div", { "data-testid": "message-meta-lane", className: `${QUIET_META_LANE_CLASS} justify-end`, children: /* @__PURE__ */ jsx15(CopyMessageButton, { text: msg.content }) })
|
|
6686
|
+
] }, msg.id) : /* @__PURE__ */ jsx15(
|
|
5992
6687
|
AssistantMessage,
|
|
5993
6688
|
{
|
|
5994
6689
|
msg,
|
|
@@ -6009,8 +6704,8 @@ function ChatMessages({
|
|
|
6009
6704
|
msg.id
|
|
6010
6705
|
)
|
|
6011
6706
|
),
|
|
6012
|
-
loading && lastIsUser && /* @__PURE__ */
|
|
6013
|
-
error && !loading && /* @__PURE__ */
|
|
6707
|
+
loading && lastIsUser && /* @__PURE__ */ jsx15(ThinkingRow, { agentLabel, chrome }),
|
|
6708
|
+
error && !loading && /* @__PURE__ */ jsx15(StreamErrorRow, { message: error, onRetry })
|
|
6014
6709
|
] });
|
|
6015
6710
|
}
|
|
6016
6711
|
|
|
@@ -6119,6 +6814,26 @@ export {
|
|
|
6119
6814
|
withoutRecordGridRemoved,
|
|
6120
6815
|
pruneRecordGridOverlay,
|
|
6121
6816
|
RecordGrid,
|
|
6817
|
+
DEFAULT_SPARKLINE_WIDTH,
|
|
6818
|
+
DEFAULT_SPARKLINE_HEIGHT,
|
|
6819
|
+
DEFAULT_SPARKLINE_LABEL,
|
|
6820
|
+
DEFAULT_SPARKLINE_EMPTY_LABEL,
|
|
6821
|
+
DEFAULT_SPARKLINE_UNAVAILABLE_LABEL,
|
|
6822
|
+
formatSparklineValue,
|
|
6823
|
+
sparklineReadings,
|
|
6824
|
+
sparklineGeometry,
|
|
6825
|
+
sparklinePointsAttribute,
|
|
6826
|
+
sparklineLabel,
|
|
6827
|
+
Sparkline,
|
|
6828
|
+
insightDelta,
|
|
6829
|
+
insightDeltaTone,
|
|
6830
|
+
formatInsightDelta,
|
|
6831
|
+
InsightCard,
|
|
6832
|
+
DEFAULT_INSIGHT_PAGE_SIZE,
|
|
6833
|
+
insightPageSize,
|
|
6834
|
+
insightPageCount,
|
|
6835
|
+
insightPageSlice,
|
|
6836
|
+
InsightDeck,
|
|
6122
6837
|
formatModelCost,
|
|
6123
6838
|
formatTokensPerSecond,
|
|
6124
6839
|
RunDrillIn,
|
|
@@ -6128,4 +6843,4 @@ export {
|
|
|
6128
6843
|
useThinkingSeconds,
|
|
6129
6844
|
ChatMessages
|
|
6130
6845
|
};
|
|
6131
|
-
//# sourceMappingURL=chunk-
|
|
6846
|
+
//# sourceMappingURL=chunk-CXPWUCXC.js.map
|