+ ${canCopyMarkdown ? renderCopyAsMarkdownButton(markdown!) : nothing}
${reasoningMarkdown
? html`
${unsafeHTML(
toSanitizedMarkdownHtml(reasoningMarkdown),
@@ -181,4 +185,3 @@ function renderGroupedMessage(
`;
}
-
diff --git a/ui/src/ui/chat/legacy-render.ts b/ui/src/ui/chat/legacy-render.ts
deleted file mode 100644
index 44ef25cc5..000000000
--- a/ui/src/ui/chat/legacy-render.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import { html, nothing } from "lit";
-import { unsafeHTML } from "lit/directives/unsafe-html.js";
-
-import { toSanitizedMarkdownHtml } from "../markdown";
-import {
- isToolResultMessage,
- normalizeRoleForGrouping,
-} from "./message-normalizer";
-import {
- extractText,
- extractThinking,
- formatReasoningMarkdown,
-} from "./message-extract";
-import { extractToolCards, renderToolCardLegacy } from "./tool-cards";
-
-export type LegacyToolOutputProps = {
- isToolOutputExpanded?: (id: string) => boolean;
- onToolOutputToggle?: (id: string, expanded: boolean) => void;
-};
-
-export function renderReadingIndicator() {
- return html`
-
- `;
-}
-
-export function renderMessage(
- message: unknown,
- props?: LegacyToolOutputProps,
- opts?: { streaming?: boolean; showReasoning?: boolean },
-) {
- const m = message as Record
;
- const role = typeof m.role === "string" ? m.role : "unknown";
- const toolCards = extractToolCards(message);
- const hasToolCards = toolCards.length > 0;
- const isToolResult =
- isToolResultMessage(message) ||
- typeof m.toolCallId === "string" ||
- typeof m.tool_call_id === "string";
- const extractedText = extractText(message);
- const extractedThinking =
- opts?.showReasoning && role === "assistant" ? extractThinking(message) : null;
- const contentText = typeof m.content === "string" ? m.content : null;
- const fallback = hasToolCards ? null : JSON.stringify(message, null, 2);
-
- const display =
- !isToolResult && extractedText?.trim()
- ? { kind: "text" as const, value: extractedText }
- : !isToolResult && contentText?.trim()
- ? { kind: "text" as const, value: contentText }
- : !isToolResult && fallback
- ? { kind: "json" as const, value: fallback }
- : null;
-
- const markdownBase =
- display?.kind === "json"
- ? ["```json", display.value, "```"].join("\n")
- : (display?.value ?? null);
- const reasoningMarkdown = extractedThinking
- ? formatReasoningMarkdown(extractedThinking)
- : null;
- const markdown = markdownBase;
-
- const timestamp =
- typeof m.timestamp === "number" ? new Date(m.timestamp).toLocaleTimeString() : "";
-
- const normalizedRole = normalizeRoleForGrouping(role);
- const klass =
- normalizedRole === "assistant"
- ? "assistant"
- : normalizedRole === "user"
- ? "user"
- : normalizedRole === "tool"
- ? "tool"
- : "other";
- const who =
- normalizedRole === "assistant"
- ? "Assistant"
- : normalizedRole === "user"
- ? "You"
- : normalizedRole === "tool"
- ? "Working"
- : normalizedRole;
-
- const toolCallId = typeof m.toolCallId === "string" ? m.toolCallId : "";
- const toolCardBase =
- toolCallId ||
- (typeof m.id === "string" ? m.id : "") ||
- (typeof m.messageId === "string" ? m.messageId : "") ||
- (typeof m.timestamp === "number" ? String(m.timestamp) : "tool-card");
-
- return html`
-
-
-
- ${reasoningMarkdown
- ? html`
${unsafeHTML(
- toSanitizedMarkdownHtml(reasoningMarkdown),
- )}
`
- : nothing}
- ${markdown
- ? html`
${unsafeHTML(toSanitizedMarkdownHtml(markdown))}
`
- : nothing}
- ${toolCards.map((card, index) =>
- renderToolCardLegacy(card, {
- id: `${toolCardBase}:${index}`,
- expanded: props?.isToolOutputExpanded
- ? props.isToolOutputExpanded(`${toolCardBase}:${index}`)
- : false,
- onToggle: props?.onToolOutputToggle,
- }),
- )}
-
-
- ${who}${timestamp ? html` ยท ${timestamp}` : nothing}
-
-
-
- `;
-}
-
diff --git a/ui/src/ui/chat/tool-cards.ts b/ui/src/ui/chat/tool-cards.ts
index f725363df..58bace1a2 100644
--- a/ui/src/ui/chat/tool-cards.ts
+++ b/ui/src/ui/chat/tool-cards.ts
@@ -1,7 +1,5 @@
import { html, nothing } from "lit";
-import { unsafeHTML } from "lit/directives/unsafe-html.js";
-import { toSanitizedMarkdownHtml } from "../markdown";
import { formatToolDetail, resolveToolDisplay } from "../tool-display";
import type { ToolCard } from "../types/chat-types";
import { TOOL_INLINE_THRESHOLD } from "./constants";
@@ -54,60 +52,6 @@ export function extractToolCards(message: unknown): ToolCard[] {
return cards;
}
-export function renderToolCardLegacy(
- card: ToolCard,
- opts?: {
- id: string;
- expanded: boolean;
- onToggle?: (id: string, expanded: boolean) => void;
- },
-) {
- const display = resolveToolDisplay({ name: card.name, args: card.args });
- const detail = formatToolDetail(display);
- const hasOutput = typeof card.text === "string" && card.text.length > 0;
- const expanded = opts?.expanded ?? false;
- const id = opts?.id ?? `${card.name}-${Math.random()}`;
- return html`
-
- `;
-}
-
export function renderToolCardSidebar(
card: ToolCard,
onOpenSidebar?: (content: string) => void,
@@ -197,4 +141,3 @@ function extractToolText(item: Record): string | undefined {
if (typeof item.content === "string") return item.content;
return undefined;
}
-
diff --git a/ui/src/ui/storage.ts b/ui/src/ui/storage.ts
index 1288895d9..fc410c225 100644
--- a/ui/src/ui/storage.ts
+++ b/ui/src/ui/storage.ts
@@ -11,7 +11,6 @@ export type UiSettings = {
chatFocusMode: boolean;
chatShowThinking: boolean;
splitRatio: number; // Sidebar split ratio (0.4 to 0.7, default 0.6)
- useNewChatLayout: boolean; // Slack-style grouped messages layout
navCollapsed: boolean; // Collapsible sidebar state
navGroupsCollapsed: Record; // Which nav groups are collapsed
};
@@ -31,7 +30,6 @@ export function loadSettings(): UiSettings {
chatFocusMode: false,
chatShowThinking: true,
splitRatio: 0.6,
- useNewChatLayout: true, // Enabled by default
navCollapsed: false,
navGroupsCollapsed: {},
};
@@ -77,10 +75,6 @@ export function loadSettings(): UiSettings {
parsed.splitRatio <= 0.7
? parsed.splitRatio
: defaults.splitRatio,
- useNewChatLayout:
- typeof parsed.useNewChatLayout === "boolean"
- ? parsed.useNewChatLayout
- : defaults.useNewChatLayout,
navCollapsed:
typeof parsed.navCollapsed === "boolean"
? parsed.navCollapsed
diff --git a/ui/src/ui/views/chat.ts b/ui/src/ui/views/chat.ts
index f25221db5..4618fdd8b 100644
--- a/ui/src/ui/views/chat.ts
+++ b/ui/src/ui/views/chat.ts
@@ -8,7 +8,6 @@ import {
normalizeRoleForGrouping,
} from "../chat/message-normalizer";
import { extractText } from "../chat/message-extract";
-import { renderMessage, renderReadingIndicator } from "../chat/legacy-render";
import {
renderMessageGroup,
renderReadingIndicatorGroup,
@@ -36,14 +35,9 @@ export type ChatProps = {
disabledReason: string | null;
error: string | null;
sessions: SessionsListResult | null;
- // Legacy tool output expand/collapse (used when useNewChatLayout is false)
- isToolOutputExpanded: (id: string) => boolean;
- onToolOutputToggle: (id: string, expanded: boolean) => void;
// Focus mode
focusMode: boolean;
- // Feature flag for new Slack-style layout with sidebar
- useNewChatLayout?: boolean;
- // Sidebar state (used when useNewChatLayout is true)
+ // Sidebar state
sidebarOpen?: boolean;
sidebarContent?: string | null;
sidebarError?: string | null;
@@ -51,7 +45,6 @@ export type ChatProps = {
// Event handlers
onRefresh: () => void;
onToggleFocusMode: () => void;
- onToggleLayout?: () => void;
onDraftChange: (next: string) => void;
onSend: () => void;
onAbort?: () => void;
@@ -78,7 +71,6 @@ export function renderChat(props: ChatProps) {
const splitRatio = props.splitRatio ?? 0.6;
const sidebarOpen = Boolean(props.sidebarOpen && props.onCloseSidebar);
- const useNewLayout = props.useNewChatLayout ?? false;
return html`
@@ -122,27 +114,15 @@ export function renderChat(props: ChatProps) {
: nothing}
${repeat(buildChatItems(props), (item) => item.key, (item) => {
if (item.kind === "reading-indicator") {
- return useNewLayout
- ? renderReadingIndicatorGroup()
- : renderReadingIndicator();
+ return renderReadingIndicatorGroup();
}
if (item.kind === "stream") {
- return useNewLayout
- ? renderStreamingGroup(
- item.text,
- item.startedAt,
- props.onOpenSidebar,
- )
- : renderMessage(
- {
- role: "assistant",
- content: [{ type: "text", text: item.text }],
- timestamp: item.startedAt,
- },
- props,
- { streaming: true, showReasoning },
- );
+ return renderStreamingGroup(
+ item.text,
+ item.startedAt,
+ props.onOpenSidebar,
+ );
}
if (item.kind === "group") {
@@ -152,12 +132,12 @@ export function renderChat(props: ChatProps) {
});
}
- return renderMessage(item.message, props, { showReasoning });
+ return nothing;
})}
- ${useNewLayout && sidebarOpen
+ ${sidebarOpen
? html`