@agents24/chat-react 0.5.5 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +11 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +11 -6
- package/dist/index.js.map +1 -1
- package/dist/latest-thread-scroller.d.ts +2 -1
- package/dist/runtime/index.cjs +17 -11
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.js +17 -11
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/use-agent-chat-runtime.d.ts +7 -2
- package/dist/scaffold/components/chat/chat-composer.d.ts +2 -1
- package/dist/scaffold/components/chat/chat-message.d.ts +3 -1
- package/dist/scaffold/components/chat/turn-outline.d.ts +1 -1
- package/dist/scaffold/index.cjs +195 -154
- package/dist/scaffold/index.cjs.map +1 -1
- package/dist/scaffold/index.js +215 -168
- package/dist/scaffold/index.js.map +1 -1
- package/dist/styles.css +25 -6
- package/dist/ui/adapters.d.ts +14 -2
- package/dist/ui/agent-chat-composer.d.ts +2 -9
- package/dist/ui/agent-chat-message.d.ts +7 -1
- package/dist/ui/composer-attachments.d.ts +11 -0
- package/dist/ui/index.cjs +781 -389
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +766 -375
- package/dist/ui/index.js.map +1 -1
- package/package.json +4 -3
- package/scaffold/src/components/chat/chat-composer.tsx +43 -19
- package/scaffold/src/components/chat/chat-message.tsx +19 -10
- package/scaffold/src/components/chat/chat-shell.tsx +65 -34
- package/scaffold/src/components/chat/turn-outline.tsx +17 -59
- package/scaffold/src/components/ui/message-scroller.tsx +1 -1
- package/scaffold/src/components/ui/message.tsx +1 -1
- package/scaffold/src/components/ui/sidebar.tsx +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentClient, ClientBootstrap, HitlResponse, PortableUpload } from "@agents24/client";
|
|
2
2
|
import type { ContextCompression, ContextWindow } from "@agents24/client/protocol";
|
|
3
|
-
import { type AgentChatController, type ChatHitlPart } from "@agents24/react";
|
|
3
|
+
import { type AgentChatController, type ChatAttachment, type ChatHitlPart } from "@agents24/react";
|
|
4
4
|
import type { ChatMcpOauthCompletion } from "../types";
|
|
5
5
|
export type AgentChatRuntimeAgent = {
|
|
6
6
|
name: string;
|
|
@@ -16,7 +16,7 @@ export type AgentChatRuntimeAgentOption = {
|
|
|
16
16
|
id: string;
|
|
17
17
|
label: string;
|
|
18
18
|
};
|
|
19
|
-
export type AgentChatRuntimeViewState = "ready" | "loading" | "streaming" | "reconnecting" | "paused" | "cancelling" | "cancelled" | "offline" | "denied" | "quota" | "failed" | "expired";
|
|
19
|
+
export type AgentChatRuntimeViewState = "ready" | "loading" | "uploading" | "streaming" | "reconnecting" | "paused" | "cancelling" | "cancelled" | "offline" | "denied" | "quota" | "failed" | "expired";
|
|
20
20
|
export type AgentChatRuntimeConnectionState = "connected" | "connecting" | "reconnecting" | "offline" | "expired";
|
|
21
21
|
export type AgentChatThreadChangeReason = "created" | "opened" | "new" | "deleted";
|
|
22
22
|
export type AgentChatActiveThreadChange = {
|
|
@@ -32,6 +32,7 @@ export type AgentChatMcpAuthorizationCompletion = (input: {
|
|
|
32
32
|
export type AgentChatRuntimeSubmit = {
|
|
33
33
|
text: string;
|
|
34
34
|
files?: readonly PortableUpload[];
|
|
35
|
+
attachments?: ChatAttachment[];
|
|
35
36
|
};
|
|
36
37
|
export type AgentChatRuntimeHitlActionState = {
|
|
37
38
|
action: string;
|
|
@@ -79,6 +80,10 @@ export type AgentChatRuntime = {
|
|
|
79
80
|
openThread(threadId: string): Promise<void>;
|
|
80
81
|
operationError: unknown;
|
|
81
82
|
retryBootstrap(): Promise<void>;
|
|
83
|
+
resolveAttachmentContent(attachment: ChatAttachment, signal: AbortSignal): Promise<{
|
|
84
|
+
url: string;
|
|
85
|
+
validUntil: string | null;
|
|
86
|
+
}>;
|
|
82
87
|
state: AgentChatRuntimeViewState;
|
|
83
88
|
submit(input: AgentChatRuntimeSubmit): Promise<void>;
|
|
84
89
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AgentChatComposerFile } from "@agents24/chat-react/ui";
|
|
1
2
|
import { type AgentChatInputContract } from "@agents24/chat-react/runtime";
|
|
2
3
|
import type { ContextWindow } from "@agents24/client/protocol";
|
|
3
4
|
type ChatComposerProps = {
|
|
@@ -21,7 +22,7 @@ type ChatComposerProps = {
|
|
|
21
22
|
onModelChange: (modelId: string) => void;
|
|
22
23
|
onAgentChange: (agentId: string) => void;
|
|
23
24
|
onStop: () => void;
|
|
24
|
-
onSubmit: (text: string, files:
|
|
25
|
+
onSubmit: (text: string, files: AgentChatComposerFile[]) => Promise<void>;
|
|
25
26
|
utilityRow?: "inline" | "below";
|
|
26
27
|
};
|
|
27
28
|
export declare function ChatComposer({ inputContract, disabled, contextWindow, focusKey, forceExpanded, isCancelling, isRunning, agentId, agents, modelId, models, onModelChange, onAgentChange, onStop, onSubmit, utilityRow, }: ChatComposerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ChatHitlPart, ChatMessage as ChatMessageModel } from "@agents24/react";
|
|
2
2
|
import type { FeedbackReason, HitlResponse } from "@agents24/client";
|
|
3
3
|
import type { AgentChatRuntimeHitlActionState } from "@agents24/chat-react/runtime";
|
|
4
|
+
import { type ChatAttachmentContentResolver } from "@agents24/chat-react/ui";
|
|
4
5
|
import * as React from "react";
|
|
5
6
|
import type { Agents24ChatTimelineSlotProps } from "../../app";
|
|
6
7
|
type Props = {
|
|
@@ -16,6 +17,7 @@ type Props = {
|
|
|
16
17
|
comment?: string | null;
|
|
17
18
|
}) => Promise<void>;
|
|
18
19
|
Timeline?: React.ComponentType<Agents24ChatTimelineSlotProps>;
|
|
20
|
+
resolveAttachmentContent?: ChatAttachmentContentResolver;
|
|
19
21
|
};
|
|
20
|
-
export declare function ChatMessage({ allowFeedback, getHitlActionState, isLoading, message, onHitlAction, onRegenerate, onSetFeedback, Timeline, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export declare function ChatMessage({ allowFeedback, getHitlActionState, isLoading, message, onHitlAction, onRegenerate, onSetFeedback, resolveAttachmentContent, Timeline, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
21
23
|
export {};
|
package/dist/scaffold/index.cjs
CHANGED
|
@@ -39,11 +39,12 @@ module.exports = __toCommonJS(src_exports);
|
|
|
39
39
|
|
|
40
40
|
// scaffold/src/app.tsx
|
|
41
41
|
var import_runtime3 = require("@agents24/chat-react/runtime");
|
|
42
|
-
var
|
|
42
|
+
var import_react2 = require("@agents24/react");
|
|
43
43
|
|
|
44
44
|
// scaffold/src/components/chat/chat-shell.tsx
|
|
45
45
|
var import_runtime2 = require("@agents24/chat-react/runtime");
|
|
46
46
|
var import_lucide_react12 = require("lucide-react");
|
|
47
|
+
var React8 = __toESM(require("react"), 1);
|
|
47
48
|
|
|
48
49
|
// scaffold/src/components/chat/chat-composer.tsx
|
|
49
50
|
var import_lucide_react3 = require("lucide-react");
|
|
@@ -524,11 +525,20 @@ function ChatComposer({
|
|
|
524
525
|
const [attachmentError, setAttachmentError] = React2.useState(null);
|
|
525
526
|
const inputRef = React2.useRef(null);
|
|
526
527
|
const textareaRef = React2.useRef(null);
|
|
528
|
+
const filesRef = React2.useRef([]);
|
|
529
|
+
const inFlightFilesRef = React2.useRef([]);
|
|
527
530
|
const submittingRef = React2.useRef(false);
|
|
528
531
|
const draftRevisionRef = React2.useRef(0);
|
|
529
532
|
const attachmentMimeTypes = (0, import_runtime.inputMimeTypes)(inputContract);
|
|
530
533
|
const allowAttachments = attachmentMimeTypes.length > 0;
|
|
531
534
|
const recordingAllowed = inputContract.modalities.audio.recording_enabled;
|
|
535
|
+
React2.useEffect(() => {
|
|
536
|
+
filesRef.current = files;
|
|
537
|
+
}, [files]);
|
|
538
|
+
React2.useEffect(() => () => {
|
|
539
|
+
(0, import_ui.revokeAgentChatComposerFiles)(filesRef.current);
|
|
540
|
+
(0, import_ui.revokeAgentChatComposerFiles)(inFlightFilesRef.current);
|
|
541
|
+
}, []);
|
|
532
542
|
React2.useEffect(() => {
|
|
533
543
|
if (disabled || isRunning) return;
|
|
534
544
|
const frame = window.requestAnimationFrame(() => textareaRef.current?.focus({ preventScroll: true }));
|
|
@@ -536,14 +546,14 @@ function ChatComposer({
|
|
|
536
546
|
}, [disabled, focusKey, isRunning]);
|
|
537
547
|
const addRecording = React2.useCallback((file) => {
|
|
538
548
|
draftRevisionRef.current += 1;
|
|
539
|
-
setFiles((current) => [...current, file]);
|
|
549
|
+
setFiles((current) => [...current, (0, import_ui.createAgentChatComposerFile)(file)]);
|
|
540
550
|
}, []);
|
|
541
551
|
const recorder = (0, import_ui.useAudioRecorder)(addRecording);
|
|
542
552
|
const isExpanded = forceExpanded || text.includes("\n") || text.length > 62;
|
|
543
553
|
const validationError = (0, import_runtime.validateAgentChatSubmission)(
|
|
544
554
|
inputContract,
|
|
545
555
|
text,
|
|
546
|
-
files.map((file) => ({ data: file, mediaType: file.
|
|
556
|
+
files.map((file) => ({ data: file.source, mediaType: file.mediaType }))
|
|
547
557
|
);
|
|
548
558
|
const selectedAgent = agents.find((item) => item.id === agentId);
|
|
549
559
|
const selectedModel = models.find((item) => item.id === modelId);
|
|
@@ -591,16 +601,23 @@ function ChatComposer({
|
|
|
591
601
|
const clearedRevision = draftRevisionRef.current + 1;
|
|
592
602
|
draftRevisionRef.current = clearedRevision;
|
|
593
603
|
submittingRef.current = true;
|
|
604
|
+
inFlightFilesRef.current = selectedFiles;
|
|
594
605
|
setText("");
|
|
595
606
|
setFiles([]);
|
|
596
607
|
textareaRef.current?.focus();
|
|
597
608
|
try {
|
|
598
609
|
await onSubmit(value, selectedFiles);
|
|
610
|
+
(0, import_ui.revokeAgentChatComposerFiles)(selectedFiles);
|
|
611
|
+
inFlightFilesRef.current = [];
|
|
599
612
|
} catch {
|
|
600
613
|
if (draftRevisionRef.current === clearedRevision) {
|
|
601
614
|
draftRevisionRef.current += 1;
|
|
602
615
|
setText(value);
|
|
603
616
|
setFiles(selectedFiles);
|
|
617
|
+
inFlightFilesRef.current = [];
|
|
618
|
+
} else {
|
|
619
|
+
(0, import_ui.revokeAgentChatComposerFiles)(selectedFiles);
|
|
620
|
+
inFlightFilesRef.current = [];
|
|
604
621
|
}
|
|
605
622
|
} finally {
|
|
606
623
|
submittingRef.current = false;
|
|
@@ -612,13 +629,21 @@ function ChatComposer({
|
|
|
612
629
|
className: "mx-auto w-full max-w-3xl px-4 pb-[max(1rem,env(safe-area-inset-bottom))] sm:px-6",
|
|
613
630
|
"data-agents24-chat-composer": "",
|
|
614
631
|
children: [
|
|
615
|
-
allowAttachments && files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mb-2
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
632
|
+
allowAttachments && files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mb-2 min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
633
|
+
import_ui.ChatAttachmentRows,
|
|
634
|
+
{
|
|
635
|
+
attachments: files,
|
|
636
|
+
onRemove: (attachment) => {
|
|
637
|
+
if (!attachment.id) return;
|
|
638
|
+
draftRevisionRef.current += 1;
|
|
639
|
+
setFiles((current) => {
|
|
640
|
+
const removed = current.find((file) => file.id === attachment.id);
|
|
641
|
+
if (removed) (0, import_ui.revokeAgentChatComposerFiles)([removed]);
|
|
642
|
+
return current.filter((file) => file.id !== attachment.id);
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
) }),
|
|
622
647
|
attachmentError || recorder.error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "mb-2 text-xs text-destructive", role: "alert", children: attachmentError || recorder.error }) : null,
|
|
623
648
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
624
649
|
"div",
|
|
@@ -642,7 +667,7 @@ function ChatComposer({
|
|
|
642
667
|
const selected = Array.from(event.target.files ?? []);
|
|
643
668
|
const accepted = selected.filter((file) => attachmentMimeTypes.includes((0, import_runtime.canonicalInputMimeType)(file.type)));
|
|
644
669
|
draftRevisionRef.current += 1;
|
|
645
|
-
setFiles((current) => [...current, ...accepted]);
|
|
670
|
+
setFiles((current) => [...current, ...accepted.map(import_ui.createAgentChatComposerFile)]);
|
|
646
671
|
setAttachmentError(
|
|
647
672
|
accepted.length === selected.length ? null : "One or more selected file types are not supported by this Agent."
|
|
648
673
|
);
|
|
@@ -1116,7 +1141,7 @@ function MessageFooter({ className, ...props }) {
|
|
|
1116
1141
|
{
|
|
1117
1142
|
"data-slot": "message-footer",
|
|
1118
1143
|
className: cn(
|
|
1119
|
-
"flex max-w-full min-w-0 items-center
|
|
1144
|
+
"flex max-w-full min-w-0 items-center pl-3.5 text-xs font-medium text-muted-foreground group-has-data-[variant=ghost]/message:px-0 group-data-[align=end]/message:justify-end",
|
|
1120
1145
|
className
|
|
1121
1146
|
),
|
|
1122
1147
|
...props
|
|
@@ -1134,17 +1159,19 @@ function ChatMessage({
|
|
|
1134
1159
|
onHitlAction,
|
|
1135
1160
|
onRegenerate,
|
|
1136
1161
|
onSetFeedback,
|
|
1162
|
+
resolveAttachmentContent,
|
|
1137
1163
|
Timeline
|
|
1138
1164
|
}) {
|
|
1139
1165
|
const isUser = message.role === "user";
|
|
1140
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Message, { align: isUser ? "end" : "start", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(MessageContent, { children: [
|
|
1141
|
-
isUser && message.attachments?.length ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1142
|
-
import_ui3.
|
|
1166
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Message, { align: isUser ? "end" : "start", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(MessageContent, { className: isUser ? "gap-0" : void 0, children: [
|
|
1167
|
+
isUser && message.attachments?.length ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1168
|
+
import_ui3.ChatAttachmentRows,
|
|
1143
1169
|
{
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1170
|
+
attachments: message.attachments,
|
|
1171
|
+
className: "mb-2",
|
|
1172
|
+
resolveContent: resolveAttachmentContent
|
|
1173
|
+
}
|
|
1174
|
+
) : null,
|
|
1148
1175
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Bubble, { variant: isUser ? "secondary" : "ghost", align: isUser ? "end" : "start", className: isUser ? "max-w-[min(75%,42rem)]" : "max-w-full overflow-visible", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(BubbleContent, { className: isUser ? "px-4 py-2.5" : "w-full overflow-visible", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1149
1176
|
MessageParts,
|
|
1150
1177
|
{
|
|
@@ -1155,6 +1182,17 @@ function ChatMessage({
|
|
|
1155
1182
|
Timeline
|
|
1156
1183
|
}
|
|
1157
1184
|
) }) }),
|
|
1185
|
+
isUser && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ui3.AgentChatUserMessageActionRow, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1186
|
+
import_ui3.AgentChatDefaultActions,
|
|
1187
|
+
{
|
|
1188
|
+
handlers: {
|
|
1189
|
+
onCopy: (content) => {
|
|
1190
|
+
void navigator.clipboard.writeText(content).catch(() => void 0);
|
|
1191
|
+
}
|
|
1192
|
+
},
|
|
1193
|
+
message
|
|
1194
|
+
}
|
|
1195
|
+
) }),
|
|
1158
1196
|
!isUser && message.isFinal !== false && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MessageFooter, { className: "gap-1 opacity-70 transition-opacity group-hover/message:opacity-100", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1159
1197
|
import_ui3.AgentChatDefaultActions,
|
|
1160
1198
|
{
|
|
@@ -1557,7 +1595,7 @@ function Sidebar({
|
|
|
1557
1595
|
className: cn(
|
|
1558
1596
|
"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear data-[side=left]:left-0 data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] data-[side=right]:right-0 data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] md:flex",
|
|
1559
1597
|
// Adjust the padding for floating and inset variants.
|
|
1560
|
-
variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
|
|
1598
|
+
variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" : "border-border/50 group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
|
|
1561
1599
|
className
|
|
1562
1600
|
),
|
|
1563
1601
|
...props,
|
|
@@ -1956,20 +1994,60 @@ function ThreadSidebar({ activeThreadId, hasMore, identity, isLoading, isLoading
|
|
|
1956
1994
|
}
|
|
1957
1995
|
|
|
1958
1996
|
// scaffold/src/components/chat/turn-outline.tsx
|
|
1959
|
-
var
|
|
1997
|
+
var import_chat_react = require("@agents24/chat-react");
|
|
1998
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1999
|
+
function turnsFromMessages(messages) {
|
|
2000
|
+
return messages.reduce((turns, message) => {
|
|
2001
|
+
if (message.role === "user") {
|
|
2002
|
+
turns.push({
|
|
2003
|
+
id: message.id,
|
|
2004
|
+
label: message.content.trim() || `Turn ${turns.length + 1}`,
|
|
2005
|
+
messageIds: [message.id],
|
|
2006
|
+
responsePreview: ""
|
|
2007
|
+
});
|
|
2008
|
+
} else if (turns.length) {
|
|
2009
|
+
const turn = turns[turns.length - 1];
|
|
2010
|
+
turn.messageIds?.push(message.id);
|
|
2011
|
+
if (!turn.responsePreview) turn.responsePreview = message.content.trim();
|
|
2012
|
+
}
|
|
2013
|
+
return turns;
|
|
2014
|
+
}, []);
|
|
2015
|
+
}
|
|
2016
|
+
function TurnOutline({ messages }) {
|
|
2017
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2018
|
+
import_chat_react.LatestThreadScroller.Outline,
|
|
2019
|
+
{
|
|
2020
|
+
items: turnsFromMessages(messages),
|
|
2021
|
+
minSideGutterForRail: 0,
|
|
2022
|
+
side: "left",
|
|
2023
|
+
verticalOffset: "3.5rem"
|
|
2024
|
+
}
|
|
2025
|
+
);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
// scaffold/src/components/chat/timeline-loading.ts
|
|
2029
|
+
function isScaffoldTimelineLoading({
|
|
2030
|
+
activeRunId,
|
|
2031
|
+
message,
|
|
2032
|
+
runState,
|
|
2033
|
+
streamingMessageId
|
|
2034
|
+
}) {
|
|
2035
|
+
if (runState !== "streaming" && runState !== "reconnecting") return false;
|
|
2036
|
+
return message.id === streamingMessageId || Boolean(message.runId && message.runId === activeRunId);
|
|
2037
|
+
}
|
|
1960
2038
|
|
|
1961
2039
|
// scaffold/src/components/ui/message-scroller.tsx
|
|
1962
2040
|
var import_message_scroller = require("@shadcn/react/message-scroller");
|
|
1963
2041
|
var import_lucide_react11 = require("lucide-react");
|
|
1964
|
-
var
|
|
2042
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1965
2043
|
function MessageScrollerProvider(props) {
|
|
1966
|
-
return /* @__PURE__ */ (0,
|
|
2044
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_message_scroller.MessageScroller.Provider, { ...props });
|
|
1967
2045
|
}
|
|
1968
2046
|
function MessageScroller({
|
|
1969
2047
|
className,
|
|
1970
2048
|
...props
|
|
1971
2049
|
}) {
|
|
1972
|
-
return /* @__PURE__ */ (0,
|
|
2050
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1973
2051
|
import_message_scroller.MessageScroller.Root,
|
|
1974
2052
|
{
|
|
1975
2053
|
"data-slot": "message-scroller",
|
|
@@ -1985,7 +2063,7 @@ function MessageScrollerViewport({
|
|
|
1985
2063
|
className,
|
|
1986
2064
|
...props
|
|
1987
2065
|
}) {
|
|
1988
|
-
return /* @__PURE__ */ (0,
|
|
2066
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1989
2067
|
import_message_scroller.MessageScroller.Viewport,
|
|
1990
2068
|
{
|
|
1991
2069
|
"data-slot": "message-scroller-viewport",
|
|
@@ -2001,11 +2079,11 @@ function MessageScrollerContent({
|
|
|
2001
2079
|
className,
|
|
2002
2080
|
...props
|
|
2003
2081
|
}) {
|
|
2004
|
-
return /* @__PURE__ */ (0,
|
|
2082
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2005
2083
|
import_message_scroller.MessageScroller.Content,
|
|
2006
2084
|
{
|
|
2007
2085
|
"data-slot": "message-scroller-content",
|
|
2008
|
-
className: cn("flex h-max min-h-full flex-col gap-
|
|
2086
|
+
className: cn("flex h-max min-h-full flex-col gap-3", className),
|
|
2009
2087
|
...props
|
|
2010
2088
|
}
|
|
2011
2089
|
);
|
|
@@ -2015,7 +2093,7 @@ function MessageScrollerItem({
|
|
|
2015
2093
|
scrollAnchor = false,
|
|
2016
2094
|
...props
|
|
2017
2095
|
}) {
|
|
2018
|
-
return /* @__PURE__ */ (0,
|
|
2096
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2019
2097
|
import_message_scroller.MessageScroller.Item,
|
|
2020
2098
|
{
|
|
2021
2099
|
"data-slot": "message-scroller-item",
|
|
@@ -2037,7 +2115,7 @@ function MessageScrollerButton({
|
|
|
2037
2115
|
size = "icon-sm",
|
|
2038
2116
|
...props
|
|
2039
2117
|
}) {
|
|
2040
|
-
return /* @__PURE__ */ (0,
|
|
2118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2041
2119
|
import_message_scroller.MessageScroller.Button,
|
|
2042
2120
|
{
|
|
2043
2121
|
"data-slot": "message-scroller-button",
|
|
@@ -2049,86 +2127,19 @@ function MessageScrollerButton({
|
|
|
2049
2127
|
"absolute inset-s-1/2 -translate-x-1/2 border-border bg-background text-foreground transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180",
|
|
2050
2128
|
className
|
|
2051
2129
|
),
|
|
2052
|
-
render: render ?? /* @__PURE__ */ (0,
|
|
2130
|
+
render: render ?? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Button, { variant, size }),
|
|
2053
2131
|
...props,
|
|
2054
|
-
children: children ?? /* @__PURE__ */ (0,
|
|
2055
|
-
/* @__PURE__ */ (0,
|
|
2132
|
+
children: children ?? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
2133
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2056
2134
|
import_lucide_react11.ArrowDownIcon,
|
|
2057
2135
|
{}
|
|
2058
2136
|
),
|
|
2059
|
-
/* @__PURE__ */ (0,
|
|
2137
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "sr-only", children: direction === "end" ? "Scroll to end" : "Scroll to start" })
|
|
2060
2138
|
] })
|
|
2061
2139
|
}
|
|
2062
2140
|
);
|
|
2063
2141
|
}
|
|
2064
2142
|
|
|
2065
|
-
// scaffold/src/components/chat/turn-outline.tsx
|
|
2066
|
-
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2067
|
-
function turnsFromMessages(messages) {
|
|
2068
|
-
return messages.reduce((turns, message) => {
|
|
2069
|
-
if (message.role === "user") {
|
|
2070
|
-
turns.push({ id: message.id, label: message.content.trim() || `Turn ${turns.length + 1}`, messageIds: [message.id], response: "" });
|
|
2071
|
-
} else if (turns.length) {
|
|
2072
|
-
const turn = turns[turns.length - 1];
|
|
2073
|
-
turn.messageIds.push(message.id);
|
|
2074
|
-
if (!turn.response) turn.response = message.content.trim();
|
|
2075
|
-
}
|
|
2076
|
-
return turns;
|
|
2077
|
-
}, []);
|
|
2078
|
-
}
|
|
2079
|
-
function TurnOutline({ messages }) {
|
|
2080
|
-
const turns = turnsFromMessages(messages);
|
|
2081
|
-
const { scrollToMessage } = (0, import_message_scroller.useMessageScroller)();
|
|
2082
|
-
const { currentAnchorId, visibleMessageIds } = (0, import_message_scroller.useMessageScrollerVisibility)();
|
|
2083
|
-
const visible = new Set(visibleMessageIds);
|
|
2084
|
-
const [hoveredIndex, setHoveredIndex] = (0, import_react2.useState)(null);
|
|
2085
|
-
const focusIndex = hoveredIndex ?? -1;
|
|
2086
|
-
if (turns.length < 2) return null;
|
|
2087
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("nav", { "aria-label": "Transcript outline", className: "pointer-events-none absolute end-2 top-1/2 z-20 hidden max-h-72 w-14 -translate-y-1/2 md:block xl:end-5", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "pointer-events-auto flex flex-col items-end gap-0.5 py-2", children: turns.map((turn, index) => {
|
|
2088
|
-
const active = turn.messageIds.some((id) => visible.has(id) || currentAnchorId === id);
|
|
2089
|
-
const distance = focusIndex >= 0 ? Math.abs(index - focusIndex) : Number.POSITIVE_INFINITY;
|
|
2090
|
-
const barWidth = focusIndex < 0 ? 12 : distance === 0 ? 50 : distance === 1 ? 36 : distance === 2 ? 23 : 10;
|
|
2091
|
-
const barOpacity = focusIndex < 0 ? active ? 1 : 0.4 : distance === 0 ? 1 : distance === 1 ? 0.78 : distance === 2 ? 0.58 : 0.36;
|
|
2092
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(Tooltip, { children: [
|
|
2093
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2094
|
-
"button",
|
|
2095
|
-
{
|
|
2096
|
-
type: "button",
|
|
2097
|
-
"aria-label": `Jump to ${turn.label}`,
|
|
2098
|
-
className: "group relative flex h-2 w-14 items-center justify-end outline-none after:pointer-events-auto after:absolute after:-inset-y-0.5 after:inset-x-0 after:content-['']",
|
|
2099
|
-
onBlur: () => setHoveredIndex(null),
|
|
2100
|
-
onFocus: () => setHoveredIndex(index),
|
|
2101
|
-
onMouseEnter: () => setHoveredIndex(index),
|
|
2102
|
-
onMouseLeave: () => setHoveredIndex(null),
|
|
2103
|
-
onClick: () => scrollToMessage(turn.id, { align: "start", behavior: "smooth" }),
|
|
2104
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2105
|
-
"span",
|
|
2106
|
-
{
|
|
2107
|
-
className: cn("h-0.5 rounded-full bg-muted-foreground/40 transition-[width,background-color,opacity] duration-150 ease-out group-hover:bg-foreground group-focus-visible:bg-foreground", active && "bg-foreground"),
|
|
2108
|
-
style: { opacity: barOpacity, width: barWidth }
|
|
2109
|
-
}
|
|
2110
|
-
)
|
|
2111
|
-
}
|
|
2112
|
-
) }),
|
|
2113
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(TooltipContent, { side: "left", className: "w-64 flex-col items-stretch gap-0 overflow-hidden p-3", children: [
|
|
2114
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "line-clamp-2 max-w-full wrap-break-word text-sm font-medium", children: turn.label }),
|
|
2115
|
-
turn.response && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "mt-1 line-clamp-2 max-w-full wrap-break-word text-xs opacity-70", children: turn.response })
|
|
2116
|
-
] })
|
|
2117
|
-
] }, turn.id);
|
|
2118
|
-
}) }) });
|
|
2119
|
-
}
|
|
2120
|
-
|
|
2121
|
-
// scaffold/src/components/chat/timeline-loading.ts
|
|
2122
|
-
function isScaffoldTimelineLoading({
|
|
2123
|
-
activeRunId,
|
|
2124
|
-
message,
|
|
2125
|
-
runState,
|
|
2126
|
-
streamingMessageId
|
|
2127
|
-
}) {
|
|
2128
|
-
if (runState !== "streaming" && runState !== "reconnecting") return false;
|
|
2129
|
-
return message.id === streamingMessageId || Boolean(message.runId && message.runId === activeRunId);
|
|
2130
|
-
}
|
|
2131
|
-
|
|
2132
2143
|
// scaffold/src/components/chat/chat-shell.tsx
|
|
2133
2144
|
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2134
2145
|
var LOADING_INPUT_CONTRACT = {
|
|
@@ -2179,11 +2190,25 @@ function ChatShell({
|
|
|
2179
2190
|
sidebar
|
|
2180
2191
|
}) {
|
|
2181
2192
|
const { controller } = runtime;
|
|
2182
|
-
const isRunning = controller.runState === "streaming" || controller.runState === "reconnecting" || controller.runState === "paused" || controller.runState === "cancelling"
|
|
2193
|
+
const isRunning = controller.runState === "streaming" || controller.runState === "reconnecting" || controller.runState === "paused" || controller.runState === "cancelling";
|
|
2194
|
+
const isUploading = controller.runState === "uploading" || runtime.isUploading;
|
|
2183
2195
|
const isCancelling = controller.runState === "cancelling";
|
|
2184
2196
|
const activeTitle = controller.threads.find((thread) => thread.id === controller.activeThreadId)?.title;
|
|
2185
2197
|
const hasBlockingError = Boolean(runtime.fatalError && controller.messages.length === 0);
|
|
2186
2198
|
const isEmptyState = controller.activeThreadId === null && controller.messages.length === 0 && !hasBlockingError;
|
|
2199
|
+
const composerOverlayRef = React8.useRef(null);
|
|
2200
|
+
const [composerOverlayHeight, setComposerOverlayHeight] = React8.useState(192);
|
|
2201
|
+
React8.useEffect(() => {
|
|
2202
|
+
const overlay = composerOverlayRef.current;
|
|
2203
|
+
if (!overlay || isEmptyState) return;
|
|
2204
|
+
const updateHeight = () => {
|
|
2205
|
+
setComposerOverlayHeight(Math.ceil(overlay.getBoundingClientRect().height));
|
|
2206
|
+
};
|
|
2207
|
+
updateHeight();
|
|
2208
|
+
const resizeObserver = new ResizeObserver(updateHeight);
|
|
2209
|
+
resizeObserver.observe(overlay);
|
|
2210
|
+
return () => resizeObserver.disconnect();
|
|
2211
|
+
}, [isEmptyState]);
|
|
2187
2212
|
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
2188
2213
|
SidebarProvider,
|
|
2189
2214
|
{
|
|
@@ -2211,7 +2236,7 @@ function ChatShell({
|
|
|
2211
2236
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
2212
2237
|
"header",
|
|
2213
2238
|
{
|
|
2214
|
-
className: "flex h-12 shrink-0 items-center gap-2 border-b border-border/
|
|
2239
|
+
className: "flex h-12 shrink-0 items-center gap-2 border-b border-border/50 px-3 sm:px-4",
|
|
2215
2240
|
"data-agents24-chat-header": "",
|
|
2216
2241
|
children: [
|
|
2217
2242
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CollapsedHeaderActions, { onNew: runtime.newThread }),
|
|
@@ -2235,7 +2260,7 @@ function ChatShell({
|
|
|
2235
2260
|
{
|
|
2236
2261
|
inputContract: runtime.inputContract || LOADING_INPUT_CONTRACT,
|
|
2237
2262
|
contextWindow: runtime.contextWindow,
|
|
2238
|
-
disabled: runtime.isBootstrapping || runtime.isChangingAgent,
|
|
2263
|
+
disabled: runtime.isBootstrapping || runtime.isChangingAgent || isUploading,
|
|
2239
2264
|
focusKey: controller.activeThreadId,
|
|
2240
2265
|
forceExpanded: true,
|
|
2241
2266
|
isCancelling,
|
|
@@ -2254,25 +2279,27 @@ function ChatShell({
|
|
|
2254
2279
|
onSubmit: (text, files) => runtime.submit({
|
|
2255
2280
|
text,
|
|
2256
2281
|
files: files.map((file) => ({
|
|
2257
|
-
data: file,
|
|
2258
|
-
mediaType: file.
|
|
2259
|
-
name: file.
|
|
2260
|
-
}))
|
|
2282
|
+
data: file.source,
|
|
2283
|
+
mediaType: file.mediaType,
|
|
2284
|
+
name: file.filename
|
|
2285
|
+
})),
|
|
2286
|
+
attachments: files
|
|
2261
2287
|
})
|
|
2262
2288
|
}
|
|
2263
2289
|
)
|
|
2264
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime25.
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2290
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
2291
|
+
MessageScrollerProvider,
|
|
2292
|
+
{
|
|
2293
|
+
autoScroll: true,
|
|
2294
|
+
defaultScrollPosition: "last-anchor",
|
|
2295
|
+
scrollPreviousItemPeek: 64,
|
|
2296
|
+
children: [
|
|
2297
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(MessageScroller, { className: "relative min-h-0 flex-1", children: [
|
|
2272
2298
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(MessageScrollerViewport, { preserveScrollOnPrepend: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
2273
2299
|
MessageScrollerContent,
|
|
2274
2300
|
{
|
|
2275
|
-
className: "mx-auto w-full max-w-3xl gap-
|
|
2301
|
+
className: "mx-auto w-full max-w-3xl gap-3 px-4 pt-8 pb-0 sm:px-6 sm:pt-12",
|
|
2302
|
+
style: { paddingBottom: composerOverlayHeight + 72 },
|
|
2276
2303
|
children: [
|
|
2277
2304
|
controller.hasOlderTurns && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Button, { className: "self-center", variant: "ghost", size: "sm", disabled: controller.isLoadingOlder, onClick: () => {
|
|
2278
2305
|
void controller.loadOlder().catch(() => void 0);
|
|
@@ -2310,6 +2337,7 @@ function ChatShell({
|
|
|
2310
2337
|
onHitlAction: runtime.onHitlAction,
|
|
2311
2338
|
onRegenerate: () => controller.regenerate(message),
|
|
2312
2339
|
onSetFeedback: (input) => controller.setFeedback(message, input),
|
|
2340
|
+
resolveAttachmentContent: runtime.resolveAttachmentContent,
|
|
2313
2341
|
Timeline: components?.Timeline
|
|
2314
2342
|
}
|
|
2315
2343
|
)
|
|
@@ -2319,43 +2347,56 @@ function ChatShell({
|
|
|
2319
2347
|
]
|
|
2320
2348
|
}
|
|
2321
2349
|
) }),
|
|
2322
|
-
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TurnOutline, { messages: controller.messages })
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2350
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TurnOutline, { messages: controller.messages })
|
|
2351
|
+
] }),
|
|
2352
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
2353
|
+
"div",
|
|
2354
|
+
{
|
|
2355
|
+
ref: composerOverlayRef,
|
|
2356
|
+
className: "pointer-events-none absolute inset-x-0 bottom-0 z-30 overflow-visible pt-10",
|
|
2357
|
+
style: {
|
|
2358
|
+
background: "linear-gradient(to bottom, transparent 0%, color-mix(in oklch, var(--background) 85%, transparent) 45%, var(--background) 65%, var(--background) 100%)"
|
|
2359
|
+
},
|
|
2360
|
+
children: [
|
|
2361
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "pointer-events-auto absolute inset-x-0 top-0 flex -translate-y-full justify-center pb-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(MessageScrollerButton, { className: "!relative !inset-auto !translate-x-0 rtl:!translate-x-0" }) }),
|
|
2362
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "pointer-events-auto", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
2363
|
+
ChatComposer,
|
|
2364
|
+
{
|
|
2365
|
+
inputContract: runtime.inputContract || LOADING_INPUT_CONTRACT,
|
|
2366
|
+
contextWindow: runtime.contextWindow,
|
|
2367
|
+
disabled: runtime.isBootstrapping || runtime.isChangingAgent || hasBlockingError || isUploading,
|
|
2368
|
+
focusKey: controller.activeThreadId,
|
|
2369
|
+
isCancelling,
|
|
2370
|
+
isRunning,
|
|
2371
|
+
agentId: runtime.agentId,
|
|
2372
|
+
agents: runtime.agents,
|
|
2373
|
+
onAgentChange: (agentId) => {
|
|
2374
|
+
void runtime.changeAgent(agentId);
|
|
2375
|
+
},
|
|
2376
|
+
onStop: () => {
|
|
2377
|
+
void controller.cancelRun().catch(() => void 0);
|
|
2378
|
+
},
|
|
2379
|
+
modelId: runtime.modelId,
|
|
2380
|
+
models: runtime.models,
|
|
2381
|
+
onModelChange: runtime.changeModel,
|
|
2382
|
+
onSubmit: (text, files) => runtime.submit({
|
|
2383
|
+
text,
|
|
2384
|
+
files: files.map((file) => ({
|
|
2385
|
+
data: file.source,
|
|
2386
|
+
mediaType: file.mediaType,
|
|
2387
|
+
name: file.filename
|
|
2388
|
+
})),
|
|
2389
|
+
attachments: files
|
|
2390
|
+
}),
|
|
2391
|
+
utilityRow: "below"
|
|
2392
|
+
}
|
|
2393
|
+
) })
|
|
2394
|
+
]
|
|
2395
|
+
}
|
|
2396
|
+
)
|
|
2397
|
+
]
|
|
2398
|
+
}
|
|
2399
|
+
) })
|
|
2359
2400
|
]
|
|
2360
2401
|
}
|
|
2361
2402
|
)
|
|
@@ -2384,7 +2425,7 @@ function RuntimeChat({
|
|
|
2384
2425
|
}
|
|
2385
2426
|
function App(props) {
|
|
2386
2427
|
const identity = props.identity || GUEST_CHAT_IDENTITY;
|
|
2387
|
-
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2428
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react2.Agents24Provider, { client: props.client, createAbortController: createBrowserAbortController, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(RuntimeChat, { ...props }, identity.state) });
|
|
2388
2429
|
}
|
|
2389
2430
|
|
|
2390
2431
|
// scaffold/src/index.tsx
|