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:
@ -97,6 +97,29 @@ impl AgentBusyState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Per-agent submit configuration (ARCHITECTURE §20.3), resolved from the target
|
||||
/// agent's profile and carried to the [`InputMediator`] at bind time so it can be
|
||||
/// echoed on a [`crate::events::DomainEvent::DelegationReady`].
|
||||
///
|
||||
/// Both fields stay `Option`: the **default** (`"\r"`, ~60 ms) is applied at the
|
||||
/// point of use (the frontend write-portal), never hard-coded in the domain — the
|
||||
/// domain only transports the declared values.
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct SubmitConfig {
|
||||
/// The profile's `submit_sequence` (e.g. `"\r"`). `None` ⇒ front default.
|
||||
pub sequence: Option<String>,
|
||||
/// The profile's `submit_delay_ms`. `None` ⇒ front default (~60 ms).
|
||||
pub delay_ms: Option<u32>,
|
||||
}
|
||||
|
||||
impl SubmitConfig {
|
||||
/// Builds a submit config from the two optional profile fields.
|
||||
#[must_use]
|
||||
pub const fn new(sequence: Option<String>, delay_ms: Option<u32>) -> Self {
|
||||
Self { sequence, delay_ms }
|
||||
}
|
||||
}
|
||||
|
||||
/// The single convergence point of **all** of an agent's input (one FIFO/agent),
|
||||
/// with `enqueue` (Envoyer) and `preempt` (Interrompre) kept **distinct**, plus the
|
||||
/// busy state.
|
||||
@ -108,12 +131,14 @@ pub trait InputMediator: Send + Sync {
|
||||
/// Envoyer = enqueue: appends `ticket` to `agent`'s FIFO and returns the
|
||||
/// [`PendingReply`] to await (the mailbox reply type, reused).
|
||||
///
|
||||
/// **Delivery** (cadrage C3 §5.2): the implementation also **writes** the turn
|
||||
/// into the agent's input stream — *this* is the single, serialized write path
|
||||
/// that replaces the orchestrator's former ad-hoc PTY write. The write target is
|
||||
/// the [`PtyHandle`] previously registered with [`InputMediator::bind_handle`];
|
||||
/// without one, the enqueue still queues the ticket (forward, never reject) and
|
||||
/// the orchestrator falls back to its own delivery.
|
||||
/// **Delivery** (ARCHITECTURE §20.2/§20.3): the mediator **no longer writes the
|
||||
/// turn into the PTY** (the `\n` band-aid is gone — it never submitted in raw mode
|
||||
/// and produced a "double chat"). Instead, on the enqueue that **starts a turn**
|
||||
/// (Idle→Busy), the adapter publishes a [`crate::events::DomainEvent::DelegationReady`]
|
||||
/// carrying the task text + ticket + the target's [`SubmitConfig`]; the frontend
|
||||
/// cell (sole owner of the terminal) runs the write-portal handshake and writes the
|
||||
/// text + submit sequence through the single PTY writer. The mediator stays the
|
||||
/// authority of the FIFO/busy state and correlation only.
|
||||
fn enqueue(&self, agent: AgentId, ticket: Ticket) -> PendingReply;
|
||||
|
||||
/// Registers (or refreshes) the live input [`PtyHandle`] of `agent` so a later
|
||||
@ -134,21 +159,30 @@ pub trait InputMediator: Send + Sync {
|
||||
/// only returns `Idle` on the explicit signal or the per-turn timeout (fallback
|
||||
/// «en cas de doute → reste Busy mais la file accepte»; never a false `Idle`).
|
||||
///
|
||||
/// Default: delegates to [`InputMediator::bind_handle`], ignoring the pattern (a
|
||||
/// mediator that does not observe the output stream). The infra adapter overrides
|
||||
/// it to arm the watcher.
|
||||
/// It also records the target's [`SubmitConfig`] (ARCHITECTURE §20.3) so the
|
||||
/// adapter can echo `submit_sequence`/`submit_delay_ms` on the
|
||||
/// [`crate::events::DomainEvent::DelegationReady`] published when a turn starts.
|
||||
/// The bind is the natural carrier: both the prompt pattern and the submit config
|
||||
/// are per-agent profile data the orchestrator resolves at the same time, so they
|
||||
/// travel together (no extra ticket field, no second resolve).
|
||||
///
|
||||
/// Default: delegates to [`InputMediator::bind_handle`], ignoring the pattern and
|
||||
/// submit config (a mediator that does not observe the output stream). The infra
|
||||
/// adapter overrides it to arm the watcher and stash the submit config.
|
||||
fn bind_handle_with_prompt(
|
||||
&self,
|
||||
agent: AgentId,
|
||||
handle: PtyHandle,
|
||||
_prompt_ready_pattern: Option<String>,
|
||||
_submit: SubmitConfig,
|
||||
) {
|
||||
self.bind_handle(agent, handle);
|
||||
}
|
||||
|
||||
/// Whether this mediator owns the turn-delivery write for `agent` (i.e. it has a
|
||||
/// bound handle **and** a PTY port). When `false`, the orchestrator must deliver
|
||||
/// the turn itself. Default: `false`.
|
||||
/// **Deprecated since ARCHITECTURE §20**: the mediator never writes the turn into
|
||||
/// the PTY anymore — the **frontend** always delivers (via the write-portal). Kept
|
||||
/// for source compatibility; it now always returns `false`. Callers should stop
|
||||
/// branching on it (the orchestrator no longer falls back to its own PTY write).
|
||||
#[must_use]
|
||||
fn delivers_turn(&self, _agent: AgentId) -> bool {
|
||||
false
|
||||
|
||||
Reference in New Issue
Block a user