cc-libs/.plans/opencc-agent-proxy-GRILLED_PLAN.md

32 KiB

GRILLED_PLAN - cc-agent-proxy + programme Lua opencc

Compagnon de .plans/opencc-agent-proxy-plan.md. Chaque question a une recommandation par defaut et un bloc TODO: answer que tu remplis. Un prochain /grill-me lira ce fichier et le condensera en plan v2 pret a executer.

Convention :

  • Remplace TODO: answer par ta reponse (1-3 lignes suffisent).
  • Si tu choisis une option listee, ecris Option N + raison breve.
  • Si tu inventes une 5e option, ecris-la in extenso.
  • Si une question devient sans objet apres une reponse majeure, ecris N/A - voir Q<n>.
  • Laisse TODO: answer (optionnel) tel quel si pas d'avis.

Regles de base du PoC

  • Une turtle, un OpenCode, un proxy, une reponse utilisable. Rien de plus.
  • Contraintes explicites > design generique.
  • Pas de packaging tant que la boucle n'a pas tourne in-game.
  • Aucun secret commit.
  • La forme des reponses OpenCode est suspecte tant qu'on ne l'a pas vue en vrai.

A. Les 8 questions determinantes

A repondre en premier. Le reste devient souvent trivial une fois ces choix trances.

A1. Critere d'acceptation du PoC

Quand dit-on "c'est fini" ?

  • Option 1 - curl roundtrip : curl /ask retourne une vraie reponse OpenCode. Pas d'in-game.
  • Option 2 - CraftOS-PC roundtrip : opencc "salut" repond dans l'emulateur, en pointant sur le proxy local.
  • Option 3 - in-game ATM10 : opencc marche sur une vraie turtle apres config http.rules.
  • Option 4 - conversation in-game : Option 3 + verifier que la session persistante garde le contexte sur plusieurs prompts.

Recommandation : Option 4. C'est ce qui prouve que le pipeline tient bout en bout. 1-3 sont des jalons intermediaires. Premier prompt anodin (dis bonjour) avant prompts libres.

Pourquoi ca compte : decide si async, multi-turtle, logs riches, quotas, packaging et UX terminale sont hors scope.

Option 4. Le PoC est fini seulement quand opencc marche in-game sur une vraie turtle et que deux prompts successifs prouvent la session persistante. Les curls OpenCode faits sur 4242 restent des jalons de contrat API.

A2. Autorite et workspace d'OpenCode

Le proxy parle a un opencode serve qui a, potentiellement, acces complet a des fichiers et a un shell. Une turtle qui prompt = un acteur exterieur qui peut indirectement declencher des actions cote hote.

  • Option 1 - workspace dedie jetable : opencode serve lance dans un dir temporaire (/tmp/opencc-poc) sans secrets, sans repo perso.
  • Option 2 - workspace projet dedie : un dossier ~/opencc-workspace/ vide ou minimal, persistant entre runs.
  • Option 3 - repo perso : non, trop risque.
  • Option 4 - sandbox container : OpenCode dans Docker avec mount limite. Plus de cout pour le PoC.

Recommandation : Option 1. Workspace jetable, recree a chaque session de test. Documenter le dir exact dans .env.

Pourquoi ca compte : c'est la vraie frontiere de confiance, plus que le token Lua.

Option 1. opencode serve doit tourner dans un workspace jetable dedie au PoC, pas dans ce repo : les endpoints serveur peuvent piloter le TUI et declencher le LLM, donc la frontiere de confiance est le workspace OpenCode.

A3. Cycle de vie de la session

  • Option 1 - session unique partagee : le proxy cree une session au boot, toutes les turtles tapent dedans. Conflits de memoire conversationnelle.
  • Option 2 - session par turtle, persistee cote turtle : la turtle stocke sessionId dans settings ; le proxy se contente de relayer.
  • Option 3 - session ephemere par prompt : chaque /ask cree+detruit. Pas de continuite. Plus simple, perd le contexte.
  • Option 4 - session par turtle, mappee cote proxy : table turtleId -> sessionId cote proxy. Necessite d'identifier la turtle.

Recommandation : Option 2. Le proxy reste sans etat ; la turtle envoie sessionId optionnel, le proxy en cree une si absent et le renvoie dans la reponse.

Option 2. La turtle garde opencc.session_id dans settings; le proxy cree une session si absent et renvoie toujours le sessionId. Cela evite un etat proxy et colle au contrat reel POST /session puis /session/:id/message.

