Dev.to · 4 min read

Come incapsulare Codex CLI in Python come fa osFoundry

Come incapsulare Codex CLI in Python come fa osFoundry

Questo è il comando che l'app desktop di osFoundry esegue quando clicchi Verify sign-in per Codex. Lo costruisce build_codex_command in src-tauri/src/providers/agent_cli.rs, la stessa funzione da cui passa ogni vera esecuzione di cli:codex:agent: codex exec "Reply with the single word: ok" \ --json \ --skip-git-repo-check \ --ignore-user-config \ --ignore-rules \ -s read-only \ -c 'approval_policy="never"' Vediamolo pezzo per pezzo: exec con il prompt come unico argomento posizionale. Codex non ha un flag per il system prompt, quindi osFoundry costruisce quell'argomento come system + "\n\n" + transcript. --json fa sì che stdout sia un oggetto JSON per riga. Quello stream è l'unico output che osFoundry legge. --skip-git-repo-check permette di avviare l'esecuzione in una cartella che non è un repository. --ignore-user-config salta ~/.codex/config.toml, così i server MCP dell'utente restano fuori dall'esecuzione. L'autenticazione viene comunque caricata da CODEX_HOME. --ignore-rules viene aggiunto solo se codex exec --help lo elenca. osFoundry lo chiede al binario perché le build più vecchie rifiutano il flag, e un flag sconosciuto fa fallire l'intera esecuzione. -s insieme a approval_policy="never" imposta la sandbox e dice a Codex che non ci sarà nessuno ad approvare nulla. Un'esecuzione autonoma riceve -s workspace-write. Una che collega il bridge MCP di osFoundry riceve invece --dangerously-bypass-approvals-and-sandbox, e solo dentro un git worktree. Prima di lanciare il processo, osFoundry rimuove anche CODEX_API_KEY, OPENAI_API_KEY e OPENAI_BASE_URL dall'ambiente del processo figlio. Se una di queste fosse impostata, l'esecuzione finirebbe su un account API a consumo invece che sull'accesso ChatGPT. Il resto del post parla dell'altro capo di quella pipe. Hai una CLI di agente il cui formato di stream non è garantito, e devi tirarne fuori la risposta, l'avanzamento e un errore pulito. Perché leggere gli eventi invece di un file con la risposta finale? Ci sono due modi per ottenere una risposta da una CLI del genere: Risposta finale su file. Passi un percorso di output (codex exec -o FILE; le note del modulo di osFoundry lo chiamano l'output su file documentato), aspetti che il processo termini e poi leggi il file. Il contratto è un file con dentro una stringa. Stream di eventi su stdout. Passi --json, leggi riga per riga e tieni gli item che capisci. Il builder attuale di osFoundry fa la seconda cosa. Il parser si trova in runtime/session_event.rs (parse_codex_line) e si basa su pochissimo: Evento Diventa item.completed + agent_message testo della risposta item.completed + reasoning riga Thinking: … item.completed + command_execution Using shell — item.completed + mcp_tool_call Using … (Codex fornisce server e tool separatamente) item.completed + file_change / todo_list Edited / Plan: 1. … 2. … turn.completed utilizzo (input_tokens, cached_input_tokens, output_tokens) turn.failed, error errore, marcato come di autenticazione se il messaggio lo sembra Tutto il resto viene ignorato, così come qualsiasi riga che non sia JSON. È questa tolleranza che rende la cosa praticabile senza uno schema stabile. Un tipo di evento sconosciuto non costa nulla. Solo un campo rinominato in una di quelle sette righe può rompere il parser. Il prezzo è la granularità. Codex emette item completati, non delta di token. La risposta compare tutta in una volta quando il messaggio è finito, ed è per questo che l'app etichetta Codex come No live stream e lo descrive come run-then-emit. Le righe di avanzamento sono diverse: arrivano man mano che ogni item si completa. Ricostruire entrambe su un Mac Sulla macchina che ho usato non c'è nessun binario di Codex installato. Quindi ho scritto fake_codex.py, un sostituto che accetta gli stessi flag, stampa i tipi di evento visti sopra con ritardi fissi, scrive il messaggio finale nel file -o all'uscita e si può configurare per bloccarsi, andare in crash o fallire l'autenticazione. Non è Codex. Quello che permette di misurare è il comportamento del wrapper, non la velocità di Codex. La timeline del sostituto: un item reasoning a 0.4 s, poi un processo figlio di shell (sleep 0.8), poi l'agent_message circa 1.3 s dopo, poi turn.completed 0.2 s più tardi. Il file della risposta viene scritto all'uscita. Il wrapper, wrap.py, usa solo la libreria standard su Python 3.9.6. Il cuore della strategia a eventi, accorciato: def run_events(argv, timeout, env=None, group=True, drain_stderr=True): t0 = time.monotonic() p = subprocess.Popen(argv + ["--json"], stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, start_new_session=group) err = [] if drain_stderr: threading.Thread(target=_drain, args=(p.stderr, err), daemon=True).start() lines = queue.Queue() threading.Thread(target=pump, args=(p.stdout, lines), daemon=True).start() deadline = t0 + timeout while True: left = deadline - time.monotonic() if left

This is a summary aggregated from Dev.to. Read the complete article on the original site:

Read full article at Dev.to

More AI & Machine Learning News