agent conversation fix

This commit is contained in:
2026-06-27 12:42:37 +02:00
parent c2d1a669c5
commit 1fc7869160
38 changed files with 1173 additions and 1549 deletions

View File

@ -2732,30 +2732,25 @@ pub(crate) fn compose_convention_file(
out.push_str("---\n\n");
out.push_str("# Orchestration IdeA\n\n");
if mcp_enabled {
// Surface MCP (cadrage v3, D3) : l'alternative native aux subagents est
// exposée comme outils typés `idea_*`. L'interdiction des subagents natifs
// du fournisseur est **conservée** ; seule la voie de délégation change.
// Surface MCP : outils IdeA natifs. `idea_ask_agent` est une porte d'entrée
// ergonomique vers l'orchestrateur headless, pas un protocole ask/reply exposé
// aux modèles.
out.push_str(
"Pour déléguer une tâche à un autre agent, n'utilise jamais les subagents \
natifs du fournisseur IA. Utilise les outils IdeA natifs : \
`idea_ask_agent` (déléguer une tâche et recevoir la réponse), \
`idea_launch_agent` (lancer/réattacher un agent) et `idea_list_agents` \
(lister les agents du projet). IdeA lancera ou réattachera l'agent cible \
avec son propre AI Profile, son contexte et sa mémoire.\n\n",
"La conversation inter-agent est gérée par IdeA en headless. Pour contacter \
un autre agent, utilise l'outil MCP IdeA `idea_ask_agent(target, task)` quand \
il est disponible : IdeA lance ou réattache la cible via son profil \
structured/headless, capture sa réponse finale et te la renvoie inline. \
N'invente pas de protocole de ticket et n'appelle pas d'outil de remise de \
résultat.\n\n",
);
// Protocole de délégation (Option 1, B-5) : côté agent SOLLICITÉ. Une tâche
// déléguée arrive dans ton terminal préfixée `[IdeA · tâche de … · ticket …]`.
// Tu DOIS y répondre via l'outil `idea_reply`, jamais en texte libre — sinon
// l'agent qui t'a sollicité reste bloqué (sa réponse ne lui parviendra pas).
// Conversation inter-agent : le transport est géré par IdeA en headless. Les
// agents n'ont plus à connaître un protocole de reply ni à corréler des tickets.
out.push_str(
"Quand tu reçois une tâche déléguée par IdeA (un message préfixé \
`[IdeA · tâche de … · ticket …]`), traite-la puis appelle \
**impérativement** l'outil `idea_reply(ticket=…, result=…)` pour rendre ton \
résultat — **même pour une réponse triviale** (un simple `pong`). Ne réponds \
**JAMAIS** uniquement en texte/prose dans le terminal : tant que tu n'as pas \
appelé `idea_reply`, l'agent qui t'a sollicité reste **bloqué** et sa réponse \
ne lui parviendra pas. Terminer ton tour sans `idea_reply` est un échec du \
protocole, pas une réponse.\n\n",
"Quand IdeA te sollicite via une conversation inter-agent headless, traite \
simplement la demande et termine ton tour avec ta réponse normale. N'ajoute \
pas de protocole de ticket, n'appelle pas d'outil de remise de résultat : IdeA \
capture automatiquement la réponse finale du modèle et la transmet à l'agent \
demandeur.\n\n",
);
// Capacités IdeA (feature skill-awareness) : briefing à HAUTE ALTITUDE,
// télégraphique, injecté à CHAQUE lancement (coût token → pas d'exemples ni de
@ -3379,22 +3374,18 @@ mod tests {
#[test]
fn compose_convention_file_mcp_prose_points_to_idea_tools_and_keeps_subagent_ban() {
// mcp_enabled = true ⇒ prose exposes the native `idea_*` tools while keeping
// the ban on the provider's native subagents (cadrage v3, Décision 3).
// mcp_enabled = true ⇒ prose exposes the remaining native `idea_*` tools while
// keeping the ban on the provider's native subagents (cadrage v3, Décision 3).
let doc = compose_convention_file("/root", "", "# Persona", &[], &[], None, &[], true);
// Native IdeA orchestration tools surfaced.
assert!(
doc.contains("idea_ask_agent"),
"MCP prose must mention idea_ask_agent"
);
assert!(doc.contains("idea_launch_agent"));
assert!(doc.contains("idea_list_agents"));
// Native-subagent ban preserved.
assert!(
doc.contains("n'utilise jamais les subagents"),
"MCP prose must keep the native-subagent ban"
doc.contains("idea_context_read"),
"MCP prose must mention remaining IdeA tools"
);
assert!(doc.contains("idea_memory_read"));
assert!(doc.contains("idea_ask_agent"));
assert!(!doc.contains("idea_reply"));
// It does NOT fall back to the file protocol wording.
assert!(
!doc.contains(".ideai/requests"),
@ -3403,20 +3394,23 @@ mod tests {
}
#[test]
fn compose_convention_file_mcp_prose_carries_the_idea_reply_delegation_protocol() {
// B-5 — the solicited-agent side of the protocol: a delegated task arrives as
// `[IdeA · tâche …]` and MUST be answered via `idea_reply`, never plain text.
fn compose_convention_file_mcp_prose_does_not_carry_idea_reply_protocol() {
// Inter-agent conversation is headless: the model's final answer is captured by
// IdeA. Agents must not be instructed to call a reply tool or echo tickets.
let doc = compose_convention_file("/root", "", "# Persona", &[], &[], None, &[], true);
assert!(
doc.contains("idea_reply"),
"MCP prose must instruct answering via idea_reply"
!doc.contains("idea_reply"),
"MCP prose must not instruct answering via idea_reply"
);
assert!(
doc.contains("[IdeA · tâche"),
"MCP prose must describe the delegated-task prefix it answers to"
doc.contains("capture automatiquement la réponse finale")
|| doc.contains("capture sa réponse finale"),
"MCP prose must describe final-answer capture"
);
assert!(
!doc.contains("[IdeA · tâche"),
"MCP prose must not describe the old delegated-task prefix"
);
// Negative: the non-MCP (file-protocol) prose must NOT carry the idea_reply
// instruction (zero regression on the file path).
let file_doc =
compose_convention_file("/root", "", "# Persona", &[], &[], None, &[], false);
assert!(!file_doc.contains("idea_reply"));