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 blocTODO: answerque tu remplis. Un prochain/grill-melira ce fichier et le condensera en plan v2 pret a executer.Convention :
- Remplace
TODO: answerpar 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 /askretourne 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 :
openccmarche sur une vraie turtle apres confighttp.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 servelance 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
sessionIddanssettings; le proxy se contente de relayer. - Option 3 - session ephemere par prompt : chaque
/askcree+detruit. Pas de continuite. Plus simple, perd le contexte. - Option 4 - session par turtle, mappee cote proxy : table
turtleId -> sessionIdcote 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/:jobIdpour 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
/askreste 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-proxyen 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 viasettings. 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 }avecMAX_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 :
sessionIdabsent dans la requete -> proxy en cree un (recommande oui).sessionIdfourni 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 ?
/healthreflete-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.
/sessionobligatoire ou implicite via/ask?/healthinclut 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 :
200succes400requete invalide (prompt vide, body malforme)401token absent/invalide413prompt trop long502OpenCode down504OpenCode timeout500erreur 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
tsxen dev,node dist/index.jsaprestscen 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_tokenopencc.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,--versionopencc "prompt"(argv) ou interactif viaread()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. Verifieopencc.proxy_urlet que l'hote est autorise danshttp.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 :
httpenable cote serveur.- Hote du proxy autorise dans
http.rules(allow*.tondomaine.tld:443ou 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.luadependencies:tos-coreautostart: 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
_VERSIONsur chaque module Lua modifie. --version/--helpsuropencc.- 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
partsretournees parPOST /session/:id/message:text,reasoning,tool,step-start,step-finishobserves. - Comportement OpenCode si
modelest passe vs absent : absent fonctionne avec le modele/session par defaut ;noReply:truecree sans LLM. - Basic Auth vraiment necessaire dans la config de Guillaume.
- Timeout effectif
http.postcote 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
/provideren logs partages, cet endpoint peut exposer l'auth. - CraftOS-PC headless peut-il faire
http.postHTTPS vers le proxy en local ?
L. Quoi repondre en priorite
Si tu veux aller vite, reponds dans cet ordre. Le reste decoule.
- A1 - critere d'acceptation
- A2 - workspace OpenCode (frontiere de confiance)
- A3 - cycle session
- A4 - sync vs async
- A5 - topologie deploiement
- A6 - auth turtle <-> proxy
- A7 - forme de la reponse
- 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.