Expose l'exécution structurée à l'UI (jumeau du chemin PTY) :
- ChatBridge (chat.rs) : pompe ReplyStream -> Channel<ReplyChunk>,
generation-tracked (anti-double-pompe) ; scrollback de conversation
côté transport (le port AgentSession est sans mémoire), purgé à la
fermeture, préservé à la ré-attache.
- Commandes agent_send / reattach_agent_chat / close_agent_session.
- DTO : ReplyChunk (textDelta/toolActivity/final, camelCase tagué kind),
ReattachChatDto, CellKind {pty,chat} + champ cellKind dérivé sur
TerminalSessionDto (chat ssi LaunchAgentOutput.structured = Some).
- Wiring composition root : StructuredSessions + ChatBridge dans AppState,
via la factory déjà injectée (aucun new d'adapter — règle D §17.8).
- From<AgentSessionError> for AppError (mappe sur PROCESS).
Tests (QA) : 35 unitaires verts — generation supersede validé par mutation
test, séquence deltas*+Final, reattach sans re-spawn, teardown shutdown+
unregister, DTO cellKind + round-trip ReplyChunk, non-régression PTY.
cargo test --workspace : 803 passed, 0 failed.
Reste D5 : AgentChatView (frontend) + routage cellKind dans LayoutGrid.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
89 lines
5.2 KiB
Markdown
89 lines
5.2 KiB
Markdown
# Brief Dev — Lot D4 : commandes Tauri + bridge chat (§17.9)
|
|
|
|
> Demandé par **Main** à **DevBackend** (dev) + **QA** (test). Cycle §3 : code → tests → vert.
|
|
> Périmètre **backend uniquement** (`app-tauri`). Le frontend chat est D5, hors périmètre ici.
|
|
|
|
## 0. Où on en est
|
|
|
|
Le fil §17 (exécution structurée des agents IA via le port `AgentSession`) est livré
|
|
jusqu'à **D3 inclus** :
|
|
|
|
- **D0/D1** (`5e10b5e`) : port `domain::ports::AgentSession` + `AgentSessionFactory`,
|
|
`ReplyEvent`/`ReplyStream`/`AgentSessionError`, champ `AgentProfile.structured_adapter`,
|
|
registre `StructuredSessions`, agrégateur `LiveSessions`, helper `send_blocking`.
|
|
- **D2** (`751d94d`) + spikes **S1/S2** (`f104862`) : adapters `ClaudeSdkSession` /
|
|
`CodexExecSession` dans `crates/infrastructure/src/session/`, fake CLI + harnais de
|
|
conformité, **formats réels** Claude `stream-json` / Codex `exec --json` câblés.
|
|
- **D3** (`56913b9`) : `LaunchAgent` route structuré vs PTY ; `LaunchAgentOutput` porte
|
|
désormais `structured: Option<StructuredSessionDescriptor>`.
|
|
|
|
**D4 = exposer tout ça à l'UI** : commandes Tauri + pont de streaming, jumeau exact du
|
|
chemin PTY existant. Aucun chemin PTY (terminal non-IA) ne doit changer ni régresser.
|
|
|
|
## 1. Périmètre D4 (réf. §17.7 et tableau §17.9)
|
|
|
|
À livrer dans `crates/app-tauri/src/` :
|
|
|
|
1. **`ChatBridge`** — jumeau de `PtyBridge` (`crates/app-tauri/src/pty.rs`), **generation-tracked**
|
|
(même mécanique de génération pour éviter la double-pompe lors d'une ré-attache). Il pompe
|
|
un `ReplyStream` (events `ReplyEvent` du port) vers un `tauri::ipc::Channel`, en émettant
|
|
des `ReplyChunk` (DTO ci-dessous). Vit à côté de `PtyBridge`, ne le remplace pas.
|
|
2. **Commandes Tauri** :
|
|
- `agent_send(sessionId, prompt)` → pompe les `ReplyEvent` du tour sur le `Channel`
|
|
(deltas `TextDelta` → chunks, `ToolActivity` → chunks d'activité, `Final` → chunk final
|
|
qui fige le tour). S'appuie sur le registre `StructuredSessions` / `send_blocking` côté
|
|
application (déjà livré en D1).
|
|
- `reattach_agent_chat(...)` → renvoie le scrollback de conversation + rebranche le `Channel`
|
|
(repeint sans re-spawn ; supersede l'ancienne génération).
|
|
- `close_agent_session(sessionId)` → `shutdown` (polymorphe) + unregister du registre.
|
|
3. **DTO** (`crates/app-tauri/src/dto.rs`) :
|
|
- `ReplyChunk` : variantes delta texte / activité outil / final (sérialisation camelCase,
|
|
cohérente avec les DTO existants).
|
|
- `ReattachChatDto`.
|
|
- **`cellKind`** ajouté au DTO de session (terminal `pty` vs chat `chat`), dérivé de la
|
|
présence d'un descripteur structuré (`LaunchAgentOutput.structured`).
|
|
4. **Wiring composition root** (`state.rs`/`lib.rs`) : injecter les dépendances nécessaires,
|
|
enregistrer les nouvelles commandes. **Aucun `new ClaudeSdkSession` ici** — passe par la
|
|
factory déjà injectée (règle D du §17.8).
|
|
|
|
## 2. Contrat / invariants à respecter
|
|
|
|
- **Generation supersede** : une ré-attache invalide l'ancienne pompe ; pas de double émission.
|
|
- **`cellKind`** est la seule info dont D5 (frontend) a besoin pour router cellule chat vs
|
|
terminal. Stable et explicite au DTO.
|
|
- **Isolation parsing** : D4 ne parse aucun format CLI — il consomme des `ReplyEvent` typés.
|
|
- **Zéro régression PTY** : le chemin terminal brut (`PtyBridge`, commandes terminal) reste
|
|
identique. Les tests PTY existants restent verts.
|
|
- Frontières hexagonales (§17.8) : `app-tauri` dépend des ports/registres application, jamais
|
|
des adapters infra concrets.
|
|
|
|
## 3. Tests attendus (QA — réf. colonne « Tests attendus » D4 du §17.9)
|
|
|
|
Crate `app-tauri` (fakes pour la session structurée, pas de vrai CLI) :
|
|
|
|
- `agent_send` pompe les events d'un tour sur le `Channel` (séquence deltas… puis `Final`).
|
|
- ré-attache → scrollback conversation repeint, **sans** re-spawn de session.
|
|
- `close_agent_session` → `shutdown` appelé **et** unregister du registre.
|
|
- **generation supersede** : après ré-attache, l'ancienne génération ne pompe plus (pas de
|
|
double émission sur le `Channel`).
|
|
- DTO : `cellKind` = `chat` pour une sortie `LaunchAgentOutput` avec `structured: Some(..)`,
|
|
`pty` sinon ; round-trip `ReplyChunk` (camelCase).
|
|
- non-régression : un DTO de session PTY existant sérialise toujours pareil (le nouveau champ
|
|
`cellKind` ne casse pas les snapshots — vérifier la valeur par défaut/dérivée).
|
|
|
|
## 4. Méthode
|
|
|
|
Cycle §3 strict : DevBackend code → QA écrit + exécute les tests → vert avant de clore.
|
|
Rapport d'erreurs clair si rouge → correction → re-test. Commit `feat(agent): … (D4) — §17`
|
|
quand `cargo test --workspace` est vert. **Ne pas push** (validation Main requise).
|
|
|
|
## 5. Références code
|
|
|
|
- Jumeau à copier : `crates/app-tauri/src/pty.rs` (`PtyBridge`, generation tracking).
|
|
- Source du flux : `domain::ports::{AgentSession, ReplyEvent, ReplyStream}` ;
|
|
registre/`send_blocking` : `crates/application/src/agent/structured.rs`.
|
|
- Routage déjà fait : `crates/application/src/agent/lifecycle.rs`
|
|
(`LaunchAgentOutput.structured`).
|
|
- DTO existants : `crates/app-tauri/src/dto.rs` ; commandes : `crates/app-tauri/src/commands.rs`.
|
|
- Spec complète : `ARCHITECTURE.md` §17.7 (commandes & DTO) et tableau §17.9 ligne **D4**.
|