mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-06-02 00:57:41 +08:00
feat: display thinking content in web console
This commit is contained in:
@@ -57,7 +57,16 @@ class ChatService:
|
||||
event_type = event.get("type")
|
||||
data = event.get("data", {})
|
||||
|
||||
if event_type == "message_update":
|
||||
if event_type == "reasoning_update":
|
||||
delta = data.get("delta", "")
|
||||
if delta:
|
||||
send_chunk_fn({
|
||||
"chunk_type": "reasoning",
|
||||
"delta": delta,
|
||||
"segment_id": state.segment_id,
|
||||
})
|
||||
|
||||
elif event_type == "message_update":
|
||||
# Incremental text delta
|
||||
delta = data.get("delta", "")
|
||||
if delta:
|
||||
|
||||
@@ -188,8 +188,9 @@ def _group_into_display_turns(
|
||||
if text:
|
||||
turns.append({"role": "user", "content": text, "created_at": created_at})
|
||||
|
||||
# Collect all tool_calls and tool_results from the rest of the group
|
||||
all_tool_calls: List[Dict[str, Any]] = []
|
||||
# Build an ordered list of steps preserving the original sequence:
|
||||
# thinking → content → tool_call → content → ...
|
||||
steps: List[Dict[str, Any]] = []
|
||||
tool_results: Dict[str, str] = {}
|
||||
final_text = ""
|
||||
final_ts: Optional[int] = None
|
||||
@@ -198,24 +199,46 @@ def _group_into_display_turns(
|
||||
if role == "user":
|
||||
tool_results.update(_extract_tool_results(content))
|
||||
elif role == "assistant":
|
||||
tcs = _extract_tool_calls(content)
|
||||
all_tool_calls.extend(tcs)
|
||||
t = _extract_display_text(content)
|
||||
if t:
|
||||
final_text = t
|
||||
# Walk content blocks in order to preserve interleaving
|
||||
if isinstance(content, list):
|
||||
for block in content:
|
||||
if not isinstance(block, dict):
|
||||
continue
|
||||
btype = block.get("type")
|
||||
if btype == "thinking":
|
||||
txt = block.get("thinking", "").strip()
|
||||
if txt:
|
||||
steps.append({"type": "thinking", "content": txt})
|
||||
elif btype == "text":
|
||||
txt = block.get("text", "").strip()
|
||||
if txt:
|
||||
steps.append({"type": "content", "content": txt})
|
||||
final_text = txt
|
||||
elif btype == "tool_use":
|
||||
steps.append({
|
||||
"type": "tool",
|
||||
"id": block.get("id", ""),
|
||||
"name": block.get("name", ""),
|
||||
"arguments": block.get("input", {}),
|
||||
})
|
||||
elif isinstance(content, str) and content.strip():
|
||||
steps.append({"type": "content", "content": content.strip()})
|
||||
final_text = content.strip()
|
||||
final_ts = created_at
|
||||
|
||||
# Attach tool results to their matching tool_call entries
|
||||
for tc in all_tool_calls:
|
||||
tc["result"] = tool_results.get(tc.get("id", ""), "")
|
||||
# Attach tool results to tool steps
|
||||
for step in steps:
|
||||
if step["type"] == "tool":
|
||||
step["result"] = tool_results.get(step.get("id", ""), "")
|
||||
|
||||
if final_text or all_tool_calls:
|
||||
turns.append({
|
||||
if steps or final_text:
|
||||
turn = {
|
||||
"role": "assistant",
|
||||
"content": final_text,
|
||||
"tool_calls": all_tool_calls,
|
||||
"steps": steps,
|
||||
"created_at": final_ts or (user_row[1] if user_row else 0),
|
||||
})
|
||||
}
|
||||
turns.append(turn)
|
||||
|
||||
return turns
|
||||
|
||||
@@ -312,6 +335,9 @@ class ConversationStore:
|
||||
content = json.loads(raw_content)
|
||||
except Exception:
|
||||
content = raw_content
|
||||
# Strip thinking blocks — they are stored for UI display only
|
||||
if role == "assistant" and isinstance(content, list):
|
||||
content = [b for b in content if b.get("type") != "thinking"]
|
||||
result.append({"role": role, "content": content})
|
||||
return result
|
||||
|
||||
|
||||
@@ -527,6 +527,7 @@ class AgentStreamExecutor:
|
||||
|
||||
# Streaming response
|
||||
full_content = ""
|
||||
full_reasoning = ""
|
||||
tool_calls_buffer = {} # {index: {id, name, arguments}}
|
||||
gemini_raw_parts = None # Preserve Gemini thoughtSignature for round-trip
|
||||
stop_reason = None # Track why the stream stopped
|
||||
@@ -584,10 +585,10 @@ class AgentStreamExecutor:
|
||||
if finish_reason:
|
||||
stop_reason = finish_reason
|
||||
|
||||
# Skip reasoning_content (internal thinking from models like GLM-5)
|
||||
reasoning_delta = delta.get("reasoning_content") or ""
|
||||
# if reasoning_delta:
|
||||
# logger.debug(f"🧠 [thinking] {reasoning_delta[:100]}...")
|
||||
if reasoning_delta:
|
||||
full_reasoning += reasoning_delta
|
||||
self._emit_event("reasoning_update", {"delta": reasoning_delta})
|
||||
|
||||
# Handle text content
|
||||
content_delta = delta.get("content") or ""
|
||||
@@ -788,7 +789,12 @@ class AgentStreamExecutor:
|
||||
# Add assistant message to history (Claude format uses content blocks)
|
||||
assistant_msg = {"role": "assistant", "content": []}
|
||||
|
||||
# Add text content block if present
|
||||
if full_reasoning:
|
||||
assistant_msg["content"].append({
|
||||
"type": "thinking",
|
||||
"thinking": full_reasoning
|
||||
})
|
||||
|
||||
if full_content:
|
||||
assistant_msg["content"].append({
|
||||
"type": "text",
|
||||
|
||||
Reference in New Issue
Block a user