A4. Sync vs async pour /ask

POST /session/:id/message peut bloquer longtemps. CC:Tweaked a des timeouts HTTP (~30s typiques, depend du serveur).

  • Option 1 - sync stricte : le proxy attend la fin et renvoie. Risque de timeout cote turtle.
  • Option 2 - async + polling : POST /ask -> jobId, GET /ask/:jobId pour poll. Plus robuste, plus complexe.
  • Option 3 - keepalive / chunked : inutile en HTTP CC standard.
  • Option 4 - sync now, async later : on commence en sync (prompts courts pour PoC), on documente la limite, on bascule async si on l'atteint. API /ask reste compatible.

Recommandation : Option 4.

Option 4. On demarre en sync avec prompts courts, car POST /session/:id/message attend bien la reponse LLM quand noReply est absent. Si les timeouts CC apparaissent, on ajoute async/polling sans changer le happy path /ask.

A5. Topologie de deploiement

Le plan source dit "deploiement HTTPS, RP, firewall, exposition publique geres separement par Guillaume".

  • Option 1 - tout sur ta machine perso : opencode serve + cc-agent-proxy en localhost, expose via tunnel (Cloudflare, ngrok).
  • Option 2 - VPS dedie : meme hote distant, HTTPS via Caddy/nginx.
  • Option 3 - homelab : Option 2 mais chez toi, derriere ton RP existant.
  • Option 4 - deux hotes separes : OpenCode sur GPU dedie, proxy ailleurs.

Conditionne : auth (A6), OPENCODE_BASE_URL, qui termine TLS.

Recommandation : Option 3 si tu as un homelab, sinon Option 1. Proxy + opencode sur le meme hote, loopback entre les deux, proxy expose en HTTPS.

Option 3 pour moi : homelab/RP si expose a une turtle ATM10 reelle. Proxy et OpenCode restent sur le meme hote, OpenCode en loopback, seul le proxy sort en HTTPS. Pour dev local, Option 1 avec tunnel reste acceptable.

A6. Modele d'authentification turtle <-> proxy

  • Option 1 - token unique partage : un seul PROXY_TOKEN, meme valeur sur toutes les turtles via settings. Pas de revocation granulaire.
  • Option 2 - token par turtle : table de tokens cote proxy. Permet revocation par turtle.
  • Option 3 - HMAC signe : turtle envoie os.getComputerID() + HMAC. Plus complexe, peu de gain sans rotation.
  • Option 4 - allowlist IP : impossible, la turtle sort via le proxy HTTP du serveur Minecraft.

Recommandation : Option 1. Helper isTokenValid(token) pour permettre une table plus tard sans refactor.

Option 1 pour le PoC. Token unique partage, header seulement, helper isTokenValid pour permettre token par turtle plus tard sans changer le programme Lua.

A7. Forme de la reponse renvoyee a la turtle

OpenCode retourne parts, tool calls, code blocks. La turtle a peu de RAM.

  • Option 1 - texte plat : { reply }. Tout ce qui n'est pas texte est jete.
  • Option 2 - texte + meta : { reply, model, tokens, sessionId }.
  • Option 3 - parts brutes : la turtle parse. Trop couteux.
  • Option 4 - texte plat + troncature : { reply, sessionId, truncated } avec MAX_REPLY_CHARS (ex. 4 KiB). Logs proxy gardent le complet.

Recommandation : Option 4.

Option 4. Le proxy renvoie { reply, sessionId, truncated }; il concatene les parts text uniquement et tronque pour la turtle. Les parts tools/reasoning observees dans OpenCode doivent rester cote proxy/logs, pas cote turtle.

A8. Scope minimal v1 (in et out)

  • Option 1 - hello world : turtle envoie "ping", recoit "pong". Une seule route, sync, pas de session persistante.
  • Option 2 - conversation 1 turtle / 1 session : echange sur plusieurs prompts, sessionId persistante.
  • Option 3 - + outils OpenCode : agent peut lire/ecrire un fichier dans le workspace.
  • Option 4 - + multi-turtle : deux turtles en parallele sans collision.

Recommandation : Option 2.

Hors-scope explicite du PoC : async, multi-turtles, package ccpm, deploiement auto, Docker, quotas, UI terminale riche, streaming OpenCode (/event).

Option 2. Scope v1 = une turtle, une session persistante, un prompt par invocation. Les endpoints TUI sont utiles pour piloter un client humain, mais le proxy turtle doit utiliser /session/:id/message directement.


