Skip to content

Commit 580111d

Browse files
authored
🤖 feat: add mux-gateway provider (#772)
Add new `mux-gateway` provider that uses `createGateway` from the AI SDK. ## Configuration In `~/.mux/providers.jsonc`: ```jsonc { "mux-gateway": { "couponCode": "your-coupon-code-here" } } ``` Then use models like `mux-gateway:claude-3-5-sonnet-20241022`. ## Changes - Add `importMuxGateway()` and registry entry in `providers.ts` - Add `mux-gateway` handler in `aiService.ts` using hardcoded baseURL - Add `couponCodeSet` field to settings UI (no baseUrl field exposed) - Update schemas and types for the new provider _Generated with `mux`_
1 parent a2a417e commit 580111d

File tree

5 files changed

+70
-0
lines changed

5 files changed

+70
-0
lines changed

src/browser/components/Settings/sections/ProvidersSection.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ function getProviderFields(provider: ProviderName): FieldConfig[] {
4444
];
4545
}
4646

47+
// Mux Gateway only needs couponCode
48+
if (provider === "mux-gateway") {
49+
return [
50+
{ key: "couponCode", label: "Coupon Code", placeholder: "Enter coupon code", type: "secret" },
51+
];
52+
}
53+
4754
// Default for most providers
4855
return [
4956
{ key: "apiKey", label: "API Key", placeholder: "Enter API key", type: "secret" },
@@ -138,6 +145,11 @@ export function ProvidersSection() {
138145
);
139146
}
140147

148+
// For Mux Gateway, check couponCodeSet
149+
if (provider === "mux-gateway") {
150+
return providerConfig.couponCodeSet ?? false;
151+
}
152+
141153
// For other providers, check apiKeySet
142154
return providerConfig.apiKeySet ?? false;
143155
};
@@ -153,6 +165,8 @@ export function ProvidersSection() {
153165
if (fieldConfig.type === "secret") {
154166
// For apiKey, we have apiKeySet from the sanitized config
155167
if (field === "apiKey") return config[provider]?.apiKeySet ?? false;
168+
// For couponCode (mux-gateway), check couponCodeSet
169+
if (field === "couponCode") return config[provider]?.couponCodeSet ?? false;
156170
// For other secrets, check if the field exists in the raw config
157171
// Since we don't expose secret values, we assume they're not set if undefined
158172
const providerConfig = config[provider] as Record<string, unknown> | undefined;

src/browser/components/Settings/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ export interface ProviderConfigDisplay {
1616
bearerTokenSet?: boolean;
1717
accessKeyIdSet?: boolean;
1818
secretAccessKeySet?: boolean;
19+
// Mux Gateway-specific fields
20+
couponCodeSet?: boolean;
1921
// Allow additional fields for extensibility
2022
[key: string]: unknown;
2123
}

src/common/constants/providers.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ export async function importBedrock() {
5555
return import("@ai-sdk/amazon-bedrock");
5656
}
5757

58+
/**
59+
* Dynamically import the Gateway provider from the AI SDK
60+
*/
61+
export async function importMuxGateway() {
62+
return import("ai");
63+
}
64+
5865
/**
5966
* Centralized provider registry mapping provider names to their import functions
6067
*
@@ -76,6 +83,7 @@ export const PROVIDER_REGISTRY = {
7683
ollama: importOllama,
7784
openrouter: importOpenRouter,
7885
bedrock: importBedrock,
86+
"mux-gateway": importMuxGateway,
7987
} as const;
8088

8189
/**
@@ -99,6 +107,7 @@ export const PROVIDER_DISPLAY_NAMES: Record<ProviderName, string> = {
99107
ollama: "Ollama",
100108
openrouter: "OpenRouter",
101109
bedrock: "Amazon Bedrock",
110+
"mux-gateway": "Mux Gateway",
102111
};
103112

104113
/**

src/node/services/aiService.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,25 @@ export class AIService extends EventEmitter {
656656
return Ok(provider(modelId));
657657
}
658658

659+
// Handle Mux Gateway provider
660+
if (providerName === "mux-gateway") {
661+
// Mux Gateway uses couponCode as the API key
662+
const couponCode = providerConfig.couponCode;
663+
if (typeof couponCode !== "string" || !couponCode) {
664+
return Err({
665+
type: "api_key_not_found",
666+
provider: providerName,
667+
});
668+
}
669+
670+
const { createGateway } = await PROVIDER_REGISTRY["mux-gateway"]();
671+
const gateway = createGateway({
672+
apiKey: couponCode,
673+
baseURL: "https://gateway.mux.coder.com/api/v1/ai-gateway/v1/ai",
674+
});
675+
return Ok(gateway(modelId));
676+
}
677+
659678
return Err({
660679
type: "provider_not_supported",
661680
provider: providerName,

src/node/services/ipcMain.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,6 +1467,14 @@ export class IpcMain {
14671467
// Load current providers config or create empty
14681468
const providersConfig = this.config.loadProvidersConfig() ?? {};
14691469

1470+
// Track if this is first time setting couponCode for mux-gateway
1471+
const isFirstMuxGatewayCoupon =
1472+
provider === "mux-gateway" &&
1473+
keyPath.length === 1 &&
1474+
keyPath[0] === "couponCode" &&
1475+
value !== "" &&
1476+
!providersConfig[provider]?.couponCode;
1477+
14701478
// Ensure provider exists
14711479
if (!providersConfig[provider]) {
14721480
providersConfig[provider] = {};
@@ -1492,6 +1500,19 @@ export class IpcMain {
14921500
}
14931501
}
14941502

1503+
// Add default models when setting up mux-gateway for the first time
1504+
if (isFirstMuxGatewayCoupon) {
1505+
const providerConfig = providersConfig[provider] as Record<string, unknown>;
1506+
if (!providerConfig.models || (providerConfig.models as string[]).length === 0) {
1507+
providerConfig.models = [
1508+
"anthropic/claude-sonnet-4-5-20250514",
1509+
"anthropic/claude-opus-4-5-20250514",
1510+
"openai/gpt-5.1",
1511+
"openai/gpt-5.1-codex",
1512+
];
1513+
}
1514+
}
1515+
14951516
// Save updated config
14961517
this.config.saveProvidersConfig(providersConfig);
14971518

@@ -1562,6 +1583,11 @@ export class IpcMain {
15621583
providerData.secretAccessKeySet = !!providerConfig.secretAccessKey;
15631584
}
15641585

1586+
// Mux Gateway-specific fields
1587+
if (provider === "mux-gateway") {
1588+
providerData.couponCodeSet = !!providerConfig.couponCode;
1589+
}
1590+
15651591
sanitized[provider] = providerData;
15661592
}
15671593
return sanitized;

0 commit comments

Comments
 (0)