From 863f9caf0fe600881a8d2da2b475ed51ee163cd8 Mon Sep 17 00:00:00 2001 From: paisley <8197966+su8su@users.noreply.github.com> Date: Tue, 28 Jul 2026 16:46:13 +0800 Subject: [PATCH] fix markdown display (#1199) --- README.ja-JP.md | 4 +-- README.md | 4 +-- README.ru-RU.md | 4 +-- README.zh-CN.md | 4 +-- src/pages/Chat/AcpMessageSegment.tsx | 18 +++--------- .../e2e/chat-assistant-markdown-plain.spec.ts | 10 ++++--- tests/unit/acp-chat-components.test.tsx | 28 +++++++++++++++++++ 7 files changed, 46 insertions(+), 26 deletions(-) diff --git a/README.ja-JP.md b/README.ja-JP.md index daa41a97..d2ec2a57 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -103,7 +103,7 @@ ClawXは公式の**OpenClaw**コアを直接ベースに構築されています インストールから最初のAIインタラクションまで、すべてのセットアップを直感的なグラフィカルインターフェースで完了できます。ターミナルコマンド不要、YAMLファイル不要、環境変数の探索も不要です。 ### 💬 インテリジェントチャットインターフェース -モダンなチャット体験を通じてAIエージェントとコミュニケーションできます。複数の会話コンテキスト、メッセージ履歴、Markdownによるリッチコンテンツレンダリング(GitHub 風テーブルや KaTeX による LaTeX 数式 `$インライン$`、`$$ブロック$$`、`\(インライン\)`、`\[ブロック\]` を含む)に加え、マルチエージェント構成ではメイン入力欄の `@agent` から対象エージェントへ直接ルーティングできます。 +モダンなチャット体験を通じてAIエージェントとコミュニケーションできます。複数の会話コンテキスト、メッセージ履歴、エージェント応答の Markdown レンダリング(GitHub 風テーブルや KaTeX による LaTeX 数式 `$インライン$`、`$$ブロック$$`、`\(インライン\)`、`\[ブロック\]` を含む)をサポートし、ユーザー入力は常にプレーンテキストとして表示します。さらに、マルチエージェント構成ではメイン入力欄の `@agent` から対象エージェントへ直接ルーティングできます。 コンポーザーから挿入した Skill は `/skill-name` 形式のチップとして表示され、チップをクリックすると右側のプレビュー側欄でその Skill の `SKILL.md` を開けます。 `@agent` で別のエージェントを選ぶと、ClawX はデフォルトエージェントを経由せず、そのエージェント自身の会話コンテキストへ直接切り替えます。各エージェントのワークスペースは既定で分離されていますが、より強い実行時分離は OpenClaw の sandbox 設定に依存します。 セッション側欄はワークスペース優先で整理され、既定ワークスペースを先頭に固定し、その他のワークスペースは自然順に並べます。各ワークスペースは折りたたみや追加読み込みができます。AI の返信中は行にスピナーが表示され、未確認の返信が完了すると青い点に変わり、会話を開くと相対アクティビティ時刻に戻ります。ホバーすると引き続き操作ボタンが表示されます。インポートしたワークスペースは側欄の見出しから名前を変更でき、新しい名前はチャット入力欄の下にも反映されます。見出しにホバーすると引き続きファイルシステムのパスを確認できます。選択中の会話に有効なワークスペースがある場合、新しいチャットはそれを引き継ぎ、最初の送信までは変更できます。編集可能な新規または未バインドのチャットでは、コンポーザーのワークスペースチップから最近使用したワークスペースと既存セッションのワークスペースの一覧を開き、既定ワークスペースへ戻すか別フォルダーを選べます。保存済みのワークスペースフォルダーが移動または削除されている場合、Chat はセッション作成を一時停止し、無効なパスを繰り返し再試行せずに既存のフォルダーを選ぶよう案内します。利用できない既定以外のグループには側欄で印が付き、確認後に削除できます。この操作ではグループ内の全セッションが完全に削除されます。OpenClaw が生成する UUID と日付のフォールバックタイトルは、そのセッション ID と一致する場合に限って欠落タイトルとして扱い、セッション名として保存せず、会話の最初のユーザーメッセージに置き換えて表示します。 @@ -268,7 +268,7 @@ ACP Chat は、runtime が画像生成メディアを信頼できる構造化メ │ │ • モダンなコンポーネントベースUI(React 19) │ │ │ │ • Zustandによるステート管理 │ │ │ │ • 統一 host-api/api-client 呼び出し │ │ -│ │ • リッチなMarkdownレンダリング │ │ +│ │ • 応答はMarkdown、ユーザー入力はプレーンテキスト │ │ │ └──────────────────────────────────────────────────────────────┘ │ └──────────────────────────────┬─────────────────────────────────────┘ │ diff --git a/README.md b/README.md index 705194b9..23a819f4 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ When Developer Mode is enabled, the sidebar also provides a native Dreams page f Complete the entire setup—from installation to your first AI interaction—through an intuitive graphical interface. No terminal commands, no YAML files, no environment variable hunting. ### 💬 Intelligent Chat Interface -Communicate with AI agents through a modern chat experience. Support for multiple conversation contexts, message history, rich content rendering with Markdown (including GitHub-flavored tables and KaTeX-powered LaTeX math: `$inline$`, `$$block$$`, `\(inline\)`, and `\[block\]`), and direct `@agent` routing in the main composer for multi-agent setups. +Communicate with AI agents through a modern chat experience. Support for multiple conversation contexts, message history, assistant replies rendered with Markdown (including GitHub-flavored tables and KaTeX-powered LaTeX math: `$inline$`, `$$block$$`, `\(inline\)`, and `\[block\]`) while user input remains literal text, and direct `@agent` routing in the main composer for multi-agent setups. Skills you insert from the composer appear as `/skill-name` chips; click a chip to open the preview sidebar and read that skill's `SKILL.md`. When you target another agent with `@agent`, ClawX switches into that agent's own conversation context directly instead of relaying through the default agent. Agent workspaces stay separate by default, and stronger isolation depends on OpenClaw sandbox settings. The session sidebar is workspace-first: the default workspace stays at the top, other workspaces sort naturally, and each workspace can collapse or load more sessions. A row shows a spinner while the AI is replying, a blue dot when an unseen reply finishes, and its relative activity time after the conversation is opened; hovering still reveals row actions. Imported workspaces can be renamed from their sidebar header; the custom name is reflected in the chat composer while hovering the header still reveals the filesystem path. When available, a new chat inherits the selected conversation's workspace while remaining editable until first send. Editable new or unbound chats expose the composer workspace chip as a small menu that lists recent and known-session workspaces, returns to the default workspace, or chooses another folder. If a saved workspace folder was moved or deleted, Chat pauses session creation and prompts you to choose an existing folder instead of repeatedly retrying the missing path. Unavailable non-default groups are marked in the sidebar and can be removed after confirmation; this permanently deletes every session in that group. Synthetic OpenClaw UUID-date fallback titles are treated as missing only when they match the session ID, then replaced with the conversation's first user prompt instead of being persisted as the session name. @@ -271,7 +271,7 @@ ACP Chat can also display generated image previews when image-generation media i │ │ • Modern component-based UI (React 19) │ │ │ │ • State management with Zustand │ │ │ │ • Unified host-api/api-client calls │ │ -│ │ • Rich Markdown rendering │ │ +│ │ • Markdown assistant replies, literal user input │ │ │ └────────────────────────────────────────────────────────────┘ │ └──────────────────────────────┬───────────────────────────────────┘ │ diff --git a/README.ru-RU.md b/README.ru-RU.md index 0873f14c..85230666 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -101,7 +101,7 @@ ClawX построен непосредственно на официально Весь процесс — от установки до первого взаимодействия с AI — выполняется через интуитивный графический интерфейс. Без терминальных команд, без YAML-файлов, без поиска переменных окружения. ### 💬 Интеллектуальный интерфейс чата -Общайтесь с AI-агентами через современный чат. Поддержка нескольких контекстов разговора, истории сообщений, рендеринга Markdown (включая таблицы GitHub-flavored и математические формулы LaTeX через KaTeX: `$строчные$`, `$$блочные$$`, `\(строчные\)` и `\[блочные\]`) и прямая маршрутизация через `@agent` в главном поле ввода для мультиагентных конфигураций. +Общайтесь с AI-агентами через современный чат. Поддержка нескольких контекстов разговора, истории сообщений и рендеринга ответов агента в Markdown (включая таблицы GitHub-flavored и математические формулы LaTeX через KaTeX: `$строчные$`, `$$блочные$$`, `\(строчные\)` и `\[блочные\]`), при этом пользовательский ввод всегда отображается как обычный текст. Для мультиагентных конфигураций также доступна прямая маршрутизация через `@agent` в главном поле ввода. Навыки, вставляемые из поля ввода, отображаются как чипы `/skill-name`; нажмите на чип, чтобы открыть боковую панель предпросмотра и прочитать `SKILL.md` соответствующего навыка. При выборе другого агента через `@agent` ClawX переключается непосредственно в контекст этого агента вместо ретрансляции через агента по умолчанию. Рабочие пространства агентов по умолчанию разделены, но более строгая изоляция зависит от настроек песочницы OpenClaw. Каждый агент может переопределить свои настройки `provider/model`; агенты без переопределения продолжают наследовать глобальную модель по умолчанию. @@ -237,7 +237,7 @@ ClawX использует **двухпроцессную архитектуру │ │ • Современный UI на компонентах (React 19) │ │ │ │ • Управление состоянием с Zustand │ │ │ │ • Унифицированные вызовы host-api/api-client │ │ -│ │ • Рендеринг Markdown │ │ +│ │ • Ответы в Markdown, ввод как обычный текст │ │ │ └────────────────────────────────────────────────────────────┘ │ └──────────────────────────────┬──────────────────────────────────┘ │ diff --git a/README.zh-CN.md b/README.zh-CN.md index 4ca2e70c..d5c74d3e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -104,7 +104,7 @@ ClawX 直接基于官方 **OpenClaw** 核心构建。无需单独安装,我们 从安装到第一次 AI 对话,全程通过直观的图形界面完成。无需终端命令,无需 YAML 文件,无需到处寻找环境变量。 ### 💬 智能聊天界面 -通过现代化的聊天体验与 AI 智能体交互。支持多会话上下文、消息历史记录、Markdown 富文本渲染(包括 GitHub 风格表格以及由 KaTeX 渲染的 LaTeX 数学公式:`$行内$`、`$$块级$$`、`\(行内\)` 和 `\[块级\]`),以及在多 Agent 场景下通过主输入框中的 `@agent` 直接路由到目标智能体。 +通过现代化的聊天体验与 AI 智能体交互。支持多会话上下文、消息历史记录、以 Markdown 渲染智能体回复(包括 GitHub 风格表格以及由 KaTeX 渲染的 LaTeX 数学公式:`$行内$`、`$$块级$$`、`\(行内\)` 和 `\[块级\]`),用户输入则始终按原始文本显示;同时支持在多 Agent 场景下通过主输入框中的 `@agent` 直接路由到目标智能体。 从输入框插入的技能会以 `/技能名` 卡片形式显示;点击卡片可在右侧预览栏打开并阅读该技能的 `SKILL.md`。 当你使用 `@agent` 选择其他智能体时,ClawX 会直接切换到该智能体自己的对话上下文,而不是经过默认智能体转发。各 Agent 工作区默认彼此分离,但更强的运行时隔离仍取决于 OpenClaw 的 sandbox 配置。 会话侧边栏现在以工作空间优先组织:默认工作空间固定在最上方,其它工作空间按自然顺序排列,每个工作空间都可折叠或继续加载更多会话。AI 回复期间,会话行显示加载指示器;未查看的回复完成后显示蓝点;打开会话后恢复显示相对活跃时间,悬停时仍会露出操作按钮。导入的工作空间可从侧边栏标题处重命名,新名称会同步显示在对话输入框下方,同时悬浮标题仍可查看文件系统路径。如果当前所选会话存在有效工作空间,新对话会继承该工作空间,并在首次发送前保持可编辑。对于可编辑的新对话或未绑定对话,输入框的工作空间卡片会打开一个小菜单,列出最近使用及现有会话中的工作空间,并可切回默认工作空间或选择其它目录。如果保存的工作空间文件夹已被移动或删除,Chat 会暂停创建会话并提示选择现有文件夹,而不会持续重试失效路径。不可用的非默认工作空间会在侧边栏显示标记,并可在确认后删除;该操作会永久删除分组中的全部会话。OpenClaw 生成的 UUID 加日期兜底标题只有在与该会话 ID 匹配时才会被视为缺失标题,随后改用会话的首条用户消息展示,而不会被持久化为会话名称。 @@ -272,7 +272,7 @@ ACP Chat 也可在 runtime 以可信结构化媒体投递图像生成结果时 │ │ • 现代组件化 UI(React 19) │ │ │ │ • Zustand 状态管理 │ │ │ │ • 统一 host-api/api-client 调用 │ │ -│ │ • Markdown 富文本渲染 │ │ +│ │ • 回复使用 Markdown,用户输入按原文显示 │ │ │ └────────────────────────────────────────────────────────────┘ │ └──────────────────────────────┬───────────────────────────────────┘ │ diff --git a/src/pages/Chat/AcpMessageSegment.tsx b/src/pages/Chat/AcpMessageSegment.tsx index c2cf923e..7143ea9c 100644 --- a/src/pages/Chat/AcpMessageSegment.tsx +++ b/src/pages/Chat/AcpMessageSegment.tsx @@ -26,21 +26,11 @@ function normalizeLatexDelimiters(input: string): string { return parts.join(''); } -function AcpMarkdownPart({ text, tone }: { text: string; tone: RenderTone }) { +function AcpMarkdownPart({ text }: { text: string }) { const { t } = useTranslation('chat'); - const isUser = tone === 'user'; return ( -
{part.text}