Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"dependencies": {
"@ai-sdk/amazon-bedrock": "^3.0.65",
"@ai-sdk/anthropic": "^2.0.53",
"@ai-sdk/azure": "^2.0.0",
"@ai-sdk/deepseek": "^1.0.31",
"@ai-sdk/google": "^2.0.44",
"@ai-sdk/mcp": "^0.0.11",
Expand Down Expand Up @@ -196,6 +197,8 @@

"@ai-sdk/anthropic": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ih7NV+OFSNWZCF+tYYD7ovvvM+gv7TRKQblpVohg2ipIwC9Y0TirzocJVREzZa/v9luxUwFbsPji++DUDWWxsg=="],

"@ai-sdk/azure": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/openai": "2.0.89", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-9tznVSs6LGQNKKxb8pKd7CkBV9yk+a/ENpFicHCj2CmBUKefxzwJ9JbUqrlK3VF6dGZw3LXq0dWxt7/Yekaj1w=="],

"@ai-sdk/deepseek": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Il7WJp8bA3CmlreYSl1YzCucGTn2e5P81IANYIIEeLtWrbK0Y9CLoOCROj8xKYyUSMKlINyGZX2uP79cKewtSg=="],

"@ai-sdk/gateway": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18", "@vercel/oidc": "3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-sDQcW+6ck2m0pTIHW6BPHD7S125WD3qNkx/B8sEzJp/hurocmJ5Cni0ybExg6sQMGo+fr/GWOwpHF1cmCdg5rQ=="],
Expand Down Expand Up @@ -3770,6 +3773,12 @@

"zwitch": ["[email protected]", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],

"@ai-sdk/azure/@ai-sdk/openai": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-4+qWkBCbL9HPKbgrUO/F2uXZ8GqrYxHa8SWEYIzxEJ9zvWw3ISr3t1/27O1i8MGSym+PzEyHBT48EV4LAwWaEw=="],

"@ai-sdk/azure/@ai-sdk/provider": ["@ai-sdk/[email protected]", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng=="],

"@ai-sdk/azure/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ=="],

"@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],

"@aws-crypto/util/@smithy/util-utf8": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
Expand Down
106 changes: 81 additions & 25 deletions docs/config/providers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,36 @@ Most providers only need an API key. The UI handles validation and shows which p

## Supported Providers

