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
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
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",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user