跳转到内容

配置与认证

一次接好模型,再用模型池、自动切换和项目覆盖去复用。Chord 将行为配置与凭据配置分开管理。

  • ~/.config/chord/config.yaml:provider、模型、权限、扩展能力等行为配置
  • ~/.config/chord/auth.yaml:API key 或 OAuth 凭据
  • .chord/config.yaml:项目级覆盖配置
  • ~/.config/chord/agents/ / .chord/agents/:角色配置

无需从头到尾阅读本页:

优先级从低到高:

  1. 内置默认
  2. 全局配置
  3. 项目配置
  4. Agent 级配置

兼顾用户习惯、项目差异和不同 Agent 的能力特化。

项目配置读取启动目录下的 .chord/config.yaml,不会向父目录查找。只填写需要覆盖的字段,其余沿用全局设置。合并规则如下:

  • 项目里没写的字段会保持真正的未设置状态,不会意外遮蔽全局默认值;
  • 任何配置文件里无法识别的键、类型不对的值、或超出范围的取值,都会记录到 chord.log 并按未配置处理,文件其余部分照常生效;项目配置里的非法字段回退到被覆盖的全局值。YAML 语法错误(文件无法解析)会阻止启动,可用 chord doctor config 查看完整问题列表;
  • 能按原样加载、但多半达不到预期效果的设置(比如 Chat Completions 网关收不到的 thinking 块)会以警告记录到 chord.log,chord doctor config 也会列出,但不算作问题;
  • paths.*、maintenance.*(以及 model_templates、diagnostics)这类仅全局生效的字段,即使写进项目配置也会被忽略;
  • 大多数标量值和对象值会按同一路径直接覆盖全局值;
  • model_pools 按 pool 名称合并:项目里同名 pool 会覆盖全局定义;
  • mcp 按 server 名称合并:项目里的同名 server 会完整替换全局定义,不会逐字段继承旧的连接、凭据或工具权限;
  • 追加型扩展点会保留全局条目并附加项目条目:当前包括 skills.paths 和 hooks.* 下各触发点的 hook 列表,它们是 append,不是 replace。

全局 config.yaml 缺失时,首次运行 chord 会启动一次性的初始化向导,写入 config.yaml,必要时再写入 auth.yaml,具体交互见快速开始。想自己写这两个文件也没问题,本页以下内容就是完整的字段参考。

providers:
modelscope:
type: chat-completions
api_url: https://api-inference.modelscope.cn/v1/chat/completions
models:
Qwen/Qwen3.5-397B-A17B:
limit:
context: 262144
input: 262144
output: 65536
modalities:
input: [text, image]

BigModel Chat Completions(Coding Plan)

Section titled “BigModel Chat Completions(Coding Plan)”

Chord 的 api_url 是完整请求 URL。BigModel Coding Plan 的 OpenAI-compatible endpoint 需要在 Coding Plan base 后追加 /chat/completions。

providers:
bigmodel:
type: chat-completions
api_url: https://open.bigmodel.cn/api/coding/paas/v4/chat/completions
models:
glm-5.3: &bigmodel-glm-5-3
limit:
context: 1000000
output: 128000
reasoning:
effort: max
compat:
request_overrides:
rename_body_fields:
max_completion_tokens: max_tokens
body:
thinking:
type: enabled
clear_thinking: false
reasoning_continuity:
mode: openai_visible
glm-5.3-flash:
<<: *bigmodel-glm-5-3
modalities:
input: [text, image, pdf]

glm-5.3 是纯文本旗舰;glm-5.3-flash 的文本参数与设置完全相同,另加图像 / PDF 输入,按工作负载需要的模型 ID 选用即可。

各 provider / 模型的可复制片段(GPT-5.4/5.5/5.6、Claude、Gemini、GLM、DeepSeek/OpenAI-compatible)见模型配置速查。

providers:
openai:
type: responses
api_url: https://api.openai.com/v1/responses
models:
gpt-5.6-sol:
limit:
context: 1050000
output: 128000
reasoning:
effort: medium
summary: auto
variants:
low:
reasoning:
effort: low
high:
reasoning:
effort: high
xhigh:
reasoning:
effort: xhigh
max:
reasoning:
effort: max
modalities:
input: [text, image, pdf]
model_pools:
default:
- openai/gpt-5.6-sol@xhigh

还需要在 ~/.config/chord/auth.yaml 中为这个 provider 配置 API key:

openai:
- "$OPENAI_API_KEY"
  • gpt-5.6-terra 和 gpt-5.6-luna 的配法相同;models 的 key 与 model_pools 的 ref 要用同一个模型 ID。
  • 这份片段面向官方 OpenAI API,因此直接声明 1050000 全窗口且不写 input:Chord 按 context 减去模型声明的 limit.output 推导可用输入预算 (此处为 1050000 - 128000 = 922000);只有未声明 limit.output 的模型才回退到 默认输出上限(64000)。这里超过 272K 是计价阈值,不是输入上限,因此不要 再补 input: 272000。
  • Codex OAuth 与 API 使用相同的模型窗口:GPT-5.4 / 5.6 / 6 在 Codex 上同样是 1050000 / 922000 / 128000 档位(见下方 OpenAI Codex preset)。
  • API 支持的 reasoning effort 为 none、low、medium、high、xhigh、max;可用 openai/gpt-5.6-sol@xhigh 这样的 ref 选择已配置 variant。
  • Responses 在启用 reasoning 时默认使用 reasoning.summary: auto;如需明确关闭,请配置为 none。Chord 当前尚未暴露 GPT-5.6 的 reasoning.mode: pro。
  • preset: codex provider 也可以使用 max;是否接受该 effort 由具体模型 / 后端决定。

模型限制和 reasoning 取值已根据当前 Codex 模型目录及 OpenAI 的 GPT-5.6 配置指南核对。 中转的实际配额可能更小,应以上游公布的模型目录为准。

按这个顺序理解模型限制:

  1. limit.context 是总窗口。对大多数模型,只要「输入 + 请求输出」放得进这个数字即可。
  2. limit.input 只在 provider 还单独列出输入上限时才需要。部分 GPT 模型属于这种情况;如果省略,Chord 按 limit.context 减去模型自身的 limit.output 推导可用输入预算,只有模型未声明 limit.output 时才回退到全局默认输出上限(max_output_tokens,默认 64000)。显式声明的 limit.input 始终按原值使用。
  3. limit.output 是模型的最大输出能力。Chord 默认 max_output_tokens 为 64000,因此在按可用上下文继续收缩前,实际请求上限为 min(64000, limit.output)。如需不同的全局上限,请显式设置 max_output_tokens。若某模型实际输出能力低于 64000 且未配置 limit.output,在服务端校验 max_tokens 的后端会直接拒绝这类请求,请为该模型声明 limit.output,或调低全局 max_output_tokens。

Responses 和 Chat Completions 服务商的 parallel_tool_calls 默认都是 true。只有后端或工作流要求串行工具调用时,才在服务商、模型或变体上设为 false。部分网关要求特定客户端标识时,还可以配置服务商级 user_agent。

Provider 的认证头会与 type 分开推断;如果某个兼容 endpoint 要求不同的凭据 header,也可以用 auth_scheme 手动覆盖:

  • type: messages → 默认 auth_scheme: anthropic-api-key(发送 x-api-key)
  • type: responses → 默认 auth_scheme: bearer(发送 Authorization: Bearer)
  • type: chat-completions → 默认 auth_scheme: bearer

Azure OpenAI Responses endpoint 用普通 type: responses provider 配置:auth_scheme: api-key、store: true,并用 compat.request_overrides.headers 置 null 移除 Codex 身份 header(见下文)。

支持的 auth_scheme 取值有:

  • anthropic-api-key
  • bearer
  • api-key

只有当 endpoint 的认证要求和 Chord 默认传输策略不一致时,才需要显式覆盖。例如,有些 /messages 兼容接口虽然走 Anthropic 风格的请求体,却要求 Authorization: Bearer,而不是 x-api-key。这时保留原有 type,只设置 auth_scheme: bearer 即可。

对于 Anthropic 受限开放的 1M 上下文能力,Chord 只会在模型声明至少 1M token 窗口时启用:优先读取 limit.input,否则读取 limit.context。窗口较小的模型不会收到相应 beta header。超过 200K token 时,服务商可能采用不同的权限要求和计价方式。

store 控制 Responses 后端是否在服务端保留请求和响应。默认值都是 false。只有后端明确要求服务端留存、且你接受相应数据保留影响时才启用。不要为 preset: codex 开启;官方 Codex OAuth 端点会拒绝 store: true。

Codex OAuth 与 API 示例使用相同的模型窗口,区别只在 provider preset 与认证方式。

providers:
codex:
preset: codex
type: responses
models:
gpt-5.5:
limit:
context: 400000
input: 272000
output: 128000
gpt-5.4:
limit:
context: 1050000
input: 922000
output: 128000
gpt-5.6-sol:
limit:
context: 1050000
input: 922000
output: 128000

GPT-5.4 / GPT-5.6 Sol / Terra / Luna / GPT-6 Sol / Luna / Astra / GPT-6.1 Sol 使用 1050000 / 922000 / 128000 (1.05M 总窗口;922K 输入预算由 context − output 推导,这些模型不公布 独立输入上限);GPT-5.5 与 GPT-5.2 使用 400000 / 272000 / 128000。 完整示例见 模型配置速查。

preset: codex 可使用 auth.yaml 中的 OpenAI / ChatGPT OAuth 凭据。OAuth 条目通常是 mapping:

codex:
- refresh: rfr_...
access: eyJ...
expires: 1774009702606
account_id: acc_... # 可选;workspace/account 账号才一定有
account_user_id: u_...__acc_... # 可选;缺失时后台解析/补齐
email: user@example.com # 可选

account_id 不是所有 ChatGPT 账号都有。个人 Plus/Pro 账号的 access token 可能只包含 user_id,不包含 chatgpt_account_id;这类账号现在仍会作为普通 OAuth access token 使用,请求时不会发送 ChatGPT-Account-ID header。依赖 workspace/account id 的增强能力(例如 Codex usage / rate limit polling)会跳过这些账号,直到后台解析或配置中提供了 account id。

为支持大量账号池,Chord 启动时不会同步解析每个 OAuth JWT,也不会因为某个 access token 缺 account_id 阻塞 provider 初始化。启动路径只读取 auth.yaml 中已经显式写出的 metadata;缺失的 account_user_id、account_id、email、expires 会在 provider 建立后后台解析并尽量回填。若手动转换 Codex / sub2api / 其他登录结果,建议保留能拿到的 account_id、account_user_id 和 email,但它们不是启动必填项。

Azure OpenAI Responses endpoint 用普通 type: responses provider 配置:auth_scheme: api-key、store: true。要省略 Codex 流式身份 header,可在 compat.request_overrides.headers 中将对应值置为 null:

providers:
azure:
type: responses
api_url: https://YOUR-RESOURCE.openai.azure.com/openai/v1/responses
auth_scheme: api-key
store: true
trust_http_400: true
retry_after_max_s: 86400
compat:
request_overrides:
headers:
OpenAI-Beta: null
originator: null
models:
gpt-5.5:
limit:
context: 400000
input: 272000
output: 128000

Azure v1 Responses endpoint 可以直接使用 /openai/v1/responses;只有需要固定或启用特定版本(例如 preview)时,才在 api_url 中添加 api-version。Azure API key 写在 auth.yaml 的同名 provider 下:

azure:
- $AZURE_OPENAI_API_KEY
providers:
gemini:
api_url: https://generativelanguage.googleapis.com/v1beta/models
models:
gemini-3.8-flash:
limit:
context: 1048576
output: 65536
modalities:
input: [text, image, pdf]

Gemini 的 api_url 应设为 /models 基础路径。Chord 根据 URL path 的 /models 后缀自动识别为 type: generate-content,可省略 type。不要在 URL 中包含模型名或 :streamGenerateContent?alt=sse,Chord 会自动追加 /{model}:streamGenerateContent?alt=sse。models 下的 key(如 gemini-3.8-flash)即为发送给 Gemini 的模型 ID。

Gemini 的 thinking 参数与其他 provider 一样统一放在 thinking 下(不使用 gemini_thinking 之类的专有键):

  • thinking.budget → generationConfig.thinkingConfig.thinkingBudget
    • Gemini:✅ 使用
    • Anthropic:⚠️ 仅在 thinking.type: enabled 时用于预算模式
    • OpenAI:❌ 忽略
  • thinking.include_thoughts → generationConfig.thinkingConfig.includeThoughts
    • Gemini:✅ 使用
    • Anthropic / OpenAI:❌ 忽略
  • thinking.level → generationConfig.thinkingConfig.thinkingLevel(minimal|low|medium|high,Gemini 3+;并非所有模型都支持 minimal)
    • Gemini 3+:✅ 使用
    • Gemini 2.x / Anthropic / OpenAI:❌ 忽略

示例:

