mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-11 20:27:44 +02:00
[eric] agents: an unclassified turn failure arms a fresh CLI session, so a chat bricked on "hit a snag" heals on the user's own next send instead of needing a manual branch (ENG-258)
This commit is contained in:
@@ -304,6 +304,14 @@ async def handle_run_error(e: Exception, session: AgentSession, session_id: str,
|
||||
else:
|
||||
# Track unclassified agent failures too so we stop flying blind on them.
|
||||
p_report_model_error("unclassified", session_id, session, turn, e, p_stderr_tail)
|
||||
# Every classified branch above is an EXTERNAL fact (auth, credits, capacity, certs) that a
|
||||
# respawn cannot fix. Landing here instead means the failure may live in this session's own
|
||||
# CLI state, and that state is replayed verbatim on every retry, which is how one chat bricks
|
||||
# forever on "hit a snag" while its siblings are fine (ENG-258). Arm the proven fresh-session
|
||||
# rebuild so the next ordinary send drops the resume transcript and respawns the client; the
|
||||
# user's own retry becomes the cure instead of needing a manual branch.
|
||||
session.needs_fresh_session = True
|
||||
logger.info(f"Agent {session_id}: unclassified failure, next turn rebuilds on a fresh CLI session")
|
||||
# The SDK's ProcessError masks the cause behind "Check stderr output for details"; append the scrubbed stderr tail so the card (and its analytics copy) names what actually broke instead of shipping a dead end.
|
||||
p_card_text = f"Error: {str(e)}"
|
||||
p_cause = redact_for_telemetry(p_stderr_tail, limit=400).strip()
|
||||
|
||||
@@ -83,3 +83,46 @@ def test_informative_error_does_not_get_stderr_appended(monkeypatch):
|
||||
session, _ = p_drive_error(monkeypatch, exc, stderr=["irrelevant tail"])
|
||||
card = [m for m in session.messages if m.role == "system"][-1].content
|
||||
assert "Runtime log tail" not in card
|
||||
|
||||
|
||||
# ENG-258: one session bricking on "hit a snag" forever while its siblings run fine. Every classified
|
||||
# branch is an external fact a respawn can't fix; the unclassified bucket is the one that can be this
|
||||
# session's own poisoned CLI state, replayed identically on every retry. Assert BOTH directions, or
|
||||
# "it arms" would pass just as well on a version that arms unconditionally.
|
||||
|
||||
def test_unclassified_failure_arms_a_fresh_session_so_the_next_send_self_heals(monkeypatch):
|
||||
session, _ = p_drive_error(
|
||||
monkeypatch, Exception("API Error: 400 invalid_request_error: messages.3: unexpected block")
|
||||
)
|
||||
assert session.needs_fresh_session is True
|
||||
|
||||
|
||||
def test_a_dead_resume_transcript_does_not_stay_sticky(monkeypatch):
|
||||
# The real shape of a session bricked by its own CLI state: the resume id no longer resolves, so
|
||||
# every retry replays the same doomed resume until something drops it.
|
||||
session, _ = p_drive_error(
|
||||
monkeypatch, Exception("No conversation found with session ID: 9f3c1a2b-dead-4f00-bbbb-000000000000")
|
||||
)
|
||||
assert session.needs_fresh_session is True
|
||||
|
||||
|
||||
def test_out_of_credits_does_not_respawn_the_cli(monkeypatch):
|
||||
session, _ = p_drive_error(
|
||||
monkeypatch, Exception("Your credit balance is too low to run this request")
|
||||
)
|
||||
assert session.needs_fresh_session is False
|
||||
|
||||
|
||||
def test_auth_failure_does_not_respawn_the_cli(monkeypatch):
|
||||
session, _ = p_drive_error(monkeypatch, Exception("401 invalid authentication credentials"))
|
||||
assert session.needs_fresh_session is False
|
||||
|
||||
|
||||
def test_rate_limit_does_not_respawn_the_cli(monkeypatch):
|
||||
session, _ = p_drive_error(monkeypatch, Exception("429 rate_limit_error: overloaded"))
|
||||
assert session.needs_fresh_session is False
|
||||
|
||||
|
||||
def test_missing_cli_binary_does_not_respawn_the_cli(monkeypatch):
|
||||
session, _ = p_drive_error(monkeypatch, Exception(P_FIELD_CLI_MISSING))
|
||||
assert session.needs_fresh_session is False
|
||||
|
||||
Reference in New Issue
Block a user