create-agents24-app 0.2.13 → 0.2.15
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/scaffold/src/components/chat/chat-composer.tsx +25 -26
- package/dist/scaffold/src/components/chat/chat-message.tsx +7 -2
- package/dist/scaffold/src/components/chat/chat-shell.tsx +52 -69
- package/dist/scaffold-manifest.json +1 -2
- package/package.json +2 -2
- package/versions.json +4 -4
- package/dist/scaffold/src/components/ui/message-scroller.tsx +0 -129
|
@@ -3,9 +3,11 @@ import * as React from "react"
|
|
|
3
3
|
import {
|
|
4
4
|
AgentChatContextStatus,
|
|
5
5
|
ChatAttachmentRows,
|
|
6
|
+
chatComposerAction,
|
|
6
7
|
createAgentChatComposerFile,
|
|
7
8
|
revokeAgentChatComposerFiles,
|
|
8
9
|
useAudioRecorder,
|
|
10
|
+
useChatComposerFocus,
|
|
9
11
|
type AgentChatComposerFile,
|
|
10
12
|
} from "@agents24/chat-react/ui"
|
|
11
13
|
import { canonicalInputMimeType, inputMimeTypes, validateAgentChatSubmission, type AgentChatInputContract } from "@agents24/chat-react/runtime"
|
|
@@ -37,6 +39,7 @@ type ChatComposerProps = {
|
|
|
37
39
|
onAgentChange: (agentId: string) => void
|
|
38
40
|
onStop: () => void
|
|
39
41
|
onSubmit: (text: string, files: AgentChatComposerFile[]) => Promise<void>
|
|
42
|
+
restoredDraft?: { revision: number; text: string; files: AgentChatComposerFile[] } | null
|
|
40
43
|
utilityRow?: "inline" | "below"
|
|
41
44
|
}
|
|
42
45
|
|
|
@@ -56,6 +59,7 @@ export function ChatComposer({
|
|
|
56
59
|
onAgentChange,
|
|
57
60
|
onStop,
|
|
58
61
|
onSubmit,
|
|
62
|
+
restoredDraft,
|
|
59
63
|
utilityRow = "inline",
|
|
60
64
|
}: ChatComposerProps) {
|
|
61
65
|
const [text, setText] = React.useState("")
|
|
@@ -77,11 +81,13 @@ export function ChatComposer({
|
|
|
77
81
|
revokeAgentChatComposerFiles(filesRef.current)
|
|
78
82
|
revokeAgentChatComposerFiles(inFlightFilesRef.current)
|
|
79
83
|
}, [])
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
const focusComposer = useChatComposerFocus({ textareaRef, disabled: Boolean(disabled), focusKey, restoredDraft,
|
|
85
|
+
onRestore: (draft) => {
|
|
86
|
+
draftRevisionRef.current += 1
|
|
87
|
+
revokeAgentChatComposerFiles(filesRef.current)
|
|
88
|
+
setText(draft.text)
|
|
89
|
+
setFiles(draft.files)
|
|
90
|
+
} })
|
|
85
91
|
const addRecording = React.useCallback((file: File) => {
|
|
86
92
|
draftRevisionRef.current += 1
|
|
87
93
|
setFiles((current) => [...current, createAgentChatComposerFile(file)])
|
|
@@ -91,8 +97,9 @@ export function ChatComposer({
|
|
|
91
97
|
const validationError = validateAgentChatSubmission(
|
|
92
98
|
inputContract,
|
|
93
99
|
text,
|
|
94
|
-
files.map((file) => ({ data: file.source, mediaType: file.mediaType })),
|
|
100
|
+
files.map((file) => ({ data: file.source || new Uint8Array(), mediaType: file.mediaType })),
|
|
95
101
|
)
|
|
102
|
+
const action = chatComposerAction({ hasDraft: Boolean(text.trim() || files.length), isRunning, isCancelling })
|
|
96
103
|
|
|
97
104
|
const selectedAgent = agents.find((item) => item.id === agentId)
|
|
98
105
|
const selectedModel = models.find((item) => item.id === modelId)
|
|
@@ -153,7 +160,7 @@ export function ChatComposer({
|
|
|
153
160
|
const showUtilityRow = utilityRow === "below"
|
|
154
161
|
|
|
155
162
|
const submit = async () => {
|
|
156
|
-
if (disabled ||
|
|
163
|
+
if (disabled || submittingRef.current || validationError) return
|
|
157
164
|
const value = text
|
|
158
165
|
const selectedFiles = files
|
|
159
166
|
const clearedRevision = draftRevisionRef.current + 1
|
|
@@ -162,7 +169,7 @@ export function ChatComposer({
|
|
|
162
169
|
inFlightFilesRef.current = selectedFiles
|
|
163
170
|
setText("")
|
|
164
171
|
setFiles([])
|
|
165
|
-
|
|
172
|
+
focusComposer()
|
|
166
173
|
try {
|
|
167
174
|
await onSubmit(value, selectedFiles)
|
|
168
175
|
revokeAgentChatComposerFiles(selectedFiles)
|
|
@@ -184,7 +191,7 @@ export function ChatComposer({
|
|
|
184
191
|
|
|
185
192
|
return (
|
|
186
193
|
<div
|
|
187
|
-
className="
|
|
194
|
+
className="relative z-10 w-full pb-[max(1rem,env(safe-area-inset-bottom))]"
|
|
188
195
|
data-agents24-chat-composer=""
|
|
189
196
|
>
|
|
190
197
|
{allowAttachments && files.length > 0 && (
|
|
@@ -235,7 +242,7 @@ export function ChatComposer({
|
|
|
235
242
|
}}
|
|
236
243
|
/>
|
|
237
244
|
<div className="agents24-composer-attach flex min-w-0 items-center">
|
|
238
|
-
<Button className="bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground" variant="ghost" size="icon" aria-label="Attach files" disabled={disabled
|
|
245
|
+
<Button className="bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground" variant="ghost" size="icon" aria-label="Attach files" disabled={disabled} onClick={() => inputRef.current?.click()}>
|
|
239
246
|
<span aria-hidden>+</span>
|
|
240
247
|
</Button>
|
|
241
248
|
</div>
|
|
@@ -277,31 +284,23 @@ export function ChatComposer({
|
|
|
277
284
|
{recorder.isRecording ? <Square className="fill-current" /> : <Mic />}
|
|
278
285
|
</Button>
|
|
279
286
|
) : null}
|
|
280
|
-
{
|
|
281
|
-
<Button
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
disabled={disabled || isCancelling}
|
|
285
|
-
onClick={onStop}
|
|
286
|
-
>
|
|
287
|
-
{isCancelling
|
|
288
|
-
? <LoaderCircle className="animate-spin" />
|
|
289
|
-
: <Square className="fill-current" />}
|
|
287
|
+
{action === "stop" ? (
|
|
288
|
+
<Button size="icon" aria-label={isCancelling ? "Cancelling response" : "Stop response"}
|
|
289
|
+
disabled={disabled || isCancelling} onClick={onStop}>
|
|
290
|
+
{isCancelling ? <LoaderCircle className="animate-spin" /> : <Square className="fill-current" />}
|
|
290
291
|
</Button>
|
|
291
|
-
) : (
|
|
292
|
-
validationError ? (
|
|
292
|
+
) : validationError ? (
|
|
293
293
|
<Tooltip>
|
|
294
294
|
<TooltipTrigger asChild>
|
|
295
295
|
<span tabIndex={0} aria-label={validationError}>
|
|
296
|
-
<Button size="icon" aria-label="Send message" disabled onClick={() => void submit()}><ArrowUp /></Button>
|
|
296
|
+
<Button size="icon" aria-label={isRunning ? "Queue message" : "Send message"} disabled onClick={() => void submit()}><ArrowUp /></Button>
|
|
297
297
|
</span>
|
|
298
298
|
</TooltipTrigger>
|
|
299
299
|
<TooltipContent>{validationError}</TooltipContent>
|
|
300
300
|
</Tooltip>
|
|
301
301
|
) : (
|
|
302
|
-
<Button size="icon" aria-label="Send message" disabled={disabled} onClick={() => void submit()}><ArrowUp /></Button>
|
|
303
|
-
)
|
|
304
|
-
)}
|
|
302
|
+
<Button size="icon" aria-label={isRunning ? "Queue message" : "Send message"} disabled={disabled} onClick={() => void submit()}><ArrowUp /></Button>
|
|
303
|
+
)}
|
|
305
304
|
</div>
|
|
306
305
|
</div>
|
|
307
306
|
{showUtilityRow ? (
|
|
@@ -1,7 +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 { AgentChatDefaultActions, AgentChatUserMessageActionRow, ChatAttachmentRows, type ChatAttachmentContentResolver } from "@agents24/chat-react/ui"
|
|
4
|
+
import { AgentChatDefaultActions, AgentChatUserMessageActionRow, ChatAttachmentRows, useCompletionActionEntrance, type ChatAttachmentContentResolver } from "@agents24/chat-react/ui"
|
|
5
5
|
import * as React from "react"
|
|
6
6
|
|
|
7
7
|
import { MessageParts } from "./message-parts"
|
|
@@ -10,6 +10,7 @@ import { Message, MessageContent, MessageFooter } from "../ui/message"
|
|
|
10
10
|
import type { Agents24ChatTimelineSlotProps } from "../../app"
|
|
11
11
|
|
|
12
12
|
type Props = {
|
|
13
|
+
animateCompletion: boolean
|
|
13
14
|
message: ChatMessageModel
|
|
14
15
|
getHitlActionState: (part: ChatHitlPart) => AgentChatRuntimeHitlActionState | undefined
|
|
15
16
|
isLoading: boolean
|
|
@@ -24,6 +25,7 @@ type Props = {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export function ChatMessage({
|
|
28
|
+
animateCompletion,
|
|
27
29
|
allowFeedback,
|
|
28
30
|
getHitlActionState,
|
|
29
31
|
isLoading,
|
|
@@ -35,6 +37,8 @@ export function ChatMessage({
|
|
|
35
37
|
Timeline,
|
|
36
38
|
}: Props) {
|
|
37
39
|
const isUser = message.role === "user"
|
|
40
|
+
const showCompletionActions = !isUser && message.isFinal !== false && !isLoading
|
|
41
|
+
const animateCompletionActions = useCompletionActionEntrance(showCompletionActions, message.runId, animateCompletion)
|
|
38
42
|
return (
|
|
39
43
|
<Message align={isUser ? "end" : "start"}>
|
|
40
44
|
<MessageContent className={isUser ? "gap-0" : undefined}>
|
|
@@ -66,9 +70,10 @@ export function ChatMessage({
|
|
|
66
70
|
/>
|
|
67
71
|
</AgentChatUserMessageActionRow>
|
|
68
72
|
)}
|
|
69
|
-
{
|
|
73
|
+
{showCompletionActions && (
|
|
70
74
|
<MessageFooter className="gap-1 opacity-70 transition-opacity group-hover/message:opacity-100">
|
|
71
75
|
<AgentChatDefaultActions
|
|
76
|
+
animateCompletion={animateCompletionActions}
|
|
72
77
|
handlers={{
|
|
73
78
|
feedback: message.feedback,
|
|
74
79
|
onCopy: (content) => { void navigator.clipboard.writeText(content).catch(() => undefined) },
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
type AgentChatRuntime,
|
|
4
4
|
} from "@agents24/chat-react/runtime"
|
|
5
5
|
import type { Agents24ChatScaffoldComponents } from "../../app"
|
|
6
|
+
import type { ThreadMessage } from "@agents24/client"
|
|
7
|
+
import { AgentChatQueue, queuedMessageComposerFiles, useLiveCompletionRuns, type AgentChatComposerFile } from "@agents24/chat-react/ui"
|
|
6
8
|
import { CircleAlert, LoaderCircle, SquarePen, X } from "lucide-react"
|
|
7
9
|
import * as React from "react"
|
|
8
10
|
import type { Agents24ChatIdentity } from "../../identity"
|
|
@@ -15,13 +17,9 @@ import { TurnOutline } from "./turn-outline"
|
|
|
15
17
|
import { isScaffoldTimelineLoading } from "./timeline-loading"
|
|
16
18
|
import { Button } from "../ui/button"
|
|
17
19
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
MessageScrollerItem,
|
|
22
|
-
MessageScrollerProvider,
|
|
23
|
-
MessageScrollerViewport,
|
|
24
|
-
} from "../ui/message-scroller"
|
|
20
|
+
LatestThreadScroller,
|
|
21
|
+
latestThreadAnchorId,
|
|
22
|
+
} from "@agents24/chat-react"
|
|
25
23
|
import { SidebarInset, SidebarProvider, SidebarTrigger, useSidebar } from "../ui/sidebar"
|
|
26
24
|
|
|
27
25
|
const LOADING_INPUT_CONTRACT = {
|
|
@@ -95,20 +93,30 @@ export function ChatShell({
|
|
|
95
93
|
sidebar?: React.ReactNode
|
|
96
94
|
}) {
|
|
97
95
|
const { controller } = runtime
|
|
96
|
+
const isUploading = controller.runState === "uploading"
|
|
98
97
|
const isRunning =
|
|
99
98
|
controller.runState === "streaming"
|
|
100
99
|
|| controller.runState === "reconnecting"
|
|
101
100
|
|| controller.runState === "paused"
|
|
102
101
|
|| controller.runState === "cancelling"
|
|
103
|
-
const isUploading = controller.runState === "uploading" || runtime.isUploading
|
|
104
102
|
const isCancelling = controller.runState === "cancelling"
|
|
103
|
+
const wasLiveRun = useLiveCompletionRuns(controller.activeRunId, isRunning)
|
|
105
104
|
const activeTitle = controller.threads.find((thread) => thread.id === controller.activeThreadId)?.title
|
|
106
105
|
const hasBlockingError = Boolean(runtime.fatalError && controller.messages.length === 0)
|
|
107
106
|
const isEmptyState = controller.activeThreadId === null && controller.messages.length === 0 && !hasBlockingError
|
|
107
|
+
const latestAnchorId = latestThreadAnchorId(controller.messages)
|
|
108
108
|
const composerOverlayRef = React.useRef<HTMLDivElement>(null)
|
|
109
109
|
const [composerOverlayHeight, setComposerOverlayHeight] = React.useState(192)
|
|
110
|
+
const [restoredDraft, setRestoredDraft] = React.useState<{ revision: number; text: string; files: AgentChatComposerFile[] } | null>(null)
|
|
111
|
+
const draftRevisionRef = React.useRef(0)
|
|
112
|
+
const retractForEdit = React.useCallback(async (message: ThreadMessage) => {
|
|
113
|
+
const draft = await controller.retractPendingMessage(message)
|
|
114
|
+
setRestoredDraft({ revision: ++draftRevisionRef.current, text: draft.text,
|
|
115
|
+
files: queuedMessageComposerFiles(draft),
|
|
116
|
+
})
|
|
117
|
+
}, [controller])
|
|
110
118
|
|
|
111
|
-
React.
|
|
119
|
+
React.useLayoutEffect(() => {
|
|
112
120
|
const overlay = composerOverlayRef.current
|
|
113
121
|
if (!overlay || isEmptyState) return
|
|
114
122
|
|
|
@@ -159,47 +167,11 @@ export function ChatShell({
|
|
|
159
167
|
data-agents24-chat-transcript=""
|
|
160
168
|
>
|
|
161
169
|
<OperationErrorNotice runtime={runtime} />
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
<ChatComposer
|
|
168
|
-
inputContract={runtime.inputContract || LOADING_INPUT_CONTRACT}
|
|
169
|
-
contextWindow={runtime.contextWindow}
|
|
170
|
-
disabled={runtime.isBootstrapping || runtime.isChangingAgent || isUploading}
|
|
171
|
-
focusKey={controller.activeThreadId}
|
|
172
|
-
forceExpanded
|
|
173
|
-
isCancelling={isCancelling}
|
|
174
|
-
isRunning={isRunning}
|
|
175
|
-
agentId={runtime.agentId}
|
|
176
|
-
agents={runtime.agents}
|
|
177
|
-
onAgentChange={(agentId) => { void runtime.changeAgent(agentId) }}
|
|
178
|
-
onStop={() => { void controller.cancelRun().catch(() => undefined) }}
|
|
179
|
-
modelId={runtime.modelId}
|
|
180
|
-
models={runtime.models}
|
|
181
|
-
onModelChange={runtime.changeModel}
|
|
182
|
-
onSubmit={(text, files) => runtime.submit({
|
|
183
|
-
text,
|
|
184
|
-
files: files.map((file) => ({
|
|
185
|
-
data: file.source,
|
|
186
|
-
mediaType: file.mediaType,
|
|
187
|
-
name: file.filename,
|
|
188
|
-
})),
|
|
189
|
-
attachments: files,
|
|
190
|
-
})}
|
|
191
|
-
/>
|
|
192
|
-
</div>
|
|
193
|
-
) : (
|
|
194
|
-
<>
|
|
195
|
-
<MessageScrollerProvider
|
|
196
|
-
autoScroll
|
|
197
|
-
defaultScrollPosition="last-anchor"
|
|
198
|
-
scrollPreviousItemPeek={64}
|
|
199
|
-
>
|
|
200
|
-
<MessageScroller className="relative min-h-0 flex-1">
|
|
201
|
-
<MessageScrollerViewport preserveScrollOnPrepend>
|
|
202
|
-
<MessageScrollerContent
|
|
170
|
+
<LatestThreadScroller.Provider autoScroll defaultScrollPosition="last-anchor" scrollPreviousItemPeek={64}>
|
|
171
|
+
{!isEmptyState && (
|
|
172
|
+
<LatestThreadScroller.Root className="relative min-h-0 flex-1">
|
|
173
|
+
<LatestThreadScroller.Viewport preserveScrollOnPrepend>
|
|
174
|
+
<LatestThreadScroller.Content
|
|
203
175
|
className="mx-auto w-full max-w-3xl gap-3 px-4 pt-8 pb-0 sm:px-6 sm:pt-12"
|
|
204
176
|
style={{ paddingBottom: composerOverlayHeight + 72 }}
|
|
205
177
|
>
|
|
@@ -221,13 +193,14 @@ export function ChatShell({
|
|
|
221
193
|
</div>
|
|
222
194
|
)}
|
|
223
195
|
{controller.messages.map((message) => (
|
|
224
|
-
<
|
|
196
|
+
<LatestThreadScroller.Item
|
|
225
197
|
key={message.id}
|
|
226
198
|
messageId={message.id}
|
|
227
|
-
scrollAnchor={message.
|
|
199
|
+
scrollAnchor={isRunning && message.id === latestAnchorId}
|
|
228
200
|
className="overflow-visible [content-visibility:visible]"
|
|
229
201
|
>
|
|
230
202
|
<ChatMessage
|
|
203
|
+
animateCompletion={wasLiveRun(message.runId)}
|
|
231
204
|
allowFeedback={runtime.allowFeedback}
|
|
232
205
|
getHitlActionState={runtime.getHitlActionState}
|
|
233
206
|
isLoading={isScaffoldTimelineLoading({
|
|
@@ -243,29 +216,40 @@ export function ChatShell({
|
|
|
243
216
|
resolveAttachmentContent={runtime.resolveAttachmentContent}
|
|
244
217
|
Timeline={components?.Timeline}
|
|
245
218
|
/>
|
|
246
|
-
</
|
|
219
|
+
</LatestThreadScroller.Item>
|
|
247
220
|
))}
|
|
248
|
-
</
|
|
249
|
-
</
|
|
221
|
+
</LatestThreadScroller.Content>
|
|
222
|
+
</LatestThreadScroller.Viewport>
|
|
250
223
|
<TurnOutline messages={controller.messages} />
|
|
251
|
-
</
|
|
224
|
+
</LatestThreadScroller.Root>
|
|
225
|
+
)}
|
|
252
226
|
|
|
253
227
|
<div
|
|
254
228
|
ref={composerOverlayRef}
|
|
255
|
-
className=
|
|
256
|
-
|
|
229
|
+
className={isEmptyState
|
|
230
|
+
? "pointer-events-none absolute inset-0 z-30 flex flex-col justify-center overflow-visible pb-20"
|
|
231
|
+
: "pointer-events-none absolute inset-x-0 bottom-0 z-30 overflow-visible pt-10"}
|
|
232
|
+
style={isEmptyState ? undefined : {
|
|
257
233
|
background: "linear-gradient(to bottom, transparent 0%, color-mix(in oklch, var(--background) 85%, transparent) 45%, var(--background) 65%, var(--background) 100%)",
|
|
258
234
|
}}
|
|
259
235
|
>
|
|
260
|
-
<div className="
|
|
261
|
-
<
|
|
262
|
-
</div>
|
|
263
|
-
|
|
236
|
+
{isEmptyState ? <div className="mx-auto mb-8 w-full max-w-3xl px-4 text-center sm:px-6">
|
|
237
|
+
<h2 className="text-3xl font-semibold tracking-tight sm:text-4xl">Ready when you are.</h2>
|
|
238
|
+
</div> : <div className="pointer-events-auto absolute inset-x-0 top-0 flex -translate-y-full justify-center pb-3">
|
|
239
|
+
<LatestThreadScroller.Button className="!relative !inset-auto !translate-x-0 rtl:!translate-x-0" />
|
|
240
|
+
</div>}
|
|
241
|
+
<div className="pointer-events-auto mx-auto w-full max-w-3xl px-4 sm:px-6">
|
|
242
|
+
<AgentChatQueue pending={controller.pendingMessages} queue={controller.messageQueue}
|
|
243
|
+
canSteer={controller.runState === "streaming"}
|
|
244
|
+
onSteer={controller.steerPendingMessage} onRemove={controller.removePendingMessage}
|
|
245
|
+
onEdit={retractForEdit} onResume={controller.resumeQueue} />
|
|
264
246
|
<ChatComposer
|
|
247
|
+
restoredDraft={restoredDraft}
|
|
265
248
|
inputContract={runtime.inputContract || LOADING_INPUT_CONTRACT}
|
|
266
249
|
contextWindow={runtime.contextWindow}
|
|
267
|
-
disabled={runtime.isBootstrapping || runtime.isChangingAgent ||
|
|
250
|
+
disabled={runtime.isBootstrapping || runtime.isChangingAgent || isUploading || hasBlockingError}
|
|
268
251
|
focusKey={controller.activeThreadId}
|
|
252
|
+
forceExpanded={isEmptyState}
|
|
269
253
|
isCancelling={isCancelling}
|
|
270
254
|
isRunning={isRunning}
|
|
271
255
|
agentId={runtime.agentId}
|
|
@@ -277,20 +261,19 @@ export function ChatShell({
|
|
|
277
261
|
onModelChange={runtime.changeModel}
|
|
278
262
|
onSubmit={(text, files) => runtime.submit({
|
|
279
263
|
text,
|
|
280
|
-
files: files.map((file) => ({
|
|
281
|
-
data: file.source
|
|
264
|
+
files: files.filter((file) => file.source).map((file) => ({
|
|
265
|
+
data: file.source!,
|
|
282
266
|
mediaType: file.mediaType,
|
|
283
267
|
name: file.filename,
|
|
284
268
|
})),
|
|
269
|
+
attachmentIds: files.flatMap((file) => file.persistedAttachmentId ? [file.persistedAttachmentId] : []),
|
|
285
270
|
attachments: files,
|
|
286
271
|
})}
|
|
287
|
-
utilityRow="below"
|
|
272
|
+
utilityRow={isEmptyState ? "inline" : "below"}
|
|
288
273
|
/>
|
|
289
274
|
</div>
|
|
290
275
|
</div>
|
|
291
|
-
|
|
292
|
-
</>
|
|
293
|
-
)}
|
|
276
|
+
</LatestThreadScroller.Provider>
|
|
294
277
|
</section>
|
|
295
278
|
</SidebarInset>
|
|
296
279
|
</SidebarProvider>
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"tailwindcss": "^4.1.16"
|
|
21
21
|
},
|
|
22
22
|
"source": "packages/agents24-chat-react/scaffold",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "28735c9ad85022adbdcd93d0499038dd837d43ac745441d2570ff6eb7164149d",
|
|
24
24
|
"files": [
|
|
25
25
|
"components.json",
|
|
26
26
|
"manifest.json",
|
|
@@ -46,7 +46,6 @@
|
|
|
46
46
|
"src/components/ui/dropdown-menu.tsx",
|
|
47
47
|
"src/components/ui/input.tsx",
|
|
48
48
|
"src/components/ui/marker.tsx",
|
|
49
|
-
"src/components/ui/message-scroller.tsx",
|
|
50
49
|
"src/components/ui/message.tsx",
|
|
51
50
|
"src/components/ui/popover.tsx",
|
|
52
51
|
"src/components/ui/select.tsx",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-agents24-app",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.15",
|
|
4
4
|
"description": "Create a production-ready Agents24 React application.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"provenance": false
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@agents24/cli": "0.3.
|
|
36
|
+
"@agents24/cli": "0.3.16",
|
|
37
37
|
"@clack/prompts": "1.7.0",
|
|
38
38
|
"shadcn": "4.13.1"
|
|
39
39
|
},
|
package/versions.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"agents24": {
|
|
3
|
-
"@agents24/client": "^0.2.
|
|
4
|
-
"@agents24/react": "^0.2.
|
|
5
|
-
"@agents24/chat-react": "^0.5.
|
|
6
|
-
"@agents24/node": "^0.5.
|
|
3
|
+
"@agents24/client": "^0.2.8",
|
|
4
|
+
"@agents24/react": "^0.2.9",
|
|
5
|
+
"@agents24/chat-react": "^0.5.18",
|
|
6
|
+
"@agents24/node": "^0.5.13"
|
|
7
7
|
},
|
|
8
8
|
"runtime": {
|
|
9
9
|
"next": "^16.3.4",
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import {
|
|
3
|
-
MessageScroller as MessageScrollerPrimitive,
|
|
4
|
-
useMessageScroller,
|
|
5
|
-
useMessageScrollerScrollable,
|
|
6
|
-
useMessageScrollerVisibility,
|
|
7
|
-
} from "@shadcn/react/message-scroller"
|
|
8
|
-
|
|
9
|
-
import { cn } from "../../lib/utils"
|
|
10
|
-
import { Button } from "./button"
|
|
11
|
-
import { ArrowDownIcon } from "lucide-react"
|
|
12
|
-
|
|
13
|
-
function MessageScrollerProvider(
|
|
14
|
-
props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>
|
|
15
|
-
) {
|
|
16
|
-
return <MessageScrollerPrimitive.Provider {...props} />
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function MessageScroller({
|
|
20
|
-
className,
|
|
21
|
-
...props
|
|
22
|
-
}: React.ComponentProps<typeof MessageScrollerPrimitive.Root>) {
|
|
23
|
-
return (
|
|
24
|
-
<MessageScrollerPrimitive.Root
|
|
25
|
-
data-slot="message-scroller"
|
|
26
|
-
className={cn(
|
|
27
|
-
"group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden",
|
|
28
|
-
className
|
|
29
|
-
)}
|
|
30
|
-
{...props}
|
|
31
|
-
/>
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function MessageScrollerViewport({
|
|
36
|
-
className,
|
|
37
|
-
...props
|
|
38
|
-
}: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>) {
|
|
39
|
-
return (
|
|
40
|
-
<MessageScrollerPrimitive.Viewport
|
|
41
|
-
data-slot="message-scroller-viewport"
|
|
42
|
-
className={cn(
|
|
43
|
-
"size-full min-h-0 min-w-0 scroll-fade-b overflow-y-auto overscroll-contain contain-content [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
44
|
-
className
|
|
45
|
-
)}
|
|
46
|
-
{...props}
|
|
47
|
-
/>
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function MessageScrollerContent({
|
|
52
|
-
className,
|
|
53
|
-
...props
|
|
54
|
-
}: React.ComponentProps<typeof MessageScrollerPrimitive.Content>) {
|
|
55
|
-
return (
|
|
56
|
-
<MessageScrollerPrimitive.Content
|
|
57
|
-
data-slot="message-scroller-content"
|
|
58
|
-
className={cn("flex h-max min-h-full flex-col gap-3", className)}
|
|
59
|
-
{...props}
|
|
60
|
-
/>
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function MessageScrollerItem({
|
|
65
|
-
className,
|
|
66
|
-
scrollAnchor = false,
|
|
67
|
-
...props
|
|
68
|
-
}: React.ComponentProps<typeof MessageScrollerPrimitive.Item>) {
|
|
69
|
-
return (
|
|
70
|
-
<MessageScrollerPrimitive.Item
|
|
71
|
-
data-slot="message-scroller-item"
|
|
72
|
-
scrollAnchor={scrollAnchor}
|
|
73
|
-
className={cn(
|
|
74
|
-
"min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]",
|
|
75
|
-
className
|
|
76
|
-
)}
|
|
77
|
-
{...props}
|
|
78
|
-
/>
|
|
79
|
-
)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function MessageScrollerButton({
|
|
83
|
-
direction = "end",
|
|
84
|
-
className,
|
|
85
|
-
children,
|
|
86
|
-
render,
|
|
87
|
-
variant = "secondary",
|
|
88
|
-
size = "icon-sm",
|
|
89
|
-
...props
|
|
90
|
-
}: React.ComponentProps<typeof MessageScrollerPrimitive.Button> &
|
|
91
|
-
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
|
|
92
|
-
return (
|
|
93
|
-
<MessageScrollerPrimitive.Button
|
|
94
|
-
data-slot="message-scroller-button"
|
|
95
|
-
data-direction={direction}
|
|
96
|
-
data-variant={variant}
|
|
97
|
-
data-size={size}
|
|
98
|
-
direction={direction}
|
|
99
|
-
className={cn(
|
|
100
|
-
"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",
|
|
101
|
-
className
|
|
102
|
-
)}
|
|
103
|
-
render={render ?? <Button variant={variant} size={size} />}
|
|
104
|
-
{...props}
|
|
105
|
-
>
|
|
106
|
-
{children ?? (
|
|
107
|
-
<>
|
|
108
|
-
<ArrowDownIcon
|
|
109
|
-
/>
|
|
110
|
-
<span className="sr-only">
|
|
111
|
-
{direction === "end" ? "Scroll to end" : "Scroll to start"}
|
|
112
|
-
</span>
|
|
113
|
-
</>
|
|
114
|
-
)}
|
|
115
|
-
</MessageScrollerPrimitive.Button>
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export {
|
|
120
|
-
MessageScrollerProvider,
|
|
121
|
-
MessageScroller,
|
|
122
|
-
MessageScrollerViewport,
|
|
123
|
-
MessageScrollerContent,
|
|
124
|
-
MessageScrollerItem,
|
|
125
|
-
MessageScrollerButton,
|
|
126
|
-
useMessageScroller,
|
|
127
|
-
useMessageScrollerScrollable,
|
|
128
|
-
useMessageScrollerVisibility,
|
|
129
|
-
}
|