providers:
gemini:
api_url: https://generativelanguage.googleapis.com/v1beta/models
models:
gemini-2.5-flash:
limit:
context: 1048576
output: 65536
modalities:
input: [text, image, pdf]
thinking:
budget: -1
include_thoughts: true
gemini-3-pro:
limit:
context: 1048576
output: 65536
modalities:
input: [text, image, pdf]
thinking:
budget: -1
level: high

省略 type 时,Chord 按以下规则自动推断:

  • preset: codex → responses
  • api_url 的 path 以 /responses 结尾 → responses
  • api_url 的 path 以 /chat/completions 结尾 → chat-completions
  • api_url 的 path 以 /messages 结尾 → messages
  • api_url 的 path 以 /models 结尾 → generate-content

不匹配以上规则时,需显式设置 type。

如果你的模型会输出英文 thinking / reasoning,而你希望在界面中附加中文译文,可启用 thinking_translation:

model_pools:
translation:
- openai/gpt-5.4-mini
thinking_translation:
target_language: zh-Hans
model_pool: translation
max_chars: 1000

要点:

  • 只翻译 thinking / reasoning,不翻译 assistant 正文。译文附加在对应 thinking 卡片下方,使用中性的 Translated · <target_language> 分隔标题,保留 Markdown / 代码高亮,不会写回模型上下文。
  • target_language 和 model_pool 都是必填,缺失任一项时该能力不会启用。model_pool 必须指向一个顶层 model_pools 条目,建议单独配置低成本翻译池。该池可包含多个 provider/model[@variant] ref;翻译会按顺序执行单轮 fallback:候选失败(含网络/5xx/超时)、返回为空、明显截断或不是目标语言时,都会切到下一个候选。
  • max_chars(默认 1000)限制送去翻译的 thinking 预览长度,只翻译开头 max_chars 个字符,超出部分不会出现在翻译卡片中。追求更低延迟/成本可设为 500,希望译文更完整可调大。
  • 某个 thinking block 临时失败只会跳过该 block,不会阻塞后续 thinking 翻译,也不会影响主回答。provider 底层传输超时(默认一分钟级别)仍然生效,卡住的模型 / key 可以失败切换,同时模型池仍有机会完整运行。
  • 译文持久化到会话目录的 thinking_translations.json,恢复同一 session 时直接复用。同一个 thinking block 最多翻译一次:之后修改 thinking_translation.target_language 也不会重新翻译已存在的块。

更完整的字段说明见下文配置参考。

auth.yaml 的 key 名需与 config.yaml 中的 provider 名称对应:

首次向导可以帮你创建这个文件。它既支持字面 API key,也支持 $ENV_VAR 占位符。

anthropic:
- "$ANTHROPIC_API_KEY"
openai:
- "$OPENAI_API_KEY"

可配置多个 key 作为轮换或备用。

对于 preset: codex 的 OAuth provider,Chord 把高频变化的运行时状态(额度快照、重置时间、最近 warm-up 时间、共享 OAuth 状态缓存)写入 auth.state.json,避免频繁改写 auth.yaml。

这样拆分是有意为之:

  • auth.yaml 仍是用户可编辑的凭据与稳定 OAuth 字段来源,例如 refresh、access、expires、account_id、email;Chord 重写文件时会省略空 OAuth 字段,OAuth status 不属于 auth.yaml;
  • auth.state.json 是机器维护的共享运行时状态。普通条目在每个 provider 下直接以 account_user_id 为 key;quota / reset 更新,以及 expired、deactivated、invalidated 这类账号状态,不会在用户可能同时编辑 auth.yaml 时频繁改写该文件。尚不知道账号的 refresh-only 凭据可临时使用 refresh_sha256:<digest> state 条目,直到首次成功 refresh 后回填 account_user_id。chord auth state clean 会移除没有对应 auth.yaml OAuth 凭据的孤儿状态,以及无法识别的旧 state key 格式。

对带 access 的 OAuth 凭据来说,access token 必须能解析出 account 与 user/account-user claim。如果 auth.yaml 已有 account_id,token 中的账号 ID 必须一致;否则该 access token 会被视为账号不匹配而拒绝。Chord 也支持只包含 refresh、没有 access 的 OAuth 条目,并会在首次使用时刷新;成功刷新后会解析 account_id 并把运行时状态切换到 account_user_id key。如果在账号未知前 refresh 发生不可恢复失败,Chord 会在 refresh_sha256:<digest> 下记录无效状态,之后由用户执行 chord auth state clean 清理该不可用凭据。既没有 access 也没有 refresh 的 OAuth 条目不可用。

expires 是 access token 的 Unix 毫秒过期时间。如果 access 是带 exp claim 的 JWT,Chord 会优先使用该值作为更准确的过期元数据,并可将得到的过期时间缓存到 auth.state.json,但不会在 state 文件里保存 access token。缺失或本地已过期的 expires 不会单独把 OAuth slot 标记为 expired 或不健康。Chord 仍会先尝试已有的 access token,只有在认证失败后,才会在可恢复时刷新凭据,或者在无法恢复时标记为 expired。

典型的 auth.state.json 内容如下:

{
"openai": {
"user-1__acc-1": {
"account_user_id": "user-1__acc-1",
"account_id": "acc-1",
"email": "user@example.com",
"expires": 1774009702606,
"status": "expired",
"updated_at": 1774009702606,
"last_warmup_at": 1774009702606,
"codex_primary_used_pct": 12.5,
"codex_primary_window_minutes": 60,
"codex_primary_reset_at": 1774013302000,
"codex_secondary_used_pct": 40,
"codex_secondary_window_minutes": 10080,
"codex_secondary_reset_at": 1774600000000
}
}
}

status 字段只在 auth.state.json 中权威生效。access token 已不可用且凭据无法刷新时,Chord 会写入 expired(包括 refresh token 缺失、无效、过期或已被复用),服务端报告账号停用 / 封禁时写入 deactivated,账号需要重新认证时写入 invalidated。任意非空状态都会让该 OAuth slot 不再被选择,直到清理或替换凭据。

这些 Codex 缓存字段是跨重启保留的调度与展示提示,不是硬封禁:

  • 会帮助启动后 / 首次选号时优先选择更可能仍有额度的账号;
  • 会让切 key 时先显示上次缓存的额度快照,再等待新 warm-up 覆盖;
  • 不会仅凭字段本身就让账号绝对不可选;
  • 真正的硬封禁仍来自已确认的请求失败和运行时 cooldown 状态。

auth.yaml 的标量 API key 值支持环境变量展开:

anthropic:
- "$ANTHROPIC_API_KEY"
openai:
- "${OPENAI_API_KEY}"

标量字符串以 $ 开头时触发展开。未设置的环境变量会展开为空字符串并被过滤,除非 YAML 值本身就是字面空字符串。该展开仅适用于 auth.yaml 凭据,config.yaml 的字段不会自动展开。

确实需要空 API key 时,请显式写字面空字符串:

local-provider:
- ""

不要依赖未设置的环境变量来表示空 key:未设置的 $ENV_VAR 会被视为缺失凭据而过滤掉。

Chord 支持多个 API key / OAuth 账号时的两层选择策略:key_rotation 决定何时重新选 key,key_order 决定在候选 key 中如何选择。

  • key_rotation: on_failure(默认):尽量固定使用当前 key,只有失败、冷却或不可用时才切换。
  • key_rotation: per_request:每次请求前都重新选择 key,适合多个独立 key 做负载均衡。
  • key_order: sequential(默认的非 Codex 行为):按可用 key 的稳定顺序选择,通常接近「最久未使用优先」。
  • key_order: random:在可用 key 中随机挑选。
  • key_order: smart:仅 Codex provider 支持。会优先健康、额度更充足、reset 更近的 OAuth 账号。

key_rotation 只轮换 credential / API key,不会轮换模型;模型选择仍由 model pool 的 sticky cursor 和 fallback 逻辑控制。

在 loop 模式下,Chord 仍尊重用户显式配置的 key_rotation / key_order。如果希望 Codex 长任务保持 transport / cache 连续性,建议保留默认 key_rotation: on_failure;如果希望多账号分摊额度,则可显式启用 per_request。

当前仅配置了 preset: codex 的 provider 支持 OAuth。

对 Codex provider,建议只写 preset: codex 和模型配置,不要手动覆盖 api_url、token_url、client_id、type、store、responses_websocket 或 supported_service_tiers 等由 preset 管理的字段。Codex preset 会自动选择官方 OAuth transport、Responses endpoint、WebSocket / cache 默认值、额度轮询、smart key 排序和 service-tier 能力。它不定义另一套 HTTP 请求体,也不会强制伪装成 Codex User-Agent;非 Codex 的 type: responses provider 也使用上面那套 Responses 请求形态,所有 provider 默认仍发送 User-Agent: chord/<version>。需要显式 tier 矩阵时使用 supported_service_tiers。

Codex OAuth 账号的选择由 Provider key 选择 中的 key_rotation / key_order 控制。Codex 默认使用 key_order: smart,会结合额度快照、soft cooldown 和 reset 时间选择更合适的账号。

smart 会在可选 Codex OAuth 账号之间优先:

  • 缓存快照中没有任何受跟踪窗口达到 100% 使用率的账号;100% 窗口只会被放到最后尝试,不会仅凭快照硬封禁;
  • 短窗口(例如 5h primary window)仍有剩余额度的账号,并优先选择 primary reset 更近的账号,以免快过期额度被浪费;
  • 然后考虑长窗口(例如 1w secondary window)仍有剩余额度的账号,同样优先选择 secondary reset 更近的账号;
  • 可比较窗口的 reset 时间相同时,再选择剩余额度更高的账号;
  • 如果没有更优信息,仍会回退尝试未知或缓存较旧的账号。

当 Codex client 变为活跃状态后,Chord 还可能在后台探测其他 OAuth slot,以刷新缓存的 headroom 快照。这个 warm-up 是 best-effort、低并发的,会在活跃 client 被替换时取消,并且只刷新缓存额度状态;usage probe 的认证失败不会把 OAuth 凭据标记为不可用。

warm-up 本身也会参考共享状态优先级:

  • 从未在共享状态里 warm-up 过的账号优先;
  • 缓存较旧的账号优先于最近刚刷新的账号;
  • warm-up 或轮询拿到更新后的快照后,会写回 auth.state.json,其他进程会在下次读取选 key 或额度状态时按需吸收这些更新。
Terminal window
# 自动选择已配置的 codex provider
chord auth
# 显式指定 provider
chord auth codex
# 无桌面环境 / SSH
chord auth codex --device-code

Chord 通过命名模型池选择当前使用的模型。每个池条目建议写成完整的 provider/model[@variant],这样 provider endpoint、认证、协议以及 variant tuning 都是明确的。

模型池在 config.yaml(全局或项目级)中定义;agent 配置可以引用池名来限制可用池,但不允许在 agent 中内联定义池。

# ~/.config/chord/config.yaml 或 .chord/config.yaml
model_pools:
thinking:
- anthropic/claude-opus-5
- openai/gpt-5.5
non-thinking:
- anthropic/claude-sonnet-4

项目级 .chord/config.yaml 的 model_pools 会合并到全局配置中(同名覆盖)。

Agent 可以不设置 model_pools。省略时,该 agent 可使用合并后的 config.yaml 顶层 model_pools 中的所有池,并按池名的字母顺序排序。只有在需要限制该 agent 可用池,或自定义 fallback 顺序时,才需要设置 model_pools: [...]。

# ~/.config/chord/agents/builder.yaml 或 .chord/agents/builder.yaml
name: builder
mode: main
model_pools: [thinking, non-thinking]
.chord/agents/reviewer.yaml
name: reviewer
mode: subagent
model_pools: [thinking]

未显式选择池时,Chord 会回退到该 agent 的第一个可用池:如果配置了 model_pools: [...],使用列表中的第一个;否则使用按字母顺序排序后的第一个顶层池。

运行时通过 /models 切换当前视图对象的池(按项目持久化,重启后仍生效):main 视图作用于当前主角色,SubAgent 视图作用于该 agent。切换池会更新后续 LLM 调用的整条 fallback 链;即使当前选中的 provider/model 同时存在于两个池中,也会按新池的顺序重新构建(已发起的 in-flight 请求仍使用其开始时快照到的 client)。也可通过 /models --agent <name> <pool> 直接设置指定 agent 的池。SubAgent 默认使用第一个可用池;想恢复默认时切回该池即可。

MainAgent 忙碌时收到的用户消息会排队,等到安全的请求边界再处理。如果当前 provider/model 尝试失败,Chord 准备向下一个 fallback 模型发请求,会先把此时已经排队的消息写入对话,并随这次 fallback 请求一并发送。已经发出的 provider 请求不会被改写;fallback 请求开始后才到达的消息继续等待下一个请求边界。

Chord 没有 model_templates 配置字段,但可以在该顶层容器中使用 YAML anchor 和 merge key。Chord 会忽略容器本身,只读取 providers 下展开后的 模型配置。

