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

@ -1,9 +1,11 @@
/**
* Tauri adapter for {@link InputGateway} (lot F1, cadrage §4.2).
* Tauri adapter for {@link InputGateway} (ARCHITECTURE §20.3).
*
* `submit` → `submit_agent_input` (enqueue), `interrupt` → `interrupt_agent`
* (preempt). These app-tauri commands land with lot C4; this adapter is complete
* on the frontend side and the mock covers tests/offline dev meanwhile.
* `interrupt` → `interrupt_agent` (preempt). `delegationDelivered` →
* `delegation_delivered` (the native write-portal's ack that a delegation's
* text was effectively written into the PTY). The former `submit` →
* `submit_agent_input` path is gone: the agent cell is a native terminal, so
* human keystrokes reach the PTY directly (no mediated-input strip).
*
* Commands use snake_case (Tauri convention); payload keys are camelCase
* (matching the backend DTO `#[serde(rename_all = "camelCase")]`), consistent
@ -15,19 +17,19 @@ import { invoke } from "@tauri-apps/api/core";
import type { InputGateway } from "@/ports";
export class TauriInputGateway implements InputGateway {
async submit(
projectId: string,
agentId: string,
text: string,
): Promise<void> {
await invoke("submit_agent_input", {
request: { projectId, agentId, text },
});
}
async interrupt(projectId: string, agentId: string): Promise<void> {
await invoke("interrupt_agent", {
request: { projectId, agentId },
});
}
async delegationDelivered(
projectId: string,
agentId: string,
ticket: string,
): Promise<void> {
await invoke("delegation_delivered", {
request: { projectId, agentId, ticket },
});
}
}

View File

@ -1533,39 +1533,38 @@ export class MockEmbedderGateway implements EmbedderGateway {
}
}
/** One recorded mediated-input call (for test assertions). */
/** One recorded agent-input control call (for test assertions). */
export interface MockInputCall {
projectId: string;
agentId: string;
/** Present for `submit`, absent for `interrupt`. */
text?: string;
/** Present for `delegationDelivered`, absent for `interrupt`. */
ticket?: string;
}
/**
* In-memory {@link InputGateway} (lot F1). Records every `submit`/`interrupt`
* so tests can assert the component routed through the port with the right
* args — no backend. `submit` always resolves (the FIFO never refuses an
* enqueue; the forward/fallback rule lives backend-side, §4.2/§6).
* In-memory {@link InputGateway} (ARCHITECTURE §20.3). Records every
* `interrupt`/`delegationDelivered` so tests can assert the component routed
* through the port with the right args — no backend.
*
* Exported so tests can instantiate it directly (same pattern as the other mocks).
*/
export class MockInputGateway implements InputGateway {
/** All recorded submit calls, in order. */
readonly submits: MockInputCall[] = [];
/** All recorded interrupt calls, in order. */
readonly interrupts: MockInputCall[] = [];
async submit(
projectId: string,
agentId: string,
text: string,
): Promise<void> {
this.submits.push({ projectId, agentId, text });
}
/** All recorded delegation-delivered acks, in order. */
readonly delivered: MockInputCall[] = [];
async interrupt(projectId: string, agentId: string): Promise<void> {
this.interrupts.push({ projectId, agentId });
}
async delegationDelivered(
projectId: string,
agentId: string,
ticket: string,
): Promise<void> {
this.delivered.push({ projectId, agentId, ticket });
}
}
/** Builds the full set of mock gateways. */