Multi-Provider Routing

niuma_code supports multiple API providers simultaneously. Configure different endpoints in factories, and requests are automatically routed to the correct provider based on the selected model.


Configuration

Provider config lives in ~/.niuma/settings.json (user layer) or <project>/.niuma/settings.json (project layer):

{
    "factories": [
        {
            "base_url": "https://api.anthropic.com",
            "api_key": "sk-ant-key1",
            "options": ["claude-sonnet-4-6", "claude-opus-4-8"]
        },
        {
            "base_url": "https://openrouter.ai/api",
            "api_key": "sk-or-key2",
            "options": ["gpt-4o", "gemini-2.5-pro"]
        }
    ],
    "llm": {
        "default_model": "claude-sonnet-4-6",
        "default_effort": "medium",
        "thinking_budget_low": "0",
        "thinking_budget_medium": "0",
        "thinking_budget_high": "10000",
        "thinking_budget_max": "20000"
    }
}

Factory Fields

Field Required Description
base_url Yes API endpoint URL (supports Anthropic-compatible proxies)
api_key Yes Authentication key for the provider
options Yes List of model names available from this provider

LLM Block

Field Required Default Description
default_model No claude-sonnet-4-6 Model used at session start
default_effort No medium Thinking depth: low, medium, high, max
thinking_budget_low No "0" Token budget when effort is low
thinking_budget_medium No "0" Token budget when effort is medium
thinking_budget_high No "10000" Token budget when effort is high
thinking_budget_max No "20000" Token budget when effort is max

How Routing Works

You type: /model
  → TUI: Model Settings overlay opens, showing all factories and their models
  → CLI: Lists all providers with model names
  → You select a model from the list
  → Config.get_current_model() switches the session model
  → get_factory_for_model() routes to the matching factory's base_url + api_key
  → Switches instantly, no restart needed

The first provider in the list is the default. Switching is instant and triggers a prompt cache invalidation warning.


Switching Models

Via /model Command

/model    → Open model selection overlay (TUI) or list all providers (CLI)

The /model command opens a visual model selection overlay in TUI mode. In CLI mode, it displays the current model and a numbered list of all available models from each provider.

Selecting a new model updates the session-level current_model — all subsequent LLM requests use the new model and its corresponding provider endpoint.

Effort Control

Effort controls thinking depth, not model selection. Switch effort during a session:

Effort Thinking Budget Use Case
low 0 tokens Quick responses, greetings
medium 0 tokens General coding tasks (default)
high 10,000 tokens Complex refactoring, architecture
max 20,000 tokens Deep analysis, multi-step reasoning

Configure thinking token budgets in the llm block of settings.json.


Config File Selection (Single-Source)

factories/llm/env/compact/memory_quality 等主配置采用单一来源(不叠加):

Mode Config Path When
Development <project>/.niuma/settings.json CWD contains "niuma" and has app/ + app/core/ subdirectories
Deploy ~/.niuma/settings.json All other cases

No local.json layer exists. No three-layer merge. Each mode reads exactly one file — "where you run is what you get."

Exception — memory_palace: This section uses a two-layer override (project → user fallback), independent of the main config. If memory_palace is present in the project-level settings.json, it is used; otherwise falls back to ~/.niuma/settings.json.

// Development mode: .niuma/settings.json
// (CWD has app/ + app/core/ → project-level only)
{
    "factories": [
        { "base_url": "https://api.anthropic.com", "api_key": "...", "options": ["claude-sonnet-4-6"] }
    ]
}
// Deploy mode: ~/.niuma/settings.json
// (other CWD → user-level only)
{
    "factories": [
        { "base_url": "https://custom-proxy.com", "api_key": "...", "options": ["claude-sonnet-4-6"] }
    ]
}

Adding a New Provider

  1. Get an API key from the provider
  2. Add a new entry to settings.json:
{
    "factories": [
        { "base_url": "https://api.anthropic.com", "api_key": "sk-ant-...", "options": ["claude-sonnet-4-6", "claude-opus-4-8"] },
        { "base_url": "https://openrouter.ai/api", "api_key": "sk-or-...", "options": ["gpt-4o", "gemini-2.5-pro"] },
        { "base_url": "https://api.deepseek.com", "api_key": "sk-ds-...", "options": ["deepseek-chat", "deepseek-coder"] }
    ]
}
  1. Use /model to open the selection overlay and switch to the new model

Common Provider Configurations

Anthropic (Direct or via Proxy)

{
    "base_url": "https://api.anthropic.com",
    "api_key": "sk-ant-...",
    "options": ["claude-sonnet-4-6", "claude-opus-4-8"]
}

OpenRouter (Multi-model)

{
    "base_url": "https://openrouter.ai/api",
    "api_key": "sk-or-...",
    "options": ["gpt-4o", "gemini-2.5-pro", "llama-3.1-405b"]
}

Self-Hosted (Ollama)

{
    "base_url": "http://localhost:11434/v1",
    "api_key": "not-needed",
    "options": ["llama3.1", "codellama"]
}

Troubleshooting

Issue Solution
Model not found in selection Check the options list in the matching factory for exact model name
401 Unauthorized Verify api_key is correct for that factory
Connection refused Check base_url and network access
Slow responses Try a different provider or region-specific endpoint
Model switch not taking effect Ensure the model name matches exactly (case-sensitive)
Prompt cache warning after switch Expected — switching models invalidates the prompt cache