# Plan - PoC `cc-agent-proxy` + programme Lua `opencc` > A executer ailleurs, pas sur cette machine. Deploiement HTTPS, reverse proxy, firewall et exposition publique geres separement par Guillaume. ## 1. Objectif Piloter un agent OpenCode depuis une turtle ComputerCraft sur Minecraft / ATM10. ```text Turtle --HTTP + token--> cc-agent-proxy --HTTP Basic Auth--> opencode serve opencc.lua Node/TypeScript proxy OpenCode headless ``` ## 2. Faisabilite `opencode serve` lance un serveur HTTP headless exposant une spec OpenAPI 3.1 sur `/doc`. Routes utiles pour le PoC : | Methode | Route | Usage | |---|---|---| | `GET` | `/global/health` | healthcheck amont | | `POST` | `/session` | cree une session | | `POST` | `/session/:id/message` | envoie un message et attend la reponse | | `POST` | `/session/:id/prompt_async` | envoie en asynchrone | | `GET` | `/session/:id/message` | liste les messages | | `GET` | `/event` | flux SSE | Conclusion : le proxy n'est pas strictement necessaire, mais il rend le client Lua beaucoup plus simple. ## 3. Pourquoi garder le proxy - Expose une API turtle simple : `POST /ask { prompt, sessionId? }` vers `{ sessionId, reply }`. - Gere le Basic Auth OpenCode cote Node. - Garde cote turtle un token Bearer simple. - Aplatit les reponses OpenCode pour limiter RAM et complexite Lua. - Permet plus tard async, polling, logs, quotas ou allowlist sans changer le programme Lua. ## 4. Partie A - `cc-agent-proxy` Creer un dossier `cc-agent-proxy/` dans le repo. Stack : - Node 20+. - TypeScript strict. - Fastify. - Vitest. - Zod. - Config via env validee, avec `.env.example`. Arborescence : ```text cc-agent-proxy/ package.json tsconfig.json .env.example src/ config.ts opencode.ts auth.ts server.ts index.ts test/ config.test.ts opencode.test.ts auth.test.ts server.test.ts ``` Config : | Variable | Defaut | Role | |---|---|---| | `PROXY_HOST` | `0.0.0.0` | interface d'ecoute | | `PROXY_PORT` | `7070` | port du proxy | | `PROXY_TOKEN` | requis | secret turtle <-> proxy | | `OPENCODE_BASE_URL` | `http://127.0.0.1:4096` | URL OpenCode | | `OPENCODE_USERNAME` | `opencode` | user Basic Auth | | `OPENCODE_PASSWORD` | requis | password Basic Auth | | `OPENCODE_MODEL` | optionnel | modele a passer a OpenCode | Routes proxy : | Methode | Route | Auth | Usage | |---|---|---|---| | `GET` | `/health` | non | etat proxy + `opencode.health()` | | `POST` | `/ask` | oui | cree/reutilise session, envoie prompt, retourne reponse | | `POST` | `/session` | oui, optionnel | cree une session explicite | Client OpenCode : - `health()` appelle `GET /global/health`. - `createSession(title?)` appelle `POST /session`. - `sendMessage(sessionId, text)` appelle `POST /session/:id/message`. - `Authorization: Basic base64(username:password)`. - Body message : `{ parts: [{ type: "text", text }], model?: ... }`. - Extraire les `parts` texte de la reponse. - A valider au premier run reel : format exact des `parts`. Auth proxy : - Accepter `Authorization: Bearer `. - Accepter aussi `X-Proxy-Token` pour simplicite CC si besoin. - Comparaison constant-time avec `crypto.timingSafeEqual`. - Reponse `401` si absent ou invalide. - Ne jamais logger le token. Tests Node en scope du PoC : - `config.test.ts` : valeurs par defaut, erreurs si secrets manquants. - `opencode.test.ts` : `fetch` mocke pour health/session/message/parsing. - `auth.test.ts` : token valide, invalide, absent. - `server.test.ts` : `app.inject()` pour `/health`, `/ask`, `401` sans token. ## 5. Partie B - programme Lua `opencc` Creer : ```text apis/libopencc.lua programs/opencc.lua tests/opencc.lua ``` Programme : - `opencc --help`. - `opencc --version`. - `opencc "prompt"` ou prompt interactif via `read()`. - Appelle `http://:/ask`. - Header `Content-Type: application/json`. - Header `Authorization: Bearer `. - Body `textutils.serialiseJSON({ prompt = prompt, sessionId = sessionId })`. - Parse la reponse JSON. - Affiche `reply`. - Memorise `sessionId` pour reutilisation si on choisit une session persistante. Config Lua : - Utiliser `settings` ComputerCraft en priorite : - `opencc.proxy_url`. - `opencc.proxy_token`. - `opencc.session_id`. - `opencc.timeout`, si applicable. - Autoriser un fallback hardcode uniquement pour PoC local, mais ne pas committer de secret reel. - Stockage session possible dans un petit fichier local, par exemple `/.opencc-session`, si plus simple que `settings`. Tests Lua : - En scope si simple : tester `libopencc` sans vraie requete HTTP via injection d'un faux client `http`. - Tester construction URL, headers, body JSON, parsing succes, parsing erreur. - Hors scope PoC si trop couteux : test end-to-end avec vrai proxy Node et vrai OpenCode. - Le test reel HTTP se fera manuellement via CraftOS-PC puis en jeu. Note repo : - Le reseau existant `apis/net.lua` est oriente modem/rednet/router, pas HTTP sortant. - Pour ce PoC, garder `http.post` direct cote Lua est le bon choix. - Le packaging existant du repo est `ccpm` / `packages/*/ccpm.json`, pas `cube`. - Ne pas integrer au packaging tant que le PoC n'est pas valide ; ajouter ensuite un package dedie type `tos-agent` si utile. ## 6. Pre-requis CC:Tweaked / ATM10 - API `http` activee. - Hote/IP du proxy autorise dans les `http.rules` cote serveur ATM10. - Pas de CORS, car ce n'est pas un navigateur. - Prompts courts pour le PoC, car `POST /session/:id/message` peut etre long. Evolution hors PoC : - Proxy utilise `prompt_async`. - Turtle appelle `POST /ask` puis poll `GET /ask/:id/status`. - Le proxy ecoute eventuellement `/event` SSE cote OpenCode. ## 7. Ordre d'execution 1. Bootstrap `cc-agent-proxy`. 2. Implementer `config.ts` + tests. 3. Implementer `opencode.ts` + tests avec `fetch` mocke. 4. Implementer `auth.ts`, `server.ts`, `/health`, `/ask` + tests `app.inject()`. 5. Valider manuellement avec `opencode serve` + `curl`. 6. Implementer `apis/libopencc.lua` + `programs/opencc.lua`. 7. Ajouter `tests/opencc.lua` si l'injection HTTP reste simple. 8. Tester via CraftOS-PC. 9. Tester en jeu sur ATM10 apres configuration `http.rules`. 10. Documenter les commandes de lancement et les pre-requis. ## 8. Validation manuelle ```bash OPENCODE_SERVER_PASSWORD=xxx opencode serve \ --hostname 127.0.0.1 \ --port 4096 ``` ```bash curl -s http://localhost:7070/health ``` ```bash curl -s -X POST http://localhost:7070/ask \ -H "Authorization: Bearer $PROXY_TOKEN" \ -H "Content-Type: application/json" \ -d '{"prompt":"dis bonjour"}' ``` ## 9. Points de vigilance - Format reel des `parts` OpenCode a valider au premier run. - OpenCode doit avoir un provider authentifie. - Timeouts longs cote agent vs limites HTTP CC:Tweaked. - `http.rules` cote serveur ATM10. - `PROXY_TOKEN` jamais committe. - `OPENCODE_PASSWORD` jamais committe. - Le proxy doit rester minimal tant que le PoC n'a pas prouve la boucle complete.