B. Scope, contraintes de temps, cleanup

B1. Limite de temps et plan de bascule

Si la forme de l'API OpenCode bloque, qu'est-ce qu'on fait ?

Recommandation : une seule passe d'implementation. Si l'API OpenCode bloque, on arrete d'abstraire et on capture le contrat reel via curl avant de coder.

Confirme. Une seule passe : avant de coder le client OpenCode, capturer le contrat reel par curl. On a deja valide GET /global/health, POST /session, POST /session/:id/message, GET /session/:id/message et /tui/*.

B2. Rollback / cleanup post-PoC

Comment on nettoie une fois la demo faite ?

Recommandation : stop proxy, stop opencode serve, supprimer sessions de test, rotation du PROXY_TOKEN et du OPENCODE_PASSWORD utilises.

Confirme. Stopper proxy + opencode serve, supprimer les sessions PoC si besoin, et rotation du PROXY_TOKEN/OPENCODE_SERVER_PASSWORD. Ne jamais garder les sorties /provider dans les logs partages.


C. OpenCode upstream : contrat et comportement

C1. Version OpenCode et Basic Auth verifies au premier run

OpenCode evolue. Le plan suppose Basic Auth active. A valider.

Recommandation : enregistrer opencode --version utilise lors de la validation ; pinger /global/health avec Basic Auth via curl avant de coder le client.

Valide sur OpenCode 1.16.2. /global/health retourne {"healthy":true,"version":"1.16.2"}. Basic Auth reste a retester avec OPENCODE_SERVER_PASSWORD; sans password, le serveur avertit qu'il est unsecured.

C2. Spec exacte de POST /session/:id/message

Plan : { parts: [{ type: "text", text }], model? }. Marque comme inconnu.

Recommandation : curl http://localhost:4096/doc une fois OpenCode lance, capturer un sample reel de reponse, le commiter sanitize dans cc-agent-proxy/test/fixtures/.

Contrat valide : POST /session/:id/message body minimal {"parts":[{"type":"text","text":"..."}]}. noReply:true cree seulement le message user; sans noReply, OpenCode declenche le LLM et attend la reponse.

C3. Provider et modele LLM

OPENCODE_MODEL optionnel. Quel provider Guillaume utilise (anthropic, openai, ollama local) ?

Recommandation : laisser defaut OpenCode, ne passer model que si OPENCODE_MODEL est defini dans .env.

Confirme. Laisser le modele par defaut OpenCode pour le PoC. Ne passer model:{providerID,modelID} que si OPENCODE_MODEL est defini, car l'appel sans model marche deja avec la session courante.

C4. Timeout amont vers OpenCode

Recommandation : REQUEST_TIMEOUT_MS configurable, defaut 60s. Au dela -> 504 cote proxy.

Confirme. REQUEST_TIMEOUT_MS=60000 par defaut cote proxy. Le timeout doit englober l'appel bloquant /session/:id/message; 504 public si depassement.

C5. Exposition des erreurs OpenCode au turtle

Recommandation : pas de stack trace ni secret. Renvoyer { error: "...", code: "..." } avec message public court ; detail dans les logs proxy uniquement.

Confirme. Reponse publique courte, code stable, aucun detail provider/config. Attention particuliere : des endpoints comme /provider peuvent exposer du materiel d'auth, donc logs sanitize obligatoires.

C6. SessionId auto-creation et recovery si stale

Deux comportements distincts :

  • sessionId absent dans la requete -> proxy en cree un (recommande oui).
  • sessionId fourni mais 404 amont -> ?
    • Option A : recreer silencieusement.
    • Option B : renvoyer { error: "session_expired" }, laisser la turtle decider (opencc --new).

Recommandation : Option B. Auto-recreation cacherait une perte de contexte deroutante.

Option B. Si sessionId absent, creer via POST /session. Si sessionId fourni renvoie 404/stale, repondre session_expired; la turtle pourra faire opencc --new plutot que perdre le contexte silencieusement.

C7. Comportement quand OpenCode est down

  • 502/503 brutal ?
  • Retry interne avec backoff ?
  • /health reflete-t-il l'etat upstream ?

Recommandation : pas de retry auto, 502 + JSON { error: "upstream_down" }. /health inclut un champ opencode: "up"/"down".

Confirme. Pas de retry auto. /health proxy ping /global/health; si down, { proxy: "ok", opencode: "down" }. /ask renvoie 502 { error: "upstream_down" }.

C8. Gestion des parts non-textuelles (tools, code blocks)

Recommandation : concatener les parts texte, ignorer les non-textuelles dans la reply, mais logger un compteur cote proxy (parts_text, parts_tool, parts_other).

Confirme. Les reponses reelles contiennent text, reasoning, tool, step-start, step-finish. La reply turtle concatene seulement les parts text; les compteurs de parts restent dans les logs proxy.


D. Proxy API shape

D1. Routes minimales du proxy

Plan : /health, /ask, /session.

  • /session obligatoire ou implicite via /ask ?
  • /health inclut upstream ?

Recommandation :

  • GET /health -> { proxy: "ok", opencode: "up"/"down" }.
  • POST /ask -> obligatoire, body { prompt, sessionId? }, response { sessionId, reply, truncated }.
  • POST /session -> garder, retourne { sessionId }. Pratique pour initialiser ou nommer une session ; ne casse pas le PoC si on ne l'expose pas a la turtle.

Confirme. /session peut rester une route debug/initialisation, mais /ask doit creer implicitement si sessionId absent. /health inclut l'etat OpenCode via /global/health.

D2. Codes HTTP stables pour la turtle

Recommandation :

  • 200 succes
  • 400 requete invalide (prompt vide, body malforme)
  • 401 token absent/invalide
  • 413 prompt trop long
  • 502 OpenCode down
  • 504 OpenCode timeout
  • 500 erreur proxy inattendue

Confirme ces codes. Ajouter 409 uniquement si un jour on gere des jobs async concurrents par session; hors PoC, la liste suffit.

D3. Limites taille de requete

  • Max prompt length ?
  • Max body size HTTP ?

Recommandation : prompt max 8 KiB (MAX_PROMPT_CHARS env), body max 32 KiB cote Fastify. Pas de rate-limit dans le PoC.

Confirme. MAX_PROMPT_CHARS=8192, body JSON max 32 KiB, pas de rate-limit dans l'app. Ces limites protegent surtout CC/Turtle RAM et les logs.

D4. Request IDs / correlation

Recommandation : requestId auto-genere cote proxy, present dans tous les logs, non expose dans la reponse JSON (juste dans header x-request-id pour debug optionnel).

Confirme. requestId genere cote proxy, logge partout, expose seulement via header x-request-id pour debug. Ne pas le mettre dans le JSON turtle par defaut.


E. Stack Node / TypeScript

E1. Runtime et gestionnaire de paquets

Recommandation : Node 20+, pnpm. Sinon npm si tu prefers vanilla.

Confirme : Node 20+ et pnpm. Si le repo n'a pas deja pnpm, garder npm possible, mais le proxy doit rester isole dans son sous-dossier.

E2. Strictness TypeScript

Recommandation : "strict": true + noUncheckedIndexedAccess. exactOptionalPropertyTypes evite (bruit pour peu de valeur en PoC).

Confirme : strict + noUncheckedIndexedAccess, sans exactOptionalPropertyTypes pour limiter le bruit PoC.

E3. Framework HTTP et validation

Plan : Fastify + Zod.

Recommandation : Fastify + Zod + fastify-type-provider-zod pour validation automatique des routes. Confirme ou propose autre.

Confirme : Fastify + Zod. Le contrat proxy est petit et beneficie de schemas explicites pour prompt, sessionId, reply, truncated.

E4. Logging

Recommandation : Pino (default Fastify). LOG_LEVEL=info par defaut, debug en dev. Flag LOG_BODIES=true pour inclure prompt/reply ; off par defaut. Jamais logger token ni OPENCODE_PASSWORD. Logs : status, duree, sessionId (12 premiers chars), requestId, longueurs prompt/reply.

Confirme. Pino/Fastify, LOG_BODIES=false par defaut. Ne pas logger les sorties brutes OpenCode sensibles (/provider, config, headers auth) ; loguer seulement longueurs, status, duree, requestId, prefix sessionId.

E5. Process / lancement / deploiement

  • tsx en dev, node dist/index.js apres tsc en prod ?
  • Dockerfile ? systemd ? pm2 ?
  • Bind 0.0.0.0 ? Shutdown gracieux ?

Recommandation : tsx en dev, node dist en prod, pas de Docker, pas de systemd dans le repo (tu deploies a la main). 0.0.0.0 car expose derriere RP. Shutdown : app.close() sur SIGTERM, rien de plus.

Confirme. Dev avec tsx, prod node dist/index.js, pas de Docker/systemd dans le repo. Bind proxy 0.0.0.0 derriere RP, OpenCode en 127.0.0.1.

E6. Tests Node

Plan : vitest, fetch mocke, app.inject(). Pas d'objectif de couverture %.

Recommandation : couvrir /ask happy path, 401, OpenCode 5xx mock, prompt vide, prompt trop long, sessionId 404 amont. Fixture OpenCode reelle (cf C2) utilisee dans opencode.test.ts.

Confirme. Tests vitest avec fetch mocke + app.inject(). Ajouter fixture reelle sanitized de /session/:id/message incluant text/reasoning/tool/step parts.

E7. Variables d'env (en plus du tableau du plan)

A ajouter :

  • LOG_LEVEL (info/debug)
  • LOG_BODIES (true/false)
  • MAX_REPLY_CHARS (defaut 4096)
  • MAX_PROMPT_CHARS (defaut 8192)
  • REQUEST_TIMEOUT_MS (defaut 60000)
  • OPENCODE_WORKSPACE (info uniquement, documente le dir A2)

Recommandation : oui, ajouter les six. .env.example les liste, jamais de secret reel.

Confirme les six variables. Ajouter aussi un commentaire .env.example pour OPENCODE_BASE_URL=http://127.0.0.1:4242 et credentials Basic Auth si actives.

E8. CORS, body parsing, etat en memoire

  • CORS : non, ce n'est pas un navigateur.
  • Body : JSON only.
  • Etat : stateless (cf A3 Option 2).

Recommandation : garder tel quel. Confirme ou contredit.

Confirme. Pas de CORS, JSON only, proxy stateless. Les endpoints /tui/* ne sont pas utilises par le proxy turtle ; ils restent une piste d'integration TUI.


F. Auth, secrets, exposition publique

F1. Generation du PROXY_TOKEN

Recommandation : genere a la main (openssl rand -hex 32), ecrit dans .env. Si absent au boot, le proxy refuse de demarrer (fail-fast).

Confirme. Token genere manuellement, fail-fast si absent. Ne jamais le passer en query string ni l'afficher dans les logs.

F2. HTTPS vs HTTP cote turtle

ATM10 accepte les deux si dans http.rules. Token nu en HTTP = leak.

Recommandation : HTTPS uniquement, meme en homelab, via le RP existant.

Confirme : HTTPS uniquement entre turtle et proxy des que ca sort de localhost. OpenCode peut rester en HTTP loopback derriere le proxy.

F3. Saisie du token sur la turtle

Le secret ne doit jamais etre dans un fichier Lua commit.

Recommandation : settings set opencc.proxy_token <token> + settings.save() manuellement dans l'environnement de chaque turtle. Documenter dans le quickstart.

Confirme. Configuration manuelle via settings; rien de secret dans les fichiers Lua commit. Documenter commandes fish/bash separement cote host si besoin.

F4. Token en query string ?

Recommandation : non, header uniquement. Les query strings se retrouvent dans les logs RP/proxy.

Confirme : non. Token en header seulement, jamais query string.

F5. Headers acceptes : Bearer et X-Proxy-Token

Plan : les deux pour simplicite CC.

Recommandation : accepter Authorization: Bearer <token> ET X-Proxy-Token, documenter Bearer comme prefere. X-Proxy-Token reste seulement si CC pose souci avec Authorization (a tester).

Confirme. Bearer prefere ; X-Proxy-Token accepte pour compat CC si Authorization pose souci, a valider en CraftOS-PC/ATM10.

F6. Comparaison constant-time

Recommandation : crypto.timingSafeEqual apres normalisation (longueur egalisee) pour eviter le throw sur taille differente.

Confirme. timingSafeEqual avec buffers normalises pour eviter throw et timing trivial.

F7. Rotation du token

Recommandation : hors scope PoC. Redemarrer proxy + reconfigurer turtles = acceptable.

Confirme. Rotation hors scope PoC : redemarrage proxy + reconfiguration turtle.

F8. Rate-limit et allowlist IP

Recommandation : ni l'un ni l'autre dans l'app. Si exposition publique le demande, c'est au RP / firewall de gerer (donc en dehors du repo).

Confirme. Rate-limit/allowlist hors app, gere par RP/firewall si necessaire.

F9. Basic Auth OpenCode

Recommandation : credentials uniquement via env (OPENCODE_USERNAME, OPENCODE_PASSWORD), valides au boot, sinon fail-fast.

Renommer cote proxy en OPENCODE_SERVER_USERNAME/OPENCODE_SERVER_PASSWORD ou documenter clairement le mapping, car OpenCode utilise ces noms pour proteger serve. Valider au boot par /global/health avec Basic Auth.


G. Programme Lua opencc

G1. Emplacement et packaging

Plan : apis/libopencc.lua, programs/opencc.lua, tests/opencc.lua.

Recommandation : pas de packages/tos-agent/ccpm.json avant validation in-game (cf I3). Fichiers nus dans apis/ et programs/ pendant le PoC.

Confirme. Pas de packaging tant que l'in-game n'a pas tourne. Fichiers nus apis/libopencc.lua, programs/opencc.lua, tests/opencc.lua pour le PoC.

G2. Source de config (settings vs fichier vs CLI)

Clefs settings :

  • opencc.proxy_url (URL complete HTTPS recommandee)
  • opencc.proxy_token
  • opencc.session_id (auto-remplie)
  • opencc.timeout (optionnel)

Recommandation : settings uniquement + flags CLI (--url, --token) qui overrident pour le debug. Si proxy_url ou proxy_token manque, message clair + exit non-zero. Pas de host/port separes.

Confirme : settings uniquement + overrides CLI debug. opencc.proxy_url, opencc.proxy_token, opencc.session_id, opencc.timeout suffisent.

G3. Format CLI

  • opencc --help, --version
  • opencc "prompt" (argv) ou interactif via read() si pas d'arg
  • REPL multi-tour ?

Recommandation : pas de REPL. Un prompt par invocation. Le contexte vient de la session_id persistante.

Confirme : pas de REPL. Un prompt par invocation ; le contexte vient du session_id persistant.

G4. Persistance et reset de la session

  • Persistance : settings.set('opencc.session_id', id); settings.save() ou fichier dedie ?
  • Reset : opencc --new ? --reset-session ?

Recommandation : settings (coherence G2) ; flag opencc --new qui efface opencc.session_id et cree une nouvelle session via le prochain /ask.

Confirme. opencc --new efface opencc.session_id; le prochain /ask cree une session. Pas besoin d'appeler /session explicitement cote turtle.

G5. Affichage de la reponse

  • Print brut ?
  • Word-wrap manuel ?
  • Pagination ?
  • Print metadata (sessionId, model) ?

Recommandation : print + word-wrap simple sur largeur terminal. Pas de pagination. Pas de metadata sauf en mode --verbose (a ajouter plus tard).

Confirme. Print avec word-wrap simple, pas de pagination. Metadata uniquement si --verbose est ajoute plus tard.

G6. Erreurs reseau et http.rules

http.post peut renvoyer nil (handshake ko, host bloque par http.rules) ou un response status != 200.

Recommandation :

  • nil -> "proxy injoignable. Verifie opencc.proxy_url et que l'hote est autorise dans http.rules".
  • 401 -> "token invalide".
  • 413 -> "prompt trop long".
  • 502/504 -> "agent indisponible / trop lent".
  • Autre -> message generique + status code.

Confirme ces messages. Ajouter un cas "session expiree" pour session_expired : "session perdue, relance avec opencc --new".

G7. Timeout HTTP CC

http.post n'a pas de parametre timeout standard. CC:Tweaked >= 1.97 a http.request avec timeout ; a verifier sur ATM10.

Recommandation : exposer opencc.timeout. Si CC l'accepte, on l'utilise ; sinon documenter la limite et compter sur A4 Option 4 pour la suite.

Confirme. Tester si ATM10/CC:Tweaked accepte un timeout via http.request; si non, documenter et garder sync court pour le PoC.

G8. Pattern factory et JSON

Repo : apis/libccpm.lua est une factory avec opts.http injectable. Meme chose pour libopencc ? Encodage JSON via textutils.serialiseJSON ?

Recommandation : factory : local createOpencc = require('/apis/libopencc'); local opencc = createOpencc({ http = http, settings = settings, computerCraftTimeout = ... }). JSON via textutils.serialiseJSON / unserialiseJSON.

Confirme. Factory injectable comme libccpm.lua; JSON via textutils.serialiseJSON et textutils.unserialiseJSON.

G9. Trim / multiline / vide

Recommandation : trim final, refus si prompt vide apres trim. Multiline preserve.

Confirme. Trim final, refuser prompt vide apres trim, preserver multiline.

G10. Tests Lua

Plan : injection d'un faux http via libtest.

Recommandation : tests/opencc.lua avec libtest, faux http qui verifie URL, headers (Bearer + Content-Type), body JSON, parsing succes, parsing erreur. Hors-scope : E2E reel avec vrai proxy.

Confirme. Tests libtest avec faux http, headers, body JSON, success, erreurs proxy et sauvegarde session_id.


H. Tests et validation

H1. Fixture OpenCode capturee

Recommandation : oui (cf C2). Sanitize, store dans cc-agent-proxy/test/fixtures/session-message.json. Sert de reference pour opencode.test.ts.

Oui. Capturer une fixture sanitized de la reponse reelle OpenCode. Important : ne pas y inclure sortie /provider ni headers/auth.

H2. E2E manuel vs automatise

Recommandation : manuel pour le PoC. Documenter les commandes (cf H7).

Confirme : E2E manuel pour le PoC. Les commandes de validation doivent etre documentees, avec versions fish si utilisees par Guillaume.

H3. CraftOS-PC headless avant l'in-game

Recommandation : oui si just craftos --headless peut faire http.post. Premier roundtrip en local avant ATM10.

Oui. CraftOS-PC headless avant ATM10 si possible, mais sans ajouter de harness standalone Lua. Utiliser les recettes repo existantes.

H4. Pre-requis ATM10 a documenter

A documenter :

  • http enable cote serveur.
  • Hote du proxy autorise dans http.rules (allow *.tondomaine.tld:443 ou IP).
  • DNS / IP joignable depuis le serveur Minecraft.
  • Token + URL definis dans les settings de la turtle.
  • Provider LLM authentifie cote OpenCode.

Recommandation : checklist dans docs/opencc-quickstart.md ecrite apres la premiere validation reelle.

Confirme. Ecrire la checklist apres premiere validation reelle, pas avant de figer des details faux.

H5. Hooks just check et just test

pre-commit = just check test (Lua + luacheck). Faut-il y mettre les tests Node ?

Recommandation : non. Recipe separee just node-check (eslint+prettier) et just node-test (vitest) dans un sous-Justfile de cc-agent-proxy/. Eviter une dependance implicite Node pour les commits Lua.

Confirme. Ne pas coupler Node aux hooks Lua existants pour le PoC ; recipes Node separees dans le sous-dossier proxy.

H6. CI

Repo : pas de CI publique declaree, juste hooks locaux.

Recommandation : pas de CI pour le PoC. Plus tard, eventuellement un workflow GH Actions node-test + lua-check.

Confirme. Pas de CI PoC.

H7. Transcript de validation manuelle

Recommandation : apres premier roundtrip reussi, enregistrer les commandes exactes et outputs sanitize dans docs/opencc-quickstart.md, incluant un deuxieme /ask avec le meme sessionId pour prouver la persistance.

Confirme. Transcript manuel sanitize dans docs/opencc-quickstart.md apres roundtrip : /health, premier /ask, deuxieme /ask meme sessionId.


I. Architecture / coherence repo

I1. Reuse de apis/net.lua

Recommandation : non. net.lua est modem/rednet. http.post direct cote Lua est le bon choix.

Confirme. apis/net.lua est hors sujet pour HTTP externe.

I2. Reuse de apis/eventloop.lua

Recommandation : non. Le PoC est request/response synchrone. Re-evaluer si A4 passe en async (G1 post-PoC).

Confirme. Pas d'eventloop Lua pour le PoC sync.

I3. Packaging ccpm

Recommandation : post-PoC. Apres validation in-game, creer packages/tos-agent/ccpm.json :

  • files : apis/libopencc.lua, programs/opencc.lua
  • dependencies : tos-core
  • autostart : aucun
  • Ajouter dans packages/index.json.

Declencheur : PoC reussi + au moins une raison de reinstaller/partager.

Confirme. Packaging seulement apres PoC in-game reussi et besoin de diffusion.

I4. ADR

Recommandation : ADR-0012 "external agent bridge via HTTPS proxy" ecrit apres validation. Justifie la presence d'un sous-dossier Node dans un repo Lua.

Confirme. ADR apres validation, pour justifier proxy Node + pont agent externe.

I5. Conformite CLAUDE.md

  • Bump _VERSION sur chaque module Lua modifie.
  • --version / --help sur opencc.
  • Lua : 2-space indent, ;, local function.
  • Node : suit Prettier default.

Recommandation : appliquer tel quel.

Confirme. Respecter _VERSION, --help/--version, indent 2 spaces, semicolons Lua, local function.


J. Post-PoC (evolutions, hors scope mais a ne pas peindre dans un coin)

Reponds seulement si avis fort.

J1. Mode async

Trigger : reponses LLM frequemment > timeout CC/proxy.

Recommandation : ajouter POST /ask?async=1 + GET /ask/:jobId/status. Backward-compatible. opencc apprend a poll.

Avis : garder ce design. Le test direct a confirme que sync fonctionne, mais noReply:true donne deja un equivalent "enqueue sans reponse" cote OpenCode si on doit construire un mode async plus tard.

J2. SSE / WebSocket pour streaming

Pas de SSE en CC:Tweaked, mais http.websocket existe.

Recommandation : proxy WS dedie si streaming devient utile. Hors-scope PoC.

Avis : ne pas confondre avec /event OpenCode. Le SSE existe et marche pour observer le serveur, mais CC ne le consomme pas bien. Pour piloter un TUI, les endpoints /tui/append-prompt, /tui/submit-prompt, /tui/select-session sont utiles, mais hors proxy turtle.

J3. Multi-turtle isolation et identite

Trigger : > 1 turtle/utilisateur sur le meme proxy.

Recommandation : avec A3 Option 2 c'est deja gratuit niveau sessions. Pour quotas, ajouter turtleId (= os.getComputerID()) au body et a la table de tokens.

Avis : confirmer. Ajouter turtleId plus tard seulement pour quotas/audit ; la vraie isolation conversationnelle reste le sessionId garde cote turtle.

J4. Outils OpenCode (lecture/ecriture fichiers)

Recommandation : sandbox stricte (mount lecture-seule + un dir scratch). Hors-scope PoC.

Avis fort : sandbox obligatoire avant d'activer des outils capables d'ecrire. Le test /tui/* prouve qu'un client externe peut declencher le LLM ; le workspace OpenCode ne doit donc jamais etre un repo sensible pour le PoC.

J5. Replacement de http.post par apis/net.lua

Recommandation : probablement jamais. net.lua est routeur/rednet, pas sortie HTTP.

Confirme : probablement jamais. HTTP direct est le bon chemin pour sortir vers le proxy ; net.lua reste pour modem/rednet.

J6. Observabilite (metrics, traces)

Recommandation : ignorer en PoC. Pino logs suffisent. Prometheus exporter plus tard si quotas.

Confirme : Pino logs suffisent. Ajouter metrics seulement si plusieurs turtles ou quotas reels.


K. Inconnues a valider au premier run

Pas de reponse texte ; coche au fur et a mesure.

  • Version exacte d'OpenCode utilisee (opencode --version) : 1.16.2.
  • Format reel des parts retournees par POST /session/:id/message : text, reasoning, tool, step-start, step-finish observes.
  • Comportement OpenCode si model est passe vs absent : absent fonctionne avec le modele/session par defaut ; noReply:true cree sans LLM.
  • Basic Auth vraiment necessaire dans la config de Guillaume.
  • Timeout effectif http.post cote CC sur ATM10 (et si CC:Tweaked version supporte un parametre timeout).
  • Reaction OpenCode si on hammer une session morte (404 ? autre ?).
  • Limite de longueur d'un message accepte par OpenCode.
  • Cas ou le provider LLM est down : OpenCode renvoie quoi ? Ne pas tester via /provider en logs partages, cet endpoint peut exposer l'auth.
  • CraftOS-PC headless peut-il faire http.post HTTPS vers le proxy en local ?

L. Quoi repondre en priorite

Si tu veux aller vite, reponds dans cet ordre. Le reste decoule.

  1. A1 - critere d'acceptation
  2. A2 - workspace OpenCode (frontiere de confiance)
  3. A3 - cycle session
  4. A4 - sync vs async
  5. A5 - topologie deploiement
  6. A6 - auth turtle <-> proxy
  7. A7 - forme de la reponse
  8. A8 - scope v1

Une fois ces 8 trances, on peut souvent ignorer les sections B-J pour le "go/no-go" et juste valider les recommandations par defaut. Les detailler n'apporte de la valeur que si tu veux devier d'une recommandation precise.