跳转至

62. 配置、模型运行时与基础设施

这个模块干什么

这一组文件把磁盘上的 settings、认证与缓存变成一次运行实际使用的 model/provider,并把项目资源的 trust、HTTP、包管理和平台入口放到可复用基础设施层。packages/coding-agent/src/core/settings-manager.ts:274-510 packages/coding-agent/src/core/model-runtime.ts:94-593

settings 是全局与项目两层的合并结果;项目层是否参与取决于 projectTrusted,而启动迁移负责把旧格式搬到当前存储。packages/coding-agent/src/core/settings-manager.ts:274-510 packages/coding-agent/src/migrations.ts:21-315

用户选到的模型并不直接等于网络 provider:resolver 先选 Model,runtime 再把 builtin、models.json、扩展、认证、headers 和远程 catalog 组合成可调用 provider。packages/coding-agent/src/core/model-resolver.ts:273-726 packages/coding-agent/src/core/model-runtime.ts:231-593 packages/coding-agent/src/core/provider-composer.ts:399-548

认证分为持久的 auth.json 和本进程的 API key override;后者不会写回凭据文件。packages/coding-agent/src/core/auth-storage.ts:28-271 packages/coding-agent/src/core/runtime-credentials.ts:3-48

其余文件提供明确但较薄的边界:路径/自更新、SDK 组装、代理 dispatcher、配置值展开、footer 数据、实验开关、包命令和 Bun 入口。packages/coding-agent/src/config.ts:315-566 packages/coding-agent/src/core/sdk.ts:38-398 packages/coding-agent/src/core/http-dispatcher.ts:4-106

核心文件速查

文件 一句话职责 必读优先级
packages/coding-agent/src/core/settings-manager.ts 加载、迁移、合并全局/项目 settings,并提供运行时读取器与写入器。packages/coding-agent/src/core/settings-manager.ts:274-510 packages/coding-agent/src/core/settings-manager.ts:660-1234 ⭐⭐⭐
packages/coding-agent/src/migrations.ts 启动时迁移旧 auth、session、tools/bin、keybindings 和 extension/commands 布局。packages/coding-agent/src/migrations.ts:21-315 ⭐⭐⭐
packages/coding-agent/src/core/model-runtime.ts model、认证、provider 注册、刷新与 stream 的主运行时。packages/coding-agent/src/core/model-runtime.ts:94-593 ⭐⭐⭐
packages/coding-agent/src/core/model-resolver.ts 解析 CLI/模式匹配、scope 与初始模型选择优先级。packages/coding-agent/src/core/model-resolver.ts:14-53 packages/coding-agent/src/core/model-resolver.ts:273-726 ⭐⭐⭐
packages/coding-agent/src/core/provider-composer.ts 把 provider 的静态定义、模型覆盖、认证和 headers 组合成最终 provider。packages/coding-agent/src/core/provider-composer.ts:399-548 ⭐⭐⭐
packages/coding-agent/src/core/auth-storage.tsruntime-credentials.ts 分别管理持久凭据与非持久的运行时 key 覆盖。packages/coding-agent/src/core/auth-storage.ts:28-271 packages/coding-agent/src/core/runtime-credentials.ts:3-48 ⭐⭐⭐
packages/coding-agent/src/core/project-trust.tstrust-manager.ts 计算项目是否可信,并持久化 trust.json 及资源 gate 的判断。packages/coding-agent/src/core/project-trust.ts:14-96 packages/coding-agent/src/core/trust-manager.ts:8-244 ⭐⭐⭐
packages/coding-agent/src/core/model-config.tsmodels-store.tsremote-catalog-provider.ts 提供 models.json 快照、远程 catalog 的持久缓存和远程 overlay。packages/coding-agent/src/core/model-config.ts:231-293 packages/coding-agent/src/core/models-store.ts:8-57 packages/coding-agent/src/core/remote-catalog-provider.ts:5-123 ⭐⭐
packages/coding-agent/src/core/model-registry.tsprovider-attribution.ts 分别是扩展用的同步 facade 与 provider/host 的 attribution header 规则。packages/coding-agent/src/core/model-registry.ts:16-145 packages/coding-agent/src/core/provider-attribution.ts:11-97 ⭐⭐
packages/coding-agent/src/config.tscore/sdk.ts 处理目录/安装方式/自更新,并把 settings、models、resources 组装给 SDK。packages/coding-agent/src/config.ts:315-566 packages/coding-agent/src/core/sdk.ts:38-398 ⭐⭐
packages/coding-agent/src/core/package-manager.tspackage-manager-cli.tsbun/ 管理包/资源与 CLI 子命令,并给 Bun 二进制做最小启动补丁。packages/coding-agent/src/core/package-manager.ts:795-1238 packages/coding-agent/src/package-manager-cli.ts:55-887 packages/coding-agent/src/bun/cli.ts:1-15 ⭐⭐

