@agents24/chat-react 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -21
- package/compatibility.json +10 -10
- package/dist/chunk-SSUO4EPD.js +189 -0
- package/dist/chunk-SSUO4EPD.js.map +1 -0
- package/dist/chunk-ZCNHLFRB.js +108 -0
- package/dist/chunk-ZCNHLFRB.js.map +1 -0
- package/dist/index.cjs +112 -95
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +362 -68
- package/dist/index.js.map +1 -1
- package/dist/mcp-oauth.d.ts +13 -0
- package/dist/runtime/index.cjs +594 -0
- package/dist/runtime/index.cjs.map +1 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +458 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/input-contract.d.ts +20 -0
- package/dist/runtime/use-agent-chat-runtime.d.ts +83 -0
- package/dist/scaffold/app.d.ts +30 -0
- package/dist/scaffold/components/chat/chat-composer.d.ts +21 -0
- package/dist/scaffold/components/chat/chat-message.d.ts +21 -0
- package/dist/scaffold/components/chat/chat-shell.d.ts +8 -0
- package/dist/scaffold/components/chat/collapsible-user-message.d.ts +3 -0
- package/dist/scaffold/components/chat/external-link-dialog.d.ts +2 -0
- package/dist/scaffold/components/chat/identity-control.d.ts +4 -0
- package/dist/scaffold/components/chat/message-parts.d.ts +12 -0
- package/dist/scaffold/components/chat/theme-menu.d.ts +1 -0
- package/dist/scaffold/components/chat/thread-sidebar.d.ts +16 -0
- package/dist/scaffold/components/chat/timeline-loading.d.ts +7 -0
- package/dist/scaffold/components/chat/turn-outline.d.ts +4 -0
- package/dist/scaffold/components/theme-provider.d.ts +20 -0
- package/dist/scaffold/components/ui/attachment.d.ts +24 -0
- package/dist/scaffold/components/ui/bubble.d.ts +17 -0
- package/dist/scaffold/components/ui/button-group.d.ts +11 -0
- package/dist/scaffold/components/ui/button.d.ts +10 -0
- package/dist/scaffold/components/ui/dialog.d.ts +17 -0
- package/dist/scaffold/components/ui/dropdown-menu.d.ts +29 -0
- package/dist/scaffold/components/ui/input.d.ts +3 -0
- package/dist/scaffold/components/ui/marker.d.ts +11 -0
- package/dist/scaffold/components/ui/message-scroller.d.ts +10 -0
- package/dist/scaffold/components/ui/message.d.ts +10 -0
- package/dist/scaffold/components/ui/popover.d.ts +6 -0
- package/dist/scaffold/components/ui/select.d.ts +8 -0
- package/dist/scaffold/components/ui/separator.d.ts +4 -0
- package/dist/scaffold/components/ui/sheet.d.ts +14 -0
- package/dist/scaffold/components/ui/sidebar.d.ts +69 -0
- package/dist/scaffold/components/ui/skeleton.d.ts +2 -0
- package/dist/scaffold/components/ui/textarea.d.ts +3 -0
- package/dist/scaffold/components/ui/tooltip.d.ts +15 -0
- package/dist/scaffold/hooks/use-mobile.d.ts +1 -0
- package/dist/scaffold/identity.d.ts +10 -0
- package/dist/scaffold/index.cjs +2270 -0
- package/dist/scaffold/index.cjs.map +1 -0
- package/dist/scaffold/index.d.ts +14 -0
- package/dist/scaffold/index.js +2244 -0
- package/dist/scaffold/index.js.map +1 -0
- package/dist/scaffold/lib/utils.d.ts +2 -0
- package/dist/styles.css +137 -378
- package/dist/types.d.ts +3 -13
- package/dist/ui/adapters.d.ts +1 -1
- package/dist/ui/agent-chat-actions.d.ts +12 -5
- package/dist/ui/agent-chat-composer.d.ts +2 -1
- package/dist/ui/agent-chat-context-compression-row.d.ts +5 -0
- package/dist/ui/agent-chat-context-status.d.ts +13 -0
- package/dist/ui/agent-chat-message.d.ts +7 -5
- package/dist/ui/agent-response-timeline.d.ts +29 -7
- package/dist/ui/ask-user-interaction-state.d.ts +20 -0
- package/dist/ui/ask-user-interaction.d.ts +8 -0
- package/dist/ui/index.cjs +1391 -271
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.ts +5 -0
- package/dist/ui/index.js +2380 -65
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/tool-sessions.d.ts +70 -0
- package/dist/ui/use-audio-recorder.d.ts +8 -0
- package/package.json +27 -12
- package/scaffold/components.json +25 -0
- package/scaffold/manifest.json +28 -0
- package/scaffold/src/app.tsx +71 -0
- package/scaffold/src/chat.css +54 -0
- package/scaffold/src/components/chat/chat-composer.tsx +237 -0
- package/scaffold/src/components/chat/chat-message.tsx +76 -0
- package/scaffold/src/components/chat/chat-shell.tsx +257 -0
- package/scaffold/src/components/chat/collapsible-user-message.tsx +37 -0
- package/scaffold/src/components/chat/external-link-dialog.tsx +48 -0
- package/scaffold/src/components/chat/identity-control.tsx +69 -0
- package/scaffold/src/components/chat/message-parts.tsx +83 -0
- package/scaffold/src/components/chat/theme-menu.tsx +79 -0
- package/scaffold/src/components/chat/thread-sidebar.tsx +114 -0
- package/scaffold/src/components/chat/timeline-loading.ts +17 -0
- package/scaffold/src/components/chat/turn-outline.tsx +73 -0
- package/scaffold/src/components/theme-provider.tsx +91 -0
- package/scaffold/src/components/ui/attachment.tsx +204 -0
- package/scaffold/src/components/ui/bubble.tsx +125 -0
- package/scaffold/src/components/ui/button-group.tsx +83 -0
- package/scaffold/src/components/ui/button.tsx +65 -0
- package/scaffold/src/components/ui/dialog.tsx +171 -0
- package/scaffold/src/components/ui/dropdown-menu.tsx +271 -0
- package/scaffold/src/components/ui/input.tsx +19 -0
- package/scaffold/src/components/ui/marker.tsx +69 -0
- package/scaffold/src/components/ui/message-scroller.tsx +129 -0
- package/scaffold/src/components/ui/message.tsx +92 -0
- package/scaffold/src/components/ui/popover.tsx +40 -0
- package/scaffold/src/components/ui/select.tsx +92 -0
- package/scaffold/src/components/ui/separator.tsx +28 -0
- package/scaffold/src/components/ui/sheet.tsx +150 -0
- package/scaffold/src/components/ui/sidebar.tsx +677 -0
- package/scaffold/src/components/ui/skeleton.tsx +13 -0
- package/scaffold/src/components/ui/textarea.tsx +18 -0
- package/scaffold/src/components/ui/tooltip.tsx +56 -0
- package/scaffold/src/hooks/use-mobile.ts +24 -0
- package/scaffold/src/identity.ts +17 -0
- package/scaffold/src/index.css +222 -0
- package/scaffold/src/index.tsx +39 -0
- package/scaffold/src/lib/utils.ts +6 -0
- package/scaffold/styles.css +3 -0
- package/dist/chunk-CHAU7FNW.js +0 -140
- package/dist/chunk-CHAU7FNW.js.map +0 -1
- package/dist/chunk-LI67M74F.js +0 -445
- package/dist/chunk-LI67M74F.js.map +0 -1
- package/dist/chunk-R7WFL3YR.js +0 -1327
- package/dist/chunk-R7WFL3YR.js.map +0 -1
- package/dist/renderers.d.ts +0 -10
- package/dist/templates/agent-chat-app.d.ts +0 -18
- package/dist/templates/agent-chat-layout.d.ts +0 -77
- package/dist/templates/agent-chat-shell.d.ts +0 -37
- package/dist/templates/appearance-control.d.ts +0 -5
- package/dist/templates/index.cjs +0 -2600
- package/dist/templates/index.cjs.map +0 -1
- package/dist/templates/index.d.ts +0 -4
- package/dist/templates/index.js +0 -846
- package/dist/templates/index.js.map +0 -1
package/dist/ui/index.cjs
CHANGED
|
@@ -30,12 +30,23 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/ui/index.ts
|
|
31
31
|
var ui_exports = {};
|
|
32
32
|
__export(ui_exports, {
|
|
33
|
+
AgentChatActivityRow: () => AgentChatActivityRow,
|
|
33
34
|
AgentChatComposer: () => AgentChatComposer,
|
|
35
|
+
AgentChatContextCompressionRow: () => AgentChatContextCompressionRow,
|
|
36
|
+
AgentChatContextStatus: () => AgentChatContextStatus,
|
|
34
37
|
AgentChatDefaultActions: () => AgentChatDefaultActions,
|
|
35
38
|
AgentChatMessage: () => AgentChatMessage,
|
|
36
|
-
|
|
39
|
+
AgentChatModelTurnRow: () => AgentChatModelTurnRow,
|
|
40
|
+
AgentChatNodeActivityRow: () => AgentChatNodeActivityRow,
|
|
41
|
+
AgentChatPart: () => AgentChatPart,
|
|
42
|
+
AgentChatSubagentGroup: () => AgentChatSubagentGroup,
|
|
43
|
+
AgentChatToolGroup: () => AgentChatToolGroup,
|
|
44
|
+
AgentChatToolPart: () => AgentChatToolPart,
|
|
45
|
+
AgentChatToolRow: () => AgentChatToolRow,
|
|
46
|
+
AgentChatToolSession: () => AgentChatToolSession,
|
|
37
47
|
AgentChatUserMessageContent: () => AgentChatUserMessageContent,
|
|
38
48
|
AgentResponseTimeline: () => AgentResponseTimeline,
|
|
49
|
+
AskUserInteraction: () => AskUserInteraction,
|
|
39
50
|
Attachment: () => Attachment,
|
|
40
51
|
AttachmentAction: () => AttachmentAction,
|
|
41
52
|
AttachmentActions: () => AttachmentActions,
|
|
@@ -72,15 +83,22 @@ __export(ui_exports, {
|
|
|
72
83
|
MessageResponse: () => MessageResponse,
|
|
73
84
|
ShadcnMessage: () => Message,
|
|
74
85
|
ShadcnMessageContent: () => MessageContent,
|
|
86
|
+
agentChatToolLabel: () => agentChatToolLabel,
|
|
75
87
|
attachmentMediaVariants: () => attachmentMediaVariants,
|
|
76
88
|
attachmentVariants: () => attachmentVariants,
|
|
77
89
|
bubbleVariants: () => bubbleVariants,
|
|
78
90
|
cn: () => cn,
|
|
91
|
+
contextStatusMetrics: () => contextStatusMetrics,
|
|
79
92
|
hitlActionLabel: () => hitlActionLabel,
|
|
80
93
|
hitlTitle: () => hitlTitle,
|
|
94
|
+
isAgentChatSubagent: () => isAgentChatSubagent,
|
|
95
|
+
isAgentChatToolRunning: () => isAgentChatToolRunning,
|
|
96
|
+
latestRunningAgentChatToolId: () => latestRunningAgentChatToolId,
|
|
81
97
|
markerVariants: () => markerVariants,
|
|
98
|
+
partitionAgentChatToolTimeline: () => partitionAgentChatToolTimeline,
|
|
82
99
|
resolvedHitlLabel: () => resolvedHitlLabel,
|
|
83
|
-
shouldCollapseUserMessage: () => shouldCollapseUserMessage
|
|
100
|
+
shouldCollapseUserMessage: () => shouldCollapseUserMessage,
|
|
101
|
+
useAudioRecorder: () => useAudioRecorder
|
|
84
102
|
});
|
|
85
103
|
module.exports = __toCommonJS(ui_exports);
|
|
86
104
|
|
|
@@ -120,20 +138,21 @@ function formatFileCount(files) {
|
|
|
120
138
|
if (files.length === 1) return files[0].filename;
|
|
121
139
|
return `${files.length} files`;
|
|
122
140
|
}
|
|
123
|
-
var pillButtonClass = "inline-flex size-8 shrink-0 items-center justify-center gap-2 rounded-
|
|
124
|
-
var submitButtonClass = "inline-flex size-9 shrink-0 items-center justify-center gap-2 rounded-
|
|
141
|
+
var pillButtonClass = "inline-flex size-8 shrink-0 items-center justify-center gap-2 rounded-lg border-0 bg-muted text-sm text-muted-foreground shadow-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50";
|
|
142
|
+
var submitButtonClass = "inline-flex size-9 shrink-0 items-center justify-center gap-2 rounded-lg border-0 bg-primary text-sm text-primary-foreground shadow-none transition-[background-color,color,opacity,transform] duration-200 hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50";
|
|
125
143
|
function AgentChatComposer({
|
|
126
144
|
accept,
|
|
127
145
|
allowAttachments = true,
|
|
128
146
|
attachmentLayout = "flow",
|
|
129
147
|
className,
|
|
130
148
|
disabled = false,
|
|
149
|
+
forceExpanded = false,
|
|
131
150
|
inputToolbarContent,
|
|
132
151
|
isRunning = false,
|
|
133
152
|
onAttachmentCountChange,
|
|
134
153
|
onStop,
|
|
135
154
|
onSubmit,
|
|
136
|
-
placeholder = "
|
|
155
|
+
placeholder = "Message the agent",
|
|
137
156
|
textareaRef
|
|
138
157
|
}) {
|
|
139
158
|
const fileInputRef = React.useRef(null);
|
|
@@ -142,7 +161,7 @@ function AgentChatComposer({
|
|
|
142
161
|
const [text, setText] = React.useState("");
|
|
143
162
|
const [files, setFiles] = React.useState([]);
|
|
144
163
|
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
145
|
-
const isExpanded = text.includes("\n") || text.length > 62;
|
|
164
|
+
const isExpanded = forceExpanded || text.includes("\n") || text.length > 62;
|
|
146
165
|
const setTextareaRef = React.useCallback(
|
|
147
166
|
(node) => {
|
|
148
167
|
localTextareaRef.current = node;
|
|
@@ -197,6 +216,7 @@ function AgentChatComposer({
|
|
|
197
216
|
setText("");
|
|
198
217
|
setFiles([]);
|
|
199
218
|
revokeComposerFiles(submittedFiles);
|
|
219
|
+
} catch {
|
|
200
220
|
} finally {
|
|
201
221
|
setIsSubmitting(false);
|
|
202
222
|
}
|
|
@@ -207,7 +227,7 @@ function AgentChatComposer({
|
|
|
207
227
|
void submit();
|
|
208
228
|
}
|
|
209
229
|
};
|
|
210
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("a24-composer relative mx-auto w-full max-w-3xl overflow-visible", className), children: [
|
|
230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("a24-composer relative mx-auto w-full max-w-3xl overflow-visible", className), "data-agents24-chat-composer": "", children: [
|
|
211
231
|
files.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
212
232
|
"div",
|
|
213
233
|
{
|
|
@@ -220,7 +240,7 @@ function AgentChatComposer({
|
|
|
220
240
|
children: files.map((file) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
221
241
|
"div",
|
|
222
242
|
{
|
|
223
|
-
className: "a24-composer__attachment group relative flex h-8 max-w-[min(20rem,calc(100vw-2rem))] cursor-default select-none items-center gap-1.5 rounded-md border border-
|
|
243
|
+
className: "a24-composer__attachment group relative flex h-8 max-w-[min(20rem,calc(100vw-2rem))] cursor-default select-none items-center gap-1.5 rounded-md border border-border bg-card px-1.5 text-sm font-medium text-card-foreground transition-colors hover:bg-accent",
|
|
224
244
|
children: [
|
|
225
245
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex size-5 shrink-0 items-center justify-center rounded bg-background text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Paperclip, { className: "size-3" }) }),
|
|
226
246
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "min-w-0 flex-1 truncate", children: file.filename }),
|
|
@@ -245,8 +265,8 @@ function AgentChatComposer({
|
|
|
245
265
|
{
|
|
246
266
|
"data-expanded": isExpanded ? "" : void 0,
|
|
247
267
|
className: cn(
|
|
248
|
-
"a24-composer__surface relative w-full border border-
|
|
249
|
-
isExpanded ? "rounded-
|
|
268
|
+
"a24-composer__surface relative w-full border border-input bg-background shadow-sm",
|
|
269
|
+
isExpanded ? "rounded-xl p-2 pb-1.5" : "rounded-xl px-2 py-[3px]"
|
|
250
270
|
),
|
|
251
271
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
252
272
|
"div",
|
|
@@ -294,7 +314,7 @@ function AgentChatComposer({
|
|
|
294
314
|
"aria-label": "Message",
|
|
295
315
|
autoComplete: "off",
|
|
296
316
|
className: cn(
|
|
297
|
-
"a24-composer__textarea w-full resize-none border-0 bg-transparent px-1 text-[15px] leading-relaxed text-foreground shadow-none outline-none placeholder:text-
|
|
317
|
+
"a24-composer__textarea w-full resize-none border-0 bg-transparent px-1 text-[15px] leading-relaxed text-foreground shadow-none outline-none placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0",
|
|
298
318
|
isExpanded ? "min-h-9 max-h-[224px] py-1" : "min-h-9 h-9 max-h-9 py-2"
|
|
299
319
|
),
|
|
300
320
|
disabled: disabled || isSubmitting || isRunning,
|
|
@@ -342,7 +362,9 @@ function AgentChatComposer({
|
|
|
342
362
|
}
|
|
343
363
|
|
|
344
364
|
// src/ui/agent-chat-actions.tsx
|
|
365
|
+
var React3 = __toESM(require("react"), 1);
|
|
345
366
|
var import_lucide_react2 = require("lucide-react");
|
|
367
|
+
var import_radix_ui = require("radix-ui");
|
|
346
368
|
|
|
347
369
|
// src/ui/adapters.ts
|
|
348
370
|
var React2 = __toESM(require("react"), 1);
|
|
@@ -613,6 +635,7 @@ function MessageFooter({ className, ...props }) {
|
|
|
613
635
|
}
|
|
614
636
|
|
|
615
637
|
// src/ui/adapters.ts
|
|
638
|
+
var ChatMessageRoleContext = React2.createContext("assistant");
|
|
616
639
|
function ChatMessage(input) {
|
|
617
640
|
const { className, from, align, ...props } = input;
|
|
618
641
|
const isUser = from === "user";
|
|
@@ -621,22 +644,27 @@ function ChatMessage(input) {
|
|
|
621
644
|
const messageProps = Object.assign({}, props);
|
|
622
645
|
messageProps.align = resolvedAlign;
|
|
623
646
|
messageProps.className = cn(
|
|
624
|
-
"group flex w-full flex-col gap-2",
|
|
625
|
-
isUser ? cn("is-user max-w-[80%] justify-end", isRtl ? "mr-auto" : "ml-auto") : "is-assistant max-w-full",
|
|
647
|
+
"a24-chat-message group flex w-full flex-col gap-2",
|
|
648
|
+
isUser ? cn("a24-chat-message--user is-user max-w-[80%] justify-end", isRtl ? "mr-auto" : "ml-auto") : "a24-chat-message--assistant is-assistant max-w-full",
|
|
626
649
|
className
|
|
627
650
|
);
|
|
628
|
-
return React2.createElement(
|
|
651
|
+
return React2.createElement(
|
|
652
|
+
ChatMessageRoleContext.Provider,
|
|
653
|
+
{ value: from },
|
|
654
|
+
React2.createElement(Message, messageProps)
|
|
655
|
+
);
|
|
629
656
|
}
|
|
630
657
|
function ChatMessageContent({
|
|
631
658
|
className,
|
|
659
|
+
from,
|
|
632
660
|
...props
|
|
633
661
|
}) {
|
|
662
|
+
const inheritedRole = React2.useContext(ChatMessageRoleContext);
|
|
663
|
+
const isUser = (from ?? inheritedRole) === "user";
|
|
634
664
|
return React2.createElement("div", {
|
|
635
665
|
className: cn(
|
|
636
|
-
"
|
|
637
|
-
"
|
|
638
|
-
"group-[.is-assistant]:w-full group-[.is-assistant]:max-w-full group-[.is-assistant]:text-foreground",
|
|
639
|
-
props.dir === "rtl" ? "group-[.is-user]:mr-auto" : "group-[.is-user]:ml-auto",
|
|
666
|
+
"a24-chat-message-content flex max-w-full min-w-0 flex-col gap-2 text-sm",
|
|
667
|
+
isUser ? "a24-chat-message-content--user is-user:dark w-fit overflow-visible rounded-lg bg-secondary px-4 py-3 text-foreground" : "a24-chat-message-content--assistant w-full overflow-visible text-foreground",
|
|
640
668
|
className
|
|
641
669
|
),
|
|
642
670
|
"data-slot": "bubble-content",
|
|
@@ -753,11 +781,30 @@ function ChatAttachments({
|
|
|
753
781
|
|
|
754
782
|
// src/ui/agent-chat-actions.tsx
|
|
755
783
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
784
|
+
var FEEDBACK_REASONS = [
|
|
785
|
+
["incorrect", "Incorrect"],
|
|
786
|
+
["irrelevant", "Irrelevant"],
|
|
787
|
+
["incomplete", "Incomplete"],
|
|
788
|
+
["unsafe", "Unsafe"],
|
|
789
|
+
["citation_issue", "Citation issue"],
|
|
790
|
+
["other", "Other"]
|
|
791
|
+
];
|
|
756
792
|
function AgentChatDefaultActions({
|
|
793
|
+
additionalActions,
|
|
794
|
+
dir,
|
|
757
795
|
handlers,
|
|
758
796
|
message
|
|
759
797
|
}) {
|
|
798
|
+
const [feedbackOpen, setFeedbackOpen] = React3.useState(false);
|
|
799
|
+
const [feedbackTrigger, setFeedbackTrigger] = React3.useState(null);
|
|
800
|
+
const [reason, setReason] = React3.useState(handlers?.feedback?.reason ?? null);
|
|
801
|
+
const [comment, setComment] = React3.useState(handlers?.feedback?.comment ?? "");
|
|
802
|
+
React3.useEffect(() => {
|
|
803
|
+
setReason(handlers?.feedback?.reason ?? null);
|
|
804
|
+
setComment(handlers?.feedback?.comment ?? "");
|
|
805
|
+
}, [handlers?.feedback?.comment, handlers?.feedback?.reason]);
|
|
760
806
|
if (!handlers || message.role !== "assistant" || message.isFinal === false) return null;
|
|
807
|
+
const canWriteFeedback = Boolean(message.runId && handlers.onSetFeedback);
|
|
761
808
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(ChatMessageActions, { children: [
|
|
762
809
|
handlers.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
763
810
|
ChatMessageAction,
|
|
@@ -768,24 +815,101 @@ function AgentChatDefaultActions({
|
|
|
768
815
|
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.RefreshCcw, { className: "size-4" })
|
|
769
816
|
}
|
|
770
817
|
) : null,
|
|
771
|
-
|
|
818
|
+
canWriteFeedback ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
772
819
|
ChatMessageAction,
|
|
773
820
|
{
|
|
774
821
|
label: "Like",
|
|
775
|
-
onClick: () => void handlers.
|
|
822
|
+
onClick: () => void handlers.onSetFeedback?.(message, {
|
|
823
|
+
rating: handlers.feedback?.rating === "like" ? null : "like"
|
|
824
|
+
}),
|
|
776
825
|
tooltip: "Like this response",
|
|
777
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ThumbsUp, { className: "size-4", fill: handlers.
|
|
778
|
-
}
|
|
779
|
-
) : null,
|
|
780
|
-
handlers.onDislike ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
781
|
-
ChatMessageAction,
|
|
782
|
-
{
|
|
783
|
-
label: "Dislike",
|
|
784
|
-
onClick: () => void handlers.onDislike?.(message),
|
|
785
|
-
tooltip: "Dislike this response",
|
|
786
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ThumbsDown, { className: "size-4", fill: handlers.disliked ? "currentColor" : "none" })
|
|
826
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ThumbsUp, { className: "size-4", fill: handlers.feedback?.rating === "like" ? "currentColor" : "none" })
|
|
787
827
|
}
|
|
788
828
|
) : null,
|
|
829
|
+
canWriteFeedback ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_radix_ui.Popover.Root, { onOpenChange: setFeedbackOpen, open: feedbackOpen, children: [
|
|
830
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui.Popover.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
831
|
+
ChatMessageAction,
|
|
832
|
+
{
|
|
833
|
+
label: "Dislike",
|
|
834
|
+
onClick: () => {
|
|
835
|
+
if (handlers.feedback?.rating !== "dislike") {
|
|
836
|
+
void handlers.onSetFeedback?.(message, { rating: "dislike" });
|
|
837
|
+
}
|
|
838
|
+
setFeedbackOpen(true);
|
|
839
|
+
},
|
|
840
|
+
ref: setFeedbackTrigger,
|
|
841
|
+
tooltip: "Dislike this response",
|
|
842
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ThumbsDown, { className: "size-4", fill: handlers.feedback?.rating === "dislike" ? "currentColor" : "none" })
|
|
843
|
+
}
|
|
844
|
+
) }),
|
|
845
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
846
|
+
import_radix_ui.Popover.Portal,
|
|
847
|
+
{
|
|
848
|
+
container: feedbackTrigger?.closest("[data-agents24-theme-root]") ?? void 0,
|
|
849
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
850
|
+
import_radix_ui.Popover.Content,
|
|
851
|
+
{
|
|
852
|
+
align: "end",
|
|
853
|
+
"aria-label": "Dislike details",
|
|
854
|
+
className: "z-50 w-80 rounded-lg border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none",
|
|
855
|
+
dir,
|
|
856
|
+
side: "top",
|
|
857
|
+
sideOffset: 8,
|
|
858
|
+
children: [
|
|
859
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-sm font-medium", children: "What could be better?" }),
|
|
860
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-3 flex flex-wrap gap-1.5", children: FEEDBACK_REASONS.map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
861
|
+
"button",
|
|
862
|
+
{
|
|
863
|
+
"aria-pressed": reason === value,
|
|
864
|
+
className: "rounded-md border border-border px-2.5 py-1.5 text-xs font-medium transition-colors hover:bg-muted aria-pressed:border-transparent aria-pressed:bg-secondary",
|
|
865
|
+
onClick: () => setReason(reason === value ? null : value),
|
|
866
|
+
type: "button",
|
|
867
|
+
children: label
|
|
868
|
+
},
|
|
869
|
+
value
|
|
870
|
+
)) }),
|
|
871
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
872
|
+
"textarea",
|
|
873
|
+
{
|
|
874
|
+
"aria-label": "Optional feedback comment",
|
|
875
|
+
className: "mt-3 min-h-20 w-full resize-none rounded-md border border-input bg-background px-3 py-2 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring",
|
|
876
|
+
maxLength: 1e3,
|
|
877
|
+
onChange: (event) => setComment(event.target.value),
|
|
878
|
+
placeholder: "Add a comment (optional)",
|
|
879
|
+
value: comment
|
|
880
|
+
}
|
|
881
|
+
),
|
|
882
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mt-3 flex items-center justify-between gap-2", children: [
|
|
883
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
884
|
+
"button",
|
|
885
|
+
{
|
|
886
|
+
className: "rounded-md px-3 py-2 text-sm font-medium hover:bg-muted",
|
|
887
|
+
onClick: () => {
|
|
888
|
+
void Promise.resolve(handlers.onSetFeedback?.(message, { rating: null })).then(() => setFeedbackOpen(false)).catch(() => void 0);
|
|
889
|
+
},
|
|
890
|
+
type: "button",
|
|
891
|
+
children: "Remove feedback"
|
|
892
|
+
}
|
|
893
|
+
),
|
|
894
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
895
|
+
"button",
|
|
896
|
+
{
|
|
897
|
+
className: "rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:opacity-90",
|
|
898
|
+
onClick: () => {
|
|
899
|
+
void Promise.resolve(handlers.onSetFeedback?.(message, { rating: "dislike", reason, comment })).then(() => setFeedbackOpen(false)).catch(() => void 0);
|
|
900
|
+
},
|
|
901
|
+
type: "button",
|
|
902
|
+
children: "Save"
|
|
903
|
+
}
|
|
904
|
+
)
|
|
905
|
+
] })
|
|
906
|
+
]
|
|
907
|
+
}
|
|
908
|
+
)
|
|
909
|
+
}
|
|
910
|
+
)
|
|
911
|
+
] }) : null,
|
|
912
|
+
additionalActions,
|
|
789
913
|
handlers.onCopy ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
790
914
|
ChatMessageAction,
|
|
791
915
|
{
|
|
@@ -799,41 +923,17 @@ function AgentChatDefaultActions({
|
|
|
799
923
|
}
|
|
800
924
|
|
|
801
925
|
// src/ui/agent-chat-message.tsx
|
|
802
|
-
var
|
|
803
|
-
var
|
|
926
|
+
var React8 = __toESM(require("react"), 1);
|
|
927
|
+
var import_lucide_react5 = require("lucide-react");
|
|
804
928
|
|
|
805
929
|
// src/ui/agent-response-timeline.tsx
|
|
806
|
-
var
|
|
807
|
-
var import_lucide_react3 = require("lucide-react");
|
|
808
|
-
|
|
809
|
-
// src/ui/message-response.tsx
|
|
810
|
-
var React3 = __toESM(require("react"), 1);
|
|
811
|
-
var import_streamdown = require("streamdown");
|
|
812
|
-
|
|
813
|
-
// src/active-content.ts
|
|
814
|
-
var CHAT_MARKDOWN_HARDEN_OPTIONS = Object.freeze({
|
|
815
|
-
allowDataImages: false,
|
|
816
|
-
allowedImagePrefixes: [],
|
|
817
|
-
allowedLinkPrefixes: ["*"],
|
|
818
|
-
allowedProtocols: [],
|
|
819
|
-
defaultOrigin: void 0,
|
|
820
|
-
imageBlockPolicy: "text-only",
|
|
821
|
-
linkBlockPolicy: "text-only"
|
|
822
|
-
});
|
|
823
|
-
function safeChatMarkdownHref(value) {
|
|
824
|
-
if (!value) return void 0;
|
|
825
|
-
if (value.startsWith("#")) return value;
|
|
826
|
-
try {
|
|
827
|
-
const url = new URL(value);
|
|
828
|
-
return url.protocol === "https:" || url.protocol === "http:" ? url.href : void 0;
|
|
829
|
-
} catch {
|
|
830
|
-
return void 0;
|
|
831
|
-
}
|
|
832
|
-
}
|
|
930
|
+
var React7 = __toESM(require("react"), 1);
|
|
833
931
|
|
|
834
932
|
// src/streaming-text.ts
|
|
835
933
|
var import_react = require("react");
|
|
836
934
|
var DEFAULT_COMPLETED_TEXT_CACHE_SIZE = 200;
|
|
935
|
+
var STREAM_RUNWAY_MS = 80;
|
|
936
|
+
var STREAM_IDLE_RELEASE_MS = 120;
|
|
837
937
|
var defaultCompletedTextCache = /* @__PURE__ */ new Map();
|
|
838
938
|
var defaultStreamingTextCache = {
|
|
839
939
|
get: (id) => defaultCompletedTextCache.get(id),
|
|
@@ -845,6 +945,36 @@ var defaultStreamingTextCache = {
|
|
|
845
945
|
}
|
|
846
946
|
}
|
|
847
947
|
};
|
|
948
|
+
var getActiveStreamingTextPartId = (message, streamingMessageId) => {
|
|
949
|
+
if (message.role !== "assistant" || streamingMessageId !== message.id) return null;
|
|
950
|
+
const trailingPart = message.parts[message.parts.length - 1];
|
|
951
|
+
return trailingPart?.kind === "text" ? trailingPart.id : null;
|
|
952
|
+
};
|
|
953
|
+
var graphemeEndOffsets = (value) => {
|
|
954
|
+
if (!value) return [];
|
|
955
|
+
if (typeof Intl !== "undefined" && "Segmenter" in Intl) {
|
|
956
|
+
const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
957
|
+
return Array.from(segmenter.segment(value), ({ index, segment }) => index + segment.length);
|
|
958
|
+
}
|
|
959
|
+
const characters = Array.from(value);
|
|
960
|
+
const offsets = [];
|
|
961
|
+
let offset = 0;
|
|
962
|
+
let regionalIndicators = 0;
|
|
963
|
+
characters.forEach((character, index) => {
|
|
964
|
+
const previous = characters[index - 1];
|
|
965
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
966
|
+
const isRegionalIndicator = codePoint >= 127462 && codePoint <= 127487;
|
|
967
|
+
const continuesCluster = index > 0 && (/^\p{Mark}$/u.test(character) || codePoint >= 65024 && codePoint <= 65039 || codePoint >= 127995 && codePoint <= 127999 || character === "\u200D" || previous === "\u200D" || isRegionalIndicator && regionalIndicators % 2 === 1);
|
|
968
|
+
if (!continuesCluster) {
|
|
969
|
+
if (offset > 0) offsets.push(offset);
|
|
970
|
+
regionalIndicators = 0;
|
|
971
|
+
}
|
|
972
|
+
offset += character.length;
|
|
973
|
+
regionalIndicators = isRegionalIndicator ? regionalIndicators + 1 : 0;
|
|
974
|
+
});
|
|
975
|
+
offsets.push(offset);
|
|
976
|
+
return offsets;
|
|
977
|
+
};
|
|
848
978
|
function useStreamingText({
|
|
849
979
|
id,
|
|
850
980
|
isStreaming,
|
|
@@ -863,85 +993,104 @@ function useStreamingText({
|
|
|
863
993
|
const displayedRef = (0, import_react.useRef)(displayedText);
|
|
864
994
|
const rafRef = (0, import_react.useRef)(null);
|
|
865
995
|
const lastFrameAtRef = (0, import_react.useRef)(null);
|
|
996
|
+
const targetUpdatedAtRef = (0, import_react.useRef)(null);
|
|
997
|
+
const progressRemainderRef = (0, import_react.useRef)(0);
|
|
866
998
|
const idRef = (0, import_react.useRef)(id);
|
|
867
|
-
const
|
|
999
|
+
const streamingRef = (0, import_react.useRef)(isStreaming);
|
|
1000
|
+
const reduceMotionRef = (0, import_react.useRef)(false);
|
|
868
1001
|
(0, import_react.useEffect)(() => {
|
|
869
1002
|
if (isStreaming || !text) return;
|
|
870
1003
|
cacheAdapter?.set(id, text);
|
|
871
1004
|
}, [cacheAdapter, id, isStreaming, text]);
|
|
872
1005
|
(0, import_react.useEffect)(() => {
|
|
873
1006
|
targetRef.current = text;
|
|
874
|
-
|
|
1007
|
+
targetUpdatedAtRef.current = typeof performance === "undefined" ? null : performance.now();
|
|
1008
|
+
if (!isStreaming || reduceMotionRef.current || !text.startsWith(displayedRef.current)) {
|
|
1009
|
+
displayedRef.current = text;
|
|
1010
|
+
setDisplayedText(text);
|
|
1011
|
+
progressRemainderRef.current = 0;
|
|
1012
|
+
}
|
|
1013
|
+
}, [isStreaming, text]);
|
|
875
1014
|
(0, import_react.useEffect)(() => {
|
|
876
1015
|
if (idRef.current === id) return;
|
|
877
1016
|
idRef.current = id;
|
|
878
1017
|
const cachedText = cacheAdapter?.get(id);
|
|
879
1018
|
const initial = cachedText && text.startsWith(cachedText) ? cachedText : text;
|
|
880
|
-
shouldAnimateRef.current = isStreaming && initial !== text;
|
|
881
1019
|
displayedRef.current = initial;
|
|
882
1020
|
setDisplayedText(initial);
|
|
883
|
-
if (rafRef.current !== null) {
|
|
884
|
-
cancelAnimationFrame(rafRef.current);
|
|
885
|
-
rafRef.current = null;
|
|
886
|
-
}
|
|
887
1021
|
lastFrameAtRef.current = null;
|
|
1022
|
+
targetUpdatedAtRef.current = typeof performance === "undefined" ? null : performance.now();
|
|
1023
|
+
progressRemainderRef.current = 0;
|
|
888
1024
|
}, [cacheAdapter, id, isStreaming, text]);
|
|
889
1025
|
(0, import_react.useEffect)(() => {
|
|
1026
|
+
streamingRef.current = isStreaming;
|
|
890
1027
|
if (typeof window === "undefined") {
|
|
891
1028
|
displayedRef.current = text;
|
|
892
1029
|
setDisplayedText(text);
|
|
893
1030
|
return;
|
|
894
1031
|
}
|
|
895
|
-
const
|
|
896
|
-
|
|
1032
|
+
const reduceMotion2 = typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1033
|
+
reduceMotionRef.current = reduceMotion2;
|
|
1034
|
+
if (reduceMotion2 || !isStreaming) {
|
|
897
1035
|
displayedRef.current = text;
|
|
898
1036
|
setDisplayedText(text);
|
|
899
|
-
shouldAnimateRef.current = false;
|
|
900
1037
|
return;
|
|
901
1038
|
}
|
|
902
1039
|
const cachedText = cacheAdapter?.get(id);
|
|
903
1040
|
if (cachedText === text) {
|
|
904
1041
|
displayedRef.current = text;
|
|
905
1042
|
setDisplayedText(text);
|
|
906
|
-
shouldAnimateRef.current = false;
|
|
907
1043
|
return;
|
|
908
1044
|
}
|
|
909
|
-
if (
|
|
910
|
-
shouldAnimateRef.current = true;
|
|
911
|
-
}
|
|
912
|
-
if (!shouldAnimateRef.current) {
|
|
1045
|
+
if (!text.startsWith(displayedRef.current)) {
|
|
913
1046
|
displayedRef.current = text;
|
|
914
1047
|
setDisplayedText(text);
|
|
915
|
-
return;
|
|
916
|
-
}
|
|
917
|
-
if (!text.startsWith(displayedRef.current)) {
|
|
918
|
-
displayedRef.current = "";
|
|
919
|
-
setDisplayedText("");
|
|
920
1048
|
}
|
|
921
1049
|
const tick = (timestamp) => {
|
|
922
1050
|
const previousTimestamp = lastFrameAtRef.current ?? timestamp;
|
|
923
1051
|
lastFrameAtRef.current = timestamp;
|
|
924
1052
|
const target = targetRef.current;
|
|
925
1053
|
const current = displayedRef.current;
|
|
926
|
-
if (current
|
|
927
|
-
|
|
1054
|
+
if (!streamingRef.current || reduceMotionRef.current) {
|
|
1055
|
+
displayedRef.current = target;
|
|
1056
|
+
setDisplayedText(target);
|
|
928
1057
|
rafRef.current = null;
|
|
929
1058
|
return;
|
|
930
1059
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1060
|
+
if (!target.startsWith(current)) {
|
|
1061
|
+
displayedRef.current = target;
|
|
1062
|
+
setDisplayedText(target);
|
|
1063
|
+
progressRemainderRef.current = 0;
|
|
1064
|
+
rafRef.current = window.requestAnimationFrame(tick);
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
const pending = target.slice(current.length);
|
|
1068
|
+
const pendingOffsets = graphemeEndOffsets(pending);
|
|
1069
|
+
if (pendingOffsets.length === 0) {
|
|
1070
|
+
rafRef.current = window.requestAnimationFrame(tick);
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
const elapsedMs = Math.max(0, timestamp - previousTimestamp);
|
|
1074
|
+
const targetIdleMs = targetUpdatedAtRef.current === null ? STREAM_IDLE_RELEASE_MS : Math.max(0, timestamp - targetUpdatedAtRef.current);
|
|
1075
|
+
const runway = targetIdleMs >= STREAM_IDLE_RELEASE_MS ? 0 : Math.min(
|
|
1076
|
+
pendingOffsets.length - 1,
|
|
1077
|
+
Math.max(1, Math.ceil(charsPerSecond * STREAM_RUNWAY_MS / 1e3))
|
|
938
1078
|
);
|
|
939
|
-
const
|
|
940
|
-
|
|
941
|
-
|
|
1079
|
+
const eligibleGraphemes = pendingOffsets.length - runway;
|
|
1080
|
+
progressRemainderRef.current += elapsedMs / 1e3 * charsPerSecond;
|
|
1081
|
+
let step = Math.floor(progressRemainderRef.current);
|
|
1082
|
+
if (current.length === 0 && eligibleGraphemes > 0) step = Math.max(1, step);
|
|
1083
|
+
const catchupStep = pendingOffsets.length > catchupThreshold ? Math.min(maxCatchupChars, Math.ceil(pendingOffsets.length / 10)) : 0;
|
|
1084
|
+
step = Math.min(eligibleGraphemes, Math.max(step, catchupStep));
|
|
1085
|
+
if (step > 0) {
|
|
1086
|
+
progressRemainderRef.current = Math.max(0, progressRemainderRef.current - step);
|
|
1087
|
+
const next = current + pending.slice(0, pendingOffsets[step - 1]);
|
|
1088
|
+
displayedRef.current = next;
|
|
1089
|
+
setDisplayedText(next);
|
|
1090
|
+
}
|
|
942
1091
|
rafRef.current = window.requestAnimationFrame(tick);
|
|
943
1092
|
};
|
|
944
|
-
if (rafRef.current === null
|
|
1093
|
+
if (rafRef.current === null) {
|
|
945
1094
|
rafRef.current = window.requestAnimationFrame(tick);
|
|
946
1095
|
}
|
|
947
1096
|
return () => {
|
|
@@ -950,28 +1099,417 @@ function useStreamingText({
|
|
|
950
1099
|
rafRef.current = null;
|
|
951
1100
|
}
|
|
952
1101
|
lastFrameAtRef.current = null;
|
|
1102
|
+
progressRemainderRef.current = 0;
|
|
953
1103
|
};
|
|
954
|
-
}, [cacheAdapter, catchupThreshold, charsPerSecond, id, isStreaming, maxCatchupChars
|
|
1104
|
+
}, [cacheAdapter, catchupThreshold, charsPerSecond, id, isStreaming, maxCatchupChars]);
|
|
1105
|
+
const reduceMotion = typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
955
1106
|
return {
|
|
956
|
-
displayedText,
|
|
1107
|
+
displayedText: !isStreaming || reduceMotion ? text : displayedText,
|
|
957
1108
|
isAnimating: isStreaming,
|
|
958
1109
|
mode: isStreaming ? "streaming" : "static",
|
|
959
1110
|
parseIncompleteMarkdown: isStreaming
|
|
960
1111
|
};
|
|
961
1112
|
}
|
|
962
1113
|
|
|
963
|
-
// src/ui/
|
|
1114
|
+
// src/ui/ask-user-interaction.tsx
|
|
1115
|
+
var React4 = __toESM(require("react"), 1);
|
|
1116
|
+
var import_lucide_react3 = require("lucide-react");
|
|
1117
|
+
|
|
1118
|
+
// src/ui/ask-user-interaction-state.ts
|
|
1119
|
+
function emptyAskUserDrafts(questions) {
|
|
1120
|
+
return Object.fromEntries(
|
|
1121
|
+
questions.map((question) => [
|
|
1122
|
+
question.id,
|
|
1123
|
+
{ customText: "", selectedOptionIds: [] }
|
|
1124
|
+
])
|
|
1125
|
+
);
|
|
1126
|
+
}
|
|
1127
|
+
function askUserDraftHasAnswer(draft) {
|
|
1128
|
+
return Boolean(
|
|
1129
|
+
draft && (draft.selectedOptionIds.length > 0 || draft.customText.trim().length > 0)
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
function selectAskUserOption({
|
|
1133
|
+
draft,
|
|
1134
|
+
drafts,
|
|
1135
|
+
optionId,
|
|
1136
|
+
question
|
|
1137
|
+
}) {
|
|
1138
|
+
const selectedOptionIds = question.multiSelect ? draft.selectedOptionIds.includes(optionId) ? draft.selectedOptionIds.filter((id) => id !== optionId) : [...draft.selectedOptionIds, optionId] : [optionId];
|
|
1139
|
+
return {
|
|
1140
|
+
...drafts,
|
|
1141
|
+
[question.id]: {
|
|
1142
|
+
customText: "",
|
|
1143
|
+
selectedOptionIds
|
|
1144
|
+
}
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
function updateAskUserCustomText({
|
|
1148
|
+
customText,
|
|
1149
|
+
drafts,
|
|
1150
|
+
question
|
|
1151
|
+
}) {
|
|
1152
|
+
return {
|
|
1153
|
+
...drafts,
|
|
1154
|
+
[question.id]: {
|
|
1155
|
+
customText,
|
|
1156
|
+
selectedOptionIds: question.multiSelect ? drafts[question.id]?.selectedOptionIds || [] : []
|
|
1157
|
+
}
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
function askUserAnswersFromDrafts(questions, drafts) {
|
|
1161
|
+
return questions.map((question) => {
|
|
1162
|
+
const answer = drafts[question.id];
|
|
1163
|
+
return {
|
|
1164
|
+
questionId: question.id,
|
|
1165
|
+
selectedOptionIds: answer?.selectedOptionIds || [],
|
|
1166
|
+
...answer?.customText.trim() ? { customText: answer.customText.trim() } : {}
|
|
1167
|
+
};
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// src/ui/ask-user-interaction.tsx
|
|
964
1172
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1173
|
+
function resolvedAnswerText(question, answer) {
|
|
1174
|
+
if (!answer) return ["No response recorded"];
|
|
1175
|
+
const labels = answer.selectedOptionIds.flatMap((optionId) => {
|
|
1176
|
+
const option = question.options.find((item) => item.id === optionId);
|
|
1177
|
+
return option ? [option.label] : [];
|
|
1178
|
+
});
|
|
1179
|
+
if (answer.customText) labels.push(answer.customText);
|
|
1180
|
+
return labels.length ? labels : ["No response recorded"];
|
|
1181
|
+
}
|
|
1182
|
+
function ResolvedQuestions({
|
|
1183
|
+
buttonRef,
|
|
1184
|
+
part
|
|
1185
|
+
}) {
|
|
1186
|
+
const [open, setOpen] = React4.useState(false);
|
|
1187
|
+
const count = part.questions.length;
|
|
1188
|
+
const answers = new Map(
|
|
1189
|
+
(part.resolution?.answers || []).map((answer) => [
|
|
1190
|
+
answer.questionId,
|
|
1191
|
+
answer
|
|
1192
|
+
])
|
|
1193
|
+
);
|
|
1194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "a24-ask-user a24-ask-user--resolved w-full", children: [
|
|
1195
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1196
|
+
"button",
|
|
1197
|
+
{
|
|
1198
|
+
"aria-expanded": open,
|
|
1199
|
+
className: "group flex min-w-0 items-center gap-1.5 rounded-md px-0 py-0.5 text-start text-sm text-muted-foreground transition-colors hover:text-foreground motion-reduce:transition-none",
|
|
1200
|
+
onClick: () => setOpen((value) => !value),
|
|
1201
|
+
ref: buttonRef,
|
|
1202
|
+
type: "button",
|
|
1203
|
+
children: [
|
|
1204
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
|
|
1205
|
+
"Asked ",
|
|
1206
|
+
count,
|
|
1207
|
+
" question",
|
|
1208
|
+
count === 1 ? "" : "s"
|
|
1209
|
+
] }),
|
|
1210
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react3.ChevronDown, { "aria-hidden": "true", className: "size-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1211
|
+
import_lucide_react3.ChevronRight,
|
|
1212
|
+
{
|
|
1213
|
+
"aria-hidden": "true",
|
|
1214
|
+
className: "size-3.5 opacity-70 rtl:rotate-180"
|
|
1215
|
+
}
|
|
1216
|
+
)
|
|
1217
|
+
]
|
|
1218
|
+
}
|
|
1219
|
+
),
|
|
1220
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "mt-2 space-y-3 ps-4", children: part.questions.map((question) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "min-w-0", children: [
|
|
1221
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "text-sm font-medium text-foreground", children: question.question }),
|
|
1222
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "mt-1 space-y-1 text-sm text-muted-foreground", children: resolvedAnswerText(
|
|
1223
|
+
question,
|
|
1224
|
+
answers.get(question.id)
|
|
1225
|
+
).map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1226
|
+
"div",
|
|
1227
|
+
{
|
|
1228
|
+
className: "whitespace-pre-wrap break-words",
|
|
1229
|
+
children: value
|
|
1230
|
+
},
|
|
1231
|
+
`${question.id}:${index}`
|
|
1232
|
+
)) })
|
|
1233
|
+
] }, question.id)) }) : null
|
|
1234
|
+
] });
|
|
1235
|
+
}
|
|
1236
|
+
function AskUserInteraction({
|
|
1237
|
+
error,
|
|
1238
|
+
isBusy = false,
|
|
1239
|
+
onSubmit,
|
|
1240
|
+
part
|
|
1241
|
+
}) {
|
|
1242
|
+
const questions = part.questions;
|
|
1243
|
+
const [step, setStep] = React4.useState(0);
|
|
1244
|
+
const [drafts, setDrafts] = React4.useState(
|
|
1245
|
+
() => emptyAskUserDrafts(questions)
|
|
1246
|
+
);
|
|
1247
|
+
const headingRef = React4.useRef(null);
|
|
1248
|
+
const questionsRef = React4.useRef(questions);
|
|
1249
|
+
const resolvedButtonRef = React4.useRef(null);
|
|
1250
|
+
const wasResolvedRef = React4.useRef(part.status !== "pending");
|
|
1251
|
+
questionsRef.current = questions;
|
|
1252
|
+
React4.useEffect(() => {
|
|
1253
|
+
setStep(0);
|
|
1254
|
+
setDrafts(emptyAskUserDrafts(questionsRef.current));
|
|
1255
|
+
}, [part.interruptId]);
|
|
1256
|
+
React4.useEffect(() => {
|
|
1257
|
+
headingRef.current?.focus();
|
|
1258
|
+
}, [step]);
|
|
1259
|
+
React4.useEffect(() => {
|
|
1260
|
+
const isResolved = part.status !== "pending";
|
|
1261
|
+
if (isResolved && !wasResolvedRef.current) {
|
|
1262
|
+
resolvedButtonRef.current?.focus();
|
|
1263
|
+
}
|
|
1264
|
+
wasResolvedRef.current = isResolved;
|
|
1265
|
+
}, [part.status]);
|
|
1266
|
+
if (part.status !== "pending") {
|
|
1267
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ResolvedQuestions, { buttonRef: resolvedButtonRef, part });
|
|
1268
|
+
}
|
|
1269
|
+
const question = questions[step];
|
|
1270
|
+
if (!question) {
|
|
1271
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "text-sm text-destructive", role: "alert", children: "This question request is unavailable." });
|
|
1272
|
+
}
|
|
1273
|
+
const draft = drafts[question.id] || {
|
|
1274
|
+
customText: "",
|
|
1275
|
+
selectedOptionIds: []
|
|
1276
|
+
};
|
|
1277
|
+
const isLastQuestion = step === questions.length - 1;
|
|
1278
|
+
const canMoveForward = askUserDraftHasAnswer(draft);
|
|
1279
|
+
const completeStep = (nextDrafts) => {
|
|
1280
|
+
if (isLastQuestion) {
|
|
1281
|
+
onSubmit?.(askUserAnswersFromDrafts(questions, nextDrafts));
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
setStep((current) => Math.min(current + 1, questions.length - 1));
|
|
1285
|
+
};
|
|
1286
|
+
const selectOption = (optionId) => {
|
|
1287
|
+
const nextDrafts = selectAskUserOption({
|
|
1288
|
+
draft,
|
|
1289
|
+
drafts,
|
|
1290
|
+
optionId,
|
|
1291
|
+
question
|
|
1292
|
+
});
|
|
1293
|
+
setDrafts(nextDrafts);
|
|
1294
|
+
if (!question.multiSelect) completeStep(nextDrafts);
|
|
1295
|
+
};
|
|
1296
|
+
const updateCustomText = (customText) => {
|
|
1297
|
+
setDrafts(
|
|
1298
|
+
(current) => updateAskUserCustomText({
|
|
1299
|
+
customText,
|
|
1300
|
+
drafts: current,
|
|
1301
|
+
question
|
|
1302
|
+
})
|
|
1303
|
+
);
|
|
1304
|
+
};
|
|
1305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "a24-ask-user space-y-3 rounded-xl border border-border/50 bg-background p-4 shadow-sm", children: [
|
|
1306
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex min-w-0 items-start justify-between gap-4", children: [
|
|
1307
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1308
|
+
"h3",
|
|
1309
|
+
{
|
|
1310
|
+
className: "min-w-0 flex-1 text-base font-medium leading-6 text-foreground outline-none",
|
|
1311
|
+
ref: headingRef,
|
|
1312
|
+
tabIndex: -1,
|
|
1313
|
+
children: question.question
|
|
1314
|
+
}
|
|
1315
|
+
),
|
|
1316
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex shrink-0 items-center gap-1 text-muted-foreground", children: [
|
|
1317
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1318
|
+
"button",
|
|
1319
|
+
{
|
|
1320
|
+
"aria-label": "Previous question",
|
|
1321
|
+
className: "flex size-8 items-center justify-center rounded-full transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-30",
|
|
1322
|
+
disabled: isBusy || step === 0,
|
|
1323
|
+
onClick: () => setStep((current) => Math.max(0, current - 1)),
|
|
1324
|
+
type: "button",
|
|
1325
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1326
|
+
import_lucide_react3.ChevronLeft,
|
|
1327
|
+
{
|
|
1328
|
+
"aria-hidden": "true",
|
|
1329
|
+
className: "size-4 rtl:rotate-180"
|
|
1330
|
+
}
|
|
1331
|
+
)
|
|
1332
|
+
}
|
|
1333
|
+
),
|
|
1334
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1335
|
+
"span",
|
|
1336
|
+
{
|
|
1337
|
+
"aria-label": `Question ${step + 1} of ${questions.length}`,
|
|
1338
|
+
className: "min-w-12 text-center text-sm tabular-nums",
|
|
1339
|
+
children: [
|
|
1340
|
+
step + 1,
|
|
1341
|
+
" / ",
|
|
1342
|
+
questions.length
|
|
1343
|
+
]
|
|
1344
|
+
}
|
|
1345
|
+
),
|
|
1346
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1347
|
+
"button",
|
|
1348
|
+
{
|
|
1349
|
+
"aria-label": isLastQuestion ? "Submit answers" : "Next question",
|
|
1350
|
+
className: "flex size-8 items-center justify-center rounded-full transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-30",
|
|
1351
|
+
disabled: isBusy || !onSubmit || !canMoveForward,
|
|
1352
|
+
onClick: () => completeStep(drafts),
|
|
1353
|
+
type: "button",
|
|
1354
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1355
|
+
import_lucide_react3.ChevronRight,
|
|
1356
|
+
{
|
|
1357
|
+
"aria-hidden": "true",
|
|
1358
|
+
className: "size-4 rtl:rotate-180"
|
|
1359
|
+
}
|
|
1360
|
+
)
|
|
1361
|
+
}
|
|
1362
|
+
)
|
|
1363
|
+
] })
|
|
1364
|
+
] }),
|
|
1365
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "space-y-1", children: [
|
|
1366
|
+
question.options.map((option, index) => {
|
|
1367
|
+
const selected = draft.selectedOptionIds.includes(option.id);
|
|
1368
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1369
|
+
"button",
|
|
1370
|
+
{
|
|
1371
|
+
"aria-pressed": selected,
|
|
1372
|
+
className: cn(
|
|
1373
|
+
"group flex min-h-11 w-full items-center gap-3 rounded-xl px-2.5 py-2 text-start text-sm transition-colors motion-reduce:transition-none",
|
|
1374
|
+
selected ? "bg-muted" : "hover:bg-muted/70"
|
|
1375
|
+
),
|
|
1376
|
+
disabled: isBusy || !onSubmit,
|
|
1377
|
+
onClick: () => selectOption(option.id),
|
|
1378
|
+
type: "button",
|
|
1379
|
+
children: [
|
|
1380
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1381
|
+
"span",
|
|
1382
|
+
{
|
|
1383
|
+
className: cn(
|
|
1384
|
+
"flex size-8 shrink-0 items-center justify-center rounded-full border text-sm tabular-nums transition-colors",
|
|
1385
|
+
selected ? "border-border bg-background text-foreground" : "border-border/70 bg-muted/60 text-muted-foreground"
|
|
1386
|
+
),
|
|
1387
|
+
children: index + 1
|
|
1388
|
+
}
|
|
1389
|
+
),
|
|
1390
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "min-w-0 flex-1 font-medium text-foreground", children: option.label }),
|
|
1391
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1392
|
+
import_lucide_react3.ChevronRight,
|
|
1393
|
+
{
|
|
1394
|
+
"aria-hidden": "true",
|
|
1395
|
+
className: "size-4 shrink-0 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100 group-focus-visible:opacity-100 rtl:rotate-180"
|
|
1396
|
+
}
|
|
1397
|
+
)
|
|
1398
|
+
]
|
|
1399
|
+
},
|
|
1400
|
+
option.id
|
|
1401
|
+
);
|
|
1402
|
+
}),
|
|
1403
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex min-h-11 items-center gap-2 rounded-xl bg-muted px-2.5 py-1.5 focus-within:ring-1 focus-within:ring-ring", children: [
|
|
1404
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-full border border-border/70 bg-background/70 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react3.Pencil, { "aria-hidden": "true", className: "size-4" }) }),
|
|
1405
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1406
|
+
"input",
|
|
1407
|
+
{
|
|
1408
|
+
"aria-label": "Other response",
|
|
1409
|
+
autoComplete: "off",
|
|
1410
|
+
className: "h-8 min-w-0 flex-1 bg-transparent px-1 text-sm text-foreground outline-none placeholder:text-muted-foreground",
|
|
1411
|
+
disabled: isBusy || !onSubmit,
|
|
1412
|
+
maxLength: 2e3,
|
|
1413
|
+
onChange: (event) => updateCustomText(event.target.value),
|
|
1414
|
+
onKeyDown: (event) => {
|
|
1415
|
+
if (event.key === "Enter" && !event.nativeEvent.isComposing && draft.customText.trim()) {
|
|
1416
|
+
event.preventDefault();
|
|
1417
|
+
completeStep(drafts);
|
|
1418
|
+
}
|
|
1419
|
+
},
|
|
1420
|
+
placeholder: "Other\u2026",
|
|
1421
|
+
value: draft.customText
|
|
1422
|
+
}
|
|
1423
|
+
),
|
|
1424
|
+
draft.customText.trim() ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1425
|
+
"button",
|
|
1426
|
+
{
|
|
1427
|
+
className: "h-8 shrink-0 rounded-full bg-foreground px-4 text-sm font-medium text-background transition-colors hover:opacity-85 disabled:opacity-50",
|
|
1428
|
+
disabled: isBusy || !onSubmit,
|
|
1429
|
+
onClick: () => completeStep(drafts),
|
|
1430
|
+
type: "button",
|
|
1431
|
+
children: isLastQuestion ? "Submit" : "Next"
|
|
1432
|
+
}
|
|
1433
|
+
) : null
|
|
1434
|
+
] })
|
|
1435
|
+
] }),
|
|
1436
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "text-sm text-destructive", role: "alert", children: error }) : null
|
|
1437
|
+
] });
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
// src/ui/agent-chat-context-compression-row.tsx
|
|
1441
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1442
|
+
function compressionPresentation(part) {
|
|
1443
|
+
if (part.status === "failed") {
|
|
1444
|
+
return { label: "Could not compact message history", status: "failed" };
|
|
1445
|
+
}
|
|
1446
|
+
if (part.status === "completed") {
|
|
1447
|
+
return { label: "Compacted message history", status: "completed" };
|
|
1448
|
+
}
|
|
1449
|
+
return { label: "Compacting message history", status: "running" };
|
|
1450
|
+
}
|
|
1451
|
+
function AgentChatContextCompressionRow({
|
|
1452
|
+
className,
|
|
1453
|
+
part
|
|
1454
|
+
}) {
|
|
1455
|
+
const presentation = compressionPresentation(part);
|
|
1456
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1457
|
+
"div",
|
|
1458
|
+
{
|
|
1459
|
+
"aria-live": "polite",
|
|
1460
|
+
className: cn("a24-context-compression-row", className),
|
|
1461
|
+
"data-agents24-context-compression": "",
|
|
1462
|
+
"data-status": part.status,
|
|
1463
|
+
role: "status",
|
|
1464
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: cn(
|
|
1465
|
+
"a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--without-orb",
|
|
1466
|
+
presentation.status === "failed" && "a24-tool-trigger--error",
|
|
1467
|
+
presentation.status === "running" && "a24-tool-trigger--active"
|
|
1468
|
+
), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: cn(
|
|
1469
|
+
"a24-tool-trigger__label",
|
|
1470
|
+
presentation.status === "running" && "a24-tool-shimmer"
|
|
1471
|
+
), children: presentation.label }) }) })
|
|
1472
|
+
}
|
|
1473
|
+
);
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
// src/ui/message-response.tsx
|
|
1477
|
+
var React5 = __toESM(require("react"), 1);
|
|
1478
|
+
var import_streamdown = require("streamdown");
|
|
1479
|
+
|
|
1480
|
+
// src/active-content.ts
|
|
1481
|
+
var CHAT_MARKDOWN_HARDEN_OPTIONS = Object.freeze({
|
|
1482
|
+
allowDataImages: false,
|
|
1483
|
+
allowedImagePrefixes: [],
|
|
1484
|
+
allowedLinkPrefixes: ["*"],
|
|
1485
|
+
allowedProtocols: [],
|
|
1486
|
+
defaultOrigin: void 0,
|
|
1487
|
+
imageBlockPolicy: "text-only",
|
|
1488
|
+
linkBlockPolicy: "text-only"
|
|
1489
|
+
});
|
|
1490
|
+
function safeChatMarkdownHref(value) {
|
|
1491
|
+
if (!value) return void 0;
|
|
1492
|
+
if (value.startsWith("#")) return value;
|
|
1493
|
+
try {
|
|
1494
|
+
const url = new URL(value);
|
|
1495
|
+
return url.protocol === "https:" || url.protocol === "http:" ? url.href : void 0;
|
|
1496
|
+
} catch {
|
|
1497
|
+
return void 0;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
// src/ui/message-response.tsx
|
|
1502
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
965
1503
|
function SafeMarkdownLink({ children, href, ...props }) {
|
|
966
1504
|
const domProps = { ...props };
|
|
967
1505
|
delete domProps.node;
|
|
968
1506
|
const safeHref = safeChatMarkdownHref(href);
|
|
969
|
-
if (!safeHref) return /* @__PURE__ */ (0,
|
|
970
|
-
if (safeHref.startsWith("#")) return /* @__PURE__ */ (0,
|
|
971
|
-
return /* @__PURE__ */ (0,
|
|
1507
|
+
if (!safeHref) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children });
|
|
1508
|
+
if (safeHref.startsWith("#")) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("a", { ...domProps, href: safeHref, children });
|
|
1509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("a", { ...domProps, href: safeHref, rel: "noopener noreferrer", target: "_blank", children });
|
|
972
1510
|
}
|
|
973
1511
|
function BlockedMarkdownImage({ alt }) {
|
|
974
|
-
return alt ? /* @__PURE__ */ (0,
|
|
1512
|
+
return alt ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-label": `Image blocked: ${alt}`, role: "img", children: alt }) : null;
|
|
975
1513
|
}
|
|
976
1514
|
var BLOCK_MARKDOWN_TAGS = /* @__PURE__ */ new Set([
|
|
977
1515
|
"blockquote",
|
|
@@ -992,7 +1530,7 @@ function isMultilineCodeNode(node) {
|
|
|
992
1530
|
return node?.tagName === "code" && node.position?.start?.line !== void 0 && node.position?.end?.line !== void 0 && node.position.start.line !== node.position.end.line;
|
|
993
1531
|
}
|
|
994
1532
|
function hasBlockMarkdownChild(child) {
|
|
995
|
-
if (!
|
|
1533
|
+
if (!React5.isValidElement(child)) {
|
|
996
1534
|
return false;
|
|
997
1535
|
}
|
|
998
1536
|
if (typeof child.type === "string" && BLOCK_MARKDOWN_TAGS.has(child.type)) {
|
|
@@ -1002,7 +1540,7 @@ function hasBlockMarkdownChild(child) {
|
|
|
1002
1540
|
if (BLOCK_MARKDOWN_TAGS.has(props.node?.tagName || "") || isMultilineCodeNode(props.node)) {
|
|
1003
1541
|
return true;
|
|
1004
1542
|
}
|
|
1005
|
-
return
|
|
1543
|
+
return React5.Children.toArray(props.children).some(hasBlockMarkdownChild);
|
|
1006
1544
|
}
|
|
1007
1545
|
function MessageMarkdownParagraph({
|
|
1008
1546
|
children,
|
|
@@ -1010,17 +1548,17 @@ function MessageMarkdownParagraph({
|
|
|
1010
1548
|
}) {
|
|
1011
1549
|
const domProps = { ...props };
|
|
1012
1550
|
delete domProps.node;
|
|
1013
|
-
const childArray =
|
|
1551
|
+
const childArray = React5.Children.toArray(children).filter(
|
|
1014
1552
|
(child) => child !== null && child !== ""
|
|
1015
1553
|
);
|
|
1016
|
-
const isImageOnly = childArray.length === 1 &&
|
|
1554
|
+
const isImageOnly = childArray.length === 1 && React5.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
|
|
1017
1555
|
if (isImageOnly) {
|
|
1018
|
-
return /* @__PURE__ */ (0,
|
|
1556
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children });
|
|
1019
1557
|
}
|
|
1020
1558
|
if (childArray.some(hasBlockMarkdownChild)) {
|
|
1021
|
-
return /* @__PURE__ */ (0,
|
|
1559
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ...domProps, children });
|
|
1022
1560
|
}
|
|
1023
|
-
return /* @__PURE__ */ (0,
|
|
1561
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { ...domProps, children });
|
|
1024
1562
|
}
|
|
1025
1563
|
var MESSAGE_RESPONSE_COMPONENTS = {
|
|
1026
1564
|
a: SafeMarkdownLink,
|
|
@@ -1040,7 +1578,7 @@ var MESSAGE_RESPONSE_REHYPE_PLUGINS = [
|
|
|
1040
1578
|
]
|
|
1041
1579
|
] : []
|
|
1042
1580
|
];
|
|
1043
|
-
var MessageResponse =
|
|
1581
|
+
var MessageResponse = React5.memo(
|
|
1044
1582
|
({
|
|
1045
1583
|
children,
|
|
1046
1584
|
className,
|
|
@@ -1058,11 +1596,11 @@ var MessageResponse = React3.memo(
|
|
|
1058
1596
|
maxCatchupChars: 32,
|
|
1059
1597
|
text
|
|
1060
1598
|
});
|
|
1061
|
-
const streamdownComponents =
|
|
1599
|
+
const streamdownComponents = React5.useMemo(
|
|
1062
1600
|
() => ({ ...MESSAGE_RESPONSE_COMPONENTS, ...components }),
|
|
1063
1601
|
[components]
|
|
1064
1602
|
);
|
|
1065
|
-
return /* @__PURE__ */ (0,
|
|
1603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1066
1604
|
import_streamdown.Streamdown,
|
|
1067
1605
|
{
|
|
1068
1606
|
className: cn("a24-message-response", className),
|
|
@@ -1085,6 +1623,7 @@ function hitlActionLabel(part, action) {
|
|
|
1085
1623
|
if (action === "approve") return ["tool_review", "app_data_permission"].includes(part.hitlKind) ? "Allow once" : "Approve";
|
|
1086
1624
|
if (action === "reject") return ["tool_review", "app_data_permission"].includes(part.hitlKind) ? "Don\u2019t allow" : "Reject";
|
|
1087
1625
|
if (action === "connect") return "Connect";
|
|
1626
|
+
if (action === "respond") return "Submit";
|
|
1088
1627
|
return "Skip";
|
|
1089
1628
|
}
|
|
1090
1629
|
function hitlTitle(part) {
|
|
@@ -1112,102 +1651,424 @@ function resolvedHitlLabel(part) {
|
|
|
1112
1651
|
}[outcome] || outcome.replace(/_/g, " ");
|
|
1113
1652
|
}
|
|
1114
1653
|
|
|
1115
|
-
// src/ui/
|
|
1116
|
-
var
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
function
|
|
1654
|
+
// src/ui/tool-sessions.tsx
|
|
1655
|
+
var React6 = __toESM(require("react"), 1);
|
|
1656
|
+
var import_lucide_react4 = require("lucide-react");
|
|
1657
|
+
var import_thinking_orbs = require("thinking-orbs");
|
|
1658
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1659
|
+
function agentChatToolLabel(part) {
|
|
1121
1660
|
const presentation = part.presentation || {};
|
|
1122
|
-
|
|
1123
|
-
return optionalString2(presentation[key]) || optionalString2(presentation[snakeKey]);
|
|
1661
|
+
return optionalText(presentation.activity) || optionalText(presentation.title) || optionalText(part.displayName) || optionalText(part.summary) || optionalText(part.toolName) || "Tool activity";
|
|
1124
1662
|
}
|
|
1125
|
-
function
|
|
1126
|
-
|
|
1663
|
+
function isAgentChatSubagent(part) {
|
|
1664
|
+
const sourceKind = String(part.sourceKind || "").trim().toLowerCase();
|
|
1665
|
+
return sourceKind === "agent" || sourceKind === "agent_call" || Boolean(part.presentation.childRun);
|
|
1127
1666
|
}
|
|
1128
|
-
function
|
|
1129
|
-
return
|
|
1667
|
+
function isAgentChatToolRunning(part) {
|
|
1668
|
+
return part.state === "input-available" || part.state === "input-streaming";
|
|
1130
1669
|
}
|
|
1131
|
-
function
|
|
1132
|
-
|
|
1670
|
+
function latestRunningAgentChatToolId(parts) {
|
|
1671
|
+
const active = [...parts].reverse().find(isAgentChatToolRunning);
|
|
1672
|
+
return active?.toolCallId || active?.id || null;
|
|
1133
1673
|
}
|
|
1134
|
-
function
|
|
1135
|
-
|
|
1674
|
+
function partitionAgentChatToolTimeline(parts, toolViewMode = "closed") {
|
|
1675
|
+
const segments = [];
|
|
1676
|
+
let index = 0;
|
|
1677
|
+
while (index < parts.length) {
|
|
1678
|
+
const part = parts[index];
|
|
1679
|
+
const leadingModelTurn = part.kind === "model-turn" && parts[index + 1]?.kind === "tool" && !isAgentChatSubagent(parts[index + 1]) ? part : void 0;
|
|
1680
|
+
if (leadingModelTurn) index += 1;
|
|
1681
|
+
const candidate = parts[index];
|
|
1682
|
+
if (candidate.kind !== "tool") {
|
|
1683
|
+
segments.push({ kind: "part", part: candidate });
|
|
1684
|
+
index += 1;
|
|
1685
|
+
continue;
|
|
1686
|
+
}
|
|
1687
|
+
if (isAgentChatSubagent(candidate)) {
|
|
1688
|
+
segments.push({ kind: "subagent", part: candidate });
|
|
1689
|
+
index += 1;
|
|
1690
|
+
continue;
|
|
1691
|
+
}
|
|
1692
|
+
const streak = [];
|
|
1693
|
+
while (index < parts.length) {
|
|
1694
|
+
const candidate2 = parts[index];
|
|
1695
|
+
if (candidate2.kind !== "tool" || isAgentChatSubagent(candidate2)) break;
|
|
1696
|
+
streak.push(candidate2);
|
|
1697
|
+
index += 1;
|
|
1698
|
+
}
|
|
1699
|
+
const modelTurn = parts[index]?.kind === "model-turn" ? parts[index] : void 0;
|
|
1700
|
+
if (modelTurn) index += 1;
|
|
1701
|
+
if (toolViewMode === "expanded") {
|
|
1702
|
+
if (leadingModelTurn) segments.push({ kind: "part", part: leadingModelTurn });
|
|
1703
|
+
segments.push(...streak.map((toolPart) => ({ kind: "tool", part: toolPart })));
|
|
1704
|
+
if (modelTurn) segments.push({ kind: "part", part: modelTurn });
|
|
1705
|
+
} else if (streak.length === 1 && !modelTurn && !leadingModelTurn) {
|
|
1706
|
+
segments.push({ kind: "tool", part: streak[0] });
|
|
1707
|
+
} else {
|
|
1708
|
+
segments.push({
|
|
1709
|
+
kind: "tool-session",
|
|
1710
|
+
parts: streak,
|
|
1711
|
+
...leadingModelTurn ? { leadingModelTurn } : {},
|
|
1712
|
+
...modelTurn ? { modelTurn } : {}
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
return segments;
|
|
1136
1717
|
}
|
|
1137
|
-
function
|
|
1138
|
-
return
|
|
1718
|
+
function optionalText(value) {
|
|
1719
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
1139
1720
|
}
|
|
1140
|
-
function
|
|
1141
|
-
return
|
|
1721
|
+
function isActive(part, activeToolId) {
|
|
1722
|
+
return Boolean(activeToolId && (part.id === activeToolId || part.toolCallId === activeToolId));
|
|
1142
1723
|
}
|
|
1143
|
-
function
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1724
|
+
function ToolActivityReel({
|
|
1725
|
+
announce = true,
|
|
1726
|
+
initialLabel,
|
|
1727
|
+
initialShownAt,
|
|
1728
|
+
label
|
|
1729
|
+
}) {
|
|
1730
|
+
const initial = initialLabel && initialLabel !== label ? initialLabel : label;
|
|
1731
|
+
const parsedInitialShownAt = initialShownAt ? Date.parse(initialShownAt) : Number.NaN;
|
|
1732
|
+
const [displayed, setDisplayed] = React6.useState(initial);
|
|
1733
|
+
const [previous, setPrevious] = React6.useState(null);
|
|
1734
|
+
const displayedRef = React6.useRef(initial);
|
|
1735
|
+
const latestRef = React6.useRef(label);
|
|
1736
|
+
const shownAtRef = React6.useRef(Number.isFinite(parsedInitialShownAt) ? parsedInitialShownAt : Date.now());
|
|
1737
|
+
React6.useEffect(() => {
|
|
1738
|
+
latestRef.current = label;
|
|
1739
|
+
if (displayedRef.current === label) return;
|
|
1740
|
+
const showLatest = () => {
|
|
1741
|
+
const next = latestRef.current;
|
|
1742
|
+
if (displayedRef.current === next) return;
|
|
1743
|
+
const old = displayedRef.current;
|
|
1744
|
+
displayedRef.current = next;
|
|
1745
|
+
shownAtRef.current = Date.now();
|
|
1746
|
+
setPrevious(old);
|
|
1747
|
+
setDisplayed(next);
|
|
1748
|
+
};
|
|
1749
|
+
const remaining = Math.max(0, 500 - (Date.now() - shownAtRef.current));
|
|
1750
|
+
if (remaining === 0) {
|
|
1751
|
+
showLatest();
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
const timer = window.setTimeout(showLatest, remaining);
|
|
1755
|
+
return () => window.clearTimeout(timer);
|
|
1756
|
+
}, [label]);
|
|
1757
|
+
React6.useEffect(() => {
|
|
1758
|
+
if (!previous) return;
|
|
1759
|
+
const timer = window.setTimeout(() => setPrevious(null), 200);
|
|
1760
|
+
return () => window.clearTimeout(timer);
|
|
1761
|
+
}, [previous]);
|
|
1762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "a24-tool-reel", "aria-live": announce ? "polite" : "off", children: [
|
|
1763
|
+
previous ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-hidden": "true", className: "a24-tool-reel__previous", children: previous }) : null,
|
|
1764
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: previous ? "a24-tool-reel__current" : void 0, children: displayed })
|
|
1765
|
+
] });
|
|
1766
|
+
}
|
|
1767
|
+
function ToolActivityOrb({ label }) {
|
|
1768
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "a24-tool-orb", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_thinking_orbs.ThinkingOrb, { "aria-label": label || "Working", size: 20, speed: 0.8, state: "searching" }) });
|
|
1769
|
+
}
|
|
1770
|
+
function AgentChatActivityRow({
|
|
1148
1771
|
label,
|
|
1149
|
-
|
|
1772
|
+
modelTurnId,
|
|
1773
|
+
onSelect
|
|
1150
1774
|
}) {
|
|
1151
|
-
const
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1775
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1776
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolActivityOrb, { label }),
|
|
1777
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "a24-tool-trigger__label a24-tool-shimmer", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolActivityReel, { label }) })
|
|
1778
|
+
] });
|
|
1779
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "a24-tool-trigger-row", "data-agents24-model-turn": modelTurnId, role: "status", children: onSelect ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", onClick: onSelect, type: "button", children: content }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", children: content }) });
|
|
1780
|
+
}
|
|
1781
|
+
function AgentChatModelTurnRow({ part }) {
|
|
1782
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId });
|
|
1783
|
+
}
|
|
1784
|
+
function AgentChatNodeActivityRow({
|
|
1785
|
+
onSelect,
|
|
1786
|
+
part
|
|
1787
|
+
}) {
|
|
1788
|
+
const [open, setOpen] = React6.useState(false);
|
|
1789
|
+
const contentId = React6.useId();
|
|
1790
|
+
const running = part.status === "running";
|
|
1791
|
+
const failed = part.status === "failed";
|
|
1792
|
+
const failureMessage = part.failure?.message || "The node could not complete the request.";
|
|
1793
|
+
const triggerClassName = cn(
|
|
1794
|
+
"a24-tool-trigger",
|
|
1795
|
+
"a24-tool-trigger--root",
|
|
1796
|
+
!running && "a24-tool-trigger--without-orb",
|
|
1797
|
+
running && "a24-tool-trigger--active",
|
|
1798
|
+
failed && "a24-tool-trigger--error"
|
|
1799
|
+
);
|
|
1800
|
+
const label = running ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "a24-tool-shimmer", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolActivityReel, { label: part.label }) }) : part.label;
|
|
1801
|
+
if (!failed) {
|
|
1802
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "a24-tool-trigger-row", role: "status", children: onSelect ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
|
|
1803
|
+
running ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolActivityOrb, { label: part.label }) : null,
|
|
1804
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "a24-tool-trigger__label", children: label })
|
|
1805
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: triggerClassName, children: [
|
|
1806
|
+
running ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolActivityOrb, { label: part.label }) : null,
|
|
1807
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "a24-tool-trigger__label", children: label })
|
|
1808
|
+
] }) });
|
|
1156
1809
|
}
|
|
1157
|
-
return /* @__PURE__ */ (0,
|
|
1158
|
-
/* @__PURE__ */ (0,
|
|
1810
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "a24-tool-disclosure", children: [
|
|
1811
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1159
1812
|
"button",
|
|
1160
1813
|
{
|
|
1814
|
+
"aria-controls": contentId,
|
|
1161
1815
|
"aria-expanded": open,
|
|
1162
|
-
className:
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1816
|
+
className: triggerClassName,
|
|
1817
|
+
onClick: () => {
|
|
1818
|
+
onSelect?.(part);
|
|
1819
|
+
setOpen((value) => !value);
|
|
1820
|
+
},
|
|
1167
1821
|
type: "button",
|
|
1168
1822
|
children: [
|
|
1169
|
-
|
|
1170
|
-
open ? /* @__PURE__ */ (0,
|
|
1823
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "a24-tool-trigger__label", children: label }),
|
|
1824
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.ChevronDown, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.ChevronRight, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
|
|
1171
1825
|
]
|
|
1172
1826
|
}
|
|
1173
|
-
),
|
|
1174
|
-
open ? /* @__PURE__ */ (0,
|
|
1175
|
-
detail ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: detail }) : null,
|
|
1176
|
-
children
|
|
1177
|
-
] }) : null
|
|
1827
|
+
) }),
|
|
1828
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "a24-tool-detail a24-tool-detail--error", id: contentId, children: failureMessage }) : null
|
|
1178
1829
|
] });
|
|
1179
1830
|
}
|
|
1180
|
-
function
|
|
1181
|
-
|
|
1182
|
-
part
|
|
1831
|
+
function toolRowLabel(part) {
|
|
1832
|
+
const label = agentChatToolLabel(part);
|
|
1833
|
+
return isAgentChatToolRunning(part) ? label : label.replace(/^(?:running|ran)\s+/i, "");
|
|
1834
|
+
}
|
|
1835
|
+
function ToolDisclosure({
|
|
1836
|
+
children,
|
|
1837
|
+
error,
|
|
1838
|
+
label,
|
|
1839
|
+
loading,
|
|
1840
|
+
onExpandedChange,
|
|
1841
|
+
onSelect,
|
|
1842
|
+
part,
|
|
1843
|
+
root,
|
|
1844
|
+
showOrb,
|
|
1845
|
+
statusLabel,
|
|
1846
|
+
accessory
|
|
1183
1847
|
}) {
|
|
1184
|
-
|
|
1185
|
-
|
|
1848
|
+
const [open, setOpen] = React6.useState(false);
|
|
1849
|
+
const contentId = React6.useId();
|
|
1850
|
+
const expandable = React6.Children.toArray(children).length > 0;
|
|
1851
|
+
if (!expandable) {
|
|
1852
|
+
const triggerClassName = cn("a24-tool-trigger", root && "a24-tool-trigger--root", root && !showOrb && "a24-tool-trigger--without-orb", error && "a24-tool-trigger--error", loading && "a24-tool-trigger--active");
|
|
1853
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "a24-tool-trigger-row", children: [
|
|
1854
|
+
onSelect && part ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
|
|
1855
|
+
showOrb ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolActivityOrb, { label: statusLabel }) : null,
|
|
1856
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "a24-tool-trigger__label", children: label })
|
|
1857
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: triggerClassName, children: [
|
|
1858
|
+
showOrb ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolActivityOrb, { label: statusLabel }) : null,
|
|
1859
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "a24-tool-trigger__label", children: label })
|
|
1860
|
+
] }),
|
|
1861
|
+
accessory
|
|
1862
|
+
] });
|
|
1863
|
+
}
|
|
1864
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "a24-tool-disclosure", children: [
|
|
1865
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "a24-tool-trigger-row", children: [
|
|
1866
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1867
|
+
"button",
|
|
1868
|
+
{
|
|
1869
|
+
"aria-controls": contentId,
|
|
1870
|
+
"aria-expanded": open,
|
|
1871
|
+
className: cn("a24-tool-trigger", root && "a24-tool-trigger--root", root && !showOrb && "a24-tool-trigger--without-orb", error && "a24-tool-trigger--error", loading && "a24-tool-trigger--active"),
|
|
1872
|
+
onClick: () => {
|
|
1873
|
+
const nextOpen = !open;
|
|
1874
|
+
setOpen(nextOpen);
|
|
1875
|
+
if (part) onSelect?.(part);
|
|
1876
|
+
onExpandedChange?.(nextOpen, part);
|
|
1877
|
+
},
|
|
1878
|
+
type: "button",
|
|
1879
|
+
children: [
|
|
1880
|
+
showOrb ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolActivityOrb, { label: statusLabel }) : null,
|
|
1881
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "a24-tool-trigger__label", children: label }),
|
|
1882
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.ChevronDown, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.ChevronRight, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
|
|
1883
|
+
]
|
|
1884
|
+
}
|
|
1885
|
+
),
|
|
1886
|
+
accessory
|
|
1887
|
+
] }),
|
|
1888
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "a24-tool-disclosure__content", id: contentId, children }) : null
|
|
1889
|
+
] });
|
|
1890
|
+
}
|
|
1891
|
+
function ToolLabel({ active, label, part, slots }) {
|
|
1892
|
+
const rendered = slots?.renderToolLabel?.({ isActive: active, label, part }) ?? label;
|
|
1893
|
+
return active ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "a24-tool-shimmer", children: rendered }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: rendered });
|
|
1894
|
+
}
|
|
1895
|
+
function ToolList({ children }) {
|
|
1896
|
+
const listRef = React6.useRef(null);
|
|
1897
|
+
const [fades, setFades] = React6.useState({ bottom: false, top: false });
|
|
1898
|
+
const updateFades = React6.useCallback(() => {
|
|
1899
|
+
const list = listRef.current;
|
|
1900
|
+
if (!list) return;
|
|
1901
|
+
const next = {
|
|
1902
|
+
bottom: list.scrollTop + list.clientHeight < list.scrollHeight - 1,
|
|
1903
|
+
top: list.scrollTop > 1
|
|
1904
|
+
};
|
|
1905
|
+
setFades((current) => current.bottom === next.bottom && current.top === next.top ? current : next);
|
|
1906
|
+
}, []);
|
|
1907
|
+
React6.useEffect(() => {
|
|
1908
|
+
updateFades();
|
|
1909
|
+
const list = listRef.current;
|
|
1910
|
+
if (!list || typeof ResizeObserver === "undefined") return;
|
|
1911
|
+
const observer = new ResizeObserver(updateFades);
|
|
1912
|
+
observer.observe(list);
|
|
1913
|
+
return () => observer.disconnect();
|
|
1914
|
+
}, [children, updateFades]);
|
|
1915
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1916
|
+
"div",
|
|
1186
1917
|
{
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
loading: isActiveTool(part, activeToolId)
|
|
1918
|
+
className: "a24-tool-list-frame",
|
|
1919
|
+
"data-scroll-fade-bottom": fades.bottom ? "" : void 0,
|
|
1920
|
+
"data-scroll-fade-top": fades.top ? "" : void 0,
|
|
1921
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "a24-tool-list", onScroll: updateFades, ref: listRef, role: "list", children })
|
|
1192
1922
|
}
|
|
1193
|
-
)
|
|
1923
|
+
);
|
|
1194
1924
|
}
|
|
1195
|
-
function
|
|
1925
|
+
function AgentChatToolRow({
|
|
1196
1926
|
activeToolId,
|
|
1197
|
-
|
|
1927
|
+
part,
|
|
1928
|
+
root = true,
|
|
1929
|
+
showOrb,
|
|
1930
|
+
slots
|
|
1198
1931
|
}) {
|
|
1199
|
-
const
|
|
1200
|
-
|
|
1201
|
-
|
|
1932
|
+
const active = isActive(part, activeToolId);
|
|
1933
|
+
const failed = part.state === "output-error";
|
|
1934
|
+
const failureMessage = part.failure?.message || null;
|
|
1935
|
+
const detail = failed ? failureMessage : optionalText(part.presentation.detail);
|
|
1936
|
+
const hostDetails = failed ? null : slots?.renderToolDetails?.(part);
|
|
1937
|
+
const context = { isActive: active, label: toolRowLabel(part), part };
|
|
1938
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1939
|
+
ToolDisclosure,
|
|
1202
1940
|
{
|
|
1203
|
-
|
|
1941
|
+
error: failed,
|
|
1942
|
+
accessory: slots?.renderToolAccessory?.(context),
|
|
1943
|
+
label: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolLabel, { active, label: context.label, part, slots }),
|
|
1944
|
+
loading: active,
|
|
1945
|
+
onExpandedChange: slots?.onExpandedChange,
|
|
1946
|
+
onSelect: slots?.onToolSelect,
|
|
1947
|
+
part,
|
|
1948
|
+
root,
|
|
1949
|
+
showOrb: showOrb ?? active,
|
|
1950
|
+
statusLabel: active ? context.label : void 0,
|
|
1204
1951
|
children: [
|
|
1205
|
-
|
|
1206
|
-
|
|
1952
|
+
detail ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn("a24-tool-detail", failed && "a24-tool-detail--error"), children: detail }) : null,
|
|
1953
|
+
hostDetails
|
|
1207
1954
|
]
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
|
|
1955
|
+
}
|
|
1956
|
+
) });
|
|
1957
|
+
}
|
|
1958
|
+
function sessionLabel(parts, visiblePart, running) {
|
|
1959
|
+
const label = agentChatToolLabel(visiblePart);
|
|
1960
|
+
const terminalLabel = label.replace(/^(?:running|ran)\s+/i, "");
|
|
1961
|
+
return running ? label : `Ran ${terminalLabel} + ${parts.length - 1} more`;
|
|
1962
|
+
}
|
|
1963
|
+
function AgentChatToolSession({
|
|
1964
|
+
activeToolId,
|
|
1965
|
+
isLatestActivity = true,
|
|
1966
|
+
isLive = false,
|
|
1967
|
+
leadingModelTurn,
|
|
1968
|
+
modelTurn,
|
|
1969
|
+
parts,
|
|
1970
|
+
slots
|
|
1971
|
+
}) {
|
|
1972
|
+
const presentedLiveRef = React6.useRef(false);
|
|
1973
|
+
if (isLive && isLatestActivity) presentedLiveRef.current = true;
|
|
1974
|
+
const activeIndex = parts.findLastIndex((part) => isActive(part, activeToolId));
|
|
1975
|
+
const running = activeIndex >= 0;
|
|
1976
|
+
if (parts.length === 1 && !modelTurn && !leadingModelTurn) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AgentChatToolRow, { activeToolId, part: parts[0], slots });
|
|
1977
|
+
const visibleIndex = running ? activeIndex : parts.length - 1;
|
|
1978
|
+
const visiblePart = parts[visibleIndex];
|
|
1979
|
+
const planning = Boolean(modelTurn);
|
|
1980
|
+
const presentingActivity = isLatestActivity && (planning || running || isLive);
|
|
1981
|
+
const failed = isLatestActivity && (visiblePart.state === "output-error" || visiblePart.state === "cancelled");
|
|
1982
|
+
const label = planning ? "Planning next moves" : isLive && isLatestActivity ? agentChatToolLabel(visiblePart) : sessionLabel(parts, visiblePart, running);
|
|
1983
|
+
const labelContent = presentedLiveRef.current ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolActivityReel, { initialLabel: leadingModelTurn ? "Planning next moves" : void 0, initialShownAt: leadingModelTurn?.timestamp, label }) }) : label;
|
|
1984
|
+
const context = { isActive: presentingActivity, label, part: visiblePart };
|
|
1985
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1986
|
+
ToolDisclosure,
|
|
1987
|
+
{
|
|
1988
|
+
accessory: slots?.renderToolAccessory?.(context),
|
|
1989
|
+
error: failed,
|
|
1990
|
+
label: labelContent,
|
|
1991
|
+
loading: presentingActivity,
|
|
1992
|
+
onExpandedChange: slots?.onExpandedChange,
|
|
1993
|
+
part: visiblePart,
|
|
1994
|
+
root: true,
|
|
1995
|
+
showOrb: isLive && isLatestActivity,
|
|
1996
|
+
statusLabel: planning ? "Planning next moves" : label,
|
|
1997
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolList, { children: parts.map((part) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { role: "listitem", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AgentChatToolRow, { activeToolId, part, root: false, showOrb: false, slots }) }, part.id)) })
|
|
1998
|
+
}
|
|
1999
|
+
);
|
|
2000
|
+
}
|
|
2001
|
+
function childLabel(child) {
|
|
2002
|
+
return optionalText(child.title) || optionalText(child.toolName) || "Tool";
|
|
2003
|
+
}
|
|
2004
|
+
function subagentLabel(part) {
|
|
2005
|
+
const childRun = part.presentation.childRun;
|
|
2006
|
+
const children = part.presentation.childTools || [];
|
|
2007
|
+
const name = optionalText(childRun?.agentName) || optionalText(part.displayName) || "agent";
|
|
2008
|
+
const status = String(childRun?.status || (isAgentChatToolRunning(part) ? "running" : "completed")).toLowerCase();
|
|
2009
|
+
const activeChild = children.find((child) => child.id === part.presentation.activeChildToolId) || [...children].reverse().find((child) => child.status === "running") || children[children.length - 1];
|
|
2010
|
+
if (status === "running" && activeChild) return { label: `Agent ${name}, running ${childLabel(activeChild)}`, running: true };
|
|
2011
|
+
if (status === "running") return { label: `Agent ${name}, starting`, running: true };
|
|
2012
|
+
if (status === "failed" || part.state === "output-error") return { label: `Agent ${name}, failed`, running: false };
|
|
2013
|
+
if (status === "cancelled" || status === "canceled" || part.state === "cancelled") return { label: `Agent ${name}, cancelled`, running: false };
|
|
2014
|
+
if (status === "paused") return { label: `Agent ${name}, paused`, running: false };
|
|
2015
|
+
return { label: `Agent ${name}, ran ${children.length} ${children.length === 1 ? "tool" : "tools"}`, running: false };
|
|
2016
|
+
}
|
|
2017
|
+
function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part, slots }) {
|
|
2018
|
+
const presentedLiveRef = React6.useRef(false);
|
|
2019
|
+
if (isLive && isLatestActivity) presentedLiveRef.current = true;
|
|
2020
|
+
const children = part.presentation.childTools || [];
|
|
2021
|
+
const state = subagentLabel(part);
|
|
2022
|
+
const childRunStatus = String(part.presentation.childRun?.status || "").toLowerCase();
|
|
2023
|
+
const failed = part.state === "output-error" || part.state === "cancelled" || childRunStatus === "failed" || childRunStatus === "cancelled" || childRunStatus === "canceled";
|
|
2024
|
+
const hostDetails = failed ? null : slots?.renderToolDetails?.(part);
|
|
2025
|
+
const failureMessage = part.failure?.message || null;
|
|
2026
|
+
const presentingActivity = isLatestActivity && state.running;
|
|
2027
|
+
const labelContent = presentedLiveRef.current ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolActivityReel, { label: state.label }) }) : state.label;
|
|
2028
|
+
const context = { isActive: presentingActivity, label: state.label, part };
|
|
2029
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2030
|
+
ToolDisclosure,
|
|
2031
|
+
{
|
|
2032
|
+
accessory: slots?.renderToolAccessory?.(context),
|
|
2033
|
+
error: failed,
|
|
2034
|
+
label: labelContent,
|
|
2035
|
+
loading: presentingActivity,
|
|
2036
|
+
onExpandedChange: slots?.onExpandedChange,
|
|
2037
|
+
part,
|
|
2038
|
+
root: true,
|
|
2039
|
+
showOrb: isLive && isLatestActivity,
|
|
2040
|
+
statusLabel: state.label,
|
|
2041
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(ToolList, { children: [
|
|
2042
|
+
children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn("a24-child-tool", child.status === "failed" && "a24-child-tool--error"), role: "listitem", children: slots?.renderChildTool?.(child, part) ?? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
2043
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: cn(isLive && isLatestActivity && child.status === "running" && "a24-tool-shimmer"), children: childLabel(child) }),
|
|
2044
|
+
child.detail ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "a24-child-tool__detail", children: child.detail }) : null
|
|
2045
|
+
] }) }, child.id)),
|
|
2046
|
+
failureMessage ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "a24-tool-detail a24-tool-detail--error", children: failureMessage }) : null,
|
|
2047
|
+
hostDetails
|
|
2048
|
+
] })
|
|
2049
|
+
}
|
|
2050
|
+
);
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
// src/ui/agent-response-timeline.tsx
|
|
2054
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2055
|
+
function isInternalAskUserTool(part) {
|
|
2056
|
+
return [part.toolName, part.toolKey, part.action].some((value) => value?.trim().toLowerCase() === "runtime__ask_user");
|
|
2057
|
+
}
|
|
2058
|
+
function Shimmer({ children, className }) {
|
|
2059
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: cn("inline-block animate-pulse", className), children });
|
|
2060
|
+
}
|
|
2061
|
+
function AgentChatToolPart({
|
|
2062
|
+
activeToolId,
|
|
2063
|
+
part
|
|
2064
|
+
}) {
|
|
2065
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatToolRow, { activeToolId, part });
|
|
2066
|
+
}
|
|
2067
|
+
function AgentChatToolGroup({
|
|
2068
|
+
activeToolId,
|
|
2069
|
+
parts
|
|
2070
|
+
}) {
|
|
2071
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatToolSession, { activeToolId, parts });
|
|
1211
2072
|
}
|
|
1212
2073
|
function HitlPartRow({
|
|
1213
2074
|
getHitlActionState,
|
|
@@ -1216,22 +2077,40 @@ function HitlPartRow({
|
|
|
1216
2077
|
part
|
|
1217
2078
|
}) {
|
|
1218
2079
|
const state = getHitlActionState?.(part);
|
|
1219
|
-
const [comment, setComment] =
|
|
2080
|
+
const [comment, setComment] = React7.useState("");
|
|
1220
2081
|
const presentation = part.presentation || {};
|
|
1221
2082
|
const requireComment = presentation.require_comment === true;
|
|
1222
2083
|
const isTerminal = part.status !== "pending";
|
|
1223
|
-
const resolvedRef =
|
|
1224
|
-
const wasTerminal =
|
|
1225
|
-
|
|
2084
|
+
const resolvedRef = React7.useRef(null);
|
|
2085
|
+
const wasTerminal = React7.useRef(isTerminal);
|
|
2086
|
+
React7.useEffect(() => {
|
|
1226
2087
|
if (isTerminal && !wasTerminal.current) resolvedRef.current?.focus();
|
|
1227
2088
|
wasTerminal.current = isTerminal;
|
|
1228
2089
|
}, [isTerminal]);
|
|
2090
|
+
if (part.hitlKind === "user_input") {
|
|
2091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2092
|
+
AskUserInteraction,
|
|
2093
|
+
{
|
|
2094
|
+
error: state?.error,
|
|
2095
|
+
isBusy: isLoading || state?.status === "resuming",
|
|
2096
|
+
onSubmit: onHitlAction ? (answers) => onHitlAction(part, {
|
|
2097
|
+
action: "respond",
|
|
2098
|
+
answers: answers.map((answer) => ({
|
|
2099
|
+
question_id: answer.questionId,
|
|
2100
|
+
selected_option_ids: answer.selectedOptionIds,
|
|
2101
|
+
...answer.customText ? { custom_text: answer.customText } : {}
|
|
2102
|
+
}))
|
|
2103
|
+
}) : void 0,
|
|
2104
|
+
part
|
|
2105
|
+
}
|
|
2106
|
+
);
|
|
2107
|
+
}
|
|
1229
2108
|
if (isTerminal) {
|
|
1230
|
-
return /* @__PURE__ */ (0,
|
|
2109
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-hitl a24-hitl--resolved px-1 py-1 text-sm text-muted-foreground", ref: resolvedRef, role: "status", tabIndex: -1, children: resolvedHitlLabel(part) });
|
|
1231
2110
|
}
|
|
1232
|
-
return /* @__PURE__ */ (0,
|
|
1233
|
-
/* @__PURE__ */ (0,
|
|
1234
|
-
requireComment ? /* @__PURE__ */ (0,
|
|
2111
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "a24-hitl space-y-2.5 px-1 py-2", children: [
|
|
2112
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-hitl__title text-sm font-medium text-foreground text-pretty", children: hitlTitle(part) }),
|
|
2113
|
+
requireComment ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1235
2114
|
"textarea",
|
|
1236
2115
|
{
|
|
1237
2116
|
"aria-label": "Approval comment",
|
|
@@ -1243,8 +2122,8 @@ function HitlPartRow({
|
|
|
1243
2122
|
value: comment
|
|
1244
2123
|
}
|
|
1245
2124
|
) : null,
|
|
1246
|
-
state?.error ? /* @__PURE__ */ (0,
|
|
1247
|
-
/* @__PURE__ */ (0,
|
|
2125
|
+
state?.error ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-hitl__error text-sm text-destructive", children: state.error }) : null,
|
|
2126
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-hitl__actions flex flex-wrap items-center gap-1.5", children: part.allowedActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1248
2127
|
"button",
|
|
1249
2128
|
{
|
|
1250
2129
|
"aria-label": hitlActionLabel(part, action),
|
|
@@ -1254,7 +2133,10 @@ function HitlPartRow({
|
|
|
1254
2133
|
),
|
|
1255
2134
|
"data-primary": action === "approve" || action === "connect" ? "" : void 0,
|
|
1256
2135
|
disabled: !onHitlAction || isLoading || state?.status === "connecting" || state?.status === "resuming" || requireComment && !comment.trim(),
|
|
1257
|
-
onClick: () => onHitlAction?.(part,
|
|
2136
|
+
onClick: () => onHitlAction?.(part, {
|
|
2137
|
+
action,
|
|
2138
|
+
...comment.trim() ? { comment: comment.trim() } : {}
|
|
2139
|
+
}),
|
|
1258
2140
|
type: "button",
|
|
1259
2141
|
children: hitlActionLabel(part, action)
|
|
1260
2142
|
},
|
|
@@ -1262,28 +2144,45 @@ function HitlPartRow({
|
|
|
1262
2144
|
)) })
|
|
1263
2145
|
] });
|
|
1264
2146
|
}
|
|
1265
|
-
function
|
|
2147
|
+
function AgentChatPart({
|
|
1266
2148
|
activeToolId,
|
|
1267
2149
|
getHitlActionState,
|
|
1268
2150
|
isLoading,
|
|
2151
|
+
isTextStreaming,
|
|
1269
2152
|
message,
|
|
1270
2153
|
onHitlAction,
|
|
1271
|
-
part
|
|
2154
|
+
part,
|
|
2155
|
+
responseProps,
|
|
2156
|
+
toolSlots
|
|
1272
2157
|
}) {
|
|
1273
|
-
if (part.kind === "text")
|
|
1274
|
-
|
|
2158
|
+
if (part.kind === "text") {
|
|
2159
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2160
|
+
MessageResponse,
|
|
2161
|
+
{
|
|
2162
|
+
...responseProps,
|
|
2163
|
+
streaming: isTextStreaming ?? Boolean(isLoading && part.raw?.status === "streaming"),
|
|
2164
|
+
streamingId: part.id,
|
|
2165
|
+
children: part.text
|
|
2166
|
+
}
|
|
2167
|
+
);
|
|
2168
|
+
}
|
|
2169
|
+
if (part.kind === "tool") return isAgentChatSubagent(part) ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatSubagentGroup, { part, slots: toolSlots }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatToolRow, { activeToolId, part, slots: toolSlots });
|
|
2170
|
+
if (part.kind === "model-turn") return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatModelTurnRow, { part });
|
|
1275
2171
|
if (part.kind === "reasoning") {
|
|
1276
2172
|
const label = part.text || part.label || "Thinking";
|
|
1277
|
-
return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ (0,
|
|
2173
|
+
return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Shimmer, { className: "text-sm text-muted-foreground", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-sm text-muted-foreground", children: label });
|
|
2174
|
+
}
|
|
2175
|
+
if (part.kind === "context-compression") {
|
|
2176
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatContextCompressionRow, { part });
|
|
1278
2177
|
}
|
|
1279
2178
|
if (part.kind === "ui-blocks") {
|
|
1280
2179
|
if (part.state === "output-error") {
|
|
1281
|
-
return /* @__PURE__ */ (0,
|
|
2180
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-timeline-error text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
|
|
1282
2181
|
}
|
|
1283
|
-
return part.bundle ? /* @__PURE__ */ (0,
|
|
2182
|
+
return part.bundle ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SafeUiBlocks, { bundle: part.bundle }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-sm text-muted-foreground", children: part.state === "input-streaming" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Shimmer, { children: "Rendering UI block" }) : "Rendered UI block" });
|
|
1284
2183
|
}
|
|
1285
2184
|
if (part.kind === "hitl") {
|
|
1286
|
-
return /* @__PURE__ */ (0,
|
|
2185
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1287
2186
|
HitlPartRow,
|
|
1288
2187
|
{
|
|
1289
2188
|
getHitlActionState,
|
|
@@ -1293,18 +2192,18 @@ function DefaultPartRow({
|
|
|
1293
2192
|
}
|
|
1294
2193
|
);
|
|
1295
2194
|
}
|
|
1296
|
-
if (part.kind === "error") return /* @__PURE__ */ (0,
|
|
2195
|
+
if (part.kind === "error") return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-timeline-error text-sm text-destructive", role: "alert", children: part.errorText });
|
|
1297
2196
|
if (part.kind === "source") {
|
|
1298
2197
|
const href = safeExternalUrl(part.url);
|
|
1299
|
-
return href ? /* @__PURE__ */ (0,
|
|
2198
|
+
return href ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("a", { className: "a24-source-link", href, rel: "noopener noreferrer", target: "_blank", children: part.title }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-source-link", children: part.title });
|
|
1300
2199
|
}
|
|
1301
2200
|
if (part.kind === "citation") {
|
|
1302
2201
|
const href = safeExternalUrl(part.url);
|
|
1303
2202
|
const label = part.label || "Citation";
|
|
1304
|
-
return href ? /* @__PURE__ */ (0,
|
|
2203
|
+
return href ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("a", { className: "a24-citation", href, rel: "noopener noreferrer", target: "_blank", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-citation", children: label });
|
|
1305
2204
|
}
|
|
1306
|
-
if (part.kind === "attachment") return /* @__PURE__ */ (0,
|
|
1307
|
-
if (part.kind === "data") return /* @__PURE__ */ (0,
|
|
2205
|
+
if (part.kind === "attachment") return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-output-attachment", children: part.attachment.filename || "Attachment" });
|
|
2206
|
+
if (part.kind === "data") return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
|
|
1308
2207
|
return null;
|
|
1309
2208
|
}
|
|
1310
2209
|
function safeExternalUrl(value) {
|
|
@@ -1318,28 +2217,28 @@ function safeExternalUrl(value) {
|
|
|
1318
2217
|
}
|
|
1319
2218
|
function SafeUiBlocks({ bundle }) {
|
|
1320
2219
|
const rows = Array.isArray(bundle.rows) ? bundle.rows : [];
|
|
1321
|
-
return /* @__PURE__ */ (0,
|
|
1322
|
-
typeof bundle.title === "string" ? /* @__PURE__ */ (0,
|
|
2220
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { "aria-label": typeof bundle.title === "string" ? bundle.title : "Agent result", className: "a24-ui-blocks", children: [
|
|
2221
|
+
typeof bundle.title === "string" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { children: bundle.title }) : null,
|
|
1323
2222
|
rows.map((rawRow, rowIndex) => {
|
|
1324
2223
|
const row = rawRow && typeof rawRow === "object" && !Array.isArray(rawRow) ? rawRow : {};
|
|
1325
2224
|
const blocks = Array.isArray(row.blocks) ? row.blocks : [];
|
|
1326
|
-
return /* @__PURE__ */ (0,
|
|
2225
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-ui-blocks__row", children: blocks.map((rawBlock, blockIndex) => {
|
|
1327
2226
|
const block = rawBlock && typeof rawBlock === "object" && !Array.isArray(rawBlock) ? rawBlock : {};
|
|
1328
2227
|
const title = typeof block.title === "string" ? block.title : "Result";
|
|
1329
2228
|
const kind = String(block.kind || "note");
|
|
1330
2229
|
if (kind === "table" && Array.isArray(block.columns) && Array.isArray(block.rows)) {
|
|
1331
|
-
return /* @__PURE__ */ (0,
|
|
1332
|
-
/* @__PURE__ */ (0,
|
|
1333
|
-
/* @__PURE__ */ (0,
|
|
1334
|
-
/* @__PURE__ */ (0,
|
|
1335
|
-
/* @__PURE__ */ (0,
|
|
2230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "a24-ui-block", children: [
|
|
2231
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h4", { children: title }),
|
|
2232
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-ui-table-scroll", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("table", { children: [
|
|
2233
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tr", { children: block.columns.map((column, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { children: String(column) }, index)) }) }),
|
|
2234
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: block.rows.map((rawCells, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tr", { children: (Array.isArray(rawCells) ? rawCells : []).map((cell, cellIndex) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { children: String(cell) }, cellIndex)) }, index)) })
|
|
1336
2235
|
] }) })
|
|
1337
2236
|
] }, String(block.id || blockIndex));
|
|
1338
2237
|
}
|
|
1339
2238
|
const value = block.value ?? block.text ?? "";
|
|
1340
|
-
return /* @__PURE__ */ (0,
|
|
1341
|
-
/* @__PURE__ */ (0,
|
|
1342
|
-
/* @__PURE__ */ (0,
|
|
2239
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "a24-ui-block", children: [
|
|
2240
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h4", { children: title }),
|
|
2241
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { children: String(value) })
|
|
1343
2242
|
] }, String(block.id || blockIndex));
|
|
1344
2243
|
}) }, `row-${rowIndex}`);
|
|
1345
2244
|
})
|
|
@@ -1349,53 +2248,81 @@ function AgentResponseTimeline({
|
|
|
1349
2248
|
getHitlActionState,
|
|
1350
2249
|
isLoading = false,
|
|
1351
2250
|
message,
|
|
2251
|
+
nodeActivityMode = "default",
|
|
1352
2252
|
onHitlAction,
|
|
1353
|
-
|
|
2253
|
+
parts: displayParts,
|
|
2254
|
+
responseProps,
|
|
2255
|
+
toolSlots,
|
|
2256
|
+
toolViewMode = "closed"
|
|
1354
2257
|
}) {
|
|
1355
|
-
const parts = message.parts || [];
|
|
1356
|
-
const
|
|
2258
|
+
const parts = (displayParts || message.parts || []).filter((part) => (part.kind !== "tool" || !isInternalAskUserTool(part)) && (part.kind !== "model-turn" || part.turnKind === "agent") && (part.kind !== "node-activity" || nodeActivityMode === "all" || nodeActivityMode === "default" && part.defaultChatVisible));
|
|
2259
|
+
const toolParts = parts.filter((part) => part.kind === "tool");
|
|
2260
|
+
const activeToolId = latestRunningAgentChatToolId(toolParts);
|
|
2261
|
+
const activeTextPartId = getActiveStreamingTextPartId(
|
|
2262
|
+
{ ...message, parts: [...parts] },
|
|
2263
|
+
isLoading ? message.id : null
|
|
2264
|
+
);
|
|
1357
2265
|
const rendered = [];
|
|
1358
|
-
let
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
if (
|
|
1362
|
-
const
|
|
1363
|
-
const
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
2266
|
+
let activeActivityClaimed = false;
|
|
2267
|
+
const segments = partitionAgentChatToolTimeline(parts, toolViewMode);
|
|
2268
|
+
for (const [segmentIndex, segment] of segments.entries()) {
|
|
2269
|
+
if (segment.kind === "tool") {
|
|
2270
|
+
const isLatestActivity = segmentIndex === segments.length - 1;
|
|
2271
|
+
const showOrb = toolViewMode === "closed" ? isLoading && isLatestActivity : Boolean(activeToolId && (segment.part.id === activeToolId || segment.part.toolCallId === activeToolId));
|
|
2272
|
+
rendered.push(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatToolRow, { activeToolId, part: segment.part, showOrb, slots: toolSlots }, segment.part.id));
|
|
2273
|
+
continue;
|
|
2274
|
+
}
|
|
2275
|
+
if (segment.kind === "tool-session") {
|
|
2276
|
+
rendered.push(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatToolSession, { activeToolId, isLatestActivity: segmentIndex === segments.length - 1, isLive: isLoading, leadingModelTurn: segment.leadingModelTurn, modelTurn: segment.modelTurn, parts: segment.parts, slots: toolSlots }, `tool-session-${segment.parts[0].id}`));
|
|
2277
|
+
continue;
|
|
2278
|
+
}
|
|
2279
|
+
if (segment.kind === "subagent") {
|
|
2280
|
+
rendered.push(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatSubagentGroup, { isLatestActivity: segmentIndex === segments.length - 1, isLive: isLoading, part: segment.part, slots: toolSlots }, segment.part.id));
|
|
2281
|
+
continue;
|
|
2282
|
+
}
|
|
2283
|
+
const part = segment.part;
|
|
2284
|
+
if (part.kind === "model-turn") {
|
|
2285
|
+
const key = activeActivityClaimed ? part.id : `${message.id}-active-activity`;
|
|
2286
|
+
activeActivityClaimed = true;
|
|
2287
|
+
rendered.push(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId }, key));
|
|
2288
|
+
continue;
|
|
2289
|
+
}
|
|
2290
|
+
if (part.kind === "node-activity") {
|
|
2291
|
+
const key = activeActivityClaimed ? part.id : `${message.id}-active-activity`;
|
|
2292
|
+
if (part.status === "running") activeActivityClaimed = true;
|
|
2293
|
+
rendered.push(
|
|
2294
|
+
part.status === "running" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatActivityRow, { label: part.label }, key) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatNodeActivityRow, { part }, part.id)
|
|
2295
|
+
);
|
|
1371
2296
|
continue;
|
|
1372
2297
|
}
|
|
1373
2298
|
rendered.push(
|
|
1374
|
-
/* @__PURE__ */ (0,
|
|
1375
|
-
|
|
2299
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(React7.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2300
|
+
AgentChatPart,
|
|
1376
2301
|
{
|
|
1377
2302
|
activeToolId,
|
|
1378
2303
|
getHitlActionState,
|
|
1379
2304
|
isLoading,
|
|
2305
|
+
isTextStreaming: part.kind === "text" && part.id === activeTextPartId,
|
|
1380
2306
|
message,
|
|
1381
2307
|
onHitlAction,
|
|
1382
|
-
part
|
|
2308
|
+
part,
|
|
2309
|
+
responseProps,
|
|
2310
|
+
toolSlots
|
|
1383
2311
|
}
|
|
1384
2312
|
) }, part.id)
|
|
1385
2313
|
);
|
|
1386
|
-
index += 1;
|
|
1387
2314
|
}
|
|
1388
2315
|
if (rendered.length === 0 && message.content) {
|
|
1389
|
-
rendered.push(/* @__PURE__ */ (0,
|
|
2316
|
+
rendered.push(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MessageResponse, { children: message.content }, `${message.id}-fallback`));
|
|
1390
2317
|
}
|
|
1391
2318
|
if (rendered.length === 0 && isLoading) {
|
|
1392
|
-
rendered.push(/* @__PURE__ */ (0,
|
|
2319
|
+
rendered.push(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatActivityRow, { label: "Thinking" }, `${message.id}-active-activity`));
|
|
1393
2320
|
}
|
|
1394
|
-
return /* @__PURE__ */ (0,
|
|
2321
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "space-y-3", children: rendered });
|
|
1395
2322
|
}
|
|
1396
2323
|
|
|
1397
2324
|
// src/ui/agent-chat-message.tsx
|
|
1398
|
-
var
|
|
2325
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1399
2326
|
var DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD = 360;
|
|
1400
2327
|
var DEFAULT_USER_MESSAGE_COLLAPSED_LINES = 4;
|
|
1401
2328
|
function shouldCollapseUserMessage(content, threshold = DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD) {
|
|
@@ -1408,19 +2335,19 @@ function AgentChatUserMessageContent({
|
|
|
1408
2335
|
showLessLabel = "Show less",
|
|
1409
2336
|
showMoreLabel = "Show more"
|
|
1410
2337
|
}) {
|
|
1411
|
-
const [isExpanded, setIsExpanded] =
|
|
1412
|
-
const contentId =
|
|
2338
|
+
const [isExpanded, setIsExpanded] = React8.useState(false);
|
|
2339
|
+
const contentId = React8.useId();
|
|
1413
2340
|
const shouldCollapse = shouldCollapseUserMessage(content, collapseThreshold);
|
|
1414
|
-
const Icon = isExpanded ?
|
|
2341
|
+
const Icon = isExpanded ? import_lucide_react5.ChevronUp : import_lucide_react5.ChevronDown;
|
|
1415
2342
|
const clampedStyle = shouldCollapse && !isExpanded ? {
|
|
1416
2343
|
WebkitBoxOrient: "vertical",
|
|
1417
2344
|
WebkitLineClamp: Math.max(1, collapsedLines),
|
|
1418
2345
|
display: "-webkit-box",
|
|
1419
2346
|
overflow: "hidden"
|
|
1420
2347
|
} : void 0;
|
|
1421
|
-
return /* @__PURE__ */ (0,
|
|
1422
|
-
/* @__PURE__ */ (0,
|
|
1423
|
-
shouldCollapse ? /* @__PURE__ */ (0,
|
|
2348
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex min-w-0 flex-col gap-3", children: [
|
|
2349
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
|
|
2350
|
+
shouldCollapse ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1424
2351
|
"button",
|
|
1425
2352
|
{
|
|
1426
2353
|
"aria-controls": contentId,
|
|
@@ -1433,7 +2360,7 @@ function AgentChatUserMessageContent({
|
|
|
1433
2360
|
type: "button",
|
|
1434
2361
|
children: [
|
|
1435
2362
|
isExpanded ? showLessLabel : showMoreLabel,
|
|
1436
|
-
/* @__PURE__ */ (0,
|
|
2363
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
|
|
1437
2364
|
]
|
|
1438
2365
|
}
|
|
1439
2366
|
) : null
|
|
@@ -1441,6 +2368,7 @@ function AgentChatUserMessageContent({
|
|
|
1441
2368
|
}
|
|
1442
2369
|
function AgentChatMessage({
|
|
1443
2370
|
actionHandlers,
|
|
2371
|
+
additionalActions,
|
|
1444
2372
|
actions,
|
|
1445
2373
|
actionsClassName,
|
|
1446
2374
|
className,
|
|
@@ -1448,9 +2376,10 @@ function AgentChatMessage({
|
|
|
1448
2376
|
dir,
|
|
1449
2377
|
getHitlActionState,
|
|
1450
2378
|
message,
|
|
2379
|
+
nodeActivityMode,
|
|
1451
2380
|
onHitlAction,
|
|
2381
|
+
Timeline = AgentResponseTimeline,
|
|
1452
2382
|
renderAssistantContent,
|
|
1453
|
-
renderPart,
|
|
1454
2383
|
renderUserContent,
|
|
1455
2384
|
showAssistantAttachments = false,
|
|
1456
2385
|
streamingMessageId,
|
|
@@ -1465,9 +2394,17 @@ function AgentChatMessage({
|
|
|
1465
2394
|
const resolvedUserContent = userMessageContent ?? message.content;
|
|
1466
2395
|
const shouldRenderContent = isAssistant || Boolean(renderUserContent || resolvedUserContent);
|
|
1467
2396
|
const showAttachments = Boolean(message.attachments?.length) && (message.role === "user" || showAssistantAttachments);
|
|
1468
|
-
const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ (0,
|
|
1469
|
-
|
|
1470
|
-
|
|
2397
|
+
const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2398
|
+
AgentChatDefaultActions,
|
|
2399
|
+
{
|
|
2400
|
+
additionalActions,
|
|
2401
|
+
dir,
|
|
2402
|
+
handlers: actionHandlers,
|
|
2403
|
+
message
|
|
2404
|
+
}
|
|
2405
|
+
) : null);
|
|
2406
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(ChatMessage, { className, dir, from: message.role, children: [
|
|
2407
|
+
showAttachments ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChatAttachments, { className: "mb-2", dir, children: message.attachments?.map((attachment, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1471
2408
|
ChatAttachment,
|
|
1472
2409
|
{
|
|
1473
2410
|
data: attachment,
|
|
@@ -1475,23 +2412,25 @@ function AgentChatMessage({
|
|
|
1475
2412
|
},
|
|
1476
2413
|
String(attachment.url || attachment.filename || index)
|
|
1477
2414
|
)) }) : null,
|
|
1478
|
-
shouldRenderContent ? /* @__PURE__ */ (0,
|
|
2415
|
+
shouldRenderContent ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1479
2416
|
ChatMessageContent,
|
|
1480
2417
|
{
|
|
1481
2418
|
className: cn(isAssistant ? "bg-transparent p-0" : void 0, contentClassName),
|
|
1482
2419
|
dir,
|
|
2420
|
+
from: message.role,
|
|
1483
2421
|
children: [
|
|
1484
|
-
isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ (0,
|
|
1485
|
-
|
|
2422
|
+
isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2423
|
+
Timeline,
|
|
1486
2424
|
{
|
|
1487
2425
|
getHitlActionState,
|
|
1488
2426
|
isLoading: isStreaming,
|
|
1489
2427
|
message,
|
|
2428
|
+
nodeActivityMode,
|
|
1490
2429
|
onHitlAction,
|
|
1491
|
-
|
|
2430
|
+
parts: message.parts
|
|
1492
2431
|
}
|
|
1493
2432
|
) : null,
|
|
1494
|
-
!isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ (0,
|
|
2433
|
+
!isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1495
2434
|
AgentChatUserMessageContent,
|
|
1496
2435
|
{
|
|
1497
2436
|
collapsedLines: userMessageCollapsedLines,
|
|
@@ -1504,16 +2443,117 @@ function AgentChatMessage({
|
|
|
1504
2443
|
]
|
|
1505
2444
|
}
|
|
1506
2445
|
) : null,
|
|
1507
|
-
renderedActions ? /* @__PURE__ */ (0,
|
|
2446
|
+
renderedActions ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: cn(dir === "rtl" ? "mt-1 h-9 w-full" : "mt-1 h-9 w-full -translate-x-2", actionsClassName), children: renderedActions }) : null
|
|
1508
2447
|
] });
|
|
1509
2448
|
}
|
|
1510
2449
|
|
|
2450
|
+
// src/ui/agent-chat-context-status.tsx
|
|
2451
|
+
var React9 = __toESM(require("react"), 1);
|
|
2452
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2453
|
+
var COMPACT_TOKENS = new Intl.NumberFormat("en-US", { notation: "compact" });
|
|
2454
|
+
var PERCENT = new Intl.NumberFormat("en-US", {
|
|
2455
|
+
style: "percent",
|
|
2456
|
+
maximumFractionDigits: 1
|
|
2457
|
+
});
|
|
2458
|
+
var EXACT_SOURCES = /* @__PURE__ */ new Set(["exact", "provider_usage"]);
|
|
2459
|
+
function contextStatusMetrics(contextWindow) {
|
|
2460
|
+
const maximum = Number(contextWindow?.max_tokens || 0);
|
|
2461
|
+
const input = Math.max(0, Number(contextWindow?.input_tokens || 0));
|
|
2462
|
+
const admissionInput = Math.max(0, Number(contextWindow?.admission_input_tokens ?? input));
|
|
2463
|
+
const usageRatio = Math.max(0, Math.min(1, Number(
|
|
2464
|
+
contextWindow?.usage_ratio ?? input / maximum
|
|
2465
|
+
)));
|
|
2466
|
+
const admissionRatio = Math.max(0, Math.min(1, Number(
|
|
2467
|
+
contextWindow?.admission_ratio ?? admissionInput / maximum
|
|
2468
|
+
)));
|
|
2469
|
+
return { maximum, input, admissionInput, usageRatio, admissionRatio };
|
|
2470
|
+
}
|
|
2471
|
+
function AgentChatContextStatus({
|
|
2472
|
+
className,
|
|
2473
|
+
contextWindow
|
|
2474
|
+
}) {
|
|
2475
|
+
const tooltipId = React9.useId();
|
|
2476
|
+
const [open, setOpen] = React9.useState(false);
|
|
2477
|
+
const { maximum, input, admissionInput, usageRatio, admissionRatio } = contextStatusMetrics(contextWindow);
|
|
2478
|
+
const percentage = Math.round(usageRatio * 100);
|
|
2479
|
+
const exact = EXACT_SOURCES.has(contextWindow?.source || "unknown");
|
|
2480
|
+
if (!Number.isFinite(maximum) || maximum <= 0) return null;
|
|
2481
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2482
|
+
"div",
|
|
2483
|
+
{
|
|
2484
|
+
className: cn("a24-context-status", className),
|
|
2485
|
+
onBlurCapture: (event) => {
|
|
2486
|
+
if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
2487
|
+
},
|
|
2488
|
+
onFocusCapture: () => setOpen(true),
|
|
2489
|
+
onMouseEnter: () => setOpen(true),
|
|
2490
|
+
onMouseLeave: () => setOpen(false),
|
|
2491
|
+
children: [
|
|
2492
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2493
|
+
"button",
|
|
2494
|
+
{
|
|
2495
|
+
"aria-describedby": open ? tooltipId : void 0,
|
|
2496
|
+
"aria-label": `Context window ${percentage}% used`,
|
|
2497
|
+
className: "a24-context-status__trigger",
|
|
2498
|
+
onKeyDown: (event) => {
|
|
2499
|
+
if (event.key === "Escape") setOpen(false);
|
|
2500
|
+
},
|
|
2501
|
+
type: "button",
|
|
2502
|
+
children: [
|
|
2503
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { "aria-hidden": "true", className: "a24-context-status__ring", viewBox: "0 0 24 24", children: [
|
|
2504
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("circle", { className: "a24-context-status__track", cx: "12", cy: "12", r: "10" }),
|
|
2505
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2506
|
+
"circle",
|
|
2507
|
+
{
|
|
2508
|
+
className: "a24-context-status__value",
|
|
2509
|
+
cx: "12",
|
|
2510
|
+
cy: "12",
|
|
2511
|
+
pathLength: "100",
|
|
2512
|
+
r: "10",
|
|
2513
|
+
strokeDasharray: `${percentage} 100`
|
|
2514
|
+
}
|
|
2515
|
+
)
|
|
2516
|
+
] }),
|
|
2517
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
2518
|
+
percentage,
|
|
2519
|
+
"%"
|
|
2520
|
+
] })
|
|
2521
|
+
]
|
|
2522
|
+
}
|
|
2523
|
+
),
|
|
2524
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "a24-context-status__popover", id: tooltipId, role: "tooltip", children: [
|
|
2525
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "a24-context-status__sr-only", children: "Context window" }),
|
|
2526
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("strong", { children: [
|
|
2527
|
+
PERCENT.format(usageRatio),
|
|
2528
|
+
" context used"
|
|
2529
|
+
] }),
|
|
2530
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
2531
|
+
exact ? "Input" : "Estimated input",
|
|
2532
|
+
": ",
|
|
2533
|
+
COMPACT_TOKENS.format(input),
|
|
2534
|
+
" / ",
|
|
2535
|
+
COMPACT_TOKENS.format(maximum),
|
|
2536
|
+
" tokens"
|
|
2537
|
+
] }),
|
|
2538
|
+
admissionInput !== input ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
2539
|
+
"Safety bound: ",
|
|
2540
|
+
COMPACT_TOKENS.format(admissionInput),
|
|
2541
|
+
" tokens (",
|
|
2542
|
+
PERCENT.format(admissionRatio),
|
|
2543
|
+
")"
|
|
2544
|
+
] }) : null
|
|
2545
|
+
] }) : null
|
|
2546
|
+
]
|
|
2547
|
+
}
|
|
2548
|
+
);
|
|
2549
|
+
}
|
|
2550
|
+
|
|
1511
2551
|
// src/ui/bubble.tsx
|
|
1512
2552
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
1513
2553
|
var import_react_slot2 = require("@radix-ui/react-slot");
|
|
1514
|
-
var
|
|
2554
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1515
2555
|
function BubbleGroup({ className, ...props }) {
|
|
1516
|
-
return /* @__PURE__ */ (0,
|
|
2556
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1517
2557
|
"div",
|
|
1518
2558
|
{
|
|
1519
2559
|
"data-slot": "bubble-group",
|
|
@@ -1547,7 +2587,7 @@ function Bubble({
|
|
|
1547
2587
|
className,
|
|
1548
2588
|
...props
|
|
1549
2589
|
}) {
|
|
1550
|
-
return /* @__PURE__ */ (0,
|
|
2590
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1551
2591
|
"div",
|
|
1552
2592
|
{
|
|
1553
2593
|
"data-slot": "bubble",
|
|
@@ -1564,7 +2604,7 @@ function BubbleContent({
|
|
|
1564
2604
|
...props
|
|
1565
2605
|
}) {
|
|
1566
2606
|
const Comp = asChild ? import_react_slot2.Slot : "div";
|
|
1567
|
-
return /* @__PURE__ */ (0,
|
|
2607
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1568
2608
|
Comp,
|
|
1569
2609
|
{
|
|
1570
2610
|
"data-slot": "bubble-content",
|
|
@@ -1601,7 +2641,7 @@ function BubbleReactions({
|
|
|
1601
2641
|
className,
|
|
1602
2642
|
...props
|
|
1603
2643
|
}) {
|
|
1604
|
-
return /* @__PURE__ */ (0,
|
|
2644
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1605
2645
|
"div",
|
|
1606
2646
|
{
|
|
1607
2647
|
"data-slot": "bubble-reactions",
|
|
@@ -1616,7 +2656,7 @@ function BubbleReactions({
|
|
|
1616
2656
|
// src/ui/marker.tsx
|
|
1617
2657
|
var import_class_variance_authority3 = require("class-variance-authority");
|
|
1618
2658
|
var import_react_slot3 = require("@radix-ui/react-slot");
|
|
1619
|
-
var
|
|
2659
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1620
2660
|
var markerVariants = (0, import_class_variance_authority3.cva)(
|
|
1621
2661
|
"group/marker relative flex min-h-4 w-full items-center gap-2 text-left text-sm text-muted-foreground [&_svg:not([class*='size-'])]:size-4 [a]:underline [a]:underline-offset-3 [a]:hover:text-foreground",
|
|
1622
2662
|
{
|
|
@@ -1636,7 +2676,7 @@ function Marker({
|
|
|
1636
2676
|
...props
|
|
1637
2677
|
}) {
|
|
1638
2678
|
const Comp = asChild ? import_react_slot3.Slot : "div";
|
|
1639
|
-
return /* @__PURE__ */ (0,
|
|
2679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1640
2680
|
Comp,
|
|
1641
2681
|
{
|
|
1642
2682
|
"data-slot": "marker",
|
|
@@ -1647,7 +2687,7 @@ function Marker({
|
|
|
1647
2687
|
);
|
|
1648
2688
|
}
|
|
1649
2689
|
function MarkerIcon({ className, ...props }) {
|
|
1650
|
-
return /* @__PURE__ */ (0,
|
|
2690
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1651
2691
|
"span",
|
|
1652
2692
|
{
|
|
1653
2693
|
"data-slot": "marker-icon",
|
|
@@ -1661,7 +2701,7 @@ function MarkerIcon({ className, ...props }) {
|
|
|
1661
2701
|
);
|
|
1662
2702
|
}
|
|
1663
2703
|
function MarkerContent({ className, ...props }) {
|
|
1664
|
-
return /* @__PURE__ */ (0,
|
|
2704
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1665
2705
|
"span",
|
|
1666
2706
|
{
|
|
1667
2707
|
"data-slot": "marker-content",
|
|
@@ -1675,7 +2715,7 @@ function MarkerContent({ className, ...props }) {
|
|
|
1675
2715
|
}
|
|
1676
2716
|
|
|
1677
2717
|
// src/ui/mcp-connect-required-card.tsx
|
|
1678
|
-
var
|
|
2718
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1679
2719
|
var STATUS_LABELS = {
|
|
1680
2720
|
pending: "Connect",
|
|
1681
2721
|
connecting: "Connecting",
|
|
@@ -1699,7 +2739,7 @@ function McpConnectRequiredCard({
|
|
|
1699
2739
|
const isBusy = loading || status === "connecting" || status === "resuming";
|
|
1700
2740
|
const isConnected = status === "connected";
|
|
1701
2741
|
const buttonDisabled = disabled || isBusy || isConnected || !onConnect;
|
|
1702
|
-
return /* @__PURE__ */ (0,
|
|
2742
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1703
2743
|
"div",
|
|
1704
2744
|
{
|
|
1705
2745
|
"data-agents24-mcp-connect-card": true,
|
|
@@ -1709,13 +2749,13 @@ function McpConnectRequiredCard({
|
|
|
1709
2749
|
className
|
|
1710
2750
|
),
|
|
1711
2751
|
...props,
|
|
1712
|
-
children: /* @__PURE__ */ (0,
|
|
1713
|
-
/* @__PURE__ */ (0,
|
|
1714
|
-
/* @__PURE__ */ (0,
|
|
1715
|
-
/* @__PURE__ */ (0,
|
|
1716
|
-
status === "error" && error ? /* @__PURE__ */ (0,
|
|
2752
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex min-w-0 items-start justify-between gap-3", children: [
|
|
2753
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "min-w-0", children: [
|
|
2754
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "truncate text-sm font-medium", children: label }),
|
|
2755
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "mt-1 text-sm text-muted-foreground", children: message || "Connect your account to continue." }),
|
|
2756
|
+
status === "error" && error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "mt-2 text-sm text-destructive", children: error }) : null
|
|
1717
2757
|
] }),
|
|
1718
|
-
/* @__PURE__ */ (0,
|
|
2758
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1719
2759
|
"button",
|
|
1720
2760
|
{
|
|
1721
2761
|
type: "button",
|
|
@@ -1732,14 +2772,87 @@ function McpConnectRequiredCard({
|
|
|
1732
2772
|
}
|
|
1733
2773
|
);
|
|
1734
2774
|
}
|
|
2775
|
+
|
|
2776
|
+
// src/ui/use-audio-recorder.ts
|
|
2777
|
+
var React10 = __toESM(require("react"), 1);
|
|
2778
|
+
var RECORDING_CANDIDATES = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4"];
|
|
2779
|
+
function recordingExtension(mimeType) {
|
|
2780
|
+
return mimeType.startsWith("audio/mp4") ? "m4a" : "webm";
|
|
2781
|
+
}
|
|
2782
|
+
function useAudioRecorder(onRecorded, options = {}) {
|
|
2783
|
+
const recorderRef = React10.useRef(null);
|
|
2784
|
+
const streamRef = React10.useRef(null);
|
|
2785
|
+
const onRecordedRef = React10.useRef(onRecorded);
|
|
2786
|
+
const onStreamChangeRef = React10.useRef(options.onStreamChange);
|
|
2787
|
+
onRecordedRef.current = onRecorded;
|
|
2788
|
+
onStreamChangeRef.current = options.onStreamChange;
|
|
2789
|
+
const [isRecording, setIsRecording] = React10.useState(false);
|
|
2790
|
+
const [error, setError] = React10.useState(null);
|
|
2791
|
+
const stop = React10.useCallback(() => recorderRef.current?.stop(), []);
|
|
2792
|
+
const start = React10.useCallback(async () => {
|
|
2793
|
+
setError(null);
|
|
2794
|
+
if (!navigator.mediaDevices?.getUserMedia || typeof MediaRecorder === "undefined") {
|
|
2795
|
+
setError("Audio recording is not supported in this browser.");
|
|
2796
|
+
return;
|
|
2797
|
+
}
|
|
2798
|
+
try {
|
|
2799
|
+
const mimeType = RECORDING_CANDIDATES.find((candidate) => MediaRecorder.isTypeSupported(candidate));
|
|
2800
|
+
if (!mimeType) {
|
|
2801
|
+
setError("Audio recording is not supported in this browser.");
|
|
2802
|
+
return;
|
|
2803
|
+
}
|
|
2804
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
2805
|
+
onStreamChangeRef.current?.(stream);
|
|
2806
|
+
const recorder = new MediaRecorder(stream, { mimeType });
|
|
2807
|
+
const chunks = [];
|
|
2808
|
+
recorder.ondataavailable = (event) => {
|
|
2809
|
+
if (event.data.size) chunks.push(event.data);
|
|
2810
|
+
};
|
|
2811
|
+
recorder.onstop = () => {
|
|
2812
|
+
const actualType = recorder.mimeType || "audio/webm";
|
|
2813
|
+
onRecordedRef.current(new File([new Blob(chunks, { type: actualType })], `recording-${Date.now()}.${recordingExtension(actualType)}`, { type: actualType }));
|
|
2814
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
2815
|
+
onStreamChangeRef.current?.(null);
|
|
2816
|
+
recorderRef.current = null;
|
|
2817
|
+
streamRef.current = null;
|
|
2818
|
+
setIsRecording(false);
|
|
2819
|
+
};
|
|
2820
|
+
recorderRef.current = recorder;
|
|
2821
|
+
streamRef.current = stream;
|
|
2822
|
+
recorder.start();
|
|
2823
|
+
setIsRecording(true);
|
|
2824
|
+
} catch {
|
|
2825
|
+
streamRef.current?.getTracks().forEach((track) => track.stop());
|
|
2826
|
+
onStreamChangeRef.current?.(null);
|
|
2827
|
+
setError("Microphone access is unavailable.");
|
|
2828
|
+
}
|
|
2829
|
+
}, []);
|
|
2830
|
+
React10.useEffect(() => () => {
|
|
2831
|
+
recorderRef.current?.stop();
|
|
2832
|
+
streamRef.current?.getTracks().forEach((track) => track.stop());
|
|
2833
|
+
onStreamChangeRef.current?.(null);
|
|
2834
|
+
}, []);
|
|
2835
|
+
return { error, isRecording, start, stop };
|
|
2836
|
+
}
|
|
1735
2837
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1736
2838
|
0 && (module.exports = {
|
|
2839
|
+
AgentChatActivityRow,
|
|
1737
2840
|
AgentChatComposer,
|
|
2841
|
+
AgentChatContextCompressionRow,
|
|
2842
|
+
AgentChatContextStatus,
|
|
1738
2843
|
AgentChatDefaultActions,
|
|
1739
2844
|
AgentChatMessage,
|
|
1740
|
-
|
|
2845
|
+
AgentChatModelTurnRow,
|
|
2846
|
+
AgentChatNodeActivityRow,
|
|
2847
|
+
AgentChatPart,
|
|
2848
|
+
AgentChatSubagentGroup,
|
|
2849
|
+
AgentChatToolGroup,
|
|
2850
|
+
AgentChatToolPart,
|
|
2851
|
+
AgentChatToolRow,
|
|
2852
|
+
AgentChatToolSession,
|
|
1741
2853
|
AgentChatUserMessageContent,
|
|
1742
2854
|
AgentResponseTimeline,
|
|
2855
|
+
AskUserInteraction,
|
|
1743
2856
|
Attachment,
|
|
1744
2857
|
AttachmentAction,
|
|
1745
2858
|
AttachmentActions,
|
|
@@ -1776,14 +2889,21 @@ function McpConnectRequiredCard({
|
|
|
1776
2889
|
MessageResponse,
|
|
1777
2890
|
ShadcnMessage,
|
|
1778
2891
|
ShadcnMessageContent,
|
|
2892
|
+
agentChatToolLabel,
|
|
1779
2893
|
attachmentMediaVariants,
|
|
1780
2894
|
attachmentVariants,
|
|
1781
2895
|
bubbleVariants,
|
|
1782
2896
|
cn,
|
|
2897
|
+
contextStatusMetrics,
|
|
1783
2898
|
hitlActionLabel,
|
|
1784
2899
|
hitlTitle,
|
|
2900
|
+
isAgentChatSubagent,
|
|
2901
|
+
isAgentChatToolRunning,
|
|
2902
|
+
latestRunningAgentChatToolId,
|
|
1785
2903
|
markerVariants,
|
|
2904
|
+
partitionAgentChatToolTimeline,
|
|
1786
2905
|
resolvedHitlLabel,
|
|
1787
|
-
shouldCollapseUserMessage
|
|
2906
|
+
shouldCollapseUserMessage,
|
|
2907
|
+
useAudioRecorder
|
|
1788
2908
|
});
|
|
1789
2909
|
//# sourceMappingURL=index.cjs.map
|