feat(agent): vue chat frontend + routage cellKind (D5) — §17

Le frontend consomme l'exécution structurée livrée en D4 :
- AgentChatView : jumeau chat de TerminalView. Accumule les textDelta du
  tour courant, badges toolActivity, fige sur final (le contenu final
  remplace les deltas, pas de double rendu). Saisie Enter/Shift+Enter.
  Au montage : reattach (rejoue le scrollback) ou launch ; au démontage :
  détache seulement (jamais de close). Vue pure pilotée par le port.
- LayoutGrid/LeafView : routage cellKind — AgentChatView si "chat",
  TerminalView sinon (chemin PTY inchangé). Cache cellKindBySession pour
  router correctement après ré-attache/navigation.
- Port AgentGateway : sendPrompt / reattachChat / closeAgentSession ;
  cellKind sur TerminalHandle. Adapter Tauri (invoke + Channel<ReplyChunk>)
  et mock (MockChatSession, _setChatAgents) étendus.
- Types TS mirrors : CellKind, ReplyChunk, ReattachChatDto + cellKind sur
  TerminalSession.

Tests (QA) : 21 Vitest verts — routage chat/pty (non-régression terminal),
accumulation/non-doublon (garde anti-always-green delta!=final), ré-attache
sans re-spawn, envoi Enter vs Shift+Enter, badges toolActivity, mock stream.
npx vitest run : 345 passed, 0 failed. npm run build vert.

Reste D6 (messagerie inter-agents via send_blocking) et D7 (menu restreint
Claude/Codex + retrait custom) pour clore §17.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 23:30:20 +02:00
parent f4d5727a69
commit 5059f37890
11 changed files with 1478 additions and 30 deletions

View File

@ -31,6 +31,7 @@ import type {
MemoryType,
Project,
ProfileAvailability,
ReplyChunk,
ResumableAgent,
Skill,
SkillScope,
@ -165,6 +166,40 @@ export interface AgentGateway {
agentId: string,
conversationId: string,
): Promise<ConversationDetails>;
/**
* Sends a prompt to a live **structured** (chat) session and streams the
* reply turn back through `onReply` (ARCHITECTURE §17.7, command `agent_send`).
* Each {@link ReplyChunk} is delivered as it arrives: `textDelta`s accumulate
* into the current turn, `toolActivity` shows tool badges, and the terminal
* `final` chunk freezes the turn. The chat twin of a PTY `write`. Resolves once
* the turn stream is wired (not when the turn completes).
*/
sendPrompt(
sessionId: string,
prompt: string,
onReply: (chunk: ReplyChunk) => void,
): Promise<void>;
/**
* Re-attaches a chat view to an **already-living** structured session without
* re-sending or re-spawning it (ARCHITECTURE §17.7, command
* `reattach_agent_chat`). Returns the retained conversation scrollback (the
* chunks already streamed) so the view repaints its prior turns; subsequent
* chunks then arrive over `onReply`. The chat twin of {@link reattach}.
*
* Rejects if no live structured session owns the id (the caller then opens
* fresh).
*/
reattachChat(
sessionId: string,
onReply: (chunk: ReplyChunk) => void,
): Promise<ReplyChunk[]>;
/**
* Shuts a live structured session down and tears its transport (channel +
* conversation scrollback) down (ARCHITECTURE §17.7, command
* `close_agent_session`). The chat twin of {@link TerminalGateway.closeTerminal};
* reserved for an explicit user action — navigation must never call this.
*/
closeAgentSession(sessionId: string): Promise<void>;
}
/** Options for opening a terminal. */
@ -222,6 +257,14 @@ export interface TerminalHandle {
* leaf so the next open resumes instead of re-assigning.
*/
readonly assignedConversationId?: string;
/**
* How the cell hosting this session should render (ARCHITECTURE §17.6).
* Present on handles returned by {@link AgentGateway.launchAgent}: `"chat"`
* routes the leaf to an `AgentChatView`, `"pty"` (the default) to a raw
* {@link TerminalView}. `undefined` on plain-terminal handles ⇒ treated as
* `"pty"`.
*/
readonly cellKind?: import("@/domain").CellKind;
/** Sends bytes (xterm keystrokes) to the PTY. */
write(data: Uint8Array): Promise<void>;
/** Resizes the PTY. */