- Fixed shared client pool bug to eliminate TTFT latency. - Added pure BYOK-only mode support. - Improved cross-user environment isolation for concurrency. - Resolved RichUI infinite vertical sizing loop. - Integrated client.ping() into stall detection. - Automatically hide TODO List widget after completion. - Synced all documentation and release notes.
3.1 KiB
GitHub Copilot SDK 卡顿/悬停问题深度源码分析报告
📌 问题现象
用户反馈在 agent 处理过程中(工具调用、思考、内容输出),github_copilot_sdk.py 管道偶尔会卡住(界面转圈不停)。
🔍 事件流架构(SDK 源码分析)
通过阅读 copilot-sdk 源码 (jsonrpc.py, client.py, session.py),事件流路径如下:
Copilot CLI (subprocess)
└─ stdout (JSON-RPC over stdio)
└─ JsonRpcClient._read_loop() [daemon thread]
└─ _handle_message()
└─ notification_handler("session.event", params) [线程安全调度到 event loop]
└─ CopilotSession._dispatch_event(event)
└─ plugin handler(event) → queue.put_nowait(chunk)
└─ main loop: await queue.get() → yield chunk
🚨 已确认的三个卡顿根因
根因 1: Stall 检测豁免盲区
原始代码的防卡死检测仅在 content_sent=False 且 thinking_started=False 且 running_tool_calls 为空时才触发。一旦 agent 开始处理(输出内容/调用工具),所有豁免条件为真,防卡死机制永久失效。
根因 2: 工具调用状态泄漏
running_tool_calls.add(tool_call_id) 在 tool.execution_start 时添加,但如果 SDK 连接断开导致 tool.execution_complete 事件丢失,集合永远不为空,直接阻塞 Stall 检测。
根因 3: session.abort() 自身可能卡住(SDK 源码确认)
SDK 源码关键证据 (jsonrpc.py:107-148):
async def request(self, method, params=None, timeout=None):
...
if timeout is not None:
return await asyncio.wait_for(future, timeout=timeout)
return await future # ← 无 timeout,永久等待!
session.abort() 底层调用 self._client.request("session.abort", ...) 没有传 timeout。
当 CLI 进程挂死但 _read_loop 尚未检测到断流(例如 TCP 半开连接),abort() RPC 自身会无限等待响应,造成修复代码自身也卡住。
✅ 修复记录 (2026-03-18)
修复 1: assistant.turn_end / session.error 兜底清理
running_tool_calls.clear() — 即时清除孤儿工具状态。
修复 2: 绝对不活跃保护 (Absolute Inactivity Guard)
当距最后一个事件超过 min(TIMEOUT, 90) × 2 = 180s 且无任何新事件时,无条件推送错误并结束流。不受 content_sent / thinking_started / running_tool_calls 任何豁免条件限制。
修复 3: session.abort() 超时保护
所有 session.abort() 调用使用 asyncio.wait_for(..., timeout=5.0) 包裹。即使 abort RPC 自身卡住也不会阻塞主循环。
📊 修复后超时时间线
| 场景 | 保护机制 | 触发时间 |
|---|---|---|
| Turn 开始后完全无事件 | Primary Stall Detection | 90 秒 |
| Agent 处理中突然断流 | Absolute Inactivity Guard | 180 秒 |
| abort() 调用本身卡住 | asyncio.wait_for timeout | 5 秒 |
| Turn 结束/Session 错误 | 兜底 running_tool_calls.clear() | 即时 |
Created by Antigravity using Source-Code-Analyzer skill on 2026-03-18.