fix(agent): register explainer config key + shorten footer prefix
Follow-up to the salvaged #34452 turn-completion explainer: - Register display.turn_completion_explainer: True in DEFAULT_CONFIG so the setting is discoverable, matching the file_mutation_verifier precedent. - Shorten the repeated footer prefix from 'Turn ended without a usable reply: ' to 'No reply: ' so the 10 reason variants don't all open with the same 8-word boilerplate. - Update the 7 assertions that referenced the old prefix.
This commit is contained in:
@ -1202,6 +1202,13 @@ DEFAULT_CONFIG = {
|
||||
# class of over-claim that otherwise forces users to run
|
||||
# `git status` to verify edits landed. Set false to suppress.
|
||||
"file_mutation_verifier": True,
|
||||
# Turn-completion explainer. When true (default), the agent appends a
|
||||
# one-line explanation to its final response whenever a turn ends
|
||||
# abnormally with no usable reply — empty content after retries, a
|
||||
# partial/truncated stream, a still-pending tool result, or an
|
||||
# iteration/budget limit. Replaces the bare "(empty)" sentinel so the
|
||||
# failure isn't silent from the UI's perspective. Set false to suppress.
|
||||
"turn_completion_explainer": True,
|
||||
"show_cost": False, # Show $ cost in the status bar (off by default)
|
||||
"skin": "default",
|
||||
# UI language for static user-facing messages (approval prompts, a
|
||||
|
||||
@ -2189,7 +2189,7 @@ class AIAgent:
|
||||
if reason.startswith("text_response"):
|
||||
return ""
|
||||
|
||||
prefix = "⚠️ Turn ended without a usable reply: "
|
||||
prefix = "⚠️ No reply: "
|
||||
if reason == "empty_response_exhausted":
|
||||
return (
|
||||
prefix
|
||||
|
||||
@ -3049,7 +3049,7 @@ class TestRunConversation:
|
||||
# #34452: the bare "(empty)" sentinel is now replaced by a
|
||||
# user-visible end-of-turn explanation so the failure isn't silent.
|
||||
assert result["final_response"] != "(empty)"
|
||||
assert "without a usable reply" in result["final_response"]
|
||||
assert "No reply:" in result["final_response"]
|
||||
assert result["turn_exit_reason"] == "empty_response_exhausted"
|
||||
assert result["api_calls"] == 6 # 1 original + 2 prefill + 3 retries
|
||||
|
||||
@ -3072,7 +3072,7 @@ class TestRunConversation:
|
||||
assert result["completed"] is True
|
||||
# #34452: explanation replaces the bare "(empty)" sentinel.
|
||||
assert result["final_response"] != "(empty)"
|
||||
assert "without a usable reply" in result["final_response"]
|
||||
assert "No reply:" in result["final_response"]
|
||||
assert result["api_calls"] == 6 # 1 original + 2 prefill + 3 retries
|
||||
|
||||
def test_reasoning_only_prefill_succeeds_on_continuation(self, agent):
|
||||
@ -3121,7 +3121,7 @@ class TestRunConversation:
|
||||
assert result["completed"] is True
|
||||
# #34452: explanation replaces the bare "(empty)" sentinel.
|
||||
assert result["final_response"] != "(empty)"
|
||||
assert "without a usable reply" in result["final_response"]
|
||||
assert "No reply:" in result["final_response"]
|
||||
assert result["api_calls"] == 4 # 1 original + 3 retries
|
||||
|
||||
def test_truly_empty_response_succeeds_on_nudge(self, agent):
|
||||
@ -3219,7 +3219,7 @@ class TestRunConversation:
|
||||
assert result["completed"] is True
|
||||
# #34452: explanation replaces the bare "(empty)" sentinel.
|
||||
assert result["final_response"] != "(empty)"
|
||||
assert "without a usable reply" in result["final_response"]
|
||||
assert "No reply:" in result["final_response"]
|
||||
|
||||
def test_empty_response_emits_status_for_gateway(self, agent):
|
||||
"""_emit_status is called during empty retries so gateway users see feedback."""
|
||||
@ -3248,7 +3248,7 @@ class TestRunConversation:
|
||||
# #34452: explanation replaces the bare "(empty)" sentinel, but the
|
||||
# status emissions during retries are unchanged.
|
||||
assert result["final_response"] != "(empty)"
|
||||
assert "without a usable reply" in result["final_response"]
|
||||
assert "No reply:" in result["final_response"]
|
||||
# Should have emitted retry statuses (3 retries) + final failure
|
||||
retry_msgs = [m for m in status_messages if "retrying" in m.lower()]
|
||||
assert len(retry_msgs) == 3, f"Expected 3 retry status messages, got {len(retry_msgs)}: {status_messages}"
|
||||
|
||||
@ -159,7 +159,7 @@ def test_run_conversation_empty_exhausted_surfaces_explanation():
|
||||
# The user must NOT be left with a bare sentinel; the explanation wins.
|
||||
assert result["final_response"] != "(empty)"
|
||||
assert result["final_response"].strip() != ""
|
||||
assert "without a usable reply" in result["final_response"]
|
||||
assert "No reply:" in result["final_response"]
|
||||
|
||||
|
||||
def test_run_conversation_normal_reply_stays_quiet():
|
||||
@ -178,4 +178,4 @@ def test_run_conversation_normal_reply_stays_quiet():
|
||||
|
||||
assert result["turn_exit_reason"].startswith("text_response")
|
||||
assert result["final_response"] == "Done."
|
||||
assert "without a usable reply" not in result["final_response"]
|
||||
assert "No reply:" not in result["final_response"]
|
||||
|
||||
Reference in New Issue
Block a user