merge key(<<:)把被引用映射按键级别复制进当前条目,冲突时当前条目 胜出:

  • 标量字段(reasoning.effort、compaction 比例)直接替换继承值。
  • 嵌套对象是整块替换,不是逐字段合并:在已声明 limit: {context: 1000000, output: 128000} 的模板上覆盖 limit: {context: 1050000},会悄悄丢掉继承的 output。凡是覆盖嵌套 对象(limit、cost、compaction、variants 条目、modalities……) 都要写全整块。
  • 链式继承同理(gpt-5.6-luna: &gpt-5-6-luna {<<: *gpt-5-6-base}): 越深层的条目按整个 key 胜出。
  • 无法「撤销」祖先模板声明的字段:要么用具体值覆盖,要么不再引用该模板。 compaction.threshold: 0 与 compaction.reminder: -1 是例外,用来显式 关闭这两个行为。

本页只介绍协议和字段语义。当前模型限制、价格以及 GPT / Claude / Gemini / GLM / DeepSeek 的完整可复制配置见模型配置速查。

model_templates:
chat-thinking: &chat-thinking
limit:
context: 200000
output: 64000
reasoning:
effort: high
compat:
# DeepSeek 与 GLM Chat API 使用 max_tokens,而不是 OpenAI reasoning
# 模型默认使用的 max_completion_tokens。
request_overrides:
rename_body_fields:
max_completion_tokens: max_tokens
body:
# 「走 Chat Completions 网关的 thinking」(model-configs_CN.md)里列出的
# 模型家族会自动写入这个对象;这里的 override 覆盖其他后端,也用于补充
# 同一对象里的家族特有字段(如 GLM 的 clear_thinking)。
thinking:
type: enabled
# 回放原生 reasoning_content,并把其他 wire family 的可移植可见
# reasoning 映射为 reasoning_content,同时不注入请求字段。
reasoning_continuity:
mode: openai_visible
responses-thinking: &responses-thinking
limit:
context: 200000
output: 64000
reasoning:
effort: high
summary: auto
messages-thinking: &messages-thinking
limit:
context: 200000
output: 64000
thinking:
type: adaptive
effort: high
compat:
# 除非兼容接口自己的文档明确要求,否则不要发送 Anthropic beta header。
request_overrides:
headers:
anthropic-beta: null
providers:
chat:
type: chat-completions
api_url: https://example.com/v1/chat/completions
models:
chat-model: *chat-thinking
responses:
type: responses
api_url: https://example.com/v1/responses
models:
responses-model: *responses-thinking
messages:
type: messages
api_url: https://example.com/v1/messages
models:
messages-model: *messages-thinking

模型字段语义:

  • limit.context:provider 公布的总请求窗口。如果省略该字段且同时配置了 正数的 limit.input 和 limit.output,Chord 会按 input + output 推导; 显式配置的 context 始终优先。
  • limit.input:provider 单独公布的输入上限。显式声明的值始终按原值使用, 即使与 limit.output 在窗口内不满足加和关系(input + output 超过 context)也不收敛。省略时,Chord 按 limit.context 减去模型声明的 limit.output 推导 prompt 预算(1.05M GPT 家族即 1050000 − 128000 = 922000);只有模型未声明 limit.output 时,才回退到有效默认输出上限 (max_output_tokens,默认 64000)。
  • limit.output:模型输出能力上限。实际请求还受全局 max_output_tokens 和总窗口剩余空间限制。
  • reasoning.effort:推理深度。Chord 不做本地白名单校验,provider 支持的 取值原样到达上游;Responses 线路发送前还会额外规范化空格和大小写。
    • Chat Completions 发送顶层 reasoning_effort。
    • Responses 发送 reasoning.effort 和可选的 reasoning.summary。
  • reasoning.effort_map:把规范 effort 值映射成 provider 实际接受的 wire 值,例如网关用 max 表达 Chord 的 high 时配置 {high: max}。映射作用 于最终解析后的 effort;variant 级别的 map 会替换该 variant 的模型级 map。
  • reasoning.summary:Responses 推理摘要请求。Chord 支持 auto、 concise、detailed、none;启用 reasoning 时,省略该字段会默认使用 auto,以便跨 provider 回放时保留可移植的摘要文本;配置 none 可明确退出。
  • thinking:Messages 兼容的扩展思考配置。type: adaptive 可与 thinking.effort 组合,Chord 会将 effort 发送为 output_config.effort。
  • text.verbosity:可选的 OpenAI 兼容可见文本详细程度提示。
  • variants:命名模型参数覆盖,可用 provider/model@high 选择。
  • cost:可选的每百万 token 美元成本估算,可包含输入 / 输出、缓存价格、 service tier 倍数和长上下文价格阶梯。
  • modalities.input:支持的输入类型:text、image、pdf。
  • supported_service_tiers:支持的非 standard tier,例如 fast、slow; 价格倍数需要在 cost 中单独配置。

兼容字段:

  • compat.request_overrides.body:递归合并任意 JSON 到最终协议请求中。 值为 null 时删除对应字段。

  • compat.request_overrides.rename_body_fields:重命名最终请求字段,同时保留 Chord 动态计算的值,例如 max_completion_tokens: max_tokens。

  • compat.request_overrides.headers:设置任意请求 header。值为 null 时 删除 Chord 默认 header,例如兼容 Messages endpoint 使用 anthropic-beta: null。

  • compat.reasoning_continuity.mode:

    • none:不回放 provider 专属的可见 reasoning。

    • openai_visible:在 Chat Completions 工具循环中原样回放 assistant 的 reasoning_content,并把其他 wire family 的可移植可见 reasoning 转成 reasoning_content。它不注入请求字段;字段差异由 request_overrides.body 配置。首次尝试时,Chord 仍会把 chat 原生 reasoning 乐观回放给任何 Chat Completions 目标(包括跨 provider),因此 Kimi K2.6/K2.7→K3 这类官方支持的同 provider 升级和同模型跨 provider fallback 都能保留连续性。

      目标拒绝该请求后,Chord 会对该 target 降级,但在严格级别之前仍尽量保留结构化工具事实。在 openai_visible 的 Responses 目标上,如果 thinking 模式要求回放的函数调用回合携带 reasoning,Chord 会先回放可用的原生明文 reasoning_text;跨 provider 切换模型导致原生 reasoning 丢失时,后端拒绝后 Chord 会把对应工具轨迹降级为文本历史记录,续跑不再依赖缺失的 reasoning。对第三方 OpenAI 兼容网关,Chord 始终使用配置中的 endpoint,不会重定向到 DeepSeek 官方 /beta endpoint。reasoning-only 输出截断时,Chord 可能在同一 endpoint 上做一次有上限的 request-only reasoning 回放;网关拒绝后会退回普通恢复提示。

    • anthropic_unsigned:仅用于已验证的 Messages 兼容模型,例如返回无 Claude signature 的可见 thinking 的 DeepSeek/GLM endpoint。无签名 thinking 首次只对同 provider/model 原生回放;对兼容 target,其他 wire family 的可移植可见 reasoning 会转成无签名 thinking block, 而不会注入 assistant 正文。

    • Responses、Claude 签名 Messages 和 Gemini 其余情况使用协议原生连续性 机制。Chord 只在 wire 和 provenance 允许时回放加密/签名 opaque 状态; 跨不兼容协议时,只有存在结构化目标载体(openai_visible 或 anthropic_unsigned)的可见 reasoning 才会被转换;否则直接丢弃。 Chord 不会伪造 opaque 状态,也不会把 reasoning 注入普通 assistant 正文。已完成工具事实会尽量转换为目标协议的结构化表示,只有目标拒绝 该形状时才文本化。达到的降级级别按 target 记忆。

  • compat.reasoning_continuity.reasoning_replay:控制 Chord 从已完成轮次(最后一条 user 消息之前)回放多少 reasoning。DeepSeek Chat/Messages 固定保留完整思考历史;其他目标默认 current_turn 剥离已完成轮次,all 原样回放,none 连当前轮一起剥离。

    默认剥离是为了控制请求体积。Anthropic 会在服务端过滤历史轮的 thinking 块,只为模型实际看到的块计费,省掉它们不花冤枉钱;原样回放历史的端点会为保留的每个 token 计费,所以下面那些契约要显式选 all。这条策略覆盖所有 reasoning 载荷——明文 reasoning_content、无签名 thinking block,以及 provider 绑定的原生思考(Claude 签名块、Responses reasoning items、Gemini thought 签名)——工具轨迹(调用与结果的配对)始终保留。

    目标契约要求完整 assistant 历史时设置 all(Kimi K3 及 keep: all 系列、Qwen preserve_thinking、GLM clear_thinking: false、小米 MiMo;DeepSeek Chat/Messages 不设也会保留),历史 reasoning 会原样回放并在每次请求中计费。none 只在确认过端点能接受「没有当前轮 reasoning」的请求时才设置。当前轮的 reasoning(最后一条 user 消息之后,含工具循环)在其余情况下都原样回传。

    Anthropic 还会把每个 thinking block 绑定到生成它的对话前缀:当历史改写使该绑定失效、API 以 invalid-signature 拒绝回放时,Chord 会丢弃 thinking block 重试一次,并保留该轮正文和已完成的工具事实。请求级 turn overlay(每轮注入的 <system-reminder> 提示)不算作用户消息边界,因此追加在对话尾部的 overlay 不会把「已完成轮次」的边界推到当前轮之后,也就不会剥离当前工具链中后端真正消费的 reasoning。

  • compat.forced_tool_choice.suppress_in_thinking:reasoning/thinking 启用 时,把 loop 强制的 tool_choice: required 降级为后端默认选择。只有 OpenAI 兼容端点明确拒绝 thinking 模式下的 forced tool choice 时才开启; 普通工具可用性和自动工具选择不受影响。

  • compat.forced_tool_choice.auto_only:无条件把任何非 auto 的 tool_choice 降级为后端默认选择。适用于只支持 tool_choice: "auto"、对 required/ none/指定工具名返回 400 的后端;自动工具选择不受影响。Chat Completions、 Messages、Gemini 会省略该字段;Responses 仍会显式发送 tool_choice: "auto", 除非把 compat.responses.send_tool_choice 设为 false。

  • compat.thinking_toolcall:为把工具调用编码进可见 reasoning 文本的网关 启用专用解析器。只有网关明确要求时才开启。

Provider 级 compat 是默认值;模型级 compat 可以覆盖单个模型。

请求 override 会在 Chord 构造完协议请求后应用于 HTTP 传输。如果 Codex Responses provider 配置了 override,该请求会停用 WebSocket 传输并改走 HTTP,确保最终 JSON patch 生效。

项目需要特定默认值时,在项目根目录创建:

.chord/config.yaml

常见用途:调整项目特有权限规则、配置该项目的 LSP / MCP / Hooks / Skills。

Provider 级别的 compress 选择上游 HTTP 请求体的压缩编码:gzip 或 zstd(zstd 是 Codex 客户端发给 codex-backend 请求体用的编码)。它和上下文管理(compaction / reduction)是两回事:只影响请求传输编码,不会总结或移除对话历史。

providers:
openai:
compress: gzip
codex:
preset: codex
compress: zstd # codex-backend 接受 zstd 请求体

Chord 仅在压缩能减小体积时才发送压缩请求体,否则按原文发送;压缩失败同样回退为原文并记日志。响应方向不受影响:仍然只声明并自己解压 gzip 响应。

Provider / 模型请求默认用 User-Agent: chord/<version> 标识客户端。只有某个 provider 或网关要求特定值,才配置 provider 级 user_agent:

providers:
gateway:
user_agent: RequiredGatewayClient/1.0

该配置也会影响对应 provider 的 Responses HTTP 请求、Codex OAuth 请求、Codex 用量轮询,以及 Responses WebSocket 握手。WebFetch 使用独立的 web_fetch.user_agent。

需要发送 Codex 风格 User-Agent 时,显式写入你抓到的 Codex 值,并在 Codex 客户端版本或终端环境变化后同步更新:

providers:
codex:
preset: codex
user_agent: "codex-tui/0.139.0 (Mac OS 15.3.2; arm64) ghostty/1.3.1 (codex-tui; 0.139.0)"

Provider 级重试配置控制完整重试轮之间由 Chord 生成的等待。一轮从当前 sticky 模型池游标开始,继续尝试模型池剩余候选及其可用 key;切换 fallback target 时不会单独等待。下一轮开始前使用游标所指 provider 的策略;某个 fallback 成功并成为新游标后,后续请求自然改用它的配置。同一策略也控制未携带 Retry-After 提示的普通 HTTP 429 的 key 冷却;合法的 Retry-After(受 retry_after_max_s 限制)始终优先于它。

providers:
gateway:
retry_backoff: exponential
retry_delay_ms: 500
  • retry_backoff: exponential 是默认策略,从 retry_delay_ms(默认 1000)开始逐轮翻倍,最多等待 60 秒;
  • retry_backoff: fixed 每轮固定等待 retry_delay_ms;
  • retry_backoff: none 关闭 Chord 生成的轮间退避。没有 Retry-After 提示的普通 429 不给失败 key 设置定时冷却,只把它标为 recovering,让健康 key 和 fallback target 保持优先;默认轮次没有上限,none 下上游快速持续失败时会被零间隔连续重试;
  • retry_delay_ms 可取 0 到 60000;0 / 省略表示 1000ms。策略拼错、负数或超过上限都会作为配置错误暴露。

带停顿的重试轮会把这段等待以倒计时显示在状态栏,指向下一次尝试的时刻(↺ round 12 · retry in 45s)。没有停顿、立刻重新探测的重试轮没有可倒数的等待,继续显示已经重试了多久。

普通 429 的 key 冷却遵循单一优先级:已确认的配额重置窗口最优先,其次是合法的 Retry-After(受 retry_after_max_s 限制、按原值生效),只有不带提示的 429 才落到上面的重试节奏:已配置的 exponential / fixed / none,或两个字段都没配置时的 1 秒起步指数退避。失效或停用凭据,以及其它硬状态已经建立的冷却,永远不会被缩短或清除。这套 429 节奏在可见流式输出前后一致:打断可见输出流的 429 会冷却该 key 并轮换到下一个。

所有模型的所有 key 都在冷却时,Chord 会等待而不是发请求,等多久取决于模型池的形态。只配了一个模型时没有别的可试,就一直等到最早的 key 恢复时刻——可能是 Provider 自己定义的已确认配额重置时刻,也可能是已被 retry_after_max_s 限过的 Retry-After 提示。这段等待期间不会重新探测模型池,因此等待中途新增的凭据要等这次等待结束才会被用上。配了 fallback 模型时,至少每分钟重新检查一次模型池:兄弟模型、新加的凭据或刷新后的限流快照,都可能让请求比最长那个冷却结束得更早。两种情况下状态栏倒计时都指向「真正能发出请求」的时刻,而不是下一次内部检查。池里最短的冷却始终说话:已经恢复的模型不会被另一个模型更长的冷却拖住;每分钟重新检查的那种模型池会立刻用上它。

某个 key 进入冷却后,导致冷却的那次 API 失败会记入错误面板(Ctrl+E):由显示冷却等待的那次请求记录,或由下一个前台请求(agent 的一轮对话或一次上下文压缩)记录,先到先记。记忆抽取、思考翻译等后台工作造成的失败也包括在内。被 Provider 永久判废的凭据(刷新令牌过期、账号失效或停用)会在下一个前台请求上提示。每条失败只记一次:已经由触发它的那次尝试作为重试错误上报过的失败不会重复记录。

Codex OAuth 遵循同样的规则:Codex 的所有 429 都算普通 429。重试提示(Retry-After 或 WebSocket 的 resets_in_seconds)优先于显式配置生效;既没有提示、也没有已耗尽额度快照的 usage-limit 429 使用上文的普通默认值,而不是 codex preset 的 1 分钟冷却(后者仍用于非 429 的 usage-limit 错误)。若 Codex 额度快照显示某个窗口已耗尽,并带有未来重置时间,Chord 会确认额度耗尽,仍以服务端重置时间为准。

项目级 .chord/config.yaml 可以单独覆盖某个 provider 的这些字段。

Provider 级超时配置都是可选项,单位为秒。省略或设为 0 会保持内置默认行为。

providers:
codex:
response_header_timeout: 180
stream_idle_timeout: 90
stream_total_timeout: 1800
websocket_handshake_timeout: 45
  • response_header_timeout:从开始流式 HTTP 请求到收到响应头的超时,包括连接建立与请求体上传。收到响应头后该计时器即停止,不限制健康流的总耗时;流式 chunk 之间的最大空闲时间由 stream_idle_timeout 控制。0 保持内置默认值。
  • stream_idle_timeout:流式模型数据的最大空闲等待时间。设置后会覆盖该 provider 的普通 SSE idle timeout 和慢阶段 idle timeout,也会用于 Codex Responses WebSocket 读等待。
  • stream_total_timeout:单条流的墙钟上限,单位秒,从响应体开始读取时计时。设置后也用于 Codex Responses WebSocket 读等待。0 / 省略表示不设上限(默认):持续产出数据的流只是慢、并非故障,只由 stream_idle_timeout 约束。设置它可以覆盖 idle 超时兜不住的那种形态:持续以足够频率滴数据从而不断重置 idle 计时器、但永不结束的流。超时后读取以超时错误结束,走正常的 key/model 重试路径。
  • websocket_handshake_timeout:Responses WebSocket 握手超时,主要用于启用了该 transport 的 provider,例如 preset: codex 且 responses_websocket 生效时。

这些配置按 provider 生效,因此项目级 .chord/config.yaml 可以只覆盖某一个 provider 的超时,不影响其他 provider。它们不会改变底层固定连接默认值,例如 TCP dial 或 TLS handshake timeout。

max_output_tokens 设置全局输出 token 请求上限,默认值为 64000。实际请求上限仍受各模型 limit.output 和可用总上下文(已知时为 limit.context)限制,因此所有 provider 都会取适用限制中的最小值。

Responses provider 默认保持稳定的 Responses 请求形态,HTTP 和 WebSocket 请求都不会发送 max_output_tokens 字段。对于需要显式服务端输出上限的兼容网关,可以在 provider 下设置 compat.responses.send_max_output_tokens: true;其余 Responses 字段开关也位于同一对象下。全局值在不发送到 wire 时仍会影响 Chord 侧预算和兼容性检查。

limit.input 是另一回事:只有当模型除了总上下文窗口外,还额外存在输入上限时才需要配置。降低 max_output_tokens 有助于控制成本、降低超长输出失败风险,但不会提升 provider 的输入上限,也不能替代 limit.input。

max_output_tokens: 64000

stream_retry_rounds 用来给公开 LLM 流式请求的「整轮重试」设置硬上限。 每一轮里仍会按正常顺序遍历当前模型池和 provider key;这个设置限制的是 CompleteStream 最多做多少轮完整重试。

这里的「一轮」指的是整个公开重试回合,而不是单次 provider/model 尝试。比如 stream_retry_rounds: 2 表示最多允许两次完整的路由遍历;一旦达到上限,即使是 all-keys-cooling、并发 429,或非官方兼容网关返回的可重试 HTTP 400 这类通常会等待后继续的错误,也会直接停止。

Provider HTTP 400 的处理是有意保守的:

  • 官方 API 会把 400 视为终态 invalid-request 错误;

  • 非官方兼容网关有时会把并发限制、上游容量不足等临时状态映射成 400。这类非请求形态的 400 会冷却当前 key、轮换到下一个 key,并在所有 key 都冷却时等待后继续;

  • 请求参数/模型不兼容类 400 仍会停止,避免无限重试,例如结构化 code/type 为 invalid_request_error、invalid_request 或 missing_required_parameter,或仅消息文本包含 missing required parameter、Store must be set to false 或 Stream must be set to true。

  • 0 保持默认行为:一直重试,直到成功、被取消,或遇到终态失败;

  • 正整数表示最多重试这么多轮,即使是 cooling / 并发 429 这类通常会继续等待的错误,也会在达到上限后停止;

  • 这个选项更适合自动化或 headless 场景:用可预测时延换取更明确的退出边界。

stream_retry_rounds: 3

以下选项影响本地 TUI,可写在全局配置中,也可由项目级 .chord/config.yaml 覆盖。

desktop_notification: true
desktop_notification_foreground: true
ime_switch_target: com.apple.keylayout.ABC
prevent_sleep: true
  • desktop_notification:启用本地 TUI 的终端通知。每次通知都会同时发出通知转义序列(按终端自动选择 OSC 9 或 OSC 777)和一声终端铃声(BEL)。终端聚焦时多数终端会隐藏通知横幅,铃声保证此时也能听到提示。Chord 只在 agent 真正运行过然后停下(回合完成、被取消、loop 结束,或所有 SubAgent 都完成)以及权限、Question、Handoff、loop 决策、notify 协议纠正等待用户输入时通知;会话 / model pool / MCP 切换、空闲型斜杠命令这类用户主动操作导致回到空闲时保持静默。铃声是否出声取决于终端配置,各终端的开启方式见平台说明。
  • desktop_notification_foreground:控制 TUI 聚焦时是否发送通知(转义序列和铃声一起),默认值为 true;设为 false 后仅在终端失焦时通知。
  • ime_switch_target:进入 Normal 模式时通过 im-select(Windows 为 im-select.exe)切换到指定输入法,回到 Insert 模式时恢复。常用于让快捷键在英文键盘布局下工作。
  • prevent_sleep:任意 agent 活跃时阻止 macOS 空闲睡眠,仅本地 TUI 模式生效。

web_fetch 默认使用类似浏览器的 User-Agent。某些站点需要不同请求头时,可在配置中覆盖:

web_fetch:
user_agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36

该配置同时支持全局和项目级,项目级优先。

也可为 WebFetch 请求单独配置代理:

web_fetch:
proxy: socks5://127.0.0.1:1080 # 支持 http, https, socks5
  • proxy: nil(默认): 继承全局 proxy 配置
  • proxy: ""(空字符串): 显式直连(不走代理)
  • proxy: "http://..."、"https://..."、"socks5://...":使用指定代理

web_fetch 保持轻量级静态 HTTP 读取,不运行本地浏览器。对 JS-heavy 页面,若返回的 HTML 只有应用空壳而非可读正文,结果会标记为 Content-Quality: suspect-shell。

web_search 通过 provider 的 hosted 搜索工具检索,返回摘要和编号来源。它默认关闭,需要对端支持 hosted 搜索的 Anthropic Messages 或 OpenAI Responses provider(也可以只开单个模型)显式启用:

providers:
anthropic:
type: messages
compat:
hosted_tools: [web_search]

OpenAI Responses provider 同样在 responses 类型上开启:

providers:
openai:
type: responses
compat:
hosted_tools: [web_search]

compat.hosted_tools 列出该 provider 的模型可以提供的 hosted 工具;模型未配置该字段时继承 provider 列表;显式 hosted_tools: [] 关闭该模型的全部 hosted 工具,非空列表替换 provider 列表。web_search 是内置条目,在 Anthropic Messages 上声明为 web_search_20250305,在 OpenAI Responses 上声明为 web_search。

只有工具的路由源里存在已启用、能承载该声明的目标时,工具才会出现在模型的工具列表里。未设置 model_pool 时,路由源是调用 agent 当前的模型池;设置具名 model_pool 后,路由源是该 hosted 请求指定的模型池。否则 Chord 会隐藏工具。每次调用另发一条只带 query 的请求,在那里声明 hosted 搜索工具;Chord 把返回的原生结果作为普通工具结果返回,主对话请求从不声明该工具,历史里也不会出现 provider 专属块。allowed_domains 和 blocked_domains 按请求参数下发,不会拼进 query 文本。

OpenAI 的搜索限制取决于型号和子请求的推理设置:gpt-5 在 reasoning.effort: minimal 下不支持网络搜索,gpt-5.4 在 reasoning.effort: none 下可能降低结果质量。各型号支持范围以 OpenAI 的 web search 指南为准。

Chord 的 Responses 搜索子请求不发送模型配置中的 reasoning.effort,默认使用服务端的推理设置。request_overrides 可以向该子请求注入 reasoning 参数;上述限制应按实际发送的参数判断。

子请求按服务它的模型计入 token;provider 可能另收按次检索费,Chord 的费用统计只算 token。

GPT、Claude 等模型的完整 provider 配方见模型配置配方。

顶层 hosted_tools 定义 provider 侧执行的 hosted 工具。每个条目会变成一个本地工具,调用时另发一条请求声明该 hosted 工具,服务端执行的能力(网络检索、代码执行、文件检索等)只需配置,不必写代码。某个 provider 或模型通过 compat.hosted_tools 启用,且目标的 provider 类型(messages / responses)在条目里有声明时,这个本地工具才会出现。

hosted 工具在真正服务子请求的端点上执行,可用性跟着渠道走而不只是模型:同一个中转可以服务相同的模型却不承载其 hosted 工具,部分 hosted 工具可能只有 provider 官方渠道才有。被端点拒绝或静默忽略的声明,会按 compat.hosted_tools 的说明以对应失败收口。

