n8n - ✅(Solved) Fix refactor(core): Extract ChatHubModelsService provider fetch methods into declarative config [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
n8n-io/n8n#28350Fetched 2026-04-11 06:30:44
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
0
Timeline (top)
closed ×1commented ×1cross-referenced ×1labeled ×1

Error Message

This drops the service from ~876 to ~283 lines with zero public API changes. Adding a new provider becomes a 1-5 line config entry instead of a switch case + method copy-paste. TypeScript enforces exhaustiveness — if a new provider is added to the union type without a config entry, it's a compile error.

Fix Action

Fix / Workaround

ChatHubModelsService has 14 nearly identical private fetchXxxModels() methods and a 16-case switch statement dispatching to them. Each method is really just a routing config object passed to DynamicNodeParametersService — it's configuration data pretending to be logic.

Replace the 14 fetch methods + switch with:

  • A Record<ChatHubLLMProvider, LLMProviderFetchConfig> declarative registry (one entry per provider)
  • A single fetchLLMProviderModels() dispatch function handling all config types

PR fix notes

PR #28351: refactor(core): Extract ChatHubModelsService provider configs into declarative registry (no-changelog)

Description (problem / solution / changelog)

Summary

ChatHubModelsService had 14 nearly identical fetchXxxModels() methods and a 16-case switch — each method was just a routing config passed to DynamicNodeParametersService. Replaced all of it with a declarative LLM_PROVIDER_FETCH_CONFIGS registry and a single dispatch function.

876 → 283 lines. Zero public API changes.

Adding a new LLM provider is now a 1-5 line config entry instead of a switch case + copy-pasted method. TypeScript catches missing providers at compile time.

Motivated by seeing #27650 and #23518 where contributors had to repeat the same boilerplate to add new providers.

Closes #28350

What changed

FileAction
chat-hub-model-fetchers.tsNEW — config types, provider registry, fetch dispatch function
chat-hub.models.service.tsMODIFIED — deleted 14 fetch methods + switch, replaced with 3-line dispatch
chat-hub-model-fetchers.test.tsNEW — 19 unit tests covering all config types

How adding a provider works now

Before:

// 1. Add switch case
case 'newProvider': {
  const rawModels = await this.fetchNewProviderModels(credentials, additionalData);
  return { models: this.transformAndFilterModels(rawModels, 'newProvider') };
}
// 2. Write ~30-line copy-pasted method
private async fetchNewProviderModels(...) { ... }

After:

newProvider: loadOptions('/models', 'data', ID_KEY),

Test plan

  • 19 new unit tests pass (noop, resourceLocator, loadOptions, loadOptionsMulti, config exhaustiveness)
  • 15 existing integration tests pass unchanged
  • Typecheck clean
  • Lint clean

Changed files

  • packages/cli/src/modules/chat-hub/__tests__/chat-hub-model-fetchers.test.ts (added, +172/-0)
  • packages/cli/src/modules/chat-hub/chat-hub-model-fetchers.ts (added, +254/-0)
  • packages/cli/src/modules/chat-hub/chat-hub.models.service.ts (modified, +13/-606)
RAW_BUFFERClick to expand / collapse

Problem

ChatHubModelsService has 14 nearly identical private fetchXxxModels() methods and a 16-case switch statement dispatching to them. Each method is really just a routing config object passed to DynamicNodeParametersService — it's configuration data pretending to be logic.

This makes adding new LLM providers unnecessarily verbose. Every new provider requires a new switch case + a new 30-line copy-pasted private method. See #27650 (MiniMax) and #23518 (AtlasCloud) for examples of contributors having to repeat this pattern.

Proposal

Replace the 14 fetch methods + switch with:

  • A Record<ChatHubLLMProvider, LLMProviderFetchConfig> declarative registry (one entry per provider)
  • A single fetchLLMProviderModels() dispatch function handling all config types

This drops the service from ~876 to ~283 lines with zero public API changes. Adding a new provider becomes a 1-5 line config entry instead of a switch case + method copy-paste. TypeScript enforces exhaustiveness — if a new provider is added to the union type without a config entry, it's a compile error.

No changes to types, controller, frontend, or metadata registry.

extent analysis

TL;DR

Replace the redundant fetchXxxModels() methods and switch statement with a declarative registry and a single dispatch function to simplify adding new LLM providers.

Guidance

  • Identify the ChatHubModelsService class and locate the 14 private fetchXxxModels() methods and the 16-case switch statement.
  • Replace these methods with a Record<ChatHubLLMProvider, LLMProviderFetchConfig> registry to store configuration data for each provider.
  • Implement a single fetchLLMProviderModels() function to handle all config types, reducing code duplication and improving maintainability.
  • Verify that the new implementation does not introduce any public API changes and that TypeScript enforces exhaustiveness for new provider additions.

Example

const llmProviderRegistry: Record<ChatHubLLMProvider, LLMProviderFetchConfig> = {
  // Example entry for a provider
  ProviderA: { /* config data */ },
  ProviderB: { /* config data */ },
  // ...
};

function fetchLLMProviderModels(provider: ChatHubLLMProvider) {
  const config = llmProviderRegistry[provider];
  // Handle config and dispatch to DynamicNodeParametersService
}

Notes

This solution assumes that the ChatHubLLMProvider union type is up-to-date and includes all existing providers. If new providers are added to the union type without a corresponding config entry, TypeScript will raise a compile error.

Recommendation

Apply the proposed workaround by replacing the redundant methods and switch statement with a declarative registry and a single dispatch function, as it simplifies the code and improves maintainability.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING