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
它没有任何 YAML 头部,第一行就是一个一级标题。文件位于测试夹具目录 [fixtures/](https://gitcode.com/GitHub_Trending/openc/opencode/blob/7c2199d84a5830f70a8250731a42ff958145b4d6/packages/opencode/test/config/fixtures?utm_source=gitcode_repo_files) 下,与 [frontmatter.md](https://gitcode.com/GitHub_Trending/openc/opencode/blob/7c2199d84a5830f70a8250731a42ff958145b4d6/packages/opencode/test/config/fixtures/frontmatter.md?utm_source=gitcode_repo_files)、[empty-frontmatter.md](https://gitcode.com/GitHub_Trending/openc/opencode/blob/7c2199d84a5830f70a8250731a42ff958145b4d6/packages/opencode/test/config/fixtures/empty-frontmatter.md?utm_source=gitcode_repo_files)、[no-frontmatter.md](https://gitcode.com/GitHub_Trending/openc/opencode/blob/7c2199d84a5830f70a8250731a42ff958145b4d6/packages/opencode/test/config/fixtures/no-frontmatter.md?utm_source=gitcode_repo_files)、[weird-model-id.md](https://gitcode.com/GitHub_Trending/openc/opencode/blob/7c2199d84a5830f70a8250731a42ff958145b4d6/packages/opencode/test/config/fixtures/weird-model-id.md?utm_source=gitcode_repo_files) 一起,构成 `ConfigMarkdown` 解析器的边界条件测试集。
该文件被 [markdown.test.ts](https://gitcode.com/GitHub_Trending/openc/opencode/blob/7c2199d84a5830f70a8250731a42ff958145b4d6/packages/opencode/test/config/markdown.test.ts?utm_source=gitcode_repo_files#L194-L212) 中名为 "frontmatter parsing w/ Markdown header" 的用例引用:
```typescript
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().replace(/\r\n/g, "\n")).toBe(`# Response Formatting Requirements
...`)
})
这条断言就是该夹具存在的意义,它验证了 opencode 对 Markdown 配置文件的解析契约:文件以 Markdown 标题开头、不含 frontmatter 时,解析不报错,data 为空对象 {},整份正文(含首行 # 标题)原封不动进入 content 字段。这与 empty-frontmatter.md 和 no-frontmatter.md 两个用例共同覆盖了「frontmatter 为空 / frontmatter 缺失」两类退化情况。
解析核心:gray-matter 优先,失败后走宽松 sanitizer
ConfigMarkdown.parse 的实现在 packages/core/src/config/markdown.ts:
import matter from "gray-matter"
export function parse(content: string) {
try {
return matter(content)
} catch {
return matter(sanitize(content))
}
}
对 markdown-header.md 这类文件,gray-matter 的 frontmatter 匹配器找不到文件顶部的 ---...--- 块,于是返回 data: {} 加完整 content,这正是测试断言所依赖的行为。对普通 frontmatter 文件(如 weird-model-id.md),则一次性解析出 description、mode、model、tools 等字段,正文 "Strictly follow da rules" 作为 content。
更值得展开的是 catch 分支里的 sanitize 函数。源码注释写明动机:其他编码智能体允许 frontmatter 中出现非标准 YAML(比如未加引号、值里带冒号),为让用户的存量配置文件继续可用,opencode 在首次解析失败时会做一轮宽松重写:
export function sanitize(content: string) {
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/)
if (!match) return content
// ...
const entry = line.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.*)$/)
// ...
if (!value.includes(":")) return [line]
return [`${entry[1]}: |-`, ` ${value}`]
}
它的规则是:只处理顶部 frontmatter 块内的顶层 key: value 行;若值包含冒号且未用引号包裹,就把该行改写成 YAML 块标量(key: |- 加缩进行),再交给 gray-matter 重解析一次。frontmatter.md 夹具就是为这套逻辑设计的压力测试,markdown.test.ts 覆盖了十余种情形:
- 值内含多个冒号:
occupation: This man has the following occupation: Software Engineer被完整保留; - 已用单/双引号包裹的值(
title: 'Hello World'、quoted_colon: "Already quoted: no change needed")不做改写; - 含冒号的时间与 URL(
time: The time is 12:30:00 PM、url: https://example.com:8080/path?query=value)正确提取; - 注释行
# field: ...不进入data;空值(empty:)解析为null; - frontmatter 之后正文里长得像 YAML 的行(
fake_field: this is not yaml)绝不会被解析——sanitizer 的正则只锚定文件最顶部的---块。
这套「严格解析优先、宽松重写兜底」的两级策略,是对齐其他编码智能体配置生态的关键兼容层。
opencode 包装层:@文件引用 与 shell 内联语法
packages/opencode/src/config/markdown.ts 在 core 层之上封装了面向会话输入与命令模板的两个正则和文件级解析入口:
export const FILE_REGEX = /(?<![\w`])@(\.?[^\s`,.]*(?:\.[^\s`,.]+)*)/g
export const SHELL_REGEX = /!`([^`]+)`/g
files(template):从文本中抽取@path形式的文件引用。负向后行断言(?<![\w]保证前缀是单词字符或反引号时不匹配——[测试用例](https://gitcode.com/GitHub_Trending/openc/opencode/blob/7c2199d84a5830f70a8250731a42ff958145b4d6/packages/opencode/test/config/markdown.test.ts?utm_source=gitcode_repo_files#L28-L90) 验证了它恰好命中 12 个合法路径(含隐藏文件@.bashrc、绝对路径@/absolute/paths.txt、home 路径@~/home-files),同时排除反引号包裹的 ``@quoted/in/backticks`` 和邮箱user@example.com`;shell(template):抽取!`command`形式的内联 shell 命令;parse(filePath):读取文件后调用 core 层解析,失败时抛出携带路径与原始错误的FrontmatterError(markdown.ts 第 20–34 行),供上层统一呈现定位清晰的错误信息。
谁在消费这些 Markdown:Agent、Command、Mode 与 Skill
解析契约落到真实加载链路后,「正文 = 提示词、frontmatter = 元数据」的拆分才有意义。
Agent / Mode。config/agent.ts 用 glob 扫描 {agent,agents}/**/*.md,逐个执行 ConfigMarkdown.parse(item).catch(() => undefined)——注意这里把解析失败静默吞掉(返回 undefined 后跳过该文件),避免一个损坏文件阻断整个配置加载:
const md = await ConfigMarkdown.parse(item).catch(() => undefined)
if (!md) continue
const config = { name, ...md.data, prompt: md.content.trim() }
frontmatter 字段展开进配置、正文 trim() 后成为 prompt。对照夹具 weird-model-id.md(frontmatter 含 description、mode: subagent、model: synthetic/hf:zai-org/GLM-4.7、嵌套 tools),可以看到一个完整 Agent 定义文件长什么样:元数据负责路由与权限,正文负责行为约束。config/command.ts 的 Command 加载逻辑与之同构,扫描 {command,commands}/**/*.md,正文成为 template,且解码失败时抛出带文件路径的 InvalidError。
Skill。skill/index.ts 的 add 流程同样以 ConfigMarkdown.parse 为入口,但它多一步 frontmatter 形状校验 isSkillFrontmatter(md.data):没有 name/description 等必需字段的文件直接不被当作 Skill 收录。这意味着像 markdown-header.md 这样 data 为空的文件,如果出现在 Skill 目录里会被静默忽略而不是报错——「无 frontmatter 可解析」和「被当作配置项」是两个独立的判定。
会话提示词模板。session/prompt.ts 的 resolvePromptParts 把用户输入中的 @文件 引用解析为附件:~/ 前缀拼接到用户主目录,其余相对 worktree 根解析;路径不存在时还会回退尝试匹配 Agent 名称。命令模板执行阶段(prompt.ts 第 1397–1408 行)则用 ConfigMarkdown.shell 抽出 !`cmd` 片段,按用户配置的 shell 逐条执行,并用输出替换原片段——命令参数占位符 $ARGUMENTS 在此之前已被替换。
如何验证:运行相关测试
该解析契约由 markdown.test.ts 完整守护,在仓库根目录可用以下命令单独运行(仓库基于 Bun 工具链):
bun test packages/opencode/test/config/markdown.test.ts
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00