精读

1. config.ts:名称、目录与安装来源的唯一口径

config.ts 定义 package/app/config directory/version 等常量,并以这些常量派生 agent、bin、docs、package 等路径。packages/coding-agent/src/config.ts:315-346 packages/coding-agent/src/config.ts:367-444

因此其它模块不应自己拼 ~/.pi/agent 或包根目录;应经 getAgentDir()getBinDir()getDocsPath()getPackageDir() 取路径。packages/coding-agent/src/config.ts:367-444

detectInstallMethod() 判断当前安装来源,getSelfUpdateCommand() 根据该结果给出可执行的自更新命令,getSelfUpdateUnavailableInstruction() 处理不能自动更新的情况。packages/coding-agent/src/config.ts:488-550 packages/coding-agent/src/config.ts:515-566

2. settings-manager.ts:schema 的加载、覆盖与 trust 边界

SettingsManager 通过 SettingsStorage 抽象读取配置,并提供 create()fromStorage()inMemory() 三种构造入口。packages/coding-agent/src/core/settings-manager.ts:274-378

它分别保留全局与项目 settings,再生成有效合并配置;项目设置只有在 project trusted 时才参与这一结果。packages/coding-agent/src/core/settings-manager.ts:274-510

loadFromStorage()migrateSettings() 在读取阶段处理旧字段,使调用者读取 getters 时面对的是当前 schema。packages/coding-agent/src/core/settings-manager.ts:381-439

setProjectTrusted()reload()applyOverrides() 是运行中改变 trust、重新读盘或加临时覆盖的三个入口。packages/coding-agent/src/core/settings-manager.ts:442-510

常用 getter 集中在同一类中:默认 provider/model/thinking、transport、compaction、retry、HTTP timeout、provider retry、telemetry、packages 与资源路径都从这里读取。packages/coding-agent/src/core/settings-manager.ts:660-1234

getDefaultProjectTrust() 读取非交互模式没有已保存信任决定时使用的默认策略。packages/coding-agent/src/core/settings-manager.ts:899-907

“settings schema”在这里表现为类型化的 load/merge/getter/setter API,而非让所有调用点直接访问 JSON 对象。packages/coding-agent/src/core/settings-manager.ts:274-510 packages/coding-agent/src/core/settings-manager.ts:660-1234

3. migrations.ts:在正常 runtime 前修旧数据

runMigrations(cwd) 在启动时依次执行 auth、session、tools/bin、keybindings 和 extension system 迁移。packages/coding-agent/src/migrations.ts:21-315

auth 迁移把旧 oauth.jsonsettings.json.apiKeys 合并进 auth.json,从而把凭据收敛到专门 storage。packages/coding-agent/src/migrations.ts:21-73

session 迁移修复旧的 agent-root 会话位置,tools 迁移把旧工具目录迁到 bin 约定。packages/coding-agent/src/migrations.ts:84-172

extension 迁移包括将旧 commands/ 目录转为 prompts/,并积累需要展示的弃用警告。packages/coding-agent/src/migrations.ts:257-315

showDeprecationWarnings() 与迁移结果分开,使 interactive 启动可以在 TUI 可用后再阻塞地展示提示。packages/coding-agent/src/migrations.ts:257-315 packages/coding-agent/src/main.ts:785-788

4. model-config.tsmodels-store.tsremote-catalog-provider.ts:静态快照和动态目录不混淆

ModelConfig.load() 解析、校验并冻结 models.json,得到 credential-blind 的不可变快照。packages/coding-agent/src/core/model-config.ts:231-293

