Skip to content

Keep skill metadata keys that follow a blank line in the block - #1061

Open
PratikDhanave (PratikDhanave) wants to merge 1 commit into
microsoft:mainfrom
PratikDhanaveFork:fsskills-metadata-blank-line
Open

PratikDhanave (PratikDhanave) wants to merge 1 commit into
microsoft:mainfrom
PratikDhanaveFork:fsskills-metadata-blank-line

Conversation

@PratikDhanave

Copy link
Copy Markdown
Contributor

Problem

In agent/skills/fsskills/source.go, the metadata block is captured by:

yamlMetadataBlockRegex = regexp.MustCompile(`(?m)^metadata\s*:\s*$\n((?:[ \t]+\S.*\n?)+)`)

The capture group requires every line to be indentation + non-space. A blank line — legal and common inside a YAML mapping block — matches neither, so the + repetition stops at the first blank line and every metadata key after it is silently dropped. This is inconsistent with a real YAML parser and with the file's own block-scalar parsing, which tolerate blank lines.

Example frontmatter:

metadata:
  a: 1

  b: 2
  c: 3

parses to {a:1}b and c are lost.

Fix

Allow blank lines within the captured block (| [ \t]*\n). The per-key extraction (yamlIndentedKeyValueRegex) already ignores blank lines, and a de-dented (non-indented, non-blank) line still ends the block, so no following top-level key is swept in.

Test

TestFileSource_MetadataWithBlankLine_KeepsAllKeys parses a metadata block with a blank line between keys and asserts all keys survive. Fails before the fix ({a:1}), passes after; existing metadata tests remain green.

The metadata block regex captured ((?:[ \t]+\S.*\n?)+), whose repetition
terminates at the first line that is not indented-then-non-space. A blank line
is legal and common inside a YAML mapping block, so any metadata key after a
blank line was silently dropped - inconsistent with a real YAML parser and with
the sibling block-scalar parsing, which tolerate blank lines.

Allow blank lines within the captured block (they are ignored by the
per-key extraction); a de-dented line still ends the block.
Copilot AI lite review requested due to automatic review settings September 13, 2026 13:00
@github-actions github-actions Bot added area:agent Changes files in the agent area size:small At most 30 changed lines across at most 2 files labels Sep 13, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

CRLF-formatted files can still lose metadata keys after a blank line.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Updates skill frontmatter parsing to preserve metadata keys after blank lines.

Changes:

  • Allows blank lines within metadata blocks.
  • Adds regression coverage for keys following blank lines.
File summaries
File Summary
agent/skills/fsskills/source.go Updates metadata block matching.
agent/skills/fsskills/source_test.go Adds blank-line metadata coverage.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

frontmatterRegex = regexp.MustCompile(`(?ms)\A^---\s*$(.+?)^---\s*$`)
yamlKeyValueRegex = regexp.MustCompile(`(?m)^([\w-]+)\s*:\s*(?:["'](.+?)["']|(.+?))\s*$`)
yamlMetadataBlockRegex = regexp.MustCompile(`(?m)^metadata\s*:\s*$\n((?:[ \t]+\S.*\n?)+)`)
yamlMetadataBlockRegex = regexp.MustCompile(`(?m)^metadata\s*:\s*$\n((?:[ \t]+\S.*\n?|[ \t]*\n)+)`)
@github-actions github-actions Bot added kind:code Changes production behavior or code kind:tests Changes tests, fixtures, or test infrastructure labels Sep 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Scope: internal-only (bug fix in unexported regex; no exported API change; parsed metadata values are user-visible output, but no new/changed public contract)

Changed Go contract: None (unexported yamlMetadataBlockRegex in agent/skills/fsskills/source.go). The observable effect is that Skill.Frontmatter.Metadata now retains keys following a blank line inside a `meta(redacted) YAML block, instead of silently dropping them.

Upstream evidence reviewed:

  • .NET: dotnet/src/Microsoft.Agents.AI/Skills/File/AgentFileSkillsSource.cs:51s_yamlMetadataBlockRegex = new(@"^metadata\s*:\s*$\n((?:[ \t]+\S.*\n?)+)", ...)
  • Python: python/packages/core/agent_framework/_skills.pyYAML_METADATA_BLOCK_RE = re.compile(r"^metadata\s*:\s*$\n((?:[ \t]+\S.*\n?)+)", re.MULTILINE)

Result: findings reported (cross-SDK parity gap, not a Go-side defect)

Finding: fix is Go-only; identical bug remains in .NET and Python

The regex this PR fixes (^metadata\s*:\s*$\n((?:[ \t]+\S.*\n?)+)) is copied nearly verbatim in both the upstream .NET (AgentFileSkillsSource.cs:51) and Python (_skills.py YAML_METADATA_BLOCK_RE) implementations, and both have the exact same defect: a blank line inside a meta(redacted) block truncates the capture group, silently dropping every key after the first blank line. For the identical SKILL.mdfrontmatter shown in the PR description, Go will now parse{a:1, b:2, c:3}while.NETand Python will still parse{a:1}` — a genuine cross-SDK behavior divergence for the same input file.

This is a good bug fix on its own, but to restore parity maintainers should port the equivalent regex fix upstream (e.g. (?:[ \t]+\S.*\n?|[ \t]*\n)+) to AgentFileSkillsSource.cs and _skills.py's YAML_METADATA_BLOCK_RE, or track this as a follow-up issue in microsoft/agent-framework so all three SDKs parse SKILL.md metadata consistently. No change requested to this Go PR itself.

Generated by Go API Consistency Review Agent · copilot · auto · 25.8 AIC · ⌖ 5.07 AIC · ⊞ 9.6K ·

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:agent Changes files in the agent area kind:code Changes production behavior or code kind:tests Changes tests, fixtures, or test infrastructure size:small At most 30 changed lines across at most 2 files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants