Skip to content

feat(gemini): inline thinking display in conversation flow#2013

Merged
piorpua merged 2 commits intomainfrom
zk/feat/gemini-inline-thinking
Apr 1, 2026
Merged

feat(gemini): inline thinking display in conversation flow#2013
piorpua merged 2 commits intomainfrom
zk/feat/gemini-inline-thinking

Conversation

@kaizhou-lab
Copy link
Copy Markdown
Collaborator

Summary

  • Convert Gemini thought stream events to thinking typed messages displayed inline in the conversation, matching ACP behavior from feat(acp): inline thinking display, plan dedup, and processing indicator fixes #1953
  • Add emitThinkingMessage/flushThinkingToDb to GeminiAgentManager for buffered DB persistence of thinking content
  • Handle thinking message type in useGeminiMessage hook with hasThinkingMessage state tracking
  • Hide ThoughtDisplay floating panel when thinking messages are shown inline in GeminiSendBox

Test plan

  • bun run lint — 0 errors
  • bunx tsc --noEmit — pass
  • bunx vitest run — pass (previewFileWatch failure is pre-existing on main)
  • Send message in Gemini conversation, verify thinking content appears inline as collapsible block with timer
  • Verify thinking block collapses when done, showing duration
  • Refresh page and verify thinking messages persist in history
  • Verify models with <think> tags in content (e.g. via proxy) have tags extracted and shown as thinking blocks

Closes #2012

Convert Gemini thought events to thinking messages that are displayed
inline in the conversation and persisted to the database, matching the
ACP implementation from PR #1953.

- GeminiAgentManager: add emitThinkingMessage/flushThinkingToDb, convert
  thought events to thinking messages, extract inline <think> tags from
  content, finalize thinking on finish signal
- useGeminiMessage: handle thinking message type, track hasThinkingMessage
- GeminiSendBox: hide ThoughtDisplay when thinking messages are shown inline
@piorpua piorpua added the bot:reviewing Review in progress (mutex) label Apr 1, 2026
@piorpua
Copy link
Copy Markdown
Contributor

piorpua commented Apr 1, 2026

