@oh-my-pi/pi-catalog 15.10.11

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 (90) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/types/build.d.ts +3 -0
  3. package/dist/types/compat/anthropic.d.ts +11 -0
  4. package/dist/types/compat/apply.d.ts +7 -0
  5. package/dist/types/compat/openai.d.ts +21 -0
  6. package/dist/types/discovery/antigravity.d.ts +61 -0
  7. package/dist/types/discovery/codex.d.ts +38 -0
  8. package/dist/types/discovery/cursor-gen/agent_pb.d.ts +13022 -0
  9. package/dist/types/discovery/cursor.d.ts +23 -0
  10. package/dist/types/discovery/gemini.d.ts +25 -0
  11. package/dist/types/discovery/index.d.ts +4 -0
  12. package/dist/types/discovery/openai-compatible.d.ts +72 -0
  13. package/dist/types/effort.d.ts +9 -0
  14. package/dist/types/fireworks-model-id.d.ts +10 -0
  15. package/dist/types/hosts.d.ts +128 -0
  16. package/dist/types/identity/bundled.d.ts +6 -0
  17. package/dist/types/identity/classify.d.ts +45 -0
  18. package/dist/types/identity/equivalence.d.ts +46 -0
  19. package/dist/types/identity/family.d.ts +45 -0
  20. package/dist/types/identity/id.d.ts +12 -0
  21. package/dist/types/identity/index.d.ts +9 -0
  22. package/dist/types/identity/markers.d.ts +4 -0
  23. package/dist/types/identity/priority.d.ts +1 -0
  24. package/dist/types/identity/reference.d.ts +22 -0
  25. package/dist/types/identity/selection.d.ts +20 -0
  26. package/dist/types/index.d.ts +15 -0
  27. package/dist/types/model-cache.d.ts +17 -0
  28. package/dist/types/model-manager.d.ts +64 -0
  29. package/dist/types/model-thinking.d.ts +67 -0
  30. package/dist/types/models.d.ts +12 -0
  31. package/dist/types/provider-models/bundled-references.d.ts +11 -0
  32. package/dist/types/provider-models/descriptor-types.d.ts +74 -0
  33. package/dist/types/provider-models/descriptors.d.ts +384 -0
  34. package/dist/types/provider-models/discovery-constants.d.ts +11 -0
  35. package/dist/types/provider-models/google.d.ts +27 -0
  36. package/dist/types/provider-models/index.d.ts +6 -0
  37. package/dist/types/provider-models/ollama.d.ts +9 -0
  38. package/dist/types/provider-models/openai-compat.d.ts +385 -0
  39. package/dist/types/provider-models/special.d.ts +16 -0
  40. package/dist/types/types.d.ts +405 -0
  41. package/dist/types/utils.d.ts +5 -0
  42. package/dist/types/wire/codex.d.ts +26 -0
  43. package/dist/types/wire/gemini-headers.d.ts +18 -0
  44. package/dist/types/wire/github-copilot.d.ts +18 -0
  45. package/package.json +100 -0
  46. package/src/build.ts +40 -0
  47. package/src/compat/anthropic.ts +67 -0
  48. package/src/compat/apply.ts +15 -0
  49. package/src/compat/openai.ts +365 -0
  50. package/src/discovery/antigravity.ts +261 -0
  51. package/src/discovery/codex.ts +371 -0
  52. package/src/discovery/cursor-gen/agent_pb.ts +15274 -0
  53. package/src/discovery/cursor.ts +307 -0
  54. package/src/discovery/gemini.ts +249 -0
  55. package/src/discovery/index.ts +4 -0
  56. package/src/discovery/openai-compatible.ts +224 -0
  57. package/src/effort.ts +16 -0
  58. package/src/fireworks-model-id.ts +30 -0
  59. package/src/hosts.ts +114 -0
  60. package/src/identity/bundled.ts +38 -0
  61. package/src/identity/classify.ts +141 -0
  62. package/src/identity/equivalence.ts +870 -0
  63. package/src/identity/family.ts +88 -0
  64. package/src/identity/id.ts +81 -0
  65. package/src/identity/index.ts +9 -0
  66. package/src/identity/markers.ts +49 -0
  67. package/src/identity/priority.ts +56 -0
  68. package/src/identity/reference.ts +134 -0
  69. package/src/identity/selection.ts +65 -0
  70. package/src/index.ts +15 -0
  71. package/src/model-cache.ts +132 -0
  72. package/src/model-manager.ts +472 -0
  73. package/src/model-thinking.ts +407 -0
  74. package/src/models.json +75308 -0
  75. package/src/models.json.d.ts +9 -0
  76. package/src/models.ts +64 -0
  77. package/src/provider-models/bundled-references.ts +54 -0
  78. package/src/provider-models/descriptor-types.ts +79 -0
  79. package/src/provider-models/descriptors.ts +456 -0
  80. package/src/provider-models/discovery-constants.ts +11 -0
  81. package/src/provider-models/google.ts +105 -0
  82. package/src/provider-models/index.ts +6 -0
  83. package/src/provider-models/ollama.ts +154 -0
  84. package/src/provider-models/openai-compat.ts +3106 -0
  85. package/src/provider-models/special.ts +67 -0
  86. package/src/types.ts +470 -0
  87. package/src/utils.ts +27 -0
  88. package/src/wire/codex.ts +43 -0
  89. package/src/wire/gemini-headers.ts +41 -0
  90. package/src/wire/github-copilot.ts +72 -0
