@ash-cloud/ash-ui 0.1.0 → 0.2.0
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/design-tokens.cjs +20 -0
- package/dist/design-tokens.cjs.map +1 -1
- package/dist/design-tokens.d.cts +31 -1
- package/dist/design-tokens.d.ts +31 -1
- package/dist/design-tokens.js +20 -1
- package/dist/design-tokens.js.map +1 -1
- package/dist/icons.cjs +23 -0
- package/dist/icons.cjs.map +1 -1
- package/dist/icons.d.cts +4 -1
- package/dist/icons.d.ts +4 -1
- package/dist/icons.js +21 -1
- package/dist/icons.js.map +1 -1
- package/dist/index.cjs +2416 -1955
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +840 -641
- package/dist/index.d.ts +840 -641
- package/dist/index.js +2360 -1930
- package/dist/index.js.map +1 -1
- package/dist/styles-full.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/types.cjs +243 -6
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +197 -121
- package/dist/types.d.ts +197 -121
- package/dist/types.js +239 -6
- package/dist/types.js.map +1 -1
- package/dist/utils.cjs +0 -35
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +2 -28
- package/dist/utils.d.ts +2 -28
- package/dist/utils.js +1 -34
- package/dist/utils.js.map +1 -1
- package/package.json +22 -16
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { createContext, lazy, useContext, useRef, useState, useCallback, useEffect, useMemo, Suspense } from 'react';
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
|
-
// src/components/
|
|
4
|
+
// src/components/Conversation.tsx
|
|
5
5
|
|
|
6
6
|
// src/utils.ts
|
|
7
7
|
function formatToolName(name) {
|
|
@@ -360,39 +360,6 @@ function truncate(str, maxLength) {
|
|
|
360
360
|
function cn(...classes) {
|
|
361
361
|
return classes.filter(Boolean).join(" ");
|
|
362
362
|
}
|
|
363
|
-
function groupEntriesForCompactMode(entries, config) {
|
|
364
|
-
const result = [];
|
|
365
|
-
let currentToolGroup = [];
|
|
366
|
-
let toolGroupCounter = 0;
|
|
367
|
-
const flushToolGroup = () => {
|
|
368
|
-
if (currentToolGroup.length > 0) {
|
|
369
|
-
result.push({
|
|
370
|
-
type: "tool_group",
|
|
371
|
-
entries: [...currentToolGroup],
|
|
372
|
-
id: `tool-group-${toolGroupCounter++}`
|
|
373
|
-
});
|
|
374
|
-
currentToolGroup = [];
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
|
-
for (const entry of entries) {
|
|
378
|
-
if (entry.entryType.type === "tool_call") {
|
|
379
|
-
currentToolGroup.push(entry);
|
|
380
|
-
if (config.breakEveryNToolCalls && config.breakEveryNToolCalls > 0 && currentToolGroup.length >= config.breakEveryNToolCalls) {
|
|
381
|
-
flushToolGroup();
|
|
382
|
-
}
|
|
383
|
-
} else {
|
|
384
|
-
flushToolGroup();
|
|
385
|
-
result.push({ type: "single", entry });
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
flushToolGroup();
|
|
389
|
-
return result;
|
|
390
|
-
}
|
|
391
|
-
function extractToolCallsFromGroup(entries) {
|
|
392
|
-
return entries.filter(
|
|
393
|
-
(e) => e.entryType.type === "tool_call"
|
|
394
|
-
).map((e) => e.entryType.toolCall);
|
|
395
|
-
}
|
|
396
363
|
function parseOptionsFromContent(content) {
|
|
397
364
|
const optionPattern = /(?:\*\*)?Option\s+(\d+)(?:\*\*)?[:\-]\s*([^\n]+)(?:\n((?:(?!\n(?:\*\*)?Option\s+\d).)*?))?/gi;
|
|
398
365
|
const options = [];
|
|
@@ -442,6 +409,376 @@ function parseOptionsFromContent(content) {
|
|
|
442
409
|
}
|
|
443
410
|
return null;
|
|
444
411
|
}
|
|
412
|
+
var ConversationContext = createContext(null);
|
|
413
|
+
function useConversation() {
|
|
414
|
+
const context = useContext(ConversationContext);
|
|
415
|
+
if (!context) {
|
|
416
|
+
throw new Error("useConversation must be used within a Conversation");
|
|
417
|
+
}
|
|
418
|
+
return context;
|
|
419
|
+
}
|
|
420
|
+
function Conversation({
|
|
421
|
+
children,
|
|
422
|
+
className,
|
|
423
|
+
autoScroll: initialAutoScroll = true,
|
|
424
|
+
scrollThreshold = 100
|
|
425
|
+
}) {
|
|
426
|
+
const containerRef = useRef(null);
|
|
427
|
+
const [isScrolledUp, setIsScrolledUp] = useState(false);
|
|
428
|
+
const [autoScroll, setAutoScroll] = useState(initialAutoScroll);
|
|
429
|
+
const scrollToBottom = useCallback((behavior = "smooth") => {
|
|
430
|
+
if (containerRef.current) {
|
|
431
|
+
containerRef.current.scrollTo({
|
|
432
|
+
top: containerRef.current.scrollHeight,
|
|
433
|
+
behavior
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
}, []);
|
|
437
|
+
const handleScroll = useCallback(() => {
|
|
438
|
+
if (!containerRef.current) return;
|
|
439
|
+
const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
|
|
440
|
+
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
|
|
441
|
+
const isAtBottom = distanceFromBottom < scrollThreshold;
|
|
442
|
+
setIsScrolledUp(!isAtBottom);
|
|
443
|
+
if (isAtBottom && !autoScroll) {
|
|
444
|
+
setAutoScroll(true);
|
|
445
|
+
}
|
|
446
|
+
}, [scrollThreshold, autoScroll]);
|
|
447
|
+
useEffect(() => {
|
|
448
|
+
if (autoScroll && !isScrolledUp) {
|
|
449
|
+
scrollToBottom("instant");
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
const contextValue = {
|
|
453
|
+
containerRef,
|
|
454
|
+
scrollToBottom,
|
|
455
|
+
isScrolledUp,
|
|
456
|
+
autoScroll,
|
|
457
|
+
setAutoScroll
|
|
458
|
+
};
|
|
459
|
+
return /* @__PURE__ */ jsx(ConversationContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
460
|
+
"div",
|
|
461
|
+
{
|
|
462
|
+
ref: containerRef,
|
|
463
|
+
onScroll: handleScroll,
|
|
464
|
+
className: cn(
|
|
465
|
+
"ash-conversation flex flex-col overflow-y-auto",
|
|
466
|
+
"ash-scrollbar",
|
|
467
|
+
className
|
|
468
|
+
),
|
|
469
|
+
role: "log",
|
|
470
|
+
"aria-live": "polite",
|
|
471
|
+
children
|
|
472
|
+
}
|
|
473
|
+
) });
|
|
474
|
+
}
|
|
475
|
+
function ConversationContent({
|
|
476
|
+
children,
|
|
477
|
+
className
|
|
478
|
+
}) {
|
|
479
|
+
return /* @__PURE__ */ jsx(
|
|
480
|
+
"div",
|
|
481
|
+
{
|
|
482
|
+
className: cn(
|
|
483
|
+
"ash-conversation-content flex flex-col",
|
|
484
|
+
"gap-[var(--ash-message-list-gap,0.25rem)]",
|
|
485
|
+
"p-[var(--ash-spacing-md,0.75rem)]",
|
|
486
|
+
className
|
|
487
|
+
),
|
|
488
|
+
children
|
|
489
|
+
}
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
function ConversationEmptyState({
|
|
493
|
+
children,
|
|
494
|
+
className
|
|
495
|
+
}) {
|
|
496
|
+
return /* @__PURE__ */ jsx(
|
|
497
|
+
"div",
|
|
498
|
+
{
|
|
499
|
+
className: cn(
|
|
500
|
+
"ash-conversation-empty flex flex-col items-center justify-center",
|
|
501
|
+
"flex-1 min-h-[200px] text-center",
|
|
502
|
+
"text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
|
|
503
|
+
className
|
|
504
|
+
),
|
|
505
|
+
children
|
|
506
|
+
}
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
function ConversationScrollButton({
|
|
510
|
+
className,
|
|
511
|
+
label = "Scroll to bottom"
|
|
512
|
+
}) {
|
|
513
|
+
const { isScrolledUp, scrollToBottom } = useConversation();
|
|
514
|
+
if (!isScrolledUp) return null;
|
|
515
|
+
return /* @__PURE__ */ jsx(
|
|
516
|
+
"button",
|
|
517
|
+
{
|
|
518
|
+
onClick: () => scrollToBottom(),
|
|
519
|
+
className: cn(
|
|
520
|
+
"ash-conversation-scroll-btn",
|
|
521
|
+
"fixed bottom-20 left-1/2 -translate-x-1/2",
|
|
522
|
+
"px-4 py-2 rounded-full",
|
|
523
|
+
"bg-[var(--ash-surface-elevated,#111)] border border-[var(--ash-border,rgba(255,255,255,0.08))]",
|
|
524
|
+
"text-[var(--ash-text-secondary,rgba(255,255,255,0.7))] text-sm",
|
|
525
|
+
"hover:bg-[var(--ash-surface-card,#0c0c0c)] hover:border-[var(--ash-border-emphasis,rgba(255,255,255,0.15))]",
|
|
526
|
+
"transition-all duration-200",
|
|
527
|
+
"shadow-lg",
|
|
528
|
+
className
|
|
529
|
+
),
|
|
530
|
+
"aria-label": label,
|
|
531
|
+
children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
532
|
+
/* @__PURE__ */ jsx(
|
|
533
|
+
"svg",
|
|
534
|
+
{
|
|
535
|
+
className: "w-4 h-4",
|
|
536
|
+
fill: "none",
|
|
537
|
+
stroke: "currentColor",
|
|
538
|
+
viewBox: "0 0 24 24",
|
|
539
|
+
children: /* @__PURE__ */ jsx(
|
|
540
|
+
"path",
|
|
541
|
+
{
|
|
542
|
+
strokeLinecap: "round",
|
|
543
|
+
strokeLinejoin: "round",
|
|
544
|
+
strokeWidth: 2,
|
|
545
|
+
d: "M19 14l-7 7m0 0l-7-7m7 7V3"
|
|
546
|
+
}
|
|
547
|
+
)
|
|
548
|
+
}
|
|
549
|
+
),
|
|
550
|
+
label
|
|
551
|
+
] })
|
|
552
|
+
}
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
var ReactMarkdown = lazy(() => import('react-markdown'));
|
|
556
|
+
function LazyMarkdown({ children, fallback, components, className }) {
|
|
557
|
+
const [mounted, setMounted] = useState(false);
|
|
558
|
+
useEffect(() => {
|
|
559
|
+
setMounted(true);
|
|
560
|
+
}, []);
|
|
561
|
+
const markdownComponents = useMemo(() => {
|
|
562
|
+
if (!components) return void 0;
|
|
563
|
+
return components;
|
|
564
|
+
}, [components]);
|
|
565
|
+
if (!mounted) {
|
|
566
|
+
return /* @__PURE__ */ jsx("span", { className, children: fallback ?? children });
|
|
567
|
+
}
|
|
568
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("span", { className, children: fallback ?? children }), children: /* @__PURE__ */ jsx(ReactMarkdown, { components: markdownComponents, children }) });
|
|
569
|
+
}
|
|
570
|
+
var MessageContext = createContext(null);
|
|
571
|
+
function useMessage() {
|
|
572
|
+
const context = useContext(MessageContext);
|
|
573
|
+
if (!context) {
|
|
574
|
+
throw new Error("useMessage must be used within a Message");
|
|
575
|
+
}
|
|
576
|
+
return context;
|
|
577
|
+
}
|
|
578
|
+
function Message({
|
|
579
|
+
from,
|
|
580
|
+
children,
|
|
581
|
+
className,
|
|
582
|
+
isStreaming,
|
|
583
|
+
toolInvocations,
|
|
584
|
+
id
|
|
585
|
+
}) {
|
|
586
|
+
const contextValue = {
|
|
587
|
+
from,
|
|
588
|
+
isStreaming,
|
|
589
|
+
toolInvocations
|
|
590
|
+
};
|
|
591
|
+
const roleMap = {
|
|
592
|
+
user: "user",
|
|
593
|
+
assistant: "assistant",
|
|
594
|
+
system: "system"
|
|
595
|
+
};
|
|
596
|
+
return /* @__PURE__ */ jsx(MessageContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
597
|
+
"div",
|
|
598
|
+
{
|
|
599
|
+
className: cn(
|
|
600
|
+
"ash-message",
|
|
601
|
+
"flex gap-[var(--ash-message-gap,0.5rem)]",
|
|
602
|
+
from === "user" && "flex-row-reverse",
|
|
603
|
+
className
|
|
604
|
+
),
|
|
605
|
+
"data-message-role": roleMap[from],
|
|
606
|
+
"data-message-id": id,
|
|
607
|
+
children
|
|
608
|
+
}
|
|
609
|
+
) });
|
|
610
|
+
}
|
|
611
|
+
function MessageAvatar({ src, fallback, className }) {
|
|
612
|
+
const { from } = useMessage();
|
|
613
|
+
const defaultFallback = from === "user" ? "U" : from === "assistant" ? "A" : "S";
|
|
614
|
+
const displayFallback = fallback || defaultFallback;
|
|
615
|
+
const bgColorMap = {
|
|
616
|
+
user: "var(--ash-avatar-user-bg,rgba(255,255,255,0.1))",
|
|
617
|
+
assistant: "var(--ash-avatar-assistant-bg,#10a37f)",
|
|
618
|
+
system: "var(--ash-avatar-user-bg,rgba(255,255,255,0.1))"
|
|
619
|
+
};
|
|
620
|
+
return /* @__PURE__ */ jsx(
|
|
621
|
+
"div",
|
|
622
|
+
{
|
|
623
|
+
className: cn(
|
|
624
|
+
"ash-message-avatar flex-shrink-0",
|
|
625
|
+
"w-[var(--ash-avatar-size,1.25rem)] h-[var(--ash-avatar-size,1.25rem)]",
|
|
626
|
+
"rounded-full flex items-center justify-center",
|
|
627
|
+
"text-[var(--ash-font-size-xs,10px)] font-medium",
|
|
628
|
+
from === "assistant" ? "text-white" : "text-[var(--ash-text-secondary,rgba(255,255,255,0.7))]",
|
|
629
|
+
className
|
|
630
|
+
),
|
|
631
|
+
style: { backgroundColor: bgColorMap[from] },
|
|
632
|
+
children: src ? /* @__PURE__ */ jsx(
|
|
633
|
+
"img",
|
|
634
|
+
{
|
|
635
|
+
src,
|
|
636
|
+
alt: `${from} avatar`,
|
|
637
|
+
className: "w-full h-full rounded-full object-cover"
|
|
638
|
+
}
|
|
639
|
+
) : displayFallback
|
|
640
|
+
}
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
function MessageContent({ children, className }) {
|
|
644
|
+
const { from } = useMessage();
|
|
645
|
+
const roleStyles = {
|
|
646
|
+
user: cn(
|
|
647
|
+
"bg-[var(--ash-user-bg,#5B6EF5)]",
|
|
648
|
+
"text-[var(--ash-user-text,#ffffff)]",
|
|
649
|
+
"border-[var(--ash-user-border,transparent)]"
|
|
650
|
+
),
|
|
651
|
+
assistant: cn(
|
|
652
|
+
"bg-[var(--ash-assistant-bg,#1a1a1a)]",
|
|
653
|
+
"text-[var(--ash-assistant-text,rgba(255,255,255,0.9))]",
|
|
654
|
+
"border-[var(--ash-assistant-border,rgba(255,255,255,0.08))]"
|
|
655
|
+
),
|
|
656
|
+
system: cn(
|
|
657
|
+
"bg-[var(--ash-surface-elevated,#111111)]",
|
|
658
|
+
"text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
|
|
659
|
+
"border-[var(--ash-border,rgba(255,255,255,0.08))]"
|
|
660
|
+
)
|
|
661
|
+
};
|
|
662
|
+
return /* @__PURE__ */ jsx(
|
|
663
|
+
"div",
|
|
664
|
+
{
|
|
665
|
+
className: cn(
|
|
666
|
+
"ash-message-content",
|
|
667
|
+
"flex-1 min-w-0",
|
|
668
|
+
"rounded-[var(--ash-radius-lg,0.75rem)]",
|
|
669
|
+
"p-[var(--ash-message-padding,0.5rem_0.75rem)]",
|
|
670
|
+
"border",
|
|
671
|
+
roleStyles[from],
|
|
672
|
+
from === "user" && "rounded-tr-sm",
|
|
673
|
+
from === "assistant" && "rounded-tl-sm",
|
|
674
|
+
className
|
|
675
|
+
),
|
|
676
|
+
children
|
|
677
|
+
}
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
function MessageResponse({
|
|
681
|
+
content,
|
|
682
|
+
isStreaming,
|
|
683
|
+
className,
|
|
684
|
+
components
|
|
685
|
+
}) {
|
|
686
|
+
if (!content) return null;
|
|
687
|
+
return /* @__PURE__ */ jsx(
|
|
688
|
+
"div",
|
|
689
|
+
{
|
|
690
|
+
className: cn(
|
|
691
|
+
"ash-message-response",
|
|
692
|
+
"font-[var(--ash-font-size-base,13px)]",
|
|
693
|
+
"leading-relaxed",
|
|
694
|
+
isStreaming && "animate-pulse",
|
|
695
|
+
className
|
|
696
|
+
),
|
|
697
|
+
children: /* @__PURE__ */ jsx(LazyMarkdown, { components, children: content })
|
|
698
|
+
}
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
function MessageActions({ children, className }) {
|
|
702
|
+
return /* @__PURE__ */ jsx(
|
|
703
|
+
"div",
|
|
704
|
+
{
|
|
705
|
+
className: cn(
|
|
706
|
+
"ash-message-actions",
|
|
707
|
+
"flex items-center gap-1 mt-2",
|
|
708
|
+
"opacity-0 group-hover:opacity-100 transition-opacity",
|
|
709
|
+
className
|
|
710
|
+
),
|
|
711
|
+
children
|
|
712
|
+
}
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
function MessageAction({
|
|
716
|
+
icon,
|
|
717
|
+
label,
|
|
718
|
+
onClick,
|
|
719
|
+
className
|
|
720
|
+
}) {
|
|
721
|
+
return /* @__PURE__ */ jsx(
|
|
722
|
+
"button",
|
|
723
|
+
{
|
|
724
|
+
onClick,
|
|
725
|
+
className: cn(
|
|
726
|
+
"ash-message-action",
|
|
727
|
+
"p-1.5 rounded-md",
|
|
728
|
+
"text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
|
|
729
|
+
"hover:text-[var(--ash-text-secondary,rgba(255,255,255,0.7))]",
|
|
730
|
+
"hover:bg-[var(--ash-surface-elevated,#111111)]",
|
|
731
|
+
"transition-colors",
|
|
732
|
+
className
|
|
733
|
+
),
|
|
734
|
+
title: label,
|
|
735
|
+
"aria-label": label,
|
|
736
|
+
children: icon || label
|
|
737
|
+
}
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
function MessageTimestamp({ timestamp, className }) {
|
|
741
|
+
const date = typeof timestamp === "string" ? new Date(timestamp) : timestamp;
|
|
742
|
+
const formatted = date.toLocaleTimeString(void 0, {
|
|
743
|
+
hour: "numeric",
|
|
744
|
+
minute: "2-digit"
|
|
745
|
+
});
|
|
746
|
+
return /* @__PURE__ */ jsx(
|
|
747
|
+
"span",
|
|
748
|
+
{
|
|
749
|
+
className: cn(
|
|
750
|
+
"ash-message-timestamp",
|
|
751
|
+
"text-[var(--ash-font-size-xs,10px)]",
|
|
752
|
+
"text-[var(--ash-text-faint,rgba(255,255,255,0.3))]",
|
|
753
|
+
className
|
|
754
|
+
),
|
|
755
|
+
children: formatted
|
|
756
|
+
}
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
function StatusIndicator({ status, size = "sm", className }) {
|
|
760
|
+
const sizeClasses = {
|
|
761
|
+
sm: "w-2 h-2",
|
|
762
|
+
md: "w-3 h-3",
|
|
763
|
+
lg: "w-4 h-4"
|
|
764
|
+
};
|
|
765
|
+
const statusClasses = {
|
|
766
|
+
pending: "ash-status-pending",
|
|
767
|
+
success: "ash-status-success",
|
|
768
|
+
failed: "ash-status-failed"
|
|
769
|
+
};
|
|
770
|
+
return /* @__PURE__ */ jsx(
|
|
771
|
+
"div",
|
|
772
|
+
{
|
|
773
|
+
className: cn(
|
|
774
|
+
"rounded-full flex-shrink-0",
|
|
775
|
+
sizeClasses[size],
|
|
776
|
+
statusClasses[status],
|
|
777
|
+
className
|
|
778
|
+
)
|
|
779
|
+
}
|
|
780
|
+
);
|
|
781
|
+
}
|
|
445
782
|
function SunIcon({ className }) {
|
|
446
783
|
return /* @__PURE__ */ jsxs("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
447
784
|
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "5" }),
|
|
@@ -692,57 +1029,25 @@ function ErrorIcon({ className }) {
|
|
|
692
1029
|
/* @__PURE__ */ jsx("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
|
|
693
1030
|
] });
|
|
694
1031
|
}
|
|
695
|
-
function
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
pending: "ash-status-pending",
|
|
703
|
-
success: "ash-status-success",
|
|
704
|
-
failed: "ash-status-failed"
|
|
705
|
-
};
|
|
706
|
-
return /* @__PURE__ */ jsx(
|
|
707
|
-
"div",
|
|
708
|
-
{
|
|
709
|
-
className: cn(
|
|
710
|
-
"rounded-full flex-shrink-0",
|
|
711
|
-
sizeClasses[size],
|
|
712
|
-
statusClasses[status],
|
|
713
|
-
className
|
|
714
|
-
)
|
|
715
|
-
}
|
|
716
|
-
);
|
|
1032
|
+
function MicrophoneIcon({ className }) {
|
|
1033
|
+
return /* @__PURE__ */ jsxs("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1034
|
+
/* @__PURE__ */ jsx("path", { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }),
|
|
1035
|
+
/* @__PURE__ */ jsx("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
|
|
1036
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "19", x2: "12", y2: "23" }),
|
|
1037
|
+
/* @__PURE__ */ jsx("line", { x1: "8", y1: "23", x2: "16", y2: "23" })
|
|
1038
|
+
] });
|
|
717
1039
|
}
|
|
718
|
-
function
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
return /* @__PURE__ */ jsx(SearchIcon, { className });
|
|
730
|
-
case "glob":
|
|
731
|
-
return /* @__PURE__ */ jsx(FolderSearchIcon, { className });
|
|
732
|
-
case "web_fetch":
|
|
733
|
-
return /* @__PURE__ */ jsx(GlobeIcon, { className });
|
|
734
|
-
case "web_search":
|
|
735
|
-
return /* @__PURE__ */ jsx(SearchIcon, { className });
|
|
736
|
-
case "mcp_tool":
|
|
737
|
-
return /* @__PURE__ */ jsx(PlugIcon, { className });
|
|
738
|
-
case "todo_write":
|
|
739
|
-
return /* @__PURE__ */ jsx(ListChecksIcon, { className });
|
|
740
|
-
case "agent_tool":
|
|
741
|
-
return /* @__PURE__ */ jsx(BotIcon, { className });
|
|
742
|
-
case "generic_tool":
|
|
743
|
-
default:
|
|
744
|
-
return /* @__PURE__ */ jsx(ToolIcon, { className });
|
|
745
|
-
}
|
|
1040
|
+
function HomeIcon({ className }) {
|
|
1041
|
+
return /* @__PURE__ */ jsxs("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1042
|
+
/* @__PURE__ */ jsx("path", { d: "M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }),
|
|
1043
|
+
/* @__PURE__ */ jsx("polyline", { points: "9 22 9 12 15 12 15 22" })
|
|
1044
|
+
] });
|
|
1045
|
+
}
|
|
1046
|
+
function ArrowUpIcon({ className }) {
|
|
1047
|
+
return /* @__PURE__ */ jsxs("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1048
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "19", x2: "12", y2: "5" }),
|
|
1049
|
+
/* @__PURE__ */ jsx("polyline", { points: "5 12 12 5 19 12" })
|
|
1050
|
+
] });
|
|
746
1051
|
}
|
|
747
1052
|
function CodeBlock({
|
|
748
1053
|
children,
|
|
@@ -752,14 +1057,41 @@ function CodeBlock({
|
|
|
752
1057
|
className
|
|
753
1058
|
}) {
|
|
754
1059
|
const [expanded, setExpanded] = useState(false);
|
|
1060
|
+
const [copied, setCopied] = useState(false);
|
|
755
1061
|
const lines = children.split("\n");
|
|
756
1062
|
const isLong = lines.length > 10 || children.length > 500;
|
|
757
|
-
|
|
1063
|
+
const handleCopy = useCallback(async () => {
|
|
1064
|
+
try {
|
|
1065
|
+
await navigator.clipboard.writeText(children);
|
|
1066
|
+
setCopied(true);
|
|
1067
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
1068
|
+
} catch (err) {
|
|
1069
|
+
console.error("Failed to copy:", err);
|
|
1070
|
+
}
|
|
1071
|
+
}, [children]);
|
|
1072
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("relative rounded-lg overflow-hidden border border-white/10", className), children: [
|
|
1073
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2 bg-[var(--ash-code-header-bg)] border-b border-white/10", children: [
|
|
1074
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-white/60 font-medium", children: language || "code" }),
|
|
1075
|
+
/* @__PURE__ */ jsx(
|
|
1076
|
+
"button",
|
|
1077
|
+
{
|
|
1078
|
+
onClick: handleCopy,
|
|
1079
|
+
className: "flex items-center gap-1.5 text-xs text-white/60 hover:text-white transition-colors",
|
|
1080
|
+
children: copied ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1081
|
+
/* @__PURE__ */ jsx(CheckIcon, { className: "w-3.5 h-3.5" }),
|
|
1082
|
+
/* @__PURE__ */ jsx("span", { children: "Copied!" })
|
|
1083
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1084
|
+
/* @__PURE__ */ jsx(CopyIcon, { className: "w-3.5 h-3.5" }),
|
|
1085
|
+
/* @__PURE__ */ jsx("span", { children: "Copy" })
|
|
1086
|
+
] })
|
|
1087
|
+
}
|
|
1088
|
+
)
|
|
1089
|
+
] }),
|
|
758
1090
|
/* @__PURE__ */ jsx(
|
|
759
1091
|
"pre",
|
|
760
1092
|
{
|
|
761
1093
|
className: cn(
|
|
762
|
-
"
|
|
1094
|
+
"text-xs font-mono text-white/90 p-4 bg-black/30 overflow-x-auto whitespace-pre-wrap break-words",
|
|
763
1095
|
!expanded && isLong && "overflow-y-hidden"
|
|
764
1096
|
),
|
|
765
1097
|
style: !expanded && isLong ? { maxHeight } : void 0,
|
|
@@ -792,1519 +1124,1173 @@ function JsonDisplay({ value, maxHeight, className }) {
|
|
|
792
1124
|
const formatted = JSON.stringify(value, null, 2);
|
|
793
1125
|
return /* @__PURE__ */ jsx(CodeBlock, { maxHeight, className, children: formatted });
|
|
794
1126
|
}
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
1127
|
+
var ToolContext = createContext(null);
|
|
1128
|
+
function useTool() {
|
|
1129
|
+
const context = useContext(ToolContext);
|
|
1130
|
+
if (!context) {
|
|
1131
|
+
throw new Error("useTool must be used within a Tool");
|
|
1132
|
+
}
|
|
1133
|
+
return context;
|
|
1134
|
+
}
|
|
1135
|
+
function Tool({
|
|
1136
|
+
toolInvocation,
|
|
1137
|
+
children,
|
|
798
1138
|
className,
|
|
799
|
-
|
|
1139
|
+
defaultExpanded = false
|
|
800
1140
|
}) {
|
|
801
|
-
const [
|
|
802
|
-
const
|
|
803
|
-
const
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
1141
|
+
const [isExpanded, setIsExpanded] = useState(defaultExpanded);
|
|
1142
|
+
const toggleExpanded = () => setIsExpanded((prev) => !prev);
|
|
1143
|
+
const contextValue = {
|
|
1144
|
+
toolInvocation,
|
|
1145
|
+
isExpanded,
|
|
1146
|
+
toggleExpanded
|
|
1147
|
+
};
|
|
1148
|
+
const status = toolInvocation.state === "result" ? "success" : "pending";
|
|
1149
|
+
const isErrorResult = Boolean(
|
|
1150
|
+
toolInvocation.result && typeof toolInvocation.result === "object" && "error" in toolInvocation.result
|
|
1151
|
+
);
|
|
1152
|
+
return /* @__PURE__ */ jsx(ToolContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
1153
|
+
"div",
|
|
1154
|
+
{
|
|
1155
|
+
className: cn(
|
|
1156
|
+
"ash-tool",
|
|
1157
|
+
"rounded-[var(--ash-radius-md,0.5rem)]",
|
|
1158
|
+
"border border-[var(--ash-border,rgba(255,255,255,0.08))]",
|
|
1159
|
+
"bg-[var(--ash-tool-bg,var(--ash-surface-dark,#0a0a0a))]",
|
|
1160
|
+
"overflow-hidden",
|
|
1161
|
+
status === "pending" && "ash-tool-status-pending",
|
|
1162
|
+
isErrorResult && "border-red-500/30",
|
|
1163
|
+
className
|
|
1164
|
+
),
|
|
1165
|
+
"data-tool-name": toolInvocation.toolName,
|
|
1166
|
+
"data-tool-state": toolInvocation.state,
|
|
1167
|
+
children: children || /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1168
|
+
/* @__PURE__ */ jsx(ToolHeader, {}),
|
|
1169
|
+
isExpanded && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1170
|
+
/* @__PURE__ */ jsx(ToolInput, {}),
|
|
1171
|
+
/* @__PURE__ */ jsx(ToolOutput, {})
|
|
1172
|
+
] })
|
|
1173
|
+
] })
|
|
808
1174
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
const
|
|
817
|
-
const
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
1175
|
+
) });
|
|
1176
|
+
}
|
|
1177
|
+
function ToolHeader({
|
|
1178
|
+
className,
|
|
1179
|
+
icon,
|
|
1180
|
+
showToggle = true
|
|
1181
|
+
}) {
|
|
1182
|
+
const { toolInvocation, isExpanded, toggleExpanded } = useTool();
|
|
1183
|
+
const status = toolInvocation.state === "result" ? "success" : "pending";
|
|
1184
|
+
const formattedName = formatToolName(toolInvocation.toolName);
|
|
1185
|
+
const toolIcon = icon;
|
|
1186
|
+
return /* @__PURE__ */ jsxs(
|
|
1187
|
+
"button",
|
|
1188
|
+
{
|
|
1189
|
+
onClick: showToggle ? toggleExpanded : void 0,
|
|
1190
|
+
className: cn(
|
|
1191
|
+
"ash-tool-header",
|
|
1192
|
+
"w-full flex items-center gap-2",
|
|
1193
|
+
"px-3 py-2",
|
|
1194
|
+
"text-left",
|
|
1195
|
+
showToggle && "cursor-pointer hover:bg-white/[0.03] transition-colors",
|
|
1196
|
+
className
|
|
1197
|
+
),
|
|
1198
|
+
children: [
|
|
1199
|
+
/* @__PURE__ */ jsx(StatusIndicator, { status, size: "sm" }),
|
|
1200
|
+
toolIcon ? /* @__PURE__ */ jsx("span", { className: "text-[var(--ash-text-muted,rgba(255,255,255,0.5))]", children: toolIcon }) : /* @__PURE__ */ jsx("span", { className: "text-[var(--ash-text-muted,rgba(255,255,255,0.5))]", children: /* @__PURE__ */ jsxs("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
|
|
1201
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }),
|
|
1202
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" })
|
|
1203
|
+
] }) }),
|
|
1204
|
+
/* @__PURE__ */ jsx(
|
|
1205
|
+
"span",
|
|
1206
|
+
{
|
|
1207
|
+
className: cn(
|
|
1208
|
+
"flex-1 font-medium",
|
|
1209
|
+
"text-[var(--ash-font-size-sm,12px)]",
|
|
1210
|
+
"text-[var(--ash-text-primary,rgba(255,255,255,0.9))]"
|
|
1211
|
+
),
|
|
1212
|
+
children: formattedName
|
|
1213
|
+
}
|
|
1214
|
+
),
|
|
1215
|
+
/* @__PURE__ */ jsx(
|
|
1216
|
+
"span",
|
|
1217
|
+
{
|
|
1218
|
+
className: cn(
|
|
1219
|
+
"text-[var(--ash-font-size-xs,10px)]",
|
|
1220
|
+
"text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
|
|
1221
|
+
"truncate max-w-[200px]"
|
|
1222
|
+
),
|
|
1223
|
+
children: Object.keys(toolInvocation.args).length > 0 && `(${Object.keys(toolInvocation.args).join(", ")})`
|
|
1224
|
+
}
|
|
1225
|
+
),
|
|
1226
|
+
showToggle && /* @__PURE__ */ jsx(
|
|
1227
|
+
"svg",
|
|
1228
|
+
{
|
|
1229
|
+
className: cn(
|
|
1230
|
+
"w-4 h-4 text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
|
|
1231
|
+
"transition-transform",
|
|
1232
|
+
isExpanded && "rotate-180"
|
|
1233
|
+
),
|
|
1234
|
+
fill: "none",
|
|
1235
|
+
stroke: "currentColor",
|
|
1236
|
+
viewBox: "0 0 24 24",
|
|
1237
|
+
children: /* @__PURE__ */ jsx(
|
|
1238
|
+
"path",
|
|
1239
|
+
{
|
|
1240
|
+
strokeLinecap: "round",
|
|
1241
|
+
strokeLinejoin: "round",
|
|
1242
|
+
strokeWidth: 2,
|
|
1243
|
+
d: "M19 9l-7 7-7-7"
|
|
1244
|
+
}
|
|
1245
|
+
)
|
|
1246
|
+
}
|
|
1247
|
+
)
|
|
1248
|
+
]
|
|
836
1249
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
1252
|
+
function ToolInput({ className, maxHeight = 200 }) {
|
|
1253
|
+
const { toolInvocation } = useTool();
|
|
1254
|
+
if (!toolInvocation.args || Object.keys(toolInvocation.args).length === 0) {
|
|
840
1255
|
return null;
|
|
841
1256
|
}
|
|
842
|
-
const { agentType, description, prompt } = agentData;
|
|
843
|
-
const indentClass = depth > 0 ? "ml-4" : "";
|
|
844
1257
|
return /* @__PURE__ */ jsxs(
|
|
845
1258
|
"div",
|
|
846
1259
|
{
|
|
847
1260
|
className: cn(
|
|
848
|
-
"
|
|
849
|
-
|
|
850
|
-
indentClass,
|
|
1261
|
+
"ash-tool-input",
|
|
1262
|
+
"border-t border-[var(--ash-border-subtle,rgba(255,255,255,0.04))]",
|
|
851
1263
|
className
|
|
852
1264
|
),
|
|
853
1265
|
children: [
|
|
854
|
-
/* @__PURE__ */
|
|
855
|
-
|
|
1266
|
+
/* @__PURE__ */ jsx("div", { className: "ash-tool-section-header", children: "Input" }),
|
|
1267
|
+
/* @__PURE__ */ jsx(
|
|
1268
|
+
"div",
|
|
856
1269
|
{
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
children:
|
|
860
|
-
/* @__PURE__ */ jsx(
|
|
861
|
-
ChevronRightIcon,
|
|
862
|
-
{
|
|
863
|
-
className: cn(
|
|
864
|
-
"w-4 h-4 text-white/40 transition-transform duration-200 shrink-0",
|
|
865
|
-
expanded && "rotate-90"
|
|
866
|
-
)
|
|
867
|
-
}
|
|
868
|
-
),
|
|
869
|
-
/* @__PURE__ */ jsx(
|
|
870
|
-
"div",
|
|
871
|
-
{
|
|
872
|
-
className: cn(
|
|
873
|
-
"w-6 h-6 rounded-lg flex items-center justify-center shrink-0",
|
|
874
|
-
isRunning ? "bg-yellow-500/20" : status === "failed" ? "bg-red-500/20" : "bg-[var(--ash-accent)]/20"
|
|
875
|
-
),
|
|
876
|
-
children: isRunning ? /* @__PURE__ */ jsx(
|
|
877
|
-
SpinnerIcon,
|
|
878
|
-
{
|
|
879
|
-
className: "w-3.5 h-3.5 text-yellow-400 animate-spin"
|
|
880
|
-
}
|
|
881
|
-
) : /* @__PURE__ */ jsx(
|
|
882
|
-
BotIcon,
|
|
883
|
-
{
|
|
884
|
-
className: cn(
|
|
885
|
-
"w-3.5 h-3.5",
|
|
886
|
-
status === "failed" ? "text-red-400" : "text-[var(--ash-accent)]"
|
|
887
|
-
)
|
|
888
|
-
}
|
|
889
|
-
)
|
|
890
|
-
}
|
|
891
|
-
),
|
|
892
|
-
/* @__PURE__ */ jsx(
|
|
893
|
-
"span",
|
|
894
|
-
{
|
|
895
|
-
className: cn(
|
|
896
|
-
"px-2 py-0.5 rounded text-xs font-medium shrink-0",
|
|
897
|
-
isRunning ? "bg-yellow-500/20 text-yellow-400" : status === "failed" ? "bg-red-500/20 text-red-400" : "bg-white/10 text-white/70"
|
|
898
|
-
),
|
|
899
|
-
children: agentType
|
|
900
|
-
}
|
|
901
|
-
),
|
|
902
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm text-white/80 truncate flex-1 text-left", children: description || summary }),
|
|
903
|
-
toolCount > 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs text-white/50 shrink-0", children: [
|
|
904
|
-
toolCount,
|
|
905
|
-
" tool call",
|
|
906
|
-
toolCount !== 1 ? "s" : ""
|
|
907
|
-
] }),
|
|
908
|
-
isRunning && elapsedTime && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-white/40 shrink-0", children: [
|
|
909
|
-
/* @__PURE__ */ jsx(ClockIcon, { className: "w-3 h-3" }),
|
|
910
|
-
/* @__PURE__ */ jsx("span", { children: elapsedTime })
|
|
911
|
-
] }),
|
|
912
|
-
/* @__PURE__ */ jsx("span", { className: "text-white/30 shrink-0", children: "..." })
|
|
913
|
-
]
|
|
1270
|
+
className: "p-3 overflow-auto",
|
|
1271
|
+
style: { maxHeight },
|
|
1272
|
+
children: /* @__PURE__ */ jsx(JsonDisplay, { value: toolInvocation.args })
|
|
914
1273
|
}
|
|
915
|
-
)
|
|
916
|
-
expanded && /* @__PURE__ */ jsxs("div", { className: "border-t border-white/5 bg-black/20", children: [
|
|
917
|
-
prompt && /* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-b border-white/5", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-white/70 whitespace-pre-wrap", children: prompt.length > 500 ? prompt.substring(0, 500) + "..." : prompt }) }),
|
|
918
|
-
nestedToolCalls && nestedToolCalls.length > 0 && /* @__PURE__ */ jsx("div", { className: "p-3 space-y-2", children: nestedToolCalls.map((nestedCall) => /* @__PURE__ */ jsx("div", { children: nestedCall.actionType.action === "agent_tool" ? /* @__PURE__ */ jsx(
|
|
919
|
-
AgentToolCard,
|
|
920
|
-
{
|
|
921
|
-
toolCall: nestedCall,
|
|
922
|
-
defaultExpanded: false,
|
|
923
|
-
depth: depth + 1
|
|
924
|
-
}
|
|
925
|
-
) : /* @__PURE__ */ jsx(
|
|
926
|
-
ToolCallCard,
|
|
927
|
-
{
|
|
928
|
-
toolCall: nestedCall,
|
|
929
|
-
defaultExpanded: false
|
|
930
|
-
}
|
|
931
|
-
) }, nestedCall.id)) }),
|
|
932
|
-
(!nestedToolCalls || nestedToolCalls.length === 0) && isRunning && /* @__PURE__ */ jsx("div", { className: "px-4 py-6 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-white/40", children: [
|
|
933
|
-
/* @__PURE__ */ jsx(SpinnerIcon, { className: "w-4 h-4 animate-spin" }),
|
|
934
|
-
/* @__PURE__ */ jsx("span", { children: "Agent is working..." })
|
|
935
|
-
] }) }),
|
|
936
|
-
(!nestedToolCalls || nestedToolCalls.length === 0) && !isRunning && /* @__PURE__ */ jsx("div", { className: "px-4 py-4 text-sm text-white/40 text-center", children: "No tool calls recorded" })
|
|
937
|
-
] })
|
|
1274
|
+
)
|
|
938
1275
|
]
|
|
939
1276
|
}
|
|
940
1277
|
);
|
|
941
1278
|
}
|
|
942
|
-
function
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
return /* @__PURE__ */ jsx("div", { className: "px-3 py-2", children });
|
|
947
|
-
}
|
|
948
|
-
function CommandRunDetails({ action }) {
|
|
949
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
950
|
-
action.command && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
951
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "COMMAND" }),
|
|
952
|
-
/* @__PURE__ */ jsx(SectionContent, { children: /* @__PURE__ */ jsx(CodeBlock, { children: action.command }) })
|
|
953
|
-
] }),
|
|
954
|
-
action.result?.output && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
955
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "OUTPUT" }),
|
|
956
|
-
/* @__PURE__ */ jsxs(SectionContent, { children: [
|
|
957
|
-
/* @__PURE__ */ jsx(CodeBlock, { maxHeight: 300, children: action.result.output }),
|
|
958
|
-
action.result.exitCode !== void 0 && action.result.exitCode !== 0 && /* @__PURE__ */ jsxs("div", { className: "mt-2 text-xs text-red-400", children: [
|
|
959
|
-
"Exit code: ",
|
|
960
|
-
action.result.exitCode
|
|
961
|
-
] })
|
|
962
|
-
] })
|
|
963
|
-
] })
|
|
964
|
-
] });
|
|
965
|
-
}
|
|
966
|
-
function FileReadDetails({ action }) {
|
|
967
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
968
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "PATH" }),
|
|
969
|
-
/* @__PURE__ */ jsxs(SectionContent, { children: [
|
|
970
|
-
/* @__PURE__ */ jsx("code", { className: "text-xs font-mono bg-white/10 text-white/90 px-1 py-0.5 rounded", children: action.path }),
|
|
971
|
-
(action.offset !== void 0 || action.limit !== void 0) && /* @__PURE__ */ jsxs("div", { className: "mt-1 text-xs text-white/50", children: [
|
|
972
|
-
action.offset !== void 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
973
|
-
"Offset: ",
|
|
974
|
-
action.offset
|
|
975
|
-
] }),
|
|
976
|
-
action.offset !== void 0 && action.limit !== void 0 && /* @__PURE__ */ jsx("span", { children: " \xB7 " }),
|
|
977
|
-
action.limit !== void 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
978
|
-
"Limit: ",
|
|
979
|
-
action.limit
|
|
980
|
-
] })
|
|
981
|
-
] })
|
|
982
|
-
] })
|
|
983
|
-
] });
|
|
984
|
-
}
|
|
985
|
-
function FileEditDetails({ action }) {
|
|
986
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
987
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "PATH" }),
|
|
988
|
-
/* @__PURE__ */ jsx(SectionContent, { children: /* @__PURE__ */ jsx("code", { className: "text-xs font-mono bg-white/10 text-white/90 px-1 py-0.5 rounded", children: action.path }) }),
|
|
989
|
-
action.oldString && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
990
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "OLD" }),
|
|
991
|
-
/* @__PURE__ */ jsx(SectionContent, { children: /* @__PURE__ */ jsx(CodeBlock, { children: action.oldString }) })
|
|
992
|
-
] }),
|
|
993
|
-
action.newString && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
994
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "NEW" }),
|
|
995
|
-
/* @__PURE__ */ jsx(SectionContent, { children: /* @__PURE__ */ jsx(CodeBlock, { children: action.newString }) })
|
|
996
|
-
] })
|
|
997
|
-
] });
|
|
998
|
-
}
|
|
999
|
-
function FileWriteDetails({ action }) {
|
|
1000
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1001
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "PATH" }),
|
|
1002
|
-
/* @__PURE__ */ jsx(SectionContent, { children: /* @__PURE__ */ jsx("code", { className: "text-xs font-mono bg-white/10 text-white/90 px-1 py-0.5 rounded", children: action.path }) }),
|
|
1003
|
-
action.content && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1004
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "CONTENT" }),
|
|
1005
|
-
/* @__PURE__ */ jsx(SectionContent, { children: /* @__PURE__ */ jsx(CodeBlock, { maxHeight: 300, children: action.content }) })
|
|
1006
|
-
] })
|
|
1007
|
-
] });
|
|
1008
|
-
}
|
|
1009
|
-
function SearchDetails({ action }) {
|
|
1010
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1011
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "PATTERN" }),
|
|
1012
|
-
/* @__PURE__ */ jsxs(SectionContent, { children: [
|
|
1013
|
-
/* @__PURE__ */ jsx("code", { className: "text-xs font-mono bg-white/10 text-white/90 px-1 py-0.5 rounded", children: action.pattern }),
|
|
1014
|
-
(action.path || action.glob || action.type) && /* @__PURE__ */ jsxs("div", { className: "mt-1 text-xs text-white/50", children: [
|
|
1015
|
-
action.path && /* @__PURE__ */ jsxs("span", { children: [
|
|
1016
|
-
"Path: ",
|
|
1017
|
-
action.path
|
|
1018
|
-
] }),
|
|
1019
|
-
action.glob && /* @__PURE__ */ jsxs("span", { children: [
|
|
1020
|
-
"Glob: ",
|
|
1021
|
-
action.glob
|
|
1022
|
-
] }),
|
|
1023
|
-
action.type && /* @__PURE__ */ jsxs("span", { children: [
|
|
1024
|
-
"Type: ",
|
|
1025
|
-
action.type
|
|
1026
|
-
] })
|
|
1027
|
-
] })
|
|
1028
|
-
] })
|
|
1029
|
-
] });
|
|
1030
|
-
}
|
|
1031
|
-
function GlobDetails({ action }) {
|
|
1032
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1033
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "PATTERN" }),
|
|
1034
|
-
/* @__PURE__ */ jsxs(SectionContent, { children: [
|
|
1035
|
-
/* @__PURE__ */ jsx("code", { className: "text-xs font-mono bg-white/10 text-white/90 px-1 py-0.5 rounded", children: action.pattern }),
|
|
1036
|
-
action.path && /* @__PURE__ */ jsxs("div", { className: "mt-1 text-xs text-white/50", children: [
|
|
1037
|
-
"Path: ",
|
|
1038
|
-
action.path
|
|
1039
|
-
] })
|
|
1040
|
-
] })
|
|
1041
|
-
] });
|
|
1042
|
-
}
|
|
1043
|
-
function WebFetchDetails({ action }) {
|
|
1044
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1045
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "URL" }),
|
|
1046
|
-
/* @__PURE__ */ jsxs(SectionContent, { children: [
|
|
1047
|
-
/* @__PURE__ */ jsx(
|
|
1048
|
-
"a",
|
|
1049
|
-
{
|
|
1050
|
-
href: action.url,
|
|
1051
|
-
target: "_blank",
|
|
1052
|
-
rel: "noopener noreferrer",
|
|
1053
|
-
className: "text-xs text-blue-400 hover:text-blue-300 underline break-all",
|
|
1054
|
-
children: action.url
|
|
1055
|
-
}
|
|
1056
|
-
),
|
|
1057
|
-
action.prompt && /* @__PURE__ */ jsx("div", { className: "mt-2 text-xs text-white/50", children: action.prompt })
|
|
1058
|
-
] })
|
|
1059
|
-
] });
|
|
1060
|
-
}
|
|
1061
|
-
function WebSearchDetails({ action }) {
|
|
1062
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1063
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "QUERY" }),
|
|
1064
|
-
/* @__PURE__ */ jsx(SectionContent, { children: /* @__PURE__ */ jsx("span", { className: "text-sm text-white/90", children: action.query }) })
|
|
1065
|
-
] });
|
|
1066
|
-
}
|
|
1067
|
-
function McpToolDetails({ action }) {
|
|
1068
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1069
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "TOOL" }),
|
|
1070
|
-
/* @__PURE__ */ jsx(SectionContent, { children: /* @__PURE__ */ jsxs("code", { className: "text-xs font-mono bg-white/10 text-white/90 px-1 py-0.5 rounded", children: [
|
|
1071
|
-
action.serverName,
|
|
1072
|
-
":",
|
|
1073
|
-
action.toolName
|
|
1074
|
-
] }) }),
|
|
1075
|
-
action.arguments && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1076
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "ARGS" }),
|
|
1077
|
-
/* @__PURE__ */ jsx(SectionContent, { children: /* @__PURE__ */ jsx(JsonDisplay, { value: action.arguments }) })
|
|
1078
|
-
] }),
|
|
1079
|
-
action.result && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1080
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "RESULT" }),
|
|
1081
|
-
/* @__PURE__ */ jsx(SectionContent, { children: action.result.type === "markdown" ? /* @__PURE__ */ jsx(CodeBlock, { children: String(action.result.value) }) : /* @__PURE__ */ jsx(JsonDisplay, { value: action.result.value }) })
|
|
1082
|
-
] })
|
|
1083
|
-
] });
|
|
1084
|
-
}
|
|
1085
|
-
function GenericToolDetails({ action }) {
|
|
1086
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1087
|
-
action.arguments && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1088
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "ARGS" }),
|
|
1089
|
-
/* @__PURE__ */ jsx(SectionContent, { children: /* @__PURE__ */ jsx(JsonDisplay, { value: action.arguments }) })
|
|
1090
|
-
] }),
|
|
1091
|
-
action.result && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1092
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "RESULT" }),
|
|
1093
|
-
/* @__PURE__ */ jsx(SectionContent, { children: action.result.type === "markdown" ? /* @__PURE__ */ jsx(CodeBlock, { children: String(action.result.value) }) : /* @__PURE__ */ jsx(JsonDisplay, { value: action.result.value }) })
|
|
1094
|
-
] })
|
|
1095
|
-
] });
|
|
1096
|
-
}
|
|
1097
|
-
function TodoWriteDetails({ action }) {
|
|
1098
|
-
const { todos, stats } = action;
|
|
1099
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1100
|
-
stats && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1101
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "PROGRESS" }),
|
|
1102
|
-
/* @__PURE__ */ jsxs(SectionContent, { children: [
|
|
1103
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1104
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 h-2 bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
1105
|
-
"div",
|
|
1106
|
-
{
|
|
1107
|
-
className: "h-full bg-emerald-400 rounded-full transition-all duration-500 ease-out",
|
|
1108
|
-
style: { width: `${stats.total > 0 ? stats.completed / stats.total * 100 : 0}%` }
|
|
1109
|
-
}
|
|
1110
|
-
) }),
|
|
1111
|
-
/* @__PURE__ */ jsxs("span", { className: "text-xs text-white/60 tabular-nums", children: [
|
|
1112
|
-
stats.completed,
|
|
1113
|
-
"/",
|
|
1114
|
-
stats.total
|
|
1115
|
-
] })
|
|
1116
|
-
] }),
|
|
1117
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-3 mt-2 text-xs", children: [
|
|
1118
|
-
stats.inProgress > 0 && /* @__PURE__ */ jsxs("span", { className: "text-yellow-400", children: [
|
|
1119
|
-
stats.inProgress,
|
|
1120
|
-
" in progress"
|
|
1121
|
-
] }),
|
|
1122
|
-
stats.pending > 0 && /* @__PURE__ */ jsxs("span", { className: "text-white/40", children: [
|
|
1123
|
-
stats.pending,
|
|
1124
|
-
" pending"
|
|
1125
|
-
] })
|
|
1126
|
-
] })
|
|
1127
|
-
] })
|
|
1128
|
-
] }),
|
|
1129
|
-
/* @__PURE__ */ jsx(SectionHeader, { children: "TASKS" }),
|
|
1130
|
-
/* @__PURE__ */ jsx(SectionContent, { children: /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: todos.map((todo, index) => {
|
|
1131
|
-
const displayText = todo.status === "in_progress" ? todo.activeForm : todo.content;
|
|
1132
|
-
return /* @__PURE__ */ jsxs(
|
|
1133
|
-
"div",
|
|
1134
|
-
{
|
|
1135
|
-
className: cn(
|
|
1136
|
-
"flex items-start gap-2 py-1 transition-all duration-200",
|
|
1137
|
-
todo.status === "completed" && "opacity-50",
|
|
1138
|
-
todo.status === "in_progress" && "bg-yellow-500/10 -mx-2 px-2 rounded"
|
|
1139
|
-
),
|
|
1140
|
-
children: [
|
|
1141
|
-
todo.status === "completed" ? /* @__PURE__ */ jsx(CheckCircleIcon, { className: "w-4 h-4 text-emerald-400 shrink-0 mt-0.5" }) : todo.status === "in_progress" ? /* @__PURE__ */ jsx(LoaderIcon, { className: "w-4 h-4 text-yellow-400 animate-spin shrink-0 mt-0.5" }) : /* @__PURE__ */ jsx(CircleIcon, { className: "w-4 h-4 text-white/30 shrink-0 mt-0.5" }),
|
|
1142
|
-
/* @__PURE__ */ jsxs(
|
|
1143
|
-
"span",
|
|
1144
|
-
{
|
|
1145
|
-
className: cn(
|
|
1146
|
-
"text-sm leading-relaxed",
|
|
1147
|
-
todo.status === "completed" ? "text-white/50 line-through" : "text-white/80"
|
|
1148
|
-
),
|
|
1149
|
-
children: [
|
|
1150
|
-
/* @__PURE__ */ jsxs("span", { className: "text-white/40 mr-1.5", children: [
|
|
1151
|
-
index + 1,
|
|
1152
|
-
"."
|
|
1153
|
-
] }),
|
|
1154
|
-
displayText
|
|
1155
|
-
]
|
|
1156
|
-
}
|
|
1157
|
-
)
|
|
1158
|
-
]
|
|
1159
|
-
},
|
|
1160
|
-
`${todo.content}-${index}`
|
|
1161
|
-
);
|
|
1162
|
-
}) }) })
|
|
1163
|
-
] });
|
|
1164
|
-
}
|
|
1165
|
-
function ToolDetails({ actionType }) {
|
|
1166
|
-
switch (actionType.action) {
|
|
1167
|
-
case "command_run":
|
|
1168
|
-
return /* @__PURE__ */ jsx(CommandRunDetails, { action: actionType });
|
|
1169
|
-
case "file_read":
|
|
1170
|
-
return /* @__PURE__ */ jsx(FileReadDetails, { action: actionType });
|
|
1171
|
-
case "file_edit":
|
|
1172
|
-
return /* @__PURE__ */ jsx(FileEditDetails, { action: actionType });
|
|
1173
|
-
case "file_write":
|
|
1174
|
-
return /* @__PURE__ */ jsx(FileWriteDetails, { action: actionType });
|
|
1175
|
-
case "search":
|
|
1176
|
-
return /* @__PURE__ */ jsx(SearchDetails, { action: actionType });
|
|
1177
|
-
case "glob":
|
|
1178
|
-
return /* @__PURE__ */ jsx(GlobDetails, { action: actionType });
|
|
1179
|
-
case "web_fetch":
|
|
1180
|
-
return /* @__PURE__ */ jsx(WebFetchDetails, { action: actionType });
|
|
1181
|
-
case "web_search":
|
|
1182
|
-
return /* @__PURE__ */ jsx(WebSearchDetails, { action: actionType });
|
|
1183
|
-
case "mcp_tool":
|
|
1184
|
-
return /* @__PURE__ */ jsx(McpToolDetails, { action: actionType });
|
|
1185
|
-
case "generic_tool":
|
|
1186
|
-
return /* @__PURE__ */ jsx(GenericToolDetails, { action: actionType });
|
|
1187
|
-
case "todo_write":
|
|
1188
|
-
return /* @__PURE__ */ jsx(TodoWriteDetails, { action: actionType });
|
|
1189
|
-
default:
|
|
1190
|
-
return null;
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
function hasDetails(actionType) {
|
|
1194
|
-
switch (actionType.action) {
|
|
1195
|
-
case "command_run":
|
|
1196
|
-
return Boolean(actionType.command || actionType.result?.output);
|
|
1197
|
-
case "file_read":
|
|
1198
|
-
return true;
|
|
1199
|
-
case "file_edit":
|
|
1200
|
-
return Boolean(actionType.oldString || actionType.newString);
|
|
1201
|
-
case "file_write":
|
|
1202
|
-
return Boolean(actionType.content);
|
|
1203
|
-
case "search":
|
|
1204
|
-
return true;
|
|
1205
|
-
case "glob":
|
|
1206
|
-
return true;
|
|
1207
|
-
case "web_fetch":
|
|
1208
|
-
return true;
|
|
1209
|
-
case "web_search":
|
|
1210
|
-
return true;
|
|
1211
|
-
case "mcp_tool":
|
|
1212
|
-
return Boolean(actionType.arguments || actionType.result);
|
|
1213
|
-
case "generic_tool":
|
|
1214
|
-
return Boolean(actionType.arguments || actionType.result);
|
|
1215
|
-
case "todo_write":
|
|
1216
|
-
return actionType.todos.length > 0;
|
|
1217
|
-
case "agent_tool":
|
|
1218
|
-
return true;
|
|
1219
|
-
// Always expandable (handled by AgentToolCard)
|
|
1220
|
-
default:
|
|
1221
|
-
return false;
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
function ToolCallCard({ toolCall, defaultExpanded = false, className }) {
|
|
1225
|
-
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
1226
|
-
const { actionType, status, summary } = toolCall;
|
|
1227
|
-
if (actionType.action === "agent_tool") {
|
|
1228
|
-
return /* @__PURE__ */ jsx(
|
|
1229
|
-
AgentToolCard,
|
|
1230
|
-
{
|
|
1231
|
-
toolCall,
|
|
1232
|
-
defaultExpanded,
|
|
1233
|
-
className
|
|
1234
|
-
}
|
|
1235
|
-
);
|
|
1279
|
+
function ToolOutput({ className, maxHeight = 300 }) {
|
|
1280
|
+
const { toolInvocation } = useTool();
|
|
1281
|
+
if (toolInvocation.state !== "result" || !toolInvocation.result) {
|
|
1282
|
+
return null;
|
|
1236
1283
|
}
|
|
1237
|
-
const
|
|
1238
|
-
const
|
|
1239
|
-
|
|
1240
|
-
success: "border-white/10",
|
|
1241
|
-
failed: "border-red-500/30"
|
|
1242
|
-
};
|
|
1284
|
+
const result = toolInvocation.result;
|
|
1285
|
+
const isString = typeof result === "string";
|
|
1286
|
+
const isError = typeof result === "object" && result !== null && "error" in result;
|
|
1243
1287
|
return /* @__PURE__ */ jsxs(
|
|
1244
1288
|
"div",
|
|
1245
1289
|
{
|
|
1246
1290
|
className: cn(
|
|
1247
|
-
"
|
|
1248
|
-
|
|
1291
|
+
"ash-tool-output",
|
|
1292
|
+
"border-t border-[var(--ash-border-subtle,rgba(255,255,255,0.04))]",
|
|
1293
|
+
isError && "bg-red-500/5",
|
|
1249
1294
|
className
|
|
1250
1295
|
),
|
|
1251
1296
|
children: [
|
|
1252
|
-
/* @__PURE__ */
|
|
1253
|
-
"
|
|
1297
|
+
/* @__PURE__ */ jsx(
|
|
1298
|
+
"div",
|
|
1254
1299
|
{
|
|
1255
|
-
onClick: () => canExpand && setExpanded(!expanded),
|
|
1256
1300
|
className: cn(
|
|
1257
|
-
"
|
|
1258
|
-
|
|
1301
|
+
"ash-tool-section-header",
|
|
1302
|
+
isError && "text-red-400"
|
|
1259
1303
|
),
|
|
1260
|
-
|
|
1261
|
-
children: [
|
|
1262
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0 flex-1", children: [
|
|
1263
|
-
/* @__PURE__ */ jsx("div", { className: cn(
|
|
1264
|
-
"w-6 h-6 rounded-lg flex items-center justify-center shrink-0",
|
|
1265
|
-
status === "pending" ? "bg-yellow-500/20" : status === "failed" ? "bg-red-500/20" : "bg-[var(--ash-accent)]/20"
|
|
1266
|
-
), children: /* @__PURE__ */ jsx(
|
|
1267
|
-
ActionIcon,
|
|
1268
|
-
{
|
|
1269
|
-
actionType,
|
|
1270
|
-
className: cn(
|
|
1271
|
-
"w-3.5 h-3.5",
|
|
1272
|
-
status === "pending" ? "text-yellow-400" : status === "failed" ? "text-red-400" : "text-[var(--ash-accent)]"
|
|
1273
|
-
)
|
|
1274
|
-
}
|
|
1275
|
-
) }),
|
|
1276
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-white shrink-0", children: getActionLabel(actionType) }),
|
|
1277
|
-
/* @__PURE__ */ jsx("span", { className: "font-mono text-sm truncate text-white/60 min-w-0", children: summary })
|
|
1278
|
-
] }),
|
|
1279
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
1280
|
-
/* @__PURE__ */ jsx(StatusIndicator, { status, size: "sm" }),
|
|
1281
|
-
canExpand && /* @__PURE__ */ jsx(
|
|
1282
|
-
ChevronDownIcon,
|
|
1283
|
-
{
|
|
1284
|
-
className: cn(
|
|
1285
|
-
"w-4 h-4 text-white/40 transition-transform duration-200",
|
|
1286
|
-
expanded && "rotate-180"
|
|
1287
|
-
)
|
|
1288
|
-
}
|
|
1289
|
-
)
|
|
1290
|
-
] })
|
|
1291
|
-
]
|
|
1304
|
+
children: isError ? "Error" : "Output"
|
|
1292
1305
|
}
|
|
1293
1306
|
),
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1307
|
+
/* @__PURE__ */ jsx(
|
|
1308
|
+
"div",
|
|
1309
|
+
{
|
|
1310
|
+
className: "p-3 overflow-auto",
|
|
1311
|
+
style: { maxHeight },
|
|
1312
|
+
children: isString ? /* @__PURE__ */ jsx(CodeBlock, { maxHeight: maxHeight - 24, children: result }) : /* @__PURE__ */ jsx(JsonDisplay, { value: result })
|
|
1313
|
+
}
|
|
1314
|
+
)
|
|
1301
1315
|
]
|
|
1302
1316
|
}
|
|
1303
1317
|
);
|
|
1304
1318
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
}
|
|
1316
|
-
function DefaultMentionBadge({ segment }) {
|
|
1317
|
-
const bgColor = segment.color ? `${segment.color}20` : "rgba(34, 197, 94, 0.2)";
|
|
1318
|
-
const textColor = segment.color || "#22c55e";
|
|
1319
|
-
const borderColor = segment.color ? `${segment.color}40` : "rgba(34, 197, 94, 0.4)";
|
|
1320
|
-
return /* @__PURE__ */ jsxs(
|
|
1321
|
-
"span",
|
|
1319
|
+
function ToolList({
|
|
1320
|
+
toolInvocations,
|
|
1321
|
+
className,
|
|
1322
|
+
defaultExpanded = false
|
|
1323
|
+
}) {
|
|
1324
|
+
if (!toolInvocations || toolInvocations.length === 0) {
|
|
1325
|
+
return null;
|
|
1326
|
+
}
|
|
1327
|
+
return /* @__PURE__ */ jsx(
|
|
1328
|
+
"div",
|
|
1322
1329
|
{
|
|
1323
|
-
className:
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1330
|
+
className: cn(
|
|
1331
|
+
"ash-tool-list",
|
|
1332
|
+
"flex flex-col gap-2",
|
|
1333
|
+
className
|
|
1334
|
+
),
|
|
1335
|
+
children: toolInvocations.map((inv) => /* @__PURE__ */ jsx(
|
|
1336
|
+
Tool,
|
|
1337
|
+
{
|
|
1338
|
+
toolInvocation: inv,
|
|
1339
|
+
defaultExpanded
|
|
1340
|
+
},
|
|
1341
|
+
inv.toolCallId
|
|
1342
|
+
))
|
|
1334
1343
|
}
|
|
1335
1344
|
);
|
|
1336
1345
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1346
|
+
var ReasoningContext = createContext(null);
|
|
1347
|
+
function useReasoning() {
|
|
1348
|
+
const context = useContext(ReasoningContext);
|
|
1349
|
+
if (!context) {
|
|
1350
|
+
throw new Error("useReasoning must be used within a Reasoning");
|
|
1351
|
+
}
|
|
1352
|
+
return context;
|
|
1353
|
+
}
|
|
1354
|
+
function Reasoning({
|
|
1355
|
+
children,
|
|
1356
|
+
isStreaming = false,
|
|
1357
|
+
className,
|
|
1358
|
+
autoExpand = true,
|
|
1359
|
+
autoCollapse = true,
|
|
1360
|
+
initialDuration = 0
|
|
1341
1361
|
}) {
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
if (renderers?.renderComponent) {
|
|
1354
|
-
return /* @__PURE__ */ jsx(Fragment, { children: renderers.renderComponent({ segment }) }, key);
|
|
1362
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1363
|
+
const [duration, setDuration] = useState(initialDuration);
|
|
1364
|
+
const startTimeRef = useRef(null);
|
|
1365
|
+
const intervalRef = useRef(null);
|
|
1366
|
+
useEffect(() => {
|
|
1367
|
+
if (isStreaming && autoExpand) {
|
|
1368
|
+
setIsOpen(true);
|
|
1369
|
+
startTimeRef.current = Date.now();
|
|
1370
|
+
intervalRef.current = setInterval(() => {
|
|
1371
|
+
if (startTimeRef.current) {
|
|
1372
|
+
setDuration(Math.floor((Date.now() - startTimeRef.current) / 1e3));
|
|
1355
1373
|
}
|
|
1356
|
-
|
|
1357
|
-
"[component: ",
|
|
1358
|
-
segment.componentType,
|
|
1359
|
-
"]"
|
|
1360
|
-
] }, key);
|
|
1361
|
-
default:
|
|
1362
|
-
return null;
|
|
1374
|
+
}, 1e3);
|
|
1363
1375
|
}
|
|
1364
|
-
|
|
1376
|
+
return () => {
|
|
1377
|
+
if (intervalRef.current) {
|
|
1378
|
+
clearInterval(intervalRef.current);
|
|
1379
|
+
intervalRef.current = null;
|
|
1380
|
+
}
|
|
1381
|
+
};
|
|
1382
|
+
}, [isStreaming, autoExpand]);
|
|
1383
|
+
useEffect(() => {
|
|
1384
|
+
if (!isStreaming && autoCollapse && startTimeRef.current) {
|
|
1385
|
+
const timeout = setTimeout(() => {
|
|
1386
|
+
setIsOpen(false);
|
|
1387
|
+
}, 500);
|
|
1388
|
+
startTimeRef.current = null;
|
|
1389
|
+
if (intervalRef.current) {
|
|
1390
|
+
clearInterval(intervalRef.current);
|
|
1391
|
+
intervalRef.current = null;
|
|
1392
|
+
}
|
|
1393
|
+
return () => clearTimeout(timeout);
|
|
1394
|
+
}
|
|
1395
|
+
return void 0;
|
|
1396
|
+
}, [isStreaming, autoCollapse]);
|
|
1397
|
+
const contextValue = {
|
|
1398
|
+
isOpen,
|
|
1399
|
+
setIsOpen,
|
|
1400
|
+
isStreaming,
|
|
1401
|
+
duration
|
|
1402
|
+
};
|
|
1403
|
+
return /* @__PURE__ */ jsx(ReasoningContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
1404
|
+
"div",
|
|
1405
|
+
{
|
|
1406
|
+
className: cn(
|
|
1407
|
+
"ash-reasoning",
|
|
1408
|
+
"rounded-[var(--ash-radius-md,0.5rem)]",
|
|
1409
|
+
"border",
|
|
1410
|
+
isStreaming ? "border-[var(--ash-thinking-border,rgba(147,51,234,0.2))] bg-[var(--ash-thinking-bg,rgba(147,51,234,0.06))]" : "border-[var(--ash-border,rgba(255,255,255,0.08))] bg-[var(--ash-surface-dark,#0a0a0a)]",
|
|
1411
|
+
"overflow-hidden",
|
|
1412
|
+
className
|
|
1413
|
+
),
|
|
1414
|
+
"data-reasoning-streaming": isStreaming,
|
|
1415
|
+
"data-reasoning-open": isOpen,
|
|
1416
|
+
children
|
|
1417
|
+
}
|
|
1418
|
+
) });
|
|
1365
1419
|
}
|
|
1366
|
-
function
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1420
|
+
function ReasoningTrigger({
|
|
1421
|
+
className,
|
|
1422
|
+
label = "Thinking",
|
|
1423
|
+
showDuration = true
|
|
1424
|
+
}) {
|
|
1425
|
+
const { isOpen, setIsOpen, isStreaming, duration } = useReasoning();
|
|
1426
|
+
const formatDuration = (seconds) => {
|
|
1427
|
+
if (seconds < 60) return `${seconds}s`;
|
|
1428
|
+
const minutes = Math.floor(seconds / 60);
|
|
1429
|
+
const remainingSeconds = seconds % 60;
|
|
1430
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
1431
|
+
};
|
|
1432
|
+
return /* @__PURE__ */ jsxs(
|
|
1370
1433
|
"button",
|
|
1371
1434
|
{
|
|
1372
|
-
onClick: () =>
|
|
1435
|
+
onClick: () => setIsOpen(!isOpen),
|
|
1373
1436
|
className: cn(
|
|
1374
|
-
"
|
|
1375
|
-
"
|
|
1376
|
-
"
|
|
1377
|
-
"
|
|
1378
|
-
"
|
|
1379
|
-
|
|
1437
|
+
"ash-reasoning-trigger",
|
|
1438
|
+
"w-full flex items-center gap-2",
|
|
1439
|
+
"px-3 py-2",
|
|
1440
|
+
"text-left",
|
|
1441
|
+
"cursor-pointer hover:bg-white/[0.03] transition-colors",
|
|
1442
|
+
className
|
|
1380
1443
|
),
|
|
1381
1444
|
children: [
|
|
1382
|
-
/* @__PURE__ */ jsx("span", { className: cn(
|
|
1383
|
-
"flex-shrink-0 w-6 h-6 rounded-lg",
|
|
1384
|
-
"bg-[var(--ash-accent)]/20 text-[var(--ash-accent)]",
|
|
1385
|
-
"flex items-center justify-center",
|
|
1386
|
-
"text-xs font-semibold",
|
|
1387
|
-
"group-hover:bg-[var(--ash-accent)]/30",
|
|
1388
|
-
"transition-colors duration-200"
|
|
1389
|
-
), children: option.id }),
|
|
1390
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
1391
|
-
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-white/90 group-hover:text-white transition-colors", children: option.label }),
|
|
1392
|
-
option.description && /* @__PURE__ */ jsx("div", { className: "text-xs text-white/50 mt-0.5 line-clamp-2 group-hover:text-white/60 transition-colors", children: option.description })
|
|
1393
|
-
] }),
|
|
1394
1445
|
/* @__PURE__ */ jsx(
|
|
1395
|
-
"
|
|
1446
|
+
"span",
|
|
1396
1447
|
{
|
|
1397
1448
|
className: cn(
|
|
1398
|
-
"w-4 h-4
|
|
1399
|
-
"
|
|
1400
|
-
"transition-all duration-200"
|
|
1449
|
+
"w-4 h-4 flex items-center justify-center",
|
|
1450
|
+
isStreaming && "animate-pulse"
|
|
1401
1451
|
),
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1452
|
+
children: isStreaming ? /* @__PURE__ */ jsxs(
|
|
1453
|
+
"svg",
|
|
1454
|
+
{
|
|
1455
|
+
className: "w-4 h-4 text-purple-400 animate-spin",
|
|
1456
|
+
fill: "none",
|
|
1457
|
+
viewBox: "0 0 24 24",
|
|
1458
|
+
children: [
|
|
1459
|
+
/* @__PURE__ */ jsx(
|
|
1460
|
+
"circle",
|
|
1461
|
+
{
|
|
1462
|
+
className: "opacity-25",
|
|
1463
|
+
cx: "12",
|
|
1464
|
+
cy: "12",
|
|
1465
|
+
r: "10",
|
|
1466
|
+
stroke: "currentColor",
|
|
1467
|
+
strokeWidth: "4"
|
|
1468
|
+
}
|
|
1469
|
+
),
|
|
1470
|
+
/* @__PURE__ */ jsx(
|
|
1471
|
+
"path",
|
|
1472
|
+
{
|
|
1473
|
+
className: "opacity-75",
|
|
1474
|
+
fill: "currentColor",
|
|
1475
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
1476
|
+
}
|
|
1477
|
+
)
|
|
1478
|
+
]
|
|
1479
|
+
}
|
|
1480
|
+
) : /* @__PURE__ */ jsx(
|
|
1481
|
+
"svg",
|
|
1482
|
+
{
|
|
1483
|
+
className: "w-4 h-4 text-purple-400",
|
|
1484
|
+
fill: "none",
|
|
1485
|
+
stroke: "currentColor",
|
|
1486
|
+
viewBox: "0 0 24 24",
|
|
1487
|
+
children: /* @__PURE__ */ jsx(
|
|
1488
|
+
"path",
|
|
1489
|
+
{
|
|
1490
|
+
strokeLinecap: "round",
|
|
1491
|
+
strokeLinejoin: "round",
|
|
1492
|
+
strokeWidth: 2,
|
|
1493
|
+
d: "M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"
|
|
1494
|
+
}
|
|
1495
|
+
)
|
|
1496
|
+
}
|
|
1497
|
+
)
|
|
1407
1498
|
}
|
|
1408
|
-
)
|
|
1409
|
-
|
|
1410
|
-
},
|
|
1411
|
-
option.id
|
|
1412
|
-
)) });
|
|
1413
|
-
}
|
|
1414
|
-
function parseFilesFromContent(content) {
|
|
1415
|
-
const fileMarker = "[Uploaded files available at /uploads/]";
|
|
1416
|
-
const markerIndex = content.indexOf(fileMarker);
|
|
1417
|
-
if (markerIndex === -1) {
|
|
1418
|
-
return { text: content, files: [] };
|
|
1419
|
-
}
|
|
1420
|
-
const text = content.substring(0, markerIndex).trim();
|
|
1421
|
-
const fileSection = content.substring(markerIndex + fileMarker.length).trim();
|
|
1422
|
-
const files = fileSection.split("\n").filter((line) => line.startsWith("- ")).map((line) => line.substring(2).trim());
|
|
1423
|
-
return { text, files };
|
|
1424
|
-
}
|
|
1425
|
-
function UserMessage({ entry, className }) {
|
|
1426
|
-
const { text, files } = parseFilesFromContent(entry.content);
|
|
1427
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-3 justify-end ash-animate-fade-in", className), children: [
|
|
1428
|
-
/* @__PURE__ */ jsxs("div", { className: "max-w-[85%]", children: [
|
|
1429
|
-
/* @__PURE__ */ jsx("div", { className: "rounded-2xl p-4 bg-[var(--ash-accent)] text-[var(--ash-accent-foreground)]", children: /* @__PURE__ */ jsx("p", { className: "text-sm leading-relaxed whitespace-pre-wrap", children: text || "(files attached)" }) }),
|
|
1430
|
-
files.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-2 pt-2 border-t border-[var(--ash-accent-foreground)]/20", children: [
|
|
1431
|
-
/* @__PURE__ */ jsxs("div", { className: "text-xs text-[var(--ash-accent-foreground)]/60 mb-1 flex items-center gap-1", children: [
|
|
1432
|
-
/* @__PURE__ */ jsx(PaperclipIcon, { className: "w-3 h-3" }),
|
|
1433
|
-
"Attached Files"
|
|
1434
|
-
] }),
|
|
1435
|
-
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: files.map((file, index) => /* @__PURE__ */ jsx(
|
|
1499
|
+
),
|
|
1500
|
+
/* @__PURE__ */ jsxs(
|
|
1436
1501
|
"span",
|
|
1437
1502
|
{
|
|
1438
|
-
className:
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
onOptionSelect(`Option ${option.id}: ${option.label}`);
|
|
1460
|
-
}
|
|
1461
|
-
};
|
|
1462
|
-
const renderContent = (textContent) => {
|
|
1463
|
-
if (entry.richContent && entry.richContent.length > 0) {
|
|
1464
|
-
return /* @__PURE__ */ jsx(
|
|
1465
|
-
RichContentRenderer,
|
|
1466
|
-
{
|
|
1467
|
-
content: entry.richContent,
|
|
1468
|
-
renderers: richContentRenderers
|
|
1469
|
-
}
|
|
1470
|
-
);
|
|
1471
|
-
}
|
|
1472
|
-
return /* @__PURE__ */ jsx(LazyMarkdown, { children: textContent || entry.content });
|
|
1473
|
-
};
|
|
1474
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-3 ash-animate-fade-in", className), children: [
|
|
1475
|
-
/* @__PURE__ */ jsx("div", { className: "w-7 h-7 rounded-full bg-[var(--ash-accent)]/20 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx(BotIcon, { className: "w-4 h-4 text-[var(--ash-accent)]" }) }),
|
|
1476
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1 max-w-[85%]", children: [
|
|
1477
|
-
/* @__PURE__ */ jsx("div", { className: "ash-card-glass rounded-2xl p-4", children: /* @__PURE__ */ jsx("div", { className: "ash-message-content prose prose-sm prose-invert max-w-none text-sm leading-relaxed", children: parsedOptions ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1478
|
-
parsedOptions.preamble && renderContent(parsedOptions.preamble),
|
|
1503
|
+
className: cn(
|
|
1504
|
+
"flex-1 font-medium",
|
|
1505
|
+
"text-[var(--ash-font-size-sm,12px)]",
|
|
1506
|
+
isStreaming ? "text-[var(--ash-thinking-text,rgb(196,181,253))]" : "text-[var(--ash-text-secondary,rgba(255,255,255,0.7))]"
|
|
1507
|
+
),
|
|
1508
|
+
children: [
|
|
1509
|
+
label,
|
|
1510
|
+
isStreaming && "..."
|
|
1511
|
+
]
|
|
1512
|
+
}
|
|
1513
|
+
),
|
|
1514
|
+
showDuration && duration > 0 && /* @__PURE__ */ jsx(
|
|
1515
|
+
"span",
|
|
1516
|
+
{
|
|
1517
|
+
className: cn(
|
|
1518
|
+
"text-[var(--ash-font-size-xs,10px)]",
|
|
1519
|
+
"text-[var(--ash-text-muted,rgba(255,255,255,0.5))]"
|
|
1520
|
+
),
|
|
1521
|
+
children: formatDuration(duration)
|
|
1522
|
+
}
|
|
1523
|
+
),
|
|
1479
1524
|
/* @__PURE__ */ jsx(
|
|
1480
|
-
|
|
1525
|
+
"svg",
|
|
1481
1526
|
{
|
|
1482
|
-
|
|
1483
|
-
|
|
1527
|
+
className: cn(
|
|
1528
|
+
"w-4 h-4 text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
|
|
1529
|
+
"transition-transform",
|
|
1530
|
+
isOpen && "rotate-180"
|
|
1531
|
+
),
|
|
1532
|
+
fill: "none",
|
|
1533
|
+
stroke: "currentColor",
|
|
1534
|
+
viewBox: "0 0 24 24",
|
|
1535
|
+
children: /* @__PURE__ */ jsx(
|
|
1536
|
+
"path",
|
|
1537
|
+
{
|
|
1538
|
+
strokeLinecap: "round",
|
|
1539
|
+
strokeLinejoin: "round",
|
|
1540
|
+
strokeWidth: 2,
|
|
1541
|
+
d: "M19 9l-7 7-7-7"
|
|
1542
|
+
}
|
|
1543
|
+
)
|
|
1484
1544
|
}
|
|
1485
1545
|
)
|
|
1486
|
-
]
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
] });
|
|
1490
|
-
}
|
|
1491
|
-
function ThinkingMessage({ entry, className }) {
|
|
1492
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-3 ash-animate-fade-in", className), children: [
|
|
1493
|
-
/* @__PURE__ */ jsx("div", { className: "w-7 h-7 rounded-full bg-purple-500/20 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx(SparklesIcon, { className: "w-4 h-4 text-purple-400" }) }),
|
|
1494
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 max-w-[85%]", children: /* @__PURE__ */ jsxs("div", { className: "rounded-2xl p-4 bg-purple-500/10 border border-purple-500/30", children: [
|
|
1495
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-purple-400 mb-2 font-medium", children: "Thinking" }),
|
|
1496
|
-
/* @__PURE__ */ jsx("div", { className: "text-sm text-purple-300 italic opacity-80 whitespace-pre-wrap leading-relaxed", children: entry.content })
|
|
1497
|
-
] }) })
|
|
1498
|
-
] });
|
|
1499
|
-
}
|
|
1500
|
-
function ToolCallMessage({ entry, defaultExpanded = false, className }) {
|
|
1501
|
-
if (entry.entryType.type !== "tool_call") return null;
|
|
1502
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-3 ash-animate-fade-in", className), children: [
|
|
1503
|
-
/* @__PURE__ */ jsx("div", { className: "w-7 h-7 rounded-full bg-[var(--ash-accent)]/20 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx(BotIcon, { className: "w-4 h-4 text-[var(--ash-accent)]" }) }),
|
|
1504
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(ToolCallCard, { toolCall: entry.entryType.toolCall, defaultExpanded }) })
|
|
1505
|
-
] });
|
|
1506
|
-
}
|
|
1507
|
-
function ErrorMessage({ entry, className }) {
|
|
1508
|
-
if (entry.entryType.type !== "error") return null;
|
|
1509
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-3 ash-animate-fade-in", className), children: [
|
|
1510
|
-
/* @__PURE__ */ jsx("div", { className: "w-7 h-7 rounded-full bg-red-500/20 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "w-4 h-4 text-red-400" }) }),
|
|
1511
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 max-w-[85%]", children: /* @__PURE__ */ jsxs("div", { className: "rounded-2xl p-4 bg-red-500/10 border border-red-500/30", children: [
|
|
1512
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-red-400 mb-2 font-medium", children: "Error" }),
|
|
1513
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-red-300", children: entry.entryType.message }),
|
|
1514
|
-
entry.entryType.code && /* @__PURE__ */ jsxs("p", { className: "text-xs text-red-400/70 mt-2 font-mono", children: [
|
|
1515
|
-
"Code: ",
|
|
1516
|
-
entry.entryType.code
|
|
1517
|
-
] })
|
|
1518
|
-
] }) })
|
|
1519
|
-
] });
|
|
1546
|
+
]
|
|
1547
|
+
}
|
|
1548
|
+
);
|
|
1520
1549
|
}
|
|
1521
|
-
function
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
richContentRenderers,
|
|
1526
|
-
className
|
|
1550
|
+
function ReasoningContent({
|
|
1551
|
+
children,
|
|
1552
|
+
className,
|
|
1553
|
+
maxHeight = 300
|
|
1527
1554
|
}) {
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1555
|
+
const { isOpen, isStreaming } = useReasoning();
|
|
1556
|
+
if (!isOpen) return null;
|
|
1557
|
+
return /* @__PURE__ */ jsx(
|
|
1558
|
+
"div",
|
|
1559
|
+
{
|
|
1560
|
+
className: cn(
|
|
1561
|
+
"ash-reasoning-content",
|
|
1562
|
+
"border-t border-[var(--ash-border-subtle,rgba(255,255,255,0.04))]",
|
|
1563
|
+
"ash-accordion-content",
|
|
1564
|
+
className
|
|
1565
|
+
),
|
|
1566
|
+
children: /* @__PURE__ */ jsx(
|
|
1567
|
+
"div",
|
|
1534
1568
|
{
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1569
|
+
className: cn(
|
|
1570
|
+
"p-3 overflow-auto",
|
|
1571
|
+
"text-[var(--ash-font-size-sm,12px)]",
|
|
1572
|
+
"text-[var(--ash-text-secondary,rgba(255,255,255,0.7))]",
|
|
1573
|
+
"whitespace-pre-wrap font-mono",
|
|
1574
|
+
isStreaming && "animate-pulse"
|
|
1575
|
+
),
|
|
1576
|
+
style: { maxHeight },
|
|
1577
|
+
children
|
|
1539
1578
|
}
|
|
1540
|
-
)
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
case "tool_call":
|
|
1544
|
-
return /* @__PURE__ */ jsx(ToolCallMessage, { entry, defaultExpanded, className });
|
|
1545
|
-
case "error":
|
|
1546
|
-
return /* @__PURE__ */ jsx(ErrorMessage, { entry, className });
|
|
1547
|
-
default:
|
|
1548
|
-
return null;
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
function LoadingIndicator({ variant = "dots", size = "md", className }) {
|
|
1552
|
-
if (variant === "dots") {
|
|
1553
|
-
const dotSizes = {
|
|
1554
|
-
sm: "w-1 h-1",
|
|
1555
|
-
md: "w-1.5 h-1.5",
|
|
1556
|
-
lg: "w-2 h-2"
|
|
1557
|
-
};
|
|
1558
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-1", className), children: [
|
|
1559
|
-
/* @__PURE__ */ jsx("span", { className: cn("rounded-full bg-[var(--ash-accent)] animate-pulse", dotSizes[size]) }),
|
|
1560
|
-
/* @__PURE__ */ jsx("span", { className: cn("rounded-full bg-[var(--ash-accent)] animate-pulse", dotSizes[size]), style: { animationDelay: "150ms" } }),
|
|
1561
|
-
/* @__PURE__ */ jsx("span", { className: cn("rounded-full bg-[var(--ash-accent)] animate-pulse", dotSizes[size]), style: { animationDelay: "300ms" } })
|
|
1562
|
-
] });
|
|
1563
|
-
}
|
|
1564
|
-
if (variant === "pulse") {
|
|
1565
|
-
const dotSizes = {
|
|
1566
|
-
sm: "w-1.5 h-1.5",
|
|
1567
|
-
md: "w-2 h-2",
|
|
1568
|
-
lg: "w-3 h-3"
|
|
1569
|
-
};
|
|
1570
|
-
return /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-1", className), children: /* @__PURE__ */ jsx("span", { className: cn("bg-[var(--ash-accent)] rounded-full animate-pulse", dotSizes[size]) }) });
|
|
1571
|
-
}
|
|
1572
|
-
if (variant === "cursor") {
|
|
1573
|
-
const cursorSizes = {
|
|
1574
|
-
sm: "w-1 h-3",
|
|
1575
|
-
md: "w-1.5 h-4",
|
|
1576
|
-
lg: "w-2 h-5"
|
|
1577
|
-
};
|
|
1578
|
-
return /* @__PURE__ */ jsx(
|
|
1579
|
-
"span",
|
|
1580
|
-
{
|
|
1581
|
-
className: cn(
|
|
1582
|
-
"inline-block bg-[var(--ash-accent)]/50 ash-tool-status-pending",
|
|
1583
|
-
cursorSizes[size],
|
|
1584
|
-
className
|
|
1585
|
-
)
|
|
1586
|
-
}
|
|
1587
|
-
);
|
|
1588
|
-
}
|
|
1589
|
-
const spinnerSizes = {
|
|
1590
|
-
sm: "w-4 h-4",
|
|
1591
|
-
md: "w-6 h-6",
|
|
1592
|
-
lg: "w-8 h-8"
|
|
1593
|
-
};
|
|
1594
|
-
return /* @__PURE__ */ jsx("div", { className: cn("animate-spin text-[var(--ash-accent)]", spinnerSizes[size], className), children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1595
|
-
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", className: "opacity-25" }),
|
|
1596
|
-
/* @__PURE__ */ jsx("path", { d: "M12 2a10 10 0 0 1 10 10", strokeLinecap: "round" })
|
|
1597
|
-
] }) });
|
|
1579
|
+
)
|
|
1580
|
+
}
|
|
1581
|
+
);
|
|
1598
1582
|
}
|
|
1599
|
-
function
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
renderMarkdown = true,
|
|
1583
|
+
function ThinkingIndicator({
|
|
1584
|
+
isActive = true,
|
|
1585
|
+
label = "Thinking",
|
|
1603
1586
|
className
|
|
1604
1587
|
}) {
|
|
1605
|
-
|
|
1606
|
-
/* @__PURE__ */ jsx(LazyMarkdown, { children: content }),
|
|
1607
|
-
isStreaming && /* @__PURE__ */ jsx(LoadingIndicator, { variant: "cursor", size: "sm", className: "inline-block ml-0.5" })
|
|
1608
|
-
] }) : /* @__PURE__ */ jsxs("p", { className: "whitespace-pre-wrap text-sm leading-relaxed", children: [
|
|
1609
|
-
content,
|
|
1610
|
-
isStreaming && /* @__PURE__ */ jsx(LoadingIndicator, { variant: "cursor", size: "sm", className: "inline-block ml-0.5" })
|
|
1611
|
-
] }) });
|
|
1612
|
-
}
|
|
1613
|
-
function getFilePath(actionType) {
|
|
1614
|
-
switch (actionType.action) {
|
|
1615
|
-
case "file_read":
|
|
1616
|
-
case "file_edit":
|
|
1617
|
-
case "file_write":
|
|
1618
|
-
return actionType.path;
|
|
1619
|
-
default:
|
|
1620
|
-
return null;
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
function getFileName(path) {
|
|
1624
|
-
const parts = path.split("/");
|
|
1625
|
-
return parts[parts.length - 1] || path;
|
|
1626
|
-
}
|
|
1627
|
-
function getFileExtension(path) {
|
|
1628
|
-
const fileName = getFileName(path);
|
|
1629
|
-
const dotIndex = fileName.lastIndexOf(".");
|
|
1630
|
-
if (dotIndex === -1) return null;
|
|
1631
|
-
return fileName.slice(dotIndex + 1).toLowerCase();
|
|
1632
|
-
}
|
|
1633
|
-
function getDiffStats(actionType) {
|
|
1634
|
-
switch (actionType.action) {
|
|
1635
|
-
case "file_edit": {
|
|
1636
|
-
const edit = actionType;
|
|
1637
|
-
if (edit.linesAdded !== void 0 || edit.linesRemoved !== void 0) {
|
|
1638
|
-
return { added: edit.linesAdded, removed: edit.linesRemoved };
|
|
1639
|
-
}
|
|
1640
|
-
return null;
|
|
1641
|
-
}
|
|
1642
|
-
case "file_read": {
|
|
1643
|
-
const read = actionType;
|
|
1644
|
-
if (read.linesRead !== void 0) {
|
|
1645
|
-
return { read: read.linesRead };
|
|
1646
|
-
}
|
|
1647
|
-
return null;
|
|
1648
|
-
}
|
|
1649
|
-
case "file_write": {
|
|
1650
|
-
const write = actionType;
|
|
1651
|
-
if (write.linesWritten !== void 0) {
|
|
1652
|
-
return { written: write.linesWritten };
|
|
1653
|
-
}
|
|
1654
|
-
return null;
|
|
1655
|
-
}
|
|
1656
|
-
default:
|
|
1657
|
-
return null;
|
|
1658
|
-
}
|
|
1659
|
-
}
|
|
1660
|
-
function getFileTypeColor(ext) {
|
|
1661
|
-
switch (ext) {
|
|
1662
|
-
case "ts":
|
|
1663
|
-
case "tsx":
|
|
1664
|
-
return "text-blue-400";
|
|
1665
|
-
case "js":
|
|
1666
|
-
case "jsx":
|
|
1667
|
-
return "text-yellow-400";
|
|
1668
|
-
case "md":
|
|
1669
|
-
return "text-white/60";
|
|
1670
|
-
case "json":
|
|
1671
|
-
return "text-orange-400";
|
|
1672
|
-
case "sh":
|
|
1673
|
-
return "text-green-400";
|
|
1674
|
-
case "css":
|
|
1675
|
-
case "scss":
|
|
1676
|
-
return "text-pink-400";
|
|
1677
|
-
case "py":
|
|
1678
|
-
return "text-blue-300";
|
|
1679
|
-
default:
|
|
1680
|
-
return "text-white/70";
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
function CompactToolRow({ toolCall, showFullPath = false, className }) {
|
|
1684
|
-
const { actionType, status, summary } = toolCall;
|
|
1685
|
-
const label = getActionLabel(actionType);
|
|
1686
|
-
const filePath = getFilePath(actionType);
|
|
1687
|
-
const diffStats = getDiffStats(actionType);
|
|
1688
|
-
const displayPath = filePath ? showFullPath ? filePath : getFileName(filePath) : null;
|
|
1689
|
-
const ext = filePath ? getFileExtension(filePath) : null;
|
|
1690
|
-
const fileColor = getFileTypeColor(ext);
|
|
1691
|
-
const showSummary = !filePath && summary;
|
|
1588
|
+
if (!isActive) return null;
|
|
1692
1589
|
return /* @__PURE__ */ jsxs(
|
|
1693
1590
|
"div",
|
|
1694
1591
|
{
|
|
1695
1592
|
className: cn(
|
|
1696
|
-
"
|
|
1593
|
+
"ash-thinking-indicator",
|
|
1594
|
+
"flex items-center gap-2",
|
|
1595
|
+
"px-3 py-2",
|
|
1596
|
+
"text-[var(--ash-font-size-sm,12px)]",
|
|
1597
|
+
"text-[var(--ash-thinking-text,rgb(196,181,253))]",
|
|
1697
1598
|
className
|
|
1698
1599
|
),
|
|
1699
1600
|
children: [
|
|
1700
|
-
/* @__PURE__ */ jsxs("
|
|
1701
|
-
/* @__PURE__ */ jsx(
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
actionType,
|
|
1705
|
-
className: cn(
|
|
1706
|
-
"w-3.5 h-3.5",
|
|
1707
|
-
status === "pending" ? "text-yellow-400" : status === "failed" ? "text-red-400" : "text-white/50"
|
|
1708
|
-
)
|
|
1709
|
-
}
|
|
1710
|
-
),
|
|
1711
|
-
/* @__PURE__ */ jsx("span", { className: cn(
|
|
1712
|
-
"font-medium",
|
|
1713
|
-
status === "pending" ? "text-white/90" : status === "failed" ? "text-red-400" : "text-white/60"
|
|
1714
|
-
), children: label })
|
|
1601
|
+
/* @__PURE__ */ jsxs("span", { className: "flex gap-1", children: [
|
|
1602
|
+
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 bg-current rounded-full animate-bounce", style: { animationDelay: "0ms" } }),
|
|
1603
|
+
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 bg-current rounded-full animate-bounce", style: { animationDelay: "150ms" } }),
|
|
1604
|
+
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 bg-current rounded-full animate-bounce", style: { animationDelay: "300ms" } })
|
|
1715
1605
|
] }),
|
|
1716
|
-
|
|
1717
|
-
"px-1.5 py-0.5 rounded bg-white/5 font-mono text-xs truncate max-w-[200px]",
|
|
1718
|
-
fileColor
|
|
1719
|
-
), children: displayPath }),
|
|
1720
|
-
diffStats && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0 font-mono", children: [
|
|
1721
|
-
diffStats.added !== void 0 && diffStats.added > 0 && /* @__PURE__ */ jsxs("span", { className: "text-emerald-400", children: [
|
|
1722
|
-
"+",
|
|
1723
|
-
diffStats.added
|
|
1724
|
-
] }),
|
|
1725
|
-
diffStats.removed !== void 0 && diffStats.removed > 0 && /* @__PURE__ */ jsxs("span", { className: "text-red-400", children: [
|
|
1726
|
-
"-",
|
|
1727
|
-
diffStats.removed
|
|
1728
|
-
] }),
|
|
1729
|
-
diffStats.read !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-white/40", children: [
|
|
1730
|
-
diffStats.read,
|
|
1731
|
-
" lines"
|
|
1732
|
-
] }),
|
|
1733
|
-
diffStats.written !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-emerald-400", children: [
|
|
1734
|
-
"+",
|
|
1735
|
-
diffStats.written
|
|
1736
|
-
] })
|
|
1737
|
-
] }),
|
|
1738
|
-
showSummary && /* @__PURE__ */ jsx("span", { className: "text-white/40 truncate min-w-0 text-xs", children: summary })
|
|
1606
|
+
/* @__PURE__ */ jsx("span", { children: label })
|
|
1739
1607
|
]
|
|
1740
1608
|
}
|
|
1741
1609
|
);
|
|
1742
1610
|
}
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
const
|
|
1746
|
-
if (
|
|
1747
|
-
|
|
1748
|
-
}
|
|
1749
|
-
function getFileIcon(ext) {
|
|
1750
|
-
switch (ext) {
|
|
1751
|
-
case "ts":
|
|
1752
|
-
case "tsx":
|
|
1753
|
-
return "TS";
|
|
1754
|
-
case "js":
|
|
1755
|
-
case "jsx":
|
|
1756
|
-
return "JS";
|
|
1757
|
-
case "md":
|
|
1758
|
-
return "MD";
|
|
1759
|
-
case "json":
|
|
1760
|
-
return "{}";
|
|
1761
|
-
case "sh":
|
|
1762
|
-
return "$";
|
|
1763
|
-
case "css":
|
|
1764
|
-
case "scss":
|
|
1765
|
-
return "#";
|
|
1766
|
-
case "py":
|
|
1767
|
-
return "PY";
|
|
1768
|
-
default:
|
|
1769
|
-
return "";
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
function getFileBgColor(ext) {
|
|
1773
|
-
switch (ext) {
|
|
1774
|
-
case "ts":
|
|
1775
|
-
case "tsx":
|
|
1776
|
-
return "bg-blue-500/20";
|
|
1777
|
-
case "js":
|
|
1778
|
-
case "jsx":
|
|
1779
|
-
return "bg-yellow-500/20";
|
|
1780
|
-
case "md":
|
|
1781
|
-
return "bg-white/10";
|
|
1782
|
-
case "json":
|
|
1783
|
-
return "bg-orange-500/20";
|
|
1784
|
-
case "sh":
|
|
1785
|
-
return "bg-green-500/20";
|
|
1786
|
-
case "css":
|
|
1787
|
-
case "scss":
|
|
1788
|
-
return "bg-pink-500/20";
|
|
1789
|
-
case "py":
|
|
1790
|
-
return "bg-blue-400/20";
|
|
1791
|
-
default:
|
|
1792
|
-
return "bg-white/10";
|
|
1611
|
+
var TaskContext = createContext(null);
|
|
1612
|
+
function useTask() {
|
|
1613
|
+
const context = useContext(TaskContext);
|
|
1614
|
+
if (!context) {
|
|
1615
|
+
throw new Error("useTask must be used within a Task");
|
|
1793
1616
|
}
|
|
1617
|
+
return context;
|
|
1794
1618
|
}
|
|
1795
|
-
function
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
linesRemoved,
|
|
1799
|
-
showOnlyFilename = true,
|
|
1619
|
+
function Task({
|
|
1620
|
+
children,
|
|
1621
|
+
defaultOpen = false,
|
|
1800
1622
|
className
|
|
1801
1623
|
}) {
|
|
1802
|
-
const
|
|
1803
|
-
const
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1624
|
+
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
1625
|
+
const contextValue = {
|
|
1626
|
+
isOpen,
|
|
1627
|
+
setIsOpen
|
|
1628
|
+
};
|
|
1629
|
+
return /* @__PURE__ */ jsx(TaskContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
1630
|
+
"div",
|
|
1631
|
+
{
|
|
1632
|
+
className: cn(
|
|
1633
|
+
"ash-task",
|
|
1634
|
+
"rounded-[var(--ash-radius-md,0.5rem)]",
|
|
1635
|
+
"border border-[var(--ash-border,rgba(255,255,255,0.08))]",
|
|
1636
|
+
"bg-[var(--ash-surface-dark,#0a0a0a)]",
|
|
1637
|
+
"overflow-hidden",
|
|
1638
|
+
className
|
|
1639
|
+
),
|
|
1640
|
+
children
|
|
1641
|
+
}
|
|
1642
|
+
) });
|
|
1643
|
+
}
|
|
1644
|
+
function TaskTrigger({ children, className }) {
|
|
1645
|
+
const { isOpen, setIsOpen } = useTask();
|
|
1807
1646
|
return /* @__PURE__ */ jsxs(
|
|
1808
|
-
"
|
|
1647
|
+
"button",
|
|
1809
1648
|
{
|
|
1649
|
+
onClick: () => setIsOpen(!isOpen),
|
|
1810
1650
|
className: cn(
|
|
1811
|
-
"
|
|
1812
|
-
|
|
1651
|
+
"ash-task-trigger",
|
|
1652
|
+
"w-full flex items-center gap-2",
|
|
1653
|
+
"px-3 py-2",
|
|
1654
|
+
"text-left",
|
|
1655
|
+
"cursor-pointer hover:bg-white/[0.03] transition-colors",
|
|
1813
1656
|
className
|
|
1814
1657
|
),
|
|
1815
1658
|
children: [
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
"
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1659
|
+
/* @__PURE__ */ jsx(
|
|
1660
|
+
"svg",
|
|
1661
|
+
{
|
|
1662
|
+
className: "w-4 h-4 text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
|
|
1663
|
+
fill: "none",
|
|
1664
|
+
stroke: "currentColor",
|
|
1665
|
+
viewBox: "0 0 24 24",
|
|
1666
|
+
children: /* @__PURE__ */ jsx(
|
|
1667
|
+
"path",
|
|
1668
|
+
{
|
|
1669
|
+
strokeLinecap: "round",
|
|
1670
|
+
strokeLinejoin: "round",
|
|
1671
|
+
strokeWidth: 2,
|
|
1672
|
+
d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
|
|
1673
|
+
}
|
|
1674
|
+
)
|
|
1675
|
+
}
|
|
1676
|
+
),
|
|
1677
|
+
/* @__PURE__ */ jsx(
|
|
1678
|
+
"span",
|
|
1679
|
+
{
|
|
1680
|
+
className: cn(
|
|
1681
|
+
"flex-1 font-medium",
|
|
1682
|
+
"text-[var(--ash-font-size-sm,12px)]",
|
|
1683
|
+
"text-[var(--ash-text-primary,rgba(255,255,255,0.9))]"
|
|
1684
|
+
),
|
|
1685
|
+
children
|
|
1686
|
+
}
|
|
1687
|
+
),
|
|
1688
|
+
/* @__PURE__ */ jsx(
|
|
1689
|
+
"svg",
|
|
1690
|
+
{
|
|
1691
|
+
className: cn(
|
|
1692
|
+
"w-4 h-4 text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
|
|
1693
|
+
"transition-transform",
|
|
1694
|
+
isOpen && "rotate-180"
|
|
1695
|
+
),
|
|
1696
|
+
fill: "none",
|
|
1697
|
+
stroke: "currentColor",
|
|
1698
|
+
viewBox: "0 0 24 24",
|
|
1699
|
+
children: /* @__PURE__ */ jsx(
|
|
1700
|
+
"path",
|
|
1701
|
+
{
|
|
1702
|
+
strokeLinecap: "round",
|
|
1703
|
+
strokeLinejoin: "round",
|
|
1704
|
+
strokeWidth: 2,
|
|
1705
|
+
d: "M19 9l-7 7-7-7"
|
|
1706
|
+
}
|
|
1707
|
+
)
|
|
1708
|
+
}
|
|
1709
|
+
)
|
|
1828
1710
|
]
|
|
1829
1711
|
}
|
|
1830
1712
|
);
|
|
1831
1713
|
}
|
|
1832
|
-
function
|
|
1833
|
-
const
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
linesAdded: edit.linesAdded,
|
|
1846
|
-
linesRemoved: edit.linesRemoved
|
|
1847
|
-
});
|
|
1848
|
-
}
|
|
1849
|
-
} else if (actionType.action === "file_write") {
|
|
1850
|
-
const write = actionType;
|
|
1851
|
-
if (!fileMap.has(write.path)) {
|
|
1852
|
-
fileMap.set(write.path, {
|
|
1853
|
-
path: write.path,
|
|
1854
|
-
linesAdded: write.linesWritten
|
|
1855
|
-
});
|
|
1856
|
-
}
|
|
1714
|
+
function TaskContent({ children, className }) {
|
|
1715
|
+
const { isOpen } = useTask();
|
|
1716
|
+
if (!isOpen) return null;
|
|
1717
|
+
return /* @__PURE__ */ jsx(
|
|
1718
|
+
"div",
|
|
1719
|
+
{
|
|
1720
|
+
className: cn(
|
|
1721
|
+
"ash-task-content",
|
|
1722
|
+
"border-t border-[var(--ash-border-subtle,rgba(255,255,255,0.04))]",
|
|
1723
|
+
"ash-accordion-content",
|
|
1724
|
+
className
|
|
1725
|
+
),
|
|
1726
|
+
children: /* @__PURE__ */ jsx("div", { className: "p-2 space-y-1", children })
|
|
1857
1727
|
}
|
|
1858
|
-
|
|
1859
|
-
return Array.from(fileMap.values());
|
|
1860
|
-
}
|
|
1861
|
-
function countActionTypes(toolCalls) {
|
|
1862
|
-
const counts = {};
|
|
1863
|
-
for (const tc of toolCalls) {
|
|
1864
|
-
const action = tc.actionType.action;
|
|
1865
|
-
counts[action] = (counts[action] || 0) + 1;
|
|
1866
|
-
}
|
|
1867
|
-
return counts;
|
|
1868
|
-
}
|
|
1869
|
-
function getActionIconComponent(action) {
|
|
1870
|
-
switch (action) {
|
|
1871
|
-
case "file_read":
|
|
1872
|
-
return FileIcon;
|
|
1873
|
-
case "file_edit":
|
|
1874
|
-
case "file_write":
|
|
1875
|
-
return EditIcon;
|
|
1876
|
-
case "command_run":
|
|
1877
|
-
return TerminalIcon;
|
|
1878
|
-
case "search":
|
|
1879
|
-
case "glob":
|
|
1880
|
-
return SearchIcon;
|
|
1881
|
-
default:
|
|
1882
|
-
return null;
|
|
1883
|
-
}
|
|
1728
|
+
);
|
|
1884
1729
|
}
|
|
1885
|
-
function
|
|
1886
|
-
|
|
1887
|
-
|
|
1730
|
+
function TaskItem({
|
|
1731
|
+
children,
|
|
1732
|
+
status,
|
|
1733
|
+
activeForm,
|
|
1888
1734
|
className
|
|
1889
1735
|
}) {
|
|
1890
|
-
const
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
const actionCounts = useMemo(() => countActionTypes(toolCalls), [toolCalls]);
|
|
1894
|
-
const displayActions = useMemo(() => {
|
|
1895
|
-
return Object.entries(actionCounts).sort((a, b) => b[1] - a[1]).slice(0, 3).map(([action]) => action);
|
|
1896
|
-
}, [actionCounts]);
|
|
1897
|
-
const totalCount = toolCalls.length;
|
|
1898
|
-
if (toolCalls.length === 0) {
|
|
1899
|
-
return null;
|
|
1900
|
-
}
|
|
1901
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("ash-animate-fade-in", className), children: [
|
|
1902
|
-
/* @__PURE__ */ jsxs(
|
|
1903
|
-
"button",
|
|
1736
|
+
const statusIcons = {
|
|
1737
|
+
pending: /* @__PURE__ */ jsx(
|
|
1738
|
+
"svg",
|
|
1904
1739
|
{
|
|
1905
|
-
|
|
1906
|
-
|
|
1740
|
+
className: "w-4 h-4 text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
|
|
1741
|
+
fill: "none",
|
|
1742
|
+
stroke: "currentColor",
|
|
1743
|
+
viewBox: "0 0 24 24",
|
|
1744
|
+
children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeWidth: 2 })
|
|
1745
|
+
}
|
|
1746
|
+
),
|
|
1747
|
+
in_progress: /* @__PURE__ */ jsxs(
|
|
1748
|
+
"svg",
|
|
1749
|
+
{
|
|
1750
|
+
className: "w-4 h-4 text-yellow-400 animate-spin",
|
|
1751
|
+
fill: "none",
|
|
1752
|
+
viewBox: "0 0 24 24",
|
|
1907
1753
|
children: [
|
|
1908
1754
|
/* @__PURE__ */ jsx(
|
|
1909
|
-
|
|
1755
|
+
"circle",
|
|
1910
1756
|
{
|
|
1911
|
-
className:
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1757
|
+
className: "opacity-25",
|
|
1758
|
+
cx: "12",
|
|
1759
|
+
cy: "12",
|
|
1760
|
+
r: "10",
|
|
1761
|
+
stroke: "currentColor",
|
|
1762
|
+
strokeWidth: "4"
|
|
1915
1763
|
}
|
|
1916
1764
|
),
|
|
1917
|
-
/* @__PURE__ */
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
return /* @__PURE__ */ jsx(
|
|
1926
|
-
IconComponent,
|
|
1927
|
-
{
|
|
1928
|
-
className: "w-3.5 h-3.5 text-white/30"
|
|
1929
|
-
},
|
|
1930
|
-
action
|
|
1931
|
-
);
|
|
1932
|
-
}) }),
|
|
1933
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
1934
|
-
!expanded && fileChanges.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 flex-wrap justify-end", children: [
|
|
1935
|
-
fileChanges.slice(0, 4).map((fc) => /* @__PURE__ */ jsx(
|
|
1936
|
-
FileBadge,
|
|
1937
|
-
{
|
|
1938
|
-
path: fc.path,
|
|
1939
|
-
linesAdded: fc.linesAdded,
|
|
1940
|
-
linesRemoved: fc.linesRemoved
|
|
1941
|
-
},
|
|
1942
|
-
fc.path
|
|
1943
|
-
)),
|
|
1944
|
-
fileChanges.length > 4 && /* @__PURE__ */ jsxs("span", { className: "text-xs text-white/40", children: [
|
|
1945
|
-
"+",
|
|
1946
|
-
fileChanges.length - 4,
|
|
1947
|
-
" more"
|
|
1948
|
-
] })
|
|
1949
|
-
] })
|
|
1765
|
+
/* @__PURE__ */ jsx(
|
|
1766
|
+
"path",
|
|
1767
|
+
{
|
|
1768
|
+
className: "opacity-75",
|
|
1769
|
+
fill: "currentColor",
|
|
1770
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
1771
|
+
}
|
|
1772
|
+
)
|
|
1950
1773
|
]
|
|
1951
1774
|
}
|
|
1952
1775
|
),
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
ToolCallCard,
|
|
1956
|
-
{
|
|
1957
|
-
toolCall,
|
|
1958
|
-
defaultExpanded: true
|
|
1959
|
-
}
|
|
1960
|
-
),
|
|
1961
|
-
/* @__PURE__ */ jsx(
|
|
1962
|
-
"button",
|
|
1963
|
-
{
|
|
1964
|
-
onClick: () => setExpandedCardId(null),
|
|
1965
|
-
className: "text-xs text-white/40 hover:text-white/60 mt-1 pl-1",
|
|
1966
|
-
children: "Collapse"
|
|
1967
|
-
}
|
|
1968
|
-
)
|
|
1969
|
-
] }) : /* @__PURE__ */ jsx(
|
|
1970
|
-
"button",
|
|
1776
|
+
completed: /* @__PURE__ */ jsx(
|
|
1777
|
+
"svg",
|
|
1971
1778
|
{
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
const existing = fileMap.get(edit.path);
|
|
1986
|
-
if (existing) {
|
|
1987
|
-
existing.linesAdded = (existing.linesAdded || 0) + (edit.linesAdded || 0);
|
|
1988
|
-
existing.linesRemoved = (existing.linesRemoved || 0) + (edit.linesRemoved || 0);
|
|
1989
|
-
} else {
|
|
1990
|
-
fileMap.set(edit.path, {
|
|
1991
|
-
path: edit.path,
|
|
1992
|
-
linesAdded: edit.linesAdded,
|
|
1993
|
-
linesRemoved: edit.linesRemoved
|
|
1994
|
-
});
|
|
1995
|
-
}
|
|
1996
|
-
} else if (actionType.action === "file_write") {
|
|
1997
|
-
if (!fileMap.has(actionType.path)) {
|
|
1998
|
-
fileMap.set(actionType.path, {
|
|
1999
|
-
path: actionType.path,
|
|
2000
|
-
linesAdded: actionType.linesWritten
|
|
2001
|
-
});
|
|
1779
|
+
className: "w-4 h-4 text-[var(--ash-accent,#ccff00)]",
|
|
1780
|
+
fill: "none",
|
|
1781
|
+
stroke: "currentColor",
|
|
1782
|
+
viewBox: "0 0 24 24",
|
|
1783
|
+
children: /* @__PURE__ */ jsx(
|
|
1784
|
+
"path",
|
|
1785
|
+
{
|
|
1786
|
+
strokeLinecap: "round",
|
|
1787
|
+
strokeLinejoin: "round",
|
|
1788
|
+
strokeWidth: 2,
|
|
1789
|
+
d: "M5 13l4 4L19 7"
|
|
1790
|
+
}
|
|
1791
|
+
)
|
|
2002
1792
|
}
|
|
1793
|
+
)
|
|
1794
|
+
};
|
|
1795
|
+
const statusColors = {
|
|
1796
|
+
pending: "text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
|
|
1797
|
+
in_progress: "text-[var(--ash-text-primary,rgba(255,255,255,0.9))]",
|
|
1798
|
+
completed: "text-[var(--ash-text-secondary,rgba(255,255,255,0.7))] line-through"
|
|
1799
|
+
};
|
|
1800
|
+
return /* @__PURE__ */ jsxs(
|
|
1801
|
+
"div",
|
|
1802
|
+
{
|
|
1803
|
+
className: cn(
|
|
1804
|
+
"ash-task-item",
|
|
1805
|
+
"flex items-center gap-2",
|
|
1806
|
+
"px-2 py-1.5 rounded-md",
|
|
1807
|
+
status === "in_progress" && "bg-yellow-400/10",
|
|
1808
|
+
className
|
|
1809
|
+
),
|
|
1810
|
+
"data-task-status": status,
|
|
1811
|
+
children: [
|
|
1812
|
+
statusIcons[status],
|
|
1813
|
+
/* @__PURE__ */ jsx(
|
|
1814
|
+
"span",
|
|
1815
|
+
{
|
|
1816
|
+
className: cn(
|
|
1817
|
+
"flex-1",
|
|
1818
|
+
"text-[var(--ash-font-size-sm,12px)]",
|
|
1819
|
+
statusColors[status]
|
|
1820
|
+
),
|
|
1821
|
+
children: status === "in_progress" && activeForm ? activeForm : children
|
|
1822
|
+
}
|
|
1823
|
+
)
|
|
1824
|
+
]
|
|
2003
1825
|
}
|
|
2004
|
-
|
|
2005
|
-
return Array.from(fileMap.values());
|
|
2006
|
-
}
|
|
2007
|
-
function countActionTypes2(toolCalls) {
|
|
2008
|
-
const counts = {};
|
|
2009
|
-
for (const tc of toolCalls) {
|
|
2010
|
-
const action = tc.actionType.action;
|
|
2011
|
-
counts[action] = (counts[action] || 0) + 1;
|
|
2012
|
-
}
|
|
2013
|
-
return counts;
|
|
2014
|
-
}
|
|
2015
|
-
function getActionIconComponent2(action) {
|
|
2016
|
-
switch (action) {
|
|
2017
|
-
case "file_read":
|
|
2018
|
-
return FileIcon;
|
|
2019
|
-
case "file_edit":
|
|
2020
|
-
case "file_write":
|
|
2021
|
-
return EditIcon;
|
|
2022
|
-
case "command_run":
|
|
2023
|
-
return TerminalIcon;
|
|
2024
|
-
case "search":
|
|
2025
|
-
case "glob":
|
|
2026
|
-
return SearchIcon;
|
|
2027
|
-
default:
|
|
2028
|
-
return null;
|
|
2029
|
-
}
|
|
1826
|
+
);
|
|
2030
1827
|
}
|
|
2031
|
-
function
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
className
|
|
1828
|
+
function TaskList({
|
|
1829
|
+
items,
|
|
1830
|
+
defaultOpen = true,
|
|
1831
|
+
className,
|
|
1832
|
+
title
|
|
2037
1833
|
}) {
|
|
2038
|
-
const
|
|
2039
|
-
const
|
|
2040
|
-
const
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
}
|
|
2046
|
-
}, [onToggle]);
|
|
2047
|
-
const fileChanges = useMemo(() => extractFileChanges2(toolCalls), [toolCalls]);
|
|
2048
|
-
const actionCounts = useMemo(() => countActionTypes2(toolCalls), [toolCalls]);
|
|
2049
|
-
const displayActions = useMemo(() => {
|
|
2050
|
-
return Object.entries(actionCounts).sort((a, b) => b[1] - a[1]).slice(0, 3).map(([action]) => action);
|
|
2051
|
-
}, [actionCounts]);
|
|
2052
|
-
if (toolCalls.length === 0) {
|
|
2053
|
-
return null;
|
|
2054
|
-
}
|
|
2055
|
-
const totalCount = toolCalls.length;
|
|
2056
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("ash-animate-fade-in", className), children: [
|
|
2057
|
-
/* @__PURE__ */ jsxs(
|
|
2058
|
-
"button",
|
|
1834
|
+
const completed = items.filter((t) => t.status === "completed").length;
|
|
1835
|
+
const total = items.length;
|
|
1836
|
+
const displayTitle = title || `Tasks (${completed}/${total})`;
|
|
1837
|
+
return /* @__PURE__ */ jsxs(Task, { defaultOpen, className, children: [
|
|
1838
|
+
/* @__PURE__ */ jsx(TaskTrigger, { children: displayTitle }),
|
|
1839
|
+
/* @__PURE__ */ jsx(TaskContent, { children: items.map((item, index) => /* @__PURE__ */ jsx(
|
|
1840
|
+
TaskItem,
|
|
2059
1841
|
{
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
{
|
|
2067
|
-
className: cn(
|
|
2068
|
-
"w-3.5 h-3.5 text-white/40 transition-transform duration-200 shrink-0",
|
|
2069
|
-
isExpanded && "rotate-90"
|
|
2070
|
-
)
|
|
2071
|
-
}
|
|
2072
|
-
),
|
|
2073
|
-
/* @__PURE__ */ jsxs("span", { className: "text-sm text-white/60", children: [
|
|
2074
|
-
totalCount,
|
|
2075
|
-
" tool call",
|
|
2076
|
-
totalCount !== 1 ? "s" : ""
|
|
2077
|
-
] }),
|
|
2078
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: displayActions.map((action) => {
|
|
2079
|
-
const IconComponent = getActionIconComponent2(action);
|
|
2080
|
-
if (!IconComponent) return null;
|
|
2081
|
-
return /* @__PURE__ */ jsx(
|
|
2082
|
-
IconComponent,
|
|
2083
|
-
{
|
|
2084
|
-
className: "w-3.5 h-3.5 text-white/30"
|
|
2085
|
-
},
|
|
2086
|
-
action
|
|
2087
|
-
);
|
|
2088
|
-
}) }),
|
|
2089
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
2090
|
-
!isExpanded && fileChanges.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 flex-wrap justify-end", children: [
|
|
2091
|
-
fileChanges.slice(0, 4).map((fc) => /* @__PURE__ */ jsx(
|
|
2092
|
-
FileBadge,
|
|
2093
|
-
{
|
|
2094
|
-
path: fc.path,
|
|
2095
|
-
linesAdded: fc.linesAdded,
|
|
2096
|
-
linesRemoved: fc.linesRemoved
|
|
2097
|
-
},
|
|
2098
|
-
fc.path
|
|
2099
|
-
)),
|
|
2100
|
-
fileChanges.length > 4 && /* @__PURE__ */ jsxs("span", { className: "text-xs text-white/40", children: [
|
|
2101
|
-
"+",
|
|
2102
|
-
fileChanges.length - 4,
|
|
2103
|
-
" more"
|
|
2104
|
-
] })
|
|
2105
|
-
] })
|
|
2106
|
-
]
|
|
2107
|
-
}
|
|
2108
|
-
),
|
|
2109
|
-
isExpanded && /* @__PURE__ */ jsx("div", { className: "pl-5 border-l border-white/10 ml-1.5 mt-1 space-y-0.5", children: toolCalls.map((toolCall) => /* @__PURE__ */ jsx(CompactToolRow, { toolCall }, toolCall.id)) })
|
|
1842
|
+
status: item.status,
|
|
1843
|
+
activeForm: item.activeForm,
|
|
1844
|
+
children: item.content
|
|
1845
|
+
},
|
|
1846
|
+
index
|
|
1847
|
+
)) })
|
|
2110
1848
|
] });
|
|
2111
1849
|
}
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
return
|
|
2119
|
-
}
|
|
2120
|
-
function isFileEditAction(action) {
|
|
2121
|
-
return action.action === "file_edit";
|
|
2122
|
-
}
|
|
2123
|
-
function isFileWriteAction(action) {
|
|
2124
|
-
return action.action === "file_write";
|
|
2125
|
-
}
|
|
2126
|
-
function isSearchAction(action) {
|
|
2127
|
-
return action.action === "search";
|
|
2128
|
-
}
|
|
2129
|
-
function isGlobAction(action) {
|
|
2130
|
-
return action.action === "glob";
|
|
2131
|
-
}
|
|
2132
|
-
function isWebFetchAction(action) {
|
|
2133
|
-
return action.action === "web_fetch";
|
|
2134
|
-
}
|
|
2135
|
-
function isWebSearchAction(action) {
|
|
2136
|
-
return action.action === "web_search";
|
|
1850
|
+
var AttachmentContext = createContext(null);
|
|
1851
|
+
function useAttachment() {
|
|
1852
|
+
const context = useContext(AttachmentContext);
|
|
1853
|
+
if (!context) {
|
|
1854
|
+
throw new Error("useAttachment must be used within an Attachment");
|
|
1855
|
+
}
|
|
1856
|
+
return context;
|
|
2137
1857
|
}
|
|
2138
|
-
function
|
|
2139
|
-
|
|
1858
|
+
function Attachments({
|
|
1859
|
+
children,
|
|
1860
|
+
layout = "inline",
|
|
1861
|
+
className
|
|
1862
|
+
}) {
|
|
1863
|
+
const layoutStyles = {
|
|
1864
|
+
grid: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2",
|
|
1865
|
+
inline: "flex flex-wrap gap-2",
|
|
1866
|
+
list: "flex flex-col gap-1"
|
|
1867
|
+
};
|
|
1868
|
+
return /* @__PURE__ */ jsx(
|
|
1869
|
+
"div",
|
|
1870
|
+
{
|
|
1871
|
+
className: cn(
|
|
1872
|
+
"ash-attachments",
|
|
1873
|
+
layoutStyles[layout],
|
|
1874
|
+
className
|
|
1875
|
+
),
|
|
1876
|
+
"data-layout": layout,
|
|
1877
|
+
children
|
|
1878
|
+
}
|
|
1879
|
+
);
|
|
2140
1880
|
}
|
|
2141
|
-
function
|
|
2142
|
-
|
|
1881
|
+
function Attachment({
|
|
1882
|
+
file,
|
|
1883
|
+
children,
|
|
1884
|
+
removable = false,
|
|
1885
|
+
onRemove,
|
|
1886
|
+
className
|
|
1887
|
+
}) {
|
|
1888
|
+
const contextValue = {
|
|
1889
|
+
file,
|
|
1890
|
+
removable,
|
|
1891
|
+
onRemove
|
|
1892
|
+
};
|
|
1893
|
+
return /* @__PURE__ */ jsx(AttachmentContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
1894
|
+
"div",
|
|
1895
|
+
{
|
|
1896
|
+
className: cn(
|
|
1897
|
+
"ash-attachment relative group",
|
|
1898
|
+
"rounded-[var(--ash-radius-sm,0.375rem)]",
|
|
1899
|
+
"border border-[var(--ash-border,rgba(255,255,255,0.08))]",
|
|
1900
|
+
"bg-[var(--ash-surface-elevated,#111111)]",
|
|
1901
|
+
"overflow-hidden",
|
|
1902
|
+
"hover:border-[var(--ash-border-emphasis,rgba(255,255,255,0.15))]",
|
|
1903
|
+
"transition-colors",
|
|
1904
|
+
className
|
|
1905
|
+
),
|
|
1906
|
+
"data-file-type": file.type,
|
|
1907
|
+
children: children || /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1908
|
+
/* @__PURE__ */ jsx(AttachmentPreview, {}),
|
|
1909
|
+
/* @__PURE__ */ jsx(AttachmentInfo, {}),
|
|
1910
|
+
removable && /* @__PURE__ */ jsx(AttachmentRemove, {})
|
|
1911
|
+
] })
|
|
1912
|
+
}
|
|
1913
|
+
) });
|
|
2143
1914
|
}
|
|
2144
|
-
function
|
|
2145
|
-
|
|
1915
|
+
function AttachmentPreview({
|
|
1916
|
+
className,
|
|
1917
|
+
height = 80
|
|
1918
|
+
}) {
|
|
1919
|
+
const { file } = useAttachment();
|
|
1920
|
+
const isImage = file.type.startsWith("image/");
|
|
1921
|
+
const url = "url" in file ? file.url : "base64" in file ? `data:${file.type};base64,${file.base64}` : void 0;
|
|
1922
|
+
if (isImage && url) {
|
|
1923
|
+
return /* @__PURE__ */ jsx(
|
|
1924
|
+
"div",
|
|
1925
|
+
{
|
|
1926
|
+
className: cn(
|
|
1927
|
+
"ash-attachment-preview",
|
|
1928
|
+
"w-full bg-black/20 overflow-hidden",
|
|
1929
|
+
className
|
|
1930
|
+
),
|
|
1931
|
+
style: { height },
|
|
1932
|
+
children: /* @__PURE__ */ jsx(
|
|
1933
|
+
"img",
|
|
1934
|
+
{
|
|
1935
|
+
src: url,
|
|
1936
|
+
alt: file.name,
|
|
1937
|
+
className: "w-full h-full object-cover"
|
|
1938
|
+
}
|
|
1939
|
+
)
|
|
1940
|
+
}
|
|
1941
|
+
);
|
|
1942
|
+
}
|
|
1943
|
+
const iconForType = () => {
|
|
1944
|
+
if (file.type.includes("pdf")) {
|
|
1945
|
+
return /* @__PURE__ */ jsxs("svg", { className: "w-8 h-8", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
|
|
1946
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }),
|
|
1947
|
+
/* @__PURE__ */ jsx("text", { x: "7", y: "16", fontSize: "6", fill: "currentColor", stroke: "none", fontWeight: "bold", children: "PDF" })
|
|
1948
|
+
] });
|
|
1949
|
+
}
|
|
1950
|
+
if (file.type.includes("text") || file.type.includes("json")) {
|
|
1951
|
+
return /* @__PURE__ */ jsx("svg", { className: "w-8 h-8", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) });
|
|
1952
|
+
}
|
|
1953
|
+
return /* @__PURE__ */ jsx("svg", { className: "w-8 h-8", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) });
|
|
1954
|
+
};
|
|
1955
|
+
return /* @__PURE__ */ jsx(
|
|
1956
|
+
"div",
|
|
1957
|
+
{
|
|
1958
|
+
className: cn(
|
|
1959
|
+
"ash-attachment-preview",
|
|
1960
|
+
"w-full flex items-center justify-center",
|
|
1961
|
+
"bg-[var(--ash-surface-dark,#0a0a0a)]",
|
|
1962
|
+
"text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
|
|
1963
|
+
className
|
|
1964
|
+
),
|
|
1965
|
+
style: { height },
|
|
1966
|
+
children: iconForType()
|
|
1967
|
+
}
|
|
1968
|
+
);
|
|
2146
1969
|
}
|
|
2147
|
-
function
|
|
2148
|
-
|
|
1970
|
+
function AttachmentInfo({
|
|
1971
|
+
className,
|
|
1972
|
+
showSize = true
|
|
1973
|
+
}) {
|
|
1974
|
+
const { file } = useAttachment();
|
|
1975
|
+
return /* @__PURE__ */ jsxs(
|
|
1976
|
+
"div",
|
|
1977
|
+
{
|
|
1978
|
+
className: cn(
|
|
1979
|
+
"ash-attachment-info",
|
|
1980
|
+
"px-2 py-1.5",
|
|
1981
|
+
"truncate",
|
|
1982
|
+
className
|
|
1983
|
+
),
|
|
1984
|
+
children: [
|
|
1985
|
+
/* @__PURE__ */ jsx(
|
|
1986
|
+
"div",
|
|
1987
|
+
{
|
|
1988
|
+
className: cn(
|
|
1989
|
+
"text-[var(--ash-font-size-xs,10px)]",
|
|
1990
|
+
"text-[var(--ash-text-primary,rgba(255,255,255,0.9))]",
|
|
1991
|
+
"truncate font-medium"
|
|
1992
|
+
),
|
|
1993
|
+
title: file.name,
|
|
1994
|
+
children: file.name
|
|
1995
|
+
}
|
|
1996
|
+
),
|
|
1997
|
+
showSize && /* @__PURE__ */ jsx(
|
|
1998
|
+
"div",
|
|
1999
|
+
{
|
|
2000
|
+
className: cn(
|
|
2001
|
+
"text-[var(--ash-font-size-xs,10px)]",
|
|
2002
|
+
"text-[var(--ash-text-muted,rgba(255,255,255,0.5))]"
|
|
2003
|
+
),
|
|
2004
|
+
children: formatFileSize(file.size)
|
|
2005
|
+
}
|
|
2006
|
+
)
|
|
2007
|
+
]
|
|
2008
|
+
}
|
|
2009
|
+
);
|
|
2149
2010
|
}
|
|
2150
|
-
function
|
|
2151
|
-
|
|
2011
|
+
function AttachmentRemove({ className }) {
|
|
2012
|
+
const { onRemove, removable } = useAttachment();
|
|
2013
|
+
if (!removable || !onRemove) return null;
|
|
2014
|
+
return /* @__PURE__ */ jsx(
|
|
2015
|
+
"button",
|
|
2016
|
+
{
|
|
2017
|
+
onClick: (e) => {
|
|
2018
|
+
e.stopPropagation();
|
|
2019
|
+
onRemove();
|
|
2020
|
+
},
|
|
2021
|
+
className: cn(
|
|
2022
|
+
"ash-attachment-remove",
|
|
2023
|
+
"absolute top-1 right-1",
|
|
2024
|
+
"w-5 h-5 rounded-full",
|
|
2025
|
+
"flex items-center justify-center",
|
|
2026
|
+
"bg-black/60 text-white/80",
|
|
2027
|
+
"hover:bg-black/80 hover:text-white",
|
|
2028
|
+
"opacity-0 group-hover:opacity-100",
|
|
2029
|
+
"transition-opacity",
|
|
2030
|
+
className
|
|
2031
|
+
),
|
|
2032
|
+
"aria-label": "Remove attachment",
|
|
2033
|
+
children: /* @__PURE__ */ jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
2034
|
+
}
|
|
2035
|
+
);
|
|
2152
2036
|
}
|
|
2153
|
-
function
|
|
2154
|
-
|
|
2037
|
+
function FileBadgeCompact({
|
|
2038
|
+
file,
|
|
2039
|
+
removable = false,
|
|
2040
|
+
onRemove,
|
|
2041
|
+
className
|
|
2042
|
+
}) {
|
|
2043
|
+
const isImage = file.type.startsWith("image/");
|
|
2044
|
+
return /* @__PURE__ */ jsxs(
|
|
2045
|
+
"div",
|
|
2046
|
+
{
|
|
2047
|
+
className: cn(
|
|
2048
|
+
"ash-file-badge group inline-flex items-center gap-1.5",
|
|
2049
|
+
"px-2 py-1 rounded-md",
|
|
2050
|
+
"bg-[var(--ash-surface-elevated,#111111)]",
|
|
2051
|
+
"border border-[var(--ash-border,rgba(255,255,255,0.08))]",
|
|
2052
|
+
"text-[var(--ash-font-size-xs,10px)]",
|
|
2053
|
+
className
|
|
2054
|
+
),
|
|
2055
|
+
children: [
|
|
2056
|
+
isImage ? /* @__PURE__ */ jsx("svg", { className: "w-3 h-3 text-[var(--ash-text-muted)]", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }) : /* @__PURE__ */ jsx("svg", { className: "w-3 h-3 text-[var(--ash-text-muted)]", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }),
|
|
2057
|
+
/* @__PURE__ */ jsx("span", { className: "text-[var(--ash-text-primary)] truncate max-w-[100px]", children: file.name }),
|
|
2058
|
+
/* @__PURE__ */ jsx("span", { className: "text-[var(--ash-text-muted)]", children: formatFileSize(file.size) }),
|
|
2059
|
+
removable && onRemove && /* @__PURE__ */ jsx(
|
|
2060
|
+
"button",
|
|
2061
|
+
{
|
|
2062
|
+
onClick: (e) => {
|
|
2063
|
+
e.stopPropagation();
|
|
2064
|
+
onRemove();
|
|
2065
|
+
},
|
|
2066
|
+
className: cn(
|
|
2067
|
+
"ml-0.5 text-[var(--ash-text-muted)]",
|
|
2068
|
+
"hover:text-red-400 transition-colors",
|
|
2069
|
+
"opacity-0 group-hover:opacity-100"
|
|
2070
|
+
),
|
|
2071
|
+
"aria-label": "Remove",
|
|
2072
|
+
children: /* @__PURE__ */ jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
2073
|
+
}
|
|
2074
|
+
)
|
|
2075
|
+
]
|
|
2076
|
+
}
|
|
2077
|
+
);
|
|
2155
2078
|
}
|
|
2156
|
-
function
|
|
2157
|
-
|
|
2079
|
+
function Shimmer({
|
|
2080
|
+
children,
|
|
2081
|
+
className,
|
|
2082
|
+
isActive = true
|
|
2083
|
+
}) {
|
|
2084
|
+
if (!isActive) return null;
|
|
2085
|
+
return /* @__PURE__ */ jsx(
|
|
2086
|
+
"div",
|
|
2087
|
+
{
|
|
2088
|
+
className: cn(
|
|
2089
|
+
"ash-shimmer",
|
|
2090
|
+
"flex flex-col gap-2",
|
|
2091
|
+
className
|
|
2092
|
+
),
|
|
2093
|
+
role: "status",
|
|
2094
|
+
"aria-label": "Loading",
|
|
2095
|
+
children: children || /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2096
|
+
/* @__PURE__ */ jsx(ShimmerLine, { width: "100%" }),
|
|
2097
|
+
/* @__PURE__ */ jsx(ShimmerLine, { width: "80%" }),
|
|
2098
|
+
/* @__PURE__ */ jsx(ShimmerLine, { width: "60%" })
|
|
2099
|
+
] })
|
|
2100
|
+
}
|
|
2101
|
+
);
|
|
2158
2102
|
}
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
mode: prev.mode === "inline" ? "compact" : "inline"
|
|
2181
|
-
}));
|
|
2182
|
-
}, []);
|
|
2183
|
-
const value = useMemo(
|
|
2184
|
-
() => ({ config, setMode, setConfig, toggleMode }),
|
|
2185
|
-
[config, setMode, setConfig, toggleMode]
|
|
2103
|
+
function ShimmerLine({
|
|
2104
|
+
width = "100%",
|
|
2105
|
+
height = 16,
|
|
2106
|
+
className
|
|
2107
|
+
}) {
|
|
2108
|
+
return /* @__PURE__ */ jsx(
|
|
2109
|
+
"div",
|
|
2110
|
+
{
|
|
2111
|
+
className: cn(
|
|
2112
|
+
"ash-shimmer-line",
|
|
2113
|
+
"rounded-md",
|
|
2114
|
+
"bg-gradient-to-r from-white/5 via-white/10 to-white/5",
|
|
2115
|
+
"bg-[length:200%_100%]",
|
|
2116
|
+
"animate-[shimmer_1.5s_ease-in-out_infinite]",
|
|
2117
|
+
className
|
|
2118
|
+
),
|
|
2119
|
+
style: {
|
|
2120
|
+
width: typeof width === "number" ? `${width}px` : width,
|
|
2121
|
+
height
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2186
2124
|
);
|
|
2187
|
-
return /* @__PURE__ */ jsx(DisplayModeContext.Provider, { value, children });
|
|
2188
2125
|
}
|
|
2189
|
-
function
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2126
|
+
function ShimmerBlock({
|
|
2127
|
+
width = "100%",
|
|
2128
|
+
height = 100,
|
|
2129
|
+
rounded = "md",
|
|
2130
|
+
className
|
|
2131
|
+
}) {
|
|
2132
|
+
const roundedStyles = {
|
|
2133
|
+
none: "rounded-none",
|
|
2134
|
+
sm: "rounded-sm",
|
|
2135
|
+
md: "rounded-md",
|
|
2136
|
+
lg: "rounded-lg",
|
|
2137
|
+
full: "rounded-full"
|
|
2138
|
+
};
|
|
2139
|
+
return /* @__PURE__ */ jsx(
|
|
2140
|
+
"div",
|
|
2141
|
+
{
|
|
2142
|
+
className: cn(
|
|
2143
|
+
"ash-shimmer-block",
|
|
2144
|
+
roundedStyles[rounded],
|
|
2145
|
+
"bg-gradient-to-r from-white/5 via-white/10 to-white/5",
|
|
2146
|
+
"bg-[length:200%_100%]",
|
|
2147
|
+
"animate-[shimmer_1.5s_ease-in-out_infinite]",
|
|
2148
|
+
className
|
|
2149
|
+
),
|
|
2150
|
+
style: {
|
|
2151
|
+
width: typeof width === "number" ? `${width}px` : width,
|
|
2152
|
+
height
|
|
2199
2153
|
}
|
|
2200
|
-
}
|
|
2201
|
-
|
|
2202
|
-
return context;
|
|
2154
|
+
}
|
|
2155
|
+
);
|
|
2203
2156
|
}
|
|
2204
|
-
function
|
|
2205
|
-
|
|
2206
|
-
return config;
|
|
2207
|
-
}
|
|
2208
|
-
function MessageList({
|
|
2209
|
-
entries,
|
|
2210
|
-
loading,
|
|
2211
|
-
streamingContent,
|
|
2212
|
-
displayConfig: displayConfigProp,
|
|
2213
|
-
onOptionSelect,
|
|
2214
|
-
renderWidget,
|
|
2215
|
-
onWidgetAction,
|
|
2216
|
-
autoScroll = true,
|
|
2217
|
-
richContentRenderers,
|
|
2157
|
+
function ShimmerText({
|
|
2158
|
+
chars = 20,
|
|
2218
2159
|
className
|
|
2219
2160
|
}) {
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
});
|
|
2238
|
-
};
|
|
2239
|
-
},
|
|
2240
|
-
[onWidgetAction]
|
|
2161
|
+
return /* @__PURE__ */ jsx(
|
|
2162
|
+
"span",
|
|
2163
|
+
{
|
|
2164
|
+
className: cn(
|
|
2165
|
+
"ash-shimmer-text inline-block",
|
|
2166
|
+
"rounded",
|
|
2167
|
+
"bg-gradient-to-r from-white/5 via-white/10 to-white/5",
|
|
2168
|
+
"bg-[length:200%_100%]",
|
|
2169
|
+
"animate-[shimmer_1.5s_ease-in-out_infinite]",
|
|
2170
|
+
className
|
|
2171
|
+
),
|
|
2172
|
+
style: {
|
|
2173
|
+
width: `${chars}ch`,
|
|
2174
|
+
height: "1em",
|
|
2175
|
+
verticalAlign: "middle"
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2241
2178
|
);
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2179
|
+
}
|
|
2180
|
+
function LoadingDots({
|
|
2181
|
+
size = "md",
|
|
2182
|
+
className
|
|
2183
|
+
}) {
|
|
2184
|
+
const sizeStyles = {
|
|
2185
|
+
sm: "w-1 h-1",
|
|
2186
|
+
md: "w-1.5 h-1.5",
|
|
2187
|
+
lg: "w-2 h-2"
|
|
2188
|
+
};
|
|
2189
|
+
const gapStyles = {
|
|
2190
|
+
sm: "gap-0.5",
|
|
2191
|
+
md: "gap-1",
|
|
2192
|
+
lg: "gap-1.5"
|
|
2193
|
+
};
|
|
2194
|
+
return /* @__PURE__ */ jsx(
|
|
2195
|
+
"span",
|
|
2196
|
+
{
|
|
2197
|
+
className: cn(
|
|
2198
|
+
"ash-loading-dots inline-flex items-center",
|
|
2199
|
+
gapStyles[size],
|
|
2200
|
+
className
|
|
2201
|
+
),
|
|
2202
|
+
role: "status",
|
|
2203
|
+
"aria-label": "Loading",
|
|
2204
|
+
children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(
|
|
2205
|
+
"span",
|
|
2206
|
+
{
|
|
2207
|
+
className: cn(
|
|
2208
|
+
sizeStyles[size],
|
|
2209
|
+
"rounded-full",
|
|
2210
|
+
"bg-current",
|
|
2211
|
+
"animate-bounce"
|
|
2212
|
+
),
|
|
2213
|
+
style: { animationDelay: `${i * 150}ms` }
|
|
2214
|
+
},
|
|
2215
|
+
i
|
|
2216
|
+
))
|
|
2249
2217
|
}
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2218
|
+
);
|
|
2219
|
+
}
|
|
2220
|
+
function LoadingSpinner({
|
|
2221
|
+
size = "md",
|
|
2222
|
+
className
|
|
2223
|
+
}) {
|
|
2224
|
+
const sizeStyles = {
|
|
2225
|
+
sm: "w-4 h-4",
|
|
2226
|
+
md: "w-6 h-6",
|
|
2227
|
+
lg: "w-8 h-8"
|
|
2228
|
+
};
|
|
2229
|
+
return /* @__PURE__ */ jsxs(
|
|
2230
|
+
"svg",
|
|
2231
|
+
{
|
|
2232
|
+
className: cn(
|
|
2233
|
+
"ash-loading-spinner animate-spin",
|
|
2234
|
+
sizeStyles[size],
|
|
2235
|
+
className
|
|
2236
|
+
),
|
|
2237
|
+
fill: "none",
|
|
2238
|
+
viewBox: "0 0 24 24",
|
|
2239
|
+
role: "status",
|
|
2240
|
+
"aria-label": "Loading",
|
|
2241
|
+
children: [
|
|
2242
|
+
/* @__PURE__ */ jsx(
|
|
2243
|
+
"circle",
|
|
2270
2244
|
{
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
/* @__PURE__ */ jsx("div", { className: "w-7 h-7 rounded-full bg-[var(--ash-accent)]/20 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx(BotIcon, { className: "w-4 h-4 text-[var(--ash-accent)]" }) }),
|
|
2282
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1", children: config.mode === "accordion" ? /* @__PURE__ */ jsx(
|
|
2283
|
-
StepAccordion,
|
|
2245
|
+
className: "opacity-25",
|
|
2246
|
+
cx: "12",
|
|
2247
|
+
cy: "12",
|
|
2248
|
+
r: "10",
|
|
2249
|
+
stroke: "currentColor",
|
|
2250
|
+
strokeWidth: "4"
|
|
2251
|
+
}
|
|
2252
|
+
),
|
|
2253
|
+
/* @__PURE__ */ jsx(
|
|
2254
|
+
"path",
|
|
2284
2255
|
{
|
|
2285
|
-
|
|
2286
|
-
|
|
2256
|
+
className: "opacity-75",
|
|
2257
|
+
fill: "currentColor",
|
|
2258
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
2287
2259
|
}
|
|
2288
|
-
)
|
|
2289
|
-
|
|
2260
|
+
)
|
|
2261
|
+
]
|
|
2262
|
+
}
|
|
2263
|
+
);
|
|
2264
|
+
}
|
|
2265
|
+
function MessageShimmer({
|
|
2266
|
+
role = "assistant",
|
|
2267
|
+
className
|
|
2268
|
+
}) {
|
|
2269
|
+
return /* @__PURE__ */ jsxs(
|
|
2270
|
+
"div",
|
|
2271
|
+
{
|
|
2272
|
+
className: cn(
|
|
2273
|
+
"ash-message-shimmer flex gap-2",
|
|
2274
|
+
role === "user" && "flex-row-reverse",
|
|
2275
|
+
className
|
|
2276
|
+
),
|
|
2277
|
+
children: [
|
|
2278
|
+
/* @__PURE__ */ jsx(
|
|
2279
|
+
ShimmerBlock,
|
|
2290
2280
|
{
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2281
|
+
width: 20,
|
|
2282
|
+
height: 20,
|
|
2283
|
+
rounded: "full"
|
|
2294
2284
|
}
|
|
2295
|
-
)
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
/* @__PURE__ */ jsx("div", { className: "rounded-xl p-3 bg-white/5", children: /* @__PURE__ */ jsx(LoadingIndicator, { variant: "dots" }) })
|
|
2305
|
-
] }),
|
|
2306
|
-
/* @__PURE__ */ jsx("div", { ref: messagesEndRef })
|
|
2307
|
-
] });
|
|
2285
|
+
),
|
|
2286
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-2 max-w-[80%]", children: [
|
|
2287
|
+
/* @__PURE__ */ jsx(ShimmerLine, { width: "100%", height: 14 }),
|
|
2288
|
+
/* @__PURE__ */ jsx(ShimmerLine, { width: "85%", height: 14 }),
|
|
2289
|
+
/* @__PURE__ */ jsx(ShimmerLine, { width: "70%", height: 14 })
|
|
2290
|
+
] })
|
|
2291
|
+
]
|
|
2292
|
+
}
|
|
2293
|
+
);
|
|
2308
2294
|
}
|
|
2309
2295
|
function getLevelIcon(level) {
|
|
2310
2296
|
switch (level) {
|
|
@@ -2450,208 +2436,6 @@ function LogsPanel({
|
|
|
2450
2436
|
}
|
|
2451
2437
|
);
|
|
2452
2438
|
}
|
|
2453
|
-
function CompactToolStatusLine({
|
|
2454
|
-
toolCall,
|
|
2455
|
-
previousToolCall,
|
|
2456
|
-
animationDuration = 300,
|
|
2457
|
-
className
|
|
2458
|
-
}) {
|
|
2459
|
-
const [isAnimating, setIsAnimating] = useState(false);
|
|
2460
|
-
const [displayedToolCall, setDisplayedToolCall] = useState(toolCall);
|
|
2461
|
-
const [exitingToolCall, setExitingToolCall] = useState(null);
|
|
2462
|
-
const prevToolCallRef = useRef(null);
|
|
2463
|
-
useEffect(() => {
|
|
2464
|
-
if (toolCall.id !== prevToolCallRef.current) {
|
|
2465
|
-
if (prevToolCallRef.current !== null && previousToolCall) {
|
|
2466
|
-
setExitingToolCall(previousToolCall);
|
|
2467
|
-
setIsAnimating(true);
|
|
2468
|
-
const timer = setTimeout(() => {
|
|
2469
|
-
setDisplayedToolCall(toolCall);
|
|
2470
|
-
setExitingToolCall(null);
|
|
2471
|
-
setIsAnimating(false);
|
|
2472
|
-
}, animationDuration);
|
|
2473
|
-
prevToolCallRef.current = toolCall.id;
|
|
2474
|
-
return () => clearTimeout(timer);
|
|
2475
|
-
} else {
|
|
2476
|
-
setDisplayedToolCall(toolCall);
|
|
2477
|
-
prevToolCallRef.current = toolCall.id;
|
|
2478
|
-
}
|
|
2479
|
-
} else {
|
|
2480
|
-
setDisplayedToolCall(toolCall);
|
|
2481
|
-
}
|
|
2482
|
-
return void 0;
|
|
2483
|
-
}, [toolCall, previousToolCall, animationDuration]);
|
|
2484
|
-
const statusClasses = {
|
|
2485
|
-
pending: "border-yellow-500/30",
|
|
2486
|
-
success: "border-[var(--ash-accent)]/30",
|
|
2487
|
-
failed: "border-red-500/30"
|
|
2488
|
-
};
|
|
2489
|
-
const renderToolCallContent = (tc, isExiting) => /* @__PURE__ */ jsxs(
|
|
2490
|
-
"div",
|
|
2491
|
-
{
|
|
2492
|
-
className: cn(
|
|
2493
|
-
"flex items-center gap-3 px-4 py-2.5",
|
|
2494
|
-
isExiting ? "ash-status-line-exit" : isAnimating ? "ash-status-line-enter" : ""
|
|
2495
|
-
),
|
|
2496
|
-
style: {
|
|
2497
|
-
animationDuration: `${animationDuration}ms`
|
|
2498
|
-
},
|
|
2499
|
-
children: [
|
|
2500
|
-
/* @__PURE__ */ jsx(
|
|
2501
|
-
"div",
|
|
2502
|
-
{
|
|
2503
|
-
className: cn(
|
|
2504
|
-
"w-6 h-6 rounded-lg flex items-center justify-center shrink-0",
|
|
2505
|
-
tc.status === "pending" ? "bg-yellow-500/20" : tc.status === "failed" ? "bg-red-500/20" : "bg-[var(--ash-accent)]/20"
|
|
2506
|
-
),
|
|
2507
|
-
children: /* @__PURE__ */ jsx(
|
|
2508
|
-
ActionIcon,
|
|
2509
|
-
{
|
|
2510
|
-
actionType: tc.actionType,
|
|
2511
|
-
className: cn(
|
|
2512
|
-
"w-3.5 h-3.5",
|
|
2513
|
-
tc.status === "pending" ? "text-yellow-400" : tc.status === "failed" ? "text-red-400" : "text-[var(--ash-accent)]"
|
|
2514
|
-
)
|
|
2515
|
-
}
|
|
2516
|
-
)
|
|
2517
|
-
}
|
|
2518
|
-
),
|
|
2519
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-white shrink-0", children: getActionLabel(tc.actionType) }),
|
|
2520
|
-
/* @__PURE__ */ jsx("span", { className: "font-mono text-sm truncate text-white/60 flex-1 min-w-0", children: tc.summary }),
|
|
2521
|
-
/* @__PURE__ */ jsx(StatusIndicator, { status: tc.status, size: "sm" })
|
|
2522
|
-
]
|
|
2523
|
-
}
|
|
2524
|
-
);
|
|
2525
|
-
return /* @__PURE__ */ jsxs(
|
|
2526
|
-
"div",
|
|
2527
|
-
{
|
|
2528
|
-
className: cn(
|
|
2529
|
-
"relative rounded-xl border bg-[var(--ash-surface-dark,#0a0a0a)] overflow-hidden",
|
|
2530
|
-
statusClasses[displayedToolCall.status],
|
|
2531
|
-
displayedToolCall.status === "pending" && "ash-tool-status-pending",
|
|
2532
|
-
className
|
|
2533
|
-
),
|
|
2534
|
-
children: [
|
|
2535
|
-
exitingToolCall && /* @__PURE__ */ jsx("div", { className: "absolute inset-0", children: renderToolCallContent(exitingToolCall, true) }),
|
|
2536
|
-
renderToolCallContent(displayedToolCall, false)
|
|
2537
|
-
]
|
|
2538
|
-
}
|
|
2539
|
-
);
|
|
2540
|
-
}
|
|
2541
|
-
function TodoStatusIcon({ status, className = "w-4 h-4" }) {
|
|
2542
|
-
switch (status) {
|
|
2543
|
-
case "completed":
|
|
2544
|
-
return /* @__PURE__ */ jsx(CheckCircleIcon, { className: cn(className, "text-emerald-400") });
|
|
2545
|
-
case "in_progress":
|
|
2546
|
-
return /* @__PURE__ */ jsx(LoaderIcon, { className: cn(className, "text-yellow-400 animate-spin") });
|
|
2547
|
-
case "pending":
|
|
2548
|
-
default:
|
|
2549
|
-
return /* @__PURE__ */ jsx(CircleIcon, { className: cn(className, "text-white/30") });
|
|
2550
|
-
}
|
|
2551
|
-
}
|
|
2552
|
-
function TodoListItem({ todo, index, compact = false }) {
|
|
2553
|
-
const displayText = todo.status === "in_progress" ? todo.activeForm : todo.content;
|
|
2554
|
-
return /* @__PURE__ */ jsxs(
|
|
2555
|
-
"div",
|
|
2556
|
-
{
|
|
2557
|
-
className: cn(
|
|
2558
|
-
"flex items-start gap-2 transition-all duration-200",
|
|
2559
|
-
compact ? "py-1" : "py-1.5",
|
|
2560
|
-
todo.status === "completed" && "opacity-60",
|
|
2561
|
-
todo.status === "in_progress" && "bg-yellow-500/5 -mx-2 px-2 rounded-md"
|
|
2562
|
-
),
|
|
2563
|
-
children: [
|
|
2564
|
-
/* @__PURE__ */ jsx(TodoStatusIcon, { status: todo.status, className: compact ? "w-3.5 h-3.5 mt-0.5" : "w-4 h-4 mt-0.5" }),
|
|
2565
|
-
/* @__PURE__ */ jsxs(
|
|
2566
|
-
"span",
|
|
2567
|
-
{
|
|
2568
|
-
className: cn(
|
|
2569
|
-
"flex-1 text-white/80",
|
|
2570
|
-
compact ? "text-xs" : "text-sm",
|
|
2571
|
-
todo.status === "completed" && "line-through text-white/50"
|
|
2572
|
-
),
|
|
2573
|
-
children: [
|
|
2574
|
-
!compact && /* @__PURE__ */ jsxs("span", { className: "text-white/40 mr-1.5", children: [
|
|
2575
|
-
index + 1,
|
|
2576
|
-
"."
|
|
2577
|
-
] }),
|
|
2578
|
-
displayText
|
|
2579
|
-
]
|
|
2580
|
-
}
|
|
2581
|
-
)
|
|
2582
|
-
]
|
|
2583
|
-
}
|
|
2584
|
-
);
|
|
2585
|
-
}
|
|
2586
|
-
function TodoProgress({ completed, total, className }) {
|
|
2587
|
-
const percentage = total > 0 ? Math.round(completed / total * 100) : 0;
|
|
2588
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", className), children: [
|
|
2589
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 h-1.5 bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
2590
|
-
"div",
|
|
2591
|
-
{
|
|
2592
|
-
className: "h-full bg-emerald-400 rounded-full transition-all duration-500 ease-out",
|
|
2593
|
-
style: { width: `${percentage}%` }
|
|
2594
|
-
}
|
|
2595
|
-
) }),
|
|
2596
|
-
/* @__PURE__ */ jsxs("span", { className: "text-xs text-white/50 tabular-nums min-w-[3rem] text-right", children: [
|
|
2597
|
-
completed,
|
|
2598
|
-
"/",
|
|
2599
|
-
total
|
|
2600
|
-
] })
|
|
2601
|
-
] });
|
|
2602
|
-
}
|
|
2603
|
-
function TodoPanel({
|
|
2604
|
-
todos,
|
|
2605
|
-
title,
|
|
2606
|
-
compact = false,
|
|
2607
|
-
showProgress = true,
|
|
2608
|
-
className
|
|
2609
|
-
}) {
|
|
2610
|
-
const stats = useMemo(() => {
|
|
2611
|
-
return {
|
|
2612
|
-
total: todos.length,
|
|
2613
|
-
completed: todos.filter((t) => t.status === "completed").length,
|
|
2614
|
-
inProgress: todos.filter((t) => t.status === "in_progress").length,
|
|
2615
|
-
pending: todos.filter((t) => t.status === "pending").length
|
|
2616
|
-
};
|
|
2617
|
-
}, [todos]);
|
|
2618
|
-
if (todos.length === 0) {
|
|
2619
|
-
return null;
|
|
2620
|
-
}
|
|
2621
|
-
return /* @__PURE__ */ jsxs(
|
|
2622
|
-
"div",
|
|
2623
|
-
{
|
|
2624
|
-
className: cn(
|
|
2625
|
-
"rounded-lg border border-white/10 bg-white/5 overflow-hidden",
|
|
2626
|
-
className
|
|
2627
|
-
),
|
|
2628
|
-
children: [
|
|
2629
|
-
(title || showProgress) && /* @__PURE__ */ jsxs("div", { className: cn("border-b border-white/5", compact ? "px-2 py-1.5" : "px-3 py-2"), children: [
|
|
2630
|
-
title && /* @__PURE__ */ jsx("div", { className: cn("font-medium text-white/90 mb-1.5", compact ? "text-xs" : "text-sm"), children: title }),
|
|
2631
|
-
showProgress && /* @__PURE__ */ jsx(TodoProgress, { completed: stats.completed, total: stats.total })
|
|
2632
|
-
] }),
|
|
2633
|
-
/* @__PURE__ */ jsx("div", { className: cn(compact ? "px-2 py-1.5" : "px-3 py-2"), children: todos.map((todo, index) => /* @__PURE__ */ jsx(
|
|
2634
|
-
TodoListItem,
|
|
2635
|
-
{
|
|
2636
|
-
todo,
|
|
2637
|
-
index,
|
|
2638
|
-
compact
|
|
2639
|
-
},
|
|
2640
|
-
`${todo.content}-${index}`
|
|
2641
|
-
)) }),
|
|
2642
|
-
!compact && stats.inProgress > 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-t border-white/5 bg-yellow-500/5", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-yellow-400", children: [
|
|
2643
|
-
/* @__PURE__ */ jsx(LoaderIcon, { className: "w-3 h-3 animate-spin" }),
|
|
2644
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
2645
|
-
stats.inProgress,
|
|
2646
|
-
" task",
|
|
2647
|
-
stats.inProgress !== 1 ? "s" : "",
|
|
2648
|
-
" in progress"
|
|
2649
|
-
] })
|
|
2650
|
-
] }) })
|
|
2651
|
-
]
|
|
2652
|
-
}
|
|
2653
|
-
);
|
|
2654
|
-
}
|
|
2655
2439
|
function EnvVarsPanel({
|
|
2656
2440
|
envVars,
|
|
2657
2441
|
onChange,
|
|
@@ -2783,236 +2567,90 @@ function EnvVarsPanel({
|
|
|
2783
2567
|
onClick: handleAddEnvVar,
|
|
2784
2568
|
disabled: !newEnvKey.trim(),
|
|
2785
2569
|
className: "ash-env-vars-add-button",
|
|
2786
|
-
children: "Add"
|
|
2787
|
-
}
|
|
2788
|
-
)
|
|
2789
|
-
] }),
|
|
2790
|
-
helperText && /* @__PURE__ */ jsx("p", { className: "ash-env-vars-helper", children: helperText })
|
|
2791
|
-
] })
|
|
2792
|
-
] });
|
|
2793
|
-
}
|
|
2794
|
-
function DisplayModeToggle({
|
|
2795
|
-
className,
|
|
2796
|
-
showLabel = true,
|
|
2797
|
-
labels = { inline: "Inline", compact: "Compact", accordion: "Steps" },
|
|
2798
|
-
modes = ["inline", "compact", "accordion"]
|
|
2799
|
-
}) {
|
|
2800
|
-
const { config, setMode } = useDisplayMode();
|
|
2801
|
-
const currentMode = config.mode;
|
|
2802
|
-
const currentIndex = modes.indexOf(currentMode);
|
|
2803
|
-
const effectiveIndex = currentIndex === -1 ? 0 : currentIndex;
|
|
2804
|
-
const nextIndex = (effectiveIndex + 1) % modes.length;
|
|
2805
|
-
const nextMode = modes[nextIndex];
|
|
2806
|
-
const handleClick = () => {
|
|
2807
|
-
setMode(nextMode);
|
|
2808
|
-
};
|
|
2809
|
-
const getIcon = (mode) => {
|
|
2810
|
-
switch (mode) {
|
|
2811
|
-
case "inline":
|
|
2812
|
-
return /* @__PURE__ */ jsx(
|
|
2813
|
-
"svg",
|
|
2814
|
-
{
|
|
2815
|
-
className: "ash-display-mode-icon",
|
|
2816
|
-
viewBox: "0 0 24 24",
|
|
2817
|
-
fill: "none",
|
|
2818
|
-
stroke: "currentColor",
|
|
2819
|
-
strokeWidth: "1.5",
|
|
2820
|
-
children: /* @__PURE__ */ jsx(
|
|
2821
|
-
"path",
|
|
2822
|
-
{
|
|
2823
|
-
strokeLinecap: "round",
|
|
2824
|
-
strokeLinejoin: "round",
|
|
2825
|
-
d: "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
|
2826
|
-
}
|
|
2827
|
-
)
|
|
2570
|
+
children: "Add"
|
|
2828
2571
|
}
|
|
2829
|
-
)
|
|
2830
|
-
|
|
2831
|
-
|
|
2572
|
+
)
|
|
2573
|
+
] }),
|
|
2574
|
+
helperText && /* @__PURE__ */ jsx("p", { className: "ash-env-vars-helper", children: helperText })
|
|
2575
|
+
] })
|
|
2576
|
+
] });
|
|
2577
|
+
}
|
|
2578
|
+
function OptionCards({ options, onSelect, className }) {
|
|
2579
|
+
return /* @__PURE__ */ jsx("div", { className: cn("grid gap-2 mt-3", className), style: {
|
|
2580
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))"
|
|
2581
|
+
}, children: options.map((option) => /* @__PURE__ */ jsxs(
|
|
2582
|
+
"button",
|
|
2583
|
+
{
|
|
2584
|
+
onClick: () => onSelect(option),
|
|
2585
|
+
className: cn(
|
|
2586
|
+
"flex items-start gap-3 p-3 rounded-xl text-left",
|
|
2587
|
+
"bg-white/5 border border-white/10",
|
|
2588
|
+
"hover:bg-[var(--ash-accent)]/10 hover:border-[var(--ash-accent)]/30",
|
|
2589
|
+
"focus:outline-none focus:ring-2 focus:ring-[var(--ash-accent)]/50",
|
|
2590
|
+
"transition-all duration-200 cursor-pointer",
|
|
2591
|
+
"group"
|
|
2592
|
+
),
|
|
2593
|
+
children: [
|
|
2594
|
+
/* @__PURE__ */ jsx("span", { className: cn(
|
|
2595
|
+
"flex-shrink-0 w-6 h-6 rounded-lg",
|
|
2596
|
+
"bg-[var(--ash-accent)]/20 text-[var(--ash-accent)]",
|
|
2597
|
+
"flex items-center justify-center",
|
|
2598
|
+
"text-xs font-semibold",
|
|
2599
|
+
"group-hover:bg-[var(--ash-accent)]/30",
|
|
2600
|
+
"transition-colors duration-200"
|
|
2601
|
+
), children: option.id }),
|
|
2602
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
2603
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-white/90 group-hover:text-white transition-colors", children: option.label }),
|
|
2604
|
+
option.description && /* @__PURE__ */ jsx("div", { className: "text-xs text-white/50 mt-0.5 line-clamp-2 group-hover:text-white/60 transition-colors", children: option.description })
|
|
2605
|
+
] }),
|
|
2606
|
+
/* @__PURE__ */ jsx(
|
|
2832
2607
|
"svg",
|
|
2833
2608
|
{
|
|
2834
|
-
className:
|
|
2835
|
-
|
|
2609
|
+
className: cn(
|
|
2610
|
+
"w-4 h-4 text-white/30 flex-shrink-0 mt-0.5",
|
|
2611
|
+
"group-hover:text-[var(--ash-accent)] group-hover:translate-x-0.5",
|
|
2612
|
+
"transition-all duration-200"
|
|
2613
|
+
),
|
|
2836
2614
|
fill: "none",
|
|
2837
|
-
stroke: "currentColor",
|
|
2838
|
-
strokeWidth: "1.5",
|
|
2839
|
-
children: /* @__PURE__ */ jsx(
|
|
2840
|
-
"path",
|
|
2841
|
-
{
|
|
2842
|
-
strokeLinecap: "round",
|
|
2843
|
-
strokeLinejoin: "round",
|
|
2844
|
-
d: "M3.75 6.75h16.5M3.75 12h16.5M12 17.25h8.25"
|
|
2845
|
-
}
|
|
2846
|
-
)
|
|
2847
|
-
}
|
|
2848
|
-
);
|
|
2849
|
-
case "accordion":
|
|
2850
|
-
return /* @__PURE__ */ jsx(
|
|
2851
|
-
"svg",
|
|
2852
|
-
{
|
|
2853
|
-
className: "ash-display-mode-icon",
|
|
2854
2615
|
viewBox: "0 0 24 24",
|
|
2855
|
-
fill: "none",
|
|
2856
2616
|
stroke: "currentColor",
|
|
2857
|
-
strokeWidth:
|
|
2858
|
-
children: /* @__PURE__ */ jsx(
|
|
2859
|
-
"path",
|
|
2860
|
-
{
|
|
2861
|
-
strokeLinecap: "round",
|
|
2862
|
-
strokeLinejoin: "round",
|
|
2863
|
-
d: "M8.25 6.75h12M8.25 12h12M8.25 17.25h12M3.75 6.75h.007v.008H3.75V6.75zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zM3.75 12h.007v.008H3.75V12zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm-.375 5.25h.007v.008H3.75v-.008zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
|
|
2864
|
-
}
|
|
2865
|
-
)
|
|
2617
|
+
strokeWidth: 2,
|
|
2618
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" })
|
|
2866
2619
|
}
|
|
2867
|
-
);
|
|
2868
|
-
}
|
|
2869
|
-
};
|
|
2870
|
-
const getLabel = (mode) => {
|
|
2871
|
-
return labels[mode] || mode.charAt(0).toUpperCase() + mode.slice(1);
|
|
2872
|
-
};
|
|
2873
|
-
return /* @__PURE__ */ jsxs(
|
|
2874
|
-
"button",
|
|
2875
|
-
{
|
|
2876
|
-
type: "button",
|
|
2877
|
-
onClick: handleClick,
|
|
2878
|
-
className: cn("ash-display-mode-toggle", className),
|
|
2879
|
-
title: `Switch to ${nextMode} mode`,
|
|
2880
|
-
children: [
|
|
2881
|
-
getIcon(currentMode),
|
|
2882
|
-
showLabel && /* @__PURE__ */ jsx("span", { className: "ash-display-mode-label", children: getLabel(currentMode) })
|
|
2883
|
-
]
|
|
2884
|
-
}
|
|
2885
|
-
);
|
|
2886
|
-
}
|
|
2887
|
-
var DEFAULT_WORDS = [
|
|
2888
|
-
"Thinking",
|
|
2889
|
-
"Reasoning",
|
|
2890
|
-
"Pondering",
|
|
2891
|
-
"Analyzing",
|
|
2892
|
-
"Considering",
|
|
2893
|
-
"Processing",
|
|
2894
|
-
"Evaluating"
|
|
2895
|
-
];
|
|
2896
|
-
function TypewriterText({
|
|
2897
|
-
words = DEFAULT_WORDS,
|
|
2898
|
-
typeSpeed = 50,
|
|
2899
|
-
pauseBeforeErase = 800,
|
|
2900
|
-
eraseSpeed = 30,
|
|
2901
|
-
pauseBeforeType = 200,
|
|
2902
|
-
showCursor = true,
|
|
2903
|
-
className,
|
|
2904
|
-
cursorClassName
|
|
2905
|
-
}) {
|
|
2906
|
-
const [displayText, setDisplayText] = useState("");
|
|
2907
|
-
const [wordIndex, setWordIndex] = useState(0);
|
|
2908
|
-
const [isTyping, setIsTyping] = useState(true);
|
|
2909
|
-
const timeoutRef = useRef(null);
|
|
2910
|
-
useEffect(() => {
|
|
2911
|
-
const currentWord = words[wordIndex] ?? "";
|
|
2912
|
-
if (isTyping) {
|
|
2913
|
-
if (displayText.length < currentWord.length) {
|
|
2914
|
-
timeoutRef.current = setTimeout(() => {
|
|
2915
|
-
setDisplayText(currentWord.slice(0, displayText.length + 1));
|
|
2916
|
-
}, typeSpeed);
|
|
2917
|
-
} else {
|
|
2918
|
-
timeoutRef.current = setTimeout(() => {
|
|
2919
|
-
setIsTyping(false);
|
|
2920
|
-
}, pauseBeforeErase);
|
|
2921
|
-
}
|
|
2922
|
-
} else {
|
|
2923
|
-
if (displayText.length > 0) {
|
|
2924
|
-
timeoutRef.current = setTimeout(() => {
|
|
2925
|
-
setDisplayText(displayText.slice(0, -1));
|
|
2926
|
-
}, eraseSpeed);
|
|
2927
|
-
} else {
|
|
2928
|
-
timeoutRef.current = setTimeout(() => {
|
|
2929
|
-
setWordIndex((prev) => (prev + 1) % words.length);
|
|
2930
|
-
setIsTyping(true);
|
|
2931
|
-
}, pauseBeforeType);
|
|
2932
|
-
}
|
|
2933
|
-
}
|
|
2934
|
-
return () => {
|
|
2935
|
-
if (timeoutRef.current) {
|
|
2936
|
-
clearTimeout(timeoutRef.current);
|
|
2937
|
-
}
|
|
2938
|
-
};
|
|
2939
|
-
}, [displayText, wordIndex, isTyping, words, typeSpeed, pauseBeforeErase, eraseSpeed, pauseBeforeType]);
|
|
2940
|
-
return /* @__PURE__ */ jsxs("span", { className: cn("inline-flex items-center", className), children: [
|
|
2941
|
-
/* @__PURE__ */ jsx("span", { children: displayText }),
|
|
2942
|
-
showCursor && /* @__PURE__ */ jsx(
|
|
2943
|
-
"span",
|
|
2944
|
-
{
|
|
2945
|
-
className: cn(
|
|
2946
|
-
"w-0.5 h-4 bg-current ml-0.5 animate-pulse",
|
|
2947
|
-
cursorClassName
|
|
2948
2620
|
)
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
}
|
|
2953
|
-
var ThemeContext = createContext(void 0);
|
|
2954
|
-
var DEFAULT_STORAGE_KEY = "ash-ui-theme";
|
|
2955
|
-
function ThemeProvider({
|
|
2956
|
-
children,
|
|
2957
|
-
defaultTheme,
|
|
2958
|
-
storageKey = DEFAULT_STORAGE_KEY,
|
|
2959
|
-
listenToSystemChanges = true
|
|
2960
|
-
}) {
|
|
2961
|
-
const [theme, setThemeState] = useState(() => {
|
|
2962
|
-
if (typeof window !== "undefined") {
|
|
2963
|
-
const stored = localStorage.getItem(storageKey);
|
|
2964
|
-
if (stored === "dark" || stored === "light") {
|
|
2965
|
-
return stored;
|
|
2966
|
-
}
|
|
2967
|
-
if (!defaultTheme && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
2968
|
-
return "dark";
|
|
2969
|
-
}
|
|
2970
|
-
}
|
|
2971
|
-
return defaultTheme ?? "light";
|
|
2972
|
-
});
|
|
2973
|
-
const [mounted, setMounted] = useState(false);
|
|
2974
|
-
useEffect(() => {
|
|
2975
|
-
setMounted(true);
|
|
2976
|
-
}, []);
|
|
2977
|
-
useEffect(() => {
|
|
2978
|
-
if (!mounted) return;
|
|
2979
|
-
const root = document.documentElement;
|
|
2980
|
-
if (theme === "dark") {
|
|
2981
|
-
root.classList.add("dark");
|
|
2982
|
-
} else {
|
|
2983
|
-
root.classList.remove("dark");
|
|
2984
|
-
}
|
|
2985
|
-
localStorage.setItem(storageKey, theme);
|
|
2986
|
-
}, [theme, mounted, storageKey]);
|
|
2987
|
-
useEffect(() => {
|
|
2988
|
-
if (!listenToSystemChanges || typeof window === "undefined") return;
|
|
2989
|
-
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
2990
|
-
const handleChange = (e) => {
|
|
2991
|
-
const stored = localStorage.getItem(storageKey);
|
|
2992
|
-
if (!stored) {
|
|
2993
|
-
setThemeState(e.matches ? "dark" : "light");
|
|
2994
|
-
}
|
|
2995
|
-
};
|
|
2996
|
-
mediaQuery.addEventListener("change", handleChange);
|
|
2997
|
-
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
2998
|
-
}, [storageKey, listenToSystemChanges]);
|
|
2999
|
-
const toggleTheme = useCallback(() => {
|
|
3000
|
-
setThemeState((prev) => prev === "light" ? "dark" : "light");
|
|
3001
|
-
}, []);
|
|
3002
|
-
const setTheme = useCallback((newTheme) => {
|
|
3003
|
-
setThemeState(newTheme);
|
|
3004
|
-
}, []);
|
|
3005
|
-
if (!mounted) {
|
|
3006
|
-
return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: { theme: defaultTheme ?? "light", toggleTheme, setTheme }, children });
|
|
3007
|
-
}
|
|
3008
|
-
return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
|
|
2621
|
+
]
|
|
2622
|
+
},
|
|
2623
|
+
option.id
|
|
2624
|
+
)) });
|
|
3009
2625
|
}
|
|
3010
|
-
function
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
2626
|
+
function ActionIcon({ actionType, className = "w-4 h-4" }) {
|
|
2627
|
+
switch (actionType.action) {
|
|
2628
|
+
case "command_run":
|
|
2629
|
+
return /* @__PURE__ */ jsx(TerminalIcon, { className });
|
|
2630
|
+
case "file_read":
|
|
2631
|
+
return /* @__PURE__ */ jsx(FileIcon, { className });
|
|
2632
|
+
case "file_edit":
|
|
2633
|
+
return /* @__PURE__ */ jsx(EditIcon, { className });
|
|
2634
|
+
case "file_write":
|
|
2635
|
+
return /* @__PURE__ */ jsx(FilePlusIcon, { className });
|
|
2636
|
+
case "search":
|
|
2637
|
+
return /* @__PURE__ */ jsx(SearchIcon, { className });
|
|
2638
|
+
case "glob":
|
|
2639
|
+
return /* @__PURE__ */ jsx(FolderSearchIcon, { className });
|
|
2640
|
+
case "web_fetch":
|
|
2641
|
+
return /* @__PURE__ */ jsx(GlobeIcon, { className });
|
|
2642
|
+
case "web_search":
|
|
2643
|
+
return /* @__PURE__ */ jsx(SearchIcon, { className });
|
|
2644
|
+
case "mcp_tool":
|
|
2645
|
+
return /* @__PURE__ */ jsx(PlugIcon, { className });
|
|
2646
|
+
case "todo_write":
|
|
2647
|
+
return /* @__PURE__ */ jsx(ListChecksIcon, { className });
|
|
2648
|
+
case "agent_tool":
|
|
2649
|
+
return /* @__PURE__ */ jsx(BotIcon, { className });
|
|
2650
|
+
case "generic_tool":
|
|
2651
|
+
default:
|
|
2652
|
+
return /* @__PURE__ */ jsx(ToolIcon, { className });
|
|
3014
2653
|
}
|
|
3015
|
-
return context;
|
|
3016
2654
|
}
|
|
3017
2655
|
|
|
3018
2656
|
// src/design-tokens.ts
|
|
@@ -3118,6 +2756,21 @@ var typography = {
|
|
|
3118
2756
|
relaxed: "1.75"
|
|
3119
2757
|
}
|
|
3120
2758
|
};
|
|
2759
|
+
var cssVars = {
|
|
2760
|
+
fontSize: {
|
|
2761
|
+
base: "--ash-font-size-base",
|
|
2762
|
+
sm: "--ash-font-size-sm",
|
|
2763
|
+
xs: "--ash-font-size-xs",
|
|
2764
|
+
code: "--ash-font-size-code"
|
|
2765
|
+
},
|
|
2766
|
+
accent: "--ash-accent",
|
|
2767
|
+
accentForeground: "--ash-accent-foreground",
|
|
2768
|
+
surfaceDark: "--ash-surface-dark",
|
|
2769
|
+
surfaceDarker: "--ash-surface-darker",
|
|
2770
|
+
surfaceCard: "--ash-surface-card",
|
|
2771
|
+
surfaceElevated: "--ash-surface-elevated",
|
|
2772
|
+
surfaceBorder: "--ash-surface-border"
|
|
2773
|
+
};
|
|
3121
2774
|
var keyframes = {
|
|
3122
2775
|
slideUp: {
|
|
3123
2776
|
from: { opacity: "0", transform: "translateY(20px)" },
|
|
@@ -3236,42 +2889,332 @@ function tokensToCssVariables(prefix = "ash") {
|
|
|
3236
2889
|
if (key !== "DEFAULT") vars[`--${prefix}-border-${key}`] = value;
|
|
3237
2890
|
else vars[`--${prefix}-border`] = value;
|
|
3238
2891
|
});
|
|
2892
|
+
vars[`--${prefix}-font-size-base`] = "14px";
|
|
2893
|
+
vars[`--${prefix}-font-size-sm`] = "12px";
|
|
2894
|
+
vars[`--${prefix}-font-size-xs`] = "11px";
|
|
2895
|
+
vars[`--${prefix}-font-size-code`] = "13px";
|
|
3239
2896
|
return vars;
|
|
3240
2897
|
}
|
|
3241
|
-
var inlineStyles = {
|
|
3242
|
-
// Glass panel effect
|
|
3243
|
-
glassPanel: {
|
|
3244
|
-
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
|
3245
|
-
backdropFilter: "blur(24px)",
|
|
3246
|
-
WebkitBackdropFilter: "blur(24px)",
|
|
3247
|
-
border: `1px solid ${colors.border.DEFAULT}`
|
|
3248
|
-
},
|
|
3249
|
-
// Accent button
|
|
3250
|
-
accentButton: {
|
|
3251
|
-
backgroundColor: colors.accent.DEFAULT,
|
|
3252
|
-
color: "#000000",
|
|
3253
|
-
border: `1px solid ${colors.accent.DEFAULT}`,
|
|
3254
|
-
boxShadow: shadows.glow.md
|
|
3255
|
-
},
|
|
3256
|
-
// Ghost button
|
|
3257
|
-
ghostButton: {
|
|
3258
|
-
backgroundColor: "transparent",
|
|
3259
|
-
color: colors.text.secondary,
|
|
3260
|
-
border: "1px solid transparent"
|
|
3261
|
-
},
|
|
3262
|
-
// User message bubble
|
|
3263
|
-
userMessage: {
|
|
3264
|
-
backgroundColor: colors.user.bg,
|
|
3265
|
-
border: `1px solid ${colors.user.border}`,
|
|
3266
|
-
borderRadius: borderRadius.lg
|
|
3267
|
-
},
|
|
3268
|
-
// Assistant message bubble
|
|
3269
|
-
assistantMessage: {
|
|
3270
|
-
backgroundColor: colors.assistant.bg,
|
|
3271
|
-
border: `1px solid ${colors.assistant.border}`,
|
|
3272
|
-
borderRadius: borderRadius.lg
|
|
2898
|
+
var inlineStyles = {
|
|
2899
|
+
// Glass panel effect
|
|
2900
|
+
glassPanel: {
|
|
2901
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
|
2902
|
+
backdropFilter: "blur(24px)",
|
|
2903
|
+
WebkitBackdropFilter: "blur(24px)",
|
|
2904
|
+
border: `1px solid ${colors.border.DEFAULT}`
|
|
2905
|
+
},
|
|
2906
|
+
// Accent button
|
|
2907
|
+
accentButton: {
|
|
2908
|
+
backgroundColor: colors.accent.DEFAULT,
|
|
2909
|
+
color: "#000000",
|
|
2910
|
+
border: `1px solid ${colors.accent.DEFAULT}`,
|
|
2911
|
+
boxShadow: shadows.glow.md
|
|
2912
|
+
},
|
|
2913
|
+
// Ghost button
|
|
2914
|
+
ghostButton: {
|
|
2915
|
+
backgroundColor: "transparent",
|
|
2916
|
+
color: colors.text.secondary,
|
|
2917
|
+
border: "1px solid transparent"
|
|
2918
|
+
},
|
|
2919
|
+
// User message bubble
|
|
2920
|
+
userMessage: {
|
|
2921
|
+
backgroundColor: colors.user.bg,
|
|
2922
|
+
border: `1px solid ${colors.user.border}`,
|
|
2923
|
+
borderRadius: borderRadius.lg
|
|
2924
|
+
},
|
|
2925
|
+
// Assistant message bubble
|
|
2926
|
+
assistantMessage: {
|
|
2927
|
+
backgroundColor: colors.assistant.bg,
|
|
2928
|
+
border: `1px solid ${colors.assistant.border}`,
|
|
2929
|
+
borderRadius: borderRadius.lg
|
|
2930
|
+
}
|
|
2931
|
+
};
|
|
2932
|
+
|
|
2933
|
+
// src/types.ts
|
|
2934
|
+
function isCommandRunAction(action) {
|
|
2935
|
+
return action.action === "command_run";
|
|
2936
|
+
}
|
|
2937
|
+
function isFileReadAction(action) {
|
|
2938
|
+
return action.action === "file_read";
|
|
2939
|
+
}
|
|
2940
|
+
function isFileEditAction(action) {
|
|
2941
|
+
return action.action === "file_edit";
|
|
2942
|
+
}
|
|
2943
|
+
function isFileWriteAction(action) {
|
|
2944
|
+
return action.action === "file_write";
|
|
2945
|
+
}
|
|
2946
|
+
function isSearchAction(action) {
|
|
2947
|
+
return action.action === "search";
|
|
2948
|
+
}
|
|
2949
|
+
function isGlobAction(action) {
|
|
2950
|
+
return action.action === "glob";
|
|
2951
|
+
}
|
|
2952
|
+
function isWebFetchAction(action) {
|
|
2953
|
+
return action.action === "web_fetch";
|
|
2954
|
+
}
|
|
2955
|
+
function isWebSearchAction(action) {
|
|
2956
|
+
return action.action === "web_search";
|
|
2957
|
+
}
|
|
2958
|
+
function isMcpToolAction(action) {
|
|
2959
|
+
return action.action === "mcp_tool";
|
|
2960
|
+
}
|
|
2961
|
+
function isGenericToolAction(action) {
|
|
2962
|
+
return action.action === "generic_tool";
|
|
2963
|
+
}
|
|
2964
|
+
function isTodoWriteAction(action) {
|
|
2965
|
+
return action.action === "todo_write";
|
|
2966
|
+
}
|
|
2967
|
+
function isAgentToolAction(action) {
|
|
2968
|
+
return action.action === "agent_tool";
|
|
2969
|
+
}
|
|
2970
|
+
function isToolCallEntry(entry) {
|
|
2971
|
+
return entry.type === "tool_call";
|
|
2972
|
+
}
|
|
2973
|
+
function isErrorEntry(entry) {
|
|
2974
|
+
return entry.type === "error";
|
|
2975
|
+
}
|
|
2976
|
+
function isWidgetEntry(entry) {
|
|
2977
|
+
return entry.type === "widget";
|
|
2978
|
+
}
|
|
2979
|
+
var DEFAULT_STYLE_CONFIG = {
|
|
2980
|
+
userVariant: "bubble",
|
|
2981
|
+
assistantVariant: "bubble",
|
|
2982
|
+
scale: "compact",
|
|
2983
|
+
showTimestamp: true,
|
|
2984
|
+
showAvatars: true
|
|
2985
|
+
};
|
|
2986
|
+
function normalizedEntryToMessage(entry) {
|
|
2987
|
+
const { id, entryType, content, timestamp } = entry;
|
|
2988
|
+
const createdAt = timestamp ? new Date(timestamp) : void 0;
|
|
2989
|
+
switch (entryType.type) {
|
|
2990
|
+
case "user_message":
|
|
2991
|
+
return {
|
|
2992
|
+
id,
|
|
2993
|
+
role: "user",
|
|
2994
|
+
content,
|
|
2995
|
+
createdAt
|
|
2996
|
+
};
|
|
2997
|
+
case "assistant_message":
|
|
2998
|
+
return {
|
|
2999
|
+
id,
|
|
3000
|
+
role: "assistant",
|
|
3001
|
+
content,
|
|
3002
|
+
createdAt
|
|
3003
|
+
};
|
|
3004
|
+
case "thinking":
|
|
3005
|
+
return {
|
|
3006
|
+
id,
|
|
3007
|
+
role: "assistant",
|
|
3008
|
+
content: "",
|
|
3009
|
+
reasoning: content,
|
|
3010
|
+
createdAt
|
|
3011
|
+
};
|
|
3012
|
+
case "tool_call": {
|
|
3013
|
+
const { toolCall } = entryType;
|
|
3014
|
+
const toolInvocation = {
|
|
3015
|
+
state: toolCall.status === "pending" ? "call" : "result",
|
|
3016
|
+
toolCallId: toolCall.id,
|
|
3017
|
+
toolName: toolCall.toolName,
|
|
3018
|
+
args: toolCall.input || {},
|
|
3019
|
+
result: toolCall.output
|
|
3020
|
+
};
|
|
3021
|
+
return {
|
|
3022
|
+
id,
|
|
3023
|
+
role: "assistant",
|
|
3024
|
+
content: "",
|
|
3025
|
+
toolInvocations: [toolInvocation],
|
|
3026
|
+
createdAt
|
|
3027
|
+
};
|
|
3028
|
+
}
|
|
3029
|
+
case "error":
|
|
3030
|
+
return {
|
|
3031
|
+
id,
|
|
3032
|
+
role: "system",
|
|
3033
|
+
content: `Error: ${entryType.message}${entryType.code ? ` (${entryType.code})` : ""}`,
|
|
3034
|
+
createdAt
|
|
3035
|
+
};
|
|
3036
|
+
case "widget":
|
|
3037
|
+
return {
|
|
3038
|
+
id,
|
|
3039
|
+
role: "data",
|
|
3040
|
+
content: JSON.stringify({
|
|
3041
|
+
widgetType: entryType.widgetType,
|
|
3042
|
+
widgetData: entryType.widgetData
|
|
3043
|
+
}),
|
|
3044
|
+
createdAt
|
|
3045
|
+
};
|
|
3046
|
+
default:
|
|
3047
|
+
return null;
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
function messageToNormalizedEntry(message) {
|
|
3051
|
+
const { id, role, content, createdAt, toolInvocations, reasoning } = message;
|
|
3052
|
+
const timestamp = createdAt?.toISOString();
|
|
3053
|
+
if (toolInvocations && toolInvocations.length > 0) {
|
|
3054
|
+
const inv = toolInvocations[0];
|
|
3055
|
+
const toolCall = {
|
|
3056
|
+
id: inv.toolCallId,
|
|
3057
|
+
toolName: inv.toolName,
|
|
3058
|
+
actionType: {
|
|
3059
|
+
action: "generic_tool",
|
|
3060
|
+
toolName: inv.toolName,
|
|
3061
|
+
arguments: inv.args,
|
|
3062
|
+
result: inv.result ? { type: "json", value: inv.result } : void 0
|
|
3063
|
+
},
|
|
3064
|
+
status: inv.state === "result" ? "success" : "pending",
|
|
3065
|
+
summary: `${inv.toolName}(${Object.keys(inv.args).join(", ")})`,
|
|
3066
|
+
input: inv.args,
|
|
3067
|
+
output: inv.result
|
|
3068
|
+
};
|
|
3069
|
+
return {
|
|
3070
|
+
id,
|
|
3071
|
+
timestamp,
|
|
3072
|
+
entryType: { type: "tool_call", toolCall },
|
|
3073
|
+
content: toolCall.summary
|
|
3074
|
+
};
|
|
3075
|
+
}
|
|
3076
|
+
if (reasoning) {
|
|
3077
|
+
return {
|
|
3078
|
+
id,
|
|
3079
|
+
timestamp,
|
|
3080
|
+
entryType: { type: "thinking" },
|
|
3081
|
+
content: reasoning
|
|
3082
|
+
};
|
|
3083
|
+
}
|
|
3084
|
+
if (role === "user") {
|
|
3085
|
+
return {
|
|
3086
|
+
id,
|
|
3087
|
+
timestamp,
|
|
3088
|
+
entryType: { type: "user_message" },
|
|
3089
|
+
content
|
|
3090
|
+
};
|
|
3091
|
+
}
|
|
3092
|
+
if (role === "assistant") {
|
|
3093
|
+
return {
|
|
3094
|
+
id,
|
|
3095
|
+
timestamp,
|
|
3096
|
+
entryType: { type: "assistant_message" },
|
|
3097
|
+
content
|
|
3098
|
+
};
|
|
3099
|
+
}
|
|
3100
|
+
if (role === "system") {
|
|
3101
|
+
if (content.startsWith("Error:")) {
|
|
3102
|
+
return {
|
|
3103
|
+
id,
|
|
3104
|
+
timestamp,
|
|
3105
|
+
entryType: { type: "error", message: content.replace("Error: ", "") },
|
|
3106
|
+
content
|
|
3107
|
+
};
|
|
3108
|
+
}
|
|
3109
|
+
return {
|
|
3110
|
+
id,
|
|
3111
|
+
timestamp,
|
|
3112
|
+
entryType: { type: "assistant_message" },
|
|
3113
|
+
content
|
|
3114
|
+
};
|
|
3115
|
+
}
|
|
3116
|
+
if (role === "data") {
|
|
3117
|
+
try {
|
|
3118
|
+
const data = JSON.parse(content);
|
|
3119
|
+
if (data.widgetType) {
|
|
3120
|
+
return {
|
|
3121
|
+
id,
|
|
3122
|
+
timestamp,
|
|
3123
|
+
entryType: {
|
|
3124
|
+
type: "widget",
|
|
3125
|
+
widgetType: data.widgetType,
|
|
3126
|
+
widgetData: data.widgetData
|
|
3127
|
+
},
|
|
3128
|
+
content: ""
|
|
3129
|
+
};
|
|
3130
|
+
}
|
|
3131
|
+
} catch {
|
|
3132
|
+
}
|
|
3133
|
+
return {
|
|
3134
|
+
id,
|
|
3135
|
+
timestamp,
|
|
3136
|
+
entryType: { type: "assistant_message" },
|
|
3137
|
+
content
|
|
3138
|
+
};
|
|
3139
|
+
}
|
|
3140
|
+
return {
|
|
3141
|
+
id,
|
|
3142
|
+
timestamp,
|
|
3143
|
+
entryType: { type: "assistant_message" },
|
|
3144
|
+
content
|
|
3145
|
+
};
|
|
3146
|
+
}
|
|
3147
|
+
function normalizedEntriesToMessages(entries) {
|
|
3148
|
+
const messages = [];
|
|
3149
|
+
let currentAssistantMessage = null;
|
|
3150
|
+
for (const entry of entries) {
|
|
3151
|
+
const message = normalizedEntryToMessage(entry);
|
|
3152
|
+
if (!message) continue;
|
|
3153
|
+
if (message.role === "assistant") {
|
|
3154
|
+
if (currentAssistantMessage) {
|
|
3155
|
+
if (message.toolInvocations) {
|
|
3156
|
+
currentAssistantMessage.toolInvocations = [
|
|
3157
|
+
...currentAssistantMessage.toolInvocations || [],
|
|
3158
|
+
...message.toolInvocations
|
|
3159
|
+
];
|
|
3160
|
+
}
|
|
3161
|
+
if (message.content) {
|
|
3162
|
+
currentAssistantMessage.content = currentAssistantMessage.content ? `${currentAssistantMessage.content}
|
|
3163
|
+
${message.content}` : message.content;
|
|
3164
|
+
}
|
|
3165
|
+
if (message.reasoning) {
|
|
3166
|
+
currentAssistantMessage.reasoning = currentAssistantMessage.reasoning ? `${currentAssistantMessage.reasoning}
|
|
3167
|
+
${message.reasoning}` : message.reasoning;
|
|
3168
|
+
}
|
|
3169
|
+
} else {
|
|
3170
|
+
currentAssistantMessage = { ...message };
|
|
3171
|
+
}
|
|
3172
|
+
} else {
|
|
3173
|
+
if (currentAssistantMessage) {
|
|
3174
|
+
messages.push(currentAssistantMessage);
|
|
3175
|
+
currentAssistantMessage = null;
|
|
3176
|
+
}
|
|
3177
|
+
messages.push(message);
|
|
3178
|
+
}
|
|
3273
3179
|
}
|
|
3274
|
-
|
|
3180
|
+
if (currentAssistantMessage) {
|
|
3181
|
+
messages.push(currentAssistantMessage);
|
|
3182
|
+
}
|
|
3183
|
+
return messages;
|
|
3184
|
+
}
|
|
3185
|
+
function messagesToNormalizedEntries(messages) {
|
|
3186
|
+
const entries = [];
|
|
3187
|
+
for (const message of messages) {
|
|
3188
|
+
if (message.reasoning) {
|
|
3189
|
+
entries.push({
|
|
3190
|
+
id: `${message.id}-thinking`,
|
|
3191
|
+
timestamp: message.createdAt?.toISOString(),
|
|
3192
|
+
entryType: { type: "thinking" },
|
|
3193
|
+
content: message.reasoning
|
|
3194
|
+
});
|
|
3195
|
+
}
|
|
3196
|
+
if (message.content || !message.toolInvocations?.length) {
|
|
3197
|
+
entries.push(messageToNormalizedEntry({
|
|
3198
|
+
...message,
|
|
3199
|
+
toolInvocations: void 0,
|
|
3200
|
+
reasoning: void 0
|
|
3201
|
+
}));
|
|
3202
|
+
}
|
|
3203
|
+
if (message.toolInvocations) {
|
|
3204
|
+
for (const inv of message.toolInvocations) {
|
|
3205
|
+
const toolMessage = {
|
|
3206
|
+
id: inv.toolCallId,
|
|
3207
|
+
role: "assistant",
|
|
3208
|
+
content: "",
|
|
3209
|
+
toolInvocations: [inv],
|
|
3210
|
+
createdAt: message.createdAt
|
|
3211
|
+
};
|
|
3212
|
+
entries.push(messageToNormalizedEntry(toolMessage));
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
return entries;
|
|
3217
|
+
}
|
|
3275
3218
|
function useMessageQueue({
|
|
3276
3219
|
onProcessMessage,
|
|
3277
3220
|
canProcess = true
|
|
@@ -3491,19 +3434,95 @@ function useFileUpload({
|
|
|
3491
3434
|
openFilePicker
|
|
3492
3435
|
};
|
|
3493
3436
|
}
|
|
3437
|
+
|
|
3438
|
+
// src/hooks/middleware.ts
|
|
3439
|
+
async function applyRequestMiddleware(middlewares, request) {
|
|
3440
|
+
let current = { ...request };
|
|
3441
|
+
for (const mw of middlewares) {
|
|
3442
|
+
if (mw.onRequest) {
|
|
3443
|
+
try {
|
|
3444
|
+
const result = await mw.onRequest(current);
|
|
3445
|
+
if (result?.error) {
|
|
3446
|
+
return { request: current, error: result.error };
|
|
3447
|
+
}
|
|
3448
|
+
if (result) {
|
|
3449
|
+
current = {
|
|
3450
|
+
...current,
|
|
3451
|
+
prompt: result.prompt ?? current.prompt,
|
|
3452
|
+
sessionContext: result.sessionContext ?? current.sessionContext,
|
|
3453
|
+
metadata: {
|
|
3454
|
+
...current.metadata,
|
|
3455
|
+
...result.metadata
|
|
3456
|
+
}
|
|
3457
|
+
};
|
|
3458
|
+
}
|
|
3459
|
+
} catch (err) {
|
|
3460
|
+
const errorMessage = err instanceof Error ? err.message : "Middleware error";
|
|
3461
|
+
return { request: current, error: errorMessage };
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
}
|
|
3465
|
+
return { request: current };
|
|
3466
|
+
}
|
|
3467
|
+
async function applyEventMiddleware(middlewares, event) {
|
|
3468
|
+
let current = event;
|
|
3469
|
+
for (const mw of middlewares) {
|
|
3470
|
+
if (!current) break;
|
|
3471
|
+
if (mw.onEvent) {
|
|
3472
|
+
try {
|
|
3473
|
+
current = await mw.onEvent(current);
|
|
3474
|
+
} catch (err) {
|
|
3475
|
+
console.error("[middleware] onEvent error:", err);
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
return current;
|
|
3480
|
+
}
|
|
3481
|
+
async function callMiddlewareComplete(middlewares, sessionId) {
|
|
3482
|
+
for (const mw of middlewares) {
|
|
3483
|
+
if (mw.onComplete) {
|
|
3484
|
+
try {
|
|
3485
|
+
await mw.onComplete(sessionId);
|
|
3486
|
+
} catch (err) {
|
|
3487
|
+
console.error("[middleware] onComplete error:", err);
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
async function callMiddlewareError(middlewares, error) {
|
|
3493
|
+
for (const mw of middlewares) {
|
|
3494
|
+
if (mw.onError) {
|
|
3495
|
+
try {
|
|
3496
|
+
await mw.onError(error);
|
|
3497
|
+
} catch (err) {
|
|
3498
|
+
console.error("[middleware] onError error:", err);
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
}
|
|
3503
|
+
|
|
3504
|
+
// src/hooks/useAgentChat.ts
|
|
3494
3505
|
function useAgentChat(options) {
|
|
3495
3506
|
const {
|
|
3496
3507
|
createStream,
|
|
3508
|
+
subscribeToSession,
|
|
3497
3509
|
initialSessionId,
|
|
3498
3510
|
initialEntries = [],
|
|
3499
3511
|
onSessionStart,
|
|
3500
3512
|
onSessionEnd,
|
|
3501
3513
|
onError,
|
|
3502
|
-
onSandboxLog
|
|
3514
|
+
onSandboxLog,
|
|
3515
|
+
onReconnect,
|
|
3516
|
+
maxReconnectAttempts = 3,
|
|
3517
|
+
reconnectBaseDelay = 1e3,
|
|
3518
|
+
onBeforeSend,
|
|
3519
|
+
onEvent,
|
|
3520
|
+
middleware
|
|
3503
3521
|
} = options;
|
|
3504
3522
|
const [historyEntries, setHistoryEntries] = useState(initialEntries);
|
|
3505
3523
|
const [streamingEntries, setStreamingEntries] = useState([]);
|
|
3506
3524
|
const [isStreaming, setIsStreaming] = useState(false);
|
|
3525
|
+
const [isReconnecting, setIsReconnecting] = useState(false);
|
|
3507
3526
|
const [error, setError] = useState(null);
|
|
3508
3527
|
const [sessionId, setSessionId] = useState(initialSessionId || null);
|
|
3509
3528
|
const abortControllerRef = useRef(null);
|
|
@@ -3511,6 +3530,16 @@ function useAgentChat(options) {
|
|
|
3511
3530
|
const currentTextIdRef = useRef(null);
|
|
3512
3531
|
const pendingToolCallsRef = useRef(/* @__PURE__ */ new Map());
|
|
3513
3532
|
const hadToolCallSinceTextRef = useRef(false);
|
|
3533
|
+
const reconnectAttemptsRef = useRef(0);
|
|
3534
|
+
const eventCountRef = useRef(0);
|
|
3535
|
+
const sessionIdRef = useRef(sessionId);
|
|
3536
|
+
const streamingEntriesRef = useRef([]);
|
|
3537
|
+
useEffect(() => {
|
|
3538
|
+
sessionIdRef.current = sessionId;
|
|
3539
|
+
}, [sessionId]);
|
|
3540
|
+
useEffect(() => {
|
|
3541
|
+
streamingEntriesRef.current = streamingEntries;
|
|
3542
|
+
}, [streamingEntries]);
|
|
3514
3543
|
const entries = [...historyEntries, ...streamingEntries];
|
|
3515
3544
|
const emitStreamingEntries = useCallback((newEntries) => {
|
|
3516
3545
|
setStreamingEntries([...newEntries]);
|
|
@@ -3625,7 +3654,7 @@ function useAgentChat(options) {
|
|
|
3625
3654
|
setError(event.error);
|
|
3626
3655
|
onError?.(event.error);
|
|
3627
3656
|
newEntries.push({
|
|
3628
|
-
id: `error-${Date.now()}`,
|
|
3657
|
+
id: `error-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
3629
3658
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3630
3659
|
entryType: { type: "error", message: event.error, code: event.code },
|
|
3631
3660
|
content: event.error
|
|
@@ -3644,12 +3673,112 @@ function useAgentChat(options) {
|
|
|
3644
3673
|
}
|
|
3645
3674
|
return newEntries;
|
|
3646
3675
|
}, [sessionId, onSessionStart, onSessionEnd, onError, onSandboxLog, createTextEntry, resetStreamingState]);
|
|
3676
|
+
const attemptReconnect = useCallback(async (targetSessionId, currentEntries) => {
|
|
3677
|
+
if (!subscribeToSession) {
|
|
3678
|
+
return false;
|
|
3679
|
+
}
|
|
3680
|
+
const attempt = reconnectAttemptsRef.current + 1;
|
|
3681
|
+
if (attempt > maxReconnectAttempts) {
|
|
3682
|
+
console.warn(`[useAgentChat] Max reconnection attempts (${maxReconnectAttempts}) exceeded`);
|
|
3683
|
+
return false;
|
|
3684
|
+
}
|
|
3685
|
+
reconnectAttemptsRef.current = attempt;
|
|
3686
|
+
setIsReconnecting(true);
|
|
3687
|
+
onReconnect?.(attempt, targetSessionId);
|
|
3688
|
+
const delay = reconnectBaseDelay * Math.pow(2, attempt - 1);
|
|
3689
|
+
console.log(`[useAgentChat] Reconnection attempt ${attempt}/${maxReconnectAttempts} in ${delay}ms`);
|
|
3690
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
3691
|
+
const controller = new AbortController();
|
|
3692
|
+
abortControllerRef.current = controller;
|
|
3693
|
+
try {
|
|
3694
|
+
const stream = subscribeToSession(targetSessionId, controller.signal);
|
|
3695
|
+
let localStreamingEntries = [...currentEntries];
|
|
3696
|
+
for await (const event of stream) {
|
|
3697
|
+
if (controller.signal.aborted) break;
|
|
3698
|
+
eventCountRef.current++;
|
|
3699
|
+
localStreamingEntries = processEvent(event, localStreamingEntries);
|
|
3700
|
+
emitStreamingEntries(localStreamingEntries);
|
|
3701
|
+
if (event.type === "complete" || event.type === "session_end" || event.type === "error") {
|
|
3702
|
+
reconnectAttemptsRef.current = 0;
|
|
3703
|
+
setIsReconnecting(false);
|
|
3704
|
+
if (event.type === "complete" && localStreamingEntries.length > 0) {
|
|
3705
|
+
setHistoryEntries((prev) => [...prev, ...localStreamingEntries]);
|
|
3706
|
+
setStreamingEntries([]);
|
|
3707
|
+
}
|
|
3708
|
+
return true;
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
reconnectAttemptsRef.current = 0;
|
|
3712
|
+
setIsReconnecting(false);
|
|
3713
|
+
if (localStreamingEntries.length > 0) {
|
|
3714
|
+
setHistoryEntries((prev) => [...prev, ...localStreamingEntries]);
|
|
3715
|
+
setStreamingEntries([]);
|
|
3716
|
+
}
|
|
3717
|
+
return true;
|
|
3718
|
+
} catch (err) {
|
|
3719
|
+
const isAbort = err.name === "AbortError" || err.message?.includes("aborted") || err.message?.includes("BodyStreamBuffer");
|
|
3720
|
+
if (isAbort && !controller.signal.aborted) {
|
|
3721
|
+
console.log(`[useAgentChat] Reconnection stream interrupted, will retry...`);
|
|
3722
|
+
setIsReconnecting(false);
|
|
3723
|
+
return attemptReconnect(targetSessionId, streamingEntriesRef.current);
|
|
3724
|
+
}
|
|
3725
|
+
setIsReconnecting(false);
|
|
3726
|
+
if (!controller.signal.aborted) {
|
|
3727
|
+
const errorMessage = err instanceof Error ? err.message : "Reconnection failed";
|
|
3728
|
+
console.error(`[useAgentChat] Reconnection failed:`, errorMessage);
|
|
3729
|
+
}
|
|
3730
|
+
return false;
|
|
3731
|
+
}
|
|
3732
|
+
}, [subscribeToSession, maxReconnectAttempts, reconnectBaseDelay, onReconnect, processEvent, emitStreamingEntries]);
|
|
3647
3733
|
const send = useCallback(async (prompt) => {
|
|
3648
3734
|
if (isStreaming) return;
|
|
3735
|
+
let finalPrompt = prompt;
|
|
3736
|
+
let additionalMetadata = {};
|
|
3737
|
+
let additionalContext;
|
|
3738
|
+
if (onBeforeSend) {
|
|
3739
|
+
try {
|
|
3740
|
+
const result = await onBeforeSend({
|
|
3741
|
+
prompt,
|
|
3742
|
+
sessionId,
|
|
3743
|
+
entries: [...historyEntries, ...streamingEntries]
|
|
3744
|
+
});
|
|
3745
|
+
if (result?.cancel) {
|
|
3746
|
+
return;
|
|
3747
|
+
}
|
|
3748
|
+
if (result?.prompt !== void 0) finalPrompt = result.prompt;
|
|
3749
|
+
if (result?.metadata) additionalMetadata = result.metadata;
|
|
3750
|
+
if (result?.sessionContext) additionalContext = result.sessionContext;
|
|
3751
|
+
} catch (err) {
|
|
3752
|
+
const errorMessage = err instanceof Error ? err.message : "Send cancelled";
|
|
3753
|
+
setError(errorMessage);
|
|
3754
|
+
onError?.(errorMessage);
|
|
3755
|
+
return;
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
if (middleware?.length) {
|
|
3759
|
+
const middlewareRequest = {
|
|
3760
|
+
prompt: finalPrompt,
|
|
3761
|
+
sessionId,
|
|
3762
|
+
metadata: additionalMetadata,
|
|
3763
|
+
sessionContext: additionalContext
|
|
3764
|
+
};
|
|
3765
|
+
const { request, error: middlewareError } = await applyRequestMiddleware(middleware, middlewareRequest);
|
|
3766
|
+
if (middlewareError) {
|
|
3767
|
+
setError(middlewareError);
|
|
3768
|
+
onError?.(middlewareError);
|
|
3769
|
+
await callMiddlewareError(middleware, middlewareError);
|
|
3770
|
+
return;
|
|
3771
|
+
}
|
|
3772
|
+
finalPrompt = request.prompt;
|
|
3773
|
+
additionalMetadata = request.metadata || {};
|
|
3774
|
+
additionalContext = request.sessionContext;
|
|
3775
|
+
}
|
|
3649
3776
|
setIsStreaming(true);
|
|
3650
3777
|
setError(null);
|
|
3778
|
+
reconnectAttemptsRef.current = 0;
|
|
3779
|
+
eventCountRef.current = 0;
|
|
3651
3780
|
const userEntry = {
|
|
3652
|
-
id: `user-${Date.now()}`,
|
|
3781
|
+
id: `user-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
3653
3782
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3654
3783
|
entryType: { type: "user_message" },
|
|
3655
3784
|
content: prompt
|
|
@@ -3659,39 +3788,91 @@ function useAgentChat(options) {
|
|
|
3659
3788
|
const controller = new AbortController();
|
|
3660
3789
|
abortControllerRef.current = controller;
|
|
3661
3790
|
let localStreamingEntries = [];
|
|
3791
|
+
let completedSessionId = null;
|
|
3662
3792
|
try {
|
|
3663
|
-
const stream = createStream(
|
|
3793
|
+
const stream = createStream(finalPrompt, sessionId || void 0, {
|
|
3794
|
+
signal: controller.signal,
|
|
3795
|
+
metadata: Object.keys(additionalMetadata).length > 0 ? additionalMetadata : void 0,
|
|
3796
|
+
sessionContext: additionalContext
|
|
3797
|
+
});
|
|
3664
3798
|
for await (const event of stream) {
|
|
3665
3799
|
if (controller.signal.aborted) break;
|
|
3666
|
-
|
|
3800
|
+
eventCountRef.current++;
|
|
3801
|
+
if (event.type === "session_start" && event.sessionId) {
|
|
3802
|
+
completedSessionId = event.sessionId;
|
|
3803
|
+
}
|
|
3804
|
+
if (onEvent) {
|
|
3805
|
+
try {
|
|
3806
|
+
await onEvent(event);
|
|
3807
|
+
} catch (err) {
|
|
3808
|
+
console.error("[useAgentChat] onEvent error:", err);
|
|
3809
|
+
}
|
|
3810
|
+
}
|
|
3811
|
+
let processedEvent = event;
|
|
3812
|
+
if (middleware?.length) {
|
|
3813
|
+
processedEvent = await applyEventMiddleware(middleware, event);
|
|
3814
|
+
}
|
|
3815
|
+
if (!processedEvent) continue;
|
|
3816
|
+
localStreamingEntries = processEvent(processedEvent, localStreamingEntries);
|
|
3667
3817
|
emitStreamingEntries(localStreamingEntries);
|
|
3668
3818
|
}
|
|
3669
3819
|
if (localStreamingEntries.length > 0) {
|
|
3670
3820
|
setHistoryEntries((prev) => [...prev, ...localStreamingEntries]);
|
|
3671
3821
|
setStreamingEntries([]);
|
|
3672
3822
|
}
|
|
3823
|
+
reconnectAttemptsRef.current = 0;
|
|
3824
|
+
if (middleware?.length && (completedSessionId || sessionIdRef.current)) {
|
|
3825
|
+
await callMiddlewareComplete(middleware, completedSessionId || sessionIdRef.current || "");
|
|
3826
|
+
}
|
|
3673
3827
|
} catch (err) {
|
|
3674
|
-
|
|
3828
|
+
const isAbort = err.name === "AbortError" || err.message?.includes("aborted") || err.message?.includes("BodyStreamBuffer");
|
|
3829
|
+
if (isAbort && !controller.signal.aborted) {
|
|
3830
|
+
const currentSessionId = sessionIdRef.current;
|
|
3831
|
+
const hadEvents = eventCountRef.current > 0;
|
|
3832
|
+
console.log(`[useAgentChat] Stream interrupted. sessionId=${currentSessionId}, events=${eventCountRef.current}`);
|
|
3833
|
+
if (currentSessionId && hadEvents && subscribeToSession) {
|
|
3834
|
+
console.log(`[useAgentChat] Attempting auto-reconnection...`);
|
|
3835
|
+
const reconnected = await attemptReconnect(currentSessionId, streamingEntriesRef.current);
|
|
3836
|
+
if (reconnected) {
|
|
3837
|
+
return;
|
|
3838
|
+
}
|
|
3839
|
+
const errorMsg = "Connection lost. Please try again.";
|
|
3840
|
+
setError(errorMsg);
|
|
3841
|
+
onError?.(errorMsg);
|
|
3842
|
+
if (middleware?.length) {
|
|
3843
|
+
await callMiddlewareError(middleware, errorMsg);
|
|
3844
|
+
}
|
|
3845
|
+
}
|
|
3846
|
+
} else if (!isAbort) {
|
|
3675
3847
|
const errorMessage = err instanceof Error ? err.message : "Unknown error";
|
|
3676
3848
|
setError(errorMessage);
|
|
3677
3849
|
onError?.(errorMessage);
|
|
3850
|
+
if (middleware?.length) {
|
|
3851
|
+
await callMiddlewareError(middleware, errorMessage);
|
|
3852
|
+
}
|
|
3678
3853
|
}
|
|
3679
3854
|
} finally {
|
|
3680
3855
|
setIsStreaming(false);
|
|
3856
|
+
setIsReconnecting(false);
|
|
3681
3857
|
abortControllerRef.current = null;
|
|
3682
3858
|
resetStreamingState();
|
|
3683
3859
|
}
|
|
3684
|
-
}, [isStreaming, sessionId, createStream, processEvent, emitStreamingEntries, resetStreamingState, onError]);
|
|
3860
|
+
}, [isStreaming, sessionId, historyEntries, streamingEntries, createStream, subscribeToSession, processEvent, emitStreamingEntries, resetStreamingState, onError, attemptReconnect, onBeforeSend, onEvent, middleware]);
|
|
3685
3861
|
const stop = useCallback(() => {
|
|
3862
|
+
reconnectAttemptsRef.current = maxReconnectAttempts + 1;
|
|
3863
|
+
setIsReconnecting(false);
|
|
3686
3864
|
if (abortControllerRef.current) {
|
|
3687
3865
|
abortControllerRef.current.abort();
|
|
3688
3866
|
}
|
|
3689
|
-
}, []);
|
|
3867
|
+
}, [maxReconnectAttempts]);
|
|
3690
3868
|
const clear = useCallback(() => {
|
|
3691
3869
|
setHistoryEntries([]);
|
|
3692
3870
|
resetStreamingState();
|
|
3693
3871
|
setSessionId(initialSessionId || null);
|
|
3694
3872
|
setError(null);
|
|
3873
|
+
setIsReconnecting(false);
|
|
3874
|
+
reconnectAttemptsRef.current = 0;
|
|
3875
|
+
eventCountRef.current = 0;
|
|
3695
3876
|
}, [initialSessionId, resetStreamingState]);
|
|
3696
3877
|
const setEntries = useCallback((newEntries) => {
|
|
3697
3878
|
resetStreamingState();
|
|
@@ -3707,6 +3888,7 @@ function useAgentChat(options) {
|
|
|
3707
3888
|
return {
|
|
3708
3889
|
entries,
|
|
3709
3890
|
isStreaming,
|
|
3891
|
+
isReconnecting,
|
|
3710
3892
|
error,
|
|
3711
3893
|
sessionId,
|
|
3712
3894
|
send,
|
|
@@ -3715,6 +3897,254 @@ function useAgentChat(options) {
|
|
|
3715
3897
|
setEntries
|
|
3716
3898
|
};
|
|
3717
3899
|
}
|
|
3900
|
+
function generateId() {
|
|
3901
|
+
return `msg-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
3902
|
+
}
|
|
3903
|
+
function useChat(options) {
|
|
3904
|
+
const {
|
|
3905
|
+
createStream,
|
|
3906
|
+
// subscribeToSession, // TODO: implement reconnection support
|
|
3907
|
+
initialSessionId,
|
|
3908
|
+
initialMessages = [],
|
|
3909
|
+
onToolCall,
|
|
3910
|
+
onFinish,
|
|
3911
|
+
onError,
|
|
3912
|
+
onSessionStart,
|
|
3913
|
+
maxReconnectAttempts = 3,
|
|
3914
|
+
// reconnectBaseDelay = 1000, // TODO: implement reconnection support
|
|
3915
|
+
middleware
|
|
3916
|
+
} = options;
|
|
3917
|
+
const [messages, setMessages] = useState(initialMessages);
|
|
3918
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
3919
|
+
const [isReconnecting, setIsReconnecting] = useState(false);
|
|
3920
|
+
const [error, setError] = useState(void 0);
|
|
3921
|
+
const [sessionId, setSessionId] = useState(initialSessionId || null);
|
|
3922
|
+
const [input, setInput] = useState("");
|
|
3923
|
+
const abortControllerRef = useRef(null);
|
|
3924
|
+
const currentAssistantMessageRef = useRef(null);
|
|
3925
|
+
const reconnectAttemptsRef = useRef(0);
|
|
3926
|
+
const sessionIdRef = useRef(sessionId);
|
|
3927
|
+
useEffect(() => {
|
|
3928
|
+
sessionIdRef.current = sessionId;
|
|
3929
|
+
}, [sessionId]);
|
|
3930
|
+
const entries = messagesToNormalizedEntries(messages);
|
|
3931
|
+
const updateStreamingMessage = useCallback((updater) => {
|
|
3932
|
+
if (!currentAssistantMessageRef.current) return;
|
|
3933
|
+
currentAssistantMessageRef.current = updater(currentAssistantMessageRef.current);
|
|
3934
|
+
const currentMsg = currentAssistantMessageRef.current;
|
|
3935
|
+
setMessages((prev) => {
|
|
3936
|
+
const lastIndex = prev.length - 1;
|
|
3937
|
+
const lastMessage = prev[lastIndex];
|
|
3938
|
+
if (lastIndex >= 0 && lastMessage && currentMsg && lastMessage.id === currentMsg.id) {
|
|
3939
|
+
return [...prev.slice(0, lastIndex), currentMsg];
|
|
3940
|
+
}
|
|
3941
|
+
return prev;
|
|
3942
|
+
});
|
|
3943
|
+
}, []);
|
|
3944
|
+
const processEvent = useCallback((event) => {
|
|
3945
|
+
switch (event.type) {
|
|
3946
|
+
case "session_start":
|
|
3947
|
+
if (event.sessionId) {
|
|
3948
|
+
setSessionId(event.sessionId);
|
|
3949
|
+
onSessionStart?.(event.sessionId);
|
|
3950
|
+
}
|
|
3951
|
+
break;
|
|
3952
|
+
case "text_delta":
|
|
3953
|
+
if (event.delta) {
|
|
3954
|
+
updateStreamingMessage((msg) => ({
|
|
3955
|
+
...msg,
|
|
3956
|
+
content: msg.content + event.delta
|
|
3957
|
+
}));
|
|
3958
|
+
}
|
|
3959
|
+
break;
|
|
3960
|
+
case "tool_use":
|
|
3961
|
+
if (event.toolId && event.toolName) {
|
|
3962
|
+
const toolInvocation = {
|
|
3963
|
+
state: "call",
|
|
3964
|
+
toolCallId: event.toolId,
|
|
3965
|
+
toolName: event.toolName,
|
|
3966
|
+
args: event.input || {}
|
|
3967
|
+
};
|
|
3968
|
+
updateStreamingMessage((msg) => ({
|
|
3969
|
+
...msg,
|
|
3970
|
+
toolInvocations: [...msg.toolInvocations || [], toolInvocation]
|
|
3971
|
+
}));
|
|
3972
|
+
onToolCall?.({ toolCall: toolInvocation });
|
|
3973
|
+
}
|
|
3974
|
+
break;
|
|
3975
|
+
case "tool_result":
|
|
3976
|
+
if (event.toolId) {
|
|
3977
|
+
updateStreamingMessage((msg) => ({
|
|
3978
|
+
...msg,
|
|
3979
|
+
toolInvocations: msg.toolInvocations?.map(
|
|
3980
|
+
(inv) => inv.toolCallId === event.toolId ? { ...inv, state: "result", result: event.toolResult } : inv
|
|
3981
|
+
)
|
|
3982
|
+
}));
|
|
3983
|
+
}
|
|
3984
|
+
break;
|
|
3985
|
+
case "text":
|
|
3986
|
+
if (event.text && !currentAssistantMessageRef.current?.content) {
|
|
3987
|
+
updateStreamingMessage((msg) => ({
|
|
3988
|
+
...msg,
|
|
3989
|
+
content: event.text || ""
|
|
3990
|
+
}));
|
|
3991
|
+
}
|
|
3992
|
+
break;
|
|
3993
|
+
case "error":
|
|
3994
|
+
if (event.error) {
|
|
3995
|
+
const err = new Error(event.error);
|
|
3996
|
+
setError(err);
|
|
3997
|
+
onError?.(err);
|
|
3998
|
+
}
|
|
3999
|
+
break;
|
|
4000
|
+
case "complete":
|
|
4001
|
+
if (currentAssistantMessageRef.current) {
|
|
4002
|
+
onFinish?.(currentAssistantMessageRef.current);
|
|
4003
|
+
}
|
|
4004
|
+
break;
|
|
4005
|
+
}
|
|
4006
|
+
}, [updateStreamingMessage, onToolCall, onFinish, onError, onSessionStart]);
|
|
4007
|
+
const append = useCallback(async (messageOrContent, options2) => {
|
|
4008
|
+
if (isLoading) return null;
|
|
4009
|
+
const userMessage = typeof messageOrContent === "string" ? {
|
|
4010
|
+
id: generateId(),
|
|
4011
|
+
role: "user",
|
|
4012
|
+
content: messageOrContent,
|
|
4013
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
4014
|
+
} : {
|
|
4015
|
+
id: messageOrContent.id || generateId(),
|
|
4016
|
+
role: messageOrContent.role,
|
|
4017
|
+
content: messageOrContent.content,
|
|
4018
|
+
toolInvocations: messageOrContent.toolInvocations,
|
|
4019
|
+
reasoning: messageOrContent.reasoning,
|
|
4020
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
4021
|
+
};
|
|
4022
|
+
setMessages((prev) => [...prev, userMessage]);
|
|
4023
|
+
setIsLoading(true);
|
|
4024
|
+
setError(void 0);
|
|
4025
|
+
reconnectAttemptsRef.current = 0;
|
|
4026
|
+
const assistantMessage = {
|
|
4027
|
+
id: generateId(),
|
|
4028
|
+
role: "assistant",
|
|
4029
|
+
content: "",
|
|
4030
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
4031
|
+
};
|
|
4032
|
+
currentAssistantMessageRef.current = assistantMessage;
|
|
4033
|
+
setMessages((prev) => [...prev, assistantMessage]);
|
|
4034
|
+
const controller = new AbortController();
|
|
4035
|
+
abortControllerRef.current = controller;
|
|
4036
|
+
try {
|
|
4037
|
+
let finalPrompt = userMessage.content;
|
|
4038
|
+
let additionalMetadata = options2?.body || {};
|
|
4039
|
+
if (middleware?.length) {
|
|
4040
|
+
const middlewareRequest = {
|
|
4041
|
+
prompt: finalPrompt,
|
|
4042
|
+
sessionId: sessionIdRef.current,
|
|
4043
|
+
metadata: additionalMetadata
|
|
4044
|
+
};
|
|
4045
|
+
const { request, error: middlewareError } = await applyRequestMiddleware(middleware, middlewareRequest);
|
|
4046
|
+
if (middlewareError) {
|
|
4047
|
+
const err = new Error(middlewareError);
|
|
4048
|
+
setError(err);
|
|
4049
|
+
onError?.(err);
|
|
4050
|
+
setIsLoading(false);
|
|
4051
|
+
return null;
|
|
4052
|
+
}
|
|
4053
|
+
finalPrompt = request.prompt;
|
|
4054
|
+
additionalMetadata = request.metadata || {};
|
|
4055
|
+
}
|
|
4056
|
+
const streamOptions = {
|
|
4057
|
+
signal: controller.signal,
|
|
4058
|
+
metadata: Object.keys(additionalMetadata).length > 0 ? additionalMetadata : void 0
|
|
4059
|
+
};
|
|
4060
|
+
const stream = createStream(finalPrompt, sessionIdRef.current || void 0, streamOptions);
|
|
4061
|
+
for await (const event of stream) {
|
|
4062
|
+
if (controller.signal.aborted) break;
|
|
4063
|
+
let processedEvent = event;
|
|
4064
|
+
if (middleware?.length) {
|
|
4065
|
+
processedEvent = await applyEventMiddleware(middleware, event);
|
|
4066
|
+
}
|
|
4067
|
+
if (processedEvent) {
|
|
4068
|
+
processEvent(processedEvent);
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
if (middleware?.length && sessionIdRef.current) {
|
|
4072
|
+
await callMiddlewareComplete(middleware, sessionIdRef.current);
|
|
4073
|
+
}
|
|
4074
|
+
return assistantMessage.id;
|
|
4075
|
+
} catch (err) {
|
|
4076
|
+
const isAbort = err.name === "AbortError";
|
|
4077
|
+
if (!isAbort) {
|
|
4078
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
4079
|
+
setError(error2);
|
|
4080
|
+
onError?.(error2);
|
|
4081
|
+
if (middleware?.length) {
|
|
4082
|
+
await callMiddlewareError(middleware, error2.message);
|
|
4083
|
+
}
|
|
4084
|
+
}
|
|
4085
|
+
return null;
|
|
4086
|
+
} finally {
|
|
4087
|
+
setIsLoading(false);
|
|
4088
|
+
setIsReconnecting(false);
|
|
4089
|
+
abortControllerRef.current = null;
|
|
4090
|
+
currentAssistantMessageRef.current = null;
|
|
4091
|
+
}
|
|
4092
|
+
}, [isLoading, createStream, processEvent, middleware, onError]);
|
|
4093
|
+
const stop = useCallback(() => {
|
|
4094
|
+
reconnectAttemptsRef.current = maxReconnectAttempts + 1;
|
|
4095
|
+
setIsReconnecting(false);
|
|
4096
|
+
if (abortControllerRef.current) {
|
|
4097
|
+
abortControllerRef.current.abort();
|
|
4098
|
+
}
|
|
4099
|
+
}, [maxReconnectAttempts]);
|
|
4100
|
+
const reload = useCallback(async () => {
|
|
4101
|
+
let lastUserMessageIndex = -1;
|
|
4102
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
4103
|
+
if (messages[i]?.role === "user") {
|
|
4104
|
+
lastUserMessageIndex = i;
|
|
4105
|
+
break;
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
if (lastUserMessageIndex === -1) return null;
|
|
4109
|
+
const lastUserMessage = messages[lastUserMessageIndex];
|
|
4110
|
+
if (!lastUserMessage) return null;
|
|
4111
|
+
setMessages(messages.slice(0, lastUserMessageIndex + 1));
|
|
4112
|
+
return append(lastUserMessage);
|
|
4113
|
+
}, [messages, append]);
|
|
4114
|
+
const handleInputChange = useCallback((e) => {
|
|
4115
|
+
setInput(e.target.value);
|
|
4116
|
+
}, []);
|
|
4117
|
+
const handleSubmit = useCallback((e, options2) => {
|
|
4118
|
+
e?.preventDefault();
|
|
4119
|
+
if (!input.trim()) return;
|
|
4120
|
+
const message = input;
|
|
4121
|
+
setInput("");
|
|
4122
|
+
append(message, options2);
|
|
4123
|
+
}, [input, append]);
|
|
4124
|
+
useEffect(() => {
|
|
4125
|
+
return () => {
|
|
4126
|
+
if (abortControllerRef.current) {
|
|
4127
|
+
abortControllerRef.current.abort();
|
|
4128
|
+
}
|
|
4129
|
+
};
|
|
4130
|
+
}, []);
|
|
4131
|
+
return {
|
|
4132
|
+
messages,
|
|
4133
|
+
isLoading,
|
|
4134
|
+
error,
|
|
4135
|
+
sessionId,
|
|
4136
|
+
append,
|
|
4137
|
+
stop,
|
|
4138
|
+
setMessages,
|
|
4139
|
+
reload,
|
|
4140
|
+
input,
|
|
4141
|
+
setInput,
|
|
4142
|
+
handleInputChange,
|
|
4143
|
+
handleSubmit,
|
|
4144
|
+
isReconnecting,
|
|
4145
|
+
entries
|
|
4146
|
+
};
|
|
4147
|
+
}
|
|
3718
4148
|
function textToBase64(text) {
|
|
3719
4149
|
const encoder = new TextEncoder();
|
|
3720
4150
|
const bytes = encoder.encode(text);
|
|
@@ -3788,6 +4218,6 @@ function useLongTextConversion({
|
|
|
3788
4218
|
};
|
|
3789
4219
|
}
|
|
3790
4220
|
|
|
3791
|
-
export { ActionIcon,
|
|
4221
|
+
export { ActionIcon, AlertCircleIcon, AlertTriangleIcon, ArrowUpIcon, Attachment, AttachmentInfo, AttachmentPreview, AttachmentRemove, Attachments, BotIcon, BrainIcon, BugIcon, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, CircleIcon, ClipboardListIcon, ClockIcon, CodeBlock, CodeIcon, Conversation, ConversationContent, ConversationEmptyState, ConversationScrollButton, CopyIcon, DEFAULT_STYLE_CONFIG, EditIcon, EnvVarsPanel, ErrorIcon, FileBadgeCompact, FileIcon, FilePlusIcon, FolderSearchIcon, GlobeIcon, HomeIcon, InfoIcon, JsonDisplay, LazyMarkdown, ListChecksIcon, LoaderIcon, LoadingDots, LoadingSpinner, LogsPanel, Message, MessageAction, MessageActions, MessageAvatar, MessageContent, MessageResponse, MessageShimmer, MessageSquareIcon, MessageTimestamp, MicrophoneIcon, MoonIcon, OptionCards, PaperclipIcon, PlugIcon, Reasoning, ReasoningContent, ReasoningTrigger, SearchIcon, SendIcon, Shimmer, ShimmerBlock, ShimmerLine, ShimmerText, SparklesIcon, SpinnerIcon, StatusIndicator, StopCircleIcon, SunIcon, Task, TaskContent, TaskItem, TaskList, TaskTrigger, TerminalIcon, ThinkingIndicator, Tool, ToolHeader, ToolIcon, ToolInput, ToolList, ToolOutput, UserIcon, XCircleIcon, XIcon, allKeyframesCss, applyEventMiddleware, applyRequestMiddleware, borderRadius, callMiddlewareComplete, callMiddlewareError, cn, colors, createToolCall, cssVars, extractTextContent, formatElapsedTime, formatFileSize, formatFileSize2 as formatFileSizeHook, formatTimestamp, formatToolName, generateToolSummary, getActionIcon, getActionLabel, inlineStyles, isAgentToolAction, isCommandRunAction, isErrorEntry, isFileEditAction, isFileReadAction, isFileWriteAction, isGenericToolAction, isGlobAction, isMcpToolAction, isSearchAction, isTodoWriteAction, isToolCallEntry, isWebFetchAction, isWebSearchAction, isWidgetEntry, keyframes, keyframesCss, mapToolToActionType, messageToNormalizedEntry, messagesToNormalizedEntries, normalizeToolResult, normalizedEntriesToMessages, normalizedEntryToMessage, parseCommandResult, parseMcpToolName, parseOptionsFromContent, shadows, spacing, tokensToCssVariables, transitions, truncate, typography, updateToolCallWithResult, useAgentChat, useAttachment, useChat, useConversation, useFileUpload, useLongTextConversion, useMessage, useMessageQueue, useReasoning, useStopExecution, useTask, useTool, widget, zIndex };
|
|
3792
4222
|
//# sourceMappingURL=index.js.map
|
|
3793
4223
|
//# sourceMappingURL=index.js.map
|