oh-my-pi Model Catalog:面向 Coding Agent 的模型数据库、兼容性规则引擎与动态发现体系
【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi
导读:
@oh-my-pi/pi-catalog是 oh-my-pi(OMP,⌥ 代号驱动的编码 Agent)内置的模型目录包,它同时承载三件事:随包分发、可离线查询的模型数据库models.json;用 KDL 声明式编写、再编译为rules.json的模型身份/兼容性策略树;以及面向 OpenAI 兼容端点、Gemini、Codex、Cursor、Antigravity、Ollama 等形态的运行期模型发现。读完本文,你将掌握该包的模块划分与子路径导入方式、gen:compat/gen:models两条生成流水线的边界、KDL 规则树的层级结构与核心语法,以及带分时定价(peak/off-peak、历史费率卡)的成本计算 API 的完整调用方式。
包的定位:模型目录为什么值得做成独立模块
@oh-my-pi/pi-catalog(仓库内位于 packages/catalog,版本见 package.json)解决的是一类很容易被低估的问题:一个长期运行的编码 Agent 会面对成百上千个模型标识符——同一模型在不同提供商(含各种代理/网关/转售商)下有不同的 SKU 名称、限速、上下文窗口、定价甚至“思考(thinking)”能力标注。如果这些信息散落在各模块的硬编码里,任何一处上游改价、改名或推出新 SKU,都需要改代码、发版本。
该包把这类信息收敛为三层:
- 数据层:
models.json内置模型数据库,记录每个模型的定价、上下文窗口、模态(modality)、thinking 支持等; - 策略层:
compat/rules下的 KDL 策略树,描述模型身份(taxonomy)、类/提供商级联规则(cascade)、运行期行为词汇表(runtime behavior vocabulary),并编译为提交进仓库的rules.json; - 执行层:
compat模块的规则引擎classifyModel(分类)、resolveModelPolicy(级联解析)以及行为访问器与 OpenAI/Anthropic 线协议(wire)构造器。
包的全部入口由 src/index.ts 统一导出,同时支持从子路径按需导入(@oh-my-pi/pi-catalog/<module>),这在 package.json 的exports字段中有完整映射(如./models.json、./discovery/*、./compat/*、./wire/*等)。包直接分发 TypeScript 源码、无构建步骤,要求 Bun ≥ 1.3.14;安装方式为bun add @oh-my-pi/pi-catalog。
模块全景:一张表看懂 What's inside
原文档给出的模块职责表是该包的索引地图,逐项展开如下:
| 模块 | 职责 | 关键源码 |
|---|---|---|
models.json+models | 内置模型数据库(定价、上下文窗口、模态、thinking 支持) | src/models.ts |
provider-models | 提供商目录描述符CATALOG_PROVIDERS,以及按提供商的模型解析规则 | src/provider-models/index.ts |
discovery | 针对 OpenAI 兼容端点、Gemini、Codex、Cursor、Antigravity、Ollama 的运行期模型发现 | src/discovery/index.ts |
compat/rules | 已检入的 KDL 策略树;由bun run gen:compat编译为rules.json | src/compat/rules |
compat | 规则引擎:classifyModel、resolveModelPolicy、行为访问器、collapse、OpenAI/Anthropic wire 构造器 | src/compat/axes.ts 等 |
identity | 机械性 id 工具:基于内置索引的引用解析、方言、选择优先级、tokenizer 家族 | src/identity/index.ts |
model-thinking | 基于已解析模型记录的 thinking 运行期助手(getSupportedEfforts、effort 钳制/映射、wire-id 路由) | src/model-thinking.ts |
model-manager/model-cache | 运行期模型注册表,带发现刷新与磁盘缓存 | src/model-manager.ts |
wire | 线级助手:Codex、Gemini headers、GitHub Copilot | src/wire |
effort | 推理 effort 级别定义 | src/effort.ts |
其中effort模块定义了面向用户的六个思考级别,按强度升序为minimal → low → medium → high → xhigh → max(THINKING_EFFORTS常量),这一枚举贯穿分类 override、级联 thinking 轴与运行期 effort 钳制,是整个包的基础词汇。
两条生成流水线:models.json 与 rules.json 是产物而非手写源
包内最重要的工程约定写在原文档第一节:永远不要手改src/models.json和src/compat/rules.json。它们是生成产物:
bun run gen:compat # src/compat/rules/**/*.kdl -> src/compat/rules.json bun run gen:models # upstream sources + rules -> src/models.jsongen:compat由 scripts/compile-compat.ts 执行,把 KDL 策略树编译成规则引擎消费的 JSON;gen:models由 scripts/generate-models.ts 执行,从上游来源(stencil.so、提供商目录发现、OpenCode 文档)结合rules.json重新“烘焙”模型库;脚本目录中还包含 scripts/equivalence.ts,负责等价模型候选的生成与打分,但候选生成和打分算法所需的全部作者维护 token 都声明在 KDL 的discovery词汇表里。
配套的测试 test/compat-compile.test.ts 会在rules.json与 KDL 源漂移时失败;test/compat-parity.test.ts 则证明引擎能复现models.json里所有已烘焙的 compat/thinking 值。
变更纪律:模型或提供商的条件策略(身份、effort 阶梯、wire 怪癖、模态/限额/定价修正、API 路由、名册排除)一律写在 KDL 树里;TypeScript 改动只允许涉及“传输机制”——即provider-models/descriptors.ts中的提供商条目、provider-models/openai-compat.ts中的发现/请求管道、以及scripts/generate-models.ts中的生成器接线。改完.kdl必须同时提交重新生成的rules.json(以及值变化时重新烘焙的models.json)。
KDL 策略树:身份分类、级联规则与运行期行为
三类所有权分层(ownership strata)
src/compat/rules/目录按职责划分文件,规则作者被明确要求“不要把统计上常见的提供商行为挪进类文件,也不要把血统事实挪进提供商文件”。四个目录的职责如下:
taxonomy/*.kdl:定义身份——类成员关系、产品家族、修订版本提取、人工复核的精确修正(override)、后缀折叠(collapse);classes/*.kdl:定义模型血统事实——模型线固有的行为,可限定到建立该事实的提供商或请求适配器;providers/*.kdl:定义部署契约——宿主强加的行为,以及 taxonomy 无法精确表达的各模型残留(residue);runtime/behavior.kdl:精确模型查找之前/之外的启发式——responses 路由、API 路由、配额档位、计划要求、模型限额、名册排除、托管默认、定价对等;auth/<provider>.kdl:提供商的身份认证契约,供@oh-my-pi/pi-ai的注册表引擎解释。
分类的三大概念:class / family / revision
- class(类):厂商血统,如
gemini、anthropic; - family(家族):类内的产品线,如
flash、pro、sonnet、opus; - revision(修订版):从模型名提取的
major.minor.patch三元组,缺失的 minor/patch 按 0 处理。
分类时会对完整模型标识符做 trim 与小写化,bare name是最后一个/之后的段。类成员匹配器按以下排名竞争(数值越大越优先,同分按匹配 token 字节长度,仍并列则报歧义错误;全部不匹配时归入unknown类):
| 节点 | 排名 | 匹配语义 |
|---|---|---|
exact "token" | 4 | 整个 bare name 等于 token |
bounded "token" | 3 | bare name 等于 token,或以-_.:或 ASCII 数字开头 |
namespace "token" | 2 | 完整标识符的某个非空/分段等于 token |
namespace "token" bounded=#true | 2 | 按/.:切分,某段满足 bounded 规则(唯一带属性的匹配器) |
prefix "token" | 1 | bare name 以 token 开头 |
glob "pattern" | 0 | 基于 bare name 的锚定*通配 |
家族规则含必填glob属性与可选的有符号整数priority(默认 0),按(priority, glob 非通配字节数)排序,如family "lite" glob="*flash-lite*" priority=10优先于family "flash" glob="*flash*"。修订提取通过revision prefix=...(anywhere=#true允许出现在 bare name 任意位置)、skip-bare(显式声明不带修订的 bare name)完成;提取从第一个 ASCII 数字开始,最多读取三个无符号 8 位数字分量,缺失分量补 0——因此claude-opus-4-6得到4.6.0。
复核过的身份修正:override
override节点只含属性、无子块,必填id(稳定且全局唯一的复核 ID)、model(精确 bare 标识符)、rationale、provenance(溯源);可选provider、logical(修正后的逻辑标识符)、class、family、revision、effort(off/minimal/low/medium/high/xhigh/max)、thinking-variant、expires-at-ms(Unix 毫秒过期时间,观测时间达到或超过该值后 override 失效)。带provider的 override 优先于全局 override,(provider, model)组合必须唯一。代码注释里通常带有 census 溯源(provenance),例如frozen census case identity-01。
后缀折叠与发现词汇表
collapse节点是整个清单中唯一、必有的一个定义,处理:thinking-suffix(如-thinking)、pair-token(声明 thinking 孪生兄弟 token,如sonar-reasoning-pro与sonar-pro)、effort-suffix(如-minimal/-max,可带except-bare-prefix)、effort-lane-suffix、routing-variant-suffix、variant-family(可带{rev}占位符的模板化家族,如gemini-{rev}-flash)、provider-alias。discovery节点则声明recover-canonical-params、borrow-responses-route、billing-variant-suffix、trailing-marker、pro-reasoning-alias、canonical-family-token、wrapper-prefix/synthetic-prefix(如hf:)等发现期词汇。这些词汇全部服务于 scripts/equivalence.ts 的候选生成,但所有作者维护的 token 都集中声明在 KDL 里。
级联(cascade)与行为轴
级联文档以class或provider开头,选择器可嵌套:class(根/提供商下)→on(按部署提供商,仅根 class 下)→on-api(按请求适配器)→family→revision(如">=2.5 <4")→models(精确 id 或vendor/*锚定通配,也可用token="name")。每条规则按(model-selector exactness, constrained-dimension count, priority)字典序取最高分;同分且赋同一轴即歧义错误,文件与声明顺序从不充当决胜因素。
轴的词汇表是封闭的、集中定义在 src/compat/axes.ts:一张表把每个 kebab-case 指令映射到解析后的 camelCase 字段、所属命名空间(wire/thinking/catalog)、值形状与可选枚举值,编译器据此拒绝未知指令。值形状有三种:标量、数组、对象。一个实用细节:long-context-cost对象轴支持绝对费率或input-threshold + multiplier两种写法,后者在构建时按行内实时基础价推导阶梯费率,从而自动跟随上游价目表(例如 xAI SuperGrok 200K 档)。
运行期行为词汇
runtime/behavior.kdl的根节点是behavior,其子节点形状严格,覆盖:openai-responses-heuristic、model-operations、cursor-effort、cursor-model-parameter、quota-tiers、hosted-default、api-routes(可带strip-prefix=#true)、model-limits、exclude-models、plan-requirement、pricing-peer。这些值直接从它们替代的 TS 常量逐字复制而来,运行期访问器在 src/compat/behavior.ts。仓库中 auth 契约(auth/*.kdl)还声明了每种提供商唯一一个auth "<id>"节点,支持api-key、oauth-code、device-code、custom四种登录形态,OAuth 客户端 id 以 base64 混淆存储、运行期解码——这是为了让密钥扫描器保持安静,同时仍可在运行期还原。
动态发现:从 OpenAI 兼容端点到各厂商形态
discovery模块(src/discovery)负责把运行期环境中的真实模型“找出来”,与静态内置库互补:
- openai-compatible.ts:面向 OpenAI 兼容端点的通用发现;
- gemini.ts / gemini-cli.ts:Gemini 与 Gemini CLI;
- codex.ts、cursor.ts(含 cursor-proto.ts)、antigravity.ts、devin.ts(含 protobuf 支持)、gitlab-duo-workflow.ts、ollama.ts;
- protobuf.ts:若干厂商发现协议依赖的 protobuf 解析。
本地模型服务在用户侧文档 docs/models.md 有具体约定:Ollama 未显式配置时注册表自动添加隐式可发现提供商(base URL 取OLLAMA_BASE_URL→OLLAMA_HOST→http://127.0.0.1:11434,上下文窗口取OLLAMA_CONTEXT_LENGTH→/api/show元数据 → 128000,无鉴权);llama.cpp 默认http://127.0.0.1:8080;LM Studio 默认http://127.0.0.1:1234/v1(也可借道/v1/models发现其他 OpenAI 兼容本地服务);LiteLLM 则按GET /model_group/info→/v2/model/info→/model/info→/v1/model/info依次探测管理元数据,全部不可用时回退GET /models。发现结果交给model-manager/model-cache(src/model-manager.ts)做运行期注册、刷新与磁盘缓存。对应的大量发现测试可从 test/codex-discovery.test.ts、test/cursor-discovery.test.ts、test/gemini-cli-discovery.test.ts 等文件查看。
成本计算:时间感知的定价 API
models子路径(根导出同样可用)提供一组时间戳感知的定价助手,这是原文档表格的完整 API:
| API | 结果 |
|---|---|
calculateCost(model, usage, timestamp?) | 用model.cost更新并返回usage.cost |
calculateUsageCost(cost, usage, timestamp?) | 用ModelCost更新并返回usage.cost |
calculateUncachedInputCost(cost, promptInputTokens, timestamp?) | 返回完全未缓存提示的计价结果 |
getTimeBasedPricingPeriod(cost, timestamp?) | 返回"peak"、"off-peak"或(无调度时)undefined |
getNextTimeBasedPricingTransition(cost, timestamp?) | 返回时间戳之后严格意义上的下一个 peak/off-peak 切换时刻,或undefined |
实现位于 src/models.ts:
- 时间戳语义:时间戳为 Unix 毫秒;省略时对带调度的价格使用当前时间。平坦的 token 价格不受影响。
- 选择顺序:先取“时间戳之前最新生效”的费率卡(
resolveTokenCost遍历effectiveRates,取effectiveFrom <= timestamp且最晚者),再取其长上下文档位(longContext.inputThreshold,inputThresholdInclusive决定阈值是否含等号),最后应用 peak/off-peak 倍率。 - 分时判定:
isPeakPricingPeriod用纯算术(Unix 纪元是周四)逐分钟判定是否落在某个 peak 窗口内,全程不分配Date对象;窗口 start 包含、end 排除,跨午夜窗口必须拆到两天。 - cache-write 特例:
cacheWriteCost在 provider 上报 TTL 明细(usage.cttl)时按 5 分钟档与 1 小时档分别计价(1h 写入按input * 2推导),未归属的残差按平坦费率计价,保证部分/过期明细永远不会让写入 token“免费”。 - 验证前置:src/pricing.ts 里的
isTimeBasedCost/materializeTimeBasedCost会在缓存模型行被接纳前严格校验调度——周几必须是0-6去重、窗口分钟须满足0 <= start < end <= 1440、effective-from必须是合法的 ISO UTC 时间戳且全局去重。
ModelCost.timeBased 的类型化元数据
ModelCost.timeBased是可选类型化元数据TimeBasedCost:offPeakMultiplier(非负倍率)、peakWindows(UTC 周几,weekdays数组、Sunday = 0;start-inclusive/end-exclusive 的startMinute/endMinute),以及可选effectiveRates——每个生效费率都是一个完整的TokenCost,带effectiveFrom(Unix 毫秒)和可选longContext档位,从该时刻起整体替换基础卡。KDL 侧的语法在 src/compat/rules/README.md:time-based-cost使用具名子对象(morning、afternoon、flash-pricing等任意唯一名),weekdays是逗号分隔的无空格 UTC 周几串。
用户侧的计价约定(以 DeepSeek 为例)
KDL 中的调度会物化为ModelCost.timeBased,但不会给编码 Agent 的models.yml增加timeBased输入字段。用户侧行为见 docs/models.md:
- OMP 以助理消息的请求开始时间戳为整次请求选择费率卡与档位;跨边界请求如何计费是“估算约定”而非对服务端账单的断言——能拿到 provider 上报的货币成本时优先用它。
- 已完成的会话保留已记录的金额,跨定价边界、切换模型或重开会话都不会重估历史。
- 状态栏的
cost段在当前激活的 provider/model 上按墙钟追加↑(peak)或↓(off-peak)箭头,并在档位切换时即使空闲也刷新;无调度价格的模型不显示箭头。 models.yml显式cost(含modelOverrides)是平坦价格覆盖,会禁用该模型继承的分时定价;省略cost则保留目录定价。自定义模型省略cost时会继承其参考行的费率卡与调度(按模型 id 查表并优先取限额最宽的行)。
真实的 DeepSeek 规则就在 providers/deepseek.kdl:deepseek-flash、deepseek-v4-flash、deepseek-v4-flash-vision-exp共享 Flash 费率卡——peak 时段为周一至周五 UTC 01:00–04:00 与 06:00–10:00,其余时间(含周末)5 折;deepseek-v4-pro初始按 $1.32/$0.044/$3.96(输入/缓存读/输出,每百万 token)计费,自2026-09-14 04:00 UTC起改用 Flash 费率卡(effective-rates的flash-pricing条目),调度不变。文件内以residue:注释保留了“为什么这些残留必须存在”的证据(如 Flash 定价名称不是 taxonomy 家族、上游发现未播种 bare alias 限额需limits-patch补足 1M 上下文/384K 输出)。由于这是目录策略元数据,它并非编码 Agentmodels.yml支持的调度语法——两者边界清晰。
测试与质量保障
gen:compat之后可用以下命令验证规则树与引擎的一致性(语法详见 src/compat/rules/README.md):
cd packages/catalog bun run gen:compat # compiles rules/ → src/compat/rules.json (committed) bun test test/compat-compile.test.ts test/compat-conformance.test.ts \ test/compat-taxonomy.test.ts test/compat-cascade.test.ts test/compat-parity.test.ts测试目录 packages/catalog/test 覆盖面极广:compat-compile防漂移、compat-parity证明引擎复现全部已烘焙值、time-based-pricing/long-context-pricing覆盖计价、model-thinking/model-tokenizer覆盖运行期推理辅助,还有一批issue-NNNN-repro.test.ts回归用例(如github-copilot-model-limits、codex-discovery、nanogpt-model-limits),以及海量单提供商测试(Azure、Bedrock、Cerebras、Fireworks、Groq、Moonshot、Ollama、SiliconFlow、Together、xAI 等),说明每个 provider 的发现与 wire 行为都有专门用例守护。
小结
@oh-my-pi/pi-catalog是 oh-my-pi 的“模型常识层”:静态内置库保证离线可用与确定性,KDL 策略树把身份/兼容性/定价/鉴权等易变事实集中为可审计、可生成的声明式源,运行期发现则负责把真实世界的端点映射回这套语义。对使用者而言,最需要记住的三件事是:不要手改models.json/rules.json(改.kdl后重跑gen:compat/gen:models并一起提交);定价 API 一律传请求开始时间戳并在显示时保留金额;以及KDL 调度只是目录元数据,models.yml的timeBased并不存在——需要调整分时定价时,正确的位置是src/compat/rules/下的 KDL 文件。
【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考