|
1 | 1 | import { z } from "zod" |
2 | 2 |
|
3 | | -import { reasoningEffortsSchema, verbosityLevelsSchema, modelInfoSchema } from "./model.js" |
| 3 | +import { modelInfoSchema, reasoningEffortWithMinimalSchema, verbosityLevelsSchema } from "./model.js" |
4 | 4 | import { codebaseIndexProviderSchema } from "./codebase-index.js" |
5 | | - |
6 | | -// Bedrock Claude Sonnet 4 model ID that supports 1M context |
7 | | -export const BEDROCK_CLAUDE_SONNET_4_MODEL_ID = "anthropic.claude-sonnet-4-20250514-v1:0" |
8 | | - |
9 | | -// Extended schema that includes "minimal" for GPT-5 models |
10 | | -export const extendedReasoningEffortsSchema = z.union([reasoningEffortsSchema, z.literal("minimal")]) |
11 | | - |
12 | | -export type ReasoningEffortWithMinimal = z.infer<typeof extendedReasoningEffortsSchema> |
| 5 | +import { |
| 6 | + anthropicModels, |
| 7 | + bedrockModels, |
| 8 | + cerebrasModels, |
| 9 | + chutesModels, |
| 10 | + claudeCodeModels, |
| 11 | + deepSeekModels, |
| 12 | + doubaoModels, |
| 13 | + featherlessModels, |
| 14 | + fireworksModels, |
| 15 | + geminiModels, |
| 16 | + groqModels, |
| 17 | + ioIntelligenceModels, |
| 18 | + mistralModels, |
| 19 | + moonshotModels, |
| 20 | + openAiNativeModels, |
| 21 | + rooModels, |
| 22 | + sambaNovaModels, |
| 23 | + vertexModels, |
| 24 | + vscodeLlmModels, |
| 25 | + xaiModels, |
| 26 | + internationalZAiModels, |
| 27 | +} from "./providers/index.js" |
13 | 28 |
|
14 | 29 | /** |
15 | 30 | * ProviderName |
@@ -46,7 +61,9 @@ export const providerNames = [ |
46 | 61 | "sambanova", |
47 | 62 | "zai", |
48 | 63 | "fireworks", |
| 64 | + "featherless", |
49 | 65 | "io-intelligence", |
| 66 | + "roo", |
50 | 67 | ] as const |
51 | 68 |
|
52 | 69 | export const providerNamesSchema = z.enum(providerNames) |
@@ -85,7 +102,7 @@ const baseProviderSettingsSchema = z.object({ |
85 | 102 |
|
86 | 103 | // Model reasoning. |
87 | 104 | enableReasoningEffort: z.boolean().optional(), |
88 | | - reasoningEffort: extendedReasoningEffortsSchema.optional(), |
| 105 | + reasoningEffort: reasoningEffortWithMinimalSchema.optional(), |
89 | 106 | modelMaxTokens: z.number().optional(), |
90 | 107 | modelMaxThinkingTokens: z.number().optional(), |
91 | 108 |
|
@@ -283,11 +300,19 @@ const fireworksSchema = apiModelIdProviderModelSchema.extend({ |
283 | 300 | fireworksApiKey: z.string().optional(), |
284 | 301 | }) |
285 | 302 |
|
| 303 | +const featherlessSchema = apiModelIdProviderModelSchema.extend({ |
| 304 | + featherlessApiKey: z.string().optional(), |
| 305 | +}) |
| 306 | + |
286 | 307 | const ioIntelligenceSchema = apiModelIdProviderModelSchema.extend({ |
287 | 308 | ioIntelligenceModelId: z.string().optional(), |
288 | 309 | ioIntelligenceApiKey: z.string().optional(), |
289 | 310 | }) |
290 | 311 |
|
| 312 | +const rooSchema = apiModelIdProviderModelSchema.extend({ |
| 313 | + // No additional fields needed - uses cloud authentication |
| 314 | +}) |
| 315 | + |
291 | 316 | const defaultSchema = z.object({ |
292 | 317 | apiProvider: z.undefined(), |
293 | 318 | }) |
@@ -323,7 +348,9 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv |
323 | 348 | sambaNovaSchema.merge(z.object({ apiProvider: z.literal("sambanova") })), |
324 | 349 | zaiSchema.merge(z.object({ apiProvider: z.literal("zai") })), |
325 | 350 | fireworksSchema.merge(z.object({ apiProvider: z.literal("fireworks") })), |
| 351 | + featherlessSchema.merge(z.object({ apiProvider: z.literal("featherless") })), |
326 | 352 | ioIntelligenceSchema.merge(z.object({ apiProvider: z.literal("io-intelligence") })), |
| 353 | + rooSchema.merge(z.object({ apiProvider: z.literal("roo") })), |
327 | 354 | defaultSchema, |
328 | 355 | ]) |
329 | 356 |
|
@@ -359,7 +386,9 @@ export const providerSettingsSchema = z.object({ |
359 | 386 | ...sambaNovaSchema.shape, |
360 | 387 | ...zaiSchema.shape, |
361 | 388 | ...fireworksSchema.shape, |
| 389 | + ...featherlessSchema.shape, |
362 | 390 | ...ioIntelligenceSchema.shape, |
| 391 | + ...rooSchema.shape, |
363 | 392 | ...codebaseIndexProviderSchema.shape, |
364 | 393 | }) |
365 | 394 |
|
@@ -393,21 +422,126 @@ export const getModelId = (settings: ProviderSettings): string | undefined => { |
393 | 422 | return modelIdKey ? (settings[modelIdKey] as string) : undefined |
394 | 423 | } |
395 | 424 |
|
396 | | -// Providers that use Anthropic-style API protocol |
| 425 | +// Providers that use Anthropic-style API protocol. |
397 | 426 | export const ANTHROPIC_STYLE_PROVIDERS: ProviderName[] = ["anthropic", "claude-code", "bedrock"] |
398 | 427 |
|
399 | | -// Helper function to determine API protocol for a provider and model |
400 | 428 | export const getApiProtocol = (provider: ProviderName | undefined, modelId?: string): "anthropic" | "openai" => { |
401 | | - // First check if the provider is an Anthropic-style provider |
402 | 429 | if (provider && ANTHROPIC_STYLE_PROVIDERS.includes(provider)) { |
403 | 430 | return "anthropic" |
404 | 431 | } |
405 | 432 |
|
406 | | - // For vertex provider, check if the model ID contains "claude" (case-insensitive) |
407 | 433 | if (provider && provider === "vertex" && modelId && modelId.toLowerCase().includes("claude")) { |
408 | 434 | return "anthropic" |
409 | 435 | } |
410 | 436 |
|
411 | | - // Default to OpenAI protocol |
412 | 437 | return "openai" |
413 | 438 | } |
| 439 | + |
| 440 | +export const MODELS_BY_PROVIDER: Record< |
| 441 | + Exclude<ProviderName, "fake-ai" | "human-relay" | "gemini-cli" | "lmstudio" | "openai" | "ollama">, |
| 442 | + { id: ProviderName; label: string; models: string[] } |
| 443 | +> = { |
| 444 | + anthropic: { |
| 445 | + id: "anthropic", |
| 446 | + label: "Anthropic", |
| 447 | + models: Object.keys(anthropicModels), |
| 448 | + }, |
| 449 | + bedrock: { |
| 450 | + id: "bedrock", |
| 451 | + label: "Amazon Bedrock", |
| 452 | + models: Object.keys(bedrockModels), |
| 453 | + }, |
| 454 | + cerebras: { |
| 455 | + id: "cerebras", |
| 456 | + label: "Cerebras", |
| 457 | + models: Object.keys(cerebrasModels), |
| 458 | + }, |
| 459 | + chutes: { |
| 460 | + id: "chutes", |
| 461 | + label: "Chutes AI", |
| 462 | + models: Object.keys(chutesModels), |
| 463 | + }, |
| 464 | + "claude-code": { id: "claude-code", label: "Claude Code", models: Object.keys(claudeCodeModels) }, |
| 465 | + deepseek: { |
| 466 | + id: "deepseek", |
| 467 | + label: "DeepSeek", |
| 468 | + models: Object.keys(deepSeekModels), |
| 469 | + }, |
| 470 | + doubao: { id: "doubao", label: "Doubao", models: Object.keys(doubaoModels) }, |
| 471 | + featherless: { |
| 472 | + id: "featherless", |
| 473 | + label: "Featherless", |
| 474 | + models: Object.keys(featherlessModels), |
| 475 | + }, |
| 476 | + fireworks: { |
| 477 | + id: "fireworks", |
| 478 | + label: "Fireworks", |
| 479 | + models: Object.keys(fireworksModels), |
| 480 | + }, |
| 481 | + gemini: { |
| 482 | + id: "gemini", |
| 483 | + label: "Google Gemini", |
| 484 | + models: Object.keys(geminiModels), |
| 485 | + }, |
| 486 | + groq: { id: "groq", label: "Groq", models: Object.keys(groqModels) }, |
| 487 | + "io-intelligence": { |
| 488 | + id: "io-intelligence", |
| 489 | + label: "IO Intelligence", |
| 490 | + models: Object.keys(ioIntelligenceModels), |
| 491 | + }, |
| 492 | + mistral: { |
| 493 | + id: "mistral", |
| 494 | + label: "Mistral", |
| 495 | + models: Object.keys(mistralModels), |
| 496 | + }, |
| 497 | + moonshot: { |
| 498 | + id: "moonshot", |
| 499 | + label: "Moonshot", |
| 500 | + models: Object.keys(moonshotModels), |
| 501 | + }, |
| 502 | + "openai-native": { |
| 503 | + id: "openai-native", |
| 504 | + label: "OpenAI", |
| 505 | + models: Object.keys(openAiNativeModels), |
| 506 | + }, |
| 507 | + roo: { id: "roo", label: "Roo", models: Object.keys(rooModels) }, |
| 508 | + sambanova: { |
| 509 | + id: "sambanova", |
| 510 | + label: "SambaNova", |
| 511 | + models: Object.keys(sambaNovaModels), |
| 512 | + }, |
| 513 | + vertex: { |
| 514 | + id: "vertex", |
| 515 | + label: "GCP Vertex AI", |
| 516 | + models: Object.keys(vertexModels), |
| 517 | + }, |
| 518 | + "vscode-lm": { |
| 519 | + id: "vscode-lm", |
| 520 | + label: "VS Code LM API", |
| 521 | + models: Object.keys(vscodeLlmModels), |
| 522 | + }, |
| 523 | + xai: { id: "xai", label: "xAI (Grok)", models: Object.keys(xaiModels) }, |
| 524 | + zai: { id: "zai", label: "Zai", models: Object.keys(internationalZAiModels) }, |
| 525 | + |
| 526 | + // Dynamic providers; models pulled from the respective APIs. |
| 527 | + glama: { id: "glama", label: "Glama", models: [] }, |
| 528 | + huggingface: { id: "huggingface", label: "Hugging Face", models: [] }, |
| 529 | + litellm: { id: "litellm", label: "LiteLLM", models: [] }, |
| 530 | + openrouter: { id: "openrouter", label: "OpenRouter", models: [] }, |
| 531 | + requesty: { id: "requesty", label: "Requesty", models: [] }, |
| 532 | + unbound: { id: "unbound", label: "Unbound", models: [] }, |
| 533 | +} |
| 534 | + |
| 535 | +export const dynamicProviders = [ |
| 536 | + "glama", |
| 537 | + "huggingface", |
| 538 | + "litellm", |
| 539 | + "openrouter", |
| 540 | + "requesty", |
| 541 | + "unbound", |
| 542 | +] as const satisfies readonly ProviderName[] |
| 543 | + |
| 544 | +export type DynamicProvider = (typeof dynamicProviders)[number] |
| 545 | + |
| 546 | +export const isDynamicProvider = (key: string): key is DynamicProvider => |
| 547 | + dynamicProviders.includes(key as DynamicProvider) |
0 commit comments