它不直接读取 API key/OAuth,因此模型描述与“当前用户是否能调用”是两个阶段。packages/coding-agent/src/core/model-config.ts:231-293 packages/coding-agent/src/core/model-runtime.ts:231-593

FileModelsStore 持久化远程 catalog 缓存,InMemoryCodingAgentModelsStore 提供无文件/测试用后端。packages/coding-agent/src/core/models-store.ts:8-57

withRemoteCatalog() 在静态 builtin provider 上叠加 pi.dev catalog,并按 checkedAt、etag、last-modified 管理缓存与再验证。packages/coding-agent/src/core/remote-catalog-provider.ts:5-123

所以 catalog refresh 不必改写本地 models.json;它是 runtime 可更新的 overlay。packages/coding-agent/src/core/remote-catalog-provider.ts:5-123 packages/coding-agent/src/core/models-store.ts:8-57

5. model-resolver.ts:先确定“想用哪一个模型”

defaultModelPerProvider 保存各 provider 的首选模型 ID,供没有显式模型时的选择逻辑使用。packages/coding-agent/src/core/model-resolver.ts:14-53

resolveCliModel() 解析 --provider/--modelprovider/model[:thinking],处理模式匹配、warning/error 与 fallback model id。packages/coding-agent/src/core/model-resolver.ts:385-556

resolveModelScope() 及其带 diagnostics 的变体把 settings/CLI 的模型 pattern 解析成可循环的 scoped models。packages/coding-agent/src/core/model-resolver.ts:273-360

findInitialModel() 的优先级是 CLI 指定、scoped models、已有认证的 settings 默认模型、任一可用模型(优先 provider 默认表)、最后 fallback。packages/coding-agent/src/core/model-resolver.ts:572-726

这一步只解决 Model 对象的选择;它尚未决定最终请求如何认证或加 header。packages/coding-agent/src/core/model-resolver.ts:385-726 packages/coding-agent/src/core/provider-composer.ts:399-548

6. model-runtime.tsmodel-registry.ts:把选择变成可用运行时

ModelRuntime.create() 建立主运行时,refresh()getAuth()stream()registerProvider()registerNativeProvider()unregisterProvider() 覆盖其核心生命周期。packages/coding-agent/src/core/model-runtime.ts:94-593

运行时把 builtin providers、远程 catalog、models.json 和 extension provider 组合成可查询、可认证、可 stream 的 Modelspackages/coding-agent/src/core/model-runtime.ts:231-593

因此 extension 新注册 provider 后,不是单独维护另一个列表,而是进入同一个 runtime 的可用模型/认证路径。packages/coding-agent/src/core/model-runtime.ts:539-593

ModelRegistry 是给扩展使用的同步兼容 facade,内部仍委托 ModelRuntime,不应被理解为第二套模型数据库。packages/coding-agent/src/core/model-registry.ts:16-145

7. provider-composer.tsprovider-attribution.ts:最终 provider 的拼装点

composeModelProvider() 是最关键的组合函数:输入 builtin provider、models.json、extension config、OAuth/API key、headers 和 model overrides,输出新的 Providerpackages/coding-agent/src/core/provider-composer.ts:399-548

extension provider 先经 validateExtensionProvider() 做结构检查,再参与组合,避免任意对象直接进入请求路径。packages/coding-agent/src/core/provider-composer.ts:399-548

resolveConfiguredModelHeaders() 解析模型头,resolveCompatibilityRequestConfig() 处理兼容请求设置,configuredRequestAuthStatus() 推断配置后的认证状态。packages/coding-agent/src/core/provider-composer.ts:501-548

因此“同一个 model id”在不同 credentials、extension 覆盖或 headers 下可以得到不同的具体 provider 实例。packages/coding-agent/src/core/provider-composer.ts:399-548

provider-attribution.ts 在特定 provider/host 上加入 attribution/telemetry headers;OpenRouter、NVIDIA NIM、Cloudflare 与 opencode 都有独立分支。packages/coding-agent/src/core/provider-attribution.ts:11-97

