Private
Public Access
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)
|
current_api_messages.append(sys_msg)
|
||||||
|
|
||||||
with history.lock:
|
with history.lock:
|
||||||
for i, msg in enumerate(history):
|
from src.openai_schemas import ChatMessage as _ChatMessage
|
||||||
# Create a clean copy of the message for the API
|
for i, msg_raw in enumerate(history):
|
||||||
role = msg.get("role")
|
msg = _ChatMessage.from_dict(msg_raw)
|
||||||
api_msg = {"role": role}
|
api_msg = {"role": msg.role}
|
||||||
|
|
||||||
content = msg.get("content")
|
content = msg.content
|
||||||
if i == 0 and is_reasoner:
|
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}"
|
content = f"System Instructions:\n{_get_combined_system_prompt()}\n\nContext:\n{md_content}\n\n---\n\n{content}"
|
||||||
|
|
||||||
if role == "assistant":
|
if msg.role == "assistant":
|
||||||
# OpenAI/DeepSeek: content MUST be a string if tool_calls is absent
|
if msg.tool_calls:
|
||||||
# If tool_calls is present, content can be null
|
|
||||||
if msg.get("tool_calls"):
|
|
||||||
api_msg["content"] = content or None
|
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:
|
else:
|
||||||
api_msg["content"] = content or ""
|
api_msg["content"] = content or ""
|
||||||
if msg.get("reasoning_content"):
|
if msg_raw.get("reasoning_content"):
|
||||||
api_msg["reasoning_content"] = msg["reasoning_content"]
|
api_msg["reasoning_content"] = msg_raw["reasoning_content"]
|
||||||
elif role == "tool":
|
elif msg.role == "tool":
|
||||||
api_msg["content"] = content or ""
|
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:
|
else:
|
||||||
api_msg["content"] = content or ""
|
api_msg["content"] = content or ""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user