mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-11 12:17:45 +02:00
[eric] agents: the quarantine card spells out the clicks, because 22 of 25 never recovered from naming the fix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U6zrBsUCNzpMBnov3rTVYV
This commit is contained in:
co-authored by
Claude Opus 5
parent
b133ef7a1a
commit
59a95b268a
@@ -194,12 +194,23 @@ async def handle_run_error(e: Exception, session: AgentSession, session_id: str,
|
||||
p_report_model_error("cert_failure", session_id, session, turn, e, p_stderr_tail)
|
||||
elif is_cli_binary_missing(e, extra_text=p_stderr_tail):
|
||||
# The bundled CLI vanished from an installed app (Windows AV quarantine class; 22 of 25 field installs never recovered). The raw "not found at: C:\..." card is unactionable; name the likely cause and the two real fixes.
|
||||
# "Restore it from your antivirus quarantine" is technically right and empirically useless:
|
||||
# 22 of 25 affected field installs never recovered, and a real user replied "don't know how
|
||||
# to take a file out of quarantine" (2026-08-29). A card that names a fix the reader cannot
|
||||
# perform is a dead end, so spell the clicks out and put the fix that always works first.
|
||||
friendly_msg = (
|
||||
"A core OpenSwarm component (the bundled agent runtime) is missing from "
|
||||
"this install, which usually means antivirus software quarantined it. "
|
||||
"Restore it from your antivirus quarantine and add an exclusion for "
|
||||
"OpenSwarm, or reinstall from openswarm.com. Your chats and settings "
|
||||
"are kept either way."
|
||||
"A core OpenSwarm component (the bundled agent runtime) is missing from this "
|
||||
"install. Antivirus software almost always caused this by quarantining it. "
|
||||
"Your chats and settings are safe either way.\n\n"
|
||||
"Easiest fix: reinstall from openswarm.com over the top of this install. "
|
||||
"Nothing is lost.\n\n"
|
||||
"Or restore it in Windows Security:\n"
|
||||
"1. Open Windows Security, then Virus & threat protection.\n"
|
||||
"2. Under Current threats choose Protection history.\n"
|
||||
"3. Find the quarantined OpenSwarm or claude item and choose Actions, then Restore.\n"
|
||||
"4. Back in Virus & threat protection, open Manage settings, scroll to Exclusions, "
|
||||
"choose Add or remove exclusions, then Add an exclusion, then Folder, and pick your "
|
||||
"OpenSwarm folder. Without this step it will be quarantined again."
|
||||
)
|
||||
error_msg = Message(role="system", content=friendly_msg, branch_id=session.active_branch_id)
|
||||
absorb_repeat_card(session, error_msg)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
"""The AV-quarantine card has to be performable by the person who receives it.
|
||||
|
||||
Field evidence, 2026-08-29: a first-time user hit this card and replied "don't know how to take a
|
||||
file out of quarantine". She is not an outlier -- 22 of 25 affected installs never produced another
|
||||
agent reply. The old card named the right fix ("restore it from your antivirus quarantine and add an
|
||||
exclusion") and gave no way to do it, which is a dead end dressed as guidance.
|
||||
|
||||
Row 4 on the ladder: the app is unusable, and the stated recovery empirically does not happen."""
|
||||
|
||||
import re
|
||||
|
||||
SRC = open("backend/apps/agents/manager/run/handle_run_error.py", encoding="utf-8").read()
|
||||
# Anchor on THIS card's own words: the file holds several `friendly_msg = (` blocks and slicing the
|
||||
# first one silently tested the long-context card instead.
|
||||
_start = SRC.index("bundled agent runtime")
|
||||
CARD = SRC[_start:SRC.index("error_msg = Message(", _start)]
|
||||
|
||||
|
||||
def test_it_leads_with_the_fix_that_always_works():
|
||||
"""Reinstall works for everyone; the quarantine dance works for the few who can do it. A card
|
||||
that opens with the harder path loses the readers who needed it most."""
|
||||
lower = CARD.lower()
|
||||
assert "reinstall" in lower
|
||||
assert lower.index("reinstall") < lower.index("windows security"), \
|
||||
"the always-works fix must come before the fiddly one"
|
||||
|
||||
|
||||
def test_the_restore_path_is_actual_clicks():
|
||||
"""Naming a destination is not instructions. These are the four screens a user has to touch."""
|
||||
lower = CARD.lower()
|
||||
for step in ("windows security", "protection history", "restore", "exclusion"):
|
||||
assert step in lower, f"the card never mentions {step!r}"
|
||||
|
||||
|
||||
def test_it_says_why_the_exclusion_matters():
|
||||
"""Restoring without an exclusion just gets it quarantined again, which is how someone 'fixes'
|
||||
it twice and gives up."""
|
||||
assert "quarantined again" in CARD.lower()
|
||||
|
||||
|
||||
def test_it_still_reassures_about_data():
|
||||
"""The single most common panic on this card is 'have I lost my chats'."""
|
||||
lower = CARD.lower()
|
||||
assert "chats and settings are safe" in lower or "your chats" in lower
|
||||
|
||||
|
||||
def test_it_does_not_dump_the_dead_path():
|
||||
"""The raw CLINotFoundError path was the original unactionable card; it must not come back."""
|
||||
assert "not found at" not in CARD.lower()
|
||||
assert not re.search(r"[A-Za-z]:\\\\", CARD), "no raw Windows path in the user-facing text"
|
||||
Reference in New Issue
Block a user