fix(sandbox): keep multi-line SKILL.md frontmatter descriptions in the skill index - #5028
ChiFungHillmanChan wants to merge 2 commits into
Conversation
_parse_frontmatter split every frontmatter line on the first colon, so a folded or literal block scalar returned the header character alone, a wrapped plain scalar returned only its first line, and continuation lines became keys of their own. Skill descriptions built from those values reached the model truncated, and a continuation line spelled like a key could replace the skill name in the index. Parse block scalars and wrapped plain scalars, and treat any line indented past its key as part of that key's value rather than as a new key.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd4da157f8
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| """ | ||
|
|
||
| index = start | ||
| while index < end and (not lines[index].strip() or _indent_of(lines[index]) > key_indent): |
There was a problem hiding this comment.
Ignore indented comments when folding plain values
When a valid frontmatter comment is indented beneath a single-line field, such as name: foo followed by # explanation, this loop classifies the comment as a continuation and _fold_lines appends it to the value. The previous parser skipped that comment, but this change makes the indexed and loadable skill name foo # explanation; quoted descriptions similarly regain their surrounding quotes. Comment-only lines should be excluded when collecting plain-scalar continuations, while remaining content inside actual block scalars.
Useful? React with 👍 / 👎.
| if parsed_value in _BLOCK_SCALAR_HEADERS: | ||
| parsed_value = _join_block_lines(continuation, literal=parsed_value[0] == "|").strip() |
There was a problem hiding this comment.
Treat indented
--- as block-scalar content
When a folded or literal description contains an indented line whose content is ---, valid YAML treats that line as part of the scalar, but the earlier delimiter scan uses line.strip() and ends the frontmatter there. Consequently this new block-scalar branch receives only the preceding text, and subsequent metadata such as name is omitted and replaced by the directory-name fallback. Only a document delimiter at the frontmatter's delimiter indentation should terminate parsing.
Useful? React with 👍 / 👎.
A line indented past its key is part of that key's value, but a comment line is only content inside a block scalar. Folding it into a wrapped plain value made the skill name 'foo # explanation', and it also kept a quoted value from being unwrapped. Drop comment lines when collecting a continuation outside a block scalar, where YAML treats them as comments.
|
Thanks — the first one is a real regression in this PR and is fixed in b16c759. The second one I do not think belongs here; evidence below. Indented comments folded into plain values. Correct, and this PR caused it. A comment line is content inside a block scalar but a comment anywhere else, which is what So comment lines are now dropped when collecting a continuation outside a block scalar, and kept inside one. Three cases added, and they separate the two rules: the two comment cases pass on Indented
|
Summary
_parse_frontmatterinsrc/agents/sandbox/capabilities/skills.pysplits every frontmatter line on the first:and keeps the rest as the value. YAML block scalars and wrapped plain scalars span more than one line, sodescription: >returned>,description: |returned|, and a wrapped plain scalar returned only its first line. Each continuation line was then read as a key of its own.LocalDirLazySkillSource.list_skill_metadataandSkills._resolve_runtime_metadataboth buildSkillMetadata.descriptionfrom this parser, and the skills section renders one line per skill as- <name>: <description> (file: <path>). A folded description therefore reached the model as- triage: >, leaving nothing to match a task against, and nothing warned. A continuation line spelled like a key also overwrote the key it collided with: aname:line inside a description replaced the skill's own name in that index line.The diagnosis and the comparison against
yaml.safe_loadare the reporter's, in #5026.This teaches the parser folded (
>) and literal (|) block scalars, including their-and+chomping indicators, and wrapped plain scalars. One rule covers all three: a line indented past its key belongs to that key's value and is never read as a new key. That also keeps a nested block's keys from leaking to the top level. PyYAML stays out of the runtime dependencies.Single-line values are unchanged, quoted or not, including leading and trailing spaces inside the quotes.
Test plan
tests/sandbox/capabilities/test_skills_capability.py, asserting the rendered skills instructions rather than the parser: folded, literal, wrapped plain, folded with a blank line, and a folded description whose continuation line readsname:. All five fail onfbf59a40and pass on this branch.fbf59a40, the index line the model receives:yaml.safe_loadon the same frontmatter for the five shapes in the issue, trailing whitespace removed on both sides because this parser strips the values it returns: 3 mismatches onfbf59a40, 0 on this branch.|as folded, taking continuation lines at the key's own indent, folding blank lines to a space, not consuming continuation lines, dropping the wrapped plain continuation, and not removing the block indent for a literal scalar). Every one is caught..agents/skills/code-change-verification/scripts/run.shpassed: format, lint, typecheck, then 9641 passed and 29 skipped, plus 77 passed and 4 skipped serial.What this does not change
nameanddescriptionare read.Issue number
Closes #5026
Checks
.agents/skills/code-change-verification/scripts/run.sh/reviewbefore submitting this PR