fix: skills CLI summary crashes on a non-string description (#1595)

This commit is contained in:
Afonso Coutinho
2026-06-03 00:37:05 +01:00
committed by GitHub
parent 258fe455eb
commit 19b6cbac12
2 changed files with 52 additions and 1 deletions

View File

@@ -41,11 +41,22 @@ def _manager() -> SkillsManager:
return _mgr
def _preview_text(value, limit: int = 200) -> str:
"""Truncated preview of a text field, tolerant of non-string values.
A skill whose ``description`` is a non-string (e.g. a number from a
hand-edited/legacy store) would crash ``(value or "")[:200]`` with a
TypeError; coerce non-strings to "" instead.
"""
text = value if isinstance(value, str) else ""
return text[:limit]
def _summary(skill: dict) -> dict:
return {
"name": skill.get("name", ""),
"category": skill.get("category", "general"),
"description": (skill.get("description") or "")[:200],
"description": _preview_text(skill.get("description")),
"status": skill.get("status", ""),
"uses": skill.get("uses", 0),
"last_used": skill.get("last_used") or "",

View File

@@ -0,0 +1,40 @@
"""Regression: the skills CLI summary must tolerate a non-string description.
`_summary` did `(skill.get("description") or "")[:200]`. A non-string
description (e.g. a number from a hand-edited/legacy skill store) is truthy, so
`123[:200]` raised TypeError. `_preview_text` coerces non-strings to "".
"""
import importlib.machinery
import importlib.util
import sys
import types
from pathlib import Path
from unittest.mock import MagicMock
ROOT = Path(__file__).resolve().parents[1]
def _load_cli(monkeypatch):
mod = types.ModuleType("services.memory.skills")
mod.SkillsManager = MagicMock()
monkeypatch.setitem(sys.modules, "services.memory.skills", mod)
path = ROOT / "scripts" / "odysseus-skills"
loader = importlib.machinery.SourceFileLoader("odysseus_skills_cli", str(path))
spec = importlib.util.spec_from_loader(loader.name, loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
return module
def test_preview_text_ignores_non_string(monkeypatch):
cli = _load_cli(monkeypatch)
assert cli._preview_text(None) == ""
assert cli._preview_text(123) == ""
assert cli._preview_text({"x": 1}) == ""
assert cli._preview_text("y" * 250) == "y" * 200
def test_summary_does_not_crash_on_non_string_description(monkeypatch):
cli = _load_cli(monkeypatch)
out = cli._summary({"name": "n", "description": 123})
assert out["description"] == ""