Skip to content

Commit 89d3e97

Browse files
7418claude
andcommitted
feat: Ollama local model support, thinking display, tool call UX overhaul
Ollama integration: - Add Ollama vendor preset (provider-catalog.ts, provider-presets.tsx) - Auto-fill auth token for presets without api_key field (PresetConnectDialog.tsx) - Explicitly set ANTHROPIC_API_KEY='' for auth_token providers (provider-resolver.ts) - Add Ollama setup guide to docs site (en + zh providers.mdx) Thinking (reasoning) display: - Stream thinking deltas via SSE and render in real-time (useSSEStream, StreamingMessage) - Persist thinking blocks in message content (chat/route.ts, claude-client.ts) - Preserve thinking on stop/error/timeout instead of silently dropping (stream-session-manager.ts) - Bridge path now accumulates and persists thinking blocks (conversation-engine.ts) Tool call UX: - Refactor tool actions into grouped, collapsible display (tool-actions-group.tsx) - Show streaming tool output inline for running tools - Fallback renderer now shows raw tool name for unregistered tools (MCP, plugins) - Normalize tool_use/tool_result content blocks (message-normalizer.ts) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent cd9f549 commit 89d3e97

34 files changed

Lines changed: 1985 additions & 201 deletions

RELEASE_NOTES.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,32 @@
1-
## CodePilot v0.45.1
1+
## CodePilot v0.46.0
22

3-
> 新增默认侧边面板设置、小米 MiMo Token Plan 渠道,以及 Buddy 头像本地化等修复
3+
> 新增 Ollama 本地模型支持,优化工具调用展示和推理内容(Thinking)的显示与保留
44
55
### 新增功能
66

7-
- 新增「默认侧边面板」设置:可选择新对话时自动打开文件树、看板、Git 或不打开
8-
- 新增小米 MiMo Token Plan 服务商预设,支持订阅套餐方式使用
7+
- 新增 Ollama 服务商预设:一键接入本地模型,无需 API 密钥
8+
- 新增推理内容(Thinking)流式展示:支持实时查看模型的推理过程
9+
- 工具调用展示全面重构:分组折叠、状态指示、运行中工具实时输出
910

1011
### 修复问题
1112

12-
- 修复 Buddy 头像在部分网络环境下无法加载的问题(图片改为本地打包)
13-
- 修复 Windows 安装包下载链接指向错误文件名的问题
13+
- 修复中断或出错时已展示的推理内容(Thinking)在完成态消失的问题
14+
- 修复远程桥接(Telegram/Discord/飞书)静默丢弃推理内容的问题
15+
- 修复未注册工具(MCP 工具、插件工具等)在操作列表中不显示名称的问题
16+
- 修复 auth_token 认证方式未显式清空 API Key 导致部分服务商连接失败的问题
17+
18+
### 优化改进
19+
20+
- 服务商文档新增 Ollama 配置指南(中英双语)
1421

1522
## 下载地址
1623

