refactor(ai_client): migrate _send_deepseek history loop to ChatMessage (Phase 5 part 1)
Phase 5: ChatMessage (part 1)
Before: 6 .get('role'/'content'/'tool_calls'/'tool_call_id') sites in _send_deepseek
After: 0
Delta: -6
Migrates _send_deepseek's history transformation loop from
dict-style access to ChatMessage direct field access:
msg = _ChatMessage.from_dict(msg_raw)
msg.role (was msg.get('role'))
msg.content (was msg.get('content'))
msg.tool_calls (was msg.get('tool_calls') / msg['tool_calls'])
msg.tool_call_id (was msg.get('tool_call_id'))
The api_msg dict (output for the DeepSeek API) is constructed via
direct field access. The tool_calls list is converted to dicts via
tc.to_dict() (preserves the existing API payload format).
Notes:
- msg_raw.get('reasoning_content') is preserved as-is because
reasoning_content is NOT a ChatMessage field.
- Local import 'from src.openai_schemas import ChatMessage as _ChatMessage'
follows the existing pattern in this file (lazy imports inside functions).
Tests: 36/36 pass (test_ai_client_result, test_ai_client_tool_loop,
test_deepseek_provider, test_openai_schemas).
This commit is contained in:
+12
-15
@@ -2202,29 +2202,26 @@ def _send_deepseek(md_content: str, user_message: str, base_dir: str,
|
||||
current_api_messages.append(sys_msg)
|
||||
|
||||
with history.lock:
|
||||
for i, msg in enumerate(history):
|
||||
# Create a clean copy of the message for the API
|
||||
role = msg.get("role")
|
||||
api_msg = {"role": role}
|
||||
from src.openai_schemas import ChatMessage as _ChatMessage
|
||||
for i, msg_raw in enumerate(history):
|
||||
msg = _ChatMessage.from_dict(msg_raw)
|
||||
api_msg = {"role": msg.role}
|
||||
|
||||
content = msg.get("content")
|
||||
content = msg.content
|
||||
if i == 0 and is_reasoner:
|
||||
# Prepend system instructions to the first user message for R1
|
||||
content = f"System Instructions:\n{_get_combined_system_prompt()}\n\nContext:\n{md_content}\n\n---\n\n{content}"
|
||||
|
||||
if role == "assistant":
|
||||
# OpenAI/DeepSeek: content MUST be a string if tool_calls is absent
|
||||
# If tool_calls is present, content can be null
|
||||
if msg.get("tool_calls"):
|
||||
if msg.role == "assistant":
|
||||
if msg.tool_calls:
|
||||
api_msg["content"] = content or None
|
||||
api_msg["tool_calls"] = msg["tool_calls"]
|
||||
api_msg["tool_calls"] = [tc.to_dict() for tc in msg.tool_calls]
|
||||
else:
|
||||
api_msg["content"] = content or ""
|
||||
if msg.get("reasoning_content"):
|
||||
api_msg["reasoning_content"] = msg["reasoning_content"]
|
||||
elif role == "tool":
|
||||
if msg_raw.get("reasoning_content"):
|
||||
api_msg["reasoning_content"] = msg_raw["reasoning_content"]
|
||||
elif msg.role == "tool":
|
||||
api_msg["content"] = content or ""
|
||||
api_msg["tool_call_id"] = msg.get("tool_call_id")
|
||||
api_msg["tool_call_id"] = msg.tool_call_id
|
||||
else:
|
||||
api_msg["content"] = content or ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user