mirror of
https://github.com/HKUDS/OpenSpace.git
synced 2026-09-11 22:51:05 +00:00
fix(skill_engine): preserve multiline frontmatter values
set_frontmatter_field wrote raw newlines into YAML, so parse_frontmatter kept only the first line. Quote multiline scalars and drop old block continuation lines when replacing a field.
This commit is contained in:
parent
2c5cc409b0
commit
c0009ac030
3 changed files with 35 additions and 3 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -51,6 +51,7 @@ tests/skill_engine/*
|
|||
!tests/skill_engine/test_evolver_length_recovery.py
|
||||
!tests/skill_engine/test_evolution_retry_idempotency.py
|
||||
!tests/skill_engine/test_analyzer_length_recovery.py
|
||||
!tests/skill_engine/test_set_frontmatter_multiline.py
|
||||
!tests/skill_engine/decision/
|
||||
tests/skill_engine/decision/*
|
||||
!tests/skill_engine/decision/test_analysis_adapter.py
|
||||
|
|
|
|||
|
|
@ -58,10 +58,16 @@ _YAML_NEEDS_QUOTE_RE = re.compile(r"[:\#\[\]{}&*!|>'\"%@`]")
|
|||
|
||||
def _yaml_quote(value: str) -> str:
|
||||
"""Quote a YAML scalar value if it contains special characters."""
|
||||
if not value or not _YAML_NEEDS_QUOTE_RE.search(value):
|
||||
if not value:
|
||||
return value
|
||||
escaped = value.replace("\\", "\\\\").replace('"', '\\"')
|
||||
return f'"{escaped}"'
|
||||
if "\n" in value or _YAML_NEEDS_QUOTE_RE.search(value):
|
||||
escaped = (
|
||||
value.replace("\\", "\\\\")
|
||||
.replace('"', '\\"')
|
||||
.replace("\n", "\\n")
|
||||
)
|
||||
return f'"{escaped}"'
|
||||
return value
|
||||
|
||||
|
||||
def _yaml_unquote(value: str) -> str:
|
||||
|
|
@ -147,10 +153,17 @@ def set_frontmatter_field(content: str, field_name: str, value: str) -> str:
|
|||
new_line = f"{field_name}: {quoted}"
|
||||
found = False
|
||||
new_lines = []
|
||||
skip_block = False
|
||||
for line in fm_text.split("\n"):
|
||||
if skip_block:
|
||||
if line.startswith((" ", "\t")) or line.strip() == "":
|
||||
continue
|
||||
skip_block = False
|
||||
if ":" in line and line.split(":", 1)[0].strip() == field_name:
|
||||
new_lines.append(new_line)
|
||||
found = True
|
||||
# Drop old block-scalar / folded continuation lines under this key.
|
||||
skip_block = True
|
||||
else:
|
||||
new_lines.append(line)
|
||||
if not found:
|
||||
|
|
|
|||
18
tests/skill_engine/test_set_frontmatter_multiline.py
Normal file
18
tests/skill_engine/test_set_frontmatter_multiline.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
"""Regression: multiline frontmatter values must round-trip via parse_frontmatter."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from openspace.skill_engine.skill_utils import parse_frontmatter, set_frontmatter_field
|
||||
|
||||
|
||||
def test_set_frontmatter_field_preserves_multiline_description():
|
||||
out = set_frontmatter_field("---\nname: x\n---\n", "description", "line1\nline2")
|
||||
assert parse_frontmatter(out)["description"] == "line1\nline2"
|
||||
|
||||
|
||||
def test_set_frontmatter_field_replaces_block_scalar_without_orphan_lines():
|
||||
src = "---\nname: x\ndescription: |\n old1\n old2\n---\nbody\n"
|
||||
out = set_frontmatter_field(src, "description", "new1\nnew2")
|
||||
assert parse_frontmatter(out)["description"] == "new1\nnew2"
|
||||
assert "old1" not in out
|
||||
assert "old2" not in out
|
||||
Loading…
Add table
Reference in a new issue