Release

FabrCore Goes Multi-Model — Grok, Gemini, OpenAI, and Azure in One Runtime

Eric Brasher March 3, 2026 at 8:45 AM 5 min read

Not every task needs the same model. A fast classifier can run on GPT-4o-mini, a complex reasoning chain fits better on o1, and a cost-sensitive batch job might target Grok or Gemini. With FabrCore's ModelConfigurations in fabrcore.json, you define all your LLM providers in one file and agents reference them by name — no code changes when you swap providers.

The Configuration File

All LLM provider configuration lives in fabrcore.json, placed in the server project root. The file has two sections: ModelConfigurations (one entry per model) and ApiKeys (referenced by alias). This file should be added to .gitignore since it contains API keys.

JSON — fabrcore.json Schema
{
  "ModelConfigurations": [
    {
      "Name": "string",              // Required: unique model name
      "Provider": "string",          // Required: OpenAI | Azure | Grok | Gemini
      "Uri": "string",               // Required for Azure, optional for others
      "Model": "string",             // Required: model identifier
      "ApiKeyAlias": "string",       // Required: references an ApiKeys entry
      "TimeoutSeconds": 120,         // Optional: HTTP timeout
      "MaxOutputTokens": 16384,      // Optional: max response tokens
      "ContextWindowTokens": 128000  // Optional: total context window
    }
  ],
  "ApiKeys": [
    {
      "Alias": "string",
      "Value": "string"
    }
  ]
}

Each model entry also supports compaction settings: CompactionEnabled, CompactionKeepLastN, and CompactionThreshold. These control when chat history is summarized to stay within the context window.

Configuring Each Provider

FabrCore supports five providers out of the box. Any OpenAI-compatible endpoint can also be used by setting Provider: "OpenAI" with a custom Uri.

ProviderUri RequiredNotes
OpenAINoUses default OpenAI endpoint
AzureYesAzure OpenAI resource URL
OpenRouterNoUses OpenRouter endpoint
GrokNoxAI Grok models
GeminiNoGoogle Gemini models

OpenAI

JSON — OpenAI Configuration
{
  "ModelConfigurations": [
    {
      "Name": "default",
      "Provider": "OpenAI",
      "Model": "gpt-4o",
      "ApiKeyAlias": "openai-key",
      "TimeoutSeconds": 120,
      "MaxOutputTokens": 16384,
      "ContextWindowTokens": 128000
    }
  ],
  "ApiKeys": [
    { "Alias": "openai-key", "Value": "sk-..." }
  ]
}

Azure OpenAI

JSON — Azure OpenAI Configuration
{
  "ModelConfigurations": [
    {
      "Name": "azure-gpt4",
      "Provider": "Azure",
      "Uri": "https://your-resource.openai.azure.com/",
      "Model": "gpt-4o",
      "ApiKeyAlias": "azure-key"
    }
  ],
  "ApiKeys": [
    { "Alias": "azure-key", "Value": "your-key-here" }
  ]
}

Grok & Gemini

JSON — Grok and Gemini Side by Side
{
  "ModelConfigurations": [
    {
      "Name": "grok",
      "Provider": "Grok",
      "Model": "grok-3",
      "ApiKeyAlias": "xai-key"
    },
    {
      "Name": "gemini",
      "Provider": "Gemini",
      "Model": "gemini-2.0-flash",
      "ApiKeyAlias": "google-key"
    }
  ],
  "ApiKeys": [
    { "Alias": "xai-key", "Value": "xai-..." },
    { "Alias": "google-key", "Value": "AIza..." }
  ]
}

Using Models in Agents

Agents reference models by their Name field through the config.Models property. When you call CreateChatClientAgent in OnInitialize, you pass the model name and the framework resolves it from fabrcore.json:

C# — Agent Using a Named Model
public override async Task OnInitialize()
{
    var tools = await ResolveConfiguredToolsAsync();

    // config.Models comes from AgentConfiguration — e.g., "grok" or "gemini"
    var result = await CreateChatClientAgent(
        chatClientConfigName: config.Models ?? "default",
        threadId: config.Handle ?? fabrcoreAgentHost.GetHandle(),
        tools: tools);

    _agent = result.Agent;
    _session = result.Session;
}

The AgentConfiguration is where the model name is assigned. You can set it when creating agents via the REST API, in system agent startup code, or from ChatDock's AdditionalArgs:

C# — Creating Agents with Different Models
// Fast classifier on GPT-4o-mini
await _agentService.ConfigureSystemAgentAsync(new AgentConfiguration
{
    Handle = "classifier",
    AgentType = "classifier-agent",
    Models = "fast",
    SystemPrompt = "Classify incoming requests into categories."
});

// Deep reasoning on Grok
await _agentService.ConfigureSystemAgentAsync(new AgentConfiguration
{
    Handle = "analyst",
    AgentType = "analysis-agent",
    Models = "grok",
    SystemPrompt = "Perform deep analysis on financial data."
});

This separation of model configuration from agent code means you can switch an agent from OpenAI to Gemini by changing one string in the configuration — no recompilation, no code changes. Different agents in the same runtime can use different providers simultaneously.

Putting It All Together

A production fabrcore.json typically defines several models with different cost/performance tradeoffs. Here is an example with four providers and an embeddings model:

JSON — Multi-Provider Configuration
{
  "ModelConfigurations": [
    {
      "Name": "default",
      "Provider": "OpenAI",
      "Model": "gpt-4o",
      "ApiKeyAlias": "openai",
      "ContextWindowTokens": 128000
    },
    {
      "Name": "fast",
      "Provider": "OpenAI",
      "Model": "gpt-4o-mini",
      "ApiKeyAlias": "openai",
      "CompactionKeepLastN": 10,
      "CompactionThreshold": 0.6
    },
    {
      "Name": "grok",
      "Provider": "Grok",
      "Model": "grok-3",
      "ApiKeyAlias": "xai"
    },
    {
      "Name": "gemini",
      "Provider": "Gemini",
      "Model": "gemini-2.0-flash",
      "ApiKeyAlias": "google"
    },
    {
      "Name": "embeddings",
      "Provider": "OpenAI",
      "Model": "text-embedding-3-small",
      "ApiKeyAlias": "openai"
    }
  ],
  "ApiKeys": [
    { "Alias": "openai", "Value": "sk-..." },
    { "Alias": "xai", "Value": "xai-..." },
    { "Alias": "google", "Value": "AIza..." }
  ]
}

API keys are shared across model entries via ApiKeyAlias — define a key once and reference it from multiple models. The "embeddings" named model is special: it is automatically picked up by the IEmbeddings service and the /fabrcoreapi/embeddings API endpoint.

With this setup, a router agent running on the "fast" model can classify requests and delegate to a Grok-backed analyst or a Gemini-backed summarizer — all within the same Orleans cluster, sharing the same infrastructure, with each agent using the model best suited to its task.


Built with FabrCore on .NET 10.


Eric Brasher

Builder of FabrCore and OpenCaddis.