feat: reasoning/thinking互通适配 + history窗口扩大 + summary提示强化

This commit is contained in:
Liang Jiaqing
2026-04-25 10:33:42 +08:00
parent 114dfdb211
commit cac3ba4769
3 changed files with 23 additions and 9 deletions

View File

@@ -229,6 +229,7 @@ def _parse_openai_sse(resp_lines, api_mode="chat_completions"):
return blocks
else:
tc_buf = {} # index -> {id, name, args}
reasoning_text = ""
for line in resp_lines:
if not line: continue
line = line.decode('utf-8', errors='replace') if isinstance(line, bytes) else line
@@ -239,6 +240,8 @@ def _parse_openai_sse(resp_lines, api_mode="chat_completions"):
except: continue
ch = (evt.get("choices") or [{}])[0]
delta = ch.get("delta") or {}
if delta.get("reasoning_content"):
reasoning_text += delta["reasoning_content"]
if delta.get("content"):
text = delta["content"]; content_text += text; yield text
for tc in (delta.get("tool_calls") or []):
@@ -253,6 +256,7 @@ def _parse_openai_sse(resp_lines, api_mode="chat_completions"):
usage = evt.get("usage")
if usage: _record_usage(usage, api_mode)
blocks = []
if reasoning_text: blocks.append({"type": "thinking", "thinking": reasoning_text})
if content_text: blocks.append({"type": "text", "text": content_text})
for idx in sorted(tc_buf):
tc = tc_buf[idx]
@@ -294,6 +298,9 @@ def _parse_openai_json(data, api_mode="chat_completions"):
else:
_record_usage(data.get("usage") or {}, api_mode)
msg = (data.get("choices") or [{}])[0].get("message", {})
reasoning = msg.get("reasoning_content", "")
if reasoning:
blocks.append({"type": "thinking", "thinking": reasoning})
content = msg.get("content", "")
if content:
blocks.append({"type": "text", "text": content}); yield content
@@ -412,8 +419,8 @@ def _to_responses_input(messages):
elif ptype == "image_url":
url = (part.get("image_url") or {}).get("url", "")
if url and role != "assistant": parts.append({"type": "input_image", "image_url": url})
if len(parts) == 0: parts = [{"type": text_type, "text": str(content) or '[empty]'}]
result.append({"role": role, "content": parts})
if len(parts) == 0 and not isinstance(content, list): parts = [{"type": text_type, "text": str(content) or '[empty]'}]
if parts: result.append({"role": role, "content": parts})
pending = []
for tc in (msg.get("tool_calls") or []):
f = tc.get("function", {})
@@ -430,16 +437,18 @@ def _msgs_claude2oai(messages):
content = msg.get("content", "")
blocks = content if isinstance(content, list) else [{"type": "text", "text": str(content)}]
if role == "assistant":
text_parts, tool_calls = [], []
text_parts, tool_calls, reasoning = [], [], ""
for b in blocks:
if not isinstance(b, dict): continue
if b.get("type") == "text" and b.get("text"): text_parts.append({"type": "text", "text": b.get("text", "")})
if b.get("type") == "thinking" and b.get("thinking"): reasoning = b["thinking"]
elif b.get("type") == "text" and b.get("text"): text_parts.append({"type": "text", "text": b.get("text", "")})
elif b.get("type") == "tool_use":
tool_calls.append({
"id": b.get("id") or '', "type": "function",
"function": {"name": b.get("name", ""), "arguments": json.dumps(b.get("input", {}), ensure_ascii=False)}
})
m = {"role": "assistant"}
if reasoning: m["reasoning_content"] = reasoning
if text_parts: m["content"] = text_parts
else: m["content"] = ""
if tool_calls: m["tool_calls"] = tool_calls
@@ -525,6 +534,11 @@ class BaseSession:
if not content.startswith("!!!Error:"): self.history.append({"role": "assistant", "content": [{"type": "text", "text": content}]})
return _ask_gen() if stream else ''.join(list(_ask_gen()))
def _keep_claude_block(b): return not isinstance(b, dict) or b.get("type") != "thinking" or b.get("signature")
def _drop_unsigned_thinking(messages):
for m in messages: m["content"] = [b for b in m["content"] if _keep_claude_block(b)]
return messages
class ClaudeSession(BaseSession):
def raw_ask(self, messages):
headers = {"x-api-key": self.api_key, "Content-Type": "application/json", "anthropic-version": "2023-06-01", "anthropic-beta": "prompt-caching-2024-07-31"}
@@ -540,7 +554,7 @@ class ClaudeSession(BaseSession):
yield (err := f"!!!Error: {e}")
return [{"type": "text", "text": err}]
def make_messages(self, raw_list):
msgs = [{"role": m['role'], "content": list(m['content'])} for m in raw_list]
msgs = _drop_unsigned_thinking([{"role": m['role'], "content": list(m['content'])} for m in raw_list])
user_idxs = [i for i, m in enumerate(msgs) if m['role'] == 'user']
for idx in user_idxs[-2:]:
msgs[idx]["content"][-1] = dict(msgs[idx]["content"][-1], cache_control={"type": "ephemeral"})
@@ -582,7 +596,7 @@ class NativeClaudeSession(BaseSession):
self._device_id = uuid.uuid4().hex + uuid.uuid4().hex[:32]
self.tools = None
def raw_ask(self, messages):
messages = _fix_messages(messages)
messages = _drop_unsigned_thinking(_fix_messages(messages))
model = self.model
beta_parts = ["claude-code-20250219", "interleaved-thinking-2025-05-14", "redact-thinking-2026-02-12", "prompt-caching-scope-2026-01-05"]
if "[1m]" in model.lower():