这类 headers 在 composition 之后、网络请求之前参与,而不是写进模型选择器。packages/coding-agent/src/core/provider-attribution.ts:11-97 packages/coding-agent/src/core/provider-composer.ts:399-548

8. auth-storage.tsruntime-credentials.tsauth-guidance.ts:持久性分层

AuthStorageauth.json 后端,提供 read、modify、delete、list;readStoredCredential() 是一次性的同步读取帮助函数。packages/coding-agent/src/core/auth-storage.ts:28-271

文件后端以 withLock() / withLockAsync() 串行化修改,并处理锁和 0600 权限。packages/coding-agent/src/core/auth-storage.ts:28-271

RuntimeCredentials 在持久 storage 上叠加进程内 API key override,适合 CLI --api-key,不会把覆盖持久化。packages/coding-agent/src/core/runtime-credentials.ts:3-48 packages/coding-agent/src/main.ts:705-715

认证不存在时的“去 /login”等用户提示集中在 auth-guidance.ts,不散落到 runtime/CLI 的每个错误分支。packages/coding-agent/src/core/auth-guidance.ts:6-25

9. project-trust.tstrust-manager.ts:项目配置先过信任门

ProjectTrustStore 读写 trust.json,并提供项目/父目录的信任查找、更新和资源需求判断。packages/coding-agent/src/core/trust-manager.ts:8-244

hasTrustRequiringProjectResources() 把“是否存在需要 gate 的项目资源”变成共享判断,避免每个 loader 重新猜测。packages/coding-agent/src/core/trust-manager.ts:8-244

resolveProjectTrusted() 的顺序是显式 override、extension project_trust 事件、已保存 trust.json、默认策略或 interactive UI prompt。packages/coding-agent/src/core/project-trust.ts:14-96

这个顺序让 --approve/--no-approve 能一次性覆盖,同时仍允许扩展参与决策、用户保存决定、非交互使用默认策略。packages/coding-agent/src/core/project-trust.ts:14-96

资源 loader/package manager 在确定该布尔值后才允许项目 settings 和项目资源进入完整发现路径。packages/coding-agent/src/core/resource-loader.ts:333-493 packages/coding-agent/src/core/package-manager.ts:901-963

10. sdk.tsdefaults.ts 与辅助基础设施

createAgentSession() 是 SDK 启动器:组合 ModelRuntimeSettingsManagerSessionManagerDefaultResourceLoader 与 Agent,并串起 attribution、stream 与初始模型选择。packages/coding-agent/src/core/sdk.ts:38-398

SDK 路径和 CLI 路径因此共享 models/settings/resources 的基础对象,而不是 SDK 自己重做一个轻量 provider 栈。packages/coding-agent/src/core/sdk.ts:38-398 packages/coding-agent/src/core/model-runtime.ts:94-593

DEFAULT_THINKING_LEVEL 只有 "medium" 这一个默认常量,避免把默认值散在 resolver 和 settings getter 中。packages/coding-agent/src/core/defaults.ts:1-3

configureHttpDispatcher() 解析 idle timeout,并把 HTTP_PROXY/HTTPS_PROXY 注入 undici 全局 dispatcher。packages/coding-agent/src/core/http-dispatcher.ts:4-106

areExperimentalFeaturesEnabled() 只接受 PI_EXPERIMENTAL === "1",是极小且明确的功能 gate。packages/coding-agent/src/core/experimental.ts:1-3

SourceInfo helpers 把 package manager 的 PathMetadata 转为展示/诊断可携带的来源信息,也可创建 synthetic source。packages/coding-agent/src/core/source-info.ts:1-40

resolve-config-value.ts 支持 !command$FOO/${FOO} 模板和字面值,并提供 headers 解析与缓存清理。packages/coding-agent/src/core/resolve-config-value.ts:1-287

这意味着 models/provider 配置中的敏感值可在需要时从环境或命令求值,而不必直接写死到 settings。packages/coding-agent/src/core/resolve-config-value.ts:1-287

FooterDataProvider 提供 git branch、extension status 和可用 provider 数,并监视 HEAD/reftable;WSL 挂载仓库可退回轮询。packages/coding-agent/src/core/footer-data-provider.ts:12-388

