feat(orchestrator): durcir le rendez-vous inter-agents + backstop no-reply (Finding A)

Corrige le wedge survenant lorsqu'un agent délégué ne rappelle pas idea_reply :
le rendez-vous ask_agent ne reste plus bloqué indéfiniment.

Lot 1 — durcissement du préambule de délégation :
- input/mod.rs : delegation_preamble renforcé (obligation explicite idea_reply).
- agent/lifecycle.rs : préambule injecté conditionné à mcp_enabled.

Lot 2 — peuplement du prompt_ready_pattern :
- agent/catalogue.rs : .with_prompt_ready_pattern("? for shortcuts") sur le
  profil Claude + tests de seed, pour calibrer la détection de grâce.

Lot 3 — backstop timeout serveur :
- mcp/jsonrpc.rs : code d'erreur typé RENDEZVOUS_NO_REPLY (-32001).
- mcp/server.rs : mapping timeout → erreur typée, with_ask_rendezvous_timeout
  promu + resolve_ask_rendezvous_timeout (configurable).
- app-tauri/state.rs : lecture env IDEA_ASK_RENDEZVOUS_TIMEOUT_MS.
- tests/mcp_server.rs mis à jour, fix d'un test input flaky.

Propagation overlay (référence des profils) :
- agent/catalogue.rs : overlay_reference_defaults + reference_index + tests.
- store/profile.rs : ReferenceBackfillProfileStore + tests.
- app-tauri/state.rs : wrap au composition root.
- exports mod.rs / lib.rs (application + infrastructure).

Tests réels verts : application 494, app-tauri 235, infrastructure 248,
mcp_server 22/22, 0 échec. Validation e2e LIVE (rebuild AppImage) en attente
avant merge vers develop.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 23:46:48 +02:00
parent 47b3806d32
commit c5e54935b8
13 changed files with 414 additions and 29 deletions

View File

@ -58,7 +58,8 @@ use infrastructure::{
FsProjectStore, FsProviderSessionStore, FsSkillStore, FsTemplateStore, Git2Repository,
HeuristicHandoffSummarizer, IdeaiContextStore, InMemoryConversationRegistry, InMemoryMailbox,
LocalFileSystem, LocalProcessSpawner, McpServer, MediatedInbox, NaiveMemoryRecall,
OrchestratorWatchHandle, PortablePtyAdapter, RwFileGuard, StructuredSessionFactory,
OrchestratorWatchHandle, PortablePtyAdapter, ReferenceBackfillProfileStore, RwFileGuard,
StructuredSessionFactory,
SystemClock, SystemMillisClock, TokioBroadcastEventBus, TokioScheduler, UuidGenerator,
VectorMemoryRecall, DEFAULT_OLLAMA_BASE_URL, ONNX_CACHE_SUBDIR, RECOMMENDED_ONNX_MODELS,
VECTOR_HTTP_ENABLED, VECTOR_ONNX_ENABLED,
@ -717,7 +718,14 @@ impl AppState {
Arc::clone(&fs_port),
app_data_dir.to_string_lossy().into_owned(),
));
let profile_store_port = Arc::clone(&profile_store) as Arc<dyn ProfileStore>;
// Merge-on-read overlay (finding A) : envelopper le store concret UNE SEULE FOIS
// ici, avant toute injection, pour que chaque lecteur (use cases + `.list()` directs
// de l'orchestrateur) voie les défauts de référence backfillés (`prompt_ready_pattern`
// mesuré). `save`/`delete`/`is_configured` délèguent verbatim ⇒ persistance et
// détection first-run inchangées.
let profile_store_port: Arc<dyn ProfileStore> = Arc::new(
ReferenceBackfillProfileStore::new(Arc::clone(&profile_store) as Arc<dyn ProfileStore>),
);
let detect_profiles = Arc::new(DetectProfiles::new(Arc::clone(&runtime_port)));
let list_profiles = Arc::new(ListProfiles::new(Arc::clone(&profile_store_port)));
@ -1511,10 +1519,19 @@ impl AppState {
service_for_ready.release_agent_cold_start(AgentId::from_uuid(uuid));
}
});
// Borne du rendez-vous `idea_ask_agent` (filet serveur) : réglage projet
// optionnel via `IDEA_ASK_RENDEZVOUS_TIMEOUT_MS`. Absent / invalide / `0` ⇒
// défaut généreux inchangé (24 h), zéro régression sur les tours longs légitimes.
let ask_timeout = infrastructure::resolve_ask_rendezvous_timeout(
std::env::var("IDEA_ASK_RENDEZVOUS_TIMEOUT_MS")
.ok()
.and_then(|v| v.trim().parse::<u32>().ok()),
);
let handle = McpServerHandle::start(
McpServer::new(Arc::clone(&self.orchestrator_service), project.clone())
.with_events(events)
.with_ready_sink(ready_sink),
.with_ready_sink(ready_sink)
.with_ask_rendezvous_timeout(ask_timeout),
endpoint,
listener,
project_id,