fix(agents): coerce a non-string description in TOML command rendering (#3799)

CommandRegistrar.render_toml_command passes the raw frontmatter `description`
straight into `_render_basic_toml_string`, which iterates the value and calls
ord() on each character. Frontmatter comes from yaml.safe_load, so description
can be any YAML type:

    description='ok string' -> description = "ok string"
    description=None        -> TypeError: 'NoneType' object is not iterable
    description=42          -> TypeError: 'int' object is not iterable
    description=True        -> TypeError: 'bool' object is not iterable
    description=['a','b']   -> description = "ab"     <- silently WRONG value

This is a format-branch asymmetry: it is the only renderer reached from
register_commands' format branches that does not normalise description.
render_yaml_command (same class, ~70 lines below) already does exactly
`if not isinstance(description, str): description = str(description) if
description is not None else ""`, render_markdown_command goes through
yaml.dump which handles any type, and TomlIntegration._extract_description
returns "" for a non-str. So only extension/preset commands rendered for the two
TOML agents were affected.

Apply the same coercion the sibling uses. After: None -> "", 42 -> "42",
True -> "True", ['a','b'] -> "['a', 'b']", each still valid parseable TOML.
String descriptions are untouched.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ali jawwad
2026-07-29 19:07:29 +05:00
committed by GitHub
parent de54ff73fe
commit 2ef96532d2
2 changed files with 43 additions and 1 deletions

View File

@@ -302,8 +302,20 @@ class CommandRegistrar:
toml_lines = []
if "description" in frontmatter:
# Frontmatter comes from ``yaml.safe_load``, so ``description`` can
# be any YAML type: ``description:`` with no value yields None,
# ``description: 2`` an int, an unquoted ``true`` a bool.
# ``_render_basic_toml_string`` iterates the value and calls ord()
# on each character, so a non-string raises a raw TypeError -- and a
# list of single-character items is silently concatenated into a
# wrong value (``["a", "b"]`` -> ``"ab"``). Coerce first, matching
# ``render_yaml_command`` below and ``TomlIntegration
# ._extract_description``, which both normalise it already.
description = frontmatter["description"]
if not isinstance(description, str):
description = str(description) if description is not None else ""
toml_lines.append(
f"description = {self._render_basic_toml_string(frontmatter['description'])}"
f"description = {self._render_basic_toml_string(description)}"
)
toml_lines.append("")