feat(agent): orchestration v3 — surface MCP model-agnostic (M0→M4) — §14.3
Expose l'orchestration IdeA comme serveur MCP par-dessus le même OrchestratorService::dispatch, avec repli fichier .ideai/requests pour les CLI sans MCP. v3 réduite à la surface MCP : la messagerie inter-agents et la corrélation requête↔réponse étaient déjà résolues par §17 (send_blocking). - M0 capacité MCP sur le profil (McpCapability/McpConfigStrategy/McpTransport) - M1 injection conf MCP au LaunchAgent + prose adaptée selon la surface - M2 serveur/adapter MCP (JSON-RPC 2.0 maison ; outils idea_*) + ListAgents - M3 câblage par projet (registre mcp_servers jumeau du watcher) - M4 observabilité UI : OrchestratorRequestProcessed.source = file|mcp + badge Trois portes d'entrée (fichier, MCP, UI) → un seul dispatch ; aucun nouveau port applicatif ; MCP confiné à l'adapter infra. Tous lots verts (cycle §3). Cadrage : .ideai/briefs/orchestration-v3-cadrage.md ; ARCHITECTURE.md §14.3. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -147,6 +147,7 @@ impl OrchestratorService {
|
||||
OrchestratorCommand::AskAgent { target, task } => {
|
||||
self.ask_agent(project, target, task).await
|
||||
}
|
||||
OrchestratorCommand::ListAgents => self.list_agents(project).await,
|
||||
OrchestratorCommand::StopAgent { name } => self.stop_agent(project, name).await,
|
||||
OrchestratorCommand::UpdateAgentContext { name, context } => {
|
||||
self.update_agent_context(project, name, context).await
|
||||
@ -355,6 +356,35 @@ impl OrchestratorService {
|
||||
}
|
||||
}
|
||||
|
||||
/// `list_agents`: discovery — return the project's agents exactly as the UI
|
||||
/// reads them from the manifest, via the **same** [`ListAgents`] use case.
|
||||
///
|
||||
/// The list is serialised as a JSON array into [`OrchestratorOutcome::reply`]
|
||||
/// (the existing inline-payload channel, also used by `ask`), with a one-line
|
||||
/// count in [`OrchestratorOutcome::detail`]. Each element carries the agent's
|
||||
/// `id`, `name`, `contextPath`, `profileId`, `origin`, `synchronized` and
|
||||
/// `skills` (camelCase, the [`domain::Agent`] serde shape).
|
||||
///
|
||||
/// # Errors
|
||||
/// Propagates [`AppError`] from the use case (manifest load / invariant) or a
|
||||
/// serialisation failure ([`AppError::Invalid`]).
|
||||
async fn list_agents(&self, project: &Project) -> Result<OrchestratorOutcome, AppError> {
|
||||
let listed = self
|
||||
.list_agents
|
||||
.execute(ListAgentsInput {
|
||||
project: project.clone(),
|
||||
})
|
||||
.await?;
|
||||
|
||||
let reply = serde_json::to_string(&listed.agents)
|
||||
.map_err(|e| AppError::Invalid(format!("failed to serialise agent list: {e}")))?;
|
||||
|
||||
Ok(OrchestratorOutcome {
|
||||
detail: format!("listed {} agent(s)", listed.agents.len()),
|
||||
reply: Some(reply),
|
||||
})
|
||||
}
|
||||
|
||||
/// `stop_agent`: translate the agent name → its live session → `CloseTerminal`.
|
||||
async fn stop_agent(
|
||||
&self,
|
||||
|
||||
Reference in New Issue
Block a user