diff --git a/pkg/memory/frontmatter.go b/pkg/memory/frontmatter.go new file mode 100644 index 000000000..c953d7620 --- /dev/null +++ b/pkg/memory/frontmatter.go @@ -0,0 +1,29 @@ +package memory + +import ( + "strings" + "gopkg.in/yaml.v3" +) + +// ParseFrontmatter extracts YAML frontmatter delimited by --- from content +// Returns: frontmatter map, remaining body, error +func ParseFrontmatter(content string) (map[string]interface{}, string, error) { + result := make(map[string]interface{}) + body := content + + // Check for frontmatter delimiters + parts := strings.SplitN(content, "---", 3) + if len(parts) < 3 { + // No frontmatter, return empty map and original content + return result, body, nil + } + + // Parse YAML + fmText := parts[1] + if err := yaml.Unmarshal([]byte(fmText), &result); err != nil { + return nil, "", err + } + + body = parts[2] + return result, body, nil +} diff --git a/pkg/memory/frontmatter_test.go b/pkg/memory/frontmatter_test.go new file mode 100644 index 000000000..58213ad28 --- /dev/null +++ b/pkg/memory/frontmatter_test.go @@ -0,0 +1,53 @@ +package memory + +import ( + "testing" + "strings" +) + +func TestParseFrontmatter_ValidYAML(t *testing.T) { + input := `--- +session_id: "abc123" +timestamp: "2026-05-06T14:30:00Z" +tags: ["coding", "bug-fix"] +model: "claude-sonnet-4" +--- +{"role": "user", "content": "test"} +` + fm, body, err := ParseFrontmatter(input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if fm["session_id"] != "abc123" { + t.Errorf("expected session_id 'abc123', got %v", fm["session_id"]) + } + if len(fm["tags"].([]interface{})) != 2 { + t.Errorf("expected 2 tags, got %v", fm["tags"]) + } + if !strings.Contains(body, `"role": "user"`) { + t.Errorf("expected body to contain JSON, got %s", body) + } +} + +func TestParseFrontmatter_NoFrontmatter(t *testing.T) { + input := `{"role": "user", "content": "test"}` + _, body, err := ParseFrontmatter(input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !strings.Contains(body, `"role": "user"`) { + t.Errorf("expected body unchanged, got %s", body) + } +} + +func TestParseFrontmatter_InvalidYAML(t *testing.T) { + input := `--- +invalid: [unclosed +--- +{"role": "user"} +` + _, _, err := ParseFrontmatter(input) + if err == nil { + t.Error("expected error for invalid YAML") + } +}