Files
free-ide-proxy/internal/proxy/kilo.go
T
Renato 05a52d29e2 feat: multi-backend proxy with auto rate-limit jailing
Refactor from monolithic proxy to multi-backend architecture
(Backend interface: OpenCode Zen + Kilo gateway).

- Add auto rate-limit jailing: models returning HTTP 429 are
  hidden from /v1/models immediately and re-probed every 30 min
- Backend interface supports model aliases, custom headers, and
  per-backend routing
- Full Anthropic Messages API support with OpenAI format conversion
- 9 free models across two backends with Claude name aliases
2026-06-26 19:08:01 +02:00

92 lines
3.0 KiB
Go

package proxy
// KiloGatewayBase is the Kilo Code public gateway base URL.
// Confirmed working without auth for free models (HTTP 200 on both
// GET /api/gateway/models and POST /api/gateway/chat/completions).
const KiloGatewayBase = "https://api.kilo.ai/api/gateway"
// KiloBackend forwards to Kilo Code's free gateway models.
//
// Kilo is an opencode-based CLI whose gateway exposes a handful of free models
// (suffixed ":free") reachable without authentication, in standard OpenAI
// Chat Completions format.
type KiloBackend struct{}
// kiloFreeModels are the free models advertised by the Kilo gateway.
// Sourced from GET /api/gateway/models filtering isFree:true.
var kiloFreeModels = []ModelInfo{
{
ID: "stepfun/step-3.7-flash:free",
Name: "StepFun Step 3.7 Flash (Free)",
OwnedBy: "stepfun",
ContextWindow: 256_000,
MaxOutputTokens: 32_000,
Description: "StepFun. Flash rápido, tareas generales.",
},
{
ID: "poolside/laguna-m.1:free",
Name: "Poolside Laguna M.1 (Free)",
OwnedBy: "poolside",
ContextWindow: 256_000,
MaxOutputTokens: 32_000,
Description: "Poolside. Modelo orientado a código.",
},
{
ID: "nvidia/nemotron-3-ultra-550b-a55b:free",
Name: "Nemotron 3 Ultra 550B (Free)",
OwnedBy: "nvidia",
ContextWindow: 1_000_000,
MaxOutputTokens: 16_384,
Description: "NVIDIA Nemotron 3 Ultra (550B/55B MoE). 1M contexto, razonamiento.",
},
{
ID: "openrouter/free",
Name: "OpenRouter Best Free (Free)",
OwnedBy: "openrouter",
ContextWindow: 256_000,
MaxOutputTokens: 32_000,
Description: "OpenRouter selecciona automáticamente el mejor modelo free disponible.",
},
}
// kiloAliases lets clients use shorter names for Kilo free models.
var kiloAliases = map[string]string{
"stepfun": "stepfun/step-3.7-flash:free",
"stepfun-free": "stepfun/step-3.7-flash:free",
"poolside": "poolside/laguna-m.1:free",
"poolside-free": "poolside/laguna-m.1:free",
"laguna": "poolside/laguna-m.1:free",
"openrouter": "openrouter/free",
}
// Name returns the backend identifier.
func (KiloBackend) Name() string { return "kilo" }
// Models returns the Kilo free models.
func (KiloBackend) Models() []ModelInfo { return kiloFreeModels }
// Resolve maps a requested name to a Kilo free model ID.
func (KiloBackend) Resolve(model string) (string, bool) {
if mapped, ok := kiloAliases[model]; ok {
return mapped, true
}
for _, m := range kiloFreeModels {
if m.ID == model {
return model, true
}
}
return "", false
}
// ChatURL is the Kilo gateway chat completions endpoint.
func (KiloBackend) ChatURL() string { return KiloGatewayBase + "/chat/completions" }
// Headers returns minimal headers for the Kilo gateway (no auth needed for free).
func (KiloBackend) Headers(_, _ string) map[string]string {
return map[string]string{
"Content-Type": "application/json",
"Accept": "text/event-stream, application/json",
"User-Agent": "kilo/7.3.54",
}
}