Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
5 changes: 5 additions & 0 deletions .changeset/green-sheep-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"kilo-code": minor
---

feat: add Zenmux provider
197 changes: 197 additions & 0 deletions apps/kilocode-docs/pages/ai-providers/zenmux.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
---
title: ZenMux
---

import Codicon from "@site/src/components/Codicon";

# Using ZenMux With Kilo Code

[ZenMux](https://zenmux.ai) provides a unified API gateway to access multiple AI models from different providers through a single endpoint. It supports OpenAI, Anthropic, Google, and other major AI providers, automatically handling routing, fallbacks, and cost optimization.

## Getting Started

1. **Sign up for ZenMux:** Visit [zenmux.ai](https://zenmux.ai) to create an account.
2. **Get your API key:** After signing up, navigate to your dashboard to generate an API key.
3. **Configure in Kilo Code:** Add your API key to Kilo Code settings.

## Configuration in Kilo Code

1. **Open Kilo Code Settings:** Click the gear icon (<Codicon name="gear" />) in the Kilo Code panel.
2. **Select Provider:** Choose "ZenMux" from the "API Provider" dropdown.
3. **Enter API Key:** Paste your ZenMux API key into the "ZenMux API Key" field.
4. **Select Model:** Choose your desired model from the "Model" dropdown.
5. **(Optional) Custom Base URL:** If you need to use a custom base URL for the ZenMux API, check "Use custom base URL" and enter the URL. Leave this blank for most users.

## Supported Models

ZenMux supports a wide range of models from various providers:

Visi [zenmux.ai/models](https://zenmux.ai/models) to see the complete list of available models.

### Other Providers

ZenMux also supports models from Meta, Mistral, and many other providers. Check your ZenMux dashboard for the complete list of available models.

## API Compatibility

ZenMux provides multiple API endpoints for different protocols:

### OpenAI Compatible API

Use the standard OpenAI SDK with ZenMux's base URL:

```javascript
import OpenAI from "openai"

const openai = new OpenAI({
baseURL: "https://zenmux.ai/api/v1",
apiKey: "<ZENMUX_API_KEY>",
})

async function main() {
const completion = await openai.chat.completions.create({
model: "openai/gpt-5",
messages: [
{
role: "user",
content: "What is the meaning of life?",
},
],
})

console.log(completion.choices[0].message)
}

main()
```

### Anthropic API

For Anthropic models, use the dedicated endpoint:

```typescript
import Anthropic from "@anthropic-ai/sdk"

// 1. Initialize the Anthropic client
const anthropic = new Anthropic({
// 2. Replace with the API key from your ZenMux console
apiKey: "<YOUR ZENMUX_API_KEY>",
// 3. Point the base URL to the ZenMux endpoint
baseURL: "https://zenmux.ai/api/anthropic",
})

async function main() {
const msg = await anthropic.messages.create({
model: "anthropic/claude-sonnet-4.5",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello, Claude" }],
})
console.log(msg)
}

main()
```

### Platform API

The Get generation interface is used to query generation information, such as usage and costs.

```bash
curl https://zenmux.ai/api/v1/generation?id=<generation_id> \
-H "Authorization: Bearer $ZENMUX_API_KEY"
```

### Google Vertex AI API

For Google models:

```typescript
const genai = require("@google/genai")

const client = new genai.GoogleGenAI({
apiKey: "$ZENMUX_API_KEY",
vertexai: true,
httpOptions: {
baseUrl: "https://zenmux.ai/api/vertex-ai",
apiVersion: "v1",
},
})

const response = await client.models.generateContent({
model: "google/gemini-2.5-pro",
contents: "How does AI work?",
})
console.log(response)
```

## Features

### Automatic Routing

ZenMux automatically routes your requests to the best available provider based on:

- Model availability
- Response time
- Cost optimization
- Provider health status

### Fallback Support

If a provider is unavailable, ZenMux automatically falls back to alternative providers that support the same model capabilities.

### Cost Optimization

ZenMux can be configured to optimize for cost, routing requests to the most cost-effective provider while maintaining quality.

### Zero Data Retention (ZDR)

Enable ZDR mode to ensure that no request or response data is stored by ZenMux, providing maximum privacy for sensitive applications.

## Advanced Configuration

### Provider Routing

You can specify routing preferences:

- **Price**: Route to the lowest cost provider
- **Throughput**: Route to the provider with highest tokens/second
- **Latency**: Route to the provider with fastest response time

### Data Collection Settings

Control how ZenMux handles your data:

- **Allow**: Allow data collection for service improvement
- **Deny**: Disable all data collection

### Middle-Out Transform

Enable the middle-out transform feature to optimize prompts that exceed model context limits.

## Troubleshooting

### API Key Issues

- Ensure your API key is correctly copied without any extra spaces
- Check that your ZenMux account is active and has available credits
- Verify the API key has the necessary permissions

### Model Availability

- Some models may have regional restrictions
- Check the ZenMux dashboard for current model availability
- Ensure your account tier has access to the desired models

### Connection Issues

- Verify your internet connection
- Check if you're behind a firewall that might block API requests
- Try using a custom base URL if the default endpoint is blocked

## Support

For additional support:

- Visit the [ZenMux documentation](https://zenmux.ai/docs)
- Contact ZenMux support through their dashboard
- Check the [Kilo Code GitHub repository](https://github.com/kilocode/kilocode) for integration-specific issues
2 changes: 2 additions & 0 deletions cli/src/config/mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ export function getModelIdForProvider(provider: ProviderConfig): string {
return provider.apiModelId || ""
case "openrouter":
return provider.openRouterModelId || ""
case "zenmux":
return provider.zenmuxModelId || ""
case "ollama":
return provider.ollamaModelId || ""
case "lmstudio":
Expand Down
1 change: 1 addition & 0 deletions cli/src/constants/providers/labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const PROVIDER_LABELS: Record<ProviderName, string> = {
"openai-codex": "OpenAI - ChatGPT Plus/Pro",
"openai-responses": "OpenAI Compatible (Responses)",
openrouter: "OpenRouter",
zenmux: "ZenMux",
bedrock: "Amazon Bedrock",
gemini: "Google Gemini",
vertex: "GCP Vertex AI",
Expand Down
11 changes: 9 additions & 2 deletions cli/src/constants/providers/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
minimaxModels,
minimaxDefaultModelId,
ovhCloudAiEndpointsDefaultModelId,
zenmuxDefaultModelId,
} from "@roo-code/types"

/**
Expand All @@ -64,6 +65,7 @@ export type RouterName =
| "deepinfra"
| "vercel-ai-gateway"
| "ovhcloud"
| "zenmux"
| "nano-gpt"

/**
Expand Down Expand Up @@ -120,6 +122,7 @@ export type RouterModels = Record<RouterName, ModelRecord>
export const PROVIDER_TO_ROUTER_NAME: Record<ProviderName, RouterName | null> = {
kilocode: "kilocode",
openrouter: "openrouter",
zenmux: "zenmux", // kilocode_change
ollama: "ollama",
lmstudio: "lmstudio",
litellm: "litellm",
Expand Down Expand Up @@ -165,7 +168,7 @@ export const PROVIDER_TO_ROUTER_NAME: Record<ProviderName, RouterName | null> =
synthetic: null,
"sap-ai-core": null,
baseten: null,
corethink: null
corethink: null,
}

/**
Expand All @@ -174,6 +177,7 @@ export const PROVIDER_TO_ROUTER_NAME: Record<ProviderName, RouterName | null> =
export const PROVIDER_MODEL_FIELD: Record<ProviderName, string | null> = {
kilocode: "kilocodeModel",
openrouter: "openRouterModelId",
zenmux: "zenmuxModelId", // kilocode_change
ollama: "ollamaModelId",
lmstudio: "lmStudioModelId",
litellm: "litellmModelId",
Expand Down Expand Up @@ -219,7 +223,7 @@ export const PROVIDER_MODEL_FIELD: Record<ProviderName, string | null> = {
synthetic: null,
"sap-ai-core": "sapAiCoreModelId",
baseten: null,
corethink: null
corethink: null,
}

/**
Expand Down Expand Up @@ -285,6 +289,7 @@ export const DEFAULT_MODEL_IDS: Partial<Record<ProviderName, string>> = {
zai: internationalZAiDefaultModelId,
roo: rooDefaultModelId,
ovhcloud: ovhCloudAiEndpointsDefaultModelId,
zenmux: zenmuxDefaultModelId,
}

/**
Expand Down Expand Up @@ -460,6 +465,8 @@ export function getModelIdKey(provider: ProviderName): string {
return "vercelAiGatewayModelId"
case "ovhcloud":
return "ovhCloudAiEndpointsModelId"
case "zenmux":
return "zenmuxModelId"
case "nano-gpt":
return "nanoGptModelId"
default:
Expand Down
27 changes: 27 additions & 0 deletions cli/src/constants/providers/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,25 @@ export const FIELD_REGISTRY: Record<string, FieldMetadata> = {
placeholder: "Enter base URL (or leave empty for default)...",
isOptional: true,
},

// kilocode_change start - ZenMux fields
zenmuxApiKey: {
label: "API Key",
type: "password",
placeholder: "Enter ZenMux API key...",
},
zenmuxModelId: {
label: "Model",
type: "text",
placeholder: "Enter model name...",
},
zenmuxBaseUrl: {
label: "Base URL",
type: "text",
placeholder: "Enter base URL (or leave empty for default)...",
isOptional: true,
},
// kilocode_change end
openRouterProviderDataCollection: {
label: "Provider Data Collection",
type: "select",
Expand Down Expand Up @@ -791,6 +810,13 @@ export const getProviderSettings = (provider: ProviderName, config: ProviderSett
createFieldConfig("openRouterBaseUrl", config, "Default"),
]

case "zenmux": // kilocode_change
return [
createFieldConfig("zenmuxApiKey", config),
createFieldConfig("zenmuxModelId", config, "openai/gpt-5"),
createFieldConfig("zenmuxBaseUrl", config, "Default"),
]

case "openai-native":
return [
createFieldConfig("openAiNativeApiKey", config),
Expand Down Expand Up @@ -1043,6 +1069,7 @@ export const PROVIDER_DEFAULT_MODELS: Record<ProviderName, string> = {
"openai-codex": "gpt-4o",
"openai-responses": "gpt-4o",
openrouter: "anthropic/claude-3-5-sonnet",
zenmux: "openai/gpt-5", // kilocode_change
bedrock: "anthropic.claude-3-5-sonnet-20241022-v2:0",
gemini: "gemini-1.5-pro-latest",
vertex: "claude-3-5-sonnet@20241022",
Expand Down
1 change: 1 addition & 0 deletions cli/src/constants/providers/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const PROVIDER_REQUIRED_FIELDS: Record<ProviderName, string[]> = {
"openai-native": ["openAiNativeApiKey", "apiModelId"],
"openai-codex": ["apiModelId"],
openrouter: ["openRouterApiKey", "openRouterModelId"],
zenmux: ["zenmuxApiKey", "zenmuxModelId"], // kilocode_change
ollama: ["ollamaBaseUrl", "ollamaModelId"],
lmstudio: ["lmStudioBaseUrl", "lmStudioModelId"],
bedrock: ["awsRegion", "apiModelId"], // Auth fields handled in handleSpecialValidations (supports API key, profile, or direct credentials)
Expand Down
17 changes: 17 additions & 0 deletions packages/core-schemas/src/config/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,21 @@ export const openRouterProviderSchema = baseProviderSchema.extend({
openRouterZdr: z.boolean().optional(),
})

// kilocode_change start
// ZenMux provider
export const zenmuxProviderSchema = baseProviderSchema.extend({
provider: z.literal("zenmux"),
zenmuxModelId: z.string().optional(),
zenmuxApiKey: z.string().optional(),
zenmuxBaseUrl: z.string().optional(),
zenmuxSpecificProvider: z.string().optional(),
zenmuxUseMiddleOutTransform: z.boolean().optional(),
zenmuxProviderDataCollection: z.enum(["allow", "deny"]).optional(),
zenmuxProviderSort: z.enum(["price", "throughput", "latency"]).optional(),
zenmuxZdr: z.boolean().optional(),
})
// kilocode_change end

// Ollama provider
export const ollamaProviderSchema = baseProviderSchema.extend({
provider: z.literal("ollama"),
Expand Down Expand Up @@ -407,6 +422,7 @@ export const providerConfigSchema = z.discriminatedUnion("provider", [
openAIProviderSchema,
openAIResponsesProviderSchema, // kilocode_change
openRouterProviderSchema,
zenmuxProviderSchema, // kilocode_change
ollamaProviderSchema,
lmStudioProviderSchema,
glamaProviderSchema,
Expand Down Expand Up @@ -453,6 +469,7 @@ export type OpenAICodexProviderConfig = z.infer<typeof openAICodexProviderSchema
export type OpenAIProviderConfig = z.infer<typeof openAIProviderSchema>
export type OpenAIResponsesProviderConfig = z.infer<typeof openAIResponsesProviderSchema> // kilocode_change
export type OpenRouterProviderConfig = z.infer<typeof openRouterProviderSchema>
export type ZenmuxProviderConfig = z.infer<typeof zenmuxProviderSchema> // kilocode_change
export type OllamaProviderConfig = z.infer<typeof ollamaProviderSchema>
export type LMStudioProviderConfig = z.infer<typeof lmStudioProviderSchema>
export type GlamaProviderConfig = z.infer<typeof glamaProviderSchema>
Expand Down
Loading
Loading