hosted_tools:
code_execution:
description: 在 provider 沙箱里运行 Python 代码并返回输出。
parameters:
type: object
properties:
code:
type: string
description: 要运行的 Python 源码。
required: [code]
prompt: "运行这段代码并报告结果:\n{code}"
read_only: true
timeout_s: 300
model_pool: tools
declarations:
messages:
tool: {type: code_execution_20250825, name: code_execution}
force: {type: tool, name: code_execution}
字段 默认值 说明
description 空 展示给模型的本地工具描述。
parameters 无参数的对象 schema 本地工具参数的 JSON Schema。
prompt 参数的 JSON 子请求指令模板,{arg} 会替成对应参数值;不写则把参数序列化成 JSON。
read_only false 把本地工具标记为只读,供调度判断使用;权限仍由角色的 permission 规则决定。
concurrency_safe false 允许与其他并发安全的只读工具放进同一批并行执行。
retry_safe false 允许结果未知时重试;只在重复执行安全时开启。内置 web_search 默认开启。
image_paths (空) 每个调用结果中 base64 图片字段的点分路径,如 [output.image];图片会成为工具结果附件。只遍历对象字段,不遍历数组。
timeout_s 120 单次调用的总预算(秒),覆盖里面每一次子请求。
declarations.<type> 按 provider 类型的 wire 声明:messages 或 responses。
declarations.<type>.tool (必填) 包含非空 type 的 wire JSON,放入该 family 的 tools 数组;其他字段遵循 provider 的 schema。
declarations.<type>.force (省略) 强制调用的原始 tool_choice 值。省略时仍会声明该工具并在 prompt 里要求调用,但模型不调用就算失败。
declarations.<type>.include (省略) include 选择器,例如 Responses 的 [web_search_call.action.sources]。
declarations.<type>.headers (省略) 工具声明需要的额外 HTTP 头,在 provider 默认头和请求覆盖配置之后应用。可以替换 beta 头;认证、传输和会话头受保护。
model_pool (空) 指向顶层 model_pools 条目的名称,该工具的子请求改由这个池执行,不再跟随调用方。留空时跟随调用方:主 agent 用主池,子 agent 用自己的池。池必须在启动时已定义,调用 agent 自己的 model_pools 也必须包含它;池内哪些条目能执行该工具仍由 compat.hosted_tools 决定。想钉死单个模型,建一个只含它的池即可——池条目支持 provider/model@variant。

声明里的 {"$arg": "<name>"} 会替成同名本地参数;参数缺失或为空时删掉该键,对象的键全被删光时连对象一起删。内置 web_search 条目就用它把 allowed_domains、blocked_domains 作为声明参数下发。

只写在自己配置里的条目从保守 trait 起步:非只读、非并发安全、禁止自动重放结果未知的操作。内置条目(目前是 web_search)按字段合并,改写声明就能换工具版本,不必重述本地工具面。

工具名不能与现有工具重名,也不能使用内置工具保留名或 mcp_ 前缀。启动时校验合并后的配置:每个条目需要 object 参数 schema、非负超时,以及至少一个带非空工具 type 的 messages 或 responses 声明。header 名和值必须合法,不能覆盖认证、传输或会话头;provider 专用字段仍由端点校验。已有 web_search 条目可以按字段覆盖。

首次子请求遍历该工具路由源中支持该工具的目标。未设置 model_pool 时跟随调用方:主 agent 按其当前模型池游标遍历,子 agent 遍历自己的池。每个 hosted 工具按路由源记住成功目标——具名 model_pool 在各 agent 之间共享,未设置时按调用方隔离——后续调用优先从那里开始,池内容不变时一直有效;池重建或调用方切换模型池后会重新选择,模型池中已移除或不再支持该工具的目标不会复用。路由源中没有任何目标能执行该工具时,调用显式失败,不会回退到主对话的模型。Messages 返回 pause_turn 时,Chord 保留本次完整、有序的原生内容和沙箱容器标识,在同一个目标上最多续跑 4 次;总耗时仍受 timeout_s 限制。所有尝试和续跑的 token 用量归属发起调用的 Agent 与轮次。对明确拒绝 tool_choice 的请求,会在同一目标上重试一次不强制调用的声明。

具名 model_pool 不存在或为空时,Chord 会报错并停止启动。模型条目加载失败时,Chord 会跳过该条目并将原因写入日志。路由源中没有能承载且已启用该工具的模型,或调用 agent 无权使用具名池时,Chord 会隐藏工具,并按路由源记录一次原因。工具没有出现在可用列表中时,检查池定义、agent 的 model_pools 和目标的 compat.hosted_tools。

默认 retry_safe: false。请求可能已执行而结果未知(如连接中断、流错误或续跑上限耗尽)时,Chord 停止自动换 key 或模型重放;明确的请求前拒绝仍可尝试其他目标。只有确认重复执行安全时才设置 retry_safe: true。

hosted 子请求与其他 Agent 请求共用 orchestration.max_active_llm_requests、provider_max_active_requests 和 model_max_active_requests 限制。如果 provider 只允许一个请求同时执行,将 provider_max_active_requests 中对应的条目设为 1。这些限制只在当前 Chord 进程内生效;多个 provider 配置或多个进程共用同一账户时,不会自动共用额度限制。

对 retry_safe: true 的工具(包括内置 web_search),瞬态限流、上游不可用和传输失败在每个目标上最多尝试 3 轮,沿用已有的 key 轮转、provider 退避与 Retry-After 等待规则。每轮可能尝试多个 key;排队和重试等待都计入 timeout_s 总预算,等待期间释放请求槽。账户额度耗尽、声明被拒绝、未观察到 hosted 调用时,不会在同一目标上开启下一轮重试,仍可尝试其他可用目标。失败提示会区分这些情况并给出对应的处理建议。

Responses 的远程 MCP 错误会作为失败返回;需要 provider 侧审批的请求会停止并提示使用本地 MCP 集成完成交互审批。此桥不会自动批准远程操作。原生消息中的引用信息、文件引用与未知输出字段会保留,完整原生输出及被截断的调用结果会保存为会话产物,工具结果提供读取引用。provider 生成的文件目前保留 container_id / file_id / 文件名,Chord 不会自动下载这些文件;配置 image_paths 可将实际返回的 base64 图片附到工具结果。

当前支持 messages 和 responses 的子请求桥。主会话沿用普通工具结果历史;Gemini、Chat Completions 的 hosted 声明和主会话原生块回放需要各自的协议适配。

顶层 memory 配置控制自动跨会话记忆抽取。读取项目中已有的 MEMORY.md 始终自动进行,不需要任何配置;这个键只决定 Chord 是否把冻结的历史会话发送给模型以生成记忆记录,并写入项目文件。记录了什么、摘要如何加载、如何审阅和删除条目见项目记忆。

memory:
enabled: true
model_pool: memory-extract
字段 默认值 说明
enabled false 为本机 + 当前项目开启自动记忆抽取。开启后,冻结的会话可能被发送给模型,并自动写入 MEMORY.md / .chord/memory/records/,这些都是普通项目文件。关闭或未设置时,Chord 不会把历史发送给模型、不写记忆文件,但仍会加载已有的 MEMORY.md。
model_pool (未设置) 用于抽取请求的 model_pools 条目名,替代主模型池。可独立选择记忆抽取的模型和推理设置。未设置时,抽取使用主模型池。两种方式都遵循对应模型的推理配置;未配置 effort 时不额外覆盖,沿用服务商默认行为。配置的池必须已在 model_pools 中定义,否则抽取会以指明缺失池名的 setup 失败停止。
  • 可写在全局配置,也可写在项目 .chord/config.yaml;项目值按与其他配置一致的规则覆盖用户级值。
  • 因为项目可以为自己开启抽取,打开一个 memory.enabled: true 的项目可能开始把该项目的历史会话上传给模型。开启时状态栏会显示 MEMORY 标识,便于看到当前状态;抽取停摆时标识变成 MEMORY-FAIL,并用一行提示说明原因。
  • 该值在启动时读取;修改配置文件需要重启正在运行的进程。

顶层 orchestration 配置用于限制单个 Chord 进程内 MainAgent/SubAgent 工作流占用的资源。它不授予工具权限,也不改变 delegation.max_children 等单个 Agent 委派限制;它控制已准入 runtime 和 LLM 请求的并发量、SubAgent 输入队列容量,以及 mailbox 在内存中的保留量。

大多数用户应保留内置默认值。只有当 provider 有严格并发配额、运行主机内存有限,或编排指标显示持续排队/拒绝时,才建议调整。

orchestration:
max_live_runtimes: 10
max_borrowed_runtimes: 1
max_bypass_runtimes: 4
max_active_llm_requests: 10
provider_max_active_requests:
openai: 6
anthropic: 4
model_max_active_requests:
openai/gpt-5.5: 3
subagent_queue_messages: 256
subagent_queue_bytes: 4194304 # 4 MiB
mailbox_memory_messages: 512
mailbox_memory_bytes: 8388608 # 8 MiB
subagent_compact_usage: 0.8
waiting_main_expiry_turns: 5
waiting_main_min_wait_sec: 300 # 5 分钟
waiting_main_max_wait_sec: 3600 # 1 小时
字段 默认值 说明
max_live_runtimes 10 正常准入的 Agent runtime 最大数量。达到上限后,后续普通 runtime 获取会等待已有槽位释放。唤醒重激活在普通容量耗尽时,还可以使用单独设限的 borrowed pool 或 bypass pool。
max_borrowed_runtimes 1 为必须继续推进的编排工作临时增加的 runtime 准入量,例如子 Agent 事件到达后恢复父 Agent。借用额度与正常 runtime 槽位分开设限。
max_bypass_runtimes 4 正常 runtime 池和 borrowed pool 都耗尽时,唤醒重激活可以使用的最大 bypass 数量;达到上限后,唤醒会被拒绝,持久化消息留在队列中等待后续处理。
max_active_llm_requests 10 进程内所有编排 Agent 的 LLM 请求总并发上限。达到上限后,符合条件的请求等待。
provider_max_active_requests 无 可选的 provider 级请求并发上限,key 如 openai。请求必须同时满足该限制和进程总限制。
model_max_active_requests 无 可选的 provider/model 级请求并发上限。匹配时忽略 @high 等 inline variant,因此 openai/gpt-5.5 覆盖该模型的所有 variant。
subagent_queue_messages 256 每个 SubAgent 的待处理输入消息上限。消息数或字节数任一达到上限时,新的入队会被拒绝,已排队消息不会被丢弃。
subagent_queue_bytes 4194304 每个 SubAgent 待处理输入的估算字节数上限。这是内存准入限制,不会溢写到磁盘 spool。
mailbox_memory_messages 512 MainAgent inbox 和按 owner 分类的 mailbox 在内存中保留的 SubAgent 消息总数上限。
mailbox_memory_bytes 8388608 上述内存 mailbox 的估算总字节数上限。超过内存预算的持久化非 progress 消息会通过磁盘 mailbox spool 引用;progress 更新可能在内存中合并或省略。
subagent_compact_usage 0.8 当 SubAgent 的估算上下文用量达到可用输入预算的这一比例时,主动压缩其上下文。默认值与 context.compaction.threshold 一致;SubAgent 使用本地 token 估算和轻量滑动窗口 checkpoint,而不是 MainAgent 的 usage 驱动压缩管线。有效值必须严格大于 0 且小于 1。
waiting_main_expiry_turns 5 SubAgent 停在 waiting_main、等待 owner 回复时允许经过的用户回合数。只有同时满足 waiting_main_min_wait_sec 后,这条回合数限制才会让任务过期;waiting_main_max_wait_sec 仍会无条件结束等待。
waiting_main_min_wait_sec 300 回合数限制可以让 waiting_main 任务过期前必须经过的最短墙钟时间,单位为秒。
waiting_main_max_wait_sec 3600 waiting_main 任务最多等待的墙钟时间,单位为秒。达到后不论用户回合数如何都会过期;实际值不会小于 waiting_main_min_wait_sec。若两者都显式配置且该最大值小于最小值,配置加载会直接失败,而不是静默钳制。
  • 这些设置既可写在全局配置,也可写在项目 .chord/config.yaml 中。项目配置中的正数标量会覆盖对应的全局值。
  • provider_max_active_requests 和 model_max_active_requests 按 key 合并:项目配置替换同名全局条目,同时保留其他全局条目。
  • 标量为零或负数不表示「无限制」,而是保留继承值或内置默认值。subagent_compact_usage 只有严格位于 (0, 1) 时才有效:越界值(含 0)会被忽略并记录警告,项目层此时继承合并后的全局值,全局未配置时回退到 0.8。与 context.compaction.threshold: 0 不同,零不会关闭 SubAgent 上下文保护。
  • provider/model map 中只有正数限制会生效。建议使用明确的 key 和正整数,不要把零当作通用的「无限制」开关。
  • 所有限制只在单个进程内生效,不会协调多个 Chord 进程之间的配额。
  • 为满足 API 配额,优先设置 provider 或 model 限制,并将 max_active_llm_requests 保留为整体安全上限。
  • max_bypass_runtimes 应保持较小的正数。它只用于普通槽位和 borrowed 容量都耗尽时,让唤醒重激活继续推进,不是普通吞吐量配额。
  • 在内存有限的主机上,逐步降低 mailbox 消息数/字节数限制。overflow 使用持久化存储,因此更低的内存限制会以更多磁盘 I/O 为代价。
  • 只有消息生产方能够处理入队拒绝,才降低 SubAgent 队列限制。这些队列不会溢写到磁盘,限制过小可能中断父子 Agent 协作。
  • max_borrowed_runtimes 应保持较小的正数。借用槽位用于解除编排推进停滞,不用于提高普通吞吐量。
  • waiting_main 任务会在「回合数限制与最短等待时间都满足」或「达到最长等待时间」时过期。owner 需要更多时间回复时,可提高回合数限制或最短等待时间;只有希望任务更久保持可恢复状态时,才提高最长等待时间。
  • 降低 subagent_compact_usage 可减少上下文溢出风险,但会更早、更频繁地压缩;提高它可减少压缩开销,但会缩小恢复余量。
  • 提高并发不一定更快:provider 限流、模型延迟、本地内存压力和 workspace lease 竞争都可能降低实际吞吐。应依据排队/拒绝指标和端到端延迟调参,而不是只看 CPU 数量。

