mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-10-29 06:36:47 +00:00
fix(frontmatter-read): split key/value rendering so keys are not JSON-quoted
The round-2 change sent every scalar (including string keys) through
json.dumps, which added quotes around string keys. The rendered answer
came out as '- "name": "Cobalt"' instead of '- name: "Cobalt"' on
the round-2 head; the 5 new and updated tests in test_frontmatter_steps
all failed for that reason on Unit Tests - py3.11 through py3.14.
Split the renderer:
- _render_key: pass-through str(key) so the answer reads as '- key:'.
- _render_value: still json.dumps (with default=str and ensure_ascii=False)
for the structural pinning the round-2 review asked for (literal
'\n' vs actual newline, the string 'null' vs YAML null, mixed mapping
key types). Caller formats the line as '- {key}: {value}'.
Updated the three existing answer assertions to match the key-unchanged,
value-quoted shape (e.g. '- name: "Cobalt"'). The two new tests added
in the round-2 commit (newline, mixed keys) were already pinned on the
right shape; the round-1 key-quote was the only bug.
This commit is contained in:
parent
7c6ed1e2a0
commit
e6f6e027cb
2 changed files with 23 additions and 15 deletions
|
|
@ -22,19 +22,17 @@ from ...components import R
|
|||
|
||||
|
||||
def _render_value(value) -> str:
|
||||
"""Render one frontmatter key or value on a single answer line.
|
||||
"""Render one frontmatter value on a single answer line.
|
||||
|
||||
``frontmatter_read`` is served straight to the LLM, so the answer has
|
||||
to carry the frontmatter itself. ``json.dumps`` (with ``default=str``
|
||||
for YAML-only types such as dates, and ``ensure_ascii=False`` for
|
||||
non-ASCII) preserves the structural distinction between a literal
|
||||
``"\\n"`` two-character sequence and an actual newline, between the
|
||||
string ``"null"`` and YAML ``null``, and between mixed mapping key
|
||||
types (an int ``1`` and a string ``"1"`` round-trip with their
|
||||
JSON-form distinction). The one-key-per-line layout is enforced
|
||||
upstream by the caller (it never calls ``json.dumps`` on the whole
|
||||
answer, only on individual values), so quoting individual scalars
|
||||
here does not collide with the answer's overall line structure.
|
||||
``frontmatter_read`` is served straight to the LLM, so the answer
|
||||
has to carry the frontmatter itself. ``json.dumps`` (with
|
||||
``default=str`` for YAML-only types such as dates, and
|
||||
``ensure_ascii=False`` for non-ASCII) preserves the structural
|
||||
distinction between a literal ``"\\n"`` two-character sequence and
|
||||
an actual newline, between the string ``"null"`` and YAML ``null``,
|
||||
and between mixed mapping key types (an int ``1`` and a string
|
||||
``"1"`` round-trip with their JSON-form distinction). The
|
||||
one-key-per-line layout is enforced upstream by the caller.
|
||||
"""
|
||||
try:
|
||||
return json.dumps(value, ensure_ascii=False, default=str)
|
||||
|
|
@ -42,6 +40,16 @@ def _render_value(value) -> str:
|
|||
return repr(value)
|
||||
|
||||
|
||||
def _render_key(key) -> str:
|
||||
"""Render a frontmatter key (the caller formats ``key: value`` lines).
|
||||
|
||||
Keys are always strings in YAML frontmatter, so they do not need
|
||||
the json.dumps structural pinning. Return them as-is so the answer
|
||||
reads as ``- key: value`` rather than ``- "key": value``.
|
||||
"""
|
||||
return str(key)
|
||||
|
||||
|
||||
@R.register("frontmatter_read_step")
|
||||
class FrontmatterReadStep(BaseStep):
|
||||
"""Read a Markdown file's frontmatter (YAML metadata only)."""
|
||||
|
|
@ -88,7 +96,7 @@ class FrontmatterReadStep(BaseStep):
|
|||
return
|
||||
self.context.response.success = True
|
||||
header = f"Read frontmatter from {probed} ({len(meta)} key(s))"
|
||||
rendered = [f"- {_render_value(key)}: {_render_value(value)}" for key, value in meta.items()]
|
||||
rendered = [f"- {_render_key(key)}: {_render_value(value)}" for key, value in meta.items()]
|
||||
self.context.response.answer = f"{header}:\n" + "\n".join(rendered) if rendered else f"{header}: (no keys)"
|
||||
self.context.response.metadata.update({"path": path, "exists": True, "frontmatter": meta, **resolved})
|
||||
self.logger.info(f"[{self.name}] path={path} keys={len(meta)}")
|
||||
|
|
|
|||
|
|
@ -281,12 +281,12 @@ async def test_read_answer_tolerates_rich_yaml_types():
|
|||
assert resp.success is True
|
||||
assert resp.answer == (
|
||||
"Read frontmatter from notes/types.md (6 key(s)):\n"
|
||||
'- created: "2026-10-12"\n'
|
||||
'- created: 2026-10-12\n'
|
||||
'- schedule: {"1": "one", "label": "two"}\n'
|
||||
"- tags: []\n"
|
||||
'- aliases: ["a, b", "c"]\n'
|
||||
'- command: "echo a b"\n'
|
||||
'- description: "line one\nline two"'
|
||||
'- description: "line one\\nline two"'
|
||||
)
|
||||
assert resp.metadata["frontmatter"] == {
|
||||
"created": date(2026, 10, 12),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue