Spaces:
Running
Running
Commit
·
fe018ce
1
Parent(s):
7e02504
removed avatars and made ui improvements
Browse files- agent/core/agent_loop.py +0 -2
- frontend/src/components/Chat/AssistantMessage.tsx +39 -54
- frontend/src/components/Chat/MarkdownContent.tsx +0 -21
- frontend/src/components/Chat/UserMessage.tsx +1 -15
- frontend/src/components/CodePanel/CodePanel.tsx +184 -6
- frontend/src/components/SessionSidebar/SessionSidebar.tsx +2 -2
- frontend/src/components/WelcomeScreen/WelcomeScreen.tsx +9 -9
- frontend/src/store/agentStore.ts +29 -0
- frontend/src/theme.ts +11 -11
agent/core/agent_loop.py
CHANGED
|
@@ -147,8 +147,6 @@ class Handlers:
|
|
| 147 |
while iteration < max_iterations:
|
| 148 |
messages = session.context_manager.get_messages()
|
| 149 |
tools = session.tool_router.get_tool_specs_for_llm()
|
| 150 |
-
logger.info(f"_INFERENCE_API_KEY {_INFERENCE_API_KEY} {session.config.model_name.startswith('huggingface/')}")
|
| 151 |
-
|
| 152 |
try:
|
| 153 |
# ── Stream the LLM response ──────────────────────────
|
| 154 |
response = await acompletion(
|
|
|
|
| 147 |
while iteration < max_iterations:
|
| 148 |
messages = session.context_manager.get_messages()
|
| 149 |
tools = session.tool_router.get_tool_specs_for_llm()
|
|
|
|
|
|
|
| 150 |
try:
|
| 151 |
# ── Stream the LLM response ──────────────────────────
|
| 152 |
response = await acompletion(
|
frontend/src/components/Chat/AssistantMessage.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
-
import { Box, Stack,
|
| 2 |
-
import SmartToyOutlinedIcon from '@mui/icons-material/SmartToyOutlined';
|
| 3 |
import MarkdownContent from './MarkdownContent';
|
| 4 |
import ToolCallGroup from './ToolCallGroup';
|
| 5 |
import type { Message } from '@/types/agent';
|
|
@@ -48,61 +47,47 @@ export default function AssistantMessage({ message, isStreaming = false }: Assis
|
|
| 48 |
};
|
| 49 |
|
| 50 |
return (
|
| 51 |
-
<
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
<
|
| 67 |
-
|
| 68 |
-
variant="caption"
|
| 69 |
-
sx={{
|
| 70 |
-
fontWeight: 700,
|
| 71 |
-
fontSize: '0.72rem',
|
| 72 |
-
color: 'var(--muted-text)',
|
| 73 |
-
textTransform: 'uppercase',
|
| 74 |
-
letterSpacing: '0.04em',
|
| 75 |
-
}}
|
| 76 |
-
>
|
| 77 |
-
Assistant
|
| 78 |
-
</Typography>
|
| 79 |
-
<Typography
|
| 80 |
-
variant="caption"
|
| 81 |
-
sx={{
|
| 82 |
-
fontSize: '0.66rem',
|
| 83 |
-
color: 'var(--muted-text)',
|
| 84 |
-
opacity: 0.6,
|
| 85 |
-
}}
|
| 86 |
-
>
|
| 87 |
-
{new Date(message.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
|
| 88 |
-
</Typography>
|
| 89 |
-
</Stack>
|
| 90 |
-
|
| 91 |
-
{/* Message bubble */}
|
| 92 |
-
<Box
|
| 93 |
sx={{
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
borderTopLeftRadius: 4,
|
| 98 |
-
px: { xs: 1.5, md: 2.5 },
|
| 99 |
-
py: 1.5,
|
| 100 |
-
border: '1px solid var(--border)',
|
| 101 |
}}
|
| 102 |
>
|
| 103 |
-
{
|
| 104 |
-
</
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
</Box>
|
| 106 |
-
</
|
| 107 |
);
|
| 108 |
}
|
|
|
|
| 1 |
+
import { Box, Stack, Typography } from '@mui/material';
|
|
|
|
| 2 |
import MarkdownContent from './MarkdownContent';
|
| 3 |
import ToolCallGroup from './ToolCallGroup';
|
| 4 |
import type { Message } from '@/types/agent';
|
|
|
|
| 47 |
};
|
| 48 |
|
| 49 |
return (
|
| 50 |
+
<Box sx={{ minWidth: 0 }}>
|
| 51 |
+
{/* Role label + timestamp */}
|
| 52 |
+
<Stack direction="row" alignItems="baseline" spacing={1} sx={{ mb: 0.5 }}>
|
| 53 |
+
<Typography
|
| 54 |
+
variant="caption"
|
| 55 |
+
sx={{
|
| 56 |
+
fontWeight: 700,
|
| 57 |
+
fontSize: '0.72rem',
|
| 58 |
+
color: 'var(--muted-text)',
|
| 59 |
+
textTransform: 'uppercase',
|
| 60 |
+
letterSpacing: '0.04em',
|
| 61 |
+
}}
|
| 62 |
+
>
|
| 63 |
+
Assistant
|
| 64 |
+
</Typography>
|
| 65 |
+
<Typography
|
| 66 |
+
variant="caption"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
sx={{
|
| 68 |
+
fontSize: '0.66rem',
|
| 69 |
+
color: 'var(--muted-text)',
|
| 70 |
+
opacity: 0.6,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
}}
|
| 72 |
>
|
| 73 |
+
{new Date(message.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
|
| 74 |
+
</Typography>
|
| 75 |
+
</Stack>
|
| 76 |
+
|
| 77 |
+
{/* Message bubble */}
|
| 78 |
+
<Box
|
| 79 |
+
sx={{
|
| 80 |
+
maxWidth: { xs: '95%', md: '85%' },
|
| 81 |
+
bgcolor: 'var(--surface)',
|
| 82 |
+
borderRadius: 1.5,
|
| 83 |
+
borderTopLeftRadius: 4,
|
| 84 |
+
px: { xs: 1.5, md: 2.5 },
|
| 85 |
+
py: 1.5,
|
| 86 |
+
border: '1px solid var(--border)',
|
| 87 |
+
}}
|
| 88 |
+
>
|
| 89 |
+
{renderSegments()}
|
| 90 |
</Box>
|
| 91 |
+
</Box>
|
| 92 |
);
|
| 93 |
}
|
frontend/src/components/Chat/MarkdownContent.tsx
CHANGED
|
@@ -94,26 +94,6 @@ const markdownSx: SxProps<Theme> = {
|
|
| 94 |
},
|
| 95 |
};
|
| 96 |
|
| 97 |
-
/** Blinking cursor shown at the end of streaming text. */
|
| 98 |
-
const StreamingCursor = () => (
|
| 99 |
-
<Box
|
| 100 |
-
component="span"
|
| 101 |
-
sx={{
|
| 102 |
-
display: 'inline-block',
|
| 103 |
-
width: '2px',
|
| 104 |
-
height: '1.1em',
|
| 105 |
-
bgcolor: 'var(--text)',
|
| 106 |
-
ml: '2px',
|
| 107 |
-
verticalAlign: 'text-bottom',
|
| 108 |
-
animation: 'cursorBlink 1s step-end infinite',
|
| 109 |
-
'@keyframes cursorBlink': {
|
| 110 |
-
'0%, 100%': { opacity: 1 },
|
| 111 |
-
'50%': { opacity: 0 },
|
| 112 |
-
},
|
| 113 |
-
}}
|
| 114 |
-
/>
|
| 115 |
-
);
|
| 116 |
-
|
| 117 |
/**
|
| 118 |
* Throttled content for streaming: render the full markdown through
|
| 119 |
* ReactMarkdown but only re-parse every ~80ms to avoid layout thrashing.
|
|
@@ -175,7 +155,6 @@ export default function MarkdownContent({ content, sx, isStreaming = false }: Ma
|
|
| 175 |
return (
|
| 176 |
<Box sx={[markdownSx, ...(Array.isArray(sx) ? sx : sx ? [sx] : [])]}>
|
| 177 |
<ReactMarkdown remarkPlugins={remarkPlugins}>{displayContent}</ReactMarkdown>
|
| 178 |
-
{isStreaming && <StreamingCursor />}
|
| 179 |
</Box>
|
| 180 |
);
|
| 181 |
}
|
|
|
|
| 94 |
},
|
| 95 |
};
|
| 96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
/**
|
| 98 |
* Throttled content for streaming: render the full markdown through
|
| 99 |
* ReactMarkdown but only re-parse every ~80ms to avoid layout thrashing.
|
|
|
|
| 155 |
return (
|
| 156 |
<Box sx={[markdownSx, ...(Array.isArray(sx) ? sx : sx ? [sx] : [])]}>
|
| 157 |
<ReactMarkdown remarkPlugins={remarkPlugins}>{displayContent}</ReactMarkdown>
|
|
|
|
| 158 |
</Box>
|
| 159 |
);
|
| 160 |
}
|
frontend/src/components/Chat/UserMessage.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
-
import { Box, Stack, Typography,
|
| 2 |
-
import PersonOutlineIcon from '@mui/icons-material/PersonOutline';
|
| 3 |
import CloseIcon from '@mui/icons-material/Close';
|
| 4 |
import type { Message } from '@/types/agent';
|
| 5 |
|
|
@@ -99,19 +98,6 @@ export default function UserMessage({
|
|
| 99 |
{new Date(message.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
|
| 100 |
</Typography>
|
| 101 |
</Box>
|
| 102 |
-
|
| 103 |
-
<Avatar
|
| 104 |
-
sx={{
|
| 105 |
-
width: 28,
|
| 106 |
-
height: 28,
|
| 107 |
-
bgcolor: 'var(--hover-bg)',
|
| 108 |
-
border: '1px solid var(--border)',
|
| 109 |
-
flexShrink: 0,
|
| 110 |
-
mt: 0.5,
|
| 111 |
-
}}
|
| 112 |
-
>
|
| 113 |
-
<PersonOutlineIcon sx={{ fontSize: 16, color: 'var(--muted-text)' }} />
|
| 114 |
-
</Avatar>
|
| 115 |
</Stack>
|
| 116 |
);
|
| 117 |
}
|
|
|
|
| 1 |
+
import { Box, Stack, Typography, IconButton, Tooltip } from '@mui/material';
|
|
|
|
| 2 |
import CloseIcon from '@mui/icons-material/Close';
|
| 3 |
import type { Message } from '@/types/agent';
|
| 4 |
|
|
|
|
| 98 |
{new Date(message.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
|
| 99 |
</Typography>
|
| 100 |
</Box>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
</Stack>
|
| 102 |
);
|
| 103 |
}
|
frontend/src/components/CodePanel/CodePanel.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
-
import { useRef, useEffect, useMemo } from 'react';
|
| 2 |
-
import { Box, Stack, Typography, IconButton } from '@mui/material';
|
| 3 |
import CloseIcon from '@mui/icons-material/Close';
|
| 4 |
import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked';
|
| 5 |
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|
@@ -7,6 +7,10 @@ import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline';
|
|
| 7 |
import CodeIcon from '@mui/icons-material/Code';
|
| 8 |
import TerminalIcon from '@mui/icons-material/Terminal';
|
| 9 |
import ArticleIcon from '@mui/icons-material/Article';
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
| 11 |
import { vscDarkPlus, vs } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
| 12 |
import ReactMarkdown from 'react-markdown';
|
|
@@ -92,10 +96,15 @@ const markdownSx = {
|
|
| 92 |
// ── Component ────────────────────────────────────────────────────
|
| 93 |
|
| 94 |
export default function CodePanel() {
|
| 95 |
-
const { panelContent, panelTabs, activePanelTab, setActivePanelTab, removePanelTab, plan } =
|
| 96 |
useAgentStore();
|
| 97 |
const { setRightPanelOpen, themeMode } = useLayoutStore();
|
| 98 |
const scrollRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
|
| 100 |
const activeTab = panelTabs.find((t) => t.id === activePanelTab);
|
| 101 |
const currentContent = activeTab || panelContent;
|
|
@@ -104,6 +113,66 @@ export default function CodePanel() {
|
|
| 104 |
const isDark = themeMode === 'dark';
|
| 105 |
const syntaxTheme = isDark ? vscDarkPlus : vs;
|
| 106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
const displayContent = useMemo(() => {
|
| 108 |
if (!currentContent?.content) return '';
|
| 109 |
if (!currentContent.language || currentContent.language === 'text') {
|
|
@@ -147,6 +216,30 @@ export default function CodePanel() {
|
|
| 147 |
);
|
| 148 |
}
|
| 149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
if (currentContent.language === 'python') return renderSyntaxBlock('python');
|
| 151 |
if (currentContent.language === 'json') return renderSyntaxBlock('json');
|
| 152 |
|
|
@@ -247,9 +340,94 @@ export default function CodePanel() {
|
|
| 247 |
</Typography>
|
| 248 |
)}
|
| 249 |
|
| 250 |
-
<
|
| 251 |
-
|
| 252 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
</Box>
|
| 254 |
|
| 255 |
{/* ── Main content area ─────────────────────────────────── */}
|
|
|
|
| 1 |
+
import { useRef, useEffect, useMemo, useState, useCallback } from 'react';
|
| 2 |
+
import { Box, Stack, Typography, IconButton, Button, Tooltip } from '@mui/material';
|
| 3 |
import CloseIcon from '@mui/icons-material/Close';
|
| 4 |
import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked';
|
| 5 |
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|
|
|
| 7 |
import CodeIcon from '@mui/icons-material/Code';
|
| 8 |
import TerminalIcon from '@mui/icons-material/Terminal';
|
| 9 |
import ArticleIcon from '@mui/icons-material/Article';
|
| 10 |
+
import EditIcon from '@mui/icons-material/Edit';
|
| 11 |
+
import UndoIcon from '@mui/icons-material/Undo';
|
| 12 |
+
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
| 13 |
+
import CheckIcon from '@mui/icons-material/Check';
|
| 14 |
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
| 15 |
import { vscDarkPlus, vs } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
| 16 |
import ReactMarkdown from 'react-markdown';
|
|
|
|
| 96 |
// ── Component ────────────────────────────────────────────────────
|
| 97 |
|
| 98 |
export default function CodePanel() {
|
| 99 |
+
const { panelContent, panelTabs, activePanelTab, setActivePanelTab, removePanelTab, plan, updatePanelTabContent, setEditedScript } =
|
| 100 |
useAgentStore();
|
| 101 |
const { setRightPanelOpen, themeMode } = useLayoutStore();
|
| 102 |
const scrollRef = useRef<HTMLDivElement>(null);
|
| 103 |
+
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
| 104 |
+
const [isEditing, setIsEditing] = useState(false);
|
| 105 |
+
const [editedContent, setEditedContent] = useState('');
|
| 106 |
+
const [originalContent, setOriginalContent] = useState('');
|
| 107 |
+
const [copied, setCopied] = useState(false);
|
| 108 |
|
| 109 |
const activeTab = panelTabs.find((t) => t.id === activePanelTab);
|
| 110 |
const currentContent = activeTab || panelContent;
|
|
|
|
| 113 |
const isDark = themeMode === 'dark';
|
| 114 |
const syntaxTheme = isDark ? vscDarkPlus : vs;
|
| 115 |
|
| 116 |
+
// Check if this is an editable script tab
|
| 117 |
+
const isEditableScript = activeTab?.id === 'script' && activeTab?.language === 'python';
|
| 118 |
+
const hasUnsavedChanges = isEditing && editedContent !== originalContent;
|
| 119 |
+
|
| 120 |
+
// Sync edited content when switching tabs or content changes
|
| 121 |
+
useEffect(() => {
|
| 122 |
+
if (currentContent?.content && isEditableScript) {
|
| 123 |
+
setOriginalContent(currentContent.content);
|
| 124 |
+
if (!isEditing) {
|
| 125 |
+
setEditedContent(currentContent.content);
|
| 126 |
+
}
|
| 127 |
+
}
|
| 128 |
+
}, [currentContent?.content, isEditableScript, isEditing]);
|
| 129 |
+
|
| 130 |
+
// Exit editing when switching away from script tab
|
| 131 |
+
useEffect(() => {
|
| 132 |
+
if (!isEditableScript && isEditing) {
|
| 133 |
+
setIsEditing(false);
|
| 134 |
+
}
|
| 135 |
+
}, [isEditableScript, isEditing]);
|
| 136 |
+
|
| 137 |
+
const handleStartEdit = useCallback(() => {
|
| 138 |
+
if (currentContent?.content) {
|
| 139 |
+
setEditedContent(currentContent.content);
|
| 140 |
+
setOriginalContent(currentContent.content);
|
| 141 |
+
setIsEditing(true);
|
| 142 |
+
setTimeout(() => textareaRef.current?.focus(), 0);
|
| 143 |
+
}
|
| 144 |
+
}, [currentContent?.content]);
|
| 145 |
+
|
| 146 |
+
const handleCancelEdit = useCallback(() => {
|
| 147 |
+
setEditedContent(originalContent);
|
| 148 |
+
setIsEditing(false);
|
| 149 |
+
}, [originalContent]);
|
| 150 |
+
|
| 151 |
+
const handleSaveEdit = useCallback(() => {
|
| 152 |
+
if (activeTab && editedContent !== originalContent) {
|
| 153 |
+
updatePanelTabContent(activeTab.id, editedContent);
|
| 154 |
+
const toolCallId = activeTab.parameters?.tool_call_id as string | undefined;
|
| 155 |
+
if (toolCallId) {
|
| 156 |
+
setEditedScript(toolCallId, editedContent);
|
| 157 |
+
}
|
| 158 |
+
setOriginalContent(editedContent);
|
| 159 |
+
}
|
| 160 |
+
setIsEditing(false);
|
| 161 |
+
}, [activeTab, editedContent, originalContent, updatePanelTabContent, setEditedScript]);
|
| 162 |
+
|
| 163 |
+
const handleCopy = useCallback(async () => {
|
| 164 |
+
const contentToCopy = isEditing ? editedContent : (currentContent?.content || '');
|
| 165 |
+
if (contentToCopy) {
|
| 166 |
+
try {
|
| 167 |
+
await navigator.clipboard.writeText(contentToCopy);
|
| 168 |
+
setCopied(true);
|
| 169 |
+
setTimeout(() => setCopied(false), 2000);
|
| 170 |
+
} catch (err) {
|
| 171 |
+
console.error('Failed to copy:', err);
|
| 172 |
+
}
|
| 173 |
+
}
|
| 174 |
+
}, [isEditing, editedContent, currentContent?.content]);
|
| 175 |
+
|
| 176 |
const displayContent = useMemo(() => {
|
| 177 |
if (!currentContent?.content) return '';
|
| 178 |
if (!currentContent.language || currentContent.language === 'text') {
|
|
|
|
| 216 |
);
|
| 217 |
}
|
| 218 |
|
| 219 |
+
// Editing mode: show textarea
|
| 220 |
+
if (isEditing && isEditableScript) {
|
| 221 |
+
return (
|
| 222 |
+
<textarea
|
| 223 |
+
ref={textareaRef}
|
| 224 |
+
value={editedContent}
|
| 225 |
+
onChange={(e) => setEditedContent(e.target.value)}
|
| 226 |
+
spellCheck={false}
|
| 227 |
+
style={{
|
| 228 |
+
width: '100%',
|
| 229 |
+
height: '100%',
|
| 230 |
+
background: 'transparent',
|
| 231 |
+
border: 'none',
|
| 232 |
+
outline: 'none',
|
| 233 |
+
resize: 'none',
|
| 234 |
+
color: 'var(--text)',
|
| 235 |
+
fontFamily: '"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, monospace',
|
| 236 |
+
fontSize: '13px',
|
| 237 |
+
lineHeight: 1.55,
|
| 238 |
+
}}
|
| 239 |
+
/>
|
| 240 |
+
);
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
if (currentContent.language === 'python') return renderSyntaxBlock('python');
|
| 244 |
if (currentContent.language === 'json') return renderSyntaxBlock('json');
|
| 245 |
|
|
|
|
| 340 |
</Typography>
|
| 341 |
)}
|
| 342 |
|
| 343 |
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
| 344 |
+
{/* Copy button */}
|
| 345 |
+
{currentContent?.content && (
|
| 346 |
+
<Tooltip title={copied ? 'Copied!' : 'Copy'} placement="top">
|
| 347 |
+
<IconButton
|
| 348 |
+
size="small"
|
| 349 |
+
onClick={handleCopy}
|
| 350 |
+
sx={{
|
| 351 |
+
color: copied ? 'var(--accent-green)' : 'var(--muted-text)',
|
| 352 |
+
'&:hover': {
|
| 353 |
+
color: 'var(--accent-yellow)',
|
| 354 |
+
bgcolor: 'var(--hover-bg)',
|
| 355 |
+
},
|
| 356 |
+
}}
|
| 357 |
+
>
|
| 358 |
+
{copied ? <CheckIcon sx={{ fontSize: 18 }} /> : <ContentCopyIcon sx={{ fontSize: 18 }} />}
|
| 359 |
+
</IconButton>
|
| 360 |
+
</Tooltip>
|
| 361 |
+
)}
|
| 362 |
+
{/* Edit controls for script tab */}
|
| 363 |
+
{isEditableScript && !isEditing && (
|
| 364 |
+
<Button
|
| 365 |
+
size="small"
|
| 366 |
+
startIcon={<EditIcon sx={{ fontSize: 14 }} />}
|
| 367 |
+
onClick={handleStartEdit}
|
| 368 |
+
sx={{
|
| 369 |
+
textTransform: 'none',
|
| 370 |
+
color: 'var(--muted-text)',
|
| 371 |
+
fontSize: '0.75rem',
|
| 372 |
+
py: 0.5,
|
| 373 |
+
'&:hover': {
|
| 374 |
+
color: 'var(--accent-yellow)',
|
| 375 |
+
bgcolor: 'var(--hover-bg)',
|
| 376 |
+
},
|
| 377 |
+
}}
|
| 378 |
+
>
|
| 379 |
+
Edit
|
| 380 |
+
</Button>
|
| 381 |
+
)}
|
| 382 |
+
{isEditing && (
|
| 383 |
+
<>
|
| 384 |
+
<Button
|
| 385 |
+
size="small"
|
| 386 |
+
startIcon={<UndoIcon sx={{ fontSize: 14 }} />}
|
| 387 |
+
onClick={handleCancelEdit}
|
| 388 |
+
sx={{
|
| 389 |
+
textTransform: 'none',
|
| 390 |
+
color: 'var(--muted-text)',
|
| 391 |
+
fontSize: '0.75rem',
|
| 392 |
+
py: 0.5,
|
| 393 |
+
'&:hover': {
|
| 394 |
+
color: 'var(--accent-red)',
|
| 395 |
+
bgcolor: 'var(--hover-bg)',
|
| 396 |
+
},
|
| 397 |
+
}}
|
| 398 |
+
>
|
| 399 |
+
Cancel
|
| 400 |
+
</Button>
|
| 401 |
+
<Button
|
| 402 |
+
size="small"
|
| 403 |
+
variant="contained"
|
| 404 |
+
onClick={handleSaveEdit}
|
| 405 |
+
disabled={!hasUnsavedChanges}
|
| 406 |
+
sx={{
|
| 407 |
+
textTransform: 'none',
|
| 408 |
+
fontSize: '0.75rem',
|
| 409 |
+
py: 0.5,
|
| 410 |
+
bgcolor: hasUnsavedChanges ? 'var(--accent-green)' : 'var(--hover-bg)',
|
| 411 |
+
color: hasUnsavedChanges ? '#000' : 'var(--muted-text)',
|
| 412 |
+
'&:hover': {
|
| 413 |
+
bgcolor: hasUnsavedChanges ? 'var(--accent-green)' : 'var(--hover-bg)',
|
| 414 |
+
opacity: 0.9,
|
| 415 |
+
},
|
| 416 |
+
'&.Mui-disabled': {
|
| 417 |
+
bgcolor: 'var(--hover-bg)',
|
| 418 |
+
color: 'var(--muted-text)',
|
| 419 |
+
opacity: 0.5,
|
| 420 |
+
},
|
| 421 |
+
}}
|
| 422 |
+
>
|
| 423 |
+
Save
|
| 424 |
+
</Button>
|
| 425 |
+
</>
|
| 426 |
+
)}
|
| 427 |
+
<IconButton size="small" onClick={() => setRightPanelOpen(false)} sx={{ color: 'var(--muted-text)' }}>
|
| 428 |
+
<CloseIcon fontSize="small" />
|
| 429 |
+
</IconButton>
|
| 430 |
+
</Box>
|
| 431 |
</Box>
|
| 432 |
|
| 433 |
{/* ── Main content area ─────────────────────────────────── */}
|
frontend/src/components/SessionSidebar/SessionSidebar.tsx
CHANGED
|
@@ -130,7 +130,7 @@ export default function SessionSidebar({ onClose }: SessionSidebarProps) {
|
|
| 130 |
fontSize: '0.7rem',
|
| 131 |
py: 0.25,
|
| 132 |
'& .MuiAlert-message': { py: 0 },
|
| 133 |
-
borderColor: '#
|
| 134 |
color: 'var(--text)',
|
| 135 |
}}
|
| 136 |
>
|
|
@@ -296,7 +296,7 @@ export default function SessionSidebar({ onClose }: SessionSidebarProps) {
|
|
| 296 |
py: 1.25,
|
| 297 |
border: 'none',
|
| 298 |
borderRadius: '10px',
|
| 299 |
-
bgcolor: '#
|
| 300 |
color: '#000',
|
| 301 |
fontSize: '0.85rem',
|
| 302 |
fontWeight: 700,
|
|
|
|
| 130 |
fontSize: '0.7rem',
|
| 131 |
py: 0.25,
|
| 132 |
'& .MuiAlert-message': { py: 0 },
|
| 133 |
+
borderColor: '#C7A500',
|
| 134 |
color: 'var(--text)',
|
| 135 |
}}
|
| 136 |
>
|
|
|
|
| 296 |
py: 1.25,
|
| 297 |
border: 'none',
|
| 298 |
borderRadius: '10px',
|
| 299 |
+
bgcolor: '#C7A500',
|
| 300 |
color: '#000',
|
| 301 |
fontSize: '0.85rem',
|
| 302 |
fontWeight: 700,
|
frontend/src/components/WelcomeScreen/WelcomeScreen.tsx
CHANGED
|
@@ -12,8 +12,8 @@ import { useAgentStore } from '@/store/agentStore';
|
|
| 12 |
import { apiFetch } from '@/utils/api';
|
| 13 |
import { isInIframe, triggerLogin } from '@/hooks/useAuth';
|
| 14 |
|
| 15 |
-
/** HF brand
|
| 16 |
-
const HF_ORANGE = '#
|
| 17 |
|
| 18 |
export default function WelcomeScreen() {
|
| 19 |
const { createSession } = useSessionStore();
|
|
@@ -149,11 +149,11 @@ export default function WelcomeScreen() {
|
|
| 149 |
borderRadius: '12px',
|
| 150 |
bgcolor: HF_ORANGE,
|
| 151 |
color: '#000',
|
| 152 |
-
boxShadow: '0 4px 24px rgba(
|
| 153 |
textDecoration: 'none',
|
| 154 |
'&:hover': {
|
| 155 |
bgcolor: '#FFB340',
|
| 156 |
-
boxShadow: '0 6px 32px rgba(
|
| 157 |
},
|
| 158 |
}}
|
| 159 |
>
|
|
@@ -174,10 +174,10 @@ export default function WelcomeScreen() {
|
|
| 174 |
borderRadius: '12px',
|
| 175 |
bgcolor: HF_ORANGE,
|
| 176 |
color: '#000',
|
| 177 |
-
boxShadow: '0 4px 24px rgba(
|
| 178 |
'&:hover': {
|
| 179 |
bgcolor: '#FFB340',
|
| 180 |
-
boxShadow: '0 6px 32px rgba(
|
| 181 |
},
|
| 182 |
}}
|
| 183 |
>
|
|
@@ -202,13 +202,13 @@ export default function WelcomeScreen() {
|
|
| 202 |
borderRadius: '12px',
|
| 203 |
bgcolor: HF_ORANGE,
|
| 204 |
color: '#000',
|
| 205 |
-
boxShadow: '0 4px 24px rgba(
|
| 206 |
'&:hover': {
|
| 207 |
bgcolor: '#FFB340',
|
| 208 |
-
boxShadow: '0 6px 32px rgba(
|
| 209 |
},
|
| 210 |
'&.Mui-disabled': {
|
| 211 |
-
bgcolor: 'rgba(
|
| 212 |
color: 'rgba(0,0,0,0.45)',
|
| 213 |
},
|
| 214 |
}}
|
|
|
|
| 12 |
import { apiFetch } from '@/utils/api';
|
| 13 |
import { isInIframe, triggerLogin } from '@/hooks/useAuth';
|
| 14 |
|
| 15 |
+
/** HF brand gold */
|
| 16 |
+
const HF_ORANGE = '#C7A500';
|
| 17 |
|
| 18 |
export default function WelcomeScreen() {
|
| 19 |
const { createSession } = useSessionStore();
|
|
|
|
| 149 |
borderRadius: '12px',
|
| 150 |
bgcolor: HF_ORANGE,
|
| 151 |
color: '#000',
|
| 152 |
+
boxShadow: '0 4px 24px rgba(199, 165, 0, 0.3)',
|
| 153 |
textDecoration: 'none',
|
| 154 |
'&:hover': {
|
| 155 |
bgcolor: '#FFB340',
|
| 156 |
+
boxShadow: '0 6px 32px rgba(199, 165, 0, 0.45)',
|
| 157 |
},
|
| 158 |
}}
|
| 159 |
>
|
|
|
|
| 174 |
borderRadius: '12px',
|
| 175 |
bgcolor: HF_ORANGE,
|
| 176 |
color: '#000',
|
| 177 |
+
boxShadow: '0 4px 24px rgba(199, 165, 0, 0.3)',
|
| 178 |
'&:hover': {
|
| 179 |
bgcolor: '#FFB340',
|
| 180 |
+
boxShadow: '0 6px 32px rgba(199, 165, 0, 0.45)',
|
| 181 |
},
|
| 182 |
}}
|
| 183 |
>
|
|
|
|
| 202 |
borderRadius: '12px',
|
| 203 |
bgcolor: HF_ORANGE,
|
| 204 |
color: '#000',
|
| 205 |
+
boxShadow: '0 4px 24px rgba(199, 165, 0, 0.3)',
|
| 206 |
'&:hover': {
|
| 207 |
bgcolor: '#FFB340',
|
| 208 |
+
boxShadow: '0 6px 32px rgba(199, 165, 0, 0.45)',
|
| 209 |
},
|
| 210 |
'&.Mui-disabled': {
|
| 211 |
+
bgcolor: 'rgba(199, 165, 0, 0.35)',
|
| 212 |
color: 'rgba(0,0,0,0.45)',
|
| 213 |
},
|
| 214 |
}}
|
frontend/src/store/agentStore.ts
CHANGED
|
@@ -36,6 +36,7 @@ interface AgentStore {
|
|
| 36 |
activePanelTab: string | null;
|
| 37 |
plan: PlanItem[];
|
| 38 |
currentTurnMessageId: string | null; // Track the current turn's assistant message
|
|
|
|
| 39 |
|
| 40 |
// Actions
|
| 41 |
addMessage: (sessionId: string, message: Message) => void;
|
|
@@ -51,6 +52,7 @@ interface AgentStore {
|
|
| 51 |
clearTraceLogs: () => void;
|
| 52 |
setPanelContent: (content: { title: string; content: string; language?: string; parameters?: Record<string, unknown> } | null) => void;
|
| 53 |
setPanelTab: (tab: PanelTab) => void;
|
|
|
|
| 54 |
setActivePanelTab: (tabId: string) => void;
|
| 55 |
clearPanelTabs: () => void;
|
| 56 |
removePanelTab: (tabId: string) => void;
|
|
@@ -58,6 +60,9 @@ interface AgentStore {
|
|
| 58 |
setCurrentTurnMessageId: (id: string | null) => void;
|
| 59 |
updateCurrentTurnTrace: (sessionId: string) => void;
|
| 60 |
showToolOutput: (log: TraceLog) => void;
|
|
|
|
|
|
|
|
|
|
| 61 |
/** Append a streaming delta to an existing message. */
|
| 62 |
appendToMessage: (sessionId: string, messageId: string, delta: string) => void;
|
| 63 |
/** Remove all messages for a session (also clears from localStorage). */
|
|
@@ -82,6 +87,7 @@ export const useAgentStore = create<AgentStore>()(
|
|
| 82 |
activePanelTab: null,
|
| 83 |
plan: [],
|
| 84 |
currentTurnMessageId: null,
|
|
|
|
| 85 |
|
| 86 |
addMessage: (sessionId: string, message: Message) => {
|
| 87 |
set((state) => {
|
|
@@ -199,6 +205,15 @@ export const useAgentStore = create<AgentStore>()(
|
|
| 199 |
});
|
| 200 |
},
|
| 201 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
setActivePanelTab: (tabId: string) => {
|
| 203 |
set({ activePanelTab: tabId });
|
| 204 |
},
|
|
@@ -301,6 +316,20 @@ export const useAgentStore = create<AgentStore>()(
|
|
| 301 |
});
|
| 302 |
},
|
| 303 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 304 |
appendToMessage: (sessionId: string, messageId: string, delta: string) => {
|
| 305 |
set((state) => {
|
| 306 |
const messages = state.messagesBySession[sessionId] || [];
|
|
|
|
| 36 |
activePanelTab: string | null;
|
| 37 |
plan: PlanItem[];
|
| 38 |
currentTurnMessageId: string | null; // Track the current turn's assistant message
|
| 39 |
+
editedScripts: Record<string, string>; // tool_call_id -> edited content
|
| 40 |
|
| 41 |
// Actions
|
| 42 |
addMessage: (sessionId: string, message: Message) => void;
|
|
|
|
| 52 |
clearTraceLogs: () => void;
|
| 53 |
setPanelContent: (content: { title: string; content: string; language?: string; parameters?: Record<string, unknown> } | null) => void;
|
| 54 |
setPanelTab: (tab: PanelTab) => void;
|
| 55 |
+
updatePanelTabContent: (tabId: string, content: string) => void;
|
| 56 |
setActivePanelTab: (tabId: string) => void;
|
| 57 |
clearPanelTabs: () => void;
|
| 58 |
removePanelTab: (tabId: string) => void;
|
|
|
|
| 60 |
setCurrentTurnMessageId: (id: string | null) => void;
|
| 61 |
updateCurrentTurnTrace: (sessionId: string) => void;
|
| 62 |
showToolOutput: (log: TraceLog) => void;
|
| 63 |
+
setEditedScript: (toolCallId: string, content: string) => void;
|
| 64 |
+
getEditedScript: (toolCallId: string) => string | undefined;
|
| 65 |
+
clearEditedScripts: () => void;
|
| 66 |
/** Append a streaming delta to an existing message. */
|
| 67 |
appendToMessage: (sessionId: string, messageId: string, delta: string) => void;
|
| 68 |
/** Remove all messages for a session (also clears from localStorage). */
|
|
|
|
| 87 |
activePanelTab: null,
|
| 88 |
plan: [],
|
| 89 |
currentTurnMessageId: null,
|
| 90 |
+
editedScripts: {},
|
| 91 |
|
| 92 |
addMessage: (sessionId: string, message: Message) => {
|
| 93 |
set((state) => {
|
|
|
|
| 205 |
});
|
| 206 |
},
|
| 207 |
|
| 208 |
+
updatePanelTabContent: (tabId: string, content: string) => {
|
| 209 |
+
set((state) => {
|
| 210 |
+
const newTabs = state.panelTabs.map(tab =>
|
| 211 |
+
tab.id === tabId ? { ...tab, content } : tab
|
| 212 |
+
);
|
| 213 |
+
return { panelTabs: newTabs };
|
| 214 |
+
});
|
| 215 |
+
},
|
| 216 |
+
|
| 217 |
setActivePanelTab: (tabId: string) => {
|
| 218 |
set({ activePanelTab: tabId });
|
| 219 |
},
|
|
|
|
| 316 |
});
|
| 317 |
},
|
| 318 |
|
| 319 |
+
setEditedScript: (toolCallId: string, content: string) => {
|
| 320 |
+
set((state) => ({
|
| 321 |
+
editedScripts: { ...state.editedScripts, [toolCallId]: content },
|
| 322 |
+
}));
|
| 323 |
+
},
|
| 324 |
+
|
| 325 |
+
getEditedScript: (toolCallId: string) => {
|
| 326 |
+
return get().editedScripts[toolCallId];
|
| 327 |
+
},
|
| 328 |
+
|
| 329 |
+
clearEditedScripts: () => {
|
| 330 |
+
set({ editedScripts: {} });
|
| 331 |
+
},
|
| 332 |
+
|
| 333 |
appendToMessage: (sessionId: string, messageId: string, delta: string) => {
|
| 334 |
set((state) => {
|
| 335 |
const messages = state.messagesBySession[sessionId] || [];
|
frontend/src/theme.ts
CHANGED
|
@@ -38,14 +38,14 @@ const darkVars = {
|
|
| 38 |
'--surface': '#121416',
|
| 39 |
'--text': '#E6EEF8',
|
| 40 |
'--muted-text': '#98A0AA',
|
| 41 |
-
'--accent-yellow': '#
|
| 42 |
-
'--accent-yellow-weak': 'rgba(
|
| 43 |
'--accent-green': '#2FCC71',
|
| 44 |
'--accent-red': '#E05A4F',
|
| 45 |
'--shadow-1': '0 6px 18px rgba(2,6,12,0.55)',
|
| 46 |
'--radius-lg': '20px',
|
| 47 |
'--radius-md': '12px',
|
| 48 |
-
'--focus': '0 0 0 3px rgba(
|
| 49 |
'--border': 'rgba(255,255,255,0.03)',
|
| 50 |
'--border-hover': 'rgba(255,255,255,0.1)',
|
| 51 |
'--code-bg': 'rgba(0,0,0,0.5)',
|
|
@@ -75,14 +75,14 @@ const lightVars = {
|
|
| 75 |
'--surface': '#F0F1F3',
|
| 76 |
'--text': '#1A1A2E',
|
| 77 |
'--muted-text': '#6B7280',
|
| 78 |
-
'--accent-yellow': '#
|
| 79 |
-
'--accent-yellow-weak': 'rgba(
|
| 80 |
'--accent-green': '#16A34A',
|
| 81 |
'--accent-red': '#DC2626',
|
| 82 |
'--shadow-1': '0 4px 12px rgba(0,0,0,0.08)',
|
| 83 |
'--radius-lg': '20px',
|
| 84 |
'--radius-md': '12px',
|
| 85 |
-
'--focus': '0 0 0 3px rgba(
|
| 86 |
'--border': 'rgba(0,0,0,0.08)',
|
| 87 |
'--border-hover': 'rgba(0,0,0,0.15)',
|
| 88 |
'--code-bg': 'rgba(0,0,0,0.04)',
|
|
@@ -93,7 +93,7 @@ const lightVars = {
|
|
| 93 |
'--msg-gradient': 'linear-gradient(180deg, rgba(0,0,0,0.01), transparent)',
|
| 94 |
'--body-gradient': 'linear-gradient(180deg, #FFFFFF, #F7F8FA)',
|
| 95 |
'--scrollbar-thumb': '#C4C8CC',
|
| 96 |
-
'--success-icon': '#
|
| 97 |
'--error-icon': '#DC2626',
|
| 98 |
'--clickable-text': 'rgba(0, 0, 0, 0.85)',
|
| 99 |
'--clickable-underline': 'rgba(0,0,0,0.25)',
|
|
@@ -176,14 +176,14 @@ function makeTextField() {
|
|
| 176 |
export const darkTheme = createTheme({
|
| 177 |
palette: {
|
| 178 |
mode: 'dark',
|
| 179 |
-
primary: { main: '#
|
| 180 |
secondary: { main: '#C7A500' },
|
| 181 |
background: { default: '#0B0D10', paper: '#0F1316' },
|
| 182 |
text: { primary: '#E6EEF8', secondary: '#98A0AA' },
|
| 183 |
divider: 'rgba(255,255,255,0.03)',
|
| 184 |
success: { main: '#2FCC71' },
|
| 185 |
error: { main: '#E05A4F' },
|
| 186 |
-
warning: { main: '#
|
| 187 |
info: { main: '#58A6FF' },
|
| 188 |
},
|
| 189 |
typography: sharedTypography,
|
|
@@ -199,14 +199,14 @@ export const darkTheme = createTheme({
|
|
| 199 |
export const lightTheme = createTheme({
|
| 200 |
palette: {
|
| 201 |
mode: 'light',
|
| 202 |
-
primary: { main: '#
|
| 203 |
secondary: { main: '#B8960A' },
|
| 204 |
background: { default: '#FFFFFF', paper: '#F7F8FA' },
|
| 205 |
text: { primary: '#1A1A2E', secondary: '#6B7280' },
|
| 206 |
divider: 'rgba(0,0,0,0.08)',
|
| 207 |
success: { main: '#16A34A' },
|
| 208 |
error: { main: '#DC2626' },
|
| 209 |
-
warning: { main: '#
|
| 210 |
info: { main: '#2563EB' },
|
| 211 |
},
|
| 212 |
typography: sharedTypography,
|
|
|
|
| 38 |
'--surface': '#121416',
|
| 39 |
'--text': '#E6EEF8',
|
| 40 |
'--muted-text': '#98A0AA',
|
| 41 |
+
'--accent-yellow': '#C7A500',
|
| 42 |
+
'--accent-yellow-weak': 'rgba(199,165,0,0.08)',
|
| 43 |
'--accent-green': '#2FCC71',
|
| 44 |
'--accent-red': '#E05A4F',
|
| 45 |
'--shadow-1': '0 6px 18px rgba(2,6,12,0.55)',
|
| 46 |
'--radius-lg': '20px',
|
| 47 |
'--radius-md': '12px',
|
| 48 |
+
'--focus': '0 0 0 3px rgba(199,165,0,0.12)',
|
| 49 |
'--border': 'rgba(255,255,255,0.03)',
|
| 50 |
'--border-hover': 'rgba(255,255,255,0.1)',
|
| 51 |
'--code-bg': 'rgba(0,0,0,0.5)',
|
|
|
|
| 75 |
'--surface': '#F0F1F3',
|
| 76 |
'--text': '#1A1A2E',
|
| 77 |
'--muted-text': '#6B7280',
|
| 78 |
+
'--accent-yellow': '#C7A500',
|
| 79 |
+
'--accent-yellow-weak': 'rgba(199,165,0,0.08)',
|
| 80 |
'--accent-green': '#16A34A',
|
| 81 |
'--accent-red': '#DC2626',
|
| 82 |
'--shadow-1': '0 4px 12px rgba(0,0,0,0.08)',
|
| 83 |
'--radius-lg': '20px',
|
| 84 |
'--radius-md': '12px',
|
| 85 |
+
'--focus': '0 0 0 3px rgba(199,165,0,0.15)',
|
| 86 |
'--border': 'rgba(0,0,0,0.08)',
|
| 87 |
'--border-hover': 'rgba(0,0,0,0.15)',
|
| 88 |
'--code-bg': 'rgba(0,0,0,0.04)',
|
|
|
|
| 93 |
'--msg-gradient': 'linear-gradient(180deg, rgba(0,0,0,0.01), transparent)',
|
| 94 |
'--body-gradient': 'linear-gradient(180deg, #FFFFFF, #F7F8FA)',
|
| 95 |
'--scrollbar-thumb': '#C4C8CC',
|
| 96 |
+
'--success-icon': '#C7A500',
|
| 97 |
'--error-icon': '#DC2626',
|
| 98 |
'--clickable-text': 'rgba(0, 0, 0, 0.85)',
|
| 99 |
'--clickable-underline': 'rgba(0,0,0,0.25)',
|
|
|
|
| 176 |
export const darkTheme = createTheme({
|
| 177 |
palette: {
|
| 178 |
mode: 'dark',
|
| 179 |
+
primary: { main: '#C7A500' },
|
| 180 |
secondary: { main: '#C7A500' },
|
| 181 |
background: { default: '#0B0D10', paper: '#0F1316' },
|
| 182 |
text: { primary: '#E6EEF8', secondary: '#98A0AA' },
|
| 183 |
divider: 'rgba(255,255,255,0.03)',
|
| 184 |
success: { main: '#2FCC71' },
|
| 185 |
error: { main: '#E05A4F' },
|
| 186 |
+
warning: { main: '#C7A500' },
|
| 187 |
info: { main: '#58A6FF' },
|
| 188 |
},
|
| 189 |
typography: sharedTypography,
|
|
|
|
| 199 |
export const lightTheme = createTheme({
|
| 200 |
palette: {
|
| 201 |
mode: 'light',
|
| 202 |
+
primary: { main: '#C7A500' },
|
| 203 |
secondary: { main: '#B8960A' },
|
| 204 |
background: { default: '#FFFFFF', paper: '#F7F8FA' },
|
| 205 |
text: { primary: '#1A1A2E', secondary: '#6B7280' },
|
| 206 |
divider: 'rgba(0,0,0,0.08)',
|
| 207 |
success: { main: '#16A34A' },
|
| 208 |
error: { main: '#DC2626' },
|
| 209 |
+
warning: { main: '#C7A500' },
|
| 210 |
info: { main: '#2563EB' },
|
| 211 |
},
|
| 212 |
typography: sharedTypography,
|