fix(permissions): validate network access flow
This commit is contained in:
6
.ideai/tickets/100/carnet.md
Normal file
6
.ideai/tickets/100/carnet.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
issueRef: "#100"
|
||||
version: 3
|
||||
updatedBy: {"kind":"user"}
|
||||
updatedAt: 1784993984569
|
||||
---
|
||||
16
.ideai/tickets/100/issue.md
Normal file
16
.ideai/tickets/100/issue.md
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
id: "4709958c-5082-44fd-a1fd-d6bad85f9361"
|
||||
number: 100
|
||||
title: "[Bug] Problème sur le scroll des agents OpenCode"
|
||||
status: "open"
|
||||
priority: "high"
|
||||
sprint: "e28a4d53-8bd2-446a-b0ac-2a017373b8b2"
|
||||
links: []
|
||||
agentRefs: []
|
||||
createdBy: {"kind":"user"}
|
||||
updatedBy: {"kind":"user"}
|
||||
createdAt: 1784992615586
|
||||
updatedAt: 1784993984569
|
||||
version: 3
|
||||
---
|
||||
Quand un agent est un agent opencode, je ne peux aps scroll très haut dans sa cellule.
|
||||
@ -1,8 +1,8 @@
|
||||
---
|
||||
issueRef: "#101"
|
||||
version: 5
|
||||
version: 7
|
||||
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedAt: 1785001809027
|
||||
updatedAt: 1785011116365
|
||||
---
|
||||
# Carnet #101 — défaut d'isolation multi-projet (cause racine figée)
|
||||
|
||||
@ -74,11 +74,17 @@ Test d'intégration **non-cross-talk** : 2 projets ouverts avec **volontairement
|
||||
- wake d'un projet non-actif fonctionne ;
|
||||
- collision d'ids qui échouait avant → verte sur PTY, structured et background wake.
|
||||
|
||||
## Topologie
|
||||
- Branche de travail : `feature/ticket101-multi-project-isolation` (créée par Git depuis
|
||||
`develop` 6a87c46).
|
||||
- `main` (da907b8), `feature/ticket99-agent-model-configuration` (da907b8),
|
||||
`fix/terminal-resize-bug` (da907b8) : **preuves préservées**, à nettoyer après enquête.
|
||||
## Clôture 2026-07-25
|
||||
- Correctif livré sur `feature/ticket101-multi-project-isolation` puis mergé localement dans `develop`.
|
||||
- Commit feature : `6e98fd8 fix(runtime): isolate agent state by project (#101)`.
|
||||
- Merge local : `merge: integrate ticket 101 multi-project isolation`.
|
||||
- QA ciblée verte :
|
||||
- `cargo test -p application --test agent_wake --test orchestrator_service --test structured_registry_d1 --test structured_launch_d3 --test session_limit_service --test session_limit_t4 --test workstate --test workstate_actions`
|
||||
- `cargo test -p infrastructure --test agent_inbox --test mcp_server`
|
||||
- `cargo test -p app-tauri --test session_limit_wiring`
|
||||
- `cargo test -p application`
|
||||
- `cargo test -p app-tauri --tests`
|
||||
- Réserve connue : `cargo test -p infrastructure` complet reste rouge dans le sandbox QA sur tests `openai_compat` à cause du bind local interdit (`Operation not permitted`), sans signal de régression #101.
|
||||
|
||||
## Hors périmètre
|
||||
- #91 (popup de notification) : purement front, indépendant.
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
id: "05f9f05b-97d4-4ae2-9fd9-220dd71f7231"
|
||||
number: 101
|
||||
title: "[Bug] Soucis de retour de notification sur les taches backend"
|
||||
status: "open"
|
||||
status: "closed"
|
||||
priority: "critical"
|
||||
sprint: "e28a4d53-8bd2-446a-b0ac-2a017373b8b2"
|
||||
links: []
|
||||
@ -10,7 +10,7 @@ agentRefs: [{"agentId":"a6ced819-b893-4213-b003-9e9dc79b9641","role":"assigned"}
|
||||
createdBy: {"kind":"user"}
|
||||
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
createdAt: 1784993230013
|
||||
updatedAt: 1785001809027
|
||||
version: 5
|
||||
updatedAt: 1785011116365
|
||||
version: 7
|
||||
---
|
||||
Lorsque un agent Opencode lance une tache backend, il s'arrete de travailler et je ne suis pas sur q'uil y ai un jour un retour de notification. Je ne sais aps si le soucis provient de OpenCode ou s'il provient du model (GLM 5.2 ici)
|
||||
6
.ideai/tickets/102/carnet.md
Normal file
6
.ideai/tickets/102/carnet.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
issueRef: "#102"
|
||||
version: 4
|
||||
updatedBy: {"kind":"user"}
|
||||
updatedAt: 1784993980505
|
||||
---
|
||||
16
.ideai/tickets/102/issue.md
Normal file
16
.ideai/tickets/102/issue.md
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
id: "e91fd358-da94-4382-aa70-6a3fe5a63840"
|
||||
number: 102
|
||||
title: "[Bug] Devoir resize les cellule pour afficher la TUI d'un agent"
|
||||
status: "open"
|
||||
priority: "medium"
|
||||
sprint: "e28a4d53-8bd2-446a-b0ac-2a017373b8b2"
|
||||
links: []
|
||||
agentRefs: [{"agentId":"a6ced819-b893-4213-b003-9e9dc79b9641","role":"assigned"}]
|
||||
createdBy: {"kind":"user"}
|
||||
updatedBy: {"kind":"user"}
|
||||
createdAt: 1784993319700
|
||||
updatedAt: 1784993980505
|
||||
version: 4
|
||||
---
|
||||
J'ai toujours un soucis qui fait que quand je switch de projet IdeA ou de layout ou que j'ajoute des cellules ou autres, je suis obligé de resize un coup la cellule pour que son constenu s'affiche correctement
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
issueRef: "#91"
|
||||
version: 3
|
||||
version: 4
|
||||
updatedBy: {"kind":"user"}
|
||||
updatedAt: 1784652150003
|
||||
updatedAt: 1784994105390
|
||||
---
|
||||
|
||||
@ -4,13 +4,13 @@ number: 91
|
||||
title: "Sur la notification de fin de tache backend, mettre plutot les deux agents en conversation"
|
||||
status: "open"
|
||||
priority: "medium"
|
||||
sprint: null
|
||||
sprint: "5afd6780-0f76-40d7-a10f-32ee52469d74"
|
||||
links: []
|
||||
agentRefs: [{"agentId":"a6ced819-b893-4213-b003-9e9dc79b9641","role":"assigned"}]
|
||||
createdBy: {"kind":"user"}
|
||||
updatedBy: {"kind":"user"}
|
||||
createdAt: 1784652125081
|
||||
updatedAt: 1784652150003
|
||||
version: 3
|
||||
updatedAt: 1784994105390
|
||||
version: 4
|
||||
---
|
||||
Sur la notification de fin de tache backend, mettre plutot les deux agents en conveersation et qui a lancé l'appel (par exemple Main->DevBackend) pour que ça soit un peu plus explicite
|
||||
@ -1,8 +1,8 @@
|
||||
---
|
||||
issueRef: "#92"
|
||||
version: 8
|
||||
version: 9
|
||||
updatedBy: {"kind":"user"}
|
||||
updatedAt: 1784788822167
|
||||
updatedAt: 1784993956910
|
||||
---
|
||||
## Résumé de livraison
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
id: "9ba8d2f4-49fa-4536-a38e-891f1df3e3b7"
|
||||
number: 92
|
||||
title: "Configurer OpenCode avec un provider Opencode"
|
||||
status: "open"
|
||||
status: "closed"
|
||||
priority: "high"
|
||||
sprint: null
|
||||
links: []
|
||||
@ -10,7 +10,7 @@ agentRefs: []
|
||||
createdBy: {"kind":"user"}
|
||||
updatedBy: {"kind":"user"}
|
||||
createdAt: 1784729443275
|
||||
updatedAt: 1784788822167
|
||||
version: 8
|
||||
updatedAt: 1784993956910
|
||||
version: 9
|
||||
---
|
||||
On peut actuellement utiliser un profile AI qui utilise OpenCode pour llamacpp. J'aimerais que l'on puisse configurer des profil AI OpenCode avec llamacpp comme actuellement, mais aussi en selectionnant un provider listé dans la commande /connect de OpenCode. Je pense que le mieux serait que lors de la création d'un profile AI OpenCode, il nous soit demandé si on souhaite utiliser LlamaCpp ou un provider OpenCode. Dans le cas d'un provider llamaCpp, on utilise la même chose qu'actuellement, dans l'autre cas on nous demande quel provider et il faudrait être capable de récupérer la liste fournie par OpenCode. Une fois le provider selectionné, il faudra que l'utilisateur puisse entrer une clé API car les providers opencodes en demadnent toujours un. Pour la partie utilisation ensuite d'opencode dans les agent, je pense que cette page peut aider: https://opencode.ai/docs/fr/cli/. On y trouve entre autre la commande pour se connecter avec opencode auth login. Le but est que la partie configuration se fasse dans les profil AI comme jusqu'à présent, et que l'utilisateur puisse directement attribuer un agent à son profile AI et le lancer sans configurer d'autre choses. OpenCode marche déjà correctement avec llamacpp, j'insiste sur le fait qu'on ne fait qu'ajouter la possibilité de configurer un provider autre que llamacpp
|
||||
46
.ideai/tickets/93/carnet.md
Normal file
46
.ideai/tickets/93/carnet.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
issueRef: "#93"
|
||||
version: 3
|
||||
updatedBy: {"kind":"user"}
|
||||
updatedAt: 1784934179780
|
||||
---
|
||||
# Contexte
|
||||
|
||||
Test manuel demandé par l'utilisateur pour valider la conversation inter-agent : Main a appelé `idea_ask_agent(target="Context", task="...")` avec une tâche de simple confirmation d'identité/rôle.
|
||||
|
||||
## Observation
|
||||
|
||||
Les deux appels (identiques) ont renvoyé, à la place d'une réponse finale en langage naturel, exactement ce fragment JSON brut :
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "idea_idea_context_read",
|
||||
"arguments": {}
|
||||
}
|
||||
```
|
||||
|
||||
- Le nom d'outil est corrompu : préfixe `idea_` dupliqué (`idea_idea_context_read` au lieu de `idea_context_read`).
|
||||
- Le fragment a la forme d'un appel d'outil (tool_use), pas d'un texte de réponse — semble être une tentative de Context de lire son contexte projet via `idea_context_read`, jamais exécutée, puis remontée telle quelle comme si c'était le Final capturé.
|
||||
- Reproduit à l'identique sur 2 tentatives consécutives → pas un aléa de génération, plutôt un bug de câblage/capture.
|
||||
|
||||
## Détails agent Context
|
||||
|
||||
- id: `5d07e4a7-8676-4a71-aea1-5b64caefa944`
|
||||
- contextPath: `agents/context.md`
|
||||
- profileId: `a7037cbe-6d04-48fb-ba74-f353c93fc70a` (profil différent de celui des autres agents du manifeste, qui partagent tous `664cc20c-47b8-53ad-9351-dce3c09c0de4` — Context est le seul sur ce profil)
|
||||
- origin: scratch
|
||||
|
||||
## Pistes d'investigation pour Architect / DevBackend
|
||||
|
||||
1. Le profil `a7037cbe-...` (LLM local léger dédié à Context, cf. mémoire `agent-context-memory-and-profile-handoff`) semble ne pas capturer correctement le "Final" du tour — le pont MCP/runtime renverrait le premier tool_use brut au lieu d'attendre la réponse texte finale.
|
||||
2. Vérifier le mapping des noms d'outils exposés à ce profil : la duplication `idea_idea_*` suggère un préfixage appliqué deux fois (une fois côté définition d'outil MCP, une fois côté wrapper du profil/pont).
|
||||
3. Comparer avec le comportement des autres profils (`664cc20c-...`) qui fonctionnent correctement en inter-agent, pour isoler ce qui diffère structurellement dans le pont pour un profil local/structured.
|
||||
4. Voir mémoire projet `mcp-bridge-and-delegation-runtime-notes` pour les pièges déjà connus du pont MCP/délégation — possible recoupement.
|
||||
|
||||
## Repro
|
||||
|
||||
Depuis Main :
|
||||
```
|
||||
idea_ask_agent(target="Context", task="<n'importe quelle tâche simple>")
|
||||
```
|
||||
→ renvoie le fragment JSON ci-dessus au lieu d'une réponse.
|
||||
27
.ideai/tickets/93/issue.md
Normal file
27
.ideai/tickets/93/issue.md
Normal file
@ -0,0 +1,27 @@
|
||||
---
|
||||
id: "40f56f7d-b0ec-4409-bf6b-c010e3003b76"
|
||||
number: 93
|
||||
title: "Agent Context : réponse finale non capturée, fragment d'appel d'outil brut renvoyé via idea_ask_agent"
|
||||
status: "closed"
|
||||
priority: "medium"
|
||||
sprint: null
|
||||
links: []
|
||||
agentRefs: []
|
||||
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedBy: {"kind":"user"}
|
||||
createdAt: 1784817692650
|
||||
updatedAt: 1784934179780
|
||||
version: 3
|
||||
---
|
||||
Lors d'un test de la conversation inter-agent (idea_ask_agent ciblant Context), l'appel renvoie systématiquement un fragment JSON brut au lieu d'une réponse finale exploitable :
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "idea_idea_context_read",
|
||||
"arguments": {}
|
||||
}
|
||||
```
|
||||
|
||||
Le nom d'outil est corrompu (préfixe "idea_" dupliqué : "idea_idea_context_read" au lieu de "idea_context_read"), et ce fragment ressemble à une tentative d'appel d'outil non exécutée, renvoyée telle quelle comme si c'était la réponse finale du modèle.
|
||||
|
||||
Comportement reproduit deux fois de suite à l'identique, donc pas un aléa ponctuel.
|
||||
6
.ideai/tickets/94/carnet.md
Normal file
6
.ideai/tickets/94/carnet.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
issueRef: "#94"
|
||||
version: 2
|
||||
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedAt: 1784823278030
|
||||
---
|
||||
48
.ideai/tickets/94/issue.md
Normal file
48
.ideai/tickets/94/issue.md
Normal file
@ -0,0 +1,48 @@
|
||||
---
|
||||
id: "33a844e0-6a06-46c7-b800-d3497a7f45f4"
|
||||
number: 94
|
||||
title: "Permissions OpenCode ignorées : opencode.json code en dur bash/edit=ask au lieu de projeter EffectivePermissions"
|
||||
status: "closed"
|
||||
priority: "high"
|
||||
sprint: null
|
||||
links: []
|
||||
agentRefs: []
|
||||
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
createdAt: 1784821271815
|
||||
updatedAt: 1784823278030
|
||||
version: 2
|
||||
---
|
||||
## Bug
|
||||
|
||||
Les permissions configurées dans IdeA pour un agent sous profil OpenCode ne sont PAS appliquées dans le `opencode.json` généré. Le bloc `permission` est codé en dur à `{"bash":"ask","edit":"ask"}` quel que soit le réglage IdeA.
|
||||
|
||||
## Repro
|
||||
|
||||
Config IdeA (agent OpenCode) : Read=Allow, Write=Deny, Delete=Allow, bash=Allow.
|
||||
`opencode.json` généré (run dir) : `"permission":{"bash":"ask","edit":"ask"}`.
|
||||
Attendu : `bash` reflète la posture bash (Allow→"allow"), `edit` reflète la posture Write (Deny→"deny").
|
||||
|
||||
Claude et Codex appliquent correctement les permissions ; seul OpenCode est touché.
|
||||
|
||||
## Cause racine
|
||||
|
||||
Le pattern de projection des permissions (`PermissionProjector` + `ProjectorKey::{Claude,Codex}` dans `crates/infrastructure/src/permission/`) est bypassé pour OpenCode. Les générateurs `opencode.json` codent `permission` en dur à 4 endroits :
|
||||
|
||||
- `crates/application/src/agent/lifecycle.rs:2728-2734` (`opencode_config_json`, variante llamacpp)
|
||||
- `crates/application/src/agent/lifecycle.rs:2814-2820` (`opencode_provider_config_json`, variante cloud)
|
||||
- `crates/infrastructure/src/assistant/mod.rs:406-412` (`opencode_config_json`, doublon)
|
||||
- `crates/infrastructure/src/assistant/mod.rs:494-500` (`opencode_provider_config_json`, doublon)
|
||||
|
||||
Les call sites (`lifecycle.rs:2361-2378` branche `OpenCodeConfig`, et `assistant/mod.rs:247-256`) ne passent pas les `EffectivePermissions` résolues aux générateurs.
|
||||
|
||||
## Mapping attendu (à confirmer par Architect)
|
||||
|
||||
OpenCode `permission` = map tool→"allow"|"ask"|"deny". IdéA → OpenCode :
|
||||
- `bash` ← posture bash effective
|
||||
- `edit` ← posture Write effective
|
||||
- Read/Delete ne sont pas exprimables dans opencode (pas de clé read/delete) — déjà enforcees par le sandbox Landlock (mémoire `permissions-sandbox-system-state`).
|
||||
|
||||
## Périmètre
|
||||
|
||||
Backend Rust pur. Validation possible par tests unitaires sur les générateurs (`opencode_provider_config_json` est déjà testé à lifecycle.rs:4413 et assistant/mod.rs:639) sans rebuild AppImage. Validation live = rebuild AppImage + relance IdeA.
|
||||
36
.ideai/tickets/95/carnet.md
Normal file
36
.ideai/tickets/95/carnet.md
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
issueRef: "#95"
|
||||
version: 6
|
||||
updatedBy: {"kind":"user"}
|
||||
updatedAt: 1784934174326
|
||||
---
|
||||
## Cause racine RÉELLE (2026-07-24, après investigation code)
|
||||
|
||||
### Ce qui se passe
|
||||
|
||||
Le `"timeout": 15000` (15 secondes) **hardcoded** dans le bloc `mcp.idea` de l'`opencode.json` généré par IdeA. OpenCode applique ce timeout **par appel `tools/call`** à ses serveurs MCP. `idea_ask_agent` bloque pendant que l'agent cible travaille (potentiellement des minutes) → OpenCode tue la requête à 15s avec l'erreur `-32001: Request timed out`.
|
||||
|
||||
**Pourquoi Claude/Codex ne sont pas affectés** : leur config MCP (`.mcp.json` / `config.toml`) n'a **pas** de champ `timeout`. Ce champ est spécifique à la config OpenCode.
|
||||
|
||||
### Emplacements du hardcoded 15000 (4 occurrences)
|
||||
|
||||
1. `application/src/agent/lifecycle.rs:2728` — `opencode_config_json()`
|
||||
2. `application/src/agent/lifecycle.rs:2811` — `opencode_provider_config_json()`
|
||||
3. `infrastructure/src/assistant/mod.rs:410` — `opencode_config_json()` (duplicate)
|
||||
4. `infrastructure/src/assistant/mod.rs:495` — `opencode_provider_config_json()` (duplicate)
|
||||
|
||||
### Fix appliqué (feature/ticket95-opencode-mcp-timeout)
|
||||
|
||||
- Constante `DEFAULT_OPENCODE_MCP_TIMEOUT_MS` = 4h (14_400_000 ms), alignée sur `DEFAULT_RENDEZVOUS_CEILING` — le client MCP ne expire jamais avant le watchdog serveur.
|
||||
- Fonction `resolve_opencode_mcp_timeout_ms()` — overridable via `IDEA_OPENCODE_MCP_TIMEOUT_MS`, fallback sûr sur 0/parse-error.
|
||||
- Les 4 occurrences remplacées par `resolve_opencode_mcp_timeout_ms()`.
|
||||
- Exporté depuis `application::agent` pour réutilisation par `infrastructure`.
|
||||
- **Claude/Codex non touchés** : aucune modification de leur config MCP.
|
||||
|
||||
### Tests
|
||||
- Application : 115 passed, 0 failed
|
||||
- Infrastructure : 313 passed, 0 failed
|
||||
- Compilation : OK, aucun nouveau warning
|
||||
|
||||
### Note déploiement
|
||||
Le `opencode.json` est régénéré à chaque lancement d'agent par le code lifecycle. Nécessite rebuild AppImage pour que le binaire qui tourne génère la nouvelle config.
|
||||
54
.ideai/tickets/95/issue.md
Normal file
54
.ideai/tickets/95/issue.md
Normal file
@ -0,0 +1,54 @@
|
||||
---
|
||||
id: "611077a6-f703-44b9-935b-64f8301085bb"
|
||||
number: 95
|
||||
title: "Rendez-vous idea_ask_agent : timeout MCP OpenCode trop court (15s), le demandeur OpenCode ne reçoit jamais la réponse"
|
||||
status: "closed"
|
||||
priority: "high"
|
||||
sprint: null
|
||||
links: []
|
||||
agentRefs: []
|
||||
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedBy: {"kind":"user"}
|
||||
createdAt: 1784822537740
|
||||
updatedAt: 1784934174326
|
||||
version: 6
|
||||
---
|
||||
## Bug
|
||||
|
||||
Une délégation `idea_ask_agent` depuis un agent sous profil **OpenCode** (le **demandeur**) échoue systématiquement en `timeout` (-32001 « Request timed out »), peu importe la cible (Claude, Codex, ou OpenCode). Les agents cibles terminent bien leurs tâches (visible dans le workstate = done), mais leurs réponses ne sont jamais livrées au demandeur OpenCode.
|
||||
|
||||
Claude et Codex ne sont **pas** affectés, qu'ils soient demandeur ou cible.
|
||||
|
||||
## Cause racine (vérifiée dans les sources)
|
||||
|
||||
Le `"timeout": 15000` (15 secondes) **hardcoded** dans le bloc `mcp.idea` de l'`opencode.json` généré par IdeA. OpenCode applique ce timeout **par appel `tools/call`** à ses serveurs MCP. `idea_ask_agent` bloque pendant que l'agent cible travaille (potentiellement des minutes) → OpenCode tue la requête à 15s.
|
||||
|
||||
**Pourquoi Claude/Codex ne sont pas affectés** : leur config MCP (`.mcp.json` / `config.toml`) n'a **pas** de champ `timeout`. Ce champ est spécifique à la config OpenCode (`opencode.json` → `mcp.idea.timeout`).
|
||||
|
||||
### Emplacements (4 occurrences de `15000`)
|
||||
|
||||
1. `crates/application/src/agent/lifecycle.rs` — `opencode_config_json()`
|
||||
2. `crates/application/src/agent/lifecycle.rs` — `opencode_provider_config_json()`
|
||||
3. `crates/infrastructure/src/assistant/mod.rs` — `opencode_config_json()` (duplicate)
|
||||
4. `crates/infrastructure/src/assistant/mod.rs` — `opencode_provider_config_json()` (duplicate)
|
||||
|
||||
## Ce qui n'est PAS la cause
|
||||
|
||||
- Ce n'est pas un problème de sonde de vivacité du rendez-vous (la description originale pointait la sonde Claude-only côté cible — mauvaise piste).
|
||||
- Ce n'est pas un problème de permissions, de sandbox, ou de taille de payload.
|
||||
- Ce n'est pas lié au modèle : tout profil `structuredAdapter: "openCode"` est touché en tant que demandeur.
|
||||
|
||||
## Fix appliqué (feature/ticket95-opencode-mcp-timeout)
|
||||
|
||||
- Constante `DEFAULT_OPENCODE_MCP_TIMEOUT_MS` = 4h (14_400_000 ms), alignée sur `DEFAULT_RENDEZVOUS_CEILING`.
|
||||
- Fonction `resolve_opencode_mcp_timeout_ms()` — overridable via `IDEA_OPENCODE_MCP_TIMEOUT_MS`, fallback sûr.
|
||||
- Les 4 occurrences remplacées.
|
||||
- **Claude/Codex non touchés**.
|
||||
|
||||
## Tests
|
||||
|
||||
Application : 115 passed. Infrastructure : 313 passed. 0 failed.
|
||||
|
||||
## Déploiement
|
||||
|
||||
Nécessite rebuild AppImage (l'`opencode.json` est régénéré à chaque lancement d'agent).
|
||||
18
.ideai/tickets/96/carnet.md
Normal file
18
.ideai/tickets/96/carnet.md
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
issueRef: "#96"
|
||||
version: 3
|
||||
updatedBy: {"kind":"user"}
|
||||
updatedAt: 1784994119004
|
||||
---
|
||||
## Décision (2026-07-24) : différée — documentée, non codée
|
||||
|
||||
Sur instruction utilisateur (#96 mis en pause pour se concentrer sur #95) : **on documente le constat et la décision de fond reste ouverte pour plus tard**. Aucun code ajouté.
|
||||
|
||||
### Constat confirmé dans les sources
|
||||
`crates/infrastructure/src/assistant/mod.rs::TicketAssistantEnvironmentPreparer::materialise_mcp` passe `eff: None` à `opencode_config_json` / `opencode_provider_config_json` (lignes ~253 et ~262). Le commentaire local (l. 246-251) le documente déjà : aucun `PermissionStore`/`EffectivePermissions` n'est résolu sur ce chemin, **pour aucun adaptateur**. Conséquence : les assistants de ticket tournent toujours avec le comportement **natif** d'OpenCode (prompting à chaque action), indépendamment des permissions IdeA configurées.
|
||||
|
||||
### Pourquoi c'est différé (la vraie question produit)
|
||||
Les assistants de ticket sont lancés depuis un **profil** (pas depuis un **agent** avec une politique par-agent). Il n'y a donc **pas de source naturelle** d'`EffectivePermissions` sur ce chemin. Câbler nécessite d'abord de trancher : les permissions viennent-elles du profil ? d'un fallback projet ? d'une posture dédiée aux assistants ? Tant que ce choix produit n'est pas posé, `eff: None` (= prompting natif) reste le défaut **sûr** — ce n'est pas une régression, c'est le comportement historique préservé.
|
||||
|
||||
### Suivi
|
||||
Non bloquant, priorité basse. À reprendre quand un besoin produit le justifie : définir la source d'autorités pour un assistant de ticket, puis la résoudre ici (comme pour les agents normaux dans `application::agent::lifecycle`).
|
||||
18
.ideai/tickets/96/issue.md
Normal file
18
.ideai/tickets/96/issue.md
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
id: "d5993d21-307b-4fc8-93f9-2bfbf44223d8"
|
||||
number: 96
|
||||
title: "Les assistants de ticket (tous adaptateurs) n'ont aucune résolution EffectivePermissions — permission toujours native/absente"
|
||||
status: "open"
|
||||
priority: "low"
|
||||
sprint: "883534aa-7fc1-4d83-a9c0-17cac4a4eea5"
|
||||
links: []
|
||||
agentRefs: []
|
||||
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedBy: {"kind":"user"}
|
||||
createdAt: 1784823281794
|
||||
updatedAt: 1784994119004
|
||||
version: 3
|
||||
---
|
||||
Trouvé en implémentant #94 (projection des permissions dans opencode.json). Le call site des assistants de ticket dans `crates/infrastructure/src/assistant/mod.rs` n'a **aucun** `PermissionStore`/`EffectivePermissions` câblé, pour aucun adaptateur (Claude, Codex, OpenCode) — vérifié par grep sur la composition root `crates/backend/src/lib.rs`. Le fix #94 y passe donc `eff: None` (préserve le comportement natif existant, pas de régression), mais ce n'est pas un vrai fix de fond : les permissions IdeA configurées pour un agent n'ont jamais été appliquées aux assistants de ticket, quel que soit l'adaptateur.
|
||||
|
||||
À trancher par Architect : soit câbler la résolution `EffectivePermissions` pour ce call site (comme pour les agents normaux), soit documenter que c'est un choix produit intentionnel (permanent) et fermer sans y toucher. Non bloquant, priorité basse.
|
||||
28
.ideai/tickets/97/carnet.md
Normal file
28
.ideai/tickets/97/carnet.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
issueRef: "#97"
|
||||
version: 3
|
||||
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedAt: 1784915626417
|
||||
---
|
||||
## Décision Architect (cadrage validé)
|
||||
|
||||
Bug 100% backend, deux défauts composés :
|
||||
1. `SaveOpenCodeProviderProfile::execute` (`usecases.rs:364-367`) pose `opencode_provider` sans `opencode = None`.
|
||||
2. Invariant `opencode_backend_is_consistent` (`profile.rs:1220`) existe mais jamais appelé (garde morte).
|
||||
Lecture priorise `opencode` → cloud écrasé (`lifecycle.rs:2367`, `assistant/mod.rs:252`).
|
||||
|
||||
### Périmètre du lot (un seul, parallélisable)
|
||||
- **DevBackend** :
|
||||
- Domaine : `with_opencode`/`with_opencode_provider` (`profile.rs:1132,1140`) imposent l'exclusion mutuelle (chacun efface l'autre).
|
||||
- Infrastructure : `FsProfileStore::save` rejette tout profil incohérent → `AppError::Invalid` (active enfin le prédicat).
|
||||
- Application : `SaveOpenCodeProviderProfile` reconstruit via builder (`with_opencode_provider`) ; idem pour `SaveProfile`/`ConfigureProfiles`.
|
||||
- **Migration requise** : à la lecture (ou passe dédiée), quand `opencode` ET `opencodeProvider` présents → dropper `opencode` stale (l'intention est cloud). Sinon ne corrige que les nouveaux profils.
|
||||
- **DevFrontend** : strip de la config inactive au save selon le mode courant (requis pour SaveProfile/ConfigureProfiles qui ne portent pas d'intention explicite ; backend reste autorité via la garde).
|
||||
- **QA** : tests unitaires domaine (builders exclusifs) + garde store + intégration création profil cloud + scénario migration profils corrompus.
|
||||
|
||||
### Décisions de frontière
|
||||
- DTO `SaveOpenCodeProviderProfileRequestDto` **inchangé** (whole-profile) ; output = profil normalisé, autorité pour le frontend.
|
||||
- Priorité lecture `opencode` d'abord **gardée** (irrelevant post-exclusion), commenter comme fallback défensif.
|
||||
- Duplication de la résolution (lifecycle.rs:2367 + assistant/mod.rs:252) = dette hexagonale préexistante, **hors périmètre de ce lot** (suivre, ne pas refactoriser ici).
|
||||
|
||||
Voir mémoire projet `ticket97-opencode-provider-mutual-exclusion`.
|
||||
26
.ideai/tickets/97/issue.md
Normal file
26
.ideai/tickets/97/issue.md
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
id: "fd7057dc-0177-41e1-811c-701c802e81d3"
|
||||
number: 97
|
||||
title: "Duplication de provider lors de la création de profil AI - llamacpp ET provider cloud inclus simultanément"
|
||||
status: "closed"
|
||||
priority: "high"
|
||||
sprint: null
|
||||
links: []
|
||||
agentRefs: []
|
||||
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
createdAt: 1784899606438
|
||||
updatedAt: 1784915626417
|
||||
version: 3
|
||||
---
|
||||
Lors de la création d'un profil AI dans le premier-run wizard, le système génère un profiles.json qui contient à la fois la section `opencode` (llamacpp) et `opencodeProvider` (cloud), quel que soit le choix de l'utilisateur.
|
||||
|
||||
**Comportement attendu :**
|
||||
- Si l'utilisateur choisit "llamacpp" : seule la section `opencode` doit être présente
|
||||
- Si l'utilisateur choisit "provider cloud" : seule la section `opencodeProvider` doit être présente
|
||||
|
||||
**Comportement actuel :**
|
||||
Les deux sections sont présentes simultanément, ce qui fait que llamacpp est priorisé même quand l'utilisateur veut utiliser un provider cloud (ex: ZAI/GLM).
|
||||
|
||||
**Cas de test :**
|
||||
Création du profil GLM5.2 avec provider ZAI Code → profiles.json contient `opencodeProvider` correct MAIS contient aussi une section `opencode` vide ou inutile, ce qui force le fallback sur llamacpp.
|
||||
87
.ideai/tickets/98/carnet.md
Normal file
87
.ideai/tickets/98/carnet.md
Normal file
@ -0,0 +1,87 @@
|
||||
---
|
||||
issueRef: "#98"
|
||||
version: 5
|
||||
updatedBy: {"kind":"user"}
|
||||
updatedAt: 1784983186248
|
||||
---
|
||||
# Carnet #98 — Contrat figé (approche **B2**)
|
||||
|
||||
> Cadrage ARCHITECT figé et gelé. **Source de vérité pour DevBackend et QA.** Ce carnet remplace la phase d'arbitrage ; les options A/B1/C sont closes (voir §2 pour le rejet motivé).
|
||||
|
||||
---
|
||||
|
||||
## 1. Cause racine affinée
|
||||
|
||||
Le modèle est perdu **au spawn**, pas à la sauvegarde (persistance vérifiée correcte bout en bout, `profiles.json` conserve bien `opencodeProvider.model`). Deux facteurs composés :
|
||||
|
||||
1. **Pas de bloc `models`** pour les providers catalogue connus — `opencode_provider_config_json` (`lifecycle.rs:2774-2844` + jumeau `assistant/mod.rs:428-503`) n'émet `npm`/`baseURL`/`models` **que** pour le chemin `custom`. Pour un provider catalogue (zai), seul `provider.<id>.options.apiKey` est écrit. Test fige ce manque : `lifecycle.rs:4439-4440`.
|
||||
2. **Cache models.dev isolé et vide** — IdeA passe `XDG_CACHE_HOME=<run_dir>/.opencode/cache` vide (`lifecycle.rs:2386,2405` ; `assistant/mod.rs:272,282`) + `HOME` isolé. Or `zai` n'est connu d'OpenCode **que** via ce cache (catalogue lu côté IdeA depuis le vrai `~/.cache/opencode/models.json`, `provider_catalogue.rs:79-84`).
|
||||
|
||||
→ OpenCode ne connaît plus `zai`, ne résout pas `zai/<modèle>` → **fallback silencieux `glm-5.2`** (fallback interne CLI OpenCode, absent du code IdeA).
|
||||
|
||||
Asymétrie confirmée : local llama.cpp et cloud custom marchent car ils émettent un bloc `models` (`assistant/mod.rs:371-379`, `:457-460`).
|
||||
|
||||
## 2. Approche retenue : **B2** (seed best-effort du cache hôte)
|
||||
|
||||
Copier best-effort le cache models.dev hôte (`opencode_models_cache_path()`) vers `<xdg_cache>/opencode/models.json` dans le cache isolé, juste après le `create_dir_all` du cache dans `apply_mcp_config` (branche commune opencode/opencodeProvider), aux **DEUX** sites.
|
||||
|
||||
**Rejet motivé des alternatives :**
|
||||
- **A (émettre bloc `models` pour providers connus)** : rejeté car `provider_catalogue.rs` ne persiste que `name`+`models` et **ignore `npm`+`baseURL`**. Un bloc `models` seul laisse OpenCode incapable de *joindre* `zai` — il faudrait en plus étendre le domaine (`display_name`/`npm`/`base_url`) → scope bien plus large et risque régression. A n'est viable qu'en révision A-étendue, écartée pour ce lot.
|
||||
- **B1 (= B sans factorisation, deux sites copiés)** : rejeté pour dette hexagonale — le writer `opencode_provider_config_json` est déjà dupliqué `lifecycle.rs` vs `assistant/mod.rs`. Dupliquer aussi le seed amplifierait la dette et rendrait toute divergence un bug silencieux. B2 impose une factorisation unique.
|
||||
- **C (hybride : pointer `XDG_CACHE_HOME` vers le vrai cache)** : rejeté — casse l'invariant d'isolation du run (un profil pourrait lire/écrire le cache hôte ou un cache d'un autre run), et OpenCode pourrait y écrire (logs, refresh) → pollution mutuelle.
|
||||
|
||||
**Pourquoi B2 :** donne à OpenCode sa connaissance registry complète (npm, baseURL, modèles) sans toucher au domaine ni casser l'isolation écriture — c'est de la donnée publique read-only copiée **dans** l'espace isolé.
|
||||
|
||||
## 3. Contrat figé — ports / fichiers / invariants
|
||||
|
||||
### 3.1 Fonctions à implémenter (factorisation)
|
||||
|
||||
- **Rendre `opencode_models_cache_path()` publique** — source de vérité unique du chemin hôte, **ne pas re-dériver** le chemin dans le seed.
|
||||
- **`seed_opencode_models_cache(fs, isolated_cache_dir)`** (fonction partagée) : lit le cache hôte via `opencode_models_cache_path()`, copie best-effort vers `<isolated_cache_dir>/opencode/models.json`. Appelée aux **deux** sites après le `create_dir_all` du cache dans `apply_mcp_config` (branche commune `opencode`/`opencodeProvider`).
|
||||
- **`seed_from_bytes(fs, dest, src_bytes)`** (partie pure testable) : extrait la logique d'écriture du fichier destination à partir de bytes source. C'est le seam de test unitaire.
|
||||
|
||||
### 3.2 Sites d'appel (les DEUX)
|
||||
|
||||
1. `crates/application/src/agent/lifecycle.rs` — après `create_dir_all` cache dans `apply_mcp_config`.
|
||||
2. `crates/infrastructure/src/assistant/mod.rs` — après `create_dir_all` cache dans `apply_mcp_config`.
|
||||
|
||||
### 3.3 Invariants (à respecter, à tester)
|
||||
|
||||
- **Isolation préservée en écriture** : le seed ne fait que copier une donnée read-only **vers** le cache isolé. Jamais de `XDG_CACHE_HOME` pointé vers l'hôte.
|
||||
- **Best-effort** : le seed **n'échoue jamais le launch**. Toute erreur (fichier hôte absent, IO) est tracée (warn/log) et ignorée — on retombe sur le comportement actuel (fallback glm-5.2), pas sur un crash.
|
||||
- **Pas de régression** : profils local (llama.cpp), custom et built-ins (anthropic/openai/openrouter) doivent continuer à fonctionner byte-identique au rendu `opencode.json` actuel.
|
||||
- **Exclusion mutuelle #97 non touchée** : le seed s'exécute sur la branche commune `opencode`/`opencodeProvider`, sans affecter la logique d'exclusion.
|
||||
- **Cohérence picker↔spawn** : le catalogue vu côté UI (picker) et celui seedé au spawn proviennent du même fichier hôte → l'utilisateur ne peut pas picker un modèle qu'OpenCode ne connaîtra pas au spawn.
|
||||
|
||||
### 3.4 Hors périmètre (explicitement exclu)
|
||||
|
||||
- Remote SSH/WSL (le seed ne concerne que le spawn local).
|
||||
- Déduplication du rendu lifecycle↔infra au-delà du seed (la dette du writer `opencode_provider_config_json` reste ouverte — autre lot).
|
||||
- UI wizard (aucun changement surface).
|
||||
|
||||
## 4. Périmètre QA — 2 couches
|
||||
|
||||
### Couche 1 — Unitaire pure (obligatoire, rapide, déterministe)
|
||||
- **`seed_from_bytes`** : assert écriture byte-identique du contenu source vers `dest`, gestion erreurs (fs en échec → pas de panic), idempotence.
|
||||
- **Non-régression rendu `opencode.json`** : les tests existants `lifecycle.rs:4439-4440` et équivalents infra doivent rester **byte-identiques** pour local/custom/built-ins (le seed ne change pas le rendu config). Mettre à jour l'assert si et seulement si B2 modifie réellement le rendu — sinon la conserver telle quelle.
|
||||
|
||||
### Couche 2 — Intégration gated (obligatoire avant fermeture du lot)
|
||||
- **Spawn réel OpenCode** sur profil `zai` + modèle X choisi.
|
||||
- **Assert** : OpenCode démarre sur le modèle X (pas de fallback `glm-5.2`).
|
||||
- Vérifier dans les background-tasks/IO qu'aucune trace `glm-5.2` n'apparaît comme modèle actif.
|
||||
- **Gate obligatoire à lever** : OpenCode **refresh/écrase-t-il le cache `models.json` au démarrage** ? → si **oui**, le seed est inutile (écrasé avant lecture) et **il faut escalader vers A-étendue** (persistir npm/baseURL/models côté domaine). Consigner le verdict dans le rapport QA.
|
||||
|
||||
## 5. Risque résiduel — refresh models.dev par OpenCode
|
||||
|
||||
**Risque ouvert, à trancher en QA couche 2.** Si OpenCode rafraîchit/écrase `<xdg_cache>/opencode/models.json` au démarrage (network call ou réécriture locale), le seed B2 est potentiellement **inopérant** :
|
||||
- Meilleur cas : OpenCode lit le cache avant tout refresh → B2 fonctionne.
|
||||
- Cas dégradé : OpenCode refresh en premier, écrase le seed, et comme le profil est isolé (pas d'accès réseau garanti / HOME isolé), le refresh peut échouer ou produire un cache incomplet → bug persiste.
|
||||
- **Plan de contournement si échec** : escalader vers A-étendue (ajouter `npm`+`base_url`+`models` persistés côté `OpenCodeProviderConfig` + émettre le bloc complet au spawn). Ce plan est documenté mais **hors scope B2** — il ferait l'objet d'un lot suivant si QA le confirme nécessaire.
|
||||
|
||||
---
|
||||
|
||||
## Contexte de mise à jour
|
||||
|
||||
- Cadrage figé par Main sur validation Architect (approche B2).
|
||||
- Version précédente (v1) : phase d'arbitrage A/B/C — clos.
|
||||
- Prochaine étape cycle : Git (branche) → DevBackend (implémentation 2 sites + factorisation) → QA (2 couches, gate refresh).
|
||||
38
.ideai/tickets/98/issue.md
Normal file
38
.ideai/tickets/98/issue.md
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
id: "9db40467-a826-4dac-a679-e7934cbdda81"
|
||||
number: 98
|
||||
title: "Profil cloud provider catalogue (ex: zai) : modèle choisi écrasé par glm-5.2 au spawn"
|
||||
status: "closed"
|
||||
priority: "high"
|
||||
sprint: null
|
||||
links: []
|
||||
agentRefs: []
|
||||
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedBy: {"kind":"user"}
|
||||
createdAt: 1784966899811
|
||||
updatedAt: 1784983186248
|
||||
version: 5
|
||||
---
|
||||
## Symptôme
|
||||
|
||||
Dans le wizard de création de profil AI OpenCode (first-run), quand l'utilisateur choisit un cloud provider du catalogue (ex: **zai / ZAI Code**) puis sélectionne un modèle spécifique, **après sauvegarde l'agent tourne en `glm-5.2`** quel que soit le modèle choisi.
|
||||
|
||||
## Périmètre
|
||||
|
||||
Bug **backend** (couche application/infrastructure du spawn OpenCode). Suite logique et distincte du ticket #97 (qui réglait l'exclusion mutuelle `opencode` vs `opencodeProvider` — désormais fixée).
|
||||
|
||||
## Cause racine (diagnostiquée, à confirmer par Architect)
|
||||
|
||||
- La persistance est **correcte** : `profiles.json` conserve bien `opencodeProvider.model` = modèle choisi. `glm-5.2` est **absent de tout le code IdeA** ; c'est le **fallback interne de la CLI OpenCode** quand elle ne sait pas résoudre le modèle demandé.
|
||||
- Le modèle est perdu **au spawn** :
|
||||
1. IdeA écrit `opencode.json` avec `model: "zai/<choix>"` mais **sans bloc `models`** pour les providers catalogue connus (`crates/application/src/agent/lifecycle.rs:2796-2821`, `crates/infrastructure/src/assistant/mod.rs:447-466`). Elle suppose OpenCode built-in.
|
||||
2. Or `zai` n'est connu d'OpenCode **que** via son cache models.dev, et IdeA **isole `XDG_CACHE_HOME` vide** au spawn (`lifecycle.rs:2386,2405` ; `assistant/mod.rs:272,282`). → OpenCode ne résout ni `zai` ni le modèle → fallback silencieux `glm-5.2`.
|
||||
- Pourquoi ça marche en local (llama.cpp) et custom : ils émettent un bloc `models` (`assistant/mod.rs:371-379`, `:457-460`).
|
||||
|
||||
## Exemples impactés
|
||||
|
||||
Tout provider cloud **connu uniquement via le cache models.dev** (zai, et vraisemblablement tout provider non built-in dans OpenCode). Les providers hardcodés dans OpenCode (anthropic, openai, openrouter) fonctionnent malgré l'absence de bloc `models`.
|
||||
|
||||
## Lié à
|
||||
|
||||
- **#97** (relatesTo) : exclusion mutuelle provider — prérequis déjà livré.
|
||||
128
.ideai/tickets/99/carnet.md
Normal file
128
.ideai/tickets/99/carnet.md
Normal file
@ -0,0 +1,128 @@
|
||||
---
|
||||
issueRef: "#99"
|
||||
version: 1
|
||||
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedAt: 1784987973464
|
||||
---
|
||||
# Carnet #99 — Cadrage (prêt pour le cycle)
|
||||
|
||||
> Cadrage établi par Main après investigation code + **vérification empirique des binaires
|
||||
> installés** (`codex-cli 0.145.0`, `Claude Code 2.1.220`). Les faits CLI ci-dessous sont
|
||||
> **capitalisés et vérifiés** ; ils conditionnent toute l'architecture. Architect doit valider
|
||||
> les ports/VO et les questions ouvertes (§6) avant l'implémentation.
|
||||
|
||||
---
|
||||
|
||||
## 1. État des lieux vérifié — comparaison des 3 moteurs
|
||||
|
||||
| Moteur | Modèle contrôlé par IdeA ? | Mécanisme | Source |
|
||||
|---|---|---|---|
|
||||
| **OpenCode** | ✅ Oui | `model` écrit à la racine du `opencode.json` isolé (`OPENCODE_CONFIG`), lu par la session structured | `lifecycle.rs:2686-2689`, `2786-2788` |
|
||||
| **Codex** | ❌ Non | aucun `--model`, `codex_config_toml` n'écrit pas `model` → défaut du binaire | `codex.rs:215-239`, `lifecycle.rs:2941-2955` |
|
||||
| **Claude** | ❌ Non | aucun `--model`, `claude_settings_seed` n'écrit pas `model` → défaut du binaire | `claude.rs:273-284`, `infrastructure/permission/claude.rs:59` |
|
||||
|
||||
PTY et headless sont **deux processus OS séparés** pour un même agent
|
||||
(`allow_structured_alongside_pty: true`, `lifecycle.rs:1512-1517`) ; ils partagent le même
|
||||
`CODEX_HOME`/cwd mais **aucun état modèle** n'est synchronisé entre eux côté IdeA. Le `/model`
|
||||
de la TUI ne sort jamais du process TUI (pass-through brut, `terminal/usecases.rs:140`).
|
||||
|
||||
## 2. Faits CLI vérifiés (capitalisation) — la clé qui débloque tout
|
||||
|
||||
### Codex 0.145.0 — `model` est une clé config.toml **documentée**
|
||||
- L'exemple littéral du `--help` est `-c model="o3"`. `config.toml` est chargé depuis
|
||||
`$CODEX_HOME/config.toml`.
|
||||
- **Honorée par `codex` (TUI) ET `codex exec` (headless)** — même mécanisme de base
|
||||
(`--ignore-user-config` confirme qu'il est chargé par défaut).
|
||||
- Bonus : `codex exec` accepte aussi `-m, --model <MODEL>` (seconde porte d'injection).
|
||||
- **→ Écrire `model = "..."` dans le `$CODEX_HOME/config.toml` isolé fixe le défaut pour les
|
||||
DEUX canaux.**
|
||||
|
||||
### Claude 2.1.220 — `model` est gérable via settings + flag
|
||||
- `--model <model>` fonctionne en interactif **et** `-p/--print` (headless).
|
||||
- `--settings <file-or-json>` + la hiérarchie `./.claude/settings.local.json` (project-local)
|
||||
supportent une clé `model`.
|
||||
- **→ Écrire `"model": "..."` dans le `.claude/settings.local.json` du run dir fixe le défaut
|
||||
pour les DEUX canaux** (cwd = run dir, lu par PTY et headless).
|
||||
|
||||
### Conclusion d'architecture
|
||||
Les trois moteurs convergent vers **le même pattern** : écrire le modèle du profil dans le
|
||||
**fichier de config isolé du run dir**. Le fichier partagé = point de vérité unique pour
|
||||
headless + TUI au lancement. L'exigence produit « modèle par défaut = modèle headless = modèle
|
||||
exposé TUI au lancement » est satisfaite **par construction**, sans sync à coder.
|
||||
|
||||
## 3. Points d'intégration IdeA précis (avec chemins)
|
||||
|
||||
| Moteur | Renderer à modifier | Fichier produit | Ownership | Isolation |
|
||||
|---|---|---|---|---|
|
||||
| **Codex** | `codex_config_toml` (`application/agent/lifecycle.rs:2941-2955`) | `$CODEX_HOME/config.toml` | `MergeToml` (préservé aux régénérations) | `CODEX_HOME={runDir}/.codex` déjà isolé (`lifecycle.rs:2361`) |
|
||||
| **Claude** | `claude_settings_seed` (`infrastructure/src/permission/claude.rs:59`) | `{runDir}/.claude/settings.local.json` | `Replace` (régénéré du profil à chaque lancement) | cwd=run dir ; pas d'iso home mais **project-local override user** → le modèle IdeA gagne |
|
||||
|
||||
Champ existant à consommer ou déprécier : **`AgentProfile.model: Option<String>`**
|
||||
(`domain/src/profile.rs:1008`) — actuellement code mort. Référence OpenCode à répliquer :
|
||||
`OpenCodeProviderConfig { provider_id, model, api_key_ref }` (`domain/src/profile.rs:372-391`)
|
||||
+ `SaveOpenCodeProviderProfile` (`application/agent/usecases.rs`).
|
||||
|
||||
## 4. Architecture proposée — découpage en lots
|
||||
|
||||
- **A. Domaine** — Nouveaux VO miroir d'`OpenCodeProviderConfig` :
|
||||
`CodexProviderConfig { provider, model, api_key_ref }` et `ClaudeProviderConfig { provider,
|
||||
model, api_key_ref }`. Rendre les backends mutuellement exclusifs par moteur (cf.
|
||||
`opencode_backend_is_consistent`, `domain/src/profile.rs:363-364,1224`). **Décision
|
||||
Architect** : nouveau VO vs réutiliser `AgentProfile.model` (voir §6).
|
||||
- **B. Renderers de config** — `codex_config_toml` écrit `model` (+ `model_provider` si requis
|
||||
par la sémantique codex) ; `claude_settings_seed` écrit la clé `model`.
|
||||
- **C. Use cases / persistance** — `SaveCodexProviderProfile` / `SaveClaudeProviderProfile`
|
||||
miroirs de `SaveOpenCodeProviderProfile`, même SecretRef pour la clé scellée.
|
||||
- **D. UI / wizard** — duplication de profils Codex/Claude comme OpenCode (catalogue providers,
|
||||
sélection modèle, clé scellée). Réutiliser `provider_catalogue` + picker existants.
|
||||
- **E. QA** — assert headless + TUI utilisent le modèle du profil (voir §5).
|
||||
|
||||
## 5. Invariants (à respecter, à tester)
|
||||
|
||||
- **Source de vérité unique** : le modèle vient du profil AI, écrit dans le fichier de config
|
||||
isolé du run dir, lu par headless **et** TUI au lancement.
|
||||
- **Isolation préservée** : Codex via `CODEX_HOME` (rien ne change) ; Claude via project-local
|
||||
override (rien ne change). Pas d'accès au home global pour le modèle.
|
||||
- **`/model` en cours de session TUI ne corrompt pas le headless** (acceptable : ne concerne que
|
||||
le process PTY en cours ; le prochain lancement réapplique le défaut du profil).
|
||||
- **Non-régression OpenCode** : rendu `opencode.json` byte-identique (rien ne touche ce chemin).
|
||||
- **Non-régression permissions** : `codex_config_toml` et `claude_settings_seed` continuent
|
||||
d'écrire `mcp`/`sandbox`/`trust`/`approval` comme aujourd'hui (le `model` s'ajoute).
|
||||
|
||||
## 6. Questions ouvertes pour Architect (à trancher avant DevBackend)
|
||||
|
||||
1. **VO** : créer `CodexProviderConfig`/`ClaudeProviderConfig` (homogène à OpenCode) **ou**
|
||||
consommer le champ existant `AgentProfile.model` (code mort) ? Recommandation Main : nouveaux
|
||||
VO pour rester isomorphe à OpenCode (provider + clé scellée), déprécier `AgentProfile.model`.
|
||||
2. **Codex `model_provider`** : la config codex distingue `model` et `model_provider`. Faut-il
|
||||
exposer les deux au profil, ou `model` seul suffit (provider implicite) ?
|
||||
3. **Claude** : clé `model` dans `settings.local.json` suffit, ou faut-il gérer aussi la clé
|
||||
API Anthropic du profil (SecretRef) pour que le modèle soit réellement joignable ?
|
||||
4. **Catalogue providers** : quels providers exposer pour Codex (lié OpenAI) et Claude
|
||||
(Anthropic) ? Réutiliser `provider_catalogue.rs` ou catalogue dédié par moteur ?
|
||||
5. **Sémantique TUI** : confirmer qu'aucune CLI n'écrase `config.toml`/`settings` au démarrage
|
||||
(risque équivalent au « gate refresh » du ticket #98 côté OpenCode).
|
||||
|
||||
## 7. Périmètre QA — 2 couches (cf. méthodologie #98)
|
||||
|
||||
- **Couche 1 (unitaire pure)** : le rendu `codex_config_toml` contient la clé `model`
|
||||
attendue ; `claude_settings_seed` contient `"model"` attendue ; non-régression
|
||||
byte-identique du reste (mcp/sandbox/trust/approval) ; exclusion mutuelle des backends.
|
||||
- **Couche 2 (intégration gated)** : spawn réel `codex exec` et `claude -p` sur un profil avec
|
||||
modèle X → assert le modèle actif est X (pas le défaut binaire). Vérifier côté TUI aussi
|
||||
(modèle exposé au lancement). **Gate §6.5** à lever.
|
||||
|
||||
## 8. Hors périmètre (exclu de ce ticket)
|
||||
|
||||
- Override **runtime** du modèle à l'appel (`idea_ask_agent` porterait un modèle) — autre lot.
|
||||
- Providers distants SSH/WSL (ne concerne que le spawn local).
|
||||
- Détail de la `provider_catalogue` au-delà de la réutilisation (fast-follow).
|
||||
|
||||
---
|
||||
|
||||
## Contexte de mise à jour
|
||||
|
||||
- Cadrage Main après vérification empirique CLI (codex 0.145.0, claude 2.1.220).
|
||||
- Lié à #98 (relatesTo) — même famille « modèle au spawn ».
|
||||
- Prochaine étape cycle : **Architect** (valide ports/VO + tranche §6) → **Git** (branche) →
|
||||
**DevBackend** (lots A-C) + **DevFrontend** (lot D) → **QA** (2 couches) → **Git** (commit).
|
||||
53
.ideai/tickets/99/issue.md
Normal file
53
.ideai/tickets/99/issue.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
id: "45733f3f-5ef5-4f33-96e7-25afddcd1ce6"
|
||||
number: 99
|
||||
title: "Modèle par agent contrôlable pour Codex & Claude (headless + TUI) — égaler le pattern OpenCode"
|
||||
status: "open"
|
||||
priority: "high"
|
||||
sprint: null
|
||||
links: [{"target":"#98","kind":"relatesTo"}]
|
||||
agentRefs: []
|
||||
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
createdAt: 1784987973464
|
||||
updatedAt: 1784987973464
|
||||
version: 1
|
||||
---
|
||||
## Problème
|
||||
|
||||
Aujourd'hui IdeA **ne contrôle pas le modèle** pour les moteurs **Codex** et **Claude** :
|
||||
le modèle utilisé par le headless inter-agent (`codex exec` / `claude -p`) **et** par la TUI
|
||||
interactive est le **défaut du binaire CLI installé**, indépendamment du profil AI de l'agent.
|
||||
|
||||
- Aucun flag `--model` n'est passé au spawn (`codex.rs:215-239`, `claude.rs:273-284`).
|
||||
- `codex_config_toml` (`lifecycle.rs:2941-2955`) **n'écrit jamais de clé `model`**.
|
||||
- `AgentProfile.model` (`profile.rs:1008`) existe mais est du **code mort** (jamais consommé).
|
||||
- Le `/model` tapé dans la TUI ne se propage **pas** au headless : ce sont deux processus OS
|
||||
séparés (PTY vs `codex exec`/`claude -p`) avec des threads distincts. Le `CODEX_HOME`/cwd est
|
||||
partagé mais rien n'écrit le modèle sur disque côté IdeA.
|
||||
|
||||
**Contraste** : pour **OpenCode**, le modèle du profil (`OpenCodeConfig.model` /
|
||||
`OpenCodeProviderConfig.model`) **est** celui utilisé par le headless, via le `opencode.json`
|
||||
isolé pointé par `OPENCODE_CONFIG` (`lifecycle.rs:2686-2689`). Un profil IdeA = un
|
||||
(provider, modèle, clé scellée).
|
||||
|
||||
## Objectif produit
|
||||
|
||||
Qu'il existe un **modèle par défaut par agent**, défini dans le **profil AI**, qui soit :
|
||||
|
||||
1. utilisé par le **headless inter-agent** (`idea_ask_agent`) ;
|
||||
2. **exposé par la TUI au lancement** (valeur initiale du modèle dans la CLI) ;
|
||||
|
||||
pour les **trois** moteurs — OpenCode (déjà OK), Codex et Claude (à égaler).
|
||||
|
||||
## Périmètre
|
||||
|
||||
- **Backend** : nouveau VO domaine miroir d'`OpenCodeProviderConfig`, renderers de config
|
||||
écrivant le modèle, use cases de persistance.
|
||||
- **UI** : duplication / création de profils Codex et Claude comme OpenCode (catalogue de
|
||||
providers, sélection du modèle, clé scellée via SecretRef).
|
||||
|
||||
## Lié à
|
||||
|
||||
- **#98** (relatesTo) : même famille « contrôle du modèle au spawn » (côté OpenCode, résolveur
|
||||
zai/glm-5.2). Indépendant mais cohérent.
|
||||
@ -1,3 +1,3 @@
|
||||
{
|
||||
"nextNumber": 93
|
||||
"nextNumber": 104
|
||||
}
|
||||
@ -945,21 +945,137 @@
|
||||
"title": "Sur la notification de fin de tache backend, mettre plutot les deux agents en conversation",
|
||||
"status": "open",
|
||||
"priority": "medium",
|
||||
"sprint": null,
|
||||
"sprint": "5afd6780-0f76-40d7-a10f-32ee52469d74",
|
||||
"assignedAgentIds": [
|
||||
"a6ced819-b893-4213-b003-9e9dc79b9641"
|
||||
],
|
||||
"updatedAt": 1784652150003
|
||||
"updatedAt": 1784994105390
|
||||
},
|
||||
{
|
||||
"issueRef": "#92",
|
||||
"path": "92",
|
||||
"title": "Configurer OpenCode avec un provider Opencode",
|
||||
"status": "closed",
|
||||
"priority": "high",
|
||||
"sprint": null,
|
||||
"assignedAgentIds": [],
|
||||
"updatedAt": 1784993956910
|
||||
},
|
||||
{
|
||||
"issueRef": "#93",
|
||||
"path": "93",
|
||||
"title": "Agent Context : réponse finale non capturée, fragment d'appel d'outil brut renvoyé via idea_ask_agent",
|
||||
"status": "closed",
|
||||
"priority": "medium",
|
||||
"sprint": null,
|
||||
"assignedAgentIds": [],
|
||||
"updatedAt": 1784934179780
|
||||
},
|
||||
{
|
||||
"issueRef": "#94",
|
||||
"path": "94",
|
||||
"title": "Permissions OpenCode ignorées : opencode.json code en dur bash/edit=ask au lieu de projeter EffectivePermissions",
|
||||
"status": "closed",
|
||||
"priority": "high",
|
||||
"sprint": null,
|
||||
"assignedAgentIds": [],
|
||||
"updatedAt": 1784823278030
|
||||
},
|
||||
{
|
||||
"issueRef": "#95",
|
||||
"path": "95",
|
||||
"title": "Rendez-vous idea_ask_agent : timeout MCP OpenCode trop court (15s), le demandeur OpenCode ne reçoit jamais la réponse",
|
||||
"status": "closed",
|
||||
"priority": "high",
|
||||
"sprint": null,
|
||||
"assignedAgentIds": [],
|
||||
"updatedAt": 1784934174326
|
||||
},
|
||||
{
|
||||
"issueRef": "#96",
|
||||
"path": "96",
|
||||
"title": "Les assistants de ticket (tous adaptateurs) n'ont aucune résolution EffectivePermissions — permission toujours native/absente",
|
||||
"status": "open",
|
||||
"priority": "low",
|
||||
"sprint": "883534aa-7fc1-4d83-a9c0-17cac4a4eea5",
|
||||
"assignedAgentIds": [],
|
||||
"updatedAt": 1784994119004
|
||||
},
|
||||
{
|
||||
"issueRef": "#97",
|
||||
"path": "97",
|
||||
"title": "Duplication de provider lors de la création de profil AI - llamacpp ET provider cloud inclus simultanément",
|
||||
"status": "closed",
|
||||
"priority": "high",
|
||||
"sprint": null,
|
||||
"assignedAgentIds": [],
|
||||
"updatedAt": 1784915626417
|
||||
},
|
||||
{
|
||||
"issueRef": "#98",
|
||||
"path": "98",
|
||||
"title": "Profil cloud provider catalogue (ex: zai) : modèle choisi écrasé par glm-5.2 au spawn",
|
||||
"status": "closed",
|
||||
"priority": "high",
|
||||
"sprint": null,
|
||||
"assignedAgentIds": [],
|
||||
"updatedAt": 1784983186248
|
||||
},
|
||||
{
|
||||
"issueRef": "#99",
|
||||
"path": "99",
|
||||
"title": "Modèle par agent contrôlable pour Codex & Claude (headless + TUI) — égaler le pattern OpenCode",
|
||||
"status": "open",
|
||||
"priority": "high",
|
||||
"sprint": null,
|
||||
"assignedAgentIds": [],
|
||||
"updatedAt": 1784788822167
|
||||
"updatedAt": 1784987973464
|
||||
},
|
||||
{
|
||||
"issueRef": "#100",
|
||||
"path": "100",
|
||||
"title": "[Bug] Problème sur le scroll des agents OpenCode",
|
||||
"status": "open",
|
||||
"priority": "high",
|
||||
"sprint": "e28a4d53-8bd2-446a-b0ac-2a017373b8b2",
|
||||
"assignedAgentIds": [],
|
||||
"updatedAt": 1784993984569
|
||||
},
|
||||
{
|
||||
"issueRef": "#101",
|
||||
"path": "101",
|
||||
"title": "[Bug] Soucis de retour de notification sur les taches backend",
|
||||
"status": "closed",
|
||||
"priority": "critical",
|
||||
"sprint": "e28a4d53-8bd2-446a-b0ac-2a017373b8b2",
|
||||
"assignedAgentIds": [
|
||||
"a6ced819-b893-4213-b003-9e9dc79b9641"
|
||||
],
|
||||
"updatedAt": 1785011116365
|
||||
},
|
||||
{
|
||||
"issueRef": "#102",
|
||||
"path": "102",
|
||||
"title": "[Bug] Devoir resize les cellule pour afficher la TUI d'un agent",
|
||||
"status": "open",
|
||||
"priority": "medium",
|
||||
"sprint": "e28a4d53-8bd2-446a-b0ac-2a017373b8b2",
|
||||
"assignedAgentIds": [
|
||||
"a6ced819-b893-4213-b003-9e9dc79b9641"
|
||||
],
|
||||
"updatedAt": 1784993980505
|
||||
},
|
||||
{
|
||||
"issueRef": "#103",
|
||||
"path": "103",
|
||||
"title": "Exposer et piloter la permission réseau des agents/commandes dans IdeA",
|
||||
"status": "qa",
|
||||
"priority": "high",
|
||||
"sprint": null,
|
||||
"assignedAgentIds": [
|
||||
"a6ced819-b893-4213-b003-9e9dc79b9641"
|
||||
],
|
||||
"updatedAt": 1785013507979
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user