- Nueva interfaz Discoverer con Refresh() por backend - Kilo: full auto (isFree + metadata completa del upstream) - OpenCode: heurística -free para descubrir nuevos free - Kimchi: agrega todos los IDs no-curados del upstream - discoveryLoop cada 10 min en el Proxy - Backends stateful (mutex + catálogo dinámico) - CREDENCIALES.md y KIMCHI_ANALISIS.md documentan el setup
276 lines
8.8 KiB
Markdown
276 lines
8.8 KiB
Markdown
# Kimchi Dev — Análisis Completo para Integración en Free IDE Proxy
|
|
|
|
## 1. Instalación
|
|
|
|
```bash
|
|
which kimchi
|
|
# /home/ren/.local/bin/kimchi
|
|
```
|
|
|
|
## 2. Configuración Local
|
|
|
|
### Archivos relevantes
|
|
|
|
| Archivo | Propósito |
|
|
|---------|-----------|
|
|
| `~/.config/kimchi/config.json` | Config principal: apiKey, skillPaths, deviceId, onboarding |
|
|
| `~/.config/kimchi/harness/models.json` | Definiciones de proveedores y modelos |
|
|
| `~/.config/kimchi/harness/settings.json` | Settings: defaultProvider, defaultModel, multiModel, etc. |
|
|
| `~/.config/kimchi/harness/auth.json` | Auth por proveedor (oauth, access token) |
|
|
|
|
### `~/.config/kimchi/config.json`
|
|
|
|
```json
|
|
{
|
|
"skillPaths": [
|
|
".config/kimchi/harness/skills",
|
|
".config/opencode/skills"
|
|
],
|
|
"migrationState": "done",
|
|
"apiKey": "castai_v1_befd8c666ce652d47cc08accf8c5accc0a5aaca9e1f006392df69ac123198f9b_4f8f2d40",
|
|
"onboarding": {
|
|
"sessionModeWizardSeenAt": "2026-06-29T13:46:41.351Z"
|
|
},
|
|
"deviceId": "9fb28c0e-dd65-4bac-8c90-c98ac1c26382"
|
|
}
|
|
```
|
|
|
|
### `~/.config/kimchi/harness/auth.json`
|
|
|
|
```json
|
|
{
|
|
"kimchi-dev": {
|
|
"type": "oauth",
|
|
"access": "castai_v1_befd8c666ce652d47cc08accf8c5accc0a5aaca9e1f006392df69ac123198f9b_4f8f2d40",
|
|
"refresh": "",
|
|
"expires": 9007199254740991
|
|
}
|
|
}
|
|
```
|
|
|
|
### `~/.config/kimchi/harness/settings.json`
|
|
|
|
```json
|
|
{
|
|
"quietStartup": true,
|
|
"theme": "kimchi-minimal",
|
|
"retry": { "maxRetries": 10 },
|
|
"lastChangelogVersion": "0.1.50",
|
|
"defaultProvider": "kimchi-dev",
|
|
"defaultModel": "kimi-k2.7",
|
|
"defaultThinkingLevel": "medium",
|
|
"multiModel": true,
|
|
"rtkAutoInstallCheckedAt": 1782740800268
|
|
}
|
|
```
|
|
|
|
## 3. Endpoint del API
|
|
|
|
### Configuración del proveedor (desde `models.json`)
|
|
|
|
```json
|
|
"kimchi-dev": {
|
|
"baseUrl": "https://llm.kimchi.dev/openai/v1",
|
|
"apiKey": "$KIMCHI_API_KEY",
|
|
"api": "openai-completions",
|
|
"authHeader": true,
|
|
"headers": {
|
|
"User-Agent": "kimchi/0.1.50"
|
|
},
|
|
"models": [
|
|
...
|
|
]
|
|
}
|
|
```
|
|
|
|
### Resumen del endpoint
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| **Base URL** | `https://llm.kimchi.dev/openai/v1` |
|
|
| **Chat Completions** | `POST https://llm.kimchi.dev/openai/v1/chat/completions` |
|
|
| **Models listing** | `GET https://llm.kimchi.dev/openai/v1/models` |
|
|
| **API format** | OpenAI Chat Completions estándar |
|
|
| **Auth** | `Authorization: Bearer <access_token>` (`authHeader: true`) |
|
|
| **User-Agent** | `kimchi/0.1.50` |
|
|
| **Provider upstream** | castai (ai-enabler) |
|
|
|
|
### Auth token
|
|
|
|
- **Access token (hardcodeado):** `castai_v1_befd8c666ce652d47cc08accf8c5accc0a5aaca9e1f006392df69ac123198f9b_4f8f2d40`
|
|
- **Tipo:** oauth
|
|
- **Expira:** `9007199254740991` (nunca, es un token estático)
|
|
- **Env var equivalente:** `KIMCHI_API_KEY` (el provider usa `${KIMCHI_API_KEY}` en `apiKey`)
|
|
|
|
### Verificación con curl
|
|
|
|
```bash
|
|
# Listar modelos
|
|
curl -s https://llm.kimchi.dev/openai/v1/models \
|
|
-H "Authorization: Bearer castai_v1_befd8c666ce652d47cc08accf8c5accc0a5aaca9e1f006392df69ac123198f9b_4f8f2d40" \
|
|
-H "User-Agent: kimchi/0.1.50"
|
|
|
|
# Chat completion
|
|
curl -s https://llm.kimchi.dev/openai/v1/chat/completions \
|
|
-H "Authorization: Bearer castai_v1_befd8c666ce652d47cc08accf8c5accc0a5aaca9e1f006392df69ac123198f9b_4f8f2d40" \
|
|
-H "User-Agent: kimchi/0.1.50" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"model": "deepseek-v4-flash",
|
|
"messages": [{"role": "user", "content": "Decime solo SI"}],
|
|
"max_tokens": 500
|
|
}'
|
|
```
|
|
|
|
## 4. Modelos
|
|
|
|
### Categorización
|
|
|
|
Hay **13 modelos** que responde el upstream, pero **5 están curados** (con metadata completa en `models.json`). Los otros 8 aparecen en `/models` pero no tienen definición local.
|
|
|
|
### Los 5 curados (metadata de `models.json`)
|
|
|
|
| Modelo ID | Contexto | Max Tokens | Razonamiento | Vision | Tags |
|
|
|-----------|----------|-----------|:---:|:---:|------|
|
|
| `deepseek-v4-flash` | 1,048,576 (1M) | 1,048,576 (1M) | ✅ Sí | ❌ | DeepSeek V4, 284B params, propósito general |
|
|
| `glm-5.2-fp8` | 1,048,576 (1M) | 1,048,576 (1M) | ✅ Sí | ❌ | GLM, FP8 cuantizado, rendimiento |
|
|
| `kimi-k2.7` | 262,144 (262K) | 262,144 (262K) | ✅ Sí | ✅ Sí | Moonshot AI, multimodal, visión |
|
|
| `minimax-m3` | 1,048,576 (1M) | 1,048,576 (1M) | ✅ Sí | ✅ Sí | MiniMax, multimodal, texto+imagen |
|
|
| `nemotron-3-ultra-fp4` | 1,048,576 (1M) | 1,048,576 (1M) | ✅ Sí | ❌ | NVIDIA, 550B params, FP4 |
|
|
|
|
Costos: todos gratuitos (0 input, 0 output, 0 cache).
|
|
|
|
### Los 8 extras del upstream (sin metadata)
|
|
|
|
| Modelo ID | Notas |
|
|
|-----------|-------|
|
|
| `kimi-k2.5` | Versión anterior de kimi |
|
|
| `kimi-k2.6` | Versión anterior de kimi |
|
|
| `minimax-m2.5` | Versión anterior de minimax |
|
|
| `minimax-m2.7` | Versión anterior de minimax |
|
|
| `nemotron-3-super-fp4` | Variante "super" de nemotron, posiblemente más grande |
|
|
| `qwen3-coder-next-fp8` | 🔥 **Interesante**: modelo de código Qwen, FP8 |
|
|
| `smollm2-135m` | Toy — 135M params |
|
|
| `smollm2-360m` | Toy — 360M params |
|
|
|
|
### IDs en el upstream
|
|
|
|
El upstream responde con estos IDs exactos. No tienen sufijo `-free` (a diferencia de opencode). Esto evita colisiones con los modelos existentes del proxy.
|
|
|
|
### Comparativa con modelos existentes del proxy
|
|
|
|
| Modelo | En opencode backend | En kimchi backend |
|
|
|--------|:-:|:-:|
|
|
| deepseek-v4 | `deepseek-v4-flash-free` | `deepseek-v4-flash` (sin `-free`, distinto) |
|
|
| nemotron-3 | `nemotron-3-ultra-free` | `nemotron-3-ultra-fp4` (distinto, cuantizado FP4) |
|
|
|
|
Son IDs diferentes, no hay colisión.
|
|
|
|
## 5. Estructura del Proxy Relevante para Integración
|
|
|
|
### Interfaz Backend (`internal/proxy/backend.go`)
|
|
|
|
```go
|
|
type Backend interface {
|
|
Name() string
|
|
Models() []ModelInfo
|
|
Resolve(model string) (resolved string, ok bool)
|
|
ChatURL() string
|
|
Headers(requestID, sessionID string) map[string]string
|
|
}
|
|
```
|
|
|
|
### Registro en `NewProxy` (`internal/proxy/models.go:61`)
|
|
|
|
```go
|
|
func NewProxy(apiKey string) *Proxy {
|
|
oc := OpenCodeBackend{}
|
|
kl := KiloBackend{}
|
|
// KimchiBackend{} acá
|
|
p := &Proxy{
|
|
backends: []Backend{kl, oc}, // ← agregar KimchiBackend
|
|
...
|
|
}
|
|
}
|
|
```
|
|
|
|
### Orden de backends
|
|
|
|
Más específicos primero, para que rutas exactas ganen sobre alias:
|
|
|
|
```
|
|
KimchiBackend → KiloBackend → OpenCodeBackend (default)
|
|
```
|
|
|
|
### Patrón de implementación: `kilo.go` (plantilla exacta)
|
|
|
|
`kilo.go` es el template perfecto:
|
|
|
|
1. Const con la base URL
|
|
2. Struct vacío `KiloBackend struct{}`
|
|
3. Slice `kiloFreeModels []ModelInfo` con los modelos
|
|
4. Map `kiloAliases map[string]string`
|
|
5. Implementar `Name()`, `Models()`, `Resolve()`, `ChatURL()`, `Headers()`
|
|
|
|
### Manejo del API key
|
|
|
|
3 opciones identificadas:
|
|
|
|
| Opción | Cómo | Pros | Contras |
|
|
|--------|------|------|---------|
|
|
| **A) Env var `KIMCHI_API_KEY`** | `os.Getenv("KIMCHI_API_KEY")` en `Headers()` | Sin secretos en git, clave en systemd `Environment=` | Requiere configurar env var |
|
|
| **B) Hardcodear** | Const string igual que `"public"` en opencode | Simple | **La key queda en el repo** |
|
|
| **C) Leer config.json** | Parsear `~/.config/kimchi/config.json` en startup | Auto, no requiere config extra | Acopla proxy a ruta fija del disco |
|
|
|
|
**Recomendación: Opción A (env var)**. La key se configura solo en `~/.config/systemd/user/free-ide-proxy.service`, fuera del repo.
|
|
|
|
### `ModelByID` y routing de visión
|
|
|
|
El proxy tiene `ModelByID()` en `opencode.go` que solo revisa `zenModels`. Si se integran modelos con visión de kimchi (`kimi-k2.7`, `minimax-m3`), `ModelByID` no los encontrará. Habría que extender `ModelByID()` para que revise todos los backends, o crear un map global por ID.
|
|
|
|
## 6. Posibles Alias para el Backend Kimchi
|
|
|
|
Cuidando de no pisar alias existentes de opencode/kilo:
|
|
|
|
| Alias propuesto | Resuelve a |
|
|
|----------------|------------|
|
|
| `kimchi/deepseek` | `deepseek-v4-flash` |
|
|
| `kimchi/glm` | `glm-5.2-fp8` |
|
|
| `kimchi/kimi` | `kimi-k2.7` |
|
|
| `kimchi/minimax` | `minimax-m3` |
|
|
| `kimchi/nemotron` | `nemotron-3-ultra-fp4` |
|
|
| `kimchi/qwen` | `qwen3-coder-next-fp8` |
|
|
| `kimchi` | `deepseek-v4-flash` (alias default) |
|
|
|
|
Sin alias cortos sueltos (`deepseek`, `nemotron`) para no pisar los de opencode.
|
|
|
|
## 7. Archivos a Modificar
|
|
|
|
| Archivo | Acción |
|
|
|---------|--------|
|
|
| `internal/proxy/kimchi.go` | **CREAR** — backend completo |
|
|
| `internal/proxy/models.go` | **EDITAR** — registrar `KimchiBackend{}` en `NewProxy()` |
|
|
| `internal/proxy/opencode.go` | **EDITAR** — extender `ModelByID()` global o crear `AllModelsByID()` |
|
|
| `~/.config/systemd/user/free-ide-proxy.service` | **EDITAR** — agregar `Environment=KIMCHI_API_KEY=...` |
|
|
| `CREDENCIALES.md` | **EDITAR** — agregar sección de kimchi |
|
|
|
|
## 8. Comandos de Build y Deploy
|
|
|
|
```bash
|
|
# Build
|
|
cd /home/ren/ide_proxy
|
|
go build -o free-ide-proxy .
|
|
|
|
# Restart service
|
|
systemctl --user daemon-reload
|
|
systemctl --user restart free-ide-proxy
|
|
|
|
# Check logs
|
|
journalctl --user -u free-ide-proxy -f
|
|
|
|
# Test
|
|
curl -s http://127.0.0.1:6446/v1/chat/completions \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"Hola"}],"max_tokens":500}'
|
|
```
|