| Provider | Models | Get API Key |
| -------------- | -------------------------- | ------------------------------------------------------- |
| **Anthropic** | Claude Opus, Sonnet, Haiku | [console.anthropic.com](https://console.anthropic.com/) |
| **OpenAI** | GPT-5, Codex | [platform.openai.com](https://platform.openai.com/) |
| **Google** | Gemini Pro, Flash | [aistudio.google.com](https://aistudio.google.com/) |
| **xAI** | Grok | [console.x.ai](https://console.x.ai/) |
| **DeepSeek** | DeepSeek Chat, Reasoner | [platform.deepseek.com](https://platform.deepseek.com/) |
| **OpenRouter** | 300+ models | [openrouter.ai](https://openrouter.ai/) |
| **Ollama** | Local models | [ollama.com](https://ollama.com/) (no key needed) |
| **Bedrock** | Claude via AWS | AWS Console |
| Provider | Models | Get API Key |
| ----------------- | -------------------------- | ------------------------------------------------------- |
| **Anthropic** | Claude Opus, Sonnet, Haiku | [console.anthropic.com](https://console.anthropic.com/) |
| **Azure Foundry** | Claude via Azure Foundry | [ai.azure.com](https://ai.azure.com/) |
| **Azure OpenAI** | GPT via Azure | [portal.azure.com](https://portal.azure.com/) |
| **OpenAI** | GPT-5, Codex | [platform.openai.com](https://platform.openai.com/) |
| **Google** | Gemini Pro, Flash | [aistudio.google.com](https://aistudio.google.com/) |
| **xAI** | Grok | [console.x.ai](https://console.x.ai/) |
| **DeepSeek** | DeepSeek Chat, Reasoner | [platform.deepseek.com](https://platform.deepseek.com/) |
| **OpenRouter** | 300+ models | [openrouter.ai](https://openrouter.ai/) |
| **Ollama** | Local models | [ollama.com](https://ollama.com/) (no key needed) |
| **Bedrock** | Claude via AWS | AWS Console |

## Environment Variables

Providers also read from environment variables as fallback:

{/* BEGIN PROVIDER_ENV_VARS */}

| Provider | Environment Variable |
| ---------- | -------------------------------------------------- |
| Anthropic | `ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN` |
| OpenAI | `OPENAI_API_KEY` |
| Google | `GOOGLE_GENERATIVE_AI_API_KEY` or `GOOGLE_API_KEY` |
| xAI | `XAI_API_KEY` |
| OpenRouter | `OPENROUTER_API_KEY` |
| DeepSeek | `DEEPSEEK_API_KEY` |
| Bedrock | `AWS_REGION` (credentials via AWS SDK chain) |
| Provider | Environment Variable |
| ------------- | ----------------------------------------------------- |
| Anthropic | `ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN` |
| Azure Foundry | `AZURE_FOUNDRY_API_KEY` and `AZURE_FOUNDRY_RESOURCE` |
| Azure OpenAI | `AZURE_OPENAI_API_KEY` and `AZURE_OPENAI_ENDPOINT` |
| OpenAI | `OPENAI_API_KEY` |
| Google | `GOOGLE_GENERATIVE_AI_API_KEY` or `GOOGLE_API_KEY` |
| xAI | `XAI_API_KEY` |
| OpenRouter | `OPENROUTER_API_KEY` |
| DeepSeek | `DEEPSEEK_API_KEY` |
| Bedrock | `AWS_REGION` (credentials via AWS SDK chain) |

<details>
<summary>Additional environment variables</summary>
Expand All @@ -53,12 +57,8 @@ Providers also read from environment variables as fallback:
| OpenAI | `OPENAI_ORG_ID` | Organization ID |
| Google | `GOOGLE_BASE_URL` | Custom API endpoint |
| xAI | `XAI_BASE_URL` | Custom API endpoint |
| Azure OpenAI | `AZURE_OPENAI_API_KEY` | API key |
| Azure OpenAI | `AZURE_OPENAI_ENDPOINT` | Endpoint URL |
| Azure OpenAI | `AZURE_OPENAI_DEPLOYMENT` | Deployment name |
| Azure OpenAI | `AZURE_OPENAI_API_VERSION` | API version |

Azure OpenAI env vars configure the OpenAI provider with Azure backend.
| Azure OpenAI | `AZURE_OPENAI_DEPLOYMENT` | Deployment name (optional) |
| Azure OpenAI | `AZURE_OPENAI_API_VERSION` | API version (optional) |

</details>

Expand Down Expand Up @@ -95,6 +95,62 @@ For advanced options not exposed in the UI, edit `~/.mux/providers.jsonc` direct
}
```

### Azure Foundry

Azure Foundry provides access to Claude models through Microsoft's AI marketplace. It uses Anthropic's native API format.

```jsonc
{
"azure-foundry": {
"apiKey": "your-azure-api-key",
"resource": "your-resource-name" // Just the resource name, not full URL
}
}
```

**Getting your credentials:**
1. Go to [Azure AI Foundry](https://ai.azure.com/)
2. Create a project and deploy a Claude model
3. Find your resource name (e.g., `my-resource` from `https://my-resource.services.ai.azure.com/`)
4. Copy your API key from the Keys section

**Environment variables:**
```bash
export AZURE_FOUNDRY_RESOURCE=your-resource-name # Just the name, not full URL
export AZURE_FOUNDRY_API_KEY=your-azure-api-key
```

**Note:** Azure Foundry is separate from Azure OpenAI. All Claude features work identically: streaming, tool calling, thinking, and prompt caching.

### Azure OpenAI

Azure OpenAI provides access to OpenAI models (GPT-5, Codex) through Microsoft Azure.

```jsonc
{
"azure-openai": {
"apiKey": "your-azure-api-key",
"baseUrl": "https://your-resource.cognitiveservices.azure.com",
"deployment": "your-deployment-name", // Optional: defaults to model ID
"apiVersion": "2024-12-01-preview" // Optional
}
}
```

**Getting your credentials:**
1. Go to [Azure Portal](https://portal.azure.com/)
2. Create an Azure OpenAI resource
3. Deploy a model (e.g., gpt-5.2)
4. Copy your endpoint URL (e.g., `https://your-resource.cognitiveservices.azure.com`) and API key

**Environment variables:**
```bash
export AZURE_OPENAI_ENDPOINT=https://your-resource.cognitiveservices.azure.com
export AZURE_OPENAI_API_KEY=your-azure-api-key
export AZURE_OPENAI_DEPLOYMENT=your-deployment-name # Optional
export AZURE_OPENAI_API_VERSION=2024-12-01-preview # Optional
```

### Bedrock Authentication

Bedrock supports multiple authentication methods (tried in order):
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"dependencies": {
"@ai-sdk/amazon-bedrock": "^3.0.65",
"@ai-sdk/anthropic": "^2.0.53",
"@ai-sdk/azure": "^2.0.0",
"@ai-sdk/deepseek": "^1.0.31",
"@ai-sdk/google": "^2.0.44",
"@ai-sdk/mcp": "^0.0.11",
Expand Down
1 change: 1 addition & 0 deletions src/browser/components/ProviderIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { cn } from "@/common/lib/utils";
*/
const PROVIDER_ICONS: Partial<Record<ProviderName, React.FC>> = {
anthropic: AnthropicIcon,
"azure-foundry": AnthropicIcon, // Same icon as Anthropic (Claude branding)
openai: OpenAIIcon,
google: GoogleIcon,
xai: XAIIcon,
Expand Down
44 changes: 44 additions & 0 deletions src/browser/components/Settings/sections/ProvidersSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,44 @@ function getProviderFields(provider: ProviderName): FieldConfig[] {
return [];
}

if (provider === "azure-foundry") {
return [
{ key: "apiKey", label: "API Key", placeholder: "Enter API key", type: "secret" },
{
key: "resource",
label: "Resource",
placeholder: "your-resource-name",
type: "text",
},
];
}

if (provider === "azure-openai") {
return [
{ key: "apiKey", label: "API Key", placeholder: "Enter API key", type: "secret" },
{
key: "baseUrl",
label: "Endpoint",
placeholder: "https://your-resource.cognitiveservices.azure.com",
type: "text",
},
{
key: "deployment",
label: "Deployment",
placeholder: "your-deployment-name",
type: "text",
optional: true,
},
{
key: "apiVersion",
label: "API Version",
placeholder: "2024-12-01-preview",
type: "text",
optional: true,
},
];
}

// Default for most providers
return [
{ key: "apiKey", label: "API Key", placeholder: "Enter API key", type: "secret" },
Expand All @@ -134,6 +172,8 @@ function getProviderFields(provider: ProviderName): FieldConfig[] {
*/
const PROVIDER_KEY_URLS: Partial<Record<ProviderName, string>> = {
anthropic: "https://console.anthropic.com/settings/keys",
"azure-foundry": "https://ai.azure.com/",
"azure-openai": "https://portal.azure.com/",
openai: "https://platform.openai.com/api-keys",
google: "https://aistudio.google.com/app/apikey",
xai: "https://console.x.ai/team/default/api-keys",
Expand Down Expand Up @@ -430,6 +470,8 @@ export function ProvidersSection() {
updateOptimistically(provider, { apiKeySet: editValue !== "" });
} else if (field === "baseUrl") {
updateOptimistically(provider, { baseUrl: editValue || undefined });
} else if (field === "resource") {
updateOptimistically(provider, { resource: editValue || undefined });
}

setEditingField(null);
Expand All @@ -449,6 +491,8 @@ export function ProvidersSection() {
updateOptimistically(provider, { apiKeySet: false });
} else if (field === "baseUrl") {
updateOptimistically(provider, { baseUrl: undefined });
} else if (field === "resource") {
updateOptimistically(provider, { resource: undefined });
}

// Save in background
Expand Down
36 changes: 35 additions & 1 deletion src/common/constants/knownModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import { formatModelDisplayName } from "../utils/ai/modelDisplay";

type ModelProvider = "anthropic" | "openai" | "google" | "xai";
type ModelProvider = "anthropic" | "openai" | "google" | "xai" | "azure-foundry" | "azure-openai";

interface KnownModelDefinition {
/** Provider identifier used by SDK factories */
Expand Down Expand Up @@ -46,6 +46,40 @@ const MODEL_DEFINITIONS = {
aliases: ["haiku"],
tokenizerOverride: "anthropic/claude-3.5-haiku",
},
AZURE_FOUNDRY_OPUS: {
provider: "azure-foundry",
providerModelId: "claude-opus-4-5",
aliases: ["azure-opus", "foundry-opus"],
},
AZURE_FOUNDRY_SONNET: {
provider: "azure-foundry",
providerModelId: "claude-sonnet-4-5",
aliases: ["azure-sonnet", "foundry-sonnet"],
},
AZURE_FOUNDRY_HAIKU: {
provider: "azure-foundry",
providerModelId: "claude-haiku-4-5",
aliases: ["azure-haiku", "foundry-haiku"],
},
// Azure OpenAI models (GPT via Azure)
AZURE_OPENAI_GPT: {
provider: "azure-openai",
providerModelId: "gpt-5.2",
aliases: ["azure-gpt"],
tokenizerOverride: "openai/gpt-5",
},
AZURE_OPENAI_GPT_CODEX: {
provider: "azure-openai",
providerModelId: "gpt-5.1-codex",
aliases: ["azure-codex"],
tokenizerOverride: "openai/gpt-5",
},
AZURE_OPENAI_GPT_CODEX_MAX: {
provider: "azure-openai",
providerModelId: "gpt-5.1-codex-max",
aliases: ["azure-codex-max"],
tokenizerOverride: "openai/gpt-5",
},
GPT: {
provider: "openai",
providerModelId: "gpt-5.2",
Expand Down
12 changes: 12 additions & 0 deletions src/common/constants/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ export const PROVIDER_DEFINITIONS = {
factoryName: "createAnthropic",
requiresApiKey: true,
},
"azure-foundry": {
displayName: "Azure Foundry",
import: () => import("@ai-sdk/anthropic"), // Uses Anthropic SDK with Azure baseURL
factoryName: "createAnthropic",
requiresApiKey: true,
},
"azure-openai": {
displayName: "Azure OpenAI",
import: () => import("@ai-sdk/azure"), // Uses Azure OpenAI SDK
factoryName: "createAzure",
requiresApiKey: true,
},
openai: {
displayName: "OpenAI",
import: () => import("@ai-sdk/openai"),
Expand Down
6 changes: 6 additions & 0 deletions src/common/orpc/schemas/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ export const ProviderConfigInfoSchema = z.object({
/** Whether this provider is configured and ready to use */
isConfigured: z.boolean(),
baseUrl: z.string().optional(),
/** Azure Foundry resource name */
resource: z.string().optional(),
/** Azure OpenAI deployment name */
deployment: z.string().optional(),
/** Azure OpenAI API version */
apiVersion: z.string().optional(),
models: z.array(z.string()).optional(),
/** OpenAI-specific fields */
serviceTier: z.enum(["auto", "default", "flex", "priority"]).optional(),
Expand Down
Loading