7h. ECHO Codex — Éditeur de Code Souverain
ECHO Codex est un environnement d'édition de code complet, entièrement intégré dans Open WebUI.
Il associe un éditeur Monaco (le même moteur que VS Code) à un
dépôt Git local (via dulwich, Python pur, sans binaire Git externe)
et à une assistance AI (sous-chat Gemini via call_cascade()).
Chaque conversation dispose de son propre espace de stockage isolé, persistent et versionné.
💡 Architecture en trois couches
ECHO Codex repose sur trois composants distincts qui coopèrent :
-
echo_codex_git.py(14-owui-libs/) — Bibliothèque bas niveau : classeCodexRepogérant le dépôt Git dulwich (CRUD fichiers, commits, historique, diff, lecture à un commit donné, renommage). -
echo_codex_tool.py(12-owui-tools/) — Outil LLM (Tool Call) : 9 fonctions exposées à Gemini pour créer, lire, modifier, rechercher et gérer les fichiers du Codex depuis le chat. -
echo_codex_action.py(13-owui-actions/) — Action HUD : éditeur Monaco interactif injecté dans le DOM d'Open WebUI, avec édition AI, panneau de prévisualisation WYSIWYG, navigation Git et accès bidirectionnel Python ↔ JS.
HUD + Monaco + WYSIWYG] LLM[Gemini] -->|Tool Calls| TOOL[echo_codex_tool.py
9 Fonctions LLM] ACT --> |Python ↔ JS Promise| GIT[echo_codex_git.py
CodexRepo dulwich] TOOL --> GIT GIT --> |CRUD + Git| FS[Vault Codex
/users/id/files/codex/] GIT --> |Proprioception| DB[(SQLite codex_docs)] classDef frontend fill:#4a1d96,stroke:#8b5cf6,color:#f8fafc classDef backend fill:#1e293b,stroke:#475569,color:#f8fafc classDef db fill:#0f172a,stroke:#3b82f6,color:#f8fafc class ACT frontend class TOOL,GIT backend class FS,DB db
Stockage — Le Vault Codex
Chaque conversation dispose d'un dépôt Git dédié, isolé dans le Vault utilisateur :
/app/backend/data/users/{user_id}/files/codex/{chat_id}/
├── .git/ ← Dépôt Git dulwich (Python pur, pas de binaire git requis)
├── mon_script.py
├── config.yaml
└── README.md
La constante CODEX_DIR_NAME = "codex" (echo_constants.py) définit
le nom du sous-dossier. L'isolation est garantie par user_id et chat_id :
un utilisateur ne peut jamais accéder au Codex d'un autre, ni à celui d'une autre conversation.
Registre SQLite — codex_docs
Chaque fichier créé ou modifié est enregistré dans la table codex_docs de la base
{chat_id}.db (EchoStateManager). Ce registre sert à deux fins :
injection dans le vecteur proprioceptif (registre_codex) et statistiques rapides
sans accès disque.
| Colonne | Type | Description |
|---|---|---|
filename | TEXT (PK) | Nom du fichier (clé primaire) |
language | TEXT | Langage Monaco détecté depuis l'extension |
lines | INTEGER | Nombre de lignes au dernier commit |
last_commit | TEXT | Hash court (12 chars) du dernier commit |
commit_msg | TEXT | Message du dernier commit |
created_at | INTEGER | Timestamp Unix de création |
updated_at | INTEGER | Timestamp Unix de dernière modification |
⚙️ Détection de langage — CodexRepo.detect_language()
Méthode statique qui mappe l'extension du fichier vers l'identifiant Monaco Editor.
La table de correspondance CODEX_LANG_MAP (echo_constants.py) couvre
plus de 30 langages : Python, JavaScript, TypeScript, C/C++, Rust, Go, Java, SQL, Shell,
PowerShell, HTML, CSS, JSON, YAML, TOML, Markdown, etc. Fallback : plaintext.
Classe CodexRepo (echo_codex_git.py)
Abstraction autour de la bibliothèque dulwich (implémentation Python pure de Git).
Elle évite toute dépendance à un binaire git dans le conteneur.
Opérations CRUD
| Méthode | Description |
|---|---|
commit_file(filename, content, message) |
Écrit le contenu sur disque, indexe le fichier et crée un commit. Retourne le hash SHA du commit (str). |
read_file(filename, start_line, end_line) |
Lit le contenu d'un fichier. Sans plage : fichier complet. Avec start/end : tranche [start, end] (1-indexed, inclusif). Retourne {"content", "total_lines", "range"}. |
delete_file(filename, message) |
Supprime le fichier avec porcelain.rm() et crée un commit. Retourne le hash ou None si fichier inexistant. |
list_files() |
Liste tous les fichiers trackés (hors .git/). Retourne [{"filename", "lang", "lines", "size_bytes"}] trié alphabétiquement. |
search_in_file(filename, pattern, is_regex) |
Recherche un pattern (littéral ou regex). Retourne [{"line_number", "line_content"}]. Limité à 50 résultats. |
Historique Git
| Méthode | Description |
|---|---|
get_log(filename, limit) |
Retourne l'historique des commits. Si filename fourni, filtre les commits touchant ce fichier. Retourne [{"hash", "hash_full", "message", "author", "timestamp"}]. |
get_file_at_commit(filename, commit_hash) |
Lit le contenu d'un fichier à un commit donné (checkout virtuel sans modifier le working tree). Utilisé pour la navigation historique ◀ ▶ dans le HUD. |
get_file_history_index(filename) |
Retourne la liste ordonnée des commits touchant un fichier (du plus ancien au plus récent). Structure l'index de navigation du HUD. |
get_diff(commit_a, commit_b) |
Diff unifié entre deux commits. Si commit_b est None, diff commit_a contre son parent. |
Administration
| Méthode | Description |
|---|---|
reset_all() |
Supprime entièrement le dépôt (shutil.rmtree). Irréversible. Déclenché par l'action Reset du HUD. |
get_repo_stats() |
Retourne {"total_files", "total_commits", "total_size_bytes", "last_commit_hash", "last_commit_message"}. |
Outil LLM — echo_codex_tool.py (9 fonctions)
Ces fonctions sont exposées à Gemini comme Tool Calls. Le modèle peut les invoquer autonomement pendant une conversation pour interagir avec les fichiers du Codex.
| Fonction | Cas d'usage principal | Paramètres clés |
|---|---|---|
create_codex |
Créer un nouveau fichier avec contenu initial | filename, content, commit_msg (optionnel) |
edit_codex |
Écraser ou modifier un fichier existant | filename, content, commit_msg (optionnel) |
read_codex |
Lire tout ou partie d'un fichier | filename, start_line (opt.), end_line (opt.) |
search_codex |
Chercher un pattern pour cibler une zone avant lecture | filename, query, is_regex (opt.) |
summarize_codex |
Synthèse technique structurée via API Gemini | filename |
list_codex |
Inventaire de tous les fichiers (nom, lang, lignes, taille) | — |
delete_codex |
Supprimer un fichier (commit de suppression) | filename |
history_codex |
Afficher l'historique Git global ou d'un fichier spécifique | filename (opt.), limit (défaut 20) |
restore_codex |
Restaurer un fichier à un commit antérieur (crée un nouveau commit de restauration) | filename, commit_hash |
💡 Stratégie de lecture pour les grands fichiers
La docstring de read_codex recommande une approche en deux temps pour les fichiers
de plus de 300 lignes :
-
summarize_codex: distillation via Gemini → vue d'ensemble (architecture, classes, dépendances) sans saturer le contexte. -
search_codex: localiser la zone d'intérêt (numéros de ligne). -
read_codex(start_line, end_line): lecture chirurgicale de la plage ciblée.
Distillation dans summarize_codex
summarize_codex appelle EchoGeminiClient.call_distillation() avec
le prompt CODEX_SUMMARIZE_PROMPT (défini dans echo_constants.py).
La sortie est limitée à 8192 tokens.
CODEX_SUMMARIZE_PROMPT1. Objectif et rôle du fichier
2. Architecture : classes, fonctions, structures principales
3. Dépendances et imports
4. Patterns et conventions utilisés
5. Points d'attention, complexité, dette technique éventuelle
Action HUD — echo_codex_action.py (v1.8)
L'Action ECHO Codex injecte un éditeur Monaco complet directement dans le DOM
d'Open WebUI. C'est un HUD draggable et redimensionnable qui communique en temps réel avec
le backend Python via le Pattern Promise (__event_call__).
Architecture HUD
Le HUD est généré par EchoUI._generate_codex_js() (echo_ui.py).
Il s'agit d'un script JS auto-exécutable (IIFE) injecté une seule fois dans le DOM,
qui charge Monaco Editor depuis CDN (monaco-editor@0.52.0 sur jsDelivr).
| Zone du HUD | Description |
|---|---|
| File Tree (panneau gauche) | Liste dynamique des fichiers du Codex triés par mtime. Clic → chargement dans l'éditeur. Clic droit → Renommage natif (OS/Git). Icône × → suppression. Icône + → nouveau fichier. |
| Monaco Editor (zone centrale) | Éditeur Monaco avec panneau de prévisualisation WYSIWYG intégré (rendu HTML/Markdown). Bouton de sauvegarde explicite. Ctrl+S → sauvegarde + commit immédiat. |
| Barre d'état | Affiche le fichier courant, le hash du dernier commit, ou le hash de la version consultée (mode historique). |
| Panneau AI (bas) | Champ instruction, sélecteur modèle (LITE/FLASH/PRO), boutons d'actions rapides prédéfinies, bouton Appliquer. |
| Barre de navigation historique | Boutons ◀ ▶ pour naviguer commit par commit. Mode read-only visuel (fond différent). Bouton Restaurer. |
| Barre Diff (Accept/Reject) | Affichée après une édition AI : vue diff côte-à-côte (original vs. proposition). Accepter → commit. Rejeter → retour HEAD. |
Boucle événementielle bidirectionnelle
La boucle Python est une boucle while True bloquée sur une Promise JS.
Chaque interaction utilisateur dans le HUD résout la Promise et renvoie un dictionnaire
{ action: "...", filename: "...", content: "...", ... } au backend Python.
| Action JS | Traitement Python |
|---|---|
close | Sortie de la boucle. |
save | CodexRepo.commit_file() + state.save_codex_record() + notification JS echoCodexNotify('saved'). |
ai_edit | Appel _codex_ai_edit() → call_cascade() → echoCodexShowDiff(). |
accept_diff | commit_file() + echoCodexNotify('committed') + rechargement contenu. |
reject_diff | echoCodexRevertDiff() + rechargement contenu HEAD. |
upload | Import fichier PC → commit_file() + refresh tree. |
download | Lecture fichier → echoCodexDownload(name, content) (téléchargement navigateur). |
history_prev / history_next | get_file_at_commit() → echoCodexLoadVersion() (mode read-only). |
history_restore | commit_file() avec message "Restore from {hash}" + echoCodexNotify('restored'). |
new_file | commit_file(filename, "", "Create ...") + refresh tree. |
load_file | read_file() → echoCodexSetContent(). |
rename_file | repo.rename_file(old, new) + mise à jour codex_docs + refresh tree. |
delete_file | delete_file() + delete_codex_record() + refresh tree + auto-switch vers premier fichier. |
reset | repo.reset_all() + state.clear_codex_records() + echoCodexReset() (destroy HUD) + sortie boucle. |
refresh | list_files() → echoCodexRefreshTree() + rechargement fichier courant. |
Édition AI — _codex_ai_edit()
La méthode privée _codex_ai_edit() orchestre un sub-chat dédié (sans historique,
sans pensées) pour modifier le code. Elle retourne (texte_modifié, model_key_effectif)
ou None en cas d'échec.
## Document complet
```{lang}
{content complet du fichier}
```
## Sélection ciblée ← uniquement si l'utilisateur a sélectionné du texte
```{lang}
{selection}
```
## Instruction
{instruction de l'utilisateur}
Le système prompt (CODEX_EDIT_SYSTEM_PROMPT dans echo_constants.py)
impose au LLM de retourner uniquement le fichier complet modifié, sans explication,
sans bloc Markdown enveloppant. Le code Python nettoie les backticks parasites résiduels.
La cascade (call_cascade()) gère le clamping politique et le basculement
LITE/FLASH/PRO selon la disponibilité des modèles.
Actions rapides prédéfinies (CODEX_QUICK_ACTIONS)
L'utilisateur peut déclencher des transformations courantes via des boutons dans le panneau AI,
sans rédiger d'instruction manuelle. Ces raccourcis sont définis dans echo_constants.py :
| Bouton | Instruction envoyée au LLM |
|---|---|
| shorter | Raccourcis ce code/texte sans changer la logique ni le comportement. |
| longer | Développe avec plus de détails, commentaires et documentation. |
| comment | Ajoute des commentaires explicatifs clairs et concis. |
| uncomment | Supprime tous les commentaires du code. Ne conserve que le code exécutable. |
| refactor | Refactorise pour plus de lisibilité, maintenabilité et respect des conventions. |
| fix | Identifie et corrige les bugs potentiels. Explique chaque correction dans un commentaire. |
| tests | Génère les tests unitaires pertinents pour ce code. |
| optimize | Optimise les performances sans changer l'interface publique. |
API JS globale (callable depuis Python)
Le HUD expose ses fonctions de contrôle sur window pour être appelées
depuis les pushes Python via __event_call__({ type: "execute", data: { code } }) :
| Fonction JS | Rôle |
|---|---|
window.echoCodexNotify(type, msg) | Affiche une notification dans la barre d'état. Types : 'saved', 'committed', 'restored', générique. |
window.echoCodexSetContent(content, filename) | Charge un contenu dans l'éditeur Monaco et met à jour le sélecteur de langage. |
window.echoCodexShowDiff(modifiedContent) | Active le mode Diff (MonacoDiffEditor côte-à-côte) avec le contenu proposé. |
window.echoCodexRevertDiff() | Quitte le mode Diff et restaure l'éditeur normal. |
window.echoCodexRefreshTree(newFiles) | Met à jour la liste des fichiers dans le file tree. |
window.echoCodexLoadVersion(content, info, idx, total) | Active le mode historique read-only avec le contenu d'un commit donné. |
window.echoCodexExitHistory() | Quitte le mode historique et restaure l'éditeur normal. |
window.echoCodexDownload(name, content) | Déclenche le téléchargement natif du navigateur (Blob URL). |
window.echoCodexSetModel(modelKey) | Repositionne le sélecteur de modèle dans le panneau AI (feedback cascade). |
window.echoCodexReset() | Supprime entièrement le HUD du DOM. |
window.echoCodexResolve({action, ...}) | Résout la Promise en cours (retour utilisateur → Python). |
Proprioception — registre_codex
Le Filtre (new_context_filter.py v7.12) injecte automatiquement un registre
des fichiers Codex dans le vecteur d'état environnement_contexte (AEC) à
chaque tour de conversation. Gemini dispose ainsi d'une vue à jour de l'état du Codex
sans avoir à appeler list_codex.
registre_codex dans environnement_contexteregistre_codex:
- id: "mon_script.py"
lang: "python"
lines: 142
last_commit: "feat: add error handler"
- id: "config.yaml"
lang: "yaml"
lines: 38
last_commit: "chore: update timeout"
⚠️ Règle d'Or — Consulter le registre avant toute opération
Le modèle doit consulter registre_codex pour vérifier
l'existence d'un fichier avant d'appeler read_codex, edit_codex
ou delete_codex. Cette règle évite les erreurs 404 inutiles et les tentatives
de création de doublons.
Tableau récapitulatif des composants
| Composant | Fichier | Version | Rôle |
|---|---|---|---|
CodexRepo |
14-owui-libs/echo_codex_git.py |
1.0 | Gestion dépôt Git dulwich (CRUD, historique, diff) |
| Outil LLM Codex | 12-owui-tools/echo_codex_tool.py |
1.0 | 9 Tool Calls exposés à Gemini |
| Action HUD Codex | 13-owui-actions/echo_codex_action.py |
1.8 | Éditeur Monaco interactif avec WYSIWYG (priorité 5) |
_generate_codex_js() |
14-owui-libs/echo_ui.py |
— | Générateur du HUD JS Monaco |
| Constantes Codex | 14-owui-libs/echo_constants.py §1.4 |
5.4 | CODEX_DIR_NAME, CODEX_LANG_MAP, prompts, actions rapides |
Table codex_docs |
14-owui-libs/echo_utils.py |
7.21 | Registre SQLite par conversation (CRUD + injection AEC) |
registre_codex |
11-owui-filters/new_context_filter.py |
7.18 | Injection proprioceptive dans environnement_contexte |
✅ Exactitude — version 5.166.x
Les informations de cette page sont entièrement extraites du code source :
echo_codex_git.py, echo_codex_tool.py,
echo_codex_action.py, echo_ui.py,
echo_constants.py (§1.4), echo_utils.py (v7.21) et
new_context_filter.py (v7.12). Toute divergence avec ce document
est à résoudre en faveur du code source.