Compare commits
1 Commits
dev
...
fix-markdo
| Author | SHA1 | Date |
|---|---|---|
|
|
8aa7e65dc8 |
|
|
@ -14,7 +14,9 @@ export namespace ConfigMarkdown {
|
||||||
return Array.from(template.matchAll(SHELL_REGEX))
|
return Array.from(template.matchAll(SHELL_REGEX))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function preprocessFrontmatter(content: string): string {
|
// other coding agents like claude code allow invalid yaml in their
|
||||||
|
// frontmatter, we need to fallback to a more permissive parser for those cases
|
||||||
|
export function fallbackSanitization(content: string): string {
|
||||||
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/)
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/)
|
||||||
if (!match) return content
|
if (!match) return content
|
||||||
|
|
||||||
|
|
@ -53,7 +55,7 @@ export namespace ConfigMarkdown {
|
||||||
|
|
||||||
// if value contains a colon, convert to block scalar
|
// if value contains a colon, convert to block scalar
|
||||||
if (value.includes(":")) {
|
if (value.includes(":")) {
|
||||||
result.push(`${key}: |`)
|
result.push(`${key}: |-`)
|
||||||
result.push(` ${value}`)
|
result.push(` ${value}`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -66,12 +68,14 @@ export namespace ConfigMarkdown {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function parse(filePath: string) {
|
export async function parse(filePath: string) {
|
||||||
const raw = await Bun.file(filePath).text()
|
const template = await Bun.file(filePath).text()
|
||||||
const template = preprocessFrontmatter(raw)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const md = matter(template)
|
const md = matter(template)
|
||||||
return md
|
return md
|
||||||
|
} catch {
|
||||||
|
try {
|
||||||
|
return matter(fallbackSanitization(template))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new FrontmatterError(
|
throw new FrontmatterError(
|
||||||
{
|
{
|
||||||
|
|
@ -82,6 +86,7 @@ export namespace ConfigMarkdown {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const FrontmatterError = NamedError.create(
|
export const FrontmatterError = NamedError.create(
|
||||||
"ConfigFrontmatterError",
|
"ConfigFrontmatterError",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Response Formatting Requirements
|
||||||
|
|
||||||
|
Always structure your responses using clear markdown formatting:
|
||||||
|
|
||||||
|
- By default don't put information into tables for questions (but do put information into tables when creating or updating files)
|
||||||
|
- Use headings (##, ###) to organise sections, always
|
||||||
|
- Use bullet points or numbered lists for multiple items
|
||||||
|
- Use code blocks with language tags for any code
|
||||||
|
- Use **bold** for key terms and emphasis
|
||||||
|
- Use tables when comparing options or listing structured data
|
||||||
|
- Break long responses into logical sections with headings
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
description: General coding and planning agent
|
||||||
|
mode: subagent
|
||||||
|
model: synthetic/hf:zai-org/GLM-4.7
|
||||||
|
tools:
|
||||||
|
write: true
|
||||||
|
read: true
|
||||||
|
edit: true
|
||||||
|
stuff: >
|
||||||
|
This is some stuff
|
||||||
|
---
|
||||||
|
|
||||||
|
Strictly follow da rules
|
||||||
|
|
@ -104,7 +104,7 @@ describe("ConfigMarkdown: frontmatter parsing", async () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should extract occupation field with colon in value", () => {
|
test("should extract occupation field with colon in value", () => {
|
||||||
expect(parsed.data.occupation).toBe("This man has the following occupation: Software Engineer\n")
|
expect(parsed.data.occupation).toBe("This man has the following occupation: Software Engineer")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should extract title field with single quotes", () => {
|
test("should extract title field with single quotes", () => {
|
||||||
|
|
@ -128,15 +128,15 @@ describe("ConfigMarkdown: frontmatter parsing", async () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should extract URL with port", () => {
|
test("should extract URL with port", () => {
|
||||||
expect(parsed.data.url).toBe("https://example.com:8080/path?query=value\n")
|
expect(parsed.data.url).toBe("https://example.com:8080/path?query=value")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should extract time with colons", () => {
|
test("should extract time with colons", () => {
|
||||||
expect(parsed.data.time).toBe("The time is 12:30:00 PM\n")
|
expect(parsed.data.time).toBe("The time is 12:30:00 PM")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should extract value with multiple colons", () => {
|
test("should extract value with multiple colons", () => {
|
||||||
expect(parsed.data.nested).toBe("First: Second: Third: Fourth\n")
|
expect(parsed.data.nested).toBe("First: Second: Third: Fourth")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should preserve already double-quoted values with colons", () => {
|
test("should preserve already double-quoted values with colons", () => {
|
||||||
|
|
@ -148,7 +148,7 @@ describe("ConfigMarkdown: frontmatter parsing", async () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should extract value with quotes and colons mixed", () => {
|
test("should extract value with quotes and colons mixed", () => {
|
||||||
expect(parsed.data.mixed).toBe('He said "hello: world" and then left\n')
|
expect(parsed.data.mixed).toBe('He said "hello: world" and then left')
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should handle empty values", () => {
|
test("should handle empty values", () => {
|
||||||
|
|
@ -190,3 +190,39 @@ describe("ConfigMarkdown: frontmatter parsing w/ no frontmatter", async () => {
|
||||||
expect(result.content.trim()).toBe("Content")
|
expect(result.content.trim()).toBe("Content")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("ConfigMarkdown: frontmatter parsing w/ Markdown header", async () => {
|
||||||
|
const result = await ConfigMarkdown.parse(import.meta.dir + "/fixtures/markdown-header.md")
|
||||||
|
|
||||||
|
test("should parse and match", () => {
|
||||||
|
expect(result).toBeDefined()
|
||||||
|
expect(result.data).toEqual({})
|
||||||
|
expect(result.content.trim()).toBe(`# Response Formatting Requirements
|
||||||
|
|
||||||
|
Always structure your responses using clear markdown formatting:
|
||||||
|
|
||||||
|
- By default don't put information into tables for questions (but do put information into tables when creating or updating files)
|
||||||
|
- Use headings (##, ###) to organise sections, always
|
||||||
|
- Use bullet points or numbered lists for multiple items
|
||||||
|
- Use code blocks with language tags for any code
|
||||||
|
- Use **bold** for key terms and emphasis
|
||||||
|
- Use tables when comparing options or listing structured data
|
||||||
|
- Break long responses into logical sections with headings`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("ConfigMarkdown: frontmatter has weird model id", async () => {
|
||||||
|
const result = await ConfigMarkdown.parse(import.meta.dir + "/fixtures/weird-model-id.md")
|
||||||
|
|
||||||
|
test("should parse and match", () => {
|
||||||
|
expect(result).toBeDefined()
|
||||||
|
expect(result.data["description"]).toEqual("General coding and planning agent")
|
||||||
|
expect(result.data["mode"]).toEqual("subagent")
|
||||||
|
expect(result.data["model"]).toEqual("synthetic/hf:zai-org/GLM-4.7")
|
||||||
|
expect(result.data["tools"]["write"]).toBeTrue()
|
||||||
|
expect(result.data["tools"]["read"]).toBeTrue()
|
||||||
|
expect(result.data["stuff"]).toBe("This is some stuff\n")
|
||||||
|
|
||||||
|
expect(result.content.trim()).toBe("Strictly follow da rules")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue