107 lines
4.0 KiB
Markdown
107 lines
4.0 KiB
Markdown
# Migration provider IA → OpenCode Go (+ fallback OpenRouter)
|
|
|
|
**Instance auteur** : hermes-perso (transverse aux 3)
|
|
**Date** : 2026-06-14
|
|
**Tags** : infra, opencode, hermes, family-help, llm, fallback
|
|
**Statut** : valide
|
|
|
|
---
|
|
|
|
## Probleme
|
|
|
|
Basculer le provider IA par defaut de OpenRouter vers OpenCode Go (endpoint
|
|
`zen/go/v1`), tout en gardant DeepSeek V4 Flash et un fallback OpenRouter.
|
|
Concerne les 3 agents Hermes (gateway) + l'app family-help (module medical).
|
|
|
|
---
|
|
|
|
## Contexte et contraintes
|
|
|
|
- Image `nousresearch/hermes-agent:latest`, source montee dans `/opt/hermes`.
|
|
- Les 3 Hermes sont des **stacks Portainer** : 291=nyora, 292=perso (path-based,
|
|
compose sur le FS), 294=TT (compose **inline** dans Portainer). Le
|
|
`docker-compose.yml` top-level de `hermes-platform/` est OBSOLETE.
|
|
- 1 seul abonnement OpenCode Go, plusieurs cles tirant du meme pool (~60$/mois).
|
|
- `/Volumes/docker` (Mac) = mount SMB du NAS `/volume1/docker`.
|
|
|
|
---
|
|
|
|
## Ce qui NE fonctionne PAS
|
|
|
|
| Tentative | Erreur obtenue | Raison de l'echec |
|
|
|-----------|----------------|-------------------|
|
|
| `docker compose up` depuis `hermes-platform/` (top-level) | `Conflict. The container name is already in use` | Les containers appartiennent aux stacks per-instance, pas au compose top-level |
|
|
| `hermes model` / `hermes fallback add` en SSH | `requires an interactive terminal` | Pickers interactifs → editer le YAML directement |
|
|
| Provider custom dans `providers:` | inutile | `opencode-go` est deja BUILT-IN (models.dev) |
|
|
| family-help medical `max_tokens: 512` | `finish_reason=length`, `content` VIDE | Modele de raisonnement : reasoning_content mange le budget avant le content |
|
|
|
|
---
|
|
|
|
## Solution validee
|
|
|
|
Provider built-in `opencode-go` : base_url `https://opencode.ai/zen/go/v1`,
|
|
cle via env var **`OPENCODE_API_KEY`**, model `deepseek-v4-flash` (sans prefixe).
|
|
OpenRouter (fallback) garde `deepseek/deepseek-v4-flash`.
|
|
|
|
```yaml
|
|
# data/config.yaml (gateway) — pour chaque instance
|
|
model:
|
|
default: deepseek-v4-flash
|
|
provider: opencode-go
|
|
fallback_providers:
|
|
- provider: openrouter
|
|
model: deepseek/deepseek-v4-flash
|
|
key_env: OPENROUTER_API_KEY
|
|
```
|
|
|
|
```bash
|
|
# perso / nyora (stacks path-based) : ajouter OPENCODE_API_KEY au .env + au compose
|
|
# - OPENCODE_API_KEY=${OPENCODE_API_KEY}
|
|
cd /volume1/docker/hermes-platform/hermes-perso
|
|
docker compose up -d --force-recreate hermes-agent-perso
|
|
|
|
# TT (stack 294 inline) : via API Portainer
|
|
# GET /api/stacks/294/file → inserer "- OPENCODE_API_KEY=<cle>" → PUT /api/stacks/294?endpointId=2
|
|
```
|
|
|
|
family-help : `medical_service.py` → helper `_llm_complete()` (OpenCode primaire,
|
|
OpenRouter fallback), **`max_tokens: 2048`**, cle `BIFROST_OPENCODE_KEY`.
|
|
`docker compose build --no-cache && docker compose up -d --force-recreate`.
|
|
|
|
---
|
|
|
|
## Verification
|
|
|
|
```bash
|
|
docker exec hermes-agent-<inst> hermes fallback ls
|
|
# Attendu : Primary deepseek-v4-flash (via opencode-go)
|
|
|
|
# Test end-to-end
|
|
docker exec hermes-agent-<inst> curl -s -H "Authorization: Bearer <API_SERVER_KEY>" \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"dis OK"}],"max_tokens":40}' \
|
|
http://localhost:8642/v1/chat/completions
|
|
# Attendu : HTTP 200, content non vide
|
|
|
|
# Test fallback : pointer OPENCODE_GO_BASE_URL vers un hote injoignable → reponse via OpenRouter (200)
|
|
```
|
|
|
|
---
|
|
|
|
## Pieges specifiques DSM / NAS
|
|
|
|
- `docker` n'est PAS dans le PATH SSH → utiliser `/usr/local/bin/docker`.
|
|
- Ne jamais editer le docker-compose top-level (obsolete) ; identifier la vraie source
|
|
via `docker inspect <c> --format '{{index .Config.Labels "com.docker.compose.project.config_files"}}'`.
|
|
- TT = stack inline Portainer → API Portainer, pas le FS (sudo requis sinon).
|
|
- DeepSeek V4 Flash (OpenCode) = reasoning model → `max_tokens` >= 2048 pour les
|
|
apps maison qui parsent du JSON (Hermes gere nativement).
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- https://opencode.ai/docs/zen
|
|
- https://hermes-agent.nousresearch.com/docs/user-guide/features/fallback-providers
|
|
- NyoraNotes : note 416da848 (capitalisation), note 26c38f8c (missions)
|