@linxiraos/pi-catalog 1.1.7 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. package/CHANGELOG.md +7 -8
  2. package/README.md +9 -8
  3. package/package.json +96 -100
  4. package/src/build.ts +165 -48
  5. package/src/cline-pass-model-id.ts +11 -0
  6. package/src/compat/anthropic.ts +15 -136
  7. package/src/compat/auth-ids.ts +157 -0
  8. package/src/compat/auth.ts +60 -0
  9. package/src/compat/axes.ts +301 -0
  10. package/src/compat/behavior.ts +207 -0
  11. package/src/compat/cascade.ts +230 -0
  12. package/src/{variant-collapse.ts → compat/collapse.ts} +381 -773
  13. package/src/compat/delegation.ts +37 -0
  14. package/src/compat/openai.ts +17 -848
  15. package/src/compat/resolve.ts +1231 -0
  16. package/src/compat/revision.ts +154 -0
  17. package/src/compat/rules/README.md +315 -0
  18. package/src/compat/rules/auth/_order.kdl +13 -0
  19. package/src/compat/rules/auth/abliteration.kdl +9 -0
  20. package/src/compat/rules/auth/aiand.kdl +9 -0
  21. package/src/compat/rules/auth/aimlapi.kdl +3 -0
  22. package/src/compat/rules/auth/alibaba-coding-plan.kdl +5 -0
  23. package/src/compat/rules/auth/alibaba-token-plan.kdl +11 -0
  24. package/src/compat/rules/auth/amazon-bedrock.kdl +5 -0
  25. package/src/compat/rules/auth/anthropic.kdl +53 -0
  26. package/src/compat/rules/auth/azure.kdl +3 -0
  27. package/src/compat/rules/auth/baseten.kdl +9 -0
  28. package/src/compat/rules/auth/bedrock-mantle.kdl +5 -0
  29. package/src/compat/rules/auth/cerebras.kdl +9 -0
  30. package/src/compat/rules/auth/cline-pass.kdl +12 -0
  31. package/src/compat/rules/auth/cloudflare-ai-gateway.kdl +4 -0
  32. package/src/compat/rules/auth/coreweave.kdl +9 -0
  33. package/src/compat/rules/auth/cursor.kdl +5 -0
  34. package/src/compat/rules/auth/deepinfra.kdl +11 -0
  35. package/src/compat/rules/auth/deepseek.kdl +10 -0
  36. package/src/compat/rules/auth/devin.kdl +28 -0
  37. package/src/compat/rules/auth/exa.kdl +9 -0
  38. package/src/compat/rules/auth/firepass.kdl +14 -0
  39. package/src/compat/rules/auth/fireworks.kdl +16 -0
  40. package/src/compat/rules/auth/github-copilot.kdl +7 -0
  41. package/src/compat/rules/auth/gitlab-duo-agent.kdl +23 -0
  42. package/src/compat/rules/auth/gitlab-duo.kdl +24 -0
  43. package/src/compat/rules/auth/gmi-cloud.kdl +9 -0
  44. package/src/compat/rules/auth/google-antigravity.kdl +28 -0
  45. package/src/compat/rules/auth/google-gemini-cli.kdl +26 -0
  46. package/src/compat/rules/auth/google-vertex.kdl +5 -0
  47. package/src/compat/rules/auth/google.kdl +3 -0
  48. package/src/compat/rules/auth/groq.kdl +3 -0
  49. package/src/compat/rules/auth/huggingface.kdl +9 -0
  50. package/src/compat/rules/auth/kagi.kdl +9 -0
  51. package/src/compat/rules/auth/kilo.kdl +4 -0
  52. package/src/compat/rules/auth/kimi-code.kdl +18 -0
  53. package/src/compat/rules/auth/litellm.kdl +8 -0
  54. package/src/compat/rules/auth/llama.cpp.kdl +10 -0
  55. package/src/compat/rules/auth/lm-studio.kdl +7 -0
  56. package/src/compat/rules/auth/meta.kdl +9 -0
  57. package/src/compat/rules/auth/minimax-code-cn.kdl +9 -0
  58. package/src/compat/rules/auth/minimax-code.kdl +9 -0
  59. package/src/compat/rules/auth/minimax.kdl +3 -0
  60. package/src/compat/rules/auth/mistral.kdl +3 -0
  61. package/src/compat/rules/auth/moonshot.kdl +9 -0
  62. package/src/compat/rules/auth/nanogpt.kdl +9 -0
  63. package/src/compat/rules/auth/novita.kdl +12 -0
  64. package/src/compat/rules/auth/nvidia.kdl +11 -0
  65. package/src/compat/rules/auth/ollama-cloud.kdl +8 -0
  66. package/src/compat/rules/auth/ollama.kdl +9 -0
  67. package/src/compat/rules/auth/openai-codex-device.kdl +20 -0
  68. package/src/compat/rules/auth/openai-codex.kdl +33 -0
  69. package/src/compat/rules/auth/openai.kdl +3 -0
  70. package/src/compat/rules/auth/opencode-go.kdl +10 -0
  71. package/src/compat/rules/auth/opencode-zen.kdl +9 -0
  72. package/src/compat/rules/auth/openrouter.kdl +32 -0
  73. package/src/compat/rules/auth/parallel.kdl +9 -0
  74. package/src/compat/rules/auth/perplexity.kdl +7 -0
  75. package/src/compat/rules/auth/qianfan.kdl +9 -0
  76. package/src/compat/rules/auth/qwen-portal.kdl +9 -0
  77. package/src/compat/rules/auth/sakana.kdl +9 -0
  78. package/src/compat/rules/auth/siliconflow-cn.kdl +9 -0
  79. package/src/compat/rules/auth/siliconflow.kdl +9 -0
  80. package/src/compat/rules/auth/synthetic.kdl +9 -0
  81. package/src/compat/rules/auth/tavily.kdl +9 -0
  82. package/src/compat/rules/auth/together.kdl +14 -0
  83. package/src/compat/rules/auth/umans.kdl +9 -0
  84. package/src/compat/rules/auth/venice.kdl +9 -0
  85. package/src/compat/rules/auth/vercel-ai-gateway.kdl +8 -0
  86. package/src/compat/rules/auth/vllm.kdl +9 -0
  87. package/src/compat/rules/auth/wafer-serverless.kdl +11 -0
  88. package/src/compat/rules/auth/xai-oauth.kdl +27 -0
  89. package/src/compat/rules/auth/xai.kdl +9 -0
  90. package/src/compat/rules/auth/xiaomi-token-plan-ams.kdl +9 -0
  91. package/src/compat/rules/auth/xiaomi-token-plan-cn.kdl +9 -0
  92. package/src/compat/rules/auth/xiaomi-token-plan-sgp.kdl +9 -0
  93. package/src/compat/rules/auth/xiaomi.kdl +6 -0
  94. package/src/compat/rules/auth/yolo-auto.kdl +11 -0
  95. package/src/compat/rules/auth/zai-coding-plan.kdl +33 -0
  96. package/src/compat/rules/auth/zai.kdl +9 -0
  97. package/src/compat/rules/auth/zenmux.kdl +9 -0
  98. package/src/compat/rules/auth/zhipu-coding-plan.kdl +9 -0
  99. package/src/compat/rules/classes/amazon.kdl +21 -0
  100. package/src/compat/rules/classes/anthropic.kdl +285 -0
  101. package/src/compat/rules/classes/baidu.kdl +9 -0
  102. package/src/compat/rules/classes/bytedance.kdl +9 -0
  103. package/src/compat/rules/classes/cohere.kdl +7 -0
  104. package/src/compat/rules/classes/deepseek.kdl +80 -0
  105. package/src/compat/rules/classes/gemini.kdl +107 -0
  106. package/src/compat/rules/classes/gemma.kdl +14 -0
  107. package/src/compat/rules/classes/glm.kdl +115 -0
  108. package/src/compat/rules/classes/gpt-oss.kdl +16 -0
  109. package/src/compat/rules/classes/kimi.kdl +113 -0
  110. package/src/compat/rules/classes/meta.kdl +15 -0
  111. package/src/compat/rules/classes/mimo.kdl +32 -0
  112. package/src/compat/rules/classes/minimax.kdl +79 -0
  113. package/src/compat/rules/classes/mistral.kdl +19 -0
  114. package/src/compat/rules/classes/openai.kdl +58 -0
  115. package/src/compat/rules/classes/qwen.kdl +72 -0
  116. package/src/compat/rules/classes/stepfun.kdl +10 -0
  117. package/src/compat/rules/classes/xai.kdl +45 -0
  118. package/src/compat/rules/providers/abliteration.kdl +8 -0
  119. package/src/compat/rules/providers/aiand.kdl +19 -0
  120. package/src/compat/rules/providers/aimlapi.kdl +24 -0
  121. package/src/compat/rules/providers/alibaba-coding-plan.kdl +20 -0
  122. package/src/compat/rules/providers/alibaba-token-plan.kdl +35 -0
  123. package/src/compat/rules/providers/amazon-bedrock.kdl +36 -0
  124. package/src/compat/rules/providers/anthropic.kdl +24 -0
  125. package/src/compat/rules/providers/azure.kdl +19 -0
  126. package/src/compat/rules/providers/baseten.kdl +19 -0
  127. package/src/compat/rules/providers/bedrock-mantle.kdl +15 -0
  128. package/src/compat/rules/providers/cerebras.kdl +19 -0
  129. package/src/compat/rules/providers/cline-pass.kdl +8 -0
  130. package/src/compat/rules/providers/cloudflare-ai-gateway.kdl +26 -0
  131. package/src/compat/rules/providers/coreweave.kdl +16 -0
  132. package/src/compat/rules/providers/cursor.kdl +52 -0
  133. package/src/compat/rules/providers/deepseek.kdl +21 -0
  134. package/src/compat/rules/providers/firepass.kdl +15 -0
  135. package/src/compat/rules/providers/fireworks.kdl +43 -0
  136. package/src/compat/rules/providers/github-copilot.kdl +62 -0
  137. package/src/compat/rules/providers/gitlab-duo.kdl +24 -0
  138. package/src/compat/rules/providers/gmi-cloud.kdl +8 -0
  139. package/src/compat/rules/providers/google-antigravity.kdl +59 -0
  140. package/src/compat/rules/providers/google-gemini-cli.kdl +12 -0
  141. package/src/compat/rules/providers/google-vertex.kdl +25 -0
  142. package/src/compat/rules/providers/google.kdl +17 -0
  143. package/src/compat/rules/providers/groq.kdl +8 -0
  144. package/src/compat/rules/providers/huggingface.kdl +24 -0
  145. package/src/compat/rules/providers/kilo.kdl +51 -0
  146. package/src/compat/rules/providers/kimi-code.kdl +37 -0
  147. package/src/compat/rules/providers/llama.cpp.kdl +6 -0
  148. package/src/compat/rules/providers/lm-studio.kdl +6 -0
  149. package/src/compat/rules/providers/meta.kdl +10 -0
  150. package/src/compat/rules/providers/minimax-code-cn.kdl +13 -0
  151. package/src/compat/rules/providers/minimax-code.kdl +13 -0
  152. package/src/compat/rules/providers/minimax.kdl +6 -0
  153. package/src/compat/rules/providers/mistral.kdl +8 -0
  154. package/src/compat/rules/providers/moonshot.kdl +36 -0
  155. package/src/compat/rules/providers/nanogpt.kdl +100 -0
  156. package/src/compat/rules/providers/novita.kdl +34 -0
  157. package/src/compat/rules/providers/nvidia.kdl +27 -0
  158. package/src/compat/rules/providers/ollama-cloud.kdl +20 -0
  159. package/src/compat/rules/providers/ollama.kdl +12 -0
  160. package/src/compat/rules/providers/openai-codex.kdl +121 -0
  161. package/src/compat/rules/providers/openai.kdl +82 -0
  162. package/src/compat/rules/providers/opencode-go.kdl +97 -0
  163. package/src/compat/rules/providers/opencode-zen.kdl +103 -0
  164. package/src/compat/rules/providers/openrouter.kdl +66 -0
  165. package/src/compat/rules/providers/qianfan.kdl +8 -0
  166. package/src/compat/rules/providers/sakana.kdl +10 -0
  167. package/src/compat/rules/providers/synthetic.kdl +16 -0
  168. package/src/compat/rules/providers/together.kdl +22 -0
  169. package/src/compat/rules/providers/umans.kdl +28 -0
  170. package/src/compat/rules/providers/venice.kdl +46 -0
  171. package/src/compat/rules/providers/vercel-ai-gateway.kdl +73 -0
  172. package/src/compat/rules/providers/vllm.kdl +8 -0
  173. package/src/compat/rules/providers/wafer-serverless.kdl +35 -0
  174. package/src/compat/rules/providers/xai-oauth.kdl +48 -0
  175. package/src/compat/rules/providers/xai.kdl +50 -0
  176. package/src/compat/rules/providers/xiaomi-token-plan-ams.kdl +9 -0
  177. package/src/compat/rules/providers/xiaomi-token-plan-cn.kdl +9 -0
  178. package/src/compat/rules/providers/xiaomi-token-plan-sgp.kdl +9 -0
  179. package/src/compat/rules/providers/xiaomi.kdl +22 -0
  180. package/src/compat/rules/providers/yolo-auto.kdl +16 -0
  181. package/src/compat/rules/providers/zai.kdl +36 -0
  182. package/src/compat/rules/providers/zenmux.kdl +108 -0
  183. package/src/compat/rules/providers/zhipu-coding-plan.kdl +49 -0
  184. package/src/compat/rules/runtime/behavior.kdl +254 -0
  185. package/src/compat/rules/taxonomy/_collapse.kdl +747 -0
  186. package/src/compat/rules/taxonomy/_discovery.kdl +60 -0
  187. package/src/compat/rules/taxonomy/ai21.kdl +6 -0
  188. package/src/compat/rules/taxonomy/amazon.kdl +8 -0
  189. package/src/compat/rules/taxonomy/anthropic.kdl +17 -0
  190. package/src/compat/rules/taxonomy/baidu.kdl +5 -0
  191. package/src/compat/rules/taxonomy/bytedance.kdl +5 -0
  192. package/src/compat/rules/taxonomy/cohere.kdl +6 -0
  193. package/src/compat/rules/taxonomy/deepseek.kdl +18 -0
  194. package/src/compat/rules/taxonomy/gemini.kdl +9 -0
  195. package/src/compat/rules/taxonomy/gemma.kdl +3 -0
  196. package/src/compat/rules/taxonomy/glm.kdl +17 -0
  197. package/src/compat/rules/taxonomy/gpt-oss.kdl +11 -0
  198. package/src/compat/rules/taxonomy/kimi.kdl +20 -0
  199. package/src/compat/rules/taxonomy/meta.kdl +10 -0
  200. package/src/compat/rules/taxonomy/mimo.kdl +7 -0
  201. package/src/compat/rules/taxonomy/minimax.kdl +9 -0
  202. package/src/compat/rules/taxonomy/mistral.kdl +7 -0
  203. package/src/compat/rules/taxonomy/openai.kdl +43 -0
  204. package/src/compat/rules/taxonomy/qwen.kdl +33 -0
  205. package/src/compat/rules/taxonomy/stepfun.kdl +5 -0
  206. package/src/compat/rules/taxonomy/unknown.kdl +3 -0
  207. package/src/compat/rules/taxonomy/xai.kdl +12 -0
  208. package/src/compat/rules.d.json.ts +5 -0
  209. package/src/compat/rules.json +16984 -0
  210. package/src/compat/taxonomy.ts +452 -0
  211. package/src/compat/types.ts +588 -0
  212. package/src/discovery/antigravity.ts +5 -6
  213. package/src/discovery/codex.ts +22 -7
  214. package/src/discovery/cursor-proto.ts +7 -7
  215. package/src/discovery/cursor.ts +47 -58
  216. package/src/discovery/devin-proto.ts +613 -0
  217. package/src/discovery/devin.ts +358 -52
  218. package/src/discovery/gemini-cli.ts +14 -11
  219. package/src/discovery/gemini.ts +2 -0
  220. package/src/identity/dialect.ts +2 -2
  221. package/src/identity/id.ts +12 -0
  222. package/src/identity/index.ts +3 -3
  223. package/src/identity/metrics.ts +165 -0
  224. package/src/identity/reference.ts +37 -5
  225. package/src/index.ts +1 -1
  226. package/src/model-manager.ts +19 -6
  227. package/src/model-thinking.ts +6 -810
  228. package/src/model-tokenizer.ts +37 -44
  229. package/src/models.json +89584 -22358
  230. package/src/models.ts +6 -1
  231. package/src/provider-models/bundled-references.ts +3 -1
  232. package/src/provider-models/cline-pass.ts +226 -0
  233. package/src/provider-models/descriptors.ts +18 -0
  234. package/src/provider-models/google.ts +14 -5
  235. package/src/provider-models/models-dev-policies.ts +4 -29
  236. package/src/provider-models/ollama.ts +15 -2
  237. package/src/provider-models/openai-compat.ts +798 -520
  238. package/src/provider-models/special.ts +211 -12
  239. package/src/types.ts +214 -11
  240. package/src/wire/cline-pass.ts +35 -0
  241. package/src/wire/codex.ts +23 -2
  242. package/src/wire/devin-proto.ts +30 -0
  243. package/src/wire/devin.ts +72 -0
  244. package/src/wire/github-copilot.ts +49 -7
  245. package/THIRD-PARTY-NOTICES.txt +0 -22909
  246. package/dist/types/build.d.ts +0 -19
  247. package/dist/types/compat/anthropic.d.ts +0 -18
  248. package/dist/types/compat/apply.d.ts +0 -7
  249. package/dist/types/compat/bedrock.d.ts +0 -3
  250. package/dist/types/compat/devin.d.ts +0 -9
  251. package/dist/types/compat/openai.d.ts +0 -28
  252. package/dist/types/discovery/antigravity.d.ts +0 -70
  253. package/dist/types/discovery/codex.d.ts +0 -36
  254. package/dist/types/discovery/cursor-proto.d.ts +0 -5368
  255. package/dist/types/discovery/cursor.d.ts +0 -29
  256. package/dist/types/discovery/devin-proto.d.ts +0 -1549
  257. package/dist/types/discovery/devin.d.ts +0 -24
  258. package/dist/types/discovery/gemini-cli.d.ts +0 -33
  259. package/dist/types/discovery/gemini.d.ts +0 -25
  260. package/dist/types/discovery/gitlab-duo-workflow.d.ts +0 -30
  261. package/dist/types/discovery/index.d.ts +0 -7
  262. package/dist/types/discovery/openai-compatible.d.ts +0 -89
  263. package/dist/types/discovery/protobuf.d.ts +0 -102
  264. package/dist/types/effort.d.ts +0 -10
  265. package/dist/types/fireworks-model-id.d.ts +0 -23
  266. package/dist/types/hosts.d.ts +0 -169
  267. package/dist/types/identity/bundled.d.ts +0 -3
  268. package/dist/types/identity/classify.d.ts +0 -69
  269. package/dist/types/identity/dialect.d.ts +0 -3
  270. package/dist/types/identity/family.d.ts +0 -243
  271. package/dist/types/identity/id.d.ts +0 -12
  272. package/dist/types/identity/index.d.ts +0 -8
  273. package/dist/types/identity/markers.d.ts +0 -4
  274. package/dist/types/identity/priority.d.ts +0 -1
  275. package/dist/types/identity/reference.d.ts +0 -29
  276. package/dist/types/index.d.ts +0 -19
  277. package/dist/types/model-cache.d.ts +0 -23
  278. package/dist/types/model-manager.d.ts +0 -93
  279. package/dist/types/model-thinking.d.ts +0 -81
  280. package/dist/types/model-tokenizer.d.ts +0 -8
  281. package/dist/types/models.d.ts +0 -17
  282. package/dist/types/openai-pricing.d.ts +0 -17
  283. package/dist/types/provider-models/bundled-references.d.ts +0 -13
  284. package/dist/types/provider-models/cache-provider-id.d.ts +0 -11
  285. package/dist/types/provider-models/descriptor-types.d.ts +0 -76
  286. package/dist/types/provider-models/descriptors.d.ts +0 -524
  287. package/dist/types/provider-models/google.d.ts +0 -29
  288. package/dist/types/provider-models/index.d.ts +0 -7
  289. package/dist/types/provider-models/models-dev-policies.d.ts +0 -8
  290. package/dist/types/provider-models/ollama.d.ts +0 -22
  291. package/dist/types/provider-models/openai-compat.d.ts +0 -703
  292. package/dist/types/provider-models/special.d.ts +0 -53
  293. package/dist/types/types.d.ts +0 -879
  294. package/dist/types/utils.d.ts +0 -20
  295. package/dist/types/variant-collapse.d.ts +0 -146
  296. package/dist/types/wire/alibaba-token-plan.d.ts +0 -22
  297. package/dist/types/wire/cloudflare-ai-gateway.d.ts +0 -18
  298. package/dist/types/wire/codex.d.ts +0 -66
  299. package/dist/types/wire/coreweave.d.ts +0 -12
  300. package/dist/types/wire/gemini-headers.d.ts +0 -62
  301. package/dist/types/wire/github-copilot.d.ts +0 -47
  302. package/dist/types/wire/image-fetchers.d.ts +0 -76
  303. package/src/compat/bedrock.ts +0 -153
  304. package/src/compat/devin.ts +0 -12
  305. package/src/identity/classify.ts +0 -242
  306. package/src/identity/family.ts +0 -496
  307. package/src/identity/markers.ts +0 -49
  308. package/src/openai-pricing.ts +0 -29
