Fix split-field DSML promote and silent turn end after tools.

Parse DSML from combined content+reasoning when markers span fields; show a clear mismatch message when parse fails; run finalize synthesis when tools executed but the assistant body is empty.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-05-27 17:08:51 +08:00
parent c31e6ad4b7
commit 5325b2d9bc
4 changed files with 85 additions and 13 deletions

View file

@ -161,7 +161,7 @@ def test_direct_loop_dsml_text_persisted_as_failed_tool_pair(tmp_path, monkeypat
persist_user_message=True,
max_tool_rounds=1,
)
assert out.final_text == ""
assert "DSML" in out.final_text
rows = store.get_messages(session_id=sess.id, limit=20)
tool_rows = [r for r in rows if getattr(r, "role", "") == "tool"]
assert tool_rows
@ -212,7 +212,7 @@ def test_direct_loop_mixed_text_with_tool_intent_is_blocked(tmp_path, monkeypatc
persist_user_message=True,
max_tool_rounds=1,
)
assert out.final_text == ""
assert "DSML" in out.final_text
rows = store.get_messages(session_id=sess.id, limit=20)
tool_rows = [r for r in rows if getattr(r, "role", "") == "tool"]
assert tool_rows

View file

@ -67,6 +67,24 @@ def test_malformed_returns_none() -> None:
assert try_parse_deepseek_v4_dsml_tool_calls("<||DSML||tool_calls>broken") is None
def test_promote_combined_when_dsml_only_in_reasoning() -> None:
from runtime.dsml_tool_parse import try_promote_dsml_from_fields
p = "\uFF5C"
reasoning = (
f"<{p}{p}DSML{p}{p}tool_calls>\n"
f"<{p}{p}DSML{p}{p}invoke name=\"run_command\">\n"
f"<{p}{p}DSML{p}{p}parameter name=\"command\" string=\"true\">echo</{p}{p}DSML{p}{p}parameter>\n"
f"</{p}{p}DSML{p}{p}invoke>\n"
f"</{p}{p}DSML{p}{p}tool_calls>"
)
parsed, clean_c, clean_r = try_promote_dsml_from_fields(content="让我检查一下。", reasoning_content=reasoning)
assert parsed is not None and len(parsed) == 1
assert parsed[0].name == "run_command"
assert "检查一下" in clean_c
assert "DSML" not in clean_r
def test_parse_double_fullwidth_pipe_variant() -> None:
p = "\uFF5C"
text = (