MCP server 有两种接入方式:本地命令(stdio)或远程 HTTP 地址(url)。

mcp:
chrome-devtools:
command: "npx"
args: ["-y", "chrome-devtools-mcp@latest"]

command 是要启动的可执行文件,args 是传给它的参数,env 可追加环境变量(可选)。Chord 启动该进程后,通过 stdin/stdout 用换行分隔的 JSON-RPC 通信。

MCP server 可能暴露大量工具。通过 allowed_tools 只允许部分远端工具进入 Chord,避免把不必要的 tool schema 发送给模型:

mcp:
search:
url: https://mcp.exa.ai/mcp
allowed_tools:
- web_search_exa
- web_fetch_exa

被过滤的工具不会注册,也不会进入 LLM 工具列表。上例中 search 是用户自定义的 MCP server 名;Chord 只会注册 mcp_search_web_search_exa 和 mcp_search_web_fetch_exa。

对需要认证的远端 MCP server,可用 headers 指定随每个请求发送的额外请求头。像 Exa 这样的服务要求 x-api-key:

mcp:
exa:
url: https://mcp.exa.ai/mcp
headers:
x-api-key: "$EXA_API_KEY"

以 $ 开头的 header 值会从环境变量展开(此处即 EXA_API_KEY),避免把密钥写进配置文件;$ 值展开后为空字符串属于配置错误,那等于用空凭据认证。header 名必须是合法的 HTTP header 名,值中不能包含 CR 或 LF。headers 只对远程(url)server 生效;stdio server 不发起 HTTP 请求,为它配置 headers 会被拒绝。协议管理的请求头(Content-Type、Accept、Mcp-Session-Id)由 Chord 覆盖,不会受 headers 影响。

默认情况下,已配置的 MCP server 会自动启动,并成为默认 LLM 工具上下文的一部分。对于不是每轮对话都需要的 MCP,可设置 manual: true:启动时保持禁用,平时不连接该 server,也不把它的工具描述加入默认上下文,从而降低上下文开销;需要用到时再手动启用。

mcp:
exa:
url: https://mcp.exa.ai/mcp
manual: true
  • manual: true 时,启动后该 server 处于禁用(灰色)状态,不会主动连接。
  • 只有配置了 manual: true 的 server 才能在运行时通过 /mcp 修改状态。自动启动的 server 在 MCP 选择器中是只读的,也不会受 /mcp enable|disable 影响。
  • 运行时可用 /mcp(TUI 菜单)或带参数命令启用/禁用:
    • /mcp enable <server>
    • /mcp disable <server>
    • /mcp status
  • Agent 运行中也可以执行 /mcp enable|disable。当前正在进行的请求继续使用启动时的工具表面;下一次 LLM 请求(包括自动重试 / 恢复请求)才会应用新的执行状态。
  • 默认情况下,下一次请求会重建顶层 MCP 工具表面,因此已有提示词缓存可能无法命中。模型显式开启 compat.chat_completions.mcp_system_tools_message 或 compat.responses.mcp_additional_tools 后,Chord 会把工具声明挂在固定的对话位置,并在后续请求里原位回放。禁用 server 只会拦截执行,不删除已经发出的声明,因此前缀保持稳定。挂载形态跟随当前选中的模型:切换模型会为新模型重建顶层工具表面,新模型接受动态声明时继续沿用。会话恢复/切换或上下文压缩后则会退回顶层工具,并在本次会话运行内一直保持,因为这些边界会破坏提示词缓存复用、固定挂载位置也不再可信;之后再切换模型也不会解除,只有开启新的会话运行(比如 /new)才会重新启用动态声明。某个工具在历史里已有调用、但当前运行里还没声明过时,请求同样会退回顶层工具,免得它的声明落到自己的调用之后。回退本身不发提示;退回后的 /mcp enable|disable 要等新工具表面被某个请求装载过一次,才会再次提示缓存可能未命中。
  • manual server 的启用 / 禁用意图会随会话保存:/mcp enable 写入该意图,/mcp disable 清除它;之后 resume 该会话(包括重启后 resume)时会重新连接上次处于启用状态的 manual server。连接失败不会清除意图,server 会保持「enabled (unavailable)」状态,方便之后重试,而不是悄悄退回禁用。

自动启动的 MCP server 仍会在 TUI 启动后异步连接,但 第一次 LLM 请求会等待:每个自动启动的 server 要么连接成功,要么明确失败后才会继续发起请求,以避免工具描述不一致。

内置角色包括 builder、planner。两者都是 main 模式,因此在你自行定义至少一个 mode: subagent 角色之前,delegate 不会被注册,见下方的 mode 字段说明。可新增自定义 agent 或覆盖内置 agent。Agent 文件可放在:

  • ~/.config/chord/agents/
  • .chord/agents/

支持的文件格式:

  • .md:YAML frontmatter 加 Markdown 正文,正文作为 system prompt。
  • .yaml / .yml:普通 YAML 文档,通过 prompt 或 system_prompt 配置 system prompt。

Markdown agent 示例:

---
name: backend-coder
description: Backend developer
mode: subagent
permission:
write: ask
edit: ask
---
你是一个专注于后端开发的 Agent。

等价的 YAML agent 示例:

name: backend-coder
description: Backend developer
mode: subagent
permission:
write: ask
edit: ask
prompt: |
你是一个专注于后端开发的 Agent。

常用字段:

  • name:agent 名称。省略时使用不带扩展名的文件名;显式填写时,必须与不带扩展名的文件名一致(例如 builder.yaml 必须声明 name: builder)。同一目录内不能存在重名 agent,包括 .md、.yaml、.yml 之间的重名;项目级 agent 仍可按既有设计覆盖同名的全局 agent。
  • description:简短描述,在可委派给该 agent 时展示给 main agent。选人意图写在这里;Chord 不再单独提供 preferred tasks / write mode 这类标注。角色能不能写文件由 permission 决定,Delegate 会在每个可选项上标 empty_scope=allowed 或 non_empty_scope=required。
  • mode:main 表示 MainAgent 角色,subagent 表示 SubAgent。为空或其他值时按 main 处理;sub_agent 和 sub 也可作为 SubAgent 别名。只有委派角色能看到至少一个 subagent 角色,delegate 工具才会注册;因此没有任何 subagent 定义的配置根本不存在委派面,这通常就是 delegate 看起来消失的原因。
  • model_pools:可选的有序池名列表,用于限制该 agent 可使用的池。池定义位于 config.yaml 顶层 model_pools;省略时,该 agent 可使用所有顶层池并按池名排序。openai/gpt-5.5@high 这类 inline variant 写在池定义中。
  • variant:model ref 未写 @variant 时的默认 variant。
  • permission:该 agent 的逐工具权限策略。权限直接保存在 agent 配置文件中;确认弹窗里选择「记住规则」时,project 会更新当前项目的 .chord/agents/<role>.yaml,global 会更新用户配置目录的 agents/<role>.yaml(默认 ~/.config/chord/agents/<role>.yaml),不会写入单独的 permissions 文件夹。部分编排工具有特殊语义(delegate 的 pattern 会匹配 agent_type,并联动控制委派工作相关能力,如 cancel;handoff 和 done 的 allow / ask 都表示工作流可用,并由 Chord 自己的确认 gate 控制关键节点)。依赖精细控制工具规则前,请先阅读权限与安全。
  • mcp:作用域限定在该 agent 的增量、自动启动 MCP 配置。Agent MCP 不能与最终生效的全局/项目 mcp server 重名,否则启动时报错;也不能设置 manual: true,因为运行时 MCP 控制只管理顶层 server,如需手动启停请改在项目/全局配置中声明。要继承顶层 server,请删除 agent 中的重复项;要使用独立私有 server,请改名;要为整个项目替换顶层 server,请在 .chord/config.yaml 中覆盖。不同 agent 可以使用相同的私有 server 名称而互不共享连接,同一 agent 定义的多个实例则会复用连接。
  • delegation:本 agent 定义的委派限制;超过上限或使用负数会导致配置报错:
    • max_children:该 agent 同一时刻可拥有的直接活跃子任务数上限。默认 10,上限 64。
    • max_depth:嵌套委派可达到的深度。它按被委派 worker 自己的定义生效:一个 SubAgent 能否再往下委派,看的是它自己声明的 delegation.max_depth 和当前所处深度,而不是父角色或根角色的设置;根角色把 max_depth 设为 1,挡不住一个声明 max_depth: 8 的子角色继续嵌套。默认 1(第一层 SubAgent 要往下委派,必须由它自己的定义提高该值),上限 8。
    • child_join:SubAgent 委派出的子任务是否并入它自己的任务生命周期(默认 true)。开启时,owner 不能在有已加入的子任务仍在运行时完成:complete 会被延迟,直到这些子任务结束或被显式停止;owner 若被取消或失败,也会连带取消已加入的子任务。关闭时,owner 可以提前收工,仍在运行中的子任务会与它解绑并转由 main agent 继续托管,而不是被连带取消。该选项只影响嵌套委派:main agent 直接委派出的子任务从不并入,因为 main 本身不是任务。
  • prompt / system_prompt:纯 YAML agent 文件中的 system prompt。设置其中任一个会整块替换该角色本来会获得的内置 prompt 块。
  • prompt_preset:按能力而非角色名选择内置角色 prompt 块,可选值为 planning 和 none。planning 会注入内置规划块(计划文档命名与格式、直接回答与产出计划的判断、handoff 时序、计划质量要求),同时抑制 bug triage 块,后者与规划工作流自带的调查提纲重复。none 表示不注入任何内置块。省略该字段时,无论角色叫什么都不获得内置块,角色名不参与选择,因此自定义的 planner 角色需要显式声明 prompt_preset: planning 才能保留规划块。填写未知值会导致配置报错。
  • prompt_append:追加在最终生效的角色 prompt 之后,即 preset 块之后,或角色用 prompt / system_prompt 替换了基础块时追加在其后。用它可以在不接管整块维护责任的前提下补充项目约定,同时保留 preset 中随角色可见工具自适应的措辞。

复用内置规划块的自定义角色:

