docs(llm-pi-ai): state the composition-base assumption for the dict-merge limitation

Maintainer ruling on the review's merge-semantics warning: per-model
reasoning fields belong to the settings document, not cordis.yml entry
config (the shipped composition mounts the adapter dormant), so the
recursive-merge delete gap is a documented posture rather than a tracked
fix; the Known Limitations entry now states the assumption instead of
pointing at the closed #2003.
This commit is contained in:
Yichen Jiang
2026-08-08 11:06:29 +08:00
parent e5d0089d5b
commit c480796db4
3 changed files with 4 additions and 4 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/llm/llm-pi-ai/README.md
README.md: c5ebca23ccb4162b65a6e18132970eaf01a50b84
README.zh.md: f916462bca915bea37c59f7a33a08e1dcc18c4c7
README.md: eb67ce889193aadbd694d7aae53e47c7d20703be
README.zh.md: b4b3e3c208702fa10e5f434a70608702d0576fbd

View File

@@ -186,7 +186,7 @@ Recorded response content appends to the next request and does not invalidate it
## Known Limitations and Deferred Work
- **Settings can add or override routes, not remove composition routes** — the user layer merges over the composition `base`, so deleting a `cordis.yml`-provided provider is a composition change; `replace` on the namespace only resets the user layer.
- **The layered merge has no delete for dict keys** — the settings seam merges the composition `base` and the user layer per key, recursively, so a `reasoningEfforts` level, `modelOverrides` entry, or `compat` field the base declares cannot be removed by the user layer, only overridden — and for `reasoningEfforts` absence *is* the meaning ("not offered"), so a base-declared level stays offered. A `models` list is an array and replaces wholesale, which is the workaround: declare the model there instead. Atomic-leaf merge semantics at the settings seam are tracked in [#2003](https://github.com/deepseek-harness/deepseek-harness/issues/2003).
- **The layered merge has no delete for dict keys** — the settings seam merges the composition `base` and the user layer per key, recursively, so a `reasoningEfforts` level, `modelOverrides` entry, or `compat` field the base declares cannot be removed by the user layer, only overridden — and for `reasoningEfforts` absence *is* the meaning ("not offered"), so a base-declared level stays offered. This only triggers when a `cordis.yml` entry config declares per-model reasoning fields for the same model the user layer edits; the supported posture is to leave those to the settings document (the shipped composition mounts the adapter dormant), and a `models` list is an array replacing wholesale, which is the in-band escape.
- **`headers` can carry a credential the redactor never sees** — the profile's `headers` dict is plain strings, so `Authorization` or `api-key` set there is returned verbatim by a redacted `describe()` and rendered by any configuration UI. Store credentials as `apiKeyEnv` references; making the dict write-only is deferred with the rest of the [wire-boundary work](../llm/README.md#known-limitations-and-deferred-work).
- **A route's catalog never refreshes itself** — the catalog is whatever `settings.yaml` says, so a model list is only as current as its last edit. Nothing here queries a provider for the models it serves; a route gains a model when someone writes one.
- **One wire protocol per route** — `api` applies to the whole route, so a mixed-protocol catalog route (an OpenAI-style catalog spanning Responses and Chat Completions) cannot host a model of the other protocol, and adding a model such a route does not describe requires naming `api` and moving every model onto it. Splitting the provider across two route keys is the workaround.

View File

@@ -186,7 +186,7 @@ pi-ai 事件会变为 harness 推理、文本、工具调用、usage 与 finish
## 已知限制与暂缓事项
- **settings 能新增或覆盖路由,但不能移除组合路由**:用户层合并在组合 `base` 之上,因此删除 `cordis.yml` 提供的提供方属于组合变更;对该 namespace 执行 `replace` 只会重置用户层。
- **分层合并对字典键没有删除语义**settings seam 把组合 `base` 与用户层按键递归合并,因此 base 声明的某个 `reasoningEfforts` 档位、`modelOverrides` 条目或 `compat` 字段,用户层只能覆盖、无法移除——而 `reasoningEfforts` 里缺席本身*就是*语义(「不提供」),于是 base 声明过的档位会一直被提供。`models` 列表是数组、整体替换这也是规避写法把该模型改到那里声明。settings seam 的原子叶合并语义在 [#2003](https://github.com/deepseek-harness/deepseek-harness/issues/2003) 跟进
- **分层合并对字典键没有删除语义**settings seam 把组合 `base` 与用户层按键递归合并,因此 base 声明的某个 `reasoningEfforts` 档位、`modelOverrides` 条目或 `compat` 字段,用户层只能覆盖、无法移除——而 `reasoningEfforts` 里缺席本身*就是*语义(「不提供」),于是 base 声明过的档位会一直被提供。只有 `cordis.yml` entry config 为用户层正在编辑的同一模型声明了按模型推理字段才会触发;受支持的姿态是把这些字段留给 settings 文档shipped 组合以休眠方式挂载该适配器),且 `models` 列表是数组、整体替换,这是体制内的出口
- **`headers` 可能承载一条脱敏器看不见的凭据**profile 的 `headers` 是纯字符串字典,因此设在其中的 `Authorization``api-key` 会被脱敏后的 `describe()` 原样返回,并被任何配置 UI 渲染出来。请把凭据存为 `apiKeyEnv` 引用;把该字典整体改为只写与其余[协议边界工作](../llm/README.md#known-limitations-and-deferred-work)一并暂缓。
- **路由的 catalog 不会自我刷新**catalog 就是 `settings.yaml` 所写的内容,因此模型列表的新鲜度只到最近一次编辑为止。这里没有任何环节会去问提供方它服务哪些模型;路由要多一个模型,得有人写进去。
- **每条路由只有一种协议格式**`api` 作用于整条路由,因此混合协议的 catalog 路由(跨 Responses 与 Chat Completions 的 OpenAI 式 catalog无法承载另一种协议的模型向这类路由添加它未描述的模型必须点名 `api` 并把全部模型一起迁过去。把该提供方拆成两个路由键是变通办法。