feat(agent): conversation par paire + entrée médiée + pivot terminal/MCP

Coeur inter-agents consolidé et surface front réalignée sur la décision
"terminal natif PTY, pas d'UI chat" (Option 1).

Domaine
- nouveaux modules conversation, mailbox, input, fileguard (ports + types)
- orchestrator/profile/events étendus (conversation par paire, FIFO)

Application / Infrastructure
- orchestrator/service + context_guard : sérialisation FIFO par agent,
  garde RW mémoire/contexte, dispatch ask/reply
- adapters in-memory conversation / mailbox / input / fileguard
- registry session + lifecycle agent durcis (1 agent = 1 session vivante)
- outils MCP idea_* alignés sur le nouveau dispatch

Frontend
- MediatedInput + useAgentBusy : entrée utilisateur médiée par IdeA,
  terminal = vue sortie inchangée
- suppression de la vue chat structurée (AgentChatView) — abandonnée
- adapter input + ports mis à jour

Divers
- .ideai/ : mémoire projet + briefs de cadrage versionnés ;
  requests/ runtime ignoré ; agents projet réels (DevBackend/DevFrontend/QA)

Tests : Rust (domain/application/infrastructure/app-tauri) + front (346) verts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 07:33:04 +02:00
parent 5f45c22941
commit eca2ba95c4
61 changed files with 9491 additions and 2512 deletions

View File

@ -31,7 +31,6 @@ import type {
MemoryType,
Project,
ProfileAvailability,
ReplyChunk,
ResumableAgent,
Skill,
SkillScope,
@ -166,40 +165,6 @@ 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. */
@ -257,14 +222,6 @@ 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. */
@ -529,6 +486,25 @@ export interface MemoryGateway {
): Promise<MemoryIndexEntry[]>;
}
/**
* Mediated agent input (lot F1, cadrage §4.2). All human input to an *agent*
* cell flows through this port instead of being written straight to the PTY:
* "Envoyer" enqueues a task in the agent's single FIFO (`submit`), "Interrompre"
* preempts the current turn (`interrupt`). The component talks to this gateway,
* never to `invoke()` directly.
*
* Note (forward/fallback, §4.2/§6): `submit` must never be blocked client-side
* when the agent is busy — the UI may *disable the button visually* but the
* enqueue path stays available; the backend FIFO is the single point that
* serialises. So callers may still call `submit` while busy.
*/
export interface InputGateway {
/** Envoyer = enqueue: appends `text` to the agent's input FIFO. */
submit(projectId: string, agentId: string, text: string): Promise<void>;
/** Interrompre = preempt: signals the current turn to stop (not an enqueue). */
interrupt(projectId: string, agentId: string): Promise<void>;
}
/**
* AI profiles & first-run (L5). Drives the first-run wizard and profile
* management: the pre-filled reference catalogue, detection of installed CLIs,
@ -581,6 +557,7 @@ export interface EmbedderGateway {
export interface Gateways {
system: SystemGateway;
agent: AgentGateway;
input: InputGateway;
terminal: TerminalGateway;
project: ProjectGateway;
layout: LayoutGateway;