Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 36 additions & 31 deletions bun.lock

Large diffs are not rendered by default.

24 changes: 20 additions & 4 deletions packages/chat-components/styles/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

:root {
/* Base colors - dark theme default */
--color-background: #1e1e1e;
--color-background: #09090B;
--color-foreground: #e4e4e7;
--color-text: #e4e4e7;
--color-muted: #a1a1aa;
Expand All @@ -16,7 +16,7 @@
--color-accent: #3f3f46;

/* Code blocks */
--color-code-bg: #0d0d0d;
--color-code-bg: #141416;
--color-code-border: #27272a;

/* User messages */
Expand All @@ -42,6 +42,22 @@
/* Diff colors */
--color-diff-add-bg: rgba(16, 185, 129, 0.1);
--color-diff-remove-bg: rgba(239, 68, 68, 0.1);

/* Links & inline code */
--color-link: #60A5FA;
--color-inline-code: #94A3B8;

/* Danger text */
--color-danger-text: #F87171;

/* Badge colors */
--color-success-badge-bg: #052E16;
--color-success-badge-text: #16A34A;
--color-danger-badge-bg: #450A0A;
--color-danger-badge-text: #F87171;

/* Muted agent */
--color-muted-agent: #888895;
}

/* Light theme */
Expand All @@ -67,15 +83,15 @@

