@cntyclub/agent-react 0.9.2 → 0.10.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/components/agent-panel.d.ts +3 -1
- package/dist/components/agent-panel.d.ts.map +1 -1
- package/dist/components/agent-widget.d.ts +8 -8
- package/dist/components/agent-widget.d.ts.map +1 -1
- package/dist/index.js +220 -56
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/use-agent-chat.d.ts +1 -1
- package/dist/use-agent-chat.d.ts.map +1 -1
- package/package.json +28 -17
|
@@ -12,11 +12,13 @@ export interface AgentPanelProps {
|
|
|
12
12
|
onClose: () => void;
|
|
13
13
|
/** Remember a write tool and auto-approve its future prompts. */
|
|
14
14
|
onAlwaysApprove: (toolName: string) => void;
|
|
15
|
+
/** Message id to render a "New messages" divider before (arrived while closed). */
|
|
16
|
+
newMessageAnchorId?: string | null;
|
|
15
17
|
className?: string;
|
|
16
18
|
}
|
|
17
19
|
/**
|
|
18
20
|
* The chat surface shared by the popup panel and fullscreen Agent Mode.
|
|
19
21
|
* Header (title, history, new chat, expand/collapse, close) + messages + input.
|
|
20
22
|
*/
|
|
21
|
-
export declare function AgentPanel({ agentMode, canToggleAgentMode, chat, className, config, onAlwaysApprove, onClose, onToggleAgentMode, }: AgentPanelProps): React.JSX.Element;
|
|
23
|
+
export declare function AgentPanel({ agentMode, canToggleAgentMode, chat, className, config, newMessageAnchorId, onAlwaysApprove, onClose, onToggleAgentMode, }: AgentPanelProps): React.JSX.Element;
|
|
22
24
|
//# sourceMappingURL=agent-panel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-panel.d.ts","sourceRoot":"","sources":["../../src/components/agent-panel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent-panel.d.ts","sourceRoot":"","sources":["../../src/components/agent-panel.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAQ5C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,cAAc,GAAG,gBAAgB,CAAC;IACxC,yCAAyC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,4DAA4D;IAC5D,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,iEAAiE;IACjE,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EACzB,SAAS,EACT,kBAAkB,EAClB,IAAI,EACJ,SAAS,EACT,MAAM,EACN,kBAAkB,EAClB,eAAe,EACf,OAAO,EACP,iBAAiB,GAClB,EAAE,eAAe,qBAsUjB"}
|
|
@@ -9,15 +9,15 @@ export interface AgentWidgetProps {
|
|
|
9
9
|
/**
|
|
10
10
|
* The embeddable Agent Mode widget.
|
|
11
11
|
*
|
|
12
|
-
* - Closed: a floating round button
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - Open on mobile: fullscreen from the start.
|
|
12
|
+
* - Closed: a floating round button. While closed, it surfaces what the agent
|
|
13
|
+
* is doing — a live "Thinking… / Calling tools…" ticker, an unread badge when
|
|
14
|
+
* a reply finished, and an "approval needed" chip when a write is waiting.
|
|
15
|
+
* - Open on desktop: a popup panel that can expand to fullscreen ("Agent Mode").
|
|
16
|
+
* - Open on mobile: fullscreen.
|
|
18
17
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* Open/close and fullscreen transitions are animated (scale from the launcher
|
|
19
|
+
* corner; size morph between popup and fullscreen). All colors come from the
|
|
20
|
+
* host app's UI-kit theme tokens.
|
|
21
21
|
*/
|
|
22
22
|
export declare function AgentWidget({ config, onOpenChange, open: controlledOpen }: AgentWidgetProps): React.JSX.Element;
|
|
23
23
|
//# sourceMappingURL=agent-widget.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-widget.d.ts","sourceRoot":"","sources":["../../src/components/agent-widget.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent-widget.d.ts","sourceRoot":"","sources":["../../src/components/agent-widget.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,UAAU,CAAC;AAK1D,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,WAAW,CAAC;IACpB,wCAAwC;IACxC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAQD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,gBAAgB,qBAoQ3F"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Button, cn, Tooltip, TooltipTrigger, TooltipContent, ChatMessage, ChatMessageBubble, Markdown, Spinner, Checkbox, Collapsible, CollapsibleTrigger, ChatToolChip, CollapsiblePanel, ChatToolCard, ChatToolCardHeader, ChatToolCardActions, Group, Menu, MenuTrigger, MenuPopup, MenuItem, ChatHeader, ChatHeaderAvatar, ChatHeaderTitle, ChatHeaderActions, Chat, ChatEmptyState, ChatEmptyStateIcon, ChatEmptyStateTitle, ChatEmptyStateDescription, ChatSuggestions, ChatSuggestion, useMediaQuery, TooltipProvider,
|
|
1
|
+
import { Button, cn, Tooltip, TooltipTrigger, TooltipContent, ChatMessage, ChatMessageBubble, Markdown, Spinner, Checkbox, Collapsible, CollapsibleTrigger, ChatToolChip, CollapsiblePanel, ChatToolCard, ChatToolCardHeader, ChatToolCardActions, Group, Menu, MenuTrigger, MenuPopup, MenuItem, ChatHeader, ChatHeaderAvatar, ChatHeaderTitle, ChatHeaderActions, Chat, ChatEmptyState, ChatEmptyStateIcon, ChatEmptyStateTitle, ChatEmptyStateDescription, ChatSuggestions, ChatSuggestion, useMediaQuery, TooltipProvider, DataTablePaged } from '@cntyclub/ui-react';
|
|
2
2
|
import { FileTextIcon, XIcon, PaperclipIcon, ArrowUpIcon, CheckIcon, CopyIcon, Maximize2Icon, ListChecksIcon, ChevronDownIcon, ShieldAlertIcon, CheckCheckIcon, UploadCloudIcon, HistoryIcon, SquarePenIcon, Minimize2Icon, Trash2Icon, SparklesIcon, DownloadIcon, CodeIcon } from 'lucide-react';
|
|
3
3
|
import * as React8 from 'react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
import { motion, AnimatePresence } from 'motion/react';
|
|
5
6
|
|
|
6
7
|
// src/api-client.ts
|
|
7
8
|
var AgentApiError = class extends Error {
|
|
@@ -1042,6 +1043,7 @@ function AgentPanel({
|
|
|
1042
1043
|
chat,
|
|
1043
1044
|
className,
|
|
1044
1045
|
config,
|
|
1046
|
+
newMessageAnchorId,
|
|
1045
1047
|
onAlwaysApprove,
|
|
1046
1048
|
onClose,
|
|
1047
1049
|
onToggleAgentMode
|
|
@@ -1262,9 +1264,30 @@ function AgentPanel({
|
|
|
1262
1264
|
suggestion
|
|
1263
1265
|
)) })
|
|
1264
1266
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1267
|
+
(() => {
|
|
1268
|
+
const grouped = groupMessages(chat.messages);
|
|
1269
|
+
const anchorKey = newMessageAnchorId ? grouped.find(
|
|
1270
|
+
(it) => it.kind !== "tool-activity" && it.message.id === newMessageAnchorId
|
|
1271
|
+
)?.key : void 0;
|
|
1272
|
+
return grouped.map((item) => /* @__PURE__ */ jsxs(React8.Fragment, { children: [
|
|
1273
|
+
item.key === anchorKey ? /* @__PURE__ */ jsx(NewMessagesDivider, {}) : null,
|
|
1274
|
+
/* @__PURE__ */ jsx(
|
|
1275
|
+
motion.div,
|
|
1276
|
+
{
|
|
1277
|
+
initial: { opacity: 0, y: 8 },
|
|
1278
|
+
animate: { opacity: 1, y: 0 },
|
|
1279
|
+
transition: { duration: 0.18, ease: "easeOut" },
|
|
1280
|
+
children: item.kind === "tool-activity" ? /* @__PURE__ */ jsx(ChatMessage, { from: "assistant", children: /* @__PURE__ */ jsx(
|
|
1281
|
+
ToolActivityGroup,
|
|
1282
|
+
{
|
|
1283
|
+
describeToolCall: config.describeToolCall,
|
|
1284
|
+
steps: item.steps
|
|
1285
|
+
}
|
|
1286
|
+
) }) : /* @__PURE__ */ jsx(MessageItem, { message: item.message })
|
|
1287
|
+
}
|
|
1288
|
+
)
|
|
1289
|
+
] }, item.key));
|
|
1290
|
+
})(),
|
|
1268
1291
|
chat.pendingApprovals.map((approval) => /* @__PURE__ */ jsx(
|
|
1269
1292
|
ToolApprovalCard,
|
|
1270
1293
|
{
|
|
@@ -1314,6 +1337,13 @@ function AgentPanel({
|
|
|
1314
1337
|
}
|
|
1315
1338
|
);
|
|
1316
1339
|
}
|
|
1340
|
+
function NewMessagesDivider() {
|
|
1341
|
+
return /* @__PURE__ */ jsxs("div", { className: "my-1 flex items-center gap-2", "aria-label": "New messages", children: [
|
|
1342
|
+
/* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" }),
|
|
1343
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "New messages" }),
|
|
1344
|
+
/* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" })
|
|
1345
|
+
] });
|
|
1346
|
+
}
|
|
1317
1347
|
var OPTIMISTIC_ID_PREFIX = "optimistic-";
|
|
1318
1348
|
var STREAMING_ID_PREFIX = "streaming-";
|
|
1319
1349
|
var optimisticCounter = 0;
|
|
@@ -1515,8 +1545,10 @@ function useAgentChat(config) {
|
|
|
1515
1545
|
try {
|
|
1516
1546
|
const { conversations: list } = await client.listConversations();
|
|
1517
1547
|
setConversations(list);
|
|
1548
|
+
return list;
|
|
1518
1549
|
} catch (err) {
|
|
1519
1550
|
handleFailure(err);
|
|
1551
|
+
return [];
|
|
1520
1552
|
}
|
|
1521
1553
|
}, [client, handleFailure]);
|
|
1522
1554
|
const openConversation = React8.useCallback(
|
|
@@ -1616,45 +1648,109 @@ function useAlwaysApprove(clientId) {
|
|
|
1616
1648
|
);
|
|
1617
1649
|
return { clearAlwaysApprove, isAlwaysApproved, setAlwaysApprove };
|
|
1618
1650
|
}
|
|
1651
|
+
function isUnreadable(message) {
|
|
1652
|
+
if (message.id.startsWith("streaming-")) return false;
|
|
1653
|
+
return message.role === "assistant" || message.role === "tool";
|
|
1654
|
+
}
|
|
1619
1655
|
function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
1656
|
+
const behavior = config.behavior ?? {};
|
|
1657
|
+
const position = config.appearance?.position ?? "bottom-right";
|
|
1658
|
+
const isControlled = controlledOpen !== void 0;
|
|
1659
|
+
const storageKey2 = `cc-agent-open:${config.clientId}`;
|
|
1620
1660
|
const [uncontrolledOpen, setUncontrolledOpen] = React8.useState(false);
|
|
1621
1661
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
1662
|
+
const persist = React8.useCallback(
|
|
1663
|
+
(next) => {
|
|
1664
|
+
if (isControlled || !behavior.persistOpenState) return;
|
|
1665
|
+
try {
|
|
1666
|
+
window.localStorage.setItem(storageKey2, next ? "1" : "0");
|
|
1667
|
+
} catch {
|
|
1668
|
+
}
|
|
1669
|
+
},
|
|
1670
|
+
[behavior.persistOpenState, isControlled, storageKey2]
|
|
1671
|
+
);
|
|
1622
1672
|
const setOpen = React8.useCallback(
|
|
1623
1673
|
(next) => {
|
|
1624
1674
|
setUncontrolledOpen(next);
|
|
1675
|
+
persist(next);
|
|
1625
1676
|
onOpenChange?.(next);
|
|
1626
1677
|
},
|
|
1627
|
-
[onOpenChange]
|
|
1678
|
+
[onOpenChange, persist]
|
|
1628
1679
|
);
|
|
1629
1680
|
const [agentMode, setAgentMode] = React8.useState(false);
|
|
1630
|
-
const isDesktop = useMediaQuery("(min-width: 640px)", {
|
|
1631
|
-
defaultSSRValue: true,
|
|
1632
|
-
ssr: true
|
|
1633
|
-
});
|
|
1681
|
+
const isDesktop = useMediaQuery("(min-width: 640px)", { defaultSSRValue: true, ssr: true });
|
|
1634
1682
|
const fullscreen = !isDesktop || agentMode;
|
|
1635
1683
|
const chat = useAgentChat(config);
|
|
1636
1684
|
const alwaysApprove = useAlwaysApprove(config.clientId);
|
|
1637
|
-
const { pendingApprovals, resolveApproval, resolvingApprovalId } = chat;
|
|
1685
|
+
const { messages, pendingApprovals, resolveApproval, resolvingApprovalId, sending } = chat;
|
|
1686
|
+
const bootRef = React8.useRef(false);
|
|
1687
|
+
React8.useEffect(() => {
|
|
1688
|
+
if (isControlled || bootRef.current) return;
|
|
1689
|
+
bootRef.current = true;
|
|
1690
|
+
let cancelled = false;
|
|
1691
|
+
void (async () => {
|
|
1692
|
+
if (behavior.openLastConversation !== false) {
|
|
1693
|
+
const list = await chat.refreshConversations();
|
|
1694
|
+
if (cancelled) return;
|
|
1695
|
+
if (list.length) await chat.openConversation(list[0].id);
|
|
1696
|
+
if (cancelled) return;
|
|
1697
|
+
}
|
|
1698
|
+
let shouldOpen = behavior.initialOpen ?? false;
|
|
1699
|
+
if (behavior.persistOpenState) {
|
|
1700
|
+
try {
|
|
1701
|
+
const stored = window.localStorage.getItem(storageKey2);
|
|
1702
|
+
if (stored !== null) shouldOpen = stored === "1";
|
|
1703
|
+
} catch {
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
if (shouldOpen) {
|
|
1707
|
+
setUncontrolledOpen(true);
|
|
1708
|
+
onOpenChange?.(true);
|
|
1709
|
+
}
|
|
1710
|
+
})();
|
|
1711
|
+
return () => {
|
|
1712
|
+
cancelled = true;
|
|
1713
|
+
};
|
|
1714
|
+
}, []);
|
|
1715
|
+
const seenCountRef = React8.useRef(0);
|
|
1716
|
+
const [anchorId, setAnchorId] = React8.useState(null);
|
|
1717
|
+
React8.useEffect(() => {
|
|
1718
|
+
if (open) {
|
|
1719
|
+
if (messages.length > seenCountRef.current) {
|
|
1720
|
+
const firstUnread = messages[seenCountRef.current];
|
|
1721
|
+
setAnchorId(firstUnread && isUnreadable(firstUnread) ? firstUnread.id : null);
|
|
1722
|
+
}
|
|
1723
|
+
seenCountRef.current = messages.length;
|
|
1724
|
+
}
|
|
1725
|
+
}, [open, messages]);
|
|
1726
|
+
const unreadCount = open ? 0 : messages.slice(seenCountRef.current).filter(isUnreadable).length;
|
|
1727
|
+
const workLabel = React8.useMemo(() => {
|
|
1728
|
+
if (!sending) return null;
|
|
1729
|
+
const last = messages[messages.length - 1];
|
|
1730
|
+
if (last?.role === "tool") return "Calling tools\u2026";
|
|
1731
|
+
if (last?.role === "assistant" && (last.tool_calls?.length ?? 0) > 0) return "Calling tools\u2026";
|
|
1732
|
+
return "Thinking\u2026";
|
|
1733
|
+
}, [sending, messages]);
|
|
1734
|
+
const approvalWaiting = pendingApprovals.length > 0;
|
|
1638
1735
|
const { isAlwaysApproved } = alwaysApprove;
|
|
1639
1736
|
React8.useEffect(() => {
|
|
1640
|
-
if (
|
|
1737
|
+
if (resolvingApprovalId) return;
|
|
1641
1738
|
const target = pendingApprovals.find((approval) => isAlwaysApproved(approval.tool_name));
|
|
1642
1739
|
if (target) void resolveApproval(target.id, true);
|
|
1643
|
-
}, [
|
|
1740
|
+
}, [pendingApprovals, resolvingApprovalId, isAlwaysApproved, resolveApproval]);
|
|
1644
1741
|
const firedWriteIds = React8.useRef(/* @__PURE__ */ new Set());
|
|
1645
1742
|
const { onWriteSuccess } = config;
|
|
1646
1743
|
React8.useEffect(() => {
|
|
1647
1744
|
if (!onWriteSuccess) return;
|
|
1648
|
-
for (const message of
|
|
1745
|
+
for (const message of messages) {
|
|
1649
1746
|
if (message.role !== "tool" || !message.is_write || message.tool_status !== "success") continue;
|
|
1650
1747
|
if (firedWriteIds.current.has(message.id)) continue;
|
|
1651
1748
|
firedWriteIds.current.add(message.id);
|
|
1652
|
-
const args = findToolArguments(
|
|
1749
|
+
const args = findToolArguments(messages, message);
|
|
1653
1750
|
onWriteSuccess({ arguments: args, toolName: message.tool_name ?? "" });
|
|
1654
1751
|
}
|
|
1655
|
-
}, [
|
|
1752
|
+
}, [messages, onWriteSuccess]);
|
|
1656
1753
|
const lastNavigatedMessageId = React8.useRef(null);
|
|
1657
|
-
const { messages } = chat;
|
|
1658
1754
|
React8.useEffect(() => {
|
|
1659
1755
|
if (!open || fullscreen || !config.navigate || !config.pages?.length) return;
|
|
1660
1756
|
const toolMessages = messages.filter((message) => message.role === "tool");
|
|
@@ -1671,65 +1767,133 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
|
1671
1767
|
setOpen(false);
|
|
1672
1768
|
setAgentMode(false);
|
|
1673
1769
|
}, [setOpen]);
|
|
1770
|
+
const transformOrigin = position === "bottom-left" ? "bottom left" : "bottom right";
|
|
1771
|
+
const launcherHidden = open || config.appearance?.hideLauncher;
|
|
1674
1772
|
return /* @__PURE__ */ jsxs(TooltipProvider, { children: [
|
|
1675
|
-
|
|
1676
|
-
|
|
1773
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: !launcherHidden ? /* @__PURE__ */ jsxs(
|
|
1774
|
+
motion.div,
|
|
1677
1775
|
{
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1776
|
+
initial: { opacity: 0, scale: 0.6 },
|
|
1777
|
+
animate: { opacity: 1, scale: 1 },
|
|
1778
|
+
exit: { opacity: 0, scale: 0.6 },
|
|
1779
|
+
transition: { type: "spring", stiffness: 300, damping: 24 },
|
|
1780
|
+
style: { transformOrigin },
|
|
1781
|
+
className: cn(
|
|
1782
|
+
"fixed z-50 flex flex-col items-end gap-2",
|
|
1783
|
+
position === "bottom-left" ? "bottom-4 left-4 items-start sm:bottom-6 sm:left-6" : "right-4 bottom-4 sm:right-6 sm:bottom-6"
|
|
1784
|
+
),
|
|
1785
|
+
children: [
|
|
1786
|
+
/* @__PURE__ */ jsx(AnimatePresence, { mode: "popLayout", children: approvalWaiting ? /* @__PURE__ */ jsx(StatusChip, { tone: "warning", pulse: true, children: "Approval needed" }, "approval") : workLabel ? /* @__PURE__ */ jsx(StatusChip, { tone: "muted", children: workLabel }, workLabel) : null }),
|
|
1787
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
1788
|
+
/* @__PURE__ */ jsx(
|
|
1789
|
+
"button",
|
|
1790
|
+
{
|
|
1791
|
+
type: "button",
|
|
1792
|
+
"aria-label": "Open assistant",
|
|
1793
|
+
onClick: () => setOpen(true),
|
|
1794
|
+
className: "flex size-14 items-center justify-center rounded-full bg-primary text-primary-foreground shadow-lg outline-none transition-transform hover:scale-105 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
1795
|
+
children: /* @__PURE__ */ jsx(SparklesIcon, { className: "size-6" })
|
|
1796
|
+
}
|
|
1797
|
+
),
|
|
1798
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: unreadCount > 0 ? /* @__PURE__ */ jsx(
|
|
1799
|
+
motion.span,
|
|
1800
|
+
{
|
|
1801
|
+
initial: { scale: 0 },
|
|
1802
|
+
animate: { scale: 1 },
|
|
1803
|
+
exit: { scale: 0 },
|
|
1804
|
+
transition: { type: "spring", stiffness: 500, damping: 20 },
|
|
1805
|
+
className: "absolute -right-1 -top-1 flex h-5 min-w-5 items-center justify-center rounded-full bg-destructive px-1 text-xs font-semibold text-destructive-foreground shadow",
|
|
1806
|
+
"aria-label": `${unreadCount} new message${unreadCount === 1 ? "" : "s"}`,
|
|
1807
|
+
children: unreadCount > 9 ? "9+" : unreadCount
|
|
1808
|
+
},
|
|
1809
|
+
"badge"
|
|
1810
|
+
) : null })
|
|
1811
|
+
] })
|
|
1812
|
+
]
|
|
1813
|
+
},
|
|
1814
|
+
"agent-launcher"
|
|
1815
|
+
) : null }),
|
|
1816
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: open ? /* @__PURE__ */ jsx(
|
|
1817
|
+
motion.div,
|
|
1686
1818
|
{
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
config,
|
|
1698
|
-
onAlwaysApprove: alwaysApprove.setAlwaysApprove,
|
|
1699
|
-
onClose: closePanel,
|
|
1700
|
-
onToggleAgentMode: () => setAgentMode((value) => !value)
|
|
1819
|
+
layout: true,
|
|
1820
|
+
initial: { opacity: 0, scale: 0.9 },
|
|
1821
|
+
animate: { opacity: 1, scale: 1 },
|
|
1822
|
+
exit: { opacity: 0, scale: 0.9 },
|
|
1823
|
+
transition: { type: "spring", stiffness: 260, damping: 28 },
|
|
1824
|
+
style: {
|
|
1825
|
+
transformOrigin,
|
|
1826
|
+
...fullscreen ? {} : {
|
|
1827
|
+
height: `min(${config.appearance?.panelHeight ?? 640}px, calc(100dvh - 3rem))`,
|
|
1828
|
+
width: `min(${config.appearance?.panelWidth ?? 400}px, calc(100vw - 2rem))`
|
|
1701
1829
|
}
|
|
1702
|
-
|
|
1703
|
-
}
|
|
1704
|
-
) : /* @__PURE__ */ jsx(
|
|
1705
|
-
"div",
|
|
1706
|
-
{
|
|
1830
|
+
},
|
|
1707
1831
|
className: cn(
|
|
1708
|
-
"fixed z-50 flex flex-col overflow-hidden
|
|
1709
|
-
|
|
1832
|
+
"fixed z-50 flex flex-col overflow-hidden bg-background",
|
|
1833
|
+
fullscreen ? "inset-0" : cn(
|
|
1834
|
+
"rounded-2xl border border-border shadow-2xl",
|
|
1835
|
+
position === "bottom-left" ? "bottom-4 left-4 sm:bottom-6 sm:left-6" : "right-4 bottom-4 sm:right-6 sm:bottom-6"
|
|
1836
|
+
)
|
|
1710
1837
|
),
|
|
1711
1838
|
role: "dialog",
|
|
1712
|
-
|
|
1713
|
-
height: `min(${config.appearance?.panelHeight ?? 640}px, calc(100dvh - 3rem))`,
|
|
1714
|
-
width: `min(${config.appearance?.panelWidth ?? 400}px, calc(100vw - 2rem))`
|
|
1715
|
-
},
|
|
1839
|
+
"aria-modal": fullscreen ? "true" : void 0,
|
|
1716
1840
|
children: /* @__PURE__ */ jsx(
|
|
1717
1841
|
AgentPanel,
|
|
1718
1842
|
{
|
|
1719
|
-
agentMode:
|
|
1720
|
-
canToggleAgentMode:
|
|
1843
|
+
agentMode: fullscreen && agentMode,
|
|
1844
|
+
canToggleAgentMode: isDesktop,
|
|
1721
1845
|
chat,
|
|
1722
1846
|
className: "flex-1",
|
|
1723
1847
|
config,
|
|
1848
|
+
newMessageAnchorId: anchorId,
|
|
1724
1849
|
onAlwaysApprove: alwaysApprove.setAlwaysApprove,
|
|
1725
1850
|
onClose: closePanel,
|
|
1726
|
-
onToggleAgentMode: () => setAgentMode(
|
|
1851
|
+
onToggleAgentMode: () => setAgentMode((value) => !value)
|
|
1727
1852
|
}
|
|
1728
1853
|
)
|
|
1729
|
-
}
|
|
1730
|
-
|
|
1854
|
+
},
|
|
1855
|
+
"agent-panel"
|
|
1856
|
+
) : null })
|
|
1731
1857
|
] });
|
|
1732
1858
|
}
|
|
1859
|
+
function StatusChip({
|
|
1860
|
+
children,
|
|
1861
|
+
tone,
|
|
1862
|
+
pulse
|
|
1863
|
+
}) {
|
|
1864
|
+
return /* @__PURE__ */ jsxs(
|
|
1865
|
+
motion.div,
|
|
1866
|
+
{
|
|
1867
|
+
layout: true,
|
|
1868
|
+
initial: { opacity: 0, y: 6, scale: 0.9 },
|
|
1869
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
1870
|
+
exit: { opacity: 0, y: 6, scale: 0.9 },
|
|
1871
|
+
transition: { duration: 0.18 },
|
|
1872
|
+
className: cn(
|
|
1873
|
+
"flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium shadow-sm",
|
|
1874
|
+
tone === "warning" ? "border-warning bg-warning-surface text-warning-foreground" : "border-border bg-card text-secondary-foreground"
|
|
1875
|
+
),
|
|
1876
|
+
children: [
|
|
1877
|
+
pulse ? /* @__PURE__ */ jsx("span", { className: "size-1.5 rounded-full bg-warning-foreground" }) : /* @__PURE__ */ jsxs("span", { className: "flex gap-0.5", children: [
|
|
1878
|
+
/* @__PURE__ */ jsx(Dot, { delay: 0 }),
|
|
1879
|
+
/* @__PURE__ */ jsx(Dot, { delay: 0.15 }),
|
|
1880
|
+
/* @__PURE__ */ jsx(Dot, { delay: 0.3 })
|
|
1881
|
+
] }),
|
|
1882
|
+
children
|
|
1883
|
+
]
|
|
1884
|
+
}
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
function Dot({ delay }) {
|
|
1888
|
+
return /* @__PURE__ */ jsx(
|
|
1889
|
+
motion.span,
|
|
1890
|
+
{
|
|
1891
|
+
className: "size-1.5 rounded-full bg-current opacity-60",
|
|
1892
|
+
animate: { opacity: [0.2, 1, 0.2] },
|
|
1893
|
+
transition: { duration: 1, repeat: Infinity, delay }
|
|
1894
|
+
}
|
|
1895
|
+
);
|
|
1896
|
+
}
|
|
1733
1897
|
function findToolArguments(messages, toolMessage) {
|
|
1734
1898
|
if (!toolMessage.tool_call_id) return {};
|
|
1735
1899
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|