Files
IdeA/crates/domain/src/events.rs
Blomios 37e72747d3 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>
2026-06-10 12:53:31 +02:00

173 lines
6.6 KiB
Rust

//! Domain events published on the [`crate::ports::EventBus`] and relayed to the
//! presentation layer (ARCHITECTURE §3.2).
use crate::ids::{AgentId, ProfileId, ProjectId, SessionId, SkillId, TemplateId};
use crate::memory::MemorySlug;
use crate::template::TemplateVersion;
/// Which entry door a processed orchestration request arrived through.
///
/// IdeA exposes the *same* [`crate::OrchestratorService::dispatch`] behind two
/// substitutable driving adapters (ARCHITECTURE §14.3 + cadrage `orchestration-v3`):
/// the `.ideai/requests` filesystem watcher and the MCP server. This tag — set by
/// the adapter that received the request, never inferred in the application — lets
/// the presentation layer surface *how* a delegation came in.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OrchestrationSource {
/// A JSON request file dropped under `.ideai/requests/`.
File,
/// A `tools/call` on the MCP server.
Mcp,
}
/// Events emitted by the domain/application as state changes occur.
///
/// Deliberately *not* `Serialize`/`Deserialize`: events are an in-process
/// concern relayed to IPC by an infrastructure adapter, which owns the wire
/// format. `PtyOutput` in particular is usually short-circuited to a Tauri
/// channel rather than serialised here.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DomainEvent {
/// A project was created.
ProjectCreated {
/// The new project.
project_id: ProjectId,
},
/// An agent was launched in a terminal.
AgentLaunched {
/// The agent.
agent_id: AgentId,
/// The session it runs in.
session_id: SessionId,
},
/// A target agent produced a synchronous reply to an inter-agent `ask`
/// (ARCHITECTURE §17.4): the requester sent a task via `agent.message`, IdeA
/// drove the target's structured session to its turn `Final`, and this is the
/// observability beacon for that completed rendezvous. Carries the target id and
/// the reply size (a lightweight metric); the full body is returned to the
/// requester out-of-band, not in the event payload (the bus stays I/O-free).
AgentReplied {
/// The agent that produced the reply.
agent_id: AgentId,
/// Number of bytes in the reply content (preview metric, not the payload).
reply_len: usize,
},
/// An agent's process exited.
AgentExited {
/// The agent.
agent_id: AgentId,
/// Exit code.
code: i32,
},
/// An agent's runtime profile was changed (hot-swap of the AI engine).
AgentProfileChanged {
/// The agent.
agent_id: AgentId,
/// The new runtime profile it now uses.
profile_id: ProfileId,
},
/// A template was updated (content changed, version bumped).
TemplateUpdated {
/// The template.
template_id: TemplateId,
/// New version.
version: TemplateVersion,
},
/// A synchronized agent is behind its template.
AgentDriftDetected {
/// The drifting agent.
agent_id: AgentId,
/// Version the agent is currently at.
from: TemplateVersion,
/// Version available from the template.
to: TemplateVersion,
},
/// A synchronized agent received its template update.
AgentSynced {
/// The agent.
agent_id: AgentId,
/// Version it was brought up to.
to: TemplateVersion,
},
/// A skill was assigned to (or unassigned from) an agent.
SkillAssigned {
/// The agent whose skill set changed.
agent_id: AgentId,
/// The skill involved.
skill_id: SkillId,
/// `true` if assigned, `false` if unassigned.
assigned: bool,
},
/// A tab's layout changed.
LayoutChanged {
/// The project whose layout changed.
project_id: ProjectId,
},
/// A remote host connection was established.
RemoteConnected {
/// The project on that remote.
project_id: ProjectId,
},
/// Git state for a project changed.
GitStateChanged {
/// The project.
project_id: ProjectId,
},
/// An orchestrator request (dropped under `.ideai/requests/`) was processed
/// by IdeA on behalf of a requester agent (ARCHITECTURE §14.3). Relayed so the
/// frontend can surface orchestration activity; the resulting cell/tab opens
/// off the [`AgentLaunched`](Self::AgentLaunched) event for `spawn_agent`.
OrchestratorRequestProcessed {
/// Id of the requesting (orchestrator) agent — the request subdirectory.
requester_id: String,
/// The action that was processed (`spawn_agent`, `stop_agent`, …).
action: String,
/// Whether IdeA handled it successfully.
ok: bool,
/// Which entry door the request arrived through (file watcher vs MCP),
/// tagged by the receiving adapter.
source: OrchestrationSource,
},
/// A memory note was created or updated (`.md` written, index upserted).
MemorySaved {
/// The saved note's slug.
slug: MemorySlug,
},
/// A memory note was deleted.
MemoryDeleted {
/// The deleted note's slug.
slug: MemorySlug,
},
/// The aggregated `MEMORY.md` index was rebuilt for a project.
MemoryIndexRebuilt {
/// The project whose index was rebuilt.
project_id: ProjectId,
},
/// A project's memory grew past the recall budget while no embedder is
/// configured (strategy `none`): the first moment a semantic embedder would
/// help (ARCHITECTURE §14.5.5, LOT C3). Published **at most once per session per
/// project** (and never again once the user chose "ne plus demander"); the
/// frontend surfaces a one-time, dismissible suggestion. Carries the detected
/// local environment and the compiled-in capabilities so the UI never proposes
/// a strategy this binary cannot run.
EmbedderSuggested {
/// The project whose memory crossed the budget.
project_id: ProjectId,
/// Whether an Ollama-style local embedding server was detected (best-effort).
ollama_detected: bool,
/// Ids of the recommended ONNX models already present in the local cache.
onnx_cached: Vec<String>,
/// Whether the HTTP capability (`localServer`/`api`) is compiled in.
vector_http_enabled: bool,
/// Whether the in-process ONNX capability (`localOnnx`) is compiled in.
vector_onnx_enabled: bool,
},
/// Raw PTY output (usually routed to a dedicated channel, not this bus).
PtyOutput {
/// The session.
session_id: SessionId,
/// Output bytes.
bytes: Vec<u8>,
},
}