Code Review:feat(gemini): inline thinking display in conversation flow (#2013)

变更概述

本 PR 将 Gemini 的 thought 流事件转换为 thinking 类型消息,使其以内联折叠块的形式显示在对话流中,与 ACP 行为对齐(#1953)。主要改动涉及三个文件:GeminiAgentManager.ts 新增 emitThinkingMessage/flushThinkingToDb 用于流式内容积累与 DB 持久化;useGeminiMessage.ts 新增 hasThinkingMessage 状态追踪;GeminiSendBox.tsx 在有内联 thinking 消息时隐藏 ThoughtDisplay 浮层。


方案评估

结论:✅ 方案合理

方案正确解决了目标问题:通过 thought 事件→内联 thinking 消息的转换,使 Gemini 思考过程与 ACP 行为对齐。职责边界清晰——主进程负责内容积累与 DB 持久化(flushThinkingToDb),渲染侧负责 UI 状态更新(useAddOrUpdateMessage 只更新 React 内存状态,不写 DB)。chatLib.tsthinking 消息合并逻辑正确处理了流式追加和 done 状态切换,整体与项目架构一致。


问题清单

🟡 MEDIUM — 新增核心逻辑缺少单元测试

文件src/process/task/GeminiAgentManager.ts,第 931–989 行

问题代码

private emitThinkingMessage(content: string, status: 'thinking' | 'done' = 'thinking'): void { ... }
private flushThinkingToDb(duration: number | undefined, status: 'thinking' | 'done'): void { ... }

问题说明:这两个方法包含有状态逻辑(内容积累、定时器管理、thinkingMsgId 生命周期、DB 持久化),是本 PR 新增功能的核心。目前没有对应的单元测试覆盖以下场景:

  • 多次 thought 事件后内容是否正确积累
  • done 触发时定时器是否被清除
  • 中途 content 事件是否正确终止 thinking 阶段
  • flushThinkingToDbthinkingMsgId 为 null 时的提前返回路径

修复建议:在 GeminiAgentManager 的测试文件中补充针对这两个私有方法的行为测试(可通过 jest.spyOn 或测试公开 IPC 输出来验证)。


🔵 LOW — hasThinkingMessageRef 赋值但从未读取

文件src/renderer/pages/conversation/platforms/gemini/useGeminiMessage.ts,第 33 行

问题代码

const hasThinkingMessageRef = useRef(false);
// .current 在所有赋值处(第 136、155、315、368 行)被设置,但从未被读取

问题说明hasThinkingMessageRef 在多处被赋值,但其 .current 的值从未在任何地方被读取(事件回调、effect 或 useCallback 中均未使用)。实际使用的是 hasThinkingMessage state。ref 的目的是避免 stale closure,但这里并不需要在事件监听器中读取此值,所以 ref 是多余的。

修复建议

// 删除 ref,仅保留 state
// const hasThinkingMessageRef = useRef(false);  ← 删除
const [hasThinkingMessage, setHasThinkingMessage] = useState(false);

// 同时删除所有 hasThinkingMessageRef.current = ... 赋值

汇总

# 严重级别 文件 问题
1 🟡 MEDIUM GeminiAgentManager.ts:931-989 新增核心逻辑缺少单元测试
2 🔵 LOW useGeminiMessage.ts:33 hasThinkingMessageRef 赋值但从未读取

结论

⚠️ 有条件批准 — 核心逻辑正确,无阻塞性缺陷,MEDIUM 问题(缺少测试)建议作者补充后合并。


本报告由本地 pr-review skill 生成,包含完整项目上下文,无截断限制。

@piorpua piorpua added bot:ready-to-fix CONDITIONAL review done, waiting for bot fix bot:fixing Fix in progress (mutex) and removed bot:reviewing Review in progress (mutex) bot:ready-to-fix CONDITIONAL review done, waiting for bot fix labels Apr 1, 2026
…gToDb

- Cover content accumulation across multiple thought chunks
- Verify thinkingMsgId reuse within a single turn
- Assert DB flush timer is created on first chunk and cleared on done
- Confirm flushThinkingToDb returns early when thinkingMsgId is null
- Validate addOrUpdateMessage receives correct TMessage shape

Review follow-up for #2013
@piorpua
Copy link
Copy Markdown
Contributor

piorpua commented Apr 1, 2026

PR Fix 验证报告

原始 PR: #2013
修复方式: 直接推送到 zk/feat/gemini-inline-thinking

# 严重级别 文件 问题 修复方式 状态
1 🟡 MEDIUM GeminiAgentManager.ts:931-989 新增核心逻辑缺少单元测试 新增 tests/unit/geminiAgentManagerThinking.test.ts,13 个测试覆盖:内容积累、MsgId 复用、定时器创建与清除、thinkingMsgId 为 null 时的提前返回、addOrUpdateMessage 正确调用 ✅ 已修复

总结: ✅ 已修复 1 个 | ❌ 未能修复 0 个

🔵 LOW 级别问题(hasThinkingMessageRef 赋值但从未读取)已跳过(不阻塞合并,修复优先级低)。

@piorpua piorpua enabled auto-merge (squash) April 1, 2026 10:13
@piorpua piorpua added bot:done Auto-merged by bot and removed bot:fixing Fix in progress (mutex) labels Apr 1, 2026
@piorpua piorpua merged commit a4f4dc7 into main Apr 1, 2026
15 of 17 checks passed
@piorpua piorpua deleted the zk/feat/gemini-inline-thinking branch April 1, 2026 10:18
zhuqingyv pushed a commit that referenced this pull request Apr 2, 2026
* feat(gemini): inline thinking display in conversation flow

Convert Gemini thought events to thinking messages that are displayed
inline in the conversation and persisted to the database, matching the
ACP implementation from PR #1953.

- GeminiAgentManager: add emitThinkingMessage/flushThinkingToDb, convert
  thought events to thinking messages, extract inline <think> tags from
  content, finalize thinking on finish signal
- useGeminiMessage: handle thinking message type, track hasThinkingMessage
- GeminiSendBox: hide ThoughtDisplay when thinking messages are shown inline

* test(gemini): add unit tests for emitThinkingMessage and flushThinkingToDb

- Cover content accumulation across multiple thought chunks
- Verify thinkingMsgId reuse within a single turn
- Assert DB flush timer is created on first chunk and cleared on done
- Confirm flushThinkingToDb returns early when thinkingMsgId is null
- Validate addOrUpdateMessage receives correct TMessage shape

Review follow-up for #2013

---------

Co-authored-by: zk <[email protected]>
Co-authored-by: zynx <>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:done Auto-merged by bot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(gemini): inline thinking display in conversation flow

2 participants