@@ -0,0 +1,9 @@
1
+ import type { Api } from "./types";
2
+
3
+ /** Typed declaration for the generated models.json — only the `api` field matters for type inference. */
4
+ declare const models: {
5
+ [provider: string]: {
6
+ [modelId: string]: { readonly api: Api; [key: string]: unknown };
7
+ };
8
+ };
9
+ export default models;
package/src/models.ts ADDED
@@ -0,0 +1,64 @@
1
+ import { buildModel } from "./build";
2
+ import MODELS from "./models.json" with { type: "json" };
3
+ import type { Api, KnownProvider, Model, ModelSpec, Usage } from "./types";
4
+
5
+ /**
6
+ * Static bundled model registry loaded from `models.json`.
7
+ *
8
+ * This module intentionally exposes compile-time defaults only.
9
+ * It does not include runtime discovery, models.dev overlays, or on-disk cache state.
10
+ *
11
+ * For runtime-aware resolution, use `createModelManager()` / `resolveProviderModels()`.
12
+ */
13
+ let modelRegistry: Map<string, Map<string, Model<Api>>> | undefined;
14
+
15
+ /** Build (once) and return the enriched bundled-model registry. Lazy: enrichment of ~12K models is deferred off module load. */
16
+ function getModelRegistry(): Map<string, Map<string, Model<Api>>> {
17
+ if (modelRegistry === undefined) {
18
+ modelRegistry = new Map();
19
+ for (const [provider, models] of Object.entries(MODELS)) {
20
+ const providerModels = new Map<string, Model<Api>>();
21
+ for (const [id, model] of Object.entries(models)) {
22
+ providerModels.set(id, buildModel(model as ModelSpec<Api>));
23
+ }
24
+ modelRegistry.set(provider, providerModels);
25
+ }
26
+ }
27
+ return modelRegistry;
28
+ }
29
+
30
+ export type GeneratedProvider = keyof typeof MODELS;
31
+
32
+ export function getBundledModel<TApi extends Api = Api>(provider: GeneratedProvider, modelId: string): Model<TApi> {
33
+ const providerModels = getModelRegistry().get(provider);
34
+ return providerModels?.get(modelId) as Model<TApi>;
35
+ }
36
+
37
+ export function getBundledProviders(): KnownProvider[] {
38
+ return Object.keys(MODELS) as KnownProvider[];
39
+ }
40
+
41
+ export function getBundledModels(provider: GeneratedProvider): Model<Api>[] {
42
+ const models = getModelRegistry().get(provider);
43
+ return models ? (Array.from(models.values()) as Model<Api>[]) : [];
44
+ }
45
+
46
+ export function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): Usage["cost"] {
47
+ usage.cost.input = (model.cost.input / 1000000) * usage.input;
48
+ usage.cost.output = (model.cost.output / 1000000) * usage.output;
49
+ usage.cost.cacheRead = (model.cost.cacheRead / 1000000) * usage.cacheRead;
50
+ usage.cost.cacheWrite = (model.cost.cacheWrite / 1000000) * usage.cacheWrite;
51
+ usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
52
+ return usage.cost;
53
+ }
54
+ /**
55
+ * Check if two models are equal by comparing both their id and provider.
56
+ * Returns false if either model is null or undefined.
57
+ */
58
+ export function modelsAreEqual<TApi extends Api>(
59
+ a: Model<TApi> | null | undefined,
60
+ b: Model<TApi> | null | undefined,
61
+ ): boolean {
62
+ if (!a || !b) return false;
63
+ return a.id === b.id && a.provider === b.provider;
64
+ }
@@ -0,0 +1,54 @@
1
+ import { getBundledModels, getBundledProviders } from "../models";
2
+ import type { Api, Model, ModelSpec } from "../types";
3
+
4
+ /**
5
+ * Project a built `Model` back to spec stage: `compat` becomes the verbatim
6
+ * sparse override record (`compatConfig`), never the resolved view. Discovery
7
+ * mappers spread these references into the specs they hand to the model
8
+ * manager, which rebuilds via `buildModel`.
9
+ */
10
+ export function toModelSpec<TApi extends Api>(model: Model<TApi>): ModelSpec<TApi> {
11
+ const { compat: _compat, compatConfig, ...rest } = model;
12
+ return { ...rest, compat: compatConfig } as ModelSpec<TApi>;
13
+ }
14
+
15
+ export function createBundledReferenceMap<TApi extends Api>(
16
+ provider: Parameters<typeof getBundledModels>[0],
17
+ ): Map<string, ModelSpec<TApi>> {
18
+ const references = new Map<string, ModelSpec<TApi>>();
19
+ for (const model of getBundledModels(provider)) {
20
+ references.set(model.id, toModelSpec(model as Model<TApi>));
21
+ }
22
+ return references;
23
+ }
24
+
25
+ export function createReferenceResolver<TApi extends Api>(
26
+ providerRefs: Map<string, ModelSpec<TApi>>,
27
+ ): (modelId: string) => ModelSpec<TApi> | undefined {
28
+ const globalRefs = new Map<string, Model<Api>>();
29
+ for (const provider of getBundledProviders()) {
30
+ for (const model of getBundledModels(provider as Parameters<typeof getBundledModels>[0])) {
31
+ const candidate = model as Model<Api>;
32
+ const existing = globalRefs.get(candidate.id);
33
+ if (!existing) {
34
+ globalRefs.set(candidate.id, candidate);
35
+ } else if (candidate.contextWindow !== existing.contextWindow) {
36
+ if (candidate.contextWindow > existing.contextWindow) {
37
+ globalRefs.set(candidate.id, candidate);
38
+ }
39
+ } else if (candidate.maxTokens !== existing.maxTokens) {
40
+ if (candidate.maxTokens > existing.maxTokens) {
41
+ globalRefs.set(candidate.id, candidate);
42
+ }
43
+ } else if (existing.provider !== "openai" && candidate.provider === "openai") {
44
+ globalRefs.set(candidate.id, candidate);
45
+ }
46
+ }
47
+ }
48
+ return (modelId: string) => {
49
+ const providerRef = providerRefs.get(modelId);
50
+ if (providerRef) return providerRef;
51
+ const globalRef = globalRefs.get(modelId);
52
+ return globalRef ? toModelSpec(globalRef as Model<TApi>) : undefined;
53
+ };
54
+ }
@@ -0,0 +1,79 @@
1
+ import type { ModelManagerOptions } from "../model-manager";
2
+ import type { Api, FetchImpl } from "../types";
3
+
4
+ /** Config passed to a provider's runtime model-manager factory. */
5
+ export type ModelManagerConfig = { apiKey?: string; baseUrl?: string; fetch?: FetchImpl };
6
+
7
+ /** Catalog discovery configuration for providers that support endpoint-based model listing. */
8
+ export interface CatalogDiscoveryConfig {
9
+ /** Human-readable name for log messages. */
10
+ label: string;
11
+ /**
12
+ * Environment variables to check for API keys during catalog generation.
13
+ * Defaults to the entry-level `envVars` when omitted.
14
+ */
15
+ envVars?: readonly string[];
16
+ /** OAuth provider for credential refresh during catalog generation. */
17
+ oauthProvider?: string;
18
+ /** When true, catalog discovery proceeds even without credentials. */
19
+ allowUnauthenticated?: boolean;
20
+ }
21
+
22
+ /** Unified provider descriptor used by both runtime discovery and catalog generation. */
23
+ export interface ProviderDescriptor {
24
+ providerId: string;
25
+ createModelManagerOptions(config: ModelManagerConfig): ModelManagerOptions<Api>;
26
+ /** Preferred model ID when no explicit selection is made. */
27
+ defaultModel: string;
28
+ /** When true, the runtime creates a model manager even without a valid API key (e.g. ollama). */
29
+ allowUnauthenticated?: boolean;
30
+ /** When true, successful runtime discovery replaces bundled provider models instead of merging fallback-only IDs. */
31
+ dynamicModelsAuthoritative?: boolean;
32
+ /** Catalog discovery configuration. Only providers with this field participate in generate-models.ts. */
33
+ catalogDiscovery?: CatalogDiscoveryConfig;
34
+ }
35
+
36
+ /** A provider descriptor that has catalog discovery configured. */
37
+ export type CatalogProviderDescriptor = ProviderDescriptor & { catalogDiscovery: CatalogDiscoveryConfig };
38
+
39
+ /** Type guard for descriptors with catalog discovery. */
40
+ export function isCatalogDescriptor(d: ProviderDescriptor): d is CatalogProviderDescriptor {
41
+ return d.catalogDiscovery != null;
42
+ }
43
+
44
+ /** Whether catalog discovery may run without provider credentials. */
45
+ export function allowsUnauthenticatedCatalogDiscovery(descriptor: CatalogProviderDescriptor): boolean {
46
+ return descriptor.catalogDiscovery.allowUnauthenticated ?? descriptor.allowUnauthenticated ?? false;
47
+ }
48
+
49
+ /**
50
+ * One model provider's catalog-side description. The auth half of a provider
51
+ * (env keys, OAuth login/refresh flows) lives in `@oh-my-pi/pi-ai`'s registry;
52
+ * the catalog table below is the single source of truth for ids, default
53
+ * models, and discovery wiring.
54
+ *
55
+ * - Every entry is a member of `KnownProvider`.
56
+ * - `createModelManagerOptions` present (and not `specialModelManager`) ⇒
57
+ * appears in `PROVIDER_DESCRIPTORS` for runtime model discovery.
58
+ * - `catalogDiscovery` present ⇒ participates in `generate-models.ts`.
59
+ */
60
+ export interface ProviderCatalogEntry {
61
+ readonly id: string;
62
+ /** Preferred model ID when no explicit selection is made. */
63
+ readonly defaultModel: string;
64
+ /** Environment variables consulted (in order) for the provider's runtime API-key env fallback. */
65
+ readonly envVars?: readonly string[];
66
+ /** Runtime model-manager factory. Omitted for catalog-only providers. */
67
+ readonly createModelManagerOptions?: (config: ModelManagerConfig) => ModelManagerOptions<Api>;
68
+ /** When true, the runtime creates a model manager even without a valid API key. */
69
+ readonly allowUnauthenticated?: boolean;
70
+ /** When true, successful runtime discovery replaces bundled provider models. */
71
+ readonly dynamicModelsAuthoritative?: boolean;
72
+ /** Catalog discovery configuration for generate-models.ts. */
73
+ readonly catalogDiscovery?: CatalogDiscoveryConfig;
74
+ /**
75
+ * Built bespoke by the coding-agent runtime (OAuth-token-driven managers);
76
+ * excluded from `PROVIDER_DESCRIPTORS` even though models are discoverable.
77
+ */
78
+ readonly specialModelManager?: boolean;
79
+ }
@@ -0,0 +1,456 @@
1
+ /**
2
+ * The provider catalog table: one entry per chat-model provider, carrying the
3
+ * catalog half of what used to live in `@oh-my-pi/pi-ai`'s registry definitions
4
+ * (default model, runtime model-manager factory, discovery wiring). The auth
5
+ * half (env keys, OAuth login/refresh) stays in the pi-ai registry, which
6
+ * type-checks itself against `KnownProvider` from this table.
7
+ */
8
+ import type { ModelManagerConfig, ProviderCatalogEntry, ProviderDescriptor } from "./descriptor-types";
9
+ import { googleModelManagerOptions, googleVertexModelManagerOptions } from "./google";
10
+ import { ollamaCloudModelManagerOptions } from "./ollama";
11
+ import {
12
+ aimlApiModelManagerOptions,
13
+ alibabaCodingPlanModelManagerOptions,
14
+ anthropicModelManagerOptions,
15
+ cerebrasModelManagerOptions,
16
+ cloudflareAiGatewayModelManagerOptions,
17
+ deepseekModelManagerOptions,
18
+ firepassModelManagerOptions,
19
+ fireworksModelManagerOptions,
20
+ githubCopilotModelManagerOptions,
21
+ groqModelManagerOptions,
22
+ huggingfaceModelManagerOptions,
23
+ kiloModelManagerOptions,
24
+ kimiCodeModelManagerOptions,
25
+ litellmModelManagerOptions,
26
+ lmStudioModelManagerOptions,
27
+ mistralModelManagerOptions,
28
+ moonshotModelManagerOptions,
29
+ nanoGptModelManagerOptions,
30
+ nvidiaModelManagerOptions,
31
+ ollamaModelManagerOptions,
32
+ openaiModelManagerOptions,
33
+ opencodeGoModelManagerOptions,
34
+ opencodeZenModelManagerOptions,
35
+ openrouterModelManagerOptions,
36
+ qianfanModelManagerOptions,
37
+ qwenPortalModelManagerOptions,
38
+ syntheticModelManagerOptions,
39
+ togetherModelManagerOptions,
40
+ veniceModelManagerOptions,
41
+ vercelAiGatewayModelManagerOptions,
42
+ vllmModelManagerOptions,
43
+ waferPassModelManagerOptions,
44
+ waferServerlessModelManagerOptions,
45
+ xaiModelManagerOptions,
46
+ xaiOAuthModelManagerOptions,
47
+ xiaomiModelManagerOptions,
48
+ zenmuxModelManagerOptions,
49
+ zhipuCodingPlanModelManagerOptions,
50
+ } from "./openai-compat";
51
+ import { cursorModelManagerOptions, zaiModelManagerOptions } from "./special";
52
+
53
+ export const CATALOG_PROVIDERS = [
54
+ {
55
+ id: "aimlapi",
56
+ defaultModel: "gpt-4o",
57
+ envVars: ["AIMLAPI_API_KEY"],
58
+ createModelManagerOptions: (config: ModelManagerConfig) => aimlApiModelManagerOptions(config),
59
+ dynamicModelsAuthoritative: true,
60
+ catalogDiscovery: { label: "AIML API" },
61
+ },
62
+ {
63
+ id: "alibaba-coding-plan",
64
+ defaultModel: "qwen3.5-plus",
65
+ envVars: ["ALIBABA_CODING_PLAN_API_KEY"],
66
+ createModelManagerOptions: (config: ModelManagerConfig) => alibabaCodingPlanModelManagerOptions(config),
67
+ catalogDiscovery: { label: "Alibaba Coding Plan" },
68
+ },
69
+ {
70
+ id: "amazon-bedrock",
71
+ defaultModel: "us.anthropic.claude-opus-4-6-v1",
72
+ },
73
+ {
74
+ id: "anthropic",
75
+ defaultModel: "claude-opus-4-6",
76
+ createModelManagerOptions: (config: ModelManagerConfig) => anthropicModelManagerOptions(config),
77
+ },
78
+ {
79
+ id: "cerebras",
80
+ defaultModel: "zai-glm-4.6",
81
+ envVars: ["CEREBRAS_API_KEY"],
82
+ createModelManagerOptions: (config: ModelManagerConfig) => cerebrasModelManagerOptions(config),
83
+ catalogDiscovery: { label: "Cerebras" },
84
+ },
85
+ {
86
+ id: "cloudflare-ai-gateway",
87
+ defaultModel: "claude-sonnet-4-5",
88
+ envVars: ["CLOUDFLARE_AI_GATEWAY_API_KEY"],
89
+ createModelManagerOptions: (config: ModelManagerConfig) => cloudflareAiGatewayModelManagerOptions(config),
90
+ catalogDiscovery: { label: "Cloudflare AI Gateway" },
91
+ },
92
+ {
93
+ id: "cursor",
94
+ defaultModel: "claude-sonnet-4-6",
95
+ envVars: ["CURSOR_ACCESS_TOKEN"],
96
+ createModelManagerOptions: (config: ModelManagerConfig) => cursorModelManagerOptions(config),
97
+ catalogDiscovery: { label: "Cursor", envVars: ["CURSOR_API_KEY"], oauthProvider: "cursor" },
98
+ },
99
+ {
100
+ id: "deepseek",
101
+ defaultModel: "deepseek-v4-pro",
102
+ envVars: ["DEEPSEEK_API_KEY"],
103
+ createModelManagerOptions: (config: ModelManagerConfig) => deepseekModelManagerOptions(config),
104
+ catalogDiscovery: { label: "DeepSeek" },
105
+ },
106
+ {
107
+ id: "firepass",
108
+ defaultModel: "kimi-k2.6-turbo",
109
+ envVars: ["FIREPASS_API_KEY"],
110
+ createModelManagerOptions: (config: ModelManagerConfig) => firepassModelManagerOptions(config),
111
+ },
112
+ {
113
+ id: "fireworks",
114
+ defaultModel: "kimi-k2.6",
115
+ envVars: ["FIREWORKS_API_KEY"],
116
+ createModelManagerOptions: (config: ModelManagerConfig) => fireworksModelManagerOptions(config),
117
+ catalogDiscovery: { label: "Fireworks" },
118
+ },
119
+ {
120
+ id: "github-copilot",
121
+ defaultModel: "gpt-4o",
122
+ envVars: ["COPILOT_GITHUB_TOKEN"],
123
+ createModelManagerOptions: (config: ModelManagerConfig) => githubCopilotModelManagerOptions(config),
124
+ },
125
+ {
126
+ id: "gitlab-duo",
127
+ defaultModel: "duo-chat-sonnet-4-5",
128
+ envVars: ["GITLAB_TOKEN"],
129
+ },
130
+ {
131
+ id: "google",
132
+ defaultModel: "gemini-2.5-pro",
133
+ envVars: ["GEMINI_API_KEY"],
134
+ createModelManagerOptions: (config: ModelManagerConfig) => googleModelManagerOptions(config),
135
+ },
136
+ {
137
+ id: "google-antigravity",
138
+ defaultModel: "gemini-3-pro-high",
139
+ specialModelManager: true,
140
+ },
141
+ {
142
+ id: "google-gemini-cli",
143
+ defaultModel: "gemini-2.5-pro",
144
+ specialModelManager: true,
145
+ },
146
+ {
147
+ id: "google-vertex",
148
+ defaultModel: "gemini-3-pro-preview",
149
+ createModelManagerOptions: (config: ModelManagerConfig) => googleVertexModelManagerOptions(config),
150
+ allowUnauthenticated: true,
151
+ },
152
+ {
153
+ id: "groq",
154
+ defaultModel: "openai/gpt-oss-120b",
155
+ envVars: ["GROQ_API_KEY"],
156
+ createModelManagerOptions: (config: ModelManagerConfig) => groqModelManagerOptions(config),
157
+ },
158
+ {
159
+ id: "huggingface",
160
+ defaultModel: "deepseek-ai/DeepSeek-R1",
161
+ envVars: ["HUGGINGFACE_HUB_TOKEN", "HF_TOKEN"],
162
+ createModelManagerOptions: (config: ModelManagerConfig) => huggingfaceModelManagerOptions(config),
163
+ catalogDiscovery: { label: "Hugging Face" },
164
+ },
165
+ {
166
+ id: "kilo",
167
+ defaultModel: "anthropic/claude-sonnet-4.5",
168
+ envVars: ["KILO_API_KEY"],
169
+ createModelManagerOptions: (config: ModelManagerConfig) => kiloModelManagerOptions(config),
170
+ catalogDiscovery: { label: "Kilo Gateway", allowUnauthenticated: true },
171
+ },
172
+ {
173
+ id: "kimi-code",
174
+ defaultModel: "kimi-k2.5",
175
+ createModelManagerOptions: (config: ModelManagerConfig) => kimiCodeModelManagerOptions(config),
176
+ catalogDiscovery: { label: "Kimi Code", envVars: ["KIMI_API_KEY"] },
177
+ },
178
+ {
179
+ id: "litellm",
180
+ defaultModel: "claude-opus-4-6",
181
+ envVars: ["LITELLM_API_KEY"],
182
+ createModelManagerOptions: (config: ModelManagerConfig) => litellmModelManagerOptions(config),
183
+ catalogDiscovery: { label: "LiteLLM", allowUnauthenticated: true },
184
+ },
185
+ {
186
+ id: "lm-studio",
187
+ defaultModel: "llama-3-8b",
188
+ envVars: ["LM_STUDIO_API_KEY"],
189
+ createModelManagerOptions: (config: ModelManagerConfig) => lmStudioModelManagerOptions(config),
190
+ allowUnauthenticated: true,
191
+ },
192
+ {
193
+ id: "minimax",
194
+ defaultModel: "MiniMax-M2.5",
195
+ envVars: ["MINIMAX_API_KEY"],
196
+ },
197
+ {
198
+ id: "minimax-code",
199
+ defaultModel: "MiniMax-M2.5",
200
+ envVars: ["MINIMAX_CODE_API_KEY"],
201
+ },
202
+ {
203
+ id: "minimax-code-cn",
204
+ defaultModel: "MiniMax-M2.5",
205
+ envVars: ["MINIMAX_CODE_CN_API_KEY"],
206
+ },
207
+ {
208
+ id: "mistral",
209
+ defaultModel: "devstral-medium-latest",
210
+ envVars: ["MISTRAL_API_KEY"],
211
+ createModelManagerOptions: (config: ModelManagerConfig) => mistralModelManagerOptions(config),
212
+ },
213
+ {
214
+ id: "moonshot",
215
+ defaultModel: "kimi-k2.5",
216
+ envVars: ["MOONSHOT_API_KEY"],
217
+ createModelManagerOptions: (config: ModelManagerConfig) => moonshotModelManagerOptions(config),
218
+ catalogDiscovery: { label: "Moonshot" },
219
+ },
220
+ {
221
+ id: "nanogpt",
222
+ defaultModel: "openai/gpt-5.4",
223
+ envVars: ["NANO_GPT_API_KEY"],
224
+ createModelManagerOptions: (config: ModelManagerConfig) => nanoGptModelManagerOptions(config),
225
+ catalogDiscovery: { label: "NanoGPT" },
226
+ },
227
+ {
228
+ id: "nvidia",
229
+ defaultModel: "nvidia/llama-3.1-nemotron-70b-instruct",
230
+ envVars: ["NVIDIA_API_KEY"],
231
+ createModelManagerOptions: (config: ModelManagerConfig) => nvidiaModelManagerOptions(config),
232
+ catalogDiscovery: { label: "NVIDIA" },
233
+ },
234
+ {
235
+ id: "ollama",
236
+ defaultModel: "gpt-oss:20b",
237
+ envVars: ["OLLAMA_API_KEY"],
238
+ createModelManagerOptions: (config: ModelManagerConfig) => ollamaModelManagerOptions(config),
239
+ allowUnauthenticated: true,
240
+ },
241
+ {
242
+ id: "ollama-cloud",
243
+ defaultModel: "gpt-oss:120b",
244
+ envVars: ["OLLAMA_CLOUD_API_KEY"],
245
+ createModelManagerOptions: (config: ModelManagerConfig) => ollamaCloudModelManagerOptions(config),
246
+ catalogDiscovery: { label: "Ollama Cloud", oauthProvider: "ollama-cloud" },
247
+ },
248
+ {
249
+ id: "openai",
250
+ defaultModel: "gpt-5.4",
251
+ envVars: ["OPENAI_API_KEY"],
252
+ createModelManagerOptions: (config: ModelManagerConfig) => openaiModelManagerOptions(config),
253
+ },
254
+ {
255
+ id: "openai-codex",
256
+ defaultModel: "gpt-5.4",
257
+ envVars: ["OPENAI_CODEX_OAUTH_TOKEN"],
258
+ specialModelManager: true,
259
+ },
260
+ {
261
+ id: "opencode-go",
262
+ defaultModel: "kimi-k2.5",
263
+ envVars: ["OPENCODE_API_KEY"],
264
+ createModelManagerOptions: (config: ModelManagerConfig) => opencodeGoModelManagerOptions(config),
265
+ },
266
+ {
267
+ id: "opencode-zen",
268
+ defaultModel: "claude-sonnet-4-6",
269
+ envVars: ["OPENCODE_API_KEY"],
270
+ createModelManagerOptions: (config: ModelManagerConfig) => opencodeZenModelManagerOptions(config),
271
+ },
272
+ {
273
+ id: "openrouter",
274
+ defaultModel: "openai/gpt-5.4",
275
+ envVars: ["OPENROUTER_API_KEY"],
276
+ createModelManagerOptions: (config: ModelManagerConfig) => openrouterModelManagerOptions(config),
277
+ catalogDiscovery: { label: "OpenRouter", allowUnauthenticated: true },
278
+ },
279
+ {
280
+ id: "qianfan",
281
+ defaultModel: "deepseek-v3.2",
282
+ envVars: ["QIANFAN_API_KEY"],
283
+ createModelManagerOptions: (config: ModelManagerConfig) => qianfanModelManagerOptions(config),
284
+ catalogDiscovery: { label: "Qianfan" },
285
+ },
286
+ {
287
+ id: "qwen-portal",
288
+ defaultModel: "coder-model",
289
+ envVars: ["QWEN_OAUTH_TOKEN", "QWEN_PORTAL_API_KEY"],
290
+ createModelManagerOptions: (config: ModelManagerConfig) => qwenPortalModelManagerOptions(config),
291
+ catalogDiscovery: {
292
+ label: "Qwen Portal",
293
+ oauthProvider: "qwen-portal",
294
+ },
295
+ },
296
+ {
297
+ id: "synthetic",
298
+ defaultModel: "hf:zai-org/GLM-5.1",
299
+ envVars: ["SYNTHETIC_API_KEY"],
300
+ createModelManagerOptions: (config: ModelManagerConfig) => syntheticModelManagerOptions(config),
301
+ dynamicModelsAuthoritative: true,
302
+ catalogDiscovery: { label: "Synthetic" },
303
+ },
304
+ {
305
+ id: "together",
306
+ defaultModel: "moonshotai/Kimi-K2.5",
307
+ envVars: ["TOGETHER_API_KEY"],
308
+ createModelManagerOptions: (config: ModelManagerConfig) => togetherModelManagerOptions(config),
309
+ catalogDiscovery: { label: "Together" },
310
+ },
311
+ {
312
+ id: "venice",
313
+ defaultModel: "llama-3.3-70b",
314
+ envVars: ["VENICE_API_KEY"],
315
+ createModelManagerOptions: (config: ModelManagerConfig) => veniceModelManagerOptions(config),
316
+ catalogDiscovery: { label: "Venice", allowUnauthenticated: true },
317
+ },
318
+ {
319
+ id: "vercel-ai-gateway",
320
+ defaultModel: "anthropic/claude-sonnet-4-6",
321
+ envVars: ["AI_GATEWAY_API_KEY"],
322
+ createModelManagerOptions: (config: ModelManagerConfig) => vercelAiGatewayModelManagerOptions(config),
323
+ catalogDiscovery: {
324
+ label: "Vercel AI Gateway",
325
+ envVars: ["VERCEL_AI_GATEWAY_API_KEY"],
326
+ allowUnauthenticated: true,
327
+ },
328
+ },
329
+ {
330
+ id: "vllm",
331
+ defaultModel: "gpt-oss-20b",
332
+ envVars: ["VLLM_API_KEY"],
333
+ createModelManagerOptions: (config: ModelManagerConfig) => vllmModelManagerOptions(config),
334
+ catalogDiscovery: { label: "vLLM", allowUnauthenticated: true },
335
+ },
336
+ {
337
+ id: "wafer-pass",
338
+ defaultModel: "GLM-5.1",
339
+ envVars: ["WAFER_PASS_API_KEY"],
340
+ createModelManagerOptions: (config: ModelManagerConfig) => waferPassModelManagerOptions(config),
341
+ catalogDiscovery: { label: "Wafer Pass", oauthProvider: "wafer-pass" },
342
+ },
343
+ {
344
+ id: "wafer-serverless",
345
+ defaultModel: "GLM-5.1",
346
+ envVars: ["WAFER_SERVERLESS_API_KEY"],
347
+ createModelManagerOptions: (config: ModelManagerConfig) => waferServerlessModelManagerOptions(config),
348
+ catalogDiscovery: {
349
+ label: "Wafer Serverless",
350
+ oauthProvider: "wafer-serverless",
351
+ },
352
+ },
353
+ {
354
+ id: "xai",
355
+ defaultModel: "grok-4-fast-non-reasoning",
356
+ envVars: ["XAI_API_KEY"],
357
+ createModelManagerOptions: (config: ModelManagerConfig) => xaiModelManagerOptions(config),
358
+ },
359
+ {
360
+ id: "xai-oauth",
361
+ defaultModel: "grok-4.3",
362
+ envVars: ["XAI_OAUTH_TOKEN", "XAI_API_KEY"],
363
+ createModelManagerOptions: (config: ModelManagerConfig) => xaiOAuthModelManagerOptions(config),
364
+ catalogDiscovery: {
365
+ label: "xAI Grok OAuth (SuperGrok)",
366
+ oauthProvider: "xai-oauth",
367
+ },
368
+ },
369
+ {
370
+ id: "xiaomi",
371
+ defaultModel: "mimo-v2-flash",
372
+ envVars: ["XIAOMI_API_KEY"],
373
+ createModelManagerOptions: (config: ModelManagerConfig) => xiaomiModelManagerOptions(config),
374
+ catalogDiscovery: { label: "Xiaomi" },
375
+ },
376
+ {
377
+ id: "xiaomi-token-plan-ams",
378
+ defaultModel: "mimo-v2.5",
379
+ envVars: ["XIAOMI_TOKEN_PLAN_AMS_API_KEY"],
380
+ createModelManagerOptions: (config: ModelManagerConfig) =>
381
+ xiaomiModelManagerOptions({ ...config, providerId: "xiaomi-token-plan-ams", tokenPlanRegion: "ams" }),
382
+ },
383
+ {
384
+ id: "xiaomi-token-plan-cn",
385
+ defaultModel: "mimo-v2.5",
386
+ envVars: ["XIAOMI_TOKEN_PLAN_CN_API_KEY"],
387
+ createModelManagerOptions: (config: ModelManagerConfig) =>
388
+ xiaomiModelManagerOptions({ ...config, providerId: "xiaomi-token-plan-cn", tokenPlanRegion: "cn" }),
389
+ },
390
+ {
391
+ id: "xiaomi-token-plan-sgp",
392
+ defaultModel: "mimo-v2.5",
393
+ envVars: ["XIAOMI_TOKEN_PLAN_SGP_API_KEY"],
394
+ createModelManagerOptions: (config: ModelManagerConfig) =>
395
+ xiaomiModelManagerOptions({ ...config, providerId: "xiaomi-token-plan-sgp", tokenPlanRegion: "sgp" }),
396
+ },
397
+ {
398
+ id: "zai",
399
+ defaultModel: "glm-5.1",
400
+ envVars: ["ZAI_API_KEY"],
401
+ createModelManagerOptions: (config: ModelManagerConfig) => zaiModelManagerOptions(config),
402
+ catalogDiscovery: { label: "zAI" },
403
+ },
404
+ {
405
+ id: "zenmux",
406
+ defaultModel: "anthropic/claude-opus-4.6",
407
+ envVars: ["ZENMUX_API_KEY"],
408
+ createModelManagerOptions: (config: ModelManagerConfig) => zenmuxModelManagerOptions(config),
409
+ catalogDiscovery: { label: "ZenMux" },
410
+ },
411
+ {
412
+ id: "zhipu-coding-plan",
413
+ defaultModel: "glm-5.1",
414
+ envVars: ["ZHIPU_API_KEY"],
415
+ createModelManagerOptions: (config: ModelManagerConfig) => zhipuCodingPlanModelManagerOptions(config),
416
+ catalogDiscovery: { label: "Zhipu Coding Plan" },
417
+ },
418
+ ] as const satisfies readonly ProviderCatalogEntry[];
419
+
420
+ /** Chat-model providers — every entry in the catalog table. */
421
+ export type KnownProvider = (typeof CATALOG_PROVIDERS)[number]["id"];
422
+
423
+ /**
424
+ * Runtime model-discovery descriptors: every catalog provider that exposes a
425
+ * standard model-manager factory. Special-managed providers
426
+ * (`google-antigravity`/`google-gemini-cli`/`openai-codex`) are built bespoke in
427
+ * the coding-agent runtime and are excluded here.
428
+ */
429
+ const CATALOG_ENTRY_LIST: readonly ProviderCatalogEntry[] = CATALOG_PROVIDERS;
430
+
431
+ export const PROVIDER_DESCRIPTORS: readonly ProviderDescriptor[] = CATALOG_ENTRY_LIST.flatMap(provider => {
432
+ if (!provider.createModelManagerOptions || provider.specialModelManager) {
433
+ return [];
434
+ }
435
+ return [
436
+ {
437
+ providerId: provider.id,
438
+ defaultModel: provider.defaultModel,
439
+ createModelManagerOptions: provider.createModelManagerOptions,
440
+ allowUnauthenticated: provider.allowUnauthenticated,
441
+ dynamicModelsAuthoritative: provider.dynamicModelsAuthoritative,
442
+ catalogDiscovery: provider.catalogDiscovery
443
+ ? { ...provider.catalogDiscovery, envVars: provider.catalogDiscovery.envVars ?? provider.envVars ?? [] }
444
+ : undefined,
445
+ },
446
+ ];
447
+ });
448
+
449
+ /** Default model IDs for all known providers, derived from the catalog table. */
450
+ export const DEFAULT_MODEL_PER_PROVIDER: Record<KnownProvider, string> = Object.fromEntries(
451
+ CATALOG_PROVIDERS.map(provider => [provider.id, provider.defaultModel] as [string, string]),
452
+ ) as Record<KnownProvider, string>;
453
+
454
+ export function getCatalogProviderEntry(id: string): ProviderCatalogEntry | undefined {
455
+ return CATALOG_PROVIDERS.find(provider => provider.id === id);
456
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Fallback context-window / max-output-token values for models discovered
3
+ * without limit metadata.
4
+ *
5
+ * Kept in a dependency-free leaf module (rather than `openai-compat.ts`) so the
6
+ * model-discovery helpers in `utils/discovery/*` can import them without pulling
7
+ * the package root barrel (`@oh-my-pi/pi-ai`) into the model-manager init graph,
8
+ * which would otherwise form an import cycle through the provider registry.
9
+ */
10
+ export const UNK_CONTEXT_WINDOW = 222_222;
11
+ export const UNK_MAX_TOKENS = 8_888;