Skip to content
Open
102 changes: 102 additions & 0 deletions apps/kilocode-docs/docs/providers/aistupidlevel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
sidebar_label: AIStupidLevel
---

# Using AIStupidLevel With Kilo Code

AIStupidLevel is an intelligent AI router that continuously benchmarks 25+ AI models across multiple providers and automatically routes your requests to the best-performing model based on real-time performance data.

**Website:** [https://aistupidlevel.info](https://aistupidlevel.info)

## What is AIStupidLevel?

AIStupidLevel is a smart AI router that provides:

- **Real-time performance benchmarking** of 25+ AI models from OpenAI, Anthropic, Google, xAI, and more
- **Intelligent routing** based on hourly speed tests and daily deep reasoning benchmarks
- **7-axis scoring methodology** (Correctness, Spec Compliance, Code Quality, Efficiency, Stability, Refusal Rate, Recovery)
- **Statistical degradation detection** to automatically avoid poorly performing models
- **Cost optimization** with automatic provider switching
- **Multiple routing strategies** optimized for different use cases

Instead of manually choosing between GPT-4, Claude, Gemini, or other models, AIStupidLevel automatically selects the optimal model for your task based on continuous performance monitoring.

## Getting an API Key

1. **Sign Up:** Go to [https://aistupidlevel.info](https://aistupidlevel.info) and create an account
2. **Navigate to Router:** Click on the "Router" section in the dashboard
3. **Add Provider Keys:** Add your API keys for the providers you want to use (OpenAI, Anthropic, Google, xAI, etc.)
4. **Generate Router Key:** Create a router API key that Kilo Code will use
5. **Copy the Key:** Copy your AIStupidLevel router API key

## Available Routing Strategies

AIStupidLevel offers different "auto" models that optimize for specific use cases:

| Model | Description | Best For |
|-------|-------------|----------|
| `auto` | Best overall performance across all metrics | General-purpose tasks |
| `auto-coding` | Optimized for code generation and quality | Software development, debugging |
| `auto-reasoning` | Best for complex reasoning and problem-solving | Deep analysis, mathematical problems |
| `auto-creative` | Optimized for creative writing quality | Content creation, storytelling |
| `auto-cheapest` | Most cost-effective option | High-volume, budget-conscious tasks |
| `auto-fastest` | Fastest response time | Real-time applications, quick queries |

## 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 "AIStupidLevel" from the "API Provider" dropdown.
3. **Enter API Key:** Paste your AIStupidLevel router API key into the "AIStupidLevel API Key" field.
4. **Select Model:** Choose your desired routing strategy from the "Model" dropdown (e.g., `auto-coding`, `auto-reasoning`, etc.).

## How It Works

When you make a request through Kilo Code:

1. **AIStupidLevel analyzes** current model performance from continuous benchmarks
2. **Selects the optimal model** based on your chosen routing strategy
3. **Routes your request** using your configured provider API keys
4. **Returns the response** with metadata about which model was selected

The router automatically:
- Avoids models experiencing performance degradation
- Routes to cheaper models when performance is comparable
- Provides transparent routing decisions in response headers

## Key Features

- **Degradation Protection:** Automatically avoids models with performance issues
- **Cost Optimization:** Routes to cheaper models when performance is comparable
- **Provider Diversity:** Access models from OpenAI, Anthropic, Google, xAI, DeepSeek, and more through one API
- **Transparent Routing:** Response headers show which model was selected and why
- **Performance Tracking:** Dashboard shows your usage, cost savings, and routing decisions
- **Enterprise SLA:** 99.9% uptime guarantee with multi-region deployment
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than including the marketing copy here, could you include a link to your own pages?


## Response Headers

AIStupidLevel includes custom headers in responses to show routing decisions:

```
X-AISM-Provider: anthropic
X-AISM-Model: claude-sonnet-4-20250514
X-AISM-Reasoning: Selected claude-sonnet-4-20250514 from anthropic for best coding capabilities (score: 42.3). Ranked #1 of 12 available models. Last updated 2h ago.
```

## Pricing

AIStupidLevel charges only for the underlying model usage (at cost) plus a small routing fee. You can monitor costs in real-time through the dashboard at [https://aistupidlevel.info/router](https://aistupidlevel.info/router).

## Tips and Notes

- **Provider Keys Required:** You must add your own provider API keys (OpenAI, Anthropic, etc.) to your AIStupidLevel dashboard before using the router
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should go into the 'Configuration' section above given that its a required activity.

- **Model Selection:** The router automatically selects the best model based on real-time benchmarks - you don't need to manually switch models
- **Performance Monitoring:** Check the [AIStupidLevel dashboard](https://aistupidlevel.info) to see live performance rankings and routing decisions
- **Cost Tracking:** The dashboard shows your cost savings compared to always using premium models

## Learn More

- **Website:** [https://aistupidlevel.info](https://aistupidlevel.info)
- **Router Dashboard:** [https://aistupidlevel.info/router](https://aistupidlevel.info/router)
- **Live Benchmarks:** [https://aistupidlevel.info](https://aistupidlevel.info)
- **Community:** [r/AIStupidLevel](https://www.reddit.com/r/AIStupidlevel)
- **Twitter/X:** [@AIStupidlevel](https://x.com/AIStupidlevel)
11 changes: 11 additions & 0 deletions packages/types/src/provider-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const dynamicProviders = [
"requesty",
"unbound",
"glama",
"aistupidlevel",
] as const

export type DynamicProvider = (typeof dynamicProviders)[number]
Expand Down Expand Up @@ -490,6 +491,11 @@ const vercelAiGatewaySchema = baseProviderSettingsSchema.extend({
vercelAiGatewayModelId: z.string().optional(),
})

const aiStupidLevelSchema = baseProviderSettingsSchema.extend({
aiStupidLevelApiKey: z.string().optional(),
aiStupidLevelModelId: z.string().optional(),
})

const defaultSchema = z.object({
apiProvider: z.undefined(),
})
Expand Down Expand Up @@ -537,6 +543,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv
qwenCodeSchema.merge(z.object({ apiProvider: z.literal("qwen-code") })),
rooSchema.merge(z.object({ apiProvider: z.literal("roo") })),
vercelAiGatewaySchema.merge(z.object({ apiProvider: z.literal("vercel-ai-gateway") })),
aiStupidLevelSchema.merge(z.object({ apiProvider: z.literal("aistupidlevel") })),
defaultSchema,
])

Expand Down Expand Up @@ -583,6 +590,7 @@ export const providerSettingsSchema = z.object({
...qwenCodeSchema.shape,
...rooSchema.shape,
...vercelAiGatewaySchema.shape,
...aiStupidLevelSchema.shape,
...codebaseIndexProviderSchema.shape,
...ovhcloudSchema.shape, // kilocode_change
})
Expand Down Expand Up @@ -620,6 +628,7 @@ export const modelIdKeys = [
"deepInfraModelId",
"kilocodeModel",
"ovhCloudAiEndpointsModelId", // kilocode_change
"aiStupidLevelModelId",
] as const satisfies readonly (keyof ProviderSettings)[]

export type ModelIdKey = (typeof modelIdKeys)[number]
Expand Down Expand Up @@ -676,6 +685,7 @@ export const modelIdKeysByProvider: Record<TypicalProvider, ModelIdKey> = {
kilocode: "kilocodeModel",
"virtual-quota-fallback": "apiModelId",
ovhcloud: "ovhCloudAiEndpointsModelId", // kilocode_change
aistupidlevel: "aiStupidLevelModelId",
}

/**
Expand Down Expand Up @@ -816,6 +826,7 @@ export const MODELS_BY_PROVIDER: Record<
// kilocode_change end
deepinfra: { id: "deepinfra", label: "DeepInfra", models: [] },
"vercel-ai-gateway": { id: "vercel-ai-gateway", label: "Vercel AI Gateway", models: [] },
aistupidlevel: { id: "aistupidlevel", label: "AIStupidLevel", models: [] },

// Local providers; models discovered from localhost endpoints.
lmstudio: { id: "lmstudio", label: "LM Studio", models: [] },
Expand Down
16 changes: 16 additions & 0 deletions packages/types/src/providers/aistupidlevel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { ModelInfo } from "../model.js"

export const aiStupidLevelDefaultModelId = "auto-coding"

export const aiStupidLevelDefaultModelInfo: ModelInfo = {
maxTokens: 8192,
contextWindow: 200000,
supportsImages: true,
supportsComputerUse: false,
supportsPromptCache: false,
inputPrice: 0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we set correct default prices here?

outputPrice: 0,
description: "Optimized for code generation and quality",
}

export const AISTUPIDLEVEL_DEFAULT_TEMPERATURE = 0.7
1 change: 1 addition & 0 deletions packages/types/src/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ export * from "./xai.js"
export * from "./vercel-ai-gateway.js"
export * from "./zai.js"
export * from "./deepinfra.js"
export * from "./aistupidlevel.js"
3 changes: 3 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
VercelAiGatewayHandler,
DeepInfraHandler,
OVHcloudAIEndpointsHandler, // kilocode_change
AIStupidLevelHandler,
} from "./providers"
// kilocode_change start
import { KilocodeOpenrouterHandler } from "./providers/kilocode-openrouter"
Expand Down Expand Up @@ -206,6 +207,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler {
case "ovhcloud":
return new OVHcloudAIEndpointsHandler(options)
// kilocode_change end
case "aistupidlevel":
return new AIStupidLevelHandler(options)
default:
apiProvider satisfies "gemini-cli" | undefined
return new AnthropicHandler(options)
Expand Down
98 changes: 98 additions & 0 deletions src/api/providers/aistupidlevel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"

import { aiStupidLevelDefaultModelId, aiStupidLevelDefaultModelInfo } from "@roo-code/types"

import { ApiHandlerOptions } from "../../shared/api"

import { ApiStream } from "../transform/stream"
import { convertToOpenAiMessages } from "../transform/openai-format"

import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { RouterProvider } from "./router-provider"

const AISTUPIDLEVEL_DEFAULT_TEMPERATURE = 0.7

export class AIStupidLevelHandler extends RouterProvider implements SingleCompletionHandler {
constructor(options: ApiHandlerOptions) {
super({
options,
name: "aistupidlevel",
baseURL: "https://api.aistupidlevel.info/v1",
apiKey: options.aiStupidLevelApiKey,
modelId: options.aiStupidLevelModelId,
defaultModelId: aiStupidLevelDefaultModelId,
defaultModelInfo: aiStupidLevelDefaultModelInfo,
})
}

override async *createMessage(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no non-streaming path implemented here. But your implementation of completePrompt() below certainly implies your service supports it.

Is it intentional to only support streaming for agentic activity?

systemPrompt: string,
messages: Anthropic.Messages.MessageParam[],
metadata?: ApiHandlerCreateMessageMetadata,
): ApiStream {
const { id: modelId, info } = await this.fetchModel()

const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
{ role: "system", content: systemPrompt },
...convertToOpenAiMessages(messages),
]

const body: OpenAI.Chat.ChatCompletionCreateParams = {
model: modelId,
messages: openAiMessages,
temperature: this.supportsTemperature(modelId)
? (this.options.modelTemperature ?? AISTUPIDLEVEL_DEFAULT_TEMPERATURE)
: undefined,
max_completion_tokens: info.maxTokens,
stream: true,
}

const completion = await this.client.chat.completions.create(body)

for await (const chunk of completion) {
const delta = chunk.choices[0]?.delta
if (delta?.content) {
yield {
type: "text",
text: delta.content,
}
}

if (chunk.usage) {
yield {
type: "usage",
inputTokens: chunk.usage.prompt_tokens || 0,
outputTokens: chunk.usage.completion_tokens || 0,
totalCost: 0, // AIStupidLevel handles cost tracking in their dashboard
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If total cost information isn't available in the response, we should not override it to zero. Can you use undefined, or null, or exclude it from the response?

}
}
}
}

async completePrompt(prompt: string): Promise<string> {
const { id: modelId, info } = await this.fetchModel()

try {
const requestOptions: OpenAI.Chat.ChatCompletionCreateParams = {
model: modelId,
messages: [{ role: "user", content: prompt }],
stream: false,
}

if (this.supportsTemperature(modelId)) {
requestOptions.temperature = this.options.modelTemperature ?? AISTUPIDLEVEL_DEFAULT_TEMPERATURE
}

requestOptions.max_completion_tokens = info.maxTokens

const response = await this.client.chat.completions.create(requestOptions)
return response.choices[0]?.message.content || ""
} catch (error) {
if (error instanceof Error) {
throw new Error(`AIStupidLevel completion error: ${error.message}`)
}
throw error
}
}
}
Loading