chore(wip): checkpoint P8/C avant chantier Codex inter-agents

Sauvegarde de l'arbre de travail en cours (persistance P8, conversations
C-series, write-portal frontend, médiation d'entrée) avant d'attaquer le
support de la délégation inter-agents pour les profils Codex.

Le round-trip inter-agent question/réponse est couvert sans tokens par
les tests loopback existants (state::mcp_e2e_loopback_tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 21:42:53 +02:00
parent 4509f0db9d
commit fdcf16c387
76 changed files with 3783 additions and 1404 deletions

View File

@ -242,6 +242,33 @@ export interface TerminalHandle {
close(): Promise<void>;
}
/**
* The write-portal contract an agent-cell terminal talks to (ARCHITECTURE §20).
* The portal owns the *human line* counter, the suspension flag (raised while it
* injects a delegation) and — once the view has a live PTY — the handle it
* writes through. The terminal view is the only effective PTY writer
* (single-writer invariant): it relays human keystrokes and the portal injects
* via the same handle, never a second physical writer.
*/
export interface WritePortal {
/**
* Reports a raw human keystroke chunk (`term.onData`) so the portal can keep
* its line counter. Called for **every** keystroke in agent mode, including
* while suspended (the portal decides what to count).
*/
onHumanData(data: string): void;
/**
* Whether the keystroke relay to the PTY is currently suspended (the portal
* is injecting a delegation). When `true`, the view drops keystrokes so they
* do not race the injected text.
*/
isSuspended(): boolean;
/** Binds the live PTY handle so the portal can inject through it. */
bindHandle(handle: TerminalHandle): void;
/** Drops the handle reference (view torn down). */
unbindHandle(): void;
}
/**
* Terminals (L3): open a PTY with a per-session output stream, then write/
* resize/close it through the returned {@link TerminalHandle}.
@ -487,22 +514,32 @@ export interface MemoryGateway {
}
/**
* 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.
* Agent input control (ARCHITECTURE §20). The mediated-input strip is gone: the
* agent cell is a **native terminal** and human keystrokes (Enter included) go
* straight to the PTY. This port only carries the two out-of-band controls:
*
* 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.
* - **Interrompre** → `interrupt` (preempt the current turn — a control byte,
* not an enqueue).
* - **Ack** → `delegationDelivered`: the cell's write-portal confirms it has
* effectively written a delegation's text into the native PTY (closes the
* "the turn was delivered" loop for observability; the `ask` wake-up still
* rides on `idea_reply`).
*
* The component talks to this gateway via DI, never to `invoke()` directly.
*/
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>;
/**
* Ack: the cell's write-portal has written the delegation `ticket` into the
* agent's native PTY (ARCHITECTURE §20.3). Best-effort; never changes the
* ticket correlation.
*/
delegationDelivered(
projectId: string,
agentId: string,
ticket: string,
): Promise<void>;
}
/**