mirror of https://github.com/kortix-ai/suna.git
feat: theme change and adjustments
This commit is contained in:
parent
4485563b47
commit
6938164eff
|
@ -192,7 +192,7 @@ export const Examples = ({
|
|||
}}
|
||||
>
|
||||
<Card
|
||||
className="group cursor-pointer h-full shadow-none transition-all bg-sidebar hover:bg-neutral-100 dark:hover:bg-neutral-800/60 p-0 justify-center"
|
||||
className="group cursor-pointer h-full shadow-none transition-all bg-card hover:bg-neutral-100 dark:hover:bg-neutral-800/60 p-0 justify-center"
|
||||
onClick={() => onSelectPrompt && onSelectPrompt(prompt.query)}
|
||||
>
|
||||
<CardHeader className="p-2 grid-rows-1">
|
||||
|
|
|
@ -225,23 +225,23 @@
|
|||
}
|
||||
|
||||
:root {
|
||||
--background: oklch(98.46% 0.002 247.84);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--background: oklch(0.9741 0 129.63);
|
||||
--foreground: oklch(0.2277 0.0034 67.65);
|
||||
--card: oklch(98.46% 0.002 247.84);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover: oklch(0.9924 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(54.65% 0.246 262.87);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted: oklch(0.93 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent: oklch(0.1149 0 0 / 6%);
|
||||
--accent-foreground: oklch(0.145 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--destructive-foreground: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--border: oklch(0.1149 0 0 / 8%);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
|
@ -250,11 +250,11 @@
|
|||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--radius: 0.625rem;
|
||||
--sidebar: oklch(98.46% 0.002 247.84);
|
||||
--sidebar: oklch(0.9741 0 129.63);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent: oklch(0.1149 0 0 / 4%);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
|
@ -263,29 +263,29 @@
|
|||
.dark {
|
||||
--background: oklch(0.185 0.005 285.823);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.145 0 0);
|
||||
--card: oklch(0.2 0.005 285.823);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.145 0 0);
|
||||
--popover: oklch(0.2267 0.0051 264.48);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.985 0 0);
|
||||
--primary-foreground: oklch(0.205 0 0);
|
||||
--secondary: oklch(54.65% 0.246 262.87);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.269 0 0);
|
||||
--muted: oklch(0.31 0 0);
|
||||
--muted-foreground: oklch(0.708 0 0);
|
||||
--accent: oklch(27.39% 0.005 286.03);
|
||||
--accent: oklch(0.274 0.006 286.033);
|
||||
--accent-foreground: oklch(98.46% 0.002 247.84)
|
||||
--destructive: oklch(0.396 0.141 25.723);
|
||||
--destructive-foreground: oklch(0.637 0.237 25.331);
|
||||
--border: oklch(0.269 0 0);
|
||||
--input: oklch(0.269 0 0);
|
||||
--border: oklch(0.9911 0 0 / 6%);
|
||||
--input: oklch(0.28 0 0);
|
||||
--ring: oklch(0.439 0 0);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(21.03% 0.006 285.89);
|
||||
--sidebar: oklch(0.185 0.005 285.823);
|
||||
--sidebar-foreground: oklch(0.985 0 0);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
|
|
|
@ -286,7 +286,7 @@ export function HeroSection() {
|
|||
<div className="relative z-10">
|
||||
<Card className="shadow-none w-full max-w-8xl mx-auto bg-transparent border-none rounded-3xl overflow-hidden">
|
||||
<div className="w-full text-sm flex flex-col justify-between items-start rounded-2xl">
|
||||
<CardContent className="w-full p-1.5 pb-2 bg-sidebar rounded-3xl border">
|
||||
<CardContent className="w-full p-1.5 pb-2 bg-card rounded-3xl border">
|
||||
<div className="relative flex flex-col w-full h-full gap-2 justify-between">
|
||||
<div className="flex flex-col gap-1 px-2">
|
||||
<Textarea
|
||||
|
|
|
@ -188,7 +188,7 @@ export function NavUserWithTeams({
|
|||
sideOffset={4}
|
||||
>
|
||||
<DropdownMenuLabel className="p-0 font-normal">
|
||||
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
|
||||
<div className="flex items-center gap-2 px-1.5 py-1.5 text-left text-sm">
|
||||
<Avatar className="h-8 w-8 rounded-lg">
|
||||
<AvatarImage src={user.avatar} alt={user.name} />
|
||||
<AvatarFallback className="rounded-lg">
|
||||
|
|
|
@ -78,7 +78,7 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
|
|||
onAgentSelect,
|
||||
agentName,
|
||||
messages = [],
|
||||
bgColor = 'bg-sidebar',
|
||||
bgColor = 'bg-card',
|
||||
toolCalls = [],
|
||||
toolCallIndex = 0,
|
||||
showToolPreview = false,
|
||||
|
|
|
@ -106,7 +106,7 @@ export const FloatingToolPreview: React.FC<FloatingToolPreviewProps> = ({
|
|||
layoutId={CONTENT_LAYOUT_ID}
|
||||
whileHover={{ scale: 1.01 }}
|
||||
whileTap={{ scale: 0.99 }}
|
||||
className="bg-sidebar border border-border rounded-3xl p-2 w-full cursor-pointer group"
|
||||
className="bg-card border border-border rounded-3xl p-2 w-full cursor-pointer group"
|
||||
onClick={handleClick}
|
||||
style={{ opacity: isExpanding ? 0 : 1 }}
|
||||
>
|
||||
|
|
|
@ -169,7 +169,7 @@ export function renderMarkdownContent(
|
|||
<div key={`tool-${match.index}-${index}`} className="my-1">
|
||||
<button
|
||||
onClick={() => handleToolClick(messageId, toolName)}
|
||||
className="inline-flex items-center gap-1.5 py-1 px-1 text-xs text-muted-foreground bg-muted hover:bg-muted/80 rounded-lg transition-colors cursor-pointer border border-neutral-200 dark:border-neutral-700/50"
|
||||
className="inline-flex items-center gap-1.5 py-1 px-1 pr-1.5 text-xs text-muted-foreground bg-muted hover:bg-muted/80 rounded-lg transition-colors cursor-pointer border border-neutral-200 dark:border-neutral-700/50"
|
||||
>
|
||||
<div className='border-2 bg-gradient-to-br from-neutral-200 to-neutral-300 dark:from-neutral-700 dark:to-neutral-800 flex items-center justify-center p-0.5 rounded-sm border-neutral-400/20 dark:border-neutral-600'>
|
||||
<IconComponent className="h-3.5 w-3.5 text-muted-foreground flex-shrink-0" />
|
||||
|
@ -251,7 +251,7 @@ export function renderMarkdownContent(
|
|||
<div key={toolCallKey} className="my-1">
|
||||
<button
|
||||
onClick={() => handleToolClick(messageId, toolName)}
|
||||
className="inline-flex items-center gap-1.5 py-1 px-1 text-xs text-muted-foreground bg-muted hover:bg-muted/80 rounded-lg transition-colors cursor-pointer border border-neutral-200 dark:border-neutral-700/50"
|
||||
className="inline-flex items-center gap-1.5 py-1 px-1 pr-1.5 text-xs text-muted-foreground bg-muted hover:bg-muted/80 rounded-lg transition-colors cursor-pointer border border-neutral-200 dark:border-neutral-700/50"
|
||||
>
|
||||
<div className='border-2 bg-gradient-to-br from-neutral-200 to-neutral-300 dark:from-neutral-700 dark:to-neutral-800 flex items-center justify-center p-0.5 rounded-sm border-neutral-400/20 dark:border-neutral-600'>
|
||||
<IconComponent className="h-3.5 w-3.5 text-muted-foreground flex-shrink-0" />
|
||||
|
@ -567,7 +567,7 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
|
|||
if (debugMode) {
|
||||
return (
|
||||
<div key={group.key} className="flex justify-end">
|
||||
<div className="flex max-w-[85%] rounded-2xl bg-primary/10 px-4 py-3 break-words overflow-hidden">
|
||||
<div className="flex max-w-[85%] rounded-2xl bg-card px-4 py-3 break-words overflow-hidden">
|
||||
<pre className="text-xs font-mono whitespace-pre-wrap overflow-x-auto min-w-0 flex-1">
|
||||
{message.content}
|
||||
</pre>
|
||||
|
@ -590,7 +590,7 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
|
|||
|
||||
return (
|
||||
<div key={group.key} className="flex justify-end">
|
||||
<div className="flex max-w-[85%] rounded-2xl bg-primary/10 px-4 py-3 break-words overflow-hidden">
|
||||
<div className="flex max-w-[85%] rounded-3xl rounded-br-lg bg-card border px-4 py-3 break-words overflow-hidden">
|
||||
<div className="space-y-3 min-w-0 flex-1">
|
||||
{cleanContent && (
|
||||
<Markdown className="text-sm prose prose-sm dark:prose-invert chat-markdown max-w-none [&>:first-child]:mt-0 prose-headings:mt-3 break-words overflow-wrap-anywhere">{cleanContent}</Markdown>
|
||||
|
@ -640,7 +640,7 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
|
|||
</div>
|
||||
|
||||
{/* Message content - ALL messages in the group */}
|
||||
<div className="flex max-w-[90%] rounded-lg text-sm break-words overflow-hidden">
|
||||
<div className="flex max-w-[90%] text-sm break-words overflow-hidden">
|
||||
<div className="space-y-2 min-w-0 flex-1">
|
||||
{(() => {
|
||||
// In debug mode, just show raw messages content
|
||||
|
|
|
@ -387,8 +387,8 @@ export function FileAttachment({
|
|||
<div
|
||||
className={cn(
|
||||
"group relative rounded-xl w-full",
|
||||
"border border-black/10 dark:border-white/10",
|
||||
"bg-black/5 dark:bg-black/20",
|
||||
"border",
|
||||
"bg-card",
|
||||
"overflow-hidden",
|
||||
"h-[300px]", // Fixed height for previews
|
||||
"pt-10", // Room for header
|
||||
|
@ -462,7 +462,7 @@ export function FileAttachment({
|
|||
</div>
|
||||
|
||||
{/* Header with filename */}
|
||||
<div className="absolute top-0 left-0 right-0 bg-black/5 dark:bg-white/5 p-2 z-10 flex items-center justify-between">
|
||||
<div className="absolute top-0 left-0 right-0 bg-accent p-2 z-10 flex items-center justify-between">
|
||||
<div className="text-sm font-medium truncate">{filename}</div>
|
||||
{onClick && (
|
||||
<button
|
||||
|
|
|
@ -1551,7 +1551,7 @@ export function FileViewerModal({
|
|||
{files.map((file) => (
|
||||
<button
|
||||
key={file.path}
|
||||
className={`flex flex-col items-center p-3 rounded-lg border hover:bg-muted/50 transition-colors ${selectedFilePath === file.path
|
||||
className={`flex flex-col items-center p-3 rounded-2xl border hover:bg-muted/50 transition-colors ${selectedFilePath === file.path
|
||||
? 'bg-muted border-primary/20'
|
||||
: ''
|
||||
}`}
|
||||
|
|
|
@ -196,7 +196,7 @@ export function ToolCallSidePanel({
|
|||
displayIndex = completedIndex;
|
||||
displayTotalCalls = totalCompletedCalls;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const currentToolName = displayToolCall?.assistantCall?.name || 'Tool Call';
|
||||
const CurrentToolIcon = getToolIcon(
|
||||
|
@ -434,8 +434,7 @@ export function ToolCallSidePanel({
|
|||
<div className="pt-4 pl-4 pr-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="ml-2 flex items-center gap-2">
|
||||
<Computer className="h-4 w-4" />
|
||||
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
|
||||
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
|
||||
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
|
||||
</h2>
|
||||
</div>
|
||||
|
@ -473,8 +472,7 @@ export function ToolCallSidePanel({
|
|||
<div className="pt-4 pl-4 pr-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="ml-2 flex items-center gap-2">
|
||||
<Computer className="h-4 w-4" />
|
||||
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
|
||||
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
|
||||
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
|
||||
</h2>
|
||||
</div>
|
||||
|
@ -520,8 +518,7 @@ export function ToolCallSidePanel({
|
|||
<div className="pt-4 pl-4 pr-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="ml-2 flex items-center gap-2">
|
||||
<Computer className="h-4 w-4" />
|
||||
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
|
||||
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
|
||||
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
|
||||
</h2>
|
||||
</div>
|
||||
|
@ -567,8 +564,7 @@ export function ToolCallSidePanel({
|
|||
<div className="pt-4 pl-4 pr-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="ml-2 flex items-center gap-2">
|
||||
<Computer className="h-4 w-4" />
|
||||
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
|
||||
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
|
||||
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
|
||||
</h2>
|
||||
</div>
|
||||
|
@ -612,14 +608,13 @@ export function ToolCallSidePanel({
|
|||
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
<motion.div
|
||||
<motion.div
|
||||
layoutId={CONTENT_LAYOUT_ID}
|
||||
className="p-3"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<motion.div layoutId="tool-icon" className="ml-2 flex items-center gap-2">
|
||||
<Computer className="h-4 w-4" />
|
||||
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
|
||||
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
|
||||
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
|
||||
</h2>
|
||||
</motion.div>
|
||||
|
@ -695,16 +690,16 @@ export function ToolCallSidePanel({
|
|||
}
|
||||
}}
|
||||
className={cn(
|
||||
'fixed top-2 right-2 bottom-4 border rounded-2xl flex flex-col z-30',
|
||||
'fixed top-2 right-2 bottom-4 border rounded-3xl flex flex-col z-30',
|
||||
isMobile
|
||||
? 'left-2'
|
||||
: 'w-[40vw] sm:w-[450px] md:w-[500px] lg:w-[550px] xl:w-[645px]',
|
||||
)}
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<div className="flex-1 flex flex-col overflow-hidden bg-sidebar">
|
||||
<div className="flex-1 flex flex-col overflow-hidden bg-card">
|
||||
{renderContent()}
|
||||
</div>
|
||||
{(displayTotalCalls > 1 || (isCurrentToolStreaming && totalCompletedCalls > 0)) && (
|
||||
|
|
|
@ -74,7 +74,7 @@ export function BrowserToolView({
|
|||
try {
|
||||
const cleanedOutput = outputString.replace(/\\n/g, '\n').replace(/\\"/g, '"').replace(/\\u([0-9a-fA-F]{4})/g, (match, grp) => String.fromCharCode(parseInt(grp, 16)));
|
||||
const outputJson = JSON.parse(cleanedOutput);
|
||||
|
||||
|
||||
if (outputJson.image_url) {
|
||||
screenshotUrl = outputJson.image_url;
|
||||
}
|
||||
|
@ -84,21 +84,21 @@ export function BrowserToolView({
|
|||
} catch (parseError) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!screenshotUrl) {
|
||||
const imageUrlMatch = innerContentString.match(/"image_url":\s*"([^"]+)"/);
|
||||
if (imageUrlMatch) {
|
||||
screenshotUrl = imageUrlMatch[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!browserStateMessageId) {
|
||||
const messageIdMatch = innerContentString.match(/"message_id":\s*"([^"]+)"/);
|
||||
if (messageIdMatch) {
|
||||
browserStateMessageId = messageIdMatch[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!browserStateMessageId && !screenshotUrl) {
|
||||
const outputMatch = innerContentString.match(/\boutput='(.*?)'(?=\s*\))/);
|
||||
const outputString = outputMatch ? outputMatch[1] : null;
|
||||
|
@ -117,17 +117,17 @@ export function BrowserToolView({
|
|||
}
|
||||
}
|
||||
} else if (innerContentString && typeof innerContentString === "object") {
|
||||
screenshotUrl = (() => {
|
||||
if (!innerContentString) return null;
|
||||
if (!("tool_execution" in innerContentString)) return null;
|
||||
if (!("result" in innerContentString.tool_execution)) return null;
|
||||
if (!("output" in innerContentString.tool_execution.result)) return null;
|
||||
if (!("image_url" in innerContentString.tool_execution.result.output)) return null;
|
||||
if (typeof innerContentString.tool_execution.result.output.image_url !== "string") return null;
|
||||
return innerContentString.tool_execution.result.output.image_url;
|
||||
})()
|
||||
}
|
||||
|
||||
screenshotUrl = (() => {
|
||||
if (!innerContentString) return null;
|
||||
if (!("tool_execution" in innerContentString)) return null;
|
||||
if (!("result" in innerContentString.tool_execution)) return null;
|
||||
if (!("output" in innerContentString.tool_execution.result)) return null;
|
||||
if (!("image_url" in innerContentString.tool_execution.result.output)) return null;
|
||||
if (typeof innerContentString.tool_execution.result.output.image_url !== "string") return null;
|
||||
return innerContentString.tool_execution.result.output.image_url;
|
||||
})()
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ export function BrowserToolView({
|
|||
);
|
||||
|
||||
if (browserStateMessage) {
|
||||
const browserStateContent = safeJsonParse<{
|
||||
const browserStateContent = safeJsonParse<{
|
||||
screenshot_base64?: string;
|
||||
image_url?: string;
|
||||
}>(
|
||||
|
@ -266,11 +266,11 @@ export function BrowserToolView({
|
|||
};
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative p-2 rounded-lg bg-gradient-to-br from-purple-500/20 to-purple-600/10 border border-purple-500/20">
|
||||
<div className="relative p-2 rounded-lg bg-gradient-to-br from-purple-500/20 to-purple-600/10 border border-purple-500/20">
|
||||
<MonitorPlay className="w-5 h-5 text-purple-500 dark:text-purple-400" />
|
||||
</div>
|
||||
<div>
|
||||
|
@ -279,13 +279,13 @@ export function BrowserToolView({
|
|||
</CardTitle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!isRunning && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={
|
||||
isSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
isSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
|
||||
}
|
||||
>
|
||||
|
@ -339,9 +339,9 @@ export function BrowserToolView({
|
|||
</h3>
|
||||
{url && (
|
||||
<div className="mt-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-700 shadow-sm hover:shadow-md transition-shadow"
|
||||
asChild
|
||||
>
|
||||
|
@ -355,52 +355,52 @@ export function BrowserToolView({
|
|||
</div>
|
||||
)
|
||||
) :
|
||||
(screenshotUrl || screenshotBase64) ? (
|
||||
<div className="flex items-center justify-center w-full h-full overflow-auto relative p-4">
|
||||
{imageLoading && (
|
||||
<ImageLoader />
|
||||
)}
|
||||
<Card className={`p-0 overflow-hidden border ${imageLoading ? 'hidden' : 'block'}`}>
|
||||
{screenshotUrl ? (
|
||||
<img
|
||||
src={screenshotUrl}
|
||||
alt="Browser Screenshot"
|
||||
className="max-w-full max-h-full object-contain"
|
||||
onLoad={handleImageLoad}
|
||||
onError={handleImageError}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
src={`data:image/jpeg;base64,${screenshotBase64}`}
|
||||
alt="Browser Screenshot"
|
||||
className="max-w-full max-h-full object-contain"
|
||||
onLoad={handleImageLoad}
|
||||
onError={handleImageError}
|
||||
/>
|
||||
(screenshotUrl || screenshotBase64) ? (
|
||||
<div className="flex items-center justify-center w-full h-full overflow-auto relative p-4">
|
||||
{imageLoading && (
|
||||
<ImageLoader />
|
||||
)}
|
||||
</Card>
|
||||
{imageError && !imageLoading && (
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-zinc-50 dark:bg-zinc-900">
|
||||
<div className="text-center text-zinc-500 dark:text-zinc-400">
|
||||
<AlertTriangle className="h-8 w-8 mx-auto mb-2" />
|
||||
<p>Failed to load screenshot</p>
|
||||
<Card className={`p-0 overflow-hidden border ${imageLoading ? 'hidden' : 'block'}`}>
|
||||
{screenshotUrl ? (
|
||||
<img
|
||||
src={screenshotUrl}
|
||||
alt="Browser Screenshot"
|
||||
className="max-w-full max-h-full object-contain"
|
||||
onLoad={handleImageLoad}
|
||||
onError={handleImageError}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
src={`data:image/jpeg;base64,${screenshotBase64}`}
|
||||
alt="Browser Screenshot"
|
||||
className="max-w-full max-h-full object-contain"
|
||||
onLoad={handleImageLoad}
|
||||
onError={handleImageError}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
{imageError && !imageLoading && (
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-zinc-50 dark:bg-zinc-900">
|
||||
<div className="text-center text-zinc-500 dark:text-zinc-400">
|
||||
<AlertTriangle className="h-8 w-8 mx-auto mb-2" />
|
||||
<p>Failed to load screenshot</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-8 h-full flex flex-col items-center justify-center w-full bg-gradient-to-b from-white to-zinc-50 dark:from-zinc-950 dark:to-zinc-900 text-zinc-700 dark:text-zinc-400">
|
||||
<div className="w-20 h-20 rounded-full flex items-center justify-center mb-6 bg-gradient-to-b from-zinc-100 to-zinc-50 shadow-inner dark:from-zinc-800/40 dark:to-zinc-900/60">
|
||||
<MonitorPlay className="h-10 w-10 text-zinc-400 dark:text-zinc-600" />
|
||||
)}
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold mb-2 text-zinc-900 dark:text-zinc-100">
|
||||
No Browser State Available
|
||||
</h3>
|
||||
<p className="text-sm text-zinc-500 dark:text-zinc-400">
|
||||
Browser state image not found for this action
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
) : (
|
||||
<div className="p-8 h-full flex flex-col items-center justify-center w-full bg-gradient-to-b from-white to-zinc-50 dark:from-zinc-950 dark:to-zinc-900 text-zinc-700 dark:text-zinc-400">
|
||||
<div className="w-20 h-20 rounded-full flex items-center justify-center mb-6 bg-gradient-to-b from-zinc-100 to-zinc-50 shadow-inner dark:from-zinc-800/40 dark:to-zinc-900/60">
|
||||
<MonitorPlay className="h-10 w-10 text-zinc-400 dark:text-zinc-600" />
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold mb-2 text-zinc-900 dark:text-zinc-100">
|
||||
No Browser State Available
|
||||
</h3>
|
||||
<p className="text-sm text-zinc-500 dark:text-zinc-400">
|
||||
Browser state image not found for this action
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
|
@ -418,7 +418,7 @@ export function BrowserToolView({
|
|||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{toolTimestamp && !isRunning
|
||||
? formatTimestamp(toolTimestamp)
|
||||
|
|
|
@ -126,7 +126,7 @@ export function CompleteToolView({
|
|||
};
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -187,7 +187,7 @@ export function CompleteToolView({
|
|||
{/* Summary Section */}
|
||||
{completeData.summary && (
|
||||
<div className="space-y-2">
|
||||
<div className="bg-muted/50 rounded-lg p-4 border border-border">
|
||||
<div className="bg-muted/50 rounded-2xl p-4 border border-border">
|
||||
<Markdown className="text-sm prose prose-sm dark:prose-invert chat-markdown max-w-none [&>:first-child]:mt-0 prose-headings:mt-3">
|
||||
{completeData.summary}
|
||||
</Markdown>
|
||||
|
|
|
@ -133,7 +133,7 @@ export function DeployToolView({
|
|||
}, [deployResult?.output]);
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -223,7 +223,7 @@ export function DeployToolView({
|
|||
{/* Terminal Output */}
|
||||
{cleanOutput.length > 0 && (
|
||||
<div className="bg-zinc-100 dark:bg-neutral-900 rounded-lg overflow-hidden border border-zinc-200/20">
|
||||
<div className="bg-zinc-200 dark:bg-zinc-800 px-4 py-2 flex items-center gap-2">
|
||||
<div className="bg-accent px-4 py-2 flex items-center gap-2">
|
||||
<TerminalIcon className="h-4 w-4 text-zinc-600 dark:text-zinc-400" />
|
||||
<span className="text-sm font-medium text-zinc-700 dark:text-zinc-300">
|
||||
Deployment Log
|
||||
|
@ -259,7 +259,7 @@ export function DeployToolView({
|
|||
{/* Raw Error Output */}
|
||||
{rawContent && (
|
||||
<div className="bg-zinc-100 dark:bg-neutral-900 rounded-lg overflow-hidden border border-zinc-200/20">
|
||||
<div className="bg-zinc-200 dark:bg-zinc-800 px-4 py-2 flex items-center gap-2">
|
||||
<div className="bg-accent px-4 py-2 flex items-center gap-2">
|
||||
<TerminalIcon className="h-4 w-4 text-zinc-600 dark:text-zinc-400" />
|
||||
<span className="text-sm font-medium text-zinc-700 dark:text-zinc-300">
|
||||
Error Details
|
||||
|
|
|
@ -129,7 +129,7 @@ export function GenericToolView({
|
|||
);
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
|
@ -115,7 +115,7 @@ export function WebCrawlToolView({
|
|||
|
||||
const copyContent = async () => {
|
||||
if (!webpageContent?.text) return;
|
||||
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(webpageContent.text);
|
||||
setCopiedContent(true);
|
||||
|
@ -129,34 +129,34 @@ export function WebCrawlToolView({
|
|||
const wordCount = content.trim().split(/\s+/).length;
|
||||
const charCount = content.length;
|
||||
const lineCount = content.split('\n').length;
|
||||
|
||||
|
||||
return { wordCount, charCount, lineCount };
|
||||
};
|
||||
|
||||
const contentStats = webpageContent?.text ? getContentStats(webpageContent.text) : null;
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative p-2 rounded-lg bg-gradient-to-br from-primary/20 to-primary/10 border border-primary/20">
|
||||
<Globe className="w-5 h-5 text-primary" />
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<CardTitle className="text-base font-medium text-zinc-900 dark:text-zinc-100">
|
||||
{toolTitle}
|
||||
</CardTitle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!isStreaming && (
|
||||
<Badge
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={
|
||||
isSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
isSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
|
||||
}
|
||||
>
|
||||
|
@ -201,21 +201,21 @@ export function WebCrawlToolView({
|
|||
<div className="group relative">
|
||||
<div className="flex items-center gap-3 p-4 bg-zinc-50 dark:bg-zinc-900 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors rounded-xl border border-zinc-200 dark:border-zinc-800">
|
||||
{favicon && (
|
||||
<img
|
||||
src={favicon}
|
||||
alt=""
|
||||
<img
|
||||
src={favicon}
|
||||
alt=""
|
||||
className="w-6 h-6 rounded-md flex-shrink-0"
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).style.display = 'none';
|
||||
}}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="font-mono text-sm text-zinc-900 dark:text-zinc-100 truncate">{truncateString(url, 70)}</p>
|
||||
<p className="text-xs text-zinc-500 dark:text-zinc-400 mt-1">{domain}</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="opacity-70 group-hover:opacity-100 transition-opacity"
|
||||
asChild
|
||||
|
@ -266,7 +266,7 @@ export function WebCrawlToolView({
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
|
@ -332,7 +332,7 @@ export function WebCrawlToolView({
|
|||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
|
||||
{/* Footer */}
|
||||
<div className="px-4 py-2 h-10 bg-gradient-to-r from-zinc-50/90 to-zinc-100/90 dark:from-zinc-900/90 dark:to-zinc-800/90 backdrop-blur-sm border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center gap-4">
|
||||
<div className="h-full flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400">
|
||||
|
@ -343,7 +343,7 @@ export function WebCrawlToolView({
|
|||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{toolTimestamp && !isStreaming
|
||||
? formatTimestamp(toolTimestamp)
|
||||
|
|
|
@ -70,11 +70,11 @@ export function AskToolView({
|
|||
};
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative p-2 rounded-lg bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
|
||||
<div className="relative p-2 rounded-xl bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
|
||||
<MessageCircleQuestion className="w-5 h-5 text-blue-500 dark:text-blue-400" />
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
@ -89,7 +89,7 @@ export function CommandToolView({
|
|||
const linesToShow = showFullOutput ? formattedOutput : previewLines;
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
|
@ -51,7 +51,7 @@ export function TerminateCommandToolView({
|
|||
|
||||
const rawSessionName = React.useMemo(() => {
|
||||
if (sessionName) return sessionName;
|
||||
|
||||
|
||||
if (!assistantContent) return null;
|
||||
|
||||
const contentStr = normalizeContentToString(assistantContent);
|
||||
|
@ -82,24 +82,24 @@ export function TerminateCommandToolView({
|
|||
const finalSessionName = rawSessionName?.trim() || sessionName;
|
||||
|
||||
const toolTitle = getToolTitle(name) || 'Terminate Session';
|
||||
|
||||
|
||||
const terminationSuccess = React.useMemo(() => {
|
||||
if (!output) return false;
|
||||
|
||||
|
||||
const outputLower = output.toLowerCase();
|
||||
if (outputLower.includes('does not exist')) return false;
|
||||
if (outputLower.includes('terminated') || outputLower.includes('killed')) return true;
|
||||
|
||||
|
||||
if (typeof toolContent === 'string') {
|
||||
const toolResultMatch = toolContent.match(/ToolResult\(success=(true|false)/i);
|
||||
if (toolResultMatch) {
|
||||
return toolResultMatch[1].toLowerCase() === 'true';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return actualIsSuccess;
|
||||
}, [output, actualIsSuccess, toolContent]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (isStreaming) {
|
||||
const timer = setInterval(() => {
|
||||
|
@ -129,16 +129,16 @@ export function TerminateCommandToolView({
|
|||
}
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
|
||||
processedOutput = String(processedOutput);
|
||||
processedOutput = processedOutput.replace(/\\\\/g, '\\');
|
||||
|
||||
|
||||
processedOutput = processedOutput
|
||||
.replace(/\\n/g, '\n')
|
||||
.replace(/\\t/g, '\t')
|
||||
.replace(/\\"/g, '"')
|
||||
.replace(/\\'/g, "'");
|
||||
|
||||
|
||||
processedOutput = processedOutput.replace(/\\u([0-9a-fA-F]{4})/g, (match, group) => {
|
||||
return String.fromCharCode(parseInt(group, 16));
|
||||
});
|
||||
|
@ -150,7 +150,7 @@ export function TerminateCommandToolView({
|
|||
const linesToShow = showFullOutput ? formattedOutput : previewLines;
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -163,13 +163,13 @@ export function TerminateCommandToolView({
|
|||
</CardTitle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!isStreaming && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={
|
||||
terminationSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
terminationSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
|
||||
}
|
||||
>
|
||||
|
@ -222,18 +222,18 @@ export function TerminateCommandToolView({
|
|||
<ArrowRight className="h-4 w-4 mr-2 text-zinc-500 dark:text-zinc-400" />
|
||||
Result
|
||||
</h3>
|
||||
<Badge
|
||||
<Badge
|
||||
className={cn(
|
||||
"ml-2",
|
||||
terminationSuccess
|
||||
? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400"
|
||||
terminationSuccess
|
||||
? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400"
|
||||
: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400"
|
||||
)}
|
||||
>
|
||||
{terminationSuccess ? 'Success' : 'Failed'}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="bg-zinc-100 dark:bg-neutral-900 rounded-lg overflow-hidden border border-zinc-200/20">
|
||||
<div className="bg-zinc-300 dark:bg-neutral-800 flex items-center justify-between dark:border-zinc-700/50">
|
||||
<div className="bg-zinc-200 w-full dark:bg-zinc-800 px-4 py-2 flex items-center gap-2">
|
||||
|
@ -250,8 +250,8 @@ export function TerminateCommandToolView({
|
|||
<div className="p-4 max-h-96 overflow-auto scrollbar-hide">
|
||||
<pre className="text-xs text-zinc-600 dark:text-zinc-300 font-mono whitespace-pre-wrap break-all overflow-visible">
|
||||
{linesToShow.map((line, index) => (
|
||||
<div
|
||||
key={index}
|
||||
<div
|
||||
key={index}
|
||||
className="py-0.5 bg-transparent"
|
||||
>
|
||||
{line || ' '}
|
||||
|
@ -267,7 +267,7 @@ export function TerminateCommandToolView({
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{!output && !isStreaming && (
|
||||
<div className="bg-black rounded-lg overflow-hidden border border-zinc-700/20 shadow-md p-6 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
|
@ -292,7 +292,7 @@ export function TerminateCommandToolView({
|
|||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
|
||||
<div className="px-4 py-2 h-10 bg-gradient-to-r from-zinc-50/90 to-zinc-100/90 dark:from-zinc-900/90 dark:to-zinc-800/90 backdrop-blur-sm border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center gap-4">
|
||||
<div className="h-full flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400">
|
||||
{!isStreaming && finalSessionName && (
|
||||
|
@ -302,7 +302,7 @@ export function TerminateCommandToolView({
|
|||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="text-xs text-zinc-500 dark:text-zinc-400 flex items-center gap-2">
|
||||
<Clock className="h-3.5 w-3.5" />
|
||||
{actualToolTimestamp && !isStreaming
|
||||
|
|
|
@ -74,7 +74,7 @@ export function DataProviderEndpointsToolView({
|
|||
isSuccess = true,
|
||||
isStreaming = false,
|
||||
}: ToolViewProps) {
|
||||
|
||||
|
||||
const {
|
||||
serviceName,
|
||||
endpoints,
|
||||
|
@ -89,19 +89,19 @@ export function DataProviderEndpointsToolView({
|
|||
assistantTimestamp
|
||||
);
|
||||
|
||||
const providerConfig = serviceName && PROVIDER_CONFIG[serviceName]
|
||||
? PROVIDER_CONFIG[serviceName]
|
||||
const providerConfig = serviceName && PROVIDER_CONFIG[serviceName]
|
||||
? PROVIDER_CONFIG[serviceName]
|
||||
: PROVIDER_CONFIG['linkedin'];
|
||||
const IconComponent = providerConfig.icon;
|
||||
|
||||
const endpointCount = endpoints && typeof endpoints === 'object' ? Object.keys(endpoints).length : 0;
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative p-2 rounded-lg bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
|
||||
<div className="relative p-2 rounded-xl bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
|
||||
<Globe className="w-5 h-5 text-blue-500 dark:text-blue-400" />
|
||||
</div>
|
||||
<div>
|
||||
|
@ -110,14 +110,14 @@ export function DataProviderEndpointsToolView({
|
|||
</CardTitle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!isStreaming && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={cn(
|
||||
"text-xs font-medium",
|
||||
actualIsSuccess
|
||||
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
|
||||
actualIsSuccess
|
||||
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
|
||||
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
|
||||
)}
|
||||
>
|
||||
|
@ -157,7 +157,7 @@ export function DataProviderEndpointsToolView({
|
|||
)}>
|
||||
<IconComponent className="h-6 w-6 text-white drop-shadow-sm" />
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
|
||||
{providerConfig.name}
|
||||
|
@ -166,13 +166,13 @@ export function DataProviderEndpointsToolView({
|
|||
{endpointCount > 0 ? `${endpointCount} endpoints loaded and ready` : 'Endpoints loaded and ready'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Badge
|
||||
variant="secondary"
|
||||
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={cn(
|
||||
"text-xs font-medium",
|
||||
actualIsSuccess
|
||||
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
|
||||
actualIsSuccess
|
||||
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
|
||||
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
|
||||
)}
|
||||
>
|
||||
|
@ -198,12 +198,12 @@ export function DataProviderEndpointsToolView({
|
|||
Connection Status
|
||||
</span>
|
||||
</div>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={cn(
|
||||
"text-xs font-medium",
|
||||
actualIsSuccess
|
||||
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
|
||||
actualIsSuccess
|
||||
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
|
||||
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
|
||||
)}
|
||||
>
|
||||
|
@ -215,7 +215,7 @@ export function DataProviderEndpointsToolView({
|
|||
{actualIsSuccess ? 'Active' : 'Inactive'}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||
|
@ -227,7 +227,7 @@ export function DataProviderEndpointsToolView({
|
|||
{endpointCount > 0 ? `${endpointCount} endpoints` : 'Ready'}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-2 h-2 rounded-full bg-purple-500"></div>
|
||||
|
@ -257,7 +257,7 @@ export function DataProviderEndpointsToolView({
|
|||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
|
||||
<div className="px-4 py-2 h-10 bg-zinc-50/50 dark:bg-zinc-900/50 backdrop-blur-sm border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center gap-4">
|
||||
<div className="h-full flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400">
|
||||
{!isStreaming && (
|
||||
|
@ -267,7 +267,7 @@ export function DataProviderEndpointsToolView({
|
|||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{actualToolTimestamp && !isStreaming
|
||||
? formatTimestamp(actualToolTimestamp)
|
||||
|
|
|
@ -32,7 +32,7 @@ const PROVIDER_CONFIG = {
|
|||
borderColor: 'border-blue-200 dark:border-blue-800'
|
||||
},
|
||||
'twitter': {
|
||||
name: 'Twitter Data Provider',
|
||||
name: 'Twitter Data Provider',
|
||||
icon: MessageCircle,
|
||||
color: 'from-sky-400 to-sky-500',
|
||||
bgColor: 'bg-sky-50 dark:bg-sky-900/20',
|
||||
|
@ -82,7 +82,7 @@ export function ExecuteDataProviderCallToolView({
|
|||
isSuccess = true,
|
||||
isStreaming = false,
|
||||
}: ToolViewProps) {
|
||||
|
||||
|
||||
const {
|
||||
serviceName,
|
||||
route,
|
||||
|
@ -100,18 +100,18 @@ export function ExecuteDataProviderCallToolView({
|
|||
);
|
||||
|
||||
const providerKey = serviceName?.toLowerCase() as keyof typeof PROVIDER_CONFIG;
|
||||
const providerConfig = providerKey && PROVIDER_CONFIG[providerKey]
|
||||
? PROVIDER_CONFIG[providerKey]
|
||||
const providerConfig = providerKey && PROVIDER_CONFIG[providerKey]
|
||||
? PROVIDER_CONFIG[providerKey]
|
||||
: PROVIDER_CONFIG['linkedin'];
|
||||
|
||||
|
||||
const IconComponent = providerConfig.icon;
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative p-2 rounded-lg bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
|
||||
<div className="relative p-2 rounded-xl bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
|
||||
<Globe className="w-5 h-5 text-blue-500 dark:text-blue-400" />
|
||||
</div>
|
||||
<div>
|
||||
|
@ -120,14 +120,14 @@ export function ExecuteDataProviderCallToolView({
|
|||
</CardTitle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!isStreaming && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={cn(
|
||||
"text-xs font-medium",
|
||||
actualIsSuccess
|
||||
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
|
||||
actualIsSuccess
|
||||
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
|
||||
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
|
||||
)}
|
||||
>
|
||||
|
@ -167,7 +167,7 @@ export function ExecuteDataProviderCallToolView({
|
|||
)}>
|
||||
<IconComponent className="h-6 w-6 text-white drop-shadow-sm" />
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
|
||||
{providerConfig.name}
|
||||
|
@ -178,7 +178,7 @@ export function ExecuteDataProviderCallToolView({
|
|||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
{route && (
|
||||
<Badge variant="outline" className="text-xs font-mono">
|
||||
{route}
|
||||
|
@ -209,7 +209,7 @@ export function ExecuteDataProviderCallToolView({
|
|||
</div>
|
||||
<div className="grid gap-3">
|
||||
{Object.entries(payload).map(([key, value]) => (
|
||||
<div
|
||||
<div
|
||||
key={key}
|
||||
className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800 hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors"
|
||||
>
|
||||
|
@ -231,7 +231,7 @@ export function ExecuteDataProviderCallToolView({
|
|||
<span>Raw JSON</span>
|
||||
<ChevronRight className="h-3 w-3 text-zinc-400 group-open:rotate-90 transition-transform" />
|
||||
</summary>
|
||||
|
||||
|
||||
<div className="mt-3 p-4 bg-zinc-900 dark:bg-zinc-950 rounded-lg border border-zinc-200 dark:border-zinc-800">
|
||||
<pre className="text-xs font-mono text-emerald-400 dark:text-emerald-300 overflow-x-auto">
|
||||
{JSON.stringify(payload, null, 2)}
|
||||
|
|
|
@ -35,7 +35,7 @@ export function ExposePortToolView({
|
|||
assistantTimestamp,
|
||||
toolTimestamp,
|
||||
}: ToolViewProps) {
|
||||
|
||||
|
||||
const {
|
||||
port,
|
||||
url,
|
||||
|
@ -52,26 +52,26 @@ export function ExposePortToolView({
|
|||
);
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative p-2 rounded-lg bg-gradient-to-br from-green-500/20 to-green-600/10 border border-green-500/20">
|
||||
<Computer className="w-5 h-5 text-green-500 dark:text-green-400" />
|
||||
</div>
|
||||
<div className="relative p-2 rounded-lg bg-gradient-to-br from-green-500/20 to-green-600/10 border border-green-500/20">
|
||||
<Computer className="w-5 h-5 text-green-500 dark:text-green-400" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle className="text-base font-medium text-zinc-900 dark:text-zinc-100">
|
||||
Port Exposure
|
||||
</CardTitle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!isStreaming && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={
|
||||
actualIsSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
actualIsSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
|
||||
}
|
||||
>
|
||||
|
@ -88,7 +88,7 @@ export function ExposePortToolView({
|
|||
|
||||
<CardContent className="p-0 h-full flex-1 overflow-hidden relative">
|
||||
{isStreaming ? (
|
||||
<LoadingState
|
||||
<LoadingState
|
||||
icon={Computer}
|
||||
iconColor="text-emerald-500 dark:text-emerald-400"
|
||||
bgColor="bg-gradient-to-b from-emerald-100 to-emerald-50 shadow-inner dark:from-emerald-800/40 dark:to-emerald-900/60 dark:shadow-emerald-950/20"
|
||||
|
@ -174,7 +174,7 @@ export function ExposePortToolView({
|
|||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{actualToolTimestamp && formatTimestamp(actualToolTimestamp)}
|
||||
</div>
|
||||
|
|
|
@ -107,7 +107,7 @@ export function FileOperationToolView({
|
|||
const processedFilePath = processFilePath(filePath);
|
||||
const fileName = getFileName(processedFilePath);
|
||||
const fileExtension = getFileExtension(fileName);
|
||||
|
||||
|
||||
const isMarkdown = isFileType.markdown(fileExtension);
|
||||
const isHtml = isFileType.html(fileExtension);
|
||||
const isCsv = isFileType.csv(fileExtension);
|
||||
|
@ -269,7 +269,7 @@ export function FileOperationToolView({
|
|||
};
|
||||
|
||||
return (
|
||||
<Card className="flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<Tabs defaultValue={'preview'} className="w-full h-full">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2 mb-0">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
|
|
|
@ -6,9 +6,9 @@ import { ScrollArea } from '@/components/ui/scroll-area';
|
|||
import { Card } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Search, Database, FileText, Link2, Key, AlertTriangle,
|
||||
Copy, Globe, FileCode, Table, BookOpen, ExternalLink
|
||||
import {
|
||||
Search, Database, FileText, Link2, Key, AlertTriangle,
|
||||
Copy, Globe, FileCode, Table, BookOpen, ExternalLink
|
||||
} from 'lucide-react';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
@ -39,12 +39,12 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
|
|||
// Normalize search results from various formats
|
||||
const normalizeResults = (data: any): SearchResult[] => {
|
||||
let items: any[] = [];
|
||||
|
||||
|
||||
if (data?.results) items = data.results;
|
||||
else if (data?.data) items = data.data;
|
||||
else if (Array.isArray(data)) items = data;
|
||||
else return [];
|
||||
|
||||
|
||||
return items.map((item, index) => ({
|
||||
...item,
|
||||
url: item.url || item.link || item.href,
|
||||
|
@ -53,10 +53,10 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
|
|||
title: item.title || item.name || `Result ${index + 1}`
|
||||
})).filter(item => item.title || item.url);
|
||||
};
|
||||
|
||||
|
||||
const results = normalizeResults(data);
|
||||
const meta = metadata || data;
|
||||
|
||||
|
||||
return (
|
||||
<div className="p-3">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
|
@ -72,18 +72,18 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
{(meta?.autopromptString || meta?.query) && (
|
||||
<div className="mb-4 p-2 bg-zinc-50 dark:bg-zinc-900 rounded text-xs text-zinc-600 dark:text-zinc-400">
|
||||
<span className="font-medium">Query: </span>
|
||||
<span className="italic">{meta.autopromptString || meta.query}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
<ScrollArea className="max-h-96">
|
||||
<div className="space-y-3">
|
||||
{results.map((result, idx) => (
|
||||
<Card key={idx} className="p-3 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 hover:border-zinc-300 dark:hover:border-zinc-600 transition-colors">
|
||||
<Card key={idx} className="p-3 bg-card border border-zinc-200 dark:border-zinc-700 hover:border-zinc-300 dark:hover:border-zinc-600 transition-colors">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-start gap-2">
|
||||
<Badge variant="outline" className="text-xs shrink-0 mt-0.5">
|
||||
|
@ -95,8 +95,8 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
|
|||
</h4>
|
||||
</div>
|
||||
{result.image && (
|
||||
<img
|
||||
src={result.image}
|
||||
<img
|
||||
src={result.image}
|
||||
alt=""
|
||||
className="w-16 h-12 object-cover rounded border border-zinc-200 dark:border-zinc-700"
|
||||
onError={(e) => {
|
||||
|
@ -105,7 +105,7 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
|
|||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
{(result.author || result.date) && (
|
||||
<div className="flex items-center gap-2 text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{result.author && <span>By {result.author}</span>}
|
||||
|
@ -114,12 +114,12 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
|
|||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{result.url && (
|
||||
<div className="flex items-center gap-1.5 text-xs">
|
||||
{result.favicon && (
|
||||
<img
|
||||
src={result.favicon}
|
||||
<img
|
||||
src={result.favicon}
|
||||
alt=""
|
||||
className="w-4 h-4"
|
||||
onError={(e) => {
|
||||
|
@ -128,9 +128,9 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
|
|||
/>
|
||||
)}
|
||||
<Globe className="h-3 w-3 text-zinc-500" />
|
||||
<a
|
||||
href={result.url}
|
||||
target="_blank"
|
||||
<a
|
||||
href={result.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-600 dark:text-blue-400 hover:underline truncate flex-1"
|
||||
>
|
||||
|
@ -155,7 +155,7 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
|
|||
</TooltipProvider>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{result.summary && (
|
||||
<p className="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
||||
{result.summary}
|
||||
|
@ -174,9 +174,9 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
|
|||
function TableRenderer({ data }: { data: any }) {
|
||||
const renderAsTable = (items: any[]) => {
|
||||
if (!items.length) return null;
|
||||
|
||||
|
||||
const headers = Object.keys(items[0]);
|
||||
|
||||
|
||||
return (
|
||||
<div className="p-3">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
|
@ -212,11 +212,11 @@ function TableRenderer({ data }: { data: any }) {
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
return renderAsTable(data);
|
||||
}
|
||||
|
||||
|
||||
return <JsonRenderer data={data} />;
|
||||
}
|
||||
|
||||
|
@ -246,7 +246,7 @@ function KeyValueRenderer({ content }: { content: string }) {
|
|||
const [key, ...valueParts] = line.split(':');
|
||||
return { key: key.trim(), value: valueParts.join(':').trim() };
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<div className="p-3">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
|
@ -274,7 +274,7 @@ function KeyValueRenderer({ content }: { content: string }) {
|
|||
// Renderer for URL lists
|
||||
function UrlListRenderer({ content }: { content: string }) {
|
||||
const urls = content.match(/https?:\/\/\S+/g) || [];
|
||||
|
||||
|
||||
return (
|
||||
<div className="p-3">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
|
@ -287,9 +287,9 @@ function UrlListRenderer({ content }: { content: string }) {
|
|||
{urls.map((url, idx) => (
|
||||
<div key={idx} className="flex items-center gap-2">
|
||||
<ExternalLink className="h-3 w-3 text-zinc-500" />
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-xs text-blue-600 dark:text-blue-400 hover:underline truncate"
|
||||
>
|
||||
|
@ -337,21 +337,21 @@ function TextRenderer({ content }: { content: string }) {
|
|||
// Main renderer component
|
||||
export function MCPContentRenderer({ detectionResult, rawContent }: MCPContentRendererProps) {
|
||||
const { format, confidence, metadata, parsedData } = detectionResult;
|
||||
|
||||
|
||||
// Convert content to string if needed
|
||||
const contentStr = typeof rawContent === 'string' ? rawContent : JSON.stringify(rawContent, null, 2);
|
||||
|
||||
|
||||
// Select appropriate renderer based on detected format
|
||||
switch (format) {
|
||||
case ContentFormat.SEARCH_RESULTS:
|
||||
return <SearchResultsRenderer data={parsedData || rawContent} metadata={metadata} />;
|
||||
|
||||
|
||||
case ContentFormat.TABLE:
|
||||
return <TableRenderer data={parsedData || rawContent} />;
|
||||
|
||||
|
||||
case ContentFormat.JSON:
|
||||
return <JsonRenderer data={parsedData || rawContent} />;
|
||||
|
||||
|
||||
case ContentFormat.MARKDOWN:
|
||||
return (
|
||||
<div className="p-3">
|
||||
|
@ -364,19 +364,19 @@ export function MCPContentRenderer({ detectionResult, rawContent }: MCPContentRe
|
|||
<MarkdownRenderer content={contentStr} />
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
case ContentFormat.CSV:
|
||||
return <CsvRenderer content={contentStr} />;
|
||||
|
||||
|
||||
case ContentFormat.KEY_VALUE:
|
||||
return <KeyValueRenderer content={contentStr} />;
|
||||
|
||||
|
||||
case ContentFormat.URL_LIST:
|
||||
return <UrlListRenderer content={contentStr} />;
|
||||
|
||||
|
||||
case ContentFormat.ERROR:
|
||||
return <ErrorRenderer content={contentStr} />;
|
||||
|
||||
|
||||
case ContentFormat.CODE:
|
||||
return (
|
||||
<div className="p-3">
|
||||
|
@ -393,7 +393,7 @@ export function MCPContentRenderer({ detectionResult, rawContent }: MCPContentRe
|
|||
</ScrollArea>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
default:
|
||||
return <TextRenderer content={contentStr} />;
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@ import { ScrollArea } from "@/components/ui/scroll-area";
|
|||
import { formatTimestamp } from '../utils';
|
||||
import { detectMCPFormat } from '../mcp-format-detector';
|
||||
import { MCPContentRenderer } from '../mcp-content-renderer';
|
||||
import {
|
||||
parseMCPResult,
|
||||
parseMCPToolCall,
|
||||
getMCPServerIcon,
|
||||
import {
|
||||
parseMCPResult,
|
||||
parseMCPToolCall,
|
||||
getMCPServerIcon,
|
||||
getMCPServerColor,
|
||||
formatMCPToolDisplayName,
|
||||
MCPResult,
|
||||
|
@ -46,16 +46,16 @@ export function McpToolView({
|
|||
|
||||
const parsedTool = parseMCPToolCall(assistantContent || '');
|
||||
const result = toolContent ? parseMCPResult(toolContent) : null;
|
||||
|
||||
|
||||
const serverName = result?.mcp_metadata?.server_name || parsedTool.serverName;
|
||||
const toolName = result?.mcp_metadata?.tool_name || parsedTool.toolName;
|
||||
const fullToolName = result?.mcp_metadata?.full_tool_name || parsedTool.fullToolName;
|
||||
const argumentsCount = result?.mcp_metadata?.arguments_count ?? Object.keys(parsedTool.arguments).length;
|
||||
|
||||
const displayName = result?.mcp_metadata ?
|
||||
|
||||
const displayName = result?.mcp_metadata ?
|
||||
formatMCPToolDisplayName(serverName, toolName) :
|
||||
parsedTool.displayName;
|
||||
|
||||
|
||||
const ServerIcon = getMCPServerIcon(serverName);
|
||||
const serverColor = getMCPServerColor(serverName);
|
||||
|
||||
|
@ -79,7 +79,7 @@ export function McpToolView({
|
|||
const hasArguments = Object.keys(parsedTool.arguments).length > 0;
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
|
@ -101,13 +101,13 @@ export function McpToolView({
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!isStreaming && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={
|
||||
isSuccess && result && !result.isError
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
|
||||
}
|
||||
>
|
||||
|
@ -149,7 +149,7 @@ export function McpToolView({
|
|||
) : (
|
||||
<ScrollArea className="h-full w-full">
|
||||
<div className="p-4 space-y-4">
|
||||
|
||||
|
||||
{/* Tool Information */}
|
||||
<div className="bg-zinc-50/70 dark:bg-zinc-900/30 p-4 rounded-lg border border-zinc-100 dark:border-zinc-800">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
|
@ -187,7 +187,7 @@ export function McpToolView({
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Show error type if available */}
|
||||
{result?.error_type && (
|
||||
<div className="mt-3 pt-3 border-t border-zinc-200 dark:border-zinc-700">
|
||||
|
@ -208,7 +208,7 @@ export function McpToolView({
|
|||
? "border-emerald-200 dark:border-emerald-800 bg-emerald-50/30 dark:bg-emerald-900/10"
|
||||
: "border-red-200 dark:border-red-800 bg-red-50/30 dark:bg-red-900/10"
|
||||
)}>
|
||||
<div
|
||||
<div
|
||||
className="p-3 cursor-pointer hover:bg-black/5 dark:hover:bg-white/5 transition-colors"
|
||||
onClick={() => setExpandedResult(!expandedResult)}
|
||||
>
|
||||
|
@ -237,10 +237,10 @@ export function McpToolView({
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{expandedResult && (
|
||||
<div className="border-t border-zinc-200 dark:border-zinc-800">
|
||||
<MCPContentRenderer
|
||||
<MCPContentRenderer
|
||||
detectionResult={detectMCPFormat(result.data || '')}
|
||||
rawContent={result.data || ''}
|
||||
/>
|
||||
|
|
|
@ -35,11 +35,11 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
|
|||
'Authorization': `Bearer ${session?.access_token}`
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load image: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
|
||||
const blob = await response.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
setImgSrc(url);
|
||||
|
@ -51,11 +51,11 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
|
|||
setImgSrc(src);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
setupAuthenticatedImage();
|
||||
setError(false);
|
||||
setAttempts(0);
|
||||
|
||||
|
||||
return () => {
|
||||
if (imgSrc && imgSrc.startsWith('blob:')) {
|
||||
URL.revokeObjectURL(imgSrc);
|
||||
|
@ -67,7 +67,7 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
|
|||
if (attempts < 3) {
|
||||
setAttempts(attempts + 1);
|
||||
console.log(`Image load failed (attempt ${attempts + 1}). Trying alternative:`, filePath);
|
||||
|
||||
|
||||
if (attempts === 0) {
|
||||
setImgSrc(filePath);
|
||||
} else if (attempts === 1) {
|
||||
|
@ -103,7 +103,7 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
|
|||
const handleDownload = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
if (!imgSrc) return;
|
||||
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = imgSrc;
|
||||
link.download = filePath.split('/').pop() || 'image';
|
||||
|
@ -146,7 +146,7 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
|
|||
return (
|
||||
<div className="flex flex-col items-center">
|
||||
<div className={cn(
|
||||
"overflow-hidden transition-all duration-300 rounded-lg border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 mb-3",
|
||||
"overflow-hidden transition-all duration-300 rounded-3xl border bg-card mb-3",
|
||||
isZoomed ? "cursor-zoom-out" : "cursor-zoom-in"
|
||||
)}>
|
||||
<div className="relative flex items-center justify-center">
|
||||
|
@ -156,8 +156,8 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
|
|||
onClick={handleZoomToggle}
|
||||
className={cn(
|
||||
"max-w-full object-contain transition-all duration-300 ease-in-out",
|
||||
isZoomed
|
||||
? "max-h-[80vh]"
|
||||
isZoomed
|
||||
? "max-h-[80vh]"
|
||||
: "max-h-[500px] hover:scale-[1.01]",
|
||||
className
|
||||
)}
|
||||
|
@ -169,12 +169,12 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between w-full px-2 py-2 bg-zinc-50 dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
|
||||
<div className="flex items-center justify-between w-full px-2 py-2 bg-zinc-50 dark:bg-zinc-900 rounded-2xl border border-zinc-200 dark:border-zinc-800">
|
||||
<Badge variant="secondary" className="bg-white/90 dark:bg-black/70 text-zinc-700 dark:text-zinc-300 shadow-sm">
|
||||
<ImageIcon className="h-3 w-3 mr-1" />
|
||||
{filePath.split('.').pop()?.toUpperCase()}
|
||||
</Badge>
|
||||
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<Button
|
||||
variant="outline"
|
||||
|
@ -197,9 +197,9 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
|
|||
>
|
||||
<ZoomIn className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
|
||||
<span className="w-px h-6 bg-zinc-200 dark:bg-zinc-700 mx-2"></span>
|
||||
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
|
@ -226,7 +226,7 @@ export function SeeImageToolView({
|
|||
project,
|
||||
}: ToolViewProps) {
|
||||
const [progress, setProgress] = useState(0);
|
||||
|
||||
|
||||
const {
|
||||
filePath,
|
||||
description,
|
||||
|
@ -241,7 +241,7 @@ export function SeeImageToolView({
|
|||
toolTimestamp,
|
||||
assistantTimestamp
|
||||
);
|
||||
|
||||
|
||||
console.log('Final file path:', filePath);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -289,11 +289,11 @@ export function SeeImageToolView({
|
|||
const isAnimated = ['gif', 'webp'].includes(fileExt.toLowerCase());
|
||||
|
||||
return (
|
||||
<Card className="flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-gradient-to-r from-zinc-50/90 to-zinc-100/90 dark:from-zinc-900/90 dark:to-zinc-800/90 backdrop-blur-sm border-b p-2 px-4 space-y-0">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={cn("relative p-2 rounded-lg bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20 transition-colors", config.bgColor)}>
|
||||
<div className={cn("relative p-2 rounded-xl bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20 transition-colors", config.bgColor)}>
|
||||
<ImageIcon className={cn("w-5 h-5", config.color)} />
|
||||
</div>
|
||||
<div>
|
||||
|
@ -309,13 +309,13 @@ export function SeeImageToolView({
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!isStreaming ? (
|
||||
<Badge variant="secondary" className={cn(
|
||||
"px-2.5 py-1 transition-colors flex items-center gap-1.5",
|
||||
actualIsSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
|
||||
"px-2.5 py-1 transition-colors flex items-center gap-1.5",
|
||||
actualIsSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
|
||||
)}>
|
||||
{actualIsSuccess ? (
|
||||
<>
|
||||
|
@ -337,7 +337,7 @@ export function SeeImageToolView({
|
|||
)}
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
|
||||
<CardContent className="p-0 flex-1 overflow-hidden relative">
|
||||
{isStreaming ? (
|
||||
<div className="flex flex-col items-center justify-center h-full p-12 bg-gradient-to-b from-white to-zinc-50 dark:from-zinc-950 dark:to-zinc-900">
|
||||
|
@ -349,7 +349,7 @@ export function SeeImageToolView({
|
|||
</div>
|
||||
<Skeleton className="h-48 w-full rounded-lg mb-6" />
|
||||
<div className="w-full h-2 bg-zinc-200 dark:bg-zinc-700 rounded-full overflow-hidden">
|
||||
<div
|
||||
<div
|
||||
className="h-full bg-gradient-to-r from-blue-400 to-blue-500 dark:from-blue-600 dark:to-blue-400 rounded-full transition-all duration-300 ease-out"
|
||||
style={{ width: `${progress}%` }}
|
||||
></div>
|
||||
|
@ -370,7 +370,7 @@ export function SeeImageToolView({
|
|||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
|
||||
<div className="h-10 px-4 py-2 bg-gradient-to-r from-zinc-50/90 to-zinc-100/90 dark:from-zinc-900/90 dark:to-zinc-800/90 backdrop-blur-sm border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center">
|
||||
<div className="flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400">
|
||||
<Badge className="py-0.5 h-6 bg-gradient-to-b from-blue-50 to-blue-100 text-blue-700 border border-blue-200/50 dark:from-blue-900/30 dark:to-blue-800/20 dark:text-blue-400 dark:border-blue-800/30">
|
||||
|
@ -383,7 +383,7 @@ export function SeeImageToolView({
|
|||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{actualToolTimestamp && !isStreaming
|
||||
? formatTimestamp(actualToolTimestamp)
|
||||
|
|
|
@ -219,7 +219,7 @@ export function StrReplaceToolView({
|
|||
const shouldShowError = !isStreaming && (!oldStr || !newStr) && (assistantContent || toolContent);
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -275,7 +275,7 @@ export function StrReplaceToolView({
|
|||
<ScrollArea className="h-full w-full">
|
||||
<div className="p-4">
|
||||
<div className="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg overflow-hidden mb-4">
|
||||
<div className="p-3 border-b border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900 flex items-center justify-between">
|
||||
<div className="p-3 border-b border-zinc-200 dark:border-zinc-800 bg-accent flex items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
<File className="h-4 w-4 mr-2 text-zinc-500 dark:text-zinc-400" />
|
||||
<code className="text-xs font-mono text-zinc-700 dark:text-zinc-300">
|
||||
|
|
|
@ -118,7 +118,7 @@ export function WebScrapeToolView({
|
|||
const timestampMatch = filePath.match(/(\d{8}_\d{6})/);
|
||||
const domainMatch = filePath.match(/(\w+)_com\.json$/);
|
||||
const fileName = filePath.split('/').pop() || filePath;
|
||||
|
||||
|
||||
return {
|
||||
timestamp: timestampMatch ? timestampMatch[1] : '',
|
||||
domain: domainMatch ? domainMatch[1] : 'unknown',
|
||||
|
@ -128,27 +128,27 @@ export function WebScrapeToolView({
|
|||
};
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative p-2 rounded-lg bg-gradient-to-br from-primary/20 to-primary/10 border border-primary/20">
|
||||
<Globe className="w-5 h-5 text-primary" />
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<CardTitle className="text-base font-medium text-zinc-900 dark:text-zinc-100">
|
||||
{toolTitle}
|
||||
</CardTitle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!isStreaming && (
|
||||
<Badge
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={
|
||||
actualIsSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
actualIsSuccess
|
||||
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
|
||||
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
|
||||
}
|
||||
>
|
||||
|
@ -193,21 +193,21 @@ export function WebScrapeToolView({
|
|||
<div className="group relative">
|
||||
<div className="flex items-center gap-3 p-4 bg-zinc-50 dark:bg-zinc-900 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors rounded-xl border border-zinc-200 dark:border-zinc-800">
|
||||
{favicon && (
|
||||
<img
|
||||
src={favicon}
|
||||
alt=""
|
||||
<img
|
||||
src={favicon}
|
||||
alt=""
|
||||
className="w-6 h-6 rounded-md flex-shrink-0"
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).style.display = 'none';
|
||||
}}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="font-mono text-sm text-zinc-900 dark:text-zinc-100 truncate">{truncateString(url, 70)}</p>
|
||||
<p className="text-xs text-zinc-500 dark:text-zinc-400 mt-1">{domain}</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="opacity-70 group-hover:opacity-100 transition-opacity"
|
||||
asChild
|
||||
|
@ -238,17 +238,17 @@ export function WebScrapeToolView({
|
|||
{files.map((filePath, idx) => {
|
||||
const fileInfo = formatFileInfo(filePath);
|
||||
const isCopied = copiedFile === filePath;
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
<div
|
||||
key={idx}
|
||||
className="group relative bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-4 hover:border-zinc-300 dark:hover:border-zinc-700 transition-all duration-200 hover:shadow-sm"
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-green-500/20 to-green-600/10 flex items-center justify-center border border-green-500/20 flex-shrink-0">
|
||||
<FileText className="w-5 h-5 text-green-600 dark:text-green-400" />
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex-1 min-w-0 space-y-2">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<Badge variant="outline" className="text-xs font-normal">
|
||||
|
@ -261,7 +261,7 @@ export function WebScrapeToolView({
|
|||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="space-y-1">
|
||||
<p className="font-mono text-sm text-zinc-900 dark:text-zinc-100 font-medium">
|
||||
{fileInfo.fileName}
|
||||
|
@ -324,7 +324,7 @@ export function WebScrapeToolView({
|
|||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
|
||||
{/* Footer */}
|
||||
<div className="px-4 py-2 h-10 bg-gradient-to-r from-zinc-50/90 to-zinc-100/90 dark:from-zinc-900/90 dark:to-zinc-800/90 backdrop-blur-sm border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center gap-4">
|
||||
<div className="h-full flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400">
|
||||
|
@ -335,7 +335,7 @@ export function WebScrapeToolView({
|
|||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{actualToolTimestamp && !isStreaming
|
||||
? formatTimestamp(actualToolTimestamp)
|
||||
|
|
|
@ -87,11 +87,11 @@ export function WebSearchToolView({
|
|||
};
|
||||
|
||||
return (
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
|
||||
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
|
||||
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative p-2 rounded-lg bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
|
||||
<div className="relative p-2 rounded-xl bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
|
||||
<Search className="w-5 h-5 text-blue-500 dark:text-blue-400" />
|
||||
</div>
|
||||
<div>
|
||||
|
@ -194,7 +194,7 @@ export function WebSearchToolView({
|
|||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg shadow-sm hover:shadow transition-shadow"
|
||||
className="bg-card border rounded-lg shadow-sm hover:shadow transition-shadow"
|
||||
>
|
||||
<div className="p-4">
|
||||
<div className="flex items-start gap-3 mb-2">
|
||||
|
|
|
@ -54,7 +54,7 @@ function AlertDialogContent({
|
|||
<AlertDialogPrimitive.Content
|
||||
data-slot="alert-dialog-content"
|
||||
className={cn(
|
||||
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-xl border p-6 shadow-lg duration-200 sm:max-w-lg',
|
||||
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-2xl border p-6 shadow-lg duration-200 sm:max-w-lg',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
|
|||
import { cn } from '@/lib/utils';
|
||||
|
||||
const alertVariants = cva(
|
||||
'relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
|
||||
'relative w-full rounded-xl border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
|
|
@ -5,7 +5,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
|
|||
import { cn } from '@/lib/utils';
|
||||
|
||||
const badgeVariants = cva(
|
||||
'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
|
||||
'inline-flex items-center justify-center rounded-lg border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
|
|
@ -15,6 +15,7 @@ const Toaster = ({ ...props }: ToasterProps) => {
|
|||
'--normal-bg': 'var(--popover)',
|
||||
'--normal-text': 'var(--popover-foreground)',
|
||||
'--normal-border': 'var(--border)',
|
||||
'--border-radius': '1rem',
|
||||
} as React.CSSProperties
|
||||
}
|
||||
{...props}
|
||||
|
|
Loading…
Reference in New Issue