Repairable pi-ai settings after catalog changes
pi-ai 目录变化后可修复的设置
An installed pi-ai catalog can change the validity of unchanged user settings. OpenRouter models outside the catalog can inherit a protocol while all shipped models agree; adding a second protocol removes that inference. Removing a catalog model also invalidates an override keyed by its former id. Rejecting the entire settings namespace at registration makes unrelated providers disappear and removes the controls need
English
Problem
An installed pi-ai catalog can change the validity of unchanged user settings. OpenRouter models outside the catalog can inherit a protocol while all shipped models agree; adding a second protocol removes that inference. Removing a catalog model also invalidates an override keyed by its former id. Rejecting the entire settings namespace at registration makes unrelated providers disappear and removes the controls needed to repair the configuration.
Decision
The pi-ai consumer uses the existing settings validate callback. During namespace registration it tolerates catalog diagnostics; after registration it strictly checks changed providers against the current resolved section. Settings invokes this callback before persistence for update, replacement, and path mutation. External reload uses the same strict check and retains the last accepted section on failure. The settings service and its public API remain unchanged.
Initial profile resolution retains catalog diagnostics, while schema and self-contained profile constraints still reject loading. Writes strictly resolve each new or changed provider, comparing effective provider values against the committed snapshot. Unchanged failed providers do not block another provider's edit, and deletion remains possible. Editing a provider-wide setting validates all models it affects.
Profile resolution keeps valid models beside per-model errors. A missing override retains its diagnostic without disabling the remaining catalog. A route-level catalog failure retains its provider and editable settings but supplies no callable models. When route-wide validation aborts catalog resolution, the incomplete catalog and its collected per-model diagnostics are discarded; model requests on that route report the route-level error. The adapter checks the selected model's recorded failure before credentials or network I/O and reports INVALID_CONFIG. No protocol is guessed and no user configuration is rewritten during loading. Immutable snapshots still keep an in-flight request on its captured configuration.
LlmConfigurableProvider.error carries the first available model diagnostic for the provider row, falling back to the route error. A provider-construction failure does not overwrite a collected model diagnostic, preserving the specific correction for a missing protocol. The configurable-provider directory publishes diagnostic changes so configuration repair refreshes the browser without re-registering the adapter. Failed model ids remain in settings, while the model selector receives serviceable entries. Models settings displays the diagnostic and retains edit/delete controls. Both add actions require their owning settings namespace; the ordinary add menu filters out unavailable namespaces.
This extends the provider-routed adapter decision: provider ownership and request snapshots remain unchanged, while catalog validity does not determine whether settings can be managed. That note remains active for routing, ownership, and replay rationale.
Alternatives considered
Reject catalog errors at registration. This prevents users from repairing an otherwise parseable configuration and lets an unused stale model disable unrelated providers.
Relax save validation too. A newly entered model with no inferable protocol can be rejected immediately with the offending provider and model named. Accepting it creates an avoidable request-time failure.
Strictly revalidate the entire namespace on every save. An unrelated provider's old error would block adding a healthy provider or repairing providers independently.
Assign OpenRouter a fixed route protocol. A route override replaces every model's protocol and can change working catalog entries that intentionally use another API.
Consequences
Upgrade-dependent errors remain visible and repairable without weakening validation of new provider edits. Configuration errors remain distinct from remote model existence: a catalog-external id with an explicit protocol is accepted, and its endpoint decides whether that id exists. Scalar or document errors still fail early. Models settings does not explain namespace registration failures; those errors require inspecting the configuration and startup diagnostics. No settings API, storage format, or session event is added; configurable-provider entries gain one optional diagnostic field.
Testing
Adapter tests cover mixed valid/invalid models, deleted override referents, independent provider edits, route deletion, pre-network failure, and repair. A file-watcher regression verifies that invalid external edits retain the last accepted profiles and a repaired file takes effect. The assembled Web expectation boots with stale OpenRouter settings, preserves zai and both add controls, rejects an invalid save without changing the file, and repairs the route by removing the stale model. Existing snapshot tests continue to own request freezing and replay behavior.
中文
Problem
已安装的 pi-ai 目录可能改变未修改用户设置的有效性。OpenRouter 的目录外模型可以在所有内置模型协议一致时继承协议;加入第二种协议会使这种推断失效。删除目录模型也会使按其旧 ID 声明的覆盖失效。注册时拒绝整个 settings 命名空间,会让无关提供方消失,也移除了修复配置所需的控件。
Decision
pi-ai 消费者使用现有 settings validate 回调。命名空间注册期间容忍目录诊断;注册完成后,将变化的提供方与当前已解析分节比较并严格校验。Settings 在更新、整体替换和路径修改的持久化之前调用此回调。外部重载使用相同的严格校验,失败时保留最后一次接受的分节。Settings 服务及其公共 API 保持不变。
首次解析 profile 时保留目录诊断,而 schema 与 profile 自身的约束仍会拒绝加载。写入会将有效提供方值与已提交快照比较,严格解析每个新增或修改的提供方。未修改的错误提供方不会阻止其他提供方编辑,删除仍然可用。修改提供方级设置会校验其影响的所有模型。
Profile 解析在有效模型旁保留逐模型错误。失去引用目标的覆盖会保留诊断,而不会禁用其余目录。路由级目录失败会保留提供方与可编辑设置,但不提供可调用模型。路由级校验中止目录解析时,不完整的目录及其已收集的逐模型诊断会被丢弃,该路由上的模型请求统一报告路由级错误。适配器在解析凭据和网络 I/O 前检查所选模型已记录的错误,并报告 INVALID_CONFIG。加载过程不会猜测协议或改写用户配置。不可变快照仍保证进行中的请求使用其捕获的配置。
LlmConfigurableProvider.error 优先为提供方行携带首个模型诊断,无模型诊断时返回路由错误。提供方构造失败不会覆盖已收集的模型诊断,从而保留缺少协议时的具体修复提示。可配置提供方目录发布诊断变化,修复配置会刷新浏览器,无需重新注册适配器。错误模型 ID 保留在设置中,模型选择器只接收可服务条目。模型设置页显示诊断并保留编辑、删除控件。两个添加操作都要求其所属 settings 命名空间存在;普通添加菜单会过滤不可用的命名空间。
本决策扩展了按提供方路由的适配器决策:提供方所有权与请求快照不变,目录有效性不决定设置是否可管理。旧记录仍保留为路由、所有权与回放设计的依据。
Alternatives considered
在注册时拒绝目录错误。 这会阻止用户修复结构可解析的配置,并让未使用的过期模型禁用无关提供方。
同时放宽保存校验。 对无法推断协议的新模型,可以立即拒绝并点名提供方与模型。接受它只会制造可避免的请求时错误。
每次保存都严格重校验整个命名空间。 无关提供方的旧错误会阻止添加正常提供方,或逐个修复提供方。
为 OpenRouter 指定固定路由协议。 路由覆盖会替换所有模型的协议,可能改变有意使用其他 API 的正常目录条目。
Consequences
依赖升级产生的错误仍可见、可修复,而新增提供方编辑的校验不会放宽。配置错误与远端模型是否存在仍然不同:显式指定协议的目录外 ID 可以被接受,由端点决定该 ID 是否存在。标量或文档错误仍尽早失败。模型设置页不展示命名空间注册失败的原因,此类错误需要检查配置与启动诊断。不增加 Settings API、存储格式或 session 事件;可配置提供方条目新增一个可选诊断字段。
Testing
适配器测试覆盖有效与错误模型混合、覆盖目标被删除、独立提供方编辑、路由删除、联网前失败及修复。文件监听回归验证非法外部编辑保留最后一次接受的 profile,而修复后的文件能够生效。完整 Web 期望测试从过期 OpenRouter 设置启动,保留 zai 与两个添加控件,在不改变文件的前提下拒绝无效保存,并通过删除过期模型修复路由。已有快照测试继续负责请求冻结与回放行为。