name: architect
description: 架构规划角色
mode: main
prompt_preset: planning
prompt_append: |
每份计划文档都要引用对应的 ADR 编号。
permission:
"*": deny
read: allow
grep: allow
glob: allow
write:
.chord/plans/*: allow
handoff: allow

示例:

name: builder
mode: main
model_pools: [default]
permission:
"*": deny
read: allow
view_image: allow
grep: allow
glob: allow
web_fetch:
"localhost:8000": ask
shell: allow
edit: ask
write: ask

在这样的 allowlist 里,开头的 "*": deny 覆盖了所有你没列出的工具,因此角色需要什么就必须写什么。有两个例外值得知道,否则容易被误认为功能坏了:

  • compact_context 和 done 不受该通配规则约束。让它们各自变得可用的那个开关(前者是 context.compaction.model_driven,后者是开启 loop)本身就是授权,因此这个角色不必列出它们也能使用模型驱动压缩和 loop 模式。确实想收回某个工具时,指名写出来即可(例如 done: deny)。详见权限与安全。
  • 其余工具都按常规规则处理。todo_write 和 question 在这里就是普通工具:不列出它们,意味着模型不再维护 TODO 列表,并改用纯文本向用户提问而不是结构化弹窗。两者都会平滑降级,按需添加即可。

长会话的上下文处理涵盖上下文压缩(Compaction)(调用 LLM 生成摘要并改写会话历史)和上下文剪裁(Reduction)(请求前剪裁过时工具输出),两者都通过顶层 context: 配置,详见独立页面:上下文管理。

edit、apply_patch 或 write 修改文件后,Chord 可以把语言诊断追加到工具结果里,让模型立刻看到编译或 lint 问题。这由 diagnostics 配置控制,默认对 Python 启用(LSP 语义后端 + Ruff quick 回退)。设 diagnostics.enabled: false 可整体关闭这条流水线。

Chord 的原生文件工具会在同步 textDocument 前向匹配的 LSP 服务发送 workspace/didChangeWatchedFiles 文件事件:write 新建文件发送 Created,覆盖已有文件和 edit / apply_patch 发送 Changed,delete 成功删除文件发送 Deleted。这让 Pyright、TypeScript、gopls、rust-analyzer 等服务更容易及时刷新项目图,减少「新建模块已存在但 import 仍报 unresolved」的暂态误报。诊断仍会在文件工具结果中即时返回,便于模型判断问题是否由本次改动引入;但通过 shell 或外部程序创建/删除的文件目前不会由 Chord 的原生文件工具自动上报为文件系统 watcher 事件。

Python 使用两个后端:

  • diagnostics.python.semantic_backend:主 LSP 服务(默认 pyright)。其 server 字段必须与 lsp 下的某个 server key 一致,语言服务器才真正配置生效。
  • diagnostics.python.quick_backend:一次性回退命令(默认 ruff check),用于大文件,或语义后端不可用时。

diagnostics.python.large_file.{line_threshold, byte_threshold, strategy} 决定文件多大时改用 quick backend 而非语义后端;run_semantic_when_quick_unavailable: true 会在 quick backend 缺失时,对大文件也强制跑语义后端。Ruff quick diagnostics 不更新 LSP 侧边栏,只出现在 edit、apply_patch 或 write 结果中,并提示完整语义诊断已跳过。

推荐 Python 配置骨架:

lsp:
pyright:
command: pyright-langserver
args: ["--stdio"]
file_types: [".py", ".pyi"]
diagnostics:
python:
semantic_backend:
server: pyright
quick_backend:
type: command
command: ruff

diagnostics.python.output.{max_near_diagnostics, max_outside_diagnostics, max_total_diagnostics, near_range_before_lines, near_range_after_lines} 控制追加诊断文本的长度,并按错误/警告优先于 info/hint 的顺序展示。完整字段表见配置字段速查表。

工具结果里追加的诊断包含编辑文件自身的问题,以及与任一编辑文件同目录的其他文件缓存问题(Go 按目录编译包,workspace 诊断会覆盖被诊断包里的所有文件)。同一个其他文件诊断每个会话只附加一次:该诊断从服务器发布集合中消失后,问题再次出现才会重新报告。

后续编辑也不会重复:已经告知过模型的问题再复述一遍只是浪费上下文,因此仍然存在的诊断保持抑制,只报告发生变化的部分。而被修复掉的问题(被其他 agent 改好、被复制覆盖、或被 git checkout 还原)不会继续从缓存里报出来:文件一旦与诊断计算时的内容不再一致,缓存诊断就先被扣下;等服务器发布的集合里不再包含它,就彻底丢弃。

恢复会话时抑制状态不会被清空,而是从恢复的对话记录里还原已渲染过的诊断,因此 --continue 不会重复播报同一段对话中已经可见的问题。

文件自服务器上次发布诊断以来已在磁盘上变化(比如被其他编辑器或进程修好)时,Chord 会先跳过其缓存诊断;等 Chord 同步该文件并收到 fresh diagnostics 后才重新采用,避免把过期结果当成当前问题。

Terminal window
# 用代表模型冒烟测试所有 provider
chord doctor models
# 测试单个 provider 的代表模型
chord doctor models --provider openai
# 测试精确模型或 variant
chord doctor models --model openai/gpt-5.5@high
chord doctor models --provider openai --model gpt-5.5@high
# 独立审计模型池中的每个条目
chord doctor models --pool thinking

该命令适合做认证、endpoint、transport、模型存在性以及 variant tuning 的冒烟测试。它读取的配置视图与正常运行时一致:会先加载全局配置,再叠加项目级 provider / proxy / model 覆盖。Pool 诊断会逐项独立请求,不走正常 fallback 链。

下面是 config.yaml 的全部顶层 key(同时适用于全局 ~/.config/chord/config.yaml 和项目级 .chord/config.yaml)。除特别注明外,所有 key 均可选。

Key 类型 默认值 适用层级 简述
providers map[name]Provider — global / project 各 provider 的配置(type、api_url、preset、key_rotation、key_order、models、compress)。见 最小 provider 配置。
model_templates map[name]YAML 空 global / project 仅用于 YAML anchor 命名空间;条目可通过 alias 复用,不会直接作为运行时模型定义。
model_pools map[name][]ref — global / project 可复用的命名模型池,元素为完整 provider/model[@variant] ref。见 模型池。
thinking_translation object 关闭(max_chars: 1000) global / project 可选的 thinking / reasoning 卡片附加翻译预览。需要 target_language 和 model_pool;失败只跳过受影响的 thinking block。
context object 见下文 global / project compaction(上下文压缩)和 reduction(上下文剪裁)两项配置。见上下文管理。
diagnostics object 启用(Python LSP + Ruff 回退) global / project edit、apply_patch 或 write 完成后追加的诊断信息。diagnostics.python.semantic_backend 是主 LSP 服务(默认 pyright);diagnostics.python.quick_backend 是一次性回退命令(默认 ruff check)。diagnostics.python.large_file.{line_threshold, byte_threshold, strategy} 决定大文件何时走 quick backend;run_semantic_when_quick_unavailable: true 在 quick backend 不可用时仍强制跑语义诊断。diagnostics.python.output.{max_near_diagnostics, max_outside_diagnostics, max_total_diagnostics, near_range_before_lines, near_range_after_lines} 控制追加文本的长度和剪裁窗口。诊断按严重级别优先展示(错误/警告优先,仍有名额时再显示 info/hint)。设 diagnostics.enabled: false 可整体关闭。
skills object 空 global / project paths: [...] —— 在默认目录外追加 skill 目录。
confirm_timeout int(秒) 0(不超时) global / project TUI 确认浮层超时;0 表示永远等。
question_timeout int(秒) 0(不超时) global / project Question 工具在 TUI 和 headless 里的等待超时;0 表示永远等。倒计时覆盖整段等待,包括排在别的对话框后面的时间;一批问题里每个问题各自计时。到期后问题按 no_response 关闭,Chord 不会自动采用任何答案。
diff object {inline_max_columns: 200} global / project TUI diff 渲染。inline_max_columns 限制单行 inline diff 宽度。
desktop_notification bool false global / project 启用本地 TUI 终端通知;Chord 按终端自动选择 OSC 9 或 OSC 777,并在每次通知时附一声终端铃声(BEL)(不支持的终端通常会忽略该序列;见平台说明)。
desktop_notification_foreground bool true global / project TUI 聚焦时是否发送本地终端通知(转义序列和铃声一起);设为 false 后仅在终端失焦时通知。
prevent_sleep bool false global / project agent 活动时阻止 macOS idle sleep。仅 macOS 生效,其他平台 no-op。
keymap map[action][]key 见 快捷键:Action 名速查 global / project 覆盖键位绑定。Action 名采用 lower snake_case。
commands map[/cmd]text 空 global / project 自定义 slash 命令;"/cmd" → 作为用户消息发送的文本。见 扩展与定制:自定义 slash 命令。
ime_switch_target string 空 global / project 进 Normal 模式时传给 im-select / im-select.exe 的 IM 标识。
log_level string info global / project debug / info / warn / error。debug 输出较多。
paths object XDG 默认值 仅 global state_dir、cache_dir、sessions_dir、logs_dir。会被 CLI flag 与 CHORD_* 环境变量覆盖。
maintenance object 关闭 仅 global size_check_on_startup、warn_state_bytes、warn_cache_bytes。
lsp map[name]Server 空 global / project 各 language server 的配置。见 扩展与定制:LSP。
mcp map[name]MCP 空 global / project / agent 各 MCP 服务器的配置。见 MCP。
hooks object 空 global / project / agent 按触发点分组的 hooks。见 Hooks。
max_output_tokens int 64000 global / project 全局输出 token 上限。实际请求还会受各模型 limit.output 限制;reasoning 请求同样遵守该上限。
stream_retry_rounds int 0(重试直到成功/取消) global / project 公开 LLM 流式请求的整轮重试硬上限。0 表示一直重试,直到成功、取消或终态失败。
proxy string 空(用环境变量或直连) global / project 全局代理 URL。可通过 web_fetch.proxy 单独覆盖。
web_fetch object 空 global / project user_agent、proxy(nil 继承全局;空字符串 = 显式直连)。见 WebFetch。
worktree object 空 global / project branch_prefix 决定 worktree 分支名前缀,root 决定 checkout 建在哪里(相对路径以仓库根为基准;默认仍在仓库之外的 state 目录下)。见 Worktree 用法。

Chord 会把当前 Chord session id 自动传给 OpenAI 系 provider,作为缓存 / 路由亲和元数据:OpenAI Responses 请求会包含 prompt_cache_key,OpenAI Chat Completions / Responses HTTP 请求会在有 session id 时包含 X-Session-Id 和 session-id header。该 key 按 client 而非 provider 隔离:main agent 用当前 Chord session id,每个 SubAgent 另行派生 <session>:sub:<instanceID> 形式的 key,因此一个 agent 的请求不会继承另一个的缓存身份。这些字段不能手动配置,会随当前 Chord session 自动切换 / 恢复。

Anthropic prompt caching 由 cache_control block 驱动;Chord 还会自动发送 JSON 格式的 metadata.user_id,其中包含稳定匿名的 device_id,以及由本地 / provider 身份派生出的稳定路由 session_id。这些 Anthropic metadata 字段不能手动配置。在 explicit 模式(Anthropic 模型默认)下,Chord 按优先级放置最多 4 个 cache_control 断点:最后一个 system block、冻结的已剪裁前缀边界(当渐进式剪裁已冻结稳定前缀时)、最新的持久化消息、最后一条 assistant 消息,使长 agent loop 能复用冻结的历史前缀,而不是每轮重新写入移动的尾部。最新断点会刻意跳过 request-scoped overlay(追加在对话尾部的运行时提示),因为这些内容在下一次请求中就不存在了,写在它们之后的缓存条目永远不可能被读回。

对于 Anthropic 模型,prompt_cache.ttl 接受 5m(省略时的默认值)和 1h,且在 auto 与 explicit 两种模式下都会应用到 Chord 放置的每一个断点:

providers:
anthropic:
models:
claude-sonnet-4-5:
prompt_cache:
ttl: 1h

Gemini 在 Chord 当前的 generateContent transport 中没有简单的逐请求 session-id cache key;它的缓存信号来自 provider 专用 cached-content API / usage 字段,而不是 Chord session id header。

字段 类型 说明
type string messages / chat-completions / responses / generate-content。省略时按 api_url 或 preset 自动推断。
api_url string 接口地址。Chord 根据 URL path 自动识别 provider type,忽略 query string 和 fragment。Gemini 用 /models 基础路径,Chord 自动附加 /{model}:streamGenerateContent?alt=sse。Azure Responses 的 ?api-version=... 是可选项,可用于固定特定 API 版本。
preset string 可选 codex(OpenAI Codex / ChatGPT OAuth)。Azure OpenAI Responses 使用普通 type: responses provider,配合 auth_scheme: api-key、store: true,并在 compat.request_overrides.headers 中将 Codex 身份 header 置为 null。
trust_http_400 bool 是否把 HTTP 400 视为终止性请求错误。preset: codex 默认 true;聚合/代理网关默认 false,因为常把上游过载包装成 400。
retry_after_max_s int 采纳 Retry-After 头的最长等待秒数(1-86400)。该头始终作为 key 冷却时长生效,优先于 retry_backoff/retry_delay_ms;本参数只限制单次提示最长能占用 key 多久。preset: codex 默认 86400;第三方网关可能回显任意值,默认 60。
key_rotation string on_failure(默认)/ per_request。控制何时重新选择 credential / API key。
key_order string sequential(非 Codex 默认)/ random / smart(仅 Codex)。控制在候选 key 中如何选择。
retry_backoff string exponential(默认)/ fixed / none。控制完整重试轮之间由 Chord 生成的等待;显式设置后也控制普通 HTTP 429 的 key 冷却,并替换这类响应的 Retry-After。已确认的配额重置与凭据硬状态仍然优先。
retry_delay_ms int 轮间退避和普通 429 冷却的基准值或固定值,单位毫秒,可取 0 到 60000;0 / 省略默认 1000ms。即使省略 retry_backoff,只要写出该字段(包括显式 0)就算覆盖。none 模式下忽略。超出范围的值会记录日志并回退默认值,不会中断启动。
compress string 上游请求体的压缩编码:gzip 或 zstd;不设即关闭。只在压缩能缩小体积时生效。旧的布尔写法 compress: true 已删除——会被忽略并由 chord doctor config 报告(改成 compress: gzip 即可)。
response_header_timeout int 从开始该 provider 的流式 HTTP 请求到收到响应头的超时,单位秒,包括连接建立与请求体上传。0 / 省略表示使用内置默认值;健康流由 stream_idle_timeout 约束,而不是总请求计时器。
stream_idle_timeout int 该 provider 的流式空闲超时,单位秒。0 / 省略表示使用内置 SSE/WebSocket idle 默认值。
stream_total_timeout int 单条流的墙钟上限,单位秒,也包括 Codex Responses WebSocket 读等待。0 / 省略表示不设上限——持续产出数据的流不会仅因耗时被截断。
websocket_handshake_timeout int Responses WebSocket 握手超时,单位秒。0 / 省略表示使用内置默认值。
parallel_tool_calls bool true — provider 级 Responses / Chat Completions 工具并行默认值;模型和变体配置会覆盖它。
compat.responses.* object 协议默认值 — provider 级 Responses 可选字段开关:send_store、send_reasoning_include、send_tool_choice、send_prompt_cache_key、send_max_output_tokens、mcp_additional_tools。
compat.responses.mcp_additional_tools bool false — 把运行时 manual MCP schema 挂成固定位置的 input[type="additional_tools"] item,不改写顶层 tools。只为已确认接受该 item 的 Responses endpoint / 模型开启。挂载形态跟随当前选中的目标;请求最终落到不接受该 item 的池成员时,Chord 会把声明并入该请求的顶层 tools 数组。
compat.hosted_tools list (空)— 允许该 provider 的模型提供的 hosted 工具名列表。每次调用另发一条请求,在那里声明该工具按 provider 类型的 wire 声明,Chord 把 provider 返回的结果作为普通工具结果返回;主对话请求不声明该工具。只为确认支持该声明的端点启用:端点拒绝声明时调用会带着端点返回的原因失败,端点静默忽略时错误会提示检查这个列表。条目形状见 Hosted tools。
compat.apply_patch.enabled bool 三态 — 省略时按模型名推断。true 保留 apply_patch(同时隐藏 edit、write、delete);false 退回 edit,write/delete 重新可见。gpt-5 及之后家族(gpt-5、gpt-5-mini、gpt-5-nano、gpt-5-codex、任意 gpt-5.* 名称,以及 gpt-6-astra 等更高的主版本)和 codex-auto-review 默认 true;gpt-oss-*、gpt-3.5、gpt-4/4o、o 系列及非 OpenAI 模型默认 false。
compat.apply_patch.freeform bool 三态 — 省略时按模型名和 wire 类型推断。true 把 apply_patch 作为 freeform custom tool 发送(type: "custom",随请求带上 grammar);false 按 JSON function tool 发送。gpt-5 及之后家族名称和 codex-auto-review 在 Responses 端点上默认 true;非 Responses wire 一律默认 false(没有 custom tool 类型)。接受 Responses 但拒绝 custom tool 的主机没有内置例外:请在那里设置 false;只有确实支持 custom tool 的网关才设 true。
compat.chat_completions.send_stream_options bool true — 对拒绝 stream_options 的网关设为 false;此时流式 token usage 不再可用。
compat.chat_completions.infer_finish_reason bool false — 对结束流时不发 finish_reason 的兼容网关,自动推断为正常的 stop / tool_calls 完成;不开启时这类流会被当成中断处理。
compat.chat_completions.requires_tool_result_name bool false — 对要求 tool result 消息同时携带 name 和 tool_call_id 的网关,回填配对的工具名。
compat.chat_completions.requires_assistant_after_tool_result bool false — 对不接受 tool result 后直接跟 user 消息的网关,在中间插入一条合成 assistant 消息。
compat.chat_completions.mcp_system_tools_message bool false — 把运行时 manual MCP schema 挂成固定位置的 role: system 消息,消息只带 tools、不带 content,不改写顶层 tools。只为已确认接受 Kimi 兼容动态工具形态的模型开启。挂载形态跟随当前选中的目标;请求最终落到不接受该形态的池成员时,Chord 会把声明并入该请求的顶层 tools 数组。
compat.chat_completions.keep_reasoning_effort bool false — 本轮回放的 assistant tool-call 消息没有 reasoning_content 时,仍保留 reasoning_effort 与 reasoning 请求覆盖项。默认行为下 Chord 会把缺少 reasoning content 判定为该后端无法回放 reasoning,在本回合后续请求中剥离这些控制项;对接受 reasoning 控制、但没有 reasoning 回放契约的后端(例如走 Chat Completions 线路的 Grok)开启。它只保留请求侧控制项,不会为校验回放历史的后端(带 tools 的 DeepSeek、Kimi K3、Qwen preserve_thinking)补上 reasoning content。
compat.chat_completions.native_thinking string 端点是把 chat/completions 转成模型原生 API 的网关时,用哪个请求形状把该模型的 thinking 配置交上去。不配时只有 DeepSeek 路由会自动选到 thinking:{type} 形状:模型 ID 是 DeepSeek API 模型名,或者配了 compat.reasoning_continuity.contract: deepseek 的模型(contract: none 会取消按名字的自动识别)。其他模型必须显式配置选择器。可选值:gemini(extra_body.google.thinking_config)、gemini-3(同一形状并启用 Gemini 3 缺失签名修复)、anthropic(thinking:{type,budget_tokens})、thinking(DeepSeek、GLM、Kimi K2.x、Doubao 使用的原生 thinking:{type} 对象)、qwen(enable_thinking);claude、deepseek、glm、kimi、doubao 等家族名作为等价别名。off(别名 none)用于拒绝未知请求体字段的端点,关闭转换。没有配置 thinking 块的模型不会发送该字段,DeepSeek 路由例外:它默认开启 thinking;显式配置 thinking.type: disabled 或 reasoning.effort: none 会关闭思考,不再发送 effort(见 compat.reasoning_continuity.contract)。网关后面的模型是不是 Gemini 或 Claude,Chord 也只看这个选择器:没配时不会把 Gemini 的 thought signature 写回请求,Gemini 3 会拒绝每次工具调用之后的请求(HTTP 400),所以网关后面的每个 Gemini 3 模型都要配 gemini-3。chord doctor config 会对这类模型给出警告。显式配置的选择器只管请求形状,并且总是优先于 DeepSeek 的默认形状;推理契约照常生效,off 也不会关掉它。见走 Chat Completions 网关的 thinking。
compat.usage.input_includes_cache_read bool 协议默认值 — 覆盖 provider 顶层 input 是否已包含 cache read。默认:Messages 为 false;Chat Completions / Responses / Generate Content 为 true。
compat.usage.input_includes_cache_write bool 协议默认值 — 覆盖 provider 顶层 input 是否已包含 cache write/cache creation。默认:Chat Completions / Responses 为 true;Messages / Generate Content 为 false。
models map model id → 模型配置。
字段 类型 说明
limit.context int 已知时表示总请求窗口上限;未配置 limit.input 时,Chord 按总窗口减去模型声明的 limit.output 推导输入预算(模型未声明输出上限时回退到 max_output_tokens 默认值)。
limit.input int provider 单独公布输入上限时填写。Chord 用它判断何时在 prompt 过大前压缩或恢复重试。
limit.output int 输出 token 上限;运行时还会受 max_output_tokens 限制。
compaction object 该模型的自定义压缩参数:compaction.threshold(自动压缩使用率阈值;0 对该模型禁用)与 compaction.reminder(压力提醒线;缺省时按 threshold 派生,-1 只关闭提醒)。未设字段继承全局 context.compaction.*。越界值会被拒绝并回退继承全局值。推导方式与调参建议见上下文压缩。
reasoning object OpenAI reasoning 选项。reasoning.effort 不做本地白名单校验,provider 支持的任意取值(如 GLM 的 max / minimal / none)都原样到达上游;Responses 线路发送前会额外规范化空格和大小写(留空 = 不发送,使用 provider/model 默认)。Responses 的 reasoning.summary 支持 auto / concise / detailed / none;启用 reasoning 时留空默认使用 auto,配置 none 可明确关闭。
text.verbosity string 可选的 OpenAI 文本详细程度提示,支持的模型生效;除非明确要覆盖为 low / medium / high,否则建议留空使用 provider/model 默认值。
thinking object 扩展思考选项。Messages:type: adaptive 不携带 token 预算,与 thinking.effort 搭配,Chord 会把它发送为 output_config.effort;Claude 的 type: enabled 必须配置 thinking.budget;DeepSeek 则使用 type: enabled 与 thinking.effort,不需要预算;display 仅对 enabled / adaptive 生效。Gemini:thinking.level / thinking.budget / thinking.include_thoughts 会映射进生成请求(见 Google Gemini)。
compat.reasoning_continuity.mode string 可选的连续性覆盖项。Chat Completions 模型需要原样回放 assistant reasoning_content,并接收其他 wire 的可移植可见 reasoning 时使用 openai_visible;Responses 目标采用同类连续性契约时,这个模式也会启用缺失 reasoning_text 的兜底。只有已验证的 Messages 兼容模型需要回放或接收可见无签名 thinking 时才使用 anthropic_unsigned;模型级 none 可关闭 provider 级默认值。DeepSeek Chat/Messages 目标会忽略此字段(包括 none):其 reasoning 契约固定了模式(Chat 为 openai_visible,Messages 为 anthropic_unsigned)。
compat.reasoning_continuity.contract string 声明端点专用请求契约,覆盖按模型名推断的结果。deepseek 在 Chat Completions 与 Messages 线路上启用 DeepSeek 工具历史回传规则和请求调优(Chat Completions 上没配 native_thinking 时还会选用 thinking:{type} 形状),模型 ID 无法标识后端的别名需要它;gemini-3 在 Gemini 原生端点上启用缺失 thought signature 的修复(Chat Completions 网关改用 native_thinking: gemini-3);none 让路由退出按模型名推断出的契约(包括这个形状),比如模型 ID 是 DeepSeek API 模型名、后端却不是 DeepSeek 的第三方路由,Chat Completions 与 Messages 线路都适用。模型 ID 是 DeepSeek API 模型名时会自动选到 deepseek;Gemini 原生端点上模型 ID 最后一段以 gemini-3 开头时会自动选到 gemini-3;其他端点留空即沿用通用连续性逻辑。未知取值会被配置加载器拒绝。
compat.reasoning_continuity.reasoning_replay string 已完成轮次的 reasoning 回放多少。DeepSeek Chat/Messages 固定完整回放,不受此窗口限制。current_turn(默认)只保留最后一条 user 消息之后的 reasoning;all 原样回放已完成轮次,用于契约要求完整 assistant 历史的后端(Kimi K3 / keep: all、Qwen preserve_thinking、GLM clear_thinking: false、小米 MiMo);none 连当前轮一起剥离,只用于确认过能接受的端点。
compat.forced_tool_choice.suppress_in_thinking bool reasoning/thinking 启用时,把 loop 强制的 tool_choice: required 降级为后端默认选择。适用于拒绝 thinking 模式下 forced tool choice 的 OpenAI 兼容端点。
compat.forced_tool_choice.auto_only bool 无条件把任何非 auto 的 tool_choice 降级为后端默认选择。适用于只支持 tool_choice: "auto" 的后端。Chat Completions / Messages / Gemini 省略该字段;Responses 仍发 "auto",除非 compat.responses.send_tool_choice 为 false。
compat.request_overrides.body object Chord 构造完协议请求后应用的递归 JSON patch。null 删除字段。
compat.request_overrides.rename_body_fields map 重命名最终 JSON 字段,同时保留 Chord 动态计算的值。目标值为 null 时删除源字段。
compat.request_overrides.headers map 设置最终请求 header。值为 null 时删除该 header。
compat.chat_completions.mcp_system_tools_message bool 模型级覆盖项;provider 默认值见上表。
compat.chat_completions.keep_reasoning_effort bool 模型级覆盖项;provider 默认值见上表。
compat.chat_completions.native_thinking string 模型级覆盖项;provider 默认值见上表。
compat.responses.mcp_additional_tools bool 模型级覆盖项;provider 默认值见上表。
compat.hosted_tools list 模型级列表,替换上表描述的 provider 默认值。
compat.apply_patch.enabled bool 模型级覆盖项;provider 默认值见上表。
compat.apply_patch.freeform bool 模型级覆盖项;provider 默认值见上表。
variants map 命名参数预设。引用方式:provider/model@variant。
modalities.input array text / image / pdf 的子集。默认仅 [text];支持时需显式声明 image / pdf。
supported_service_tiers 列表 provider-level 默认值或 model-level 覆盖值,用于声明可接收的非 standard tier,例如 [fast, slow] 或 [fast]。省略时使用 preset 默认值。

服务层和 prompt cache 是 provider-specific 的:OpenAI 支持 priority/flex 风格的 tiering 以及 prompt_cache_key / prompt_cache_retention;Anthropic 支持 cache_control,并提供 5 分钟和 1 小时 TTL;Gemini 则使用它自己的路由 / thinking / cached-content 机制。Chord 会把用户侧的 tier 映射到当前 provider 能支持的最接近行为,而不是强行统一成同一种 wire 格式。

若兼容网关的 usage 字段与它声明的协议不同,应显式配置语义。例如某个 Responses 兼容网关把普通 input、cache read、cache write 三个桶分开返回:

compat:
usage:
input_includes_cache_read: false
input_includes_cache_write: false

反过来,若某个 Messages 兼容网关按包含式语义上报(input_tokens 是包含缓存命中的总输入,cache_read_input_tokens 只是其中的命中子集),就需要设成 true,否则 Chord 会把 cache read 重复计一次,导致缓存命中率被低估:

compat:
usage:
input_includes_cache_read: true

OpenAI 的 reasoning item 还可能通过 reasoning.encrypted_content 返回,用于无状态续传。这个字段是加密后的续传载荷,不适合直接在 UI 里展示;如果有可读摘要,应优先展示摘要而不是 encrypted payload。