Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions agentdescent/algorithms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,12 @@ def _unknown_algorithm_message(where: str, name: Any) -> str:
return msg
slug = _fold(name)
if slug not in _EXAMPLES_ONLY_PORTS:
# A near-miss typo (`gepaa`, `evo_skill`) names the card it most
# likely meant, so the fix is one word rather than a list scan.
import difflib
close = difflib.get_close_matches(slug, sorted(_REGISTRY), n=1, cutoff=0.75)
if close:
return f"{msg}; did you mean {close[0]!r}?"
return msg
doc = f"docs/algo-{slug.replace('_', '-')}.md"
return (f"{msg}. {slug!r} is an examples/ research port ({doc}), not a "
Expand Down
4 changes: 4 additions & 0 deletions changelog.d/874-algorithm-did-you-mean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Changed
An unknown algorithm name that is a near-miss typo of a registered card now ends
with "did you mean 'gepa'?" (`algorithms show` / `run`, specs, MCP), instead of
only listing every card (#874).
13 changes: 13 additions & 0 deletions tests/test_algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1060,3 +1060,16 @@ def test_mcp_list_algorithms_carries_cards_vs_ports_note():
names = {a["name"] for a in payload["algorithms"]}
assert "gepa" in names and "evoskill" not in names # kind filter
assert all(a["surface"] == "card" for a in payload["algorithms"])


@pytest.mark.parametrize("typo,meant", [("gepaa", "gepa"), ("evo_skill", "evoskill"),
("skilopt", "skillopt")])
def test_unknown_algorithm_names_the_near_miss(typo, meant):
with pytest.raises(AlgorithmError, match=rf"did you mean '{meant}'\?$"):
algorithms.get(typo, where="show")


def test_unknown_algorithm_without_near_miss_has_no_guess():
with pytest.raises(AlgorithmError) as e:
algorithms.get("nope", where="show")
assert "did you mean" not in str(e.value)
Loading