feat(mcp,orchestrator,frontend): tool idea_restart_self, redemarrage autonome d'un agent — #288 (tool core self-only via requester MCP handshake, retour immediat {restartId, status: scheduled} puis orchestration detachee: snapshot reprise, stop PTY/structured, liberation Busy/mailbox, relance LaunchAgent meme conversation_id fresh_start=false, injection interne invisible; events domain/wire agentRestartRequested/PhaseChanged/Completed/Failed phases stopping/releasingInput/launching/resuming; CLI custom: separateurs exacts redemarrage de l'agent + etat termine/echoue, deduplication (restartId, event), verrouillage composer; TUI native: overlay AgentRestartOverlay sans injection xterm, progress/annonces projetes jusqu'a idle; QA verte: mcp_server restart_self 1/1, restart-self 3/3, backend self_restart_contract + events wire 2/2, frontend 3 suites 92/92, npm build, cargo check --workspace, fmt --check, diff --check; reserves hors perimetre: web-server 103/110 fixture PTY preexistante, 34 echecs npm test globaux listProjectSettings/web hors #288; scripts/ hors perimetre)
This commit is contained in:
@ -49,6 +49,42 @@ pub enum OrchestrationSource {
|
||||
/// channel rather than serialised here.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum DomainEvent {
|
||||
/// An agent requested a self-restart through its MCP handshake identity.
|
||||
AgentRestartRequested {
|
||||
/// Agent authenticated by the MCP handshake.
|
||||
agent_id: AgentId,
|
||||
/// Correlation id shared by all events in this restart.
|
||||
restart_id: String,
|
||||
/// Optional model-provided diagnostic reason.
|
||||
reason: Option<String>,
|
||||
},
|
||||
/// A scheduled self-restart moved to another runtime phase.
|
||||
AgentRestartPhaseChanged {
|
||||
/// Restarting agent.
|
||||
agent_id: AgentId,
|
||||
/// Restart correlation id.
|
||||
restart_id: String,
|
||||
/// Newly entered phase.
|
||||
phase: AgentRestartPhase,
|
||||
},
|
||||
/// A self-restart relaunched the agent and submitted its internal resume turn.
|
||||
AgentRestartCompleted {
|
||||
/// Restarted agent.
|
||||
agent_id: AgentId,
|
||||
/// Restart correlation id.
|
||||
restart_id: String,
|
||||
},
|
||||
/// A self-restart failed after it had already been acknowledged as scheduled.
|
||||
AgentRestartFailed {
|
||||
/// Agent whose restart failed.
|
||||
agent_id: AgentId,
|
||||
/// Restart correlation id.
|
||||
restart_id: String,
|
||||
/// Phase that failed.
|
||||
phase: AgentRestartPhase,
|
||||
/// Human-readable failure safe to expose in the UI.
|
||||
message: String,
|
||||
},
|
||||
/// A project was created.
|
||||
ProjectCreated {
|
||||
/// The new project.
|
||||
@ -667,6 +703,19 @@ pub enum DomainEvent {
|
||||
},
|
||||
}
|
||||
|
||||
/// Stable phases exposed by the agent self-restart event stream.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AgentRestartPhase {
|
||||
/// Existing runtime teardown.
|
||||
Stopping,
|
||||
/// Busy state and mailbox cleanup.
|
||||
ReleasingInput,
|
||||
/// Activation through `LaunchAgent`.
|
||||
Launching,
|
||||
/// Submission of the internal continuation turn.
|
||||
Resuming,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@ -260,6 +260,13 @@ pub struct OrchestratorRequest {
|
||||
/// proof the request was well-formed (Parse, don't validate).
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum OrchestratorCommand {
|
||||
/// Schedule a restart of the MCP requester itself.
|
||||
RestartSelf {
|
||||
/// Requesting agent, strictly parsed from the MCP handshake identity.
|
||||
agent: AgentId,
|
||||
/// Optional diagnostic reason. It is never used as an identity or target.
|
||||
reason: Option<String>,
|
||||
},
|
||||
/// Create the agent if unknown (with `profile` + optional initial context),
|
||||
/// then launch it — exactly as the UI would.
|
||||
SpawnAgent {
|
||||
@ -476,6 +483,15 @@ impl OrchestratorRequest {
|
||||
pub fn validate(&self) -> Result<OrchestratorCommand, OrchestratorError> {
|
||||
let action = self.action_name()?;
|
||||
match action {
|
||||
"agent.restart_self" => Ok(OrchestratorCommand::RestartSelf {
|
||||
agent: self.require_from(action)?,
|
||||
reason: self
|
||||
.task
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(str::to_owned),
|
||||
}),
|
||||
"spawn_agent" => Ok(OrchestratorCommand::SpawnAgent {
|
||||
name: self.require_name(action)?,
|
||||
profile: Some(self.require("profile", action, self.profile.as_deref())?),
|
||||
|
||||
Reference in New Issue
Block a user