它是 UI 数据服务而非 model/session 状态的权威来源,因而可独立订阅和刷新。packages/coding-agent/src/core/footer-data-provider.ts:12-388

11. package-manager.tspackage-manager-cli.tsbun/:分发面基础设施

DefaultPackageManager 负责解析资源、install、remove、update、listConfiguredPackages 和检查可用更新。packages/coding-agent/src/core/package-manager.ts:795-1238

它既服务扩展包安装,也服务资源解析,所以 package 的 manifest 与普通目录最终会进入同一条资源加载链。packages/coding-agent/src/core/package-manager.ts:795-1238 packages/coding-agent/src/core/resource-loader.ts:333-493

handleConfigCommand()handlePackageCommand() 把 config/install/remove/update/list 接到 SettingsManagerProjectTrustStoreDefaultPackageManagerModelRuntimepackages/coding-agent/src/package-manager-cli.ts:55-887

普通 main() 在参数解析前调用这两个 handler,因此 package/config 子命令不会创建一般 agent runtime。packages/coding-agent/src/main.ts:492-507

bun/cli.ts 是 Bun 二进制入口:先恢复 sandbox 环境、注册 Bedrock shim,再进入主 CLI。packages/coding-agent/src/bun/cli.ts:1-15

restore-sandbox-env.ts 是 Bun sandbox 环境变量恢复补丁,register-bedrock.ts 只负责 provider module 注入,二者都刻意保持窄小。packages/coding-agent/src/bun/restore-sandbox-env.ts:1-36 packages/coding-agent/src/bun/register-bedrock.ts:1-4

数据流

下面追踪用户指定一个模型后,如何从配置走到可请求 provider。packages/coding-agent/src/core/settings-manager.ts:274-510 packages/coding-agent/src/core/model-runtime.ts:94-593

settings.json / auth.json / models.json / extension providers
  -> SettingsManager: 全局 + 已信任项目 + 临时覆盖
  -> ModelRuntime.create(): 静态 models、catalog cache/remote overlay、auth stores
  -> resolveCliModel() 或 findInitialModel(): 得到 Model
  -> RuntimeCredentials: 可选 --api-key 覆盖持久 auth
  -> composeModelProvider(): builtin + models.json + extension + auth + headers/overrides
  -> provider attribution headers
  -> ModelRuntime.stream(): 用具体 Provider 发出请求

settings 的合并与 trust gate 在 SettingsManager,auth 迁移在 runtime 建造之前执行。packages/coding-agent/src/core/settings-manager.ts:274-510 packages/coding-agent/src/migrations.ts:21-315

模型候选/初始选择由 resolver 完成,provider 的具体组合由 composer 和 runtime 完成。packages/coding-agent/src/core/model-resolver.ts:273-726 packages/coding-agent/src/core/provider-composer.ts:399-548 packages/coding-agent/src/core/model-runtime.ts:231-593

CLI --api-key 的覆盖点是 setRuntimeApiKey(),因此它在流程中位于模型已选中之后、可用列表刷新之前。packages/coding-agent/src/main.ts:705-715

自测

  1. 项目 settings 为什么不能只靠“文件存在”就参与最终配置?packages/coding-agent/src/core/settings-manager.ts:274-510 packages/coding-agent/src/core/project-trust.ts:14-96

  2. findInitialModel()composeModelProvider() 分别解决什么问题,为什么不能合成一个函数?packages/coding-agent/src/core/model-resolver.ts:572-726 packages/coding-agent/src/core/provider-composer.ts:399-548

  3. --api-key 和保存到 auth.json 的 credential 在生命周期上有何不同?packages/coding-agent/src/core/auth-storage.ts:28-271 packages/coding-agent/src/core/runtime-credentials.ts:3-48 packages/coding-agent/src/main.ts:705-715

  4. 为什么 remote catalog 需要 ModelsStore 与 etag/last-modified,而不直接覆写 models.json?packages/coding-agent/src/core/models-store.ts:8-57 packages/coding-agent/src/core/remote-catalog-provider.ts:5-123

  5. 为什么 package/config 子命令在一般 parseArgs() 之前处理?packages/coding-agent/src/package-manager-cli.ts:55-887 packages/coding-agent/src/main.ts:492-507