getFallbackModelsForAgent returns fallback providers for an agent based on its fallback configuration. It uses the same resolution logic as primary models (named model, inline provider/model format).
(ctx context.Context, cfg *latest.Config, a *latest.AgentConfig, runConfig *config.RuntimeConfig, providerRegistry *provider.Registry)
| 493 | // getFallbackModelsForAgent returns fallback providers for an agent based on its fallback configuration. |
| 494 | // It uses the same resolution logic as primary models (named model, inline provider/model format). |
| 495 | func getFallbackModelsForAgent(ctx context.Context, cfg *latest.Config, a *latest.AgentConfig, runConfig *config.RuntimeConfig, providerRegistry *provider.Registry) ([]provider.Provider, error) { |
| 496 | var fallbackModels []provider.Provider |
| 497 | |
| 498 | // Obtain the singleton store once, outside the loop. |
| 499 | modelsStore, modelsStoreErr := runConfig.ModelsDevStore() |
| 500 | |
| 501 | for _, name := range a.GetFallbackModels() { |
| 502 | modelCfg, exists := cfg.Models[name] |
| 503 | if !exists { |
| 504 | // Try parsing as inline provider/model format (e.g., "openai/gpt-4o") |
| 505 | parsed, err := latest.ParseModelRef(name) |
| 506 | if err != nil { |
| 507 | return nil, fmt.Errorf("fallback model '%s' not found in configuration and is not a valid provider/model format", name) |
| 508 | } |
| 509 | modelCfg = parsed |
| 510 | } |
| 511 | modelCfg.Name = name |
| 512 | |
| 513 | // Use max_tokens from config if specified, otherwise look up from models.dev |
| 514 | maxTokens := &defaultMaxTokens |
| 515 | if modelCfg.MaxTokens != nil { |
| 516 | maxTokens = modelCfg.MaxTokens |
| 517 | } else if modelsStoreErr == nil { |
| 518 | m, err := modelsStore.GetModel(ctx, modelsdev.NewID(modelCfg.Provider, modelCfg.Model)) |
| 519 | if err == nil { |
| 520 | maxTokens = &m.Limit.Output |
| 521 | } |
| 522 | } |
| 523 | |
| 524 | opts := []options.Opt{ |
| 525 | options.WithGateway(runConfig.ModelsGateway), |
| 526 | options.WithStructuredOutput(a.StructuredOutput), |
| 527 | options.WithProviders(cfg.Providers), |
| 528 | } |
| 529 | if maxTokens != nil { |
| 530 | opts = append(opts, options.WithMaxTokens(*maxTokens)) |
| 531 | } |
| 532 | if modelsStoreErr == nil { |
| 533 | opts = append(opts, options.WithModelsDevStore(modelsStore)) |
| 534 | } |
| 535 | |
| 536 | // Pass the full models map for routing rules to resolve model references |
| 537 | model, err := providerRegistry.NewWithModels(ctx, |
| 538 | &modelCfg, |
| 539 | cfg.Models, |
| 540 | runConfig.EnvProvider(), |
| 541 | opts..., |
| 542 | ) |
| 543 | if err != nil { |
| 544 | return nil, fmt.Errorf("failed to create fallback model '%s': %w", name, err) |
| 545 | } |
| 546 | fallbackModels = append(fallbackModels, model) |
| 547 | } |
| 548 | |
| 549 | return fallbackModels, nil |
| 550 | } |
| 551 | |
| 552 | // getTitleModelForAgent resolves the dedicated title-generation model for an |
no test coverage detected