fix(streaming): keep recovered tool call anchors

This commit is contained in:
Frank Song committed 2026-07-18 03:23:45 +08:00
1 parent 3330bb4bd1
commit e0dee876a0
2 files changed
+73 -1

No files matched your search

+4 -1
View File
@@ -849,7 +849,10 @@ def _recovered_model_context_projection(message: dict) -> dict | None:
if projected.get('_error'):
return None
if _content_has_reasoning_only_parts(projected.get('content')):
return None
if projected.get('tool_calls'):
projected['content'] = ''
else:
return None
projected_text = _normalize_journal_recovery_text(projected.get('content'))
if not projected_text and not projected.get('tool_call_id') and not projected.get('tool_calls'):
return None
@@ -428,6 +428,75 @@ def test_empty_context_recovery_omits_structured_reasoning_only_content(tmp_path
]
def test_empty_context_recovery_preserves_tool_calls_with_reasoning_only_content():
session_id = "issue3929_empty_context_reasoning_tool_call"
stream_id = "stream_empty_context_reasoning_tool_call"
tool_call = {
"id": "call_issue3929",
"type": "function",
"function": {"name": "inspect_state", "arguments": "{}"},
}
session = Session(
session_id=session_id,
title="Reasoning-only tool boundary",
messages=[
{"role": "user", "content": "Inspect the state"},
{
"role": "assistant",
"content": [
{
"type": "reasoning",
"reasoning": "Tool planning Thinking must stay display-only.",
},
],
"tool_calls": [tool_call],
},
{
"role": "tool",
"tool_call_id": "call_issue3929",
"content": "{\"ok\": true}",
},
],
context_messages=[],
)
append_run_event(
session_id,
stream_id,
"token",
{"text": "Recovered visible answer."},
)
assert _append_journaled_partial_output(
session, stream_id, dedupe_existing=True,
) is True
session.save()
models.SESSIONS.clear()
reloaded = models.get_session(session_id)
assert [message.get("role") for message in reloaded.context_messages] == [
"user",
"assistant",
"tool",
"assistant",
]
assert reloaded.context_messages[1]["content"] == ""
assert reloaded.context_messages[1]["tool_calls"] == [tool_call]
assert reloaded.context_messages[2]["tool_call_id"] == "call_issue3929"
assert "Tool planning Thinking" not in json.dumps(
reloaded.context_messages, ensure_ascii=False,
)
sanitized = _sanitize_messages_for_api(reloaded.context_messages)
assert [message.get("role") for message in sanitized] == [
"user",
"assistant",
"tool",
"assistant",
]
assert sanitized[1]["tool_calls"] == [tool_call]
assert sanitized[2]["tool_call_id"] == "call_issue3929"
def test_empty_context_recovery_preserves_duplicate_historical_replies():
session_id = "issue3929_empty_context_duplicate_history"
stream_id = "stream_empty_context_duplicate_history"