@@ -1,9 +1,14 @@
1
- import { once } from "@linxiraos/pi-utils";
1
+ import { logger, once } from "@linxiraos/pi-utils";
2
+ import { buildModel } from "../build";
3
+ import { apiRouteFor } from "../compat/behavior";
2
4
  import { type CodexModelDiscoveryResult, fetchCodexModels } from "../discovery/codex";
3
5
  import type { DevinModelDiscoveryOptions } from "../discovery/devin";
4
6
  import { buildGitLabDuoWorkflowFallbackModel, fetchGitLabDuoWorkflowModels } from "../discovery/gitlab-duo-workflow";
5
7
  import type { ModelManagerOptions } from "../model-manager";
6
- import type { FetchImpl, ModelSpec } from "../types";
8
+ import { getBundledModel } from "../models";
9
+ import type { Api, FetchImpl, Model, ModelSpec } from "../types";
10
+ import { DEVIN_DEFAULT_BASE_URL } from "../wire/devin";
11
+ import { toModelSpec } from "./bundled-references";
7
12
  import { resolveModelCacheProviderId } from "./cache-provider-id";
8
13
 
9
14
  // ---------------------------------------------------------------------------
@@ -50,14 +55,15 @@ export function openaiCodexModelManagerOptions(
50
55
  const accounts = await resolveAccounts();
51
56
  if (!accounts || accounts.length === 0) return null;
52
57
  const results = await Promise.all(
53
- accounts.map(account =>
54
- fetchCodexModels({
58
+ accounts.map(async account => ({
59
+ accountId: account.accountId,
60
+ result: await fetchCodexModels({
55
61
  accessToken: account.accessToken,
56
62
  accountId: account.accountId,
57
63
  clientVersion,
58
64
  fetchFn: fetch,
59
65
  }),
60
- ),
66
+ })),
61
67
  );
62
68
  return unionCodexModels(results);
63
69
  },
@@ -68,21 +74,35 @@ export function openaiCodexModelManagerOptions(
68
74
 
69
75
  /**
70
76
  * Merge complete per-account Codex catalogs into one authoritative list,
71
- * deduped by model id (first account to expose an id wins). Returns `null` when
72
- * any account's fetch failed, so a partial list cannot replace the previous or
73
- * bundled authoritative catalog.
77
+ * deduped by model id (first account to expose an id wins).
78
+ *
79
+ * Returns `null` when any account's fetch failed transiently, so a partial list
80
+ * cannot replace the previous or bundled authoritative catalog. An account
81
+ * whose credential the backend rejected outright (401/403 — revoked or
82
+ * deauthorized) contributes nothing and is skipped instead: it would otherwise
83
+ * veto every sibling account's models until the user removes it. If no account
84
+ * produced a catalog, discovery aborts the same way.
74
85
  */
75
86
  function unionCodexModels(
76
- results: readonly (CodexModelDiscoveryResult | null)[],
87
+ results: readonly { accountId: string | undefined; result: CodexModelDiscoveryResult | null }[],
77
88
  ): ModelSpec<"openai-codex-responses">[] | null {
78
89
  const byId = new Map<string, ModelSpec<"openai-codex-responses">>();
79
- for (const result of results) {
90
+ let catalogs = 0;
91
+ for (const { accountId, result } of results) {
80
92
  if (!result) return null;
93
+ if (result.rejectedStatus !== undefined) {
94
+ logger.warn("Codex model discovery skipped an account whose credential was rejected", {
95
+ accountId,
96
+ status: result.rejectedStatus,
97
+ });
98
+ continue;
99
+ }
100
+ catalogs++;
81
101
  for (const model of result.models) {
82
102
  if (!byId.has(model.id)) byId.set(model.id, model);
83
103
  }
84
104
  }
85
- return [...byId.values()];
105
+ return catalogs > 0 ? [...byId.values()] : null;
86
106
  }
87
107
 
88
108
  // ---------------------------------------------------------------------------
@@ -113,6 +133,131 @@ export function cursorModelManagerOptions(config: CursorModelManagerConfig = {})
113
133
 
114
134
  const cursorDiscovery = once(() => import("../discovery/cursor"));
115
135
 
136
+ // ---------------------------------------------------------------------------
137
+ // GitLab Duo Chat
138
+ // ---------------------------------------------------------------------------
139
+
140
+ const GITLAB_DUO_ANTHROPIC_BASE_URL = "https://cloud.gitlab.com/ai/v1/proxy/anthropic/";
141
+ const GITLAB_DUO_OPENAI_BASE_URL = "https://cloud.gitlab.com/ai/v1/proxy/openai/v1";
142
+
143
+ export type GitLabDuoModelIdentity = {
144
+ upstreamModelId: string;
145
+ referenceProvider: "anthropic" | "openai";
146
+ referenceModelId: string;
147
+ };
148
+
149
+ /**
150
+ * Duo's public aliases are deployment identity, not model metadata. The
151
+ * reference ids select bundled first-party rows; capabilities, prices, and
152
+ * limits are copied from those rows rather than repeated here.
153
+ */
154
+ const GITLAB_DUO_MODEL_IDENTITIES: Readonly<Record<string, GitLabDuoModelIdentity>> = {
155
+ "duo-chat-opus-4-6": {
156
+ upstreamModelId: "claude-opus-4-6",
157
+ referenceProvider: "anthropic",
158
+ referenceModelId: "claude-opus-4-6",
159
+ },
160
+ "duo-chat-sonnet-4-6": {
161
+ upstreamModelId: "claude-sonnet-4-6",
162
+ referenceProvider: "anthropic",
163
+ referenceModelId: "claude-sonnet-4-6",
164
+ },
165
+ "duo-chat-opus-4-5": {
166
+ upstreamModelId: "claude-opus-4-5-20251101",
167
+ referenceProvider: "anthropic",
168
+ referenceModelId: "claude-opus-4-5-20251101",
169
+ },
170
+ "duo-chat-sonnet-4-5": {
171
+ upstreamModelId: "claude-sonnet-4-5-20250929",
172
+ referenceProvider: "anthropic",
173
+ referenceModelId: "claude-sonnet-4-5-20250929",
174
+ },
175
+ "duo-chat-haiku-4-5": {
176
+ upstreamModelId: "claude-haiku-4-5-20251001",
177
+ referenceProvider: "anthropic",
178
+ referenceModelId: "claude-haiku-4-5-20251001",
179
+ },
180
+ "duo-chat-gpt-5-1": {
181
+ upstreamModelId: "gpt-5.1-2025-11-13",
182
+ referenceProvider: "openai",
183
+ referenceModelId: "gpt-5.1",
184
+ },
185
+ "duo-chat-gpt-5-2": {
186
+ upstreamModelId: "gpt-5.2-2025-12-11",
187
+ referenceProvider: "openai",
188
+ referenceModelId: "gpt-5.2",
189
+ },
190
+ "duo-chat-gpt-5-mini": {
191
+ upstreamModelId: "gpt-5-mini-2025-08-07",
192
+ referenceProvider: "openai",
193
+ referenceModelId: "gpt-5-mini",
194
+ },
195
+ "duo-chat-gpt-5-codex": {
196
+ upstreamModelId: "gpt-5-codex",
197
+ referenceProvider: "openai",
198
+ referenceModelId: "gpt-5-codex",
199
+ },
200
+ "duo-chat-gpt-5-2-codex": {
201
+ upstreamModelId: "gpt-5.2-codex",
202
+ referenceProvider: "openai",
203
+ referenceModelId: "gpt-5.2-codex",
204
+ },
205
+ };
206
+
207
+ export function resolveGitLabDuoModelIdentity(modelId: string): GitLabDuoModelIdentity | undefined {
208
+ const direct = GITLAB_DUO_MODEL_IDENTITIES[modelId];
209
+ if (direct) return direct;
210
+ for (const alias in GITLAB_DUO_MODEL_IDENTITIES) {
211
+ const identity = GITLAB_DUO_MODEL_IDENTITIES[alias];
212
+ if (identity?.upstreamModelId === modelId) return identity;
213
+ }
214
+ return undefined;
215
+ }
216
+
217
+ function gitLabDuoDisplayName(alias: string): string {
218
+ const parts = alias.slice("duo-chat-".length).split("-");
219
+ const family = parts.shift();
220
+ if (!family) return alias;
221
+ const numeric: string[] = [];
222
+ while (parts[0] !== undefined && /^\d+$/.test(parts[0])) {
223
+ const part = parts.shift();
224
+ if (part !== undefined) numeric.push(part);
225
+ }
226
+ const familyName = family === "gpt" ? "GPT" : `${family[0]?.toUpperCase() ?? ""}${family.slice(1)}`;
227
+ const version = numeric.length > 0 ? `${family === "gpt" ? "-" : " "}${numeric.join(".")}` : "";
228
+ const suffix = parts.map(part => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
229
+ return `Duo Chat ${familyName}${version}${suffix ? ` ${suffix}` : ""}`;
230
+ }
231
+
232
+ export function getGitLabDuoModels(): Model<Api>[] {
233
+ const models: Model<Api>[] = [];
234
+ for (const alias in GITLAB_DUO_MODEL_IDENTITIES) {
235
+ const identity = GITLAB_DUO_MODEL_IDENTITIES[alias];
236
+ if (!identity) continue;
237
+ const reference = getBundledModel(identity.referenceProvider, identity.referenceModelId);
238
+ if (!reference) {
239
+ throw new Error(
240
+ `Missing bundled ${identity.referenceProvider}/${identity.referenceModelId} reference for ${alias}`,
241
+ );
242
+ }
243
+ const route = apiRouteFor("gitlab-duo", alias)?.api;
244
+ if (route !== "anthropic-messages" && route !== "openai-completions" && route !== "openai-responses") {
245
+ throw new Error(`Missing GitLab Duo API route for ${alias}`);
246
+ }
247
+ models.push(
248
+ buildModel({
249
+ ...toModelSpec(reference),
250
+ id: alias,
251
+ name: gitLabDuoDisplayName(alias),
252
+ api: route,
253
+ provider: "gitlab-duo",
254
+ baseUrl: route === "anthropic-messages" ? GITLAB_DUO_ANTHROPIC_BASE_URL : GITLAB_DUO_OPENAI_BASE_URL,
255
+ }),
256
+ );
257
+ }
258
+ return models;
259
+ }
260
+
116
261
  // ---------------------------------------------------------------------------
117
262
  // GitLab Duo Workflow
118
263
  // ---------------------------------------------------------------------------
@@ -185,10 +330,61 @@ export interface DevinModelManagerConfig {
185
330
  fetch?: DevinModelDiscoveryOptions["fetch"];
186
331
  }
187
332
 
333
+ /**
334
+ * Curated Devin seed — the entire bundled surface for the provider. The
335
+ * Cascade catalog is credential-scoped (gated per account/team), so catalog
336
+ * generation never fetches it: baking one account's roster into the shared
337
+ * bundle would misstate every other account's entitlements and leave zombie
338
+ * rows behind (see CREDENTIAL_SCOPED_PROVIDERS in generate-models.ts). Both
339
+ * SWE-1.6 lanes are verified live against `GetCliModelConfigs`; the
340
+ * descriptor's `defaultModel` (`swe-1-6`) must resolve synchronously at
341
+ * boot, before credential-scoped runtime discovery replaces the seed. Field
342
+ * shape mirrors `devinModelSpec` so seeded and discovered rows are
343
+ * indistinguishable downstream.
344
+ */
345
+ export const DEVIN_STATIC_MODELS: readonly ModelSpec<"devin-agent">[] = [
346
+ {
347
+ id: "swe-1-6-fast",
348
+ name: "SWE-1.6 Fast",
349
+ api: "devin-agent",
350
+ provider: "devin",
351
+ baseUrl: DEVIN_DEFAULT_BASE_URL,
352
+ reasoning: true,
353
+ // SWE-1.6 lanes ignore inline images despite upstream `supports_images`
354
+ // (see DEVIN_IMAGE_BLIND_UIDS in ../discovery/devin.ts).
355
+ input: ["text"],
356
+ supportsTools: true,
357
+ cost: { input: 0.3, output: 1.5, cacheRead: 0.03, cacheWrite: 0 },
358
+ contextWindow: 200_000,
359
+ maxTokens: 128_000,
360
+ compat: { supportsParallelToolCalls: true },
361
+ },
362
+ {
363
+ id: "swe-1-6",
364
+ name: "SWE-1.6",
365
+ api: "devin-agent",
366
+ provider: "devin",
367
+ baseUrl: DEVIN_DEFAULT_BASE_URL,
368
+ reasoning: true,
369
+ input: ["text"],
370
+ supportsTools: true,
371
+ // Included in the Coding Plan: upstream reports no cost dimensions.
372
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
373
+ contextWindow: 200_000,
374
+ maxTokens: 128_000,
375
+ compat: { supportsParallelToolCalls: true },
376
+ },
377
+ ];
378
+
188
379
  export function devinModelManagerOptions(config: DevinModelManagerConfig = {}): ModelManagerOptions<"devin-agent"> {
189
380
  const { apiKey, baseUrl, fetch } = config;
190
381
  return {
191
382
  providerId: "devin",
383
+ // A configured host serves its own Cascade deployment; keep the seed on it.
384
+ staticModels:
385
+ baseUrl === undefined || baseUrl === DEVIN_DEFAULT_BASE_URL
386
+ ? DEVIN_STATIC_MODELS
387
+ : DEVIN_STATIC_MODELS.map(model => ({ ...model, baseUrl })),
192
388
  ...(apiKey ? { dynamicModelsAuthoritative: true } : undefined),
193
389
  ...(apiKey
194
390
  ? {
@@ -208,6 +404,9 @@ const devinDiscovery = once(() => import("../discovery/devin"));
208
404
 
209
405
  export interface ZaiModelManagerConfig {}
210
406
 
211
- export function zaiModelManagerOptions(_config: ZaiModelManagerConfig = {}): ModelManagerOptions<"anthropic-messages"> {
407
+ /** Creates model-manager options for Z.AI's mixed native and Anthropic transports. */
408
+ export function zaiModelManagerOptions(
409
+ _config: ZaiModelManagerConfig = {},
410
+ ): ModelManagerOptions<"anthropic-messages" | "openai-completions"> {
212
411
  return { providerId: "zai" };
213
412
  }