1724
### macOS
18-
- [Apple Silicon (M1/M2/M3/M4)](https://github.com/op7418/CodePilot/releases/download/v0.45.1/CodePilot-0.45.1-arm64.dmg)
19-
- [Intel](https://github.com/op7418/CodePilot/releases/download/v0.45.1/CodePilot-0.45.1-x64.dmg)
25+
- [Apple Silicon (M1/M2/M3/M4)](https://github.com/op7418/CodePilot/releases/download/v0.46.0/CodePilot-0.46.0-arm64.dmg)
26+
- [Intel](https://github.com/op7418/CodePilot/releases/download/v0.46.0/CodePilot-0.46.0-x64.dmg)
2027

2128
### Windows
22-
- [Windows 安装包](https://github.com/op7418/CodePilot/releases/download/v0.45.1/CodePilot.Setup.0.45.1.exe)
29+
- [Windows 安装包](https://github.com/op7418/CodePilot/releases/download/v0.46.0/CodePilot.Setup.0.46.0.exe)
2330

2431
## 安装说明
2532

@@ -29,5 +36,5 @@
2936
## 系统要求
3037

3138
- macOS 12.0+ / Windows 10+ / Linux (glibc 2.31+)
32-
- 需要配置 API 服务商(Anthropic / OpenRouter 等)
39+
- 需要配置 API 服务商(Anthropic / OpenRouter / Ollama 等)
3340
- 推荐安装 Claude Code CLI 以获得完整功能

apps/site/content/docs/en/providers.mdx

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,13 @@ Gemini image generation API, used by the design Agent.
101101
- **Auth**: API Key
102102
- **Note**: This is a provider specifically for image generation, not for text conversations
103103

104-
### Custom API (OpenAI-Compatible)
104+
### Ollama (Local Models)
105105

106-
Any endpoint compatible with the OpenAI Chat Completions API.
106+
Run local models through Ollama. Ollama provides an Anthropic-compatible API that CodePilot can connect to directly.
107107

108-
- **Auth**: API Key + Base URL
109-
- **Use case**: Connect local models (Ollama, LM Studio, vLLM) or other third-party proxies
108+
- **Auth**: No API key needed (handled automatically)
109+
- **Prerequisite**: Ollama must be installed and running
110+
- **Setup**: See [Ollama Setup Guide](#ollama-setup-guide) below
110111

111112
### LiteLLM
112113

@@ -155,4 +156,41 @@ Unified proxy supporting 100+ LLM providers.
155156

156157
### How to use local models
157158

158-
Select the **Custom API (OpenAI-Compatible)** type, and enter the local service address as the Base URL (e.g., `http://localhost:11434/v1`). The API key can be any value (local services typically don't validate it).
159+
The recommended way is to use the **Ollama** preset — see the [Ollama Setup Guide](#ollama-setup-guide) below. You can also use **LiteLLM** to connect other local inference frameworks (vLLM, LM Studio, etc.).
160+
161+
---
162+
163+
## Ollama Setup Guide
164+
165+
Ollama lets you run open-source models locally — no API key required, completely free. This guide walks through the full setup using `gemma4:e4b` as an example.
166+
167+
### Step 1: Install Ollama and Run a Model
168+
169+
```bash
170+
# Install Ollama
171+
curl -fsSL https://ollama.com/install.sh | sh
172+
173+
# Pull and run a model (this also starts the Ollama service)
174+
ollama run gemma4:e4b
175+
```
176+
177+
The model will enter interactive chat mode. Once you confirm it responds normally, press `Ctrl+D` to exit. The Ollama service continues running in the background.
178+
179+
> **Model names matter**: The model name you enter in CodePilot must **exactly match** the name shown by `ollama list` (including the tag after the colon). For example, `gemma4:e4b` — not just `gemma4`.
180+
181+
For more models and usage, see the [Ollama documentation](https://docs.ollama.com/).
182+
183+
### Step 2: Add Ollama in CodePilot
184+
185+
1. Open **Settings > Providers**
186+
2. Find **Ollama** at the bottom of the provider list and click **+ Connect**
187+
3. Configure:
188+
- **Base URL**: Keep the default `http://localhost:11434` (change if Ollama runs on a different port or remote machine)
189+
- **Model Name**: Enter `gemma4:e4b` (must exactly match the name from `ollama list`)
190+
4. Click **Save**
191+
192+
### Step 3: Start Chatting
193+
194+
1. Create a new conversation
195+
2. Switch to **Ollama** in the provider selector at the top of the conversation
196+
3. Send a message — the model runs inference locally

apps/site/content/docs/zh/providers.mdx

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,13 @@ Gemini 图片生成 API,供设计 Agent 使用。
101101
- **认证**:API 密钥
102102
- **说明**:这是专门用于图片生成的服务商,不用于文本对话
103103

104-
### Custom API(OpenAI 兼容
104+
### Ollama(本地模型
105105

106-
任何兼容 OpenAI Chat Completions API 的端点
106+
通过 Ollama 运行本地模型。Ollama 提供了 Anthropic 兼容的 API,CodePilot 可以直接连接
107107

108-
- **认证**:API 密钥 + 基础 URL
109-
- **用途**:接入本地模型(Ollama、LM Studio、vLLM)或其他第三方代理
108+
- **认证**:无需 API 密钥(系统自动处理)
109+
- **前提**:需要先安装并启动 Ollama
110+
- **详细配置**:参见下方 [Ollama 配置指南](#ollama-配置指南)
110111

111112
### LiteLLM
112113

@@ -155,4 +156,41 @@ Gemini 图片生成 API,供设计 Agent 使用。
155156

156157
### 如何使用本地模型
157158

158-
选择 **Custom API(OpenAI 兼容)** 类型,基础 URL 填写本地服务地址(如 `http://localhost:11434/v1`)。API 密钥可填任意值(本地服务通常不校验)。
159+
推荐使用 **Ollama** 预设,参见下方 [Ollama 配置指南](#ollama-配置指南)。也可以选择 **LiteLLM** 接入其他本地推理框架(如 vLLM、LM Studio)。
160+
161+
---
162+
163+
## Ollama 配置指南
164+
165+
通过 Ollama 可以在本地运行开源模型,无需 API 密钥,完全免费。以下以 `gemma4:e4b` 为例演示完整配置流程。
166+
167+
### 第一步:安装 Ollama 并运行模型
168+
169+
```bash
170+
# 安装 Ollama
171+
curl -fsSL https://ollama.com/install.sh | sh
172+
173+
# 拉取并运行模型(会自动启动 Ollama 服务)
174+
ollama run gemma4:e4b
175+
```
176+
177+
运行后模型会进入交互对话模式,确认能正常回复后按 `Ctrl+D` 退出即可。Ollama 服务会在后台继续运行。
178+
179+
> **模型名称很重要**:在 CodePilot 中填写的模型名称必须与 `ollama list` 显示的名称**完全一致**(包括冒号后的标签部分)。例如 `gemma4:e4b`,不能只写 `gemma4`
180+
181+
更多模型和用法参见 [Ollama 官方文档](https://docs.ollama.com/)
182+
183+
### 第二步:在 CodePilot 中添加 Ollama
184+
185+
1. 打开 **设置 > 服务商**
186+
2. 在服务商列表底部找到 **Ollama**,点击 **+ 连接**
187+
3. 配置以下信息:
188+
- **基础 URL**:保持默认 `http://localhost:11434`(如果 Ollama 运行在其他端口或远程机器上,修改为对应地址)
189+
- **模型名称**:填写 `gemma4:e4b`(必须与 `ollama list` 中的名称完全一致)
190+
4. 点击 **保存**
191+
192+
### 第三步:开始对话
193+
194+
1. 新建对话
195+
2. 在对话顶部的服务商选择器中切换到 **Ollama**
196+
3. 发送消息,模型会在本地运行推理

docs/handover/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@
2424
| buddy-gamification.md | Buddy 游戏化系统:生成/进化/3D 视觉、心跳双模式(完整 tick + 软 hint)、定时任务调度器健壮性、通知队列/轮询/Electron IPC、symlink 安全、cron 4 年扫描 |
2525
| context-management.md | 上下文管理系统:token 预估、自动压缩(80% 阈值)、消息归一化 + microcompaction、PTL reactive compact、前端双指标可视化 |
2626
| cli-upgrade-proxy.md | CLI 版本检测 + 一键升级 + 系统代理透传 + WinGet 支持 + Git for Windows 自动安装 |
27+
| tool-call-ux.md | 工具调用 UX 优化:thinking 展示全链路、工具注册表、上下文归组、状态动画、流式缓冲/节流 |
28+
| performance-memory.md | v0.45.0 内存优化:LRU 缓存、消息 300 条上限双向修剪、面板懒加载、流式文件读取、定时器追踪 |
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# 性能与内存优化 — 技术交接
2+
3+
> 产品思考见 [docs/insights/performance-memory.md](../insights/performance-memory.md)
4+
5+
## 概述
6+
7+
v0.45.0 的一次性内存优化,解决长对话/多工具调用场景下的渲染端内存膨胀问题。改动覆盖前端缓存、流式管道、懒加载、消息上限四个维度。
8+
9+
## 前端缓存与资源限制
10+
11+
### Shiki 高亮器缓存 → LRU
12+
13+
**文件**`src/components/ai-elements/code-block.tsx`
14+
15+
- Highlighter 缓存:`Map` → LRU(10 entries),key = `"lang:lightTheme:darkTheme"`
16+
- Token 缓存:`Map` → LRU(200 entries),key = `"lang:lightTheme:darkTheme:codeLength:first100:last100"`
17+
- 原来无上限,长对话累积数百种 lang+theme 组合导致内存持续增长
18+
19+
### 终端输出上限
20+
21+
**文件**`src/components/terminal/TerminalInstance.tsx`
22+
23+
终端输出硬上限 `MAX_OUTPUT_CHARS = 500_000`(约 500KB),超出时 `slice(-MAX_OUTPUT_CHARS)` 丢弃最早部分。防止 `npm install` 等命令产生的大量输出撑爆内存。
24+
25+
### 图片引用上限
26+
27+
**文件**`src/lib/image-ref-store.ts`
28+
29+
统一 `store` Map(包含 pending refs、last-generated refs、message-bound refs)上限 50 entries,超出时按插入顺序淘汰最老条目。原来无限增长,多图场景(image agent 批量生成)会积累大量引用。
30+
31+
### 流式工具输出窗口
32+
33+
**文件**`src/lib/stream-session-manager.ts`
34+
35+
`toolOutputAccumulated` 滑动窗口从 5000 字符缩减到 2000 字符。这是 stderr 实时输出的缓冲,只用于 UI 展示不需要保留全部。
36+
37+
## 懒加载
38+
39+
### 面板组件
40+
41+
**文件**`src/components/layout/PanelZone.tsx`
42+
43+
Preview、Git、FileTree、Dashboard、Assistant 五个面板从静态导入改为 `next/dynamic({ ssr: false })`,首屏不加载。
44+
45+
### PreviewPanel 依赖
46+
47+
**文件**`src/components/layout/panels/PreviewPanel.tsx`
48+
49+
Streamdown + plugins(cjk/code/math/mermaid)改为通过 `loadStreamdown()` 动态 `import()` 按需加载。这些是大包(Shiki 语法库尤其大),按需加载后首屏 JS 体积显著减小。
50+
51+
## 消息列表上限
52+
53+
**文件**`src/components/chat/ChatView.tsx``src/hooks/useStreamSubscription.ts`
54+
55+
**核心机制**:消息列表硬上限 300 条,双向修剪:
56+
57+
| 操作 | 行为 |
58+
|------|------|
59+
| 加载历史(prepend) | 新消息加到头部,超出上限时裁剪尾部。reconciliation 恢复。 |
60+
| 新消息(append) | 新消息加到尾部,超出上限时裁剪头部,重新启用 `hasMore` 按钮。 |
61+
| 流式完成 | `onStreamCompleted` 触发 DB reconciliation 恢复正确的消息列表。 |
62+
| 错误/停止 | 跳过 reconciliation,防止丢弃未持久化的临时内容。 |
63+
64+
**特殊保护**:本地 `cmd-*` 消息(slash command 结果)在 reconciliation 时保留,不因 DB 缺少对应记录而被丢弃。
65+
66+
**滚动锚定**`MessageList` 的 scroll anchor 从 length-based 改为 ID-based,避免 prepend 时计算错误。
67+
68+
## 服务端流式读取
69+
70+
### 文件预览
71+
72+
**文件**`src/lib/files.ts``readFilePreview` 函数),被 `src/app/api/files/preview/route.ts` 调用
73+
74+
`readFilePreview()``fs.readFileSync` 整文件读取改为 `createReadStream` + `readline.createInterface` 逐行读取。大文件(如 100MB 日志)不再加载到内存,只读取所需行数。达到行数上限时 `line_count_exact` 标记为 `false`,表示 `line_count` 是基于 `scannedLineCount``estimatedTotalLines` 的估算值。
75+
76+
### 大文件服务
77+
78+
**文件**`src/app/api/files/serve/route.ts``src/app/api/files/raw/route.ts`
79+
80+
>10MB 的文件使用 stream 响应而非 buffer 整文件。
81+
82+
### 图片 base64 及时清理
83+
84+
**文件**`src/app/api/chat/route.ts`(line 204)、`src/lib/claude-client.ts`(line ~930)
85+
86+
`/api/chat` 构建 `fileAttachments` 时,已写入磁盘的文件(`meta?.filePath` 存在)将 `data` 设为空字符串:`data: meta?.filePath ? '' : f.data``claude-client.ts` 的 vision API 调用对此做了防御性处理——当 `data` 为空时从 `filePath` 按需读取 base64。这样大图片的 base64 不会在内存中长期驻留。
87+
88+
## stream-session-manager 定时器清理
89+
90+
**文件**`src/lib/stream-session-manager.ts`
91+
92+
原来有 4 个 `setTimeout` 调用分散在代码中,流结束时只清了 `idleCheckTimer``gcTimer`,其他定时器可能泄漏。
93+
94+
改造:
95+
- `pendingTimers: Set<ReturnType<typeof setTimeout>>` 追踪所有 ad-hoc 定时器
96+
- `streamTimeout()` helper 创建定时器并自动注册到 Set
97+
- `cleanupTimers()` 遍历 Set 全部清理

docs/handover/tool-call-ux.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# 工具调用 UX 优化 — 技术交接
2+
3+
> 产品思考见 [docs/insights/tool-call-ux.md](../insights/tool-call-ux.md)
4+
> 竞品调研见 [docs/research/tool-call-ux-competitive-analysis.md](../research/tool-call-ux-competitive-analysis.md)
5+
6+
## 概述
7+
8+
对 CodePilot 工具调用展示层的全面升级,覆盖 thinking 展示、工具分类渲染、上下文归组、状态动画、流式优化等。基于 Claude Code / CraftAgent / Opencode / Codex 四个竞品的调研结论实施。
9+
10+
## 改动清单
11+
12+
### 1. Thinking Display 全链路
13+
14+
**数据流:**
15+
```
16+
claude-client.ts (thinking delta → SSE 'thinking')
17+
→ useSSEStream.ts (onThinking callback)
18+
→ stream-session-manager.ts (accumulatedThinking + phase separation)
19+
→ ChatView.tsx → MessageList.tsx → StreamingMessage.tsx
20+
→ ToolActionsGroup.tsx (ThinkingRow component)
21+
```
22+
23+
**关键文件:**
24+
25+
| 文件 | 改动 |
26+
|------|------|
27+
| `src/lib/claude-client.ts` | 两处 `stream_event` handler 转发 `thinking_delta`;retry 路径补齐 content/is_error/media |
28+
| `src/types/index.ts` | `SSEEventType` + `'thinking'``SessionStreamSnapshot` + `streamingThinkingContent``MessageContentBlock` + thinking 变体 |
29+
| `src/hooks/useSSEStream.ts` | `SSECallbacks.onThinking``handleSSEEvent` case `'thinking'` |
30+
| `src/lib/stream-session-manager.ts` | `accumulatedThinking` / `fullThinking` / `thinkingPhaseEnded` 三层累积;phase 分隔(text/tool_use 到来时重置当前 phase) |
31+
| `src/components/ai-elements/tool-actions-group.tsx` | `ThinkingRow` 组件:Brain 图标 → hover 变 CaretRight 可展开;Streamdown 渲染内容 |
32+
33+
**持久化路径:**
34+
- 客户端:`finalMessageContent` 序列化时包含 `{ type: 'thinking', thinking: allThinking }` block
35+
- 服务端:`/api/chat/route.ts``collectStreamResponse` 累积 `thinkingText` 并 unshift 到 `contentBlocks`
36+
- 历史渲染:`MessageItem.tsx``parseToolBlocks` 提取 thinking,传给 `ToolActionsGroup.thinkingContent`
37+
- 归一化:`message-normalizer.ts` 识别 thinking block,生成 `(reasoning: summary)` 摘要
38+
39+
**Phase 分隔机制:**
40+
多轮工具调用场景中,SDK 会在每轮产生新的 thinking block。`thinkingPhaseEnded` 标记在 text/tool_use 到来时设为 true,新 thinking delta 到来时将当前 thinking 保存到 `fullThinking`(用 `---` 分隔),重置 `accumulatedThinking`。UI 只显示当前 phase,持久化保存全部 phases。
41+
42+
**展开时防跳动:**
43+
`ThinkingRow` 展开时调用 `useStickToBottomContext().stopScroll()` 脱离自动滚动模式,避免内容展开触发 `use-stick-to-bottom` 的 resize 自动滚动。
44+
45+
### 2. ToolActionsGroup 重构
46+
47+
**工具注册表(ToolRegistry):**
48+
49+
```typescript
50+
interface ToolRendererDef {
51+
match: (name: string) => boolean;
52+
icon: Icon;
53+
label: string;
54+
getSummary: (input: unknown) => string;
55+
renderDetail?: (tool: ToolAction, streamingOutput?: string) => ReactNode;
56+
}
57+
```
58+
59+
内置 5 种渲染器(bash/edit/read/search/fallback),通过 `registerToolRenderer()` 可扩展。替代了原来的 `getToolCategory` / `getToolIcon` / `getToolSummary` 硬编码函数。
60+
61+
**上下文工具归组:**
62+
`computeSegments()` 线性扫描 tools 数组,连续 3+ 个 CONTEXT_TOOLS(read/glob/grep/list/search)合并为 `ContextGroup`。2 个不归组。ContextGroup 有独立的展开/折叠和 StatusDot。
63+
64+
**Bash 实时输出:**
65+
`renderDetail` 在 running 时显示 `streamingToolOutput` 最后 5 行(滚动窗口),完成后显示 `tool.result` 前 20 行。`streamingToolOutput` prop 去掉了原来的 `_` 前缀启用。
66+
67+
**Flat 模式:**
68+
`flat` prop 跳过 header 和折叠动画,直接渲染工具列表。目前未使用但保留作为扩展点。
69+
70+
**Header 布局:**
71+
内容(数量 badge + 摘要 + 运行描述)在左,CaretRight 箭头在右(`ml-auto`)。
72+
73+
### 3. 状态动画
74+
75+
`StatusDot``AnimatePresence mode="wait"` 包裹三个状态:
76+
- running: opacity fade(SpinnerGap + animate-spin)
77+
- success: spring scale 弹入(stiffness 400, damping 20)
78+
- error: 同上
79+
80+
Header 运行描述用 `Shimmer` 包裹闪烁。
81+
82+
### 4. is_error 全链路修复
83+
84+
```
85+
claude-client.ts (tool_result SSE 包含 is_error)
86+
→ useSSEStream.ts (提取 is_error)
87+
→ stream-session-manager.ts (透传到 snapshot + finalMessageContent)
88+
→ ToolActionsGroup (StatusDot 显示红色 XCircle)
89+
```
90+
91+
同步修复了 `page.tsx``route.ts` 中的本地 ToolResultInfo 类型。
92+
93+
### 5. 流式优化
94+
95+
**智能文本缓冲(`useBufferedContent` hook):**
96+
- 40 词阈值或 2.5s max timeout 后释放
97+
- 结构化块(show-widget/batch-plan/image-gen-request)旁路直通
98+
- Timer 锚定到首次内容到达(`hasContent` boolean gate),不随 delta 重建
99+
- 所有 bypass 决策通过 `useEffect` 执行,render 路径纯计算
100+
101+
**自适应文本节流(stream-session-manager):**
102+
- `throttledTextEmit()`:100ms 节流,非 text 事件(tool_use 等)触发 `flushTextThrottle()`
103+
- 定义在 try/catch 外层,error path 也能访问
104+
105+
### 6. Diff Summary
106+
107+
`DiffSummary` 组件在 `MessageItem.tsx` 中:从 pairedTools 提取 edit/write 工具的文件路径,去重后显示 "Modified N files" 折叠行。
108+
109+
## 测试覆盖
110+
111+
| 文件 | 覆盖点 |
112+
|------|--------|
113+
| `__tests__/unit/sse-stream.test.ts` | thinking 事件分发、不混入 text、is_error 提取、media 透传 |
114+
| `__tests__/unit/message-normalizer.test.ts` | thinking-only 摘要、heading 提取、组合消息、长文本截断 |
115+
116+
## 已知局限
117+
118+
- Thinking 展开后调用 `stopScroll()` 会脱离自动滚动,需要用户手动点滚动按钮回到底部
119+
- 上下文归组只基于工具名匹配,不区分 MCP vs 内置工具
120+
- Bash renderDetail 在历史消息中总是展开(showDetail 条件含 tool.result),长输出占空间

0 commit comments

Comments
 (0)