/* Dark theme (explicit) */
.dark {
--color-background: #1e1e1e;
--color-background: #09090B;
--color-foreground: #e4e4e7;
--color-text: #e4e4e7;
--color-muted: #a1a1aa;
--color-border: #27272a;
--color-card: #27272a;
--color-accent: #3f3f46;

--color-code-bg: #0d0d0d;
--color-code-bg: #141416;
--color-code-border: #27272a;

--color-user-surface: #27272a;
Expand Down
9 changes: 7 additions & 2 deletions src/browser/components/TodoList/TodoList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const TodoList: React.FC<TodoListProps> = ({ todos }) => {
let pendingIndex = 0;

return (
<div className="flex flex-col gap-[3px] px-2 py-1.5">
<div className="step-list flex flex-col gap-[3px] px-2 py-1.5">
{todos.map((todo, index) => {
const currentCompletedIndex = todo.status === "completed" ? completedIndex++ : undefined;
const currentPendingIndex = todo.status === "pending" ? pendingIndex++ : undefined;
Expand All @@ -111,7 +111,12 @@ export const TodoList: React.FC<TodoListProps> = ({ todos }) => {
return (
<div
key={index}
className="font-monospace flex items-start gap-1.5 rounded border-l-2 px-2 py-1 text-[11px] leading-[1.35]"
className={cn(
"step-item font-monospace flex items-start gap-1.5 rounded border-l-2 px-2 py-1 text-[11px] leading-[1.35]",
todo.status === "in_progress" && "step-active",
todo.status === "completed" && "step-done",
todo.status === "pending" && "step-pending"
)}
style={{
background: statusBgColors[todo.status],
borderLeftColor: statusBorderColors[todo.status],
Expand Down
11 changes: 11 additions & 0 deletions src/browser/features/Messages/MarkdownComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,22 @@ const CodeBlock: React.FC<CodeBlockProps> = ({ code, language, highlightLanguage
);
};

interface TableProps {
children?: ReactNode;
}

// Custom components for markdown rendering
export const markdownComponents = {
// Pass through pre element - let code component handle the wrapping
pre: ({ children }: PreProps) => <>{children}</>,

// Wrap tables in a scroll container for horizontal overflow.
table: ({ children }: TableProps) => (
<div className="table-scroll-wrapper">
<table>{children}</table>
</div>
),

// Custom anchor to open links externally
a: ({ href, children }: AnchorProps) => {
const normalizedHref =
Expand Down
2 changes: 1 addition & 1 deletion src/browser/features/Messages/MessageWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const MessageWindow: React.FC<MessageWindowProps> = ({
<div
className={cn(
variant === "user" &&
"bg-[var(--color-user-surface)] border border-[var(--color-user-border)] rounded-lg px-3 py-2 overflow-x-auto shadow-sm",
"bg-[var(--color-user-surface)] border border-transparent hover:border-[var(--color-user-border)] rounded-lg px-3 py-2 overflow-x-auto shadow-sm",
variant === "assistant" && "px-1 py-1"
)}
>
Expand Down
17 changes: 10 additions & 7 deletions src/browser/features/Messages/ReasoningMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { TypewriterMarkdown } from "./TypewriterMarkdown";
import { normalizeReasoningMarkdown } from "./MarkdownStyles";
import { cn } from "@/common/lib/utils";
import { Shimmer } from "../AIElements/Shimmer";
import { Lightbulb } from "lucide-react";
import { ChevronRight, Lightbulb } from "lucide-react";

interface ReasoningMessageProps {
message: DisplayedMessage & { type: "reasoning" };
Expand Down Expand Up @@ -125,12 +125,14 @@ export const ReasoningMessage: React.FC<ReasoningMessageProps> = ({ message, cla

return (
<div
data-reasoning
className={cn(
"my-2 px-2 py-1 bg-[color-mix(in_srgb,var(--color-thinking-mode)_5%,transparent)] rounded relative",
"my-2 px-2 py-1 rounded relative",
className
)}
>
<div
data-reasoning-toggle
className={cn(
"flex items-center justify-between gap-2 select-none",
isCollapsible && "cursor-pointer",
Expand All @@ -141,17 +143,17 @@ export const ReasoningMessage: React.FC<ReasoningMessageProps> = ({ message, cla
<div
className={cn(
"flex flex-1 items-center gap-1 min-w-0 text-xs opacity-80",
"text-thinking-mode"
"text-[var(--color-muted-agent,#888895)]"
)}
>
<span className="text-xs">
<Lightbulb className={cn("size-3.5", isStreaming && "animate-pulse")} />
</span>
<div className="flex min-w-0 items-center gap-1 truncate">
<div data-reasoning-badge className="flex min-w-0 items-center gap-1 truncate">
{isStreaming ? (
<Shimmer colorClass="var(--color-thinking-mode)">Thinking...</Shimmer>
) : hasContent ? (
<span className={cn("truncate whitespace-nowrap text-text", REASONING_FONT_CLASSES)}>
<span data-reasoning-preview className={cn("truncate whitespace-nowrap text-text", REASONING_FONT_CLASSES)}>
{parsedLeadingBoldSummary ? (
<>
<strong>{parsedLeadingBoldSummary.boldText}</strong>
Expand All @@ -177,11 +179,11 @@ export const ReasoningMessage: React.FC<ReasoningMessageProps> = ({ message, cla
{isCollapsible && (
<span
className={cn(
"text-thinking-mode opacity-60 transition-transform duration-200 ease-in-out text-xs",
"inline-flex items-center justify-center text-[#888895] opacity-60 transition-transform duration-200 ease-in-out",
isExpanded ? "rotate-90" : "rotate-0"
)}
>
<ChevronRight className="h-3.5 w-3.5" />
</span>
)}
</div>
Expand All @@ -190,6 +192,7 @@ export const ReasoningMessage: React.FC<ReasoningMessageProps> = ({ message, cla
Use CSS transitions for smooth height changes instead of conditional rendering. */}
<div
ref={contentRef}
data-reasoning-content
className={cn(
REASONING_FONT_CLASSES,
"italic opacity-85 [&_p]:mt-0 [&_p]:mb-1 [&_p:last-child]:mb-0",
Expand Down
44 changes: 24 additions & 20 deletions src/browser/features/Messages/UserMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,25 +142,29 @@ export const UserMessage: React.FC<UserMessageProps> = ({
const syntheticClassName = cn(className, isSynthetic && "opacity-70");

return (
<MessageWindow
label={label}
message={message}
buttons={buttons}
className={syntheticClassName}
variant="user"
>
{isLocalCommandOutput ? (
<TerminalOutput output={extractedOutput} isError={false} />
) : (
<UserMessageContent
content={content}
commandPrefix={message.commandPrefix}
agentSkillSnapshot={message.agentSkill?.snapshot}
reviews={message.reviews}
fileParts={message.fileParts}
variant="sent"
/>
)}
</MessageWindow>
<div data-user-message>
<MessageWindow
label={label}
message={message}
buttons={buttons}
className={syntheticClassName}
variant="user"
>
<div data-message-role="user">
{isLocalCommandOutput ? (
<TerminalOutput output={extractedOutput} isError={false} />
) : (
<UserMessageContent
content={content}
commandPrefix={message.commandPrefix}
agentSkillSnapshot={message.agentSkill?.snapshot}
reviews={message.reviews}
fileParts={message.fileParts}
variant="sent"
/>
)}
</div>
</MessageWindow>
</div>
);
};
2 changes: 1 addition & 1 deletion src/browser/features/Tools/AgentReportToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const AgentReportToolCall: React.FC<AgentReportToolCallProps> = ({
return (
<ToolContainer expanded={expanded}>
<ToolHeader onClick={toggleExpanded}>
<ExpandIcon expanded={expanded}>▶</ExpandIcon>
<ExpandIcon expanded={expanded} />
<ToolIcon toolName="agent_report" />
<ToolName>{title}</ToolName>
<StatusIndicator status={status}>{getStatusDisplay(status)}</StatusIndicator>
Expand Down
2 changes: 1 addition & 1 deletion src/browser/features/Tools/AgentSkillReadFileToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export const AgentSkillReadFileToolCall: React.FC<AgentSkillReadFileToolCallProp
return (
<ToolContainer expanded={expanded} className="@container">
<ToolHeader onClick={toggleExpanded}>
<ExpandIcon expanded={expanded}>▶</ExpandIcon>
<ExpandIcon expanded={expanded} />
<ToolIcon toolName="agent_skill_read_file" />
<div className="text-text flex max-w-96 min-w-0 items-center gap-1.5">
<FileIcon filePath={args.filePath} className="text-[15px] leading-none" />
Expand Down
2 changes: 1 addition & 1 deletion src/browser/features/Tools/AgentSkillReadToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export const AgentSkillReadToolCall: React.FC<AgentSkillReadToolCallProps> = ({
return (
<ToolContainer expanded={expanded} className="@container">
<ToolHeader onClick={toggleExpanded}>
<ExpandIcon expanded={expanded}>▶</ExpandIcon>
<ExpandIcon expanded={expanded} />
<ToolIcon toolName="agent_skill_read" />
<div className="text-text font-monospace flex max-w-96 min-w-0 items-baseline gap-1.5">
<span className="text-secondary whitespace-nowrap">Read skill:</span>
Expand Down
2 changes: 1 addition & 1 deletion src/browser/features/Tools/AskUserQuestionToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ export function AskUserQuestionToolCall(props: {
return (
<ToolContainer expanded={expanded}>
<ToolHeader onClick={toggleExpanded}>
<ExpandIcon expanded={expanded}>▶</ExpandIcon>
<ExpandIcon expanded={expanded} />
<div className="flex flex-1 flex-col">
<ToolName>{title}</ToolName>
<div className="text-muted-foreground text-xs">
Expand Down
2 changes: 1 addition & 1 deletion src/browser/features/Tools/BashBackgroundListToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const BashBackgroundListToolCall: React.FC<BashBackgroundListToolCallProp
return (
<ToolContainer expanded={expanded}>
<ToolHeader onClick={toggleExpanded}>
<ExpandIcon expanded={expanded}>▶</ExpandIcon>
<ExpandIcon expanded={expanded} />
<ToolIcon toolName="bash_background_list" />
<span className="text-text-secondary">
{result?.success
Expand Down
2 changes: 1 addition & 1 deletion src/browser/features/Tools/BashOutputToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const BashOutputToolCall: React.FC<BashOutputToolCallProps> = ({
return (
<ToolContainer expanded={expanded}>
<ToolHeader onClick={toggleExpanded}>
<ExpandIcon expanded={expanded}>▶</ExpandIcon>
<ExpandIcon expanded={expanded} />
<ToolIcon toolName="bash_output" />
<span className="text-text font-monospace max-w-96 truncate">{args.process_id}</span>
<span className="text-muted ml-2 flex items-center gap-1 text-[10px] whitespace-nowrap">
Expand Down
10 changes: 5 additions & 5 deletions src/browser/features/Tools/BashToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,11 @@ export const BashToolCall: React.FC<BashToolCallProps> = ({
toggleExpanded();
};
return (
<ToolContainer expanded={expanded}>
<ToolHeader onClick={handleToggle}>
<ExpandIcon expanded={expanded}>▶</ExpandIcon>
<ToolContainer expanded={expanded} data-tool-call>
<ToolHeader onClick={handleToggle} data-tool-header>
<ExpandIcon expanded={expanded} />
<ToolIcon toolName="bash" />
<span className="text-text font-monospace max-w-96 truncate">{args.script}</span>
<span className="text-[#94A3B8] font-mono max-w-96 truncate" data-tool-command>{args.script}</span>
{isBackground && backgroundProcessId && workspaceId && (
<Tooltip>
<TooltipTrigger asChild>
Expand Down Expand Up @@ -278,7 +278,7 @@ export const BashToolCall: React.FC<BashToolCallProps> = ({
{result && <ExitCodeBadge exitCode={result.exitCode} className="ml-2" />}
</>
)}
<StatusIndicator status={effectiveStatus}>
<StatusIndicator status={effectiveStatus} data-tool-status>
{getStatusDisplay(effectiveStatus)}
</StatusIndicator>
{/* Show "Background" button when bash is executing and can be sent to background.
Expand Down
2 changes: 1 addition & 1 deletion src/browser/features/Tools/DesktopScreenshotToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const DesktopScreenshotToolCall: React.FC<DesktopScreenshotToolCallProps>
return (
<ToolContainer expanded={shouldShowDetails}>
<ToolHeader onClick={() => hasDetails && toggleExpanded()}>
{hasDetails && <ExpandIcon expanded={shouldShowDetails}>▶</ExpandIcon>}
{hasDetails && <ExpandIcon expanded={shouldShowDetails} />}
<ToolIcon toolName="desktop_screenshot" />
<ToolName>Desktop Screenshot</ToolName>
{screenshotDimensions && (
Expand Down
8 changes: 4 additions & 4 deletions src/browser/features/Tools/FileEditToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,13 @@ export const FileEditToolCall: React.FC<FileEditToolCallProps> = ({
: [];

return (
<ToolContainer expanded={expanded}>
<ToolHeader className="hover:text-secondary cursor-default">
<ToolContainer expanded={expanded} className="file-change-card">
<ToolHeader className="file-change-header hover:text-secondary cursor-default">
<div
onClick={toggleExpanded}
className="hover:text-text flex flex-1 cursor-pointer items-center gap-2"
>
<ExpandIcon expanded={expanded}>▶</ExpandIcon>
<ExpandIcon expanded={expanded} />
<ToolIcon toolName={toolName} />
<div className="text-text flex max-w-96 min-w-0 items-center gap-1.5">
<FileIcon filePath={filePath} className="text-[15px] leading-none" />
Expand All @@ -165,7 +165,7 @@ export const FileEditToolCall: React.FC<FileEditToolCallProps> = ({
</ToolHeader>

{expanded && (
<ToolDetails>
<ToolDetails className="file-change-body">
{showInvocation && (
<DetailSection>
<DetailLabel>Invocation</DetailLabel>
Expand Down
2 changes: 1 addition & 1 deletion src/browser/features/Tools/FileReadToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const FileReadToolCall: React.FC<FileReadToolCallProps> = ({
return (
<ToolContainer expanded={expanded} className="@container">
<ToolHeader onClick={toggleExpanded}>
<ExpandIcon expanded={expanded}>▶</ExpandIcon>
<ExpandIcon expanded={expanded} />
<ToolIcon toolName="file_read" />
<div className="text-text flex max-w-96 min-w-0 items-center gap-1.5">
<FileIcon filePath={filePath} className="text-[15px] leading-none" />
Expand Down
8 changes: 4 additions & 4 deletions src/browser/features/Tools/GenericToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ export const GenericToolCall: React.FC<GenericToolCallProps> = ({
const shouldShowDetails = expanded || hasImages;

return (
<ToolContainer expanded={shouldShowDetails}>
<ToolHeader onClick={() => hasDetails && toggleExpanded()}>
{hasDetails && <ExpandIcon expanded={shouldShowDetails}>▶</ExpandIcon>}
<ToolContainer expanded={shouldShowDetails} data-tool-call>
<ToolHeader onClick={() => hasDetails && toggleExpanded()} data-tool-header>
{hasDetails && <ExpandIcon expanded={shouldShowDetails} />}
{TOOL_NAME_TO_ICON[toolName] && <ToolIcon toolName={toolName} />}
<ToolName>{toolName}</ToolName>
<StatusIndicator status={status}>{getStatusDisplay(status)}</StatusIndicator>
<StatusIndicator status={status} data-tool-status>{getStatusDisplay(status)}</StatusIndicator>
</ToolHeader>

{/* Always show images if present */}
Expand Down
2 changes: 1 addition & 1 deletion src/browser/features/Tools/ProposePlanToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1011,7 +1011,7 @@ export const ProposePlanToolCall: React.FC<ProposePlanToolCallProps> = (props) =
<>
<ToolContainer expanded={expanded}>
<ToolHeader onClick={toggleExpanded}>
<ExpandIcon expanded={expanded}>▶</ExpandIcon>
<ExpandIcon expanded={expanded} />
<ToolName>propose_plan</ToolName>
<StatusIndicator status={status}>{statusDisplay}</StatusIndicator>
</ToolHeader>
Expand Down
Loading
Loading