diff --git a/README.md b/README.md index fb85ab1..9e0c802 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ Ce dépôt est le marketplace A2M Systèmes. Actuellement, il contient le plugin Le plugin `miam` fournit : - le serveur MCP `miam` (outils `etat`, `modeles`, `presets`, `demarrer`, `deleguer`, `suivre`…) ; -- le subagent `miam:delegue`, qui délègue en laissant MIAM choisir le modèle, vérifie le résultat et rend un compte rendu court ; - la skill `deleguer` (quand et comment déléguer) ; - un compteur de tokens économisés (notification, ligne d'état, `/miam-economies`), net du pilotage et des corrections, en vert ou en rouge selon le signe du gain ; @@ -111,8 +110,6 @@ plugins/ .claude-plugin/ plugin.json # Métadonnées et version du plugin .mcp.json # Configuration du serveur MCP - agents/ - delegue.md # Définition du subagent de délégation hooks/ hooks.json # Liste des hooks register.tsx # Enregistrement des hooks (compteur, ligne d'état, incitation) diff --git a/plugins/miam/agents/delegue.md b/docs/agent-delegue.md similarity index 100% rename from plugins/miam/agents/delegue.md rename to docs/agent-delegue.md diff --git a/docs/token-summary-mod.md b/docs/token-summary-mod.md index 628d27e..43caf03 100644 --- a/docs/token-summary-mod.md +++ b/docs/token-summary-mod.md @@ -4,7 +4,7 @@ Destinataire : l'agent Claude Code qui travaille dans le dépôt MIAM. Le côté `plugin-claude-miam`, schéma 1) ; ce document décrit ce que MIAM doit recevoir, stocker et restituer. ## But -Le mod estime, sans aucun coût en tokens, ce que chaque délégation évite à Claude et le coût du pilotage (consommation du subagent `miam:delegue`). MIAM connaît les tokens du modèle local mais pas ce qui se passe côté Claude : ces événements complètent son bilan. +Le mod estime, sans aucun coût en tokens, ce que chaque délégation évite à Claude et le coût du pilotage (consommation d'un subagent qui délègue ; le subagent `miam:delegue` est mis de côté, voir `agent-delegue.md`). MIAM connaît les tokens du modèle local mais pas ce qui se passe côté Claude : ces événements complètent son bilan. ## Prérequis dans MIAM : `demande_id` dans le journal `delegations.jsonl` ne contient pas aujourd'hui l'identifiant de la demande (`core/delegation.py`, `journal_entry`) : diff --git a/plugins/miam/.claude-plugin/plugin.json b/plugins/miam/.claude-plugin/plugin.json index e18b38c..1785e2a 100644 --- a/plugins/miam/.claude-plugin/plugin.json +++ b/plugins/miam/.claude-plugin/plugin.json @@ -1,8 +1,8 @@ { "name": "miam", "displayName": "MIAM", - "version": "0.6.1", - "description": "Délégation de tâches à un modèle local géré par MIAM (Mon IA Manager) : subagent, règles de délégation, gains en tokens et usage Claude (5 h, hebdo) en couleur", + "version": "0.7.0", + "description": "Délégation de tâches à un modèle local géré par MIAM (Mon IA Manager) : règles de délégation, gains en tokens et usage Claude (5 h, hebdo) en couleur", "author": { "name": "Ange-Marie MAURIN" }, @@ -36,13 +36,6 @@ "min": 1, "max": 65535 }, - "modele_subagent": { - "type": "string", - "title": "Modèle Claude du subagent", - "description": "Modèle qui pilote MIAM pour l'agent principal (rédige la consigne, attend, vérifie)", - "options": ["haiku", "sonnet", "opus", "fable"], - "default": "haiku" - }, "preset_defaut": { "type": "string", "title": "Preset MIAM par défaut", diff --git a/plugins/miam/README.md b/plugins/miam/README.md index 55735b5..3dc7e7a 100644 --- a/plugins/miam/README.md +++ b/plugins/miam/README.md @@ -6,7 +6,6 @@ Plugin Claude Code pour déléguer des tâches à un modèle local géré par MI ## Contenu - Serveur MCP `miam` (http://127.0.0.1:{port}/mcp, jeton Bearer) : point d'entrée pour la communication avec le serveur MCP de MIAM. -- Subagent `miam:delegue` : agent dédié qui pilote la délégation des tâches vers MIAM. - Skill `deleguer` : règles, pour l'agent principal, sur quand et comment déléguer une tâche à MIAM. ## Prérequis @@ -36,12 +35,11 @@ Puis : à l'activation, Claude Code demande les réglages (voir section suivante | :--- | :--- | :--- | | jeton | (vide) | Jeton Bearer du serveur MCP de MIAM, rangé dans le coffre d'identifiants. | | port | 8090 | Port du serveur MCP de MIAM sur 127.0.0.1. | -| modele_subagent | haiku | Modèle Claude qui pilote MIAM pour l'agent principal (rédige la consigne, attend, vérifie). | | incitation | oui | Ajoute au prompt système une consigne de délégation (quelques centaines de tokens, en cache) et un rappel après une grosse lecture. | | preset_defaut | pre-16312f8b | Preset MIAM par défaut, démarré quand aucun modèle n'est chargé et que MIAM n'a aucun test pour le type de la tâche. | ## Utilisation -L'agent principal lance le subagent miam:delegue ; celui-ci vérifie que MIAM répond (etat), classe la tâche, délègue avec `type` (`code`, `texte`, `rapide`) et `seuil` (0,8 par défaut), vérifie, et rend un compte rendu court avec le choix de MIAM. +L'agent principal appelle directement l'outil `deleguer`, avec `type` (`code`, `texte`, `rapide`) et `seuil` (0,8 par défaut), puis vérifie le résultat. Le subagent `miam:delegue` est mis de côté : son pilotage rendait les gains négatifs. Sa définition est gardée dans `docs/agent-delegue.md` du dépôt. MIAM choisit le modèle d'après ses tests de qualité : il garde le modèle chargé s'il atteint le seuil, sinon il charge le meilleur preset, quitte à remplacer le modèle chargé (20 à 40 s) ; si aucun n'atteint le seuil, il prend le meilleur et le signale. L'agent principal peut imposer un preset ou demander de garder le modèle chargé. Contrat : `docs/protocole-agents.md` du dépôt MIAM. @@ -53,7 +51,7 @@ Avec `incitation` (par défaut), l'agent principal reçoit une courte consigne d Avec `imposer` (par défaut), et tant que MIAM répond, l'agent principal ne peut plus consommer d'usage sur de longues lectures : - `Read` d'un fichier de 20 000 octets ou plus est refusé avant la lecture, sauf plage de 400 lignes au plus (`offset`, `limit`), image, PDF ou fichier écrit par une délégation ; -- une sortie `Bash` ou `PowerShell` de 20 000 caractères ou plus est enregistrée dans `.claude/miam-sorties/` du projet (dossier ignoré par git) et retenue : le modèle reçoit le chemin, à passer à `miam:delegue`. Une commande en erreur garde sa sortie et déclenche le rappel. +- une sortie `Bash` ou `PowerShell` de 20 000 caractères ou plus est enregistrée dans `.claude/miam-sorties/` du projet (dossier ignoré par git) et retenue : le modèle reçoit le chemin, à passer à `deleguer`. Une commande en erreur garde sa sortie et déclenche le rappel. Les subagents ne sont pas concernés. Si MIAM ne répond pas, ou si la sortie ne peut pas être enregistrée, rien n'est bloqué. Si MIAM répond mais que la délégation échoue (`/mcp` à reconnecter, par exemple), la lecture par plages reste possible. @@ -66,14 +64,14 @@ Une seule ligne, sans coût en tokens (`🟢 MIAM net ~4k (cumul ~35k) · 5 h ## Tokens économisés Après chaque délégation réussie, une notification (`🟢 MIAM : ~6,1k tokens évités (5,2k lus, 900 écrits)`) et la mise à -jour de la ligne d'état, dans le terminal comme dans VS Code. À la fin du subagent, une seconde notification donne le net, pilotage déduit (`🔴 MIAM : net ~-1,5k sur la session (pilotage 2k)`). `/miam-economies` donne le détail de la session et le cumul ; `/miam-economies raz` +jour de la ligne d'état, dans le terminal comme dans VS Code. `/miam-economies` donne le détail de la session et le cumul ; `/miam-economies raz` remet les compteurs à zéro. Le calcul se fait localement dans Claude Code : il ne coûte aucun token. Chaque estimation est aussi envoyée à MIAM (`POST /economies`, toutes les 5 s, hors des hooks ; gardée et renvoyée si MIAM ne répond pas) : contrat et modèle de données dans [docs/token-summary-mod.md](../../docs/token-summary-mod.md). - **Évités** : les fichiers lus et la réponse écrite par le modèle local (chiffres de MIAM), moins la consigne et ce que Claude relit (estimés à 4 caractères par token). -- **Pilotage** : la consommation réelle du subagent `miam:delegue` (lecture en cache comptée au dixième), à déduire. +- **Pilotage** : la consommation réelle d'un subagent qui délègue (lecture en cache comptée au dixième), à déduire. - **Corrections** : ce que l'agent principal relit (`Read`) ou retouche (`Edit`, `Write`, `NotebookEdit`, `Bash`) dans un fichier écrit par une délégation (`sortie`), à déduire aussi. Celles du subagent sont déjà dans le pilotage. - **Net** = évités − pilotage − corrections. @@ -89,8 +87,6 @@ MIAM teste lui-même les presets, en travaux de fond (page Benchmarks) : le plug .claude-plugin/ plugin.json # manifeste : nom, version, réglages (jeton, port, modèle, preset) .mcp.json # serveur MCP miam (http://127.0.0.1:/mcp) -agents/ - delegue.md # subagent miam:delegue skills/ deleguer/SKILL.md # quand et comment déléguer hooks/ @@ -108,7 +104,6 @@ README.md - deleguer ne transmet que du texte (pas d'image). - Un `.mcp.json` de projet qui déclare déjà le serveur `miam` (celui de ce dépôt, celui de MIAM) fait doublon avec le plugin : le retirer une fois le plugin installé. -- Le modèle du subagent réglé par modele_subagent s'applique quand il est lancé via la skill deleguer (sinon : haiku, défaut du fichier de l'agent). ## Licence diff --git a/plugins/miam/hooks/register.test.tsx b/plugins/miam/hooks/register.test.tsx index 59a60d0..dc5c11a 100644 --- a/plugins/miam/hooks/register.test.tsx +++ b/plugins/miam/hooks/register.test.tsx @@ -152,7 +152,7 @@ test('un long fichier est refusé à l’agent principal, sauf plage, subagent o on('tool.call', () => (lectures += 1, { result: {}, text: 'ok' })) const lire = (extra = {}) => $.tool.call({ tool: 'Read', file_path: 'long.log', ...extra } as never) - expect((await lire()).deny).toContain('miam:delegue') + expect((await lire()).deny).toContain('`deleguer`') expect(lectures).toBe(0) expect((await lire({ limit: 400 })).deny).toBeUndefined() expect((await lire({ agentId: 'a1' })).deny).toBeUndefined() @@ -194,7 +194,7 @@ test('une grosse lecture de l’agent principal vaut un rappel, pas deux de suit const lire = (agentId?: string) => $.tool.call({ tool: 'Read', file_path: 'a.log', agentId } as never) expect((await lire('a1')).context).toBeUndefined() - expect((await lire()).context?.[0]).toContain('miam:delegue') + expect((await lire()).context?.[0]).toContain('`deleguer`') expect((await lire()).context).toBeUndefined() t = 600000 expect((await lire()).context).toHaveLength(1) diff --git a/plugins/miam/hooks/register.tsx b/plugins/miam/hooks/register.tsx index 7ec5b7c..3b7e93d 100644 --- a/plugins/miam/hooks/register.tsx +++ b/plugins/miam/hooks/register.tsx @@ -27,13 +27,13 @@ const CONSIGNE = { id: 'miam:delegation', scope: 'session', text: `# Délégation à MIAM -Un modèle local (MIAM) fait sans consommer l'usage Claude les tâches autonomes et vérifiables. Par réflexe, avant de les faire toi-même, lance le subagent \`miam:delegue\`, sans demander : tirer peu d'un long log, d'une longue sortie de tests ou d'un long document ; traduction, résumé, notes de version, docstrings, message de commit ; fonction pure et ses tests, tests répétitifs. Ne lis pas le fichier avant : MIAM le lit. Fais-le toi-même seulement pour l'architecture, le débogage multi-fichiers, la concurrence, la sécurité, ce qui demande le contexte de la conversation, les secrets, ou si MIAM est injoignable.`, +Un modèle local (MIAM) fait sans consommer l'usage Claude les tâches autonomes et vérifiables. Par réflexe, avant de les faire toi-même, appelle toi-même l'outil MCP \`deleguer\` de MIAM (sans subagent, qui coûte plus cher), sans demander : tirer peu d'un long log, d'une longue sortie de tests ou d'un long document ; traduction, résumé, notes de version, docstrings, message de commit ; fonction pure et ses tests, tests répétitifs. Ne lis pas le fichier avant : MIAM le lit. Fais-le toi-même seulement pour l'architecture, le débogage multi-fichiers, la concurrence, la sécurité, ce qui demande le contexte de la conversation, les secrets, ou si MIAM est injoignable.`, } as const const RAPPEL = "Cette sortie est longue. Si tu n'en as besoin que d'une petite partie, la prochaine fois confie-la à " + - "`miam:delegue` (MIAM lit les fichiers sans consommer l'usage Claude) au lieu de la lire toi-même." + "l'outil MCP `deleguer` de MIAM (il lit les fichiers sans consommer l'usage Claude) au lieu de la lire toi-même." -const REFUS_LECTURE = `Lecture refusée par le plugin MIAM : ce fichier est long. Lance le subagent \`miam:delegue\` avec ce chemin et ce que tu cherches, ou lis seulement la partie utile (\`offset\` et \`limit\` de ${PLAGE_MAX} lignes au plus). Ne découpe pas le fichier pour le lire en entier.` -const refusSortie = (chemin: string) => `Sortie longue retenue par le plugin MIAM, enregistrée dans ${chemin}. La commande a bien tourné : ne la relance pas pour lire sa sortie. Lance le subagent \`miam:delegue\` avec ce fichier et ce que tu cherches, ou lis seulement la partie utile avec \`offset\` et \`limit\`.` +const REFUS_LECTURE = `Lecture refusée par le plugin MIAM : ce fichier est long. Appelle l'outil MCP \`deleguer\` de MIAM avec ce chemin et ce que tu cherches, ou lis seulement la partie utile (\`offset\` et \`limit\` de ${PLAGE_MAX} lignes au plus). Ne découpe pas le fichier pour le lire en entier.` +const refusSortie = (chemin: string) => `Sortie longue retenue par le plugin MIAM, enregistrée dans ${chemin}. La commande a bien tourné : ne la relance pas pour lire sa sortie. Appelle l'outil MCP \`deleguer\` de MIAM avec ce fichier et ce que tu cherches, ou lis seulement la partie utile avec \`offset\` et \`limit\`.` type Demande = { consigne: string; retour?: string; agentId?: string } type Miam = { url: string; jeton: string } @@ -272,7 +272,7 @@ export const register: Register = (on, options) => { on('prompt.compose', async ($, e, next) => { const composition = await next(e) - // L'outil Agent n'est offert qu'à l'agent principal : pas de consigne pour les subagents, dont miam:delegue. + // L'outil Agent n'est offert qu'à l'agent principal : pas de consigne pour les subagents. return incitation && e.tools.includes('Agent') ? { ...composition, sections: [...composition.sections, CONSIGNE] } : composition diff --git a/plugins/miam/skills/deleguer/SKILL.md b/plugins/miam/skills/deleguer/SKILL.md index adbe33b..b6537f9 100644 --- a/plugins/miam/skills/deleguer/SKILL.md +++ b/plugins/miam/skills/deleguer/SKILL.md @@ -21,27 +21,29 @@ délégation. ## Comment -Lance le subagent `miam:delegue` (outil Agent, `subagent_type: "miam:delegue"`, `model: "${user_config.modele_subagent}"`). -Il vérifie que MIAM répond, indique le type de la tâche pour que MIAM choisisse le modèle, délègue, attend, vérifie et -rend un compte rendu court. +Appelle toi-même l'outil MCP `deleguer` du serveur `plugin:miam:miam`, chargé au besoin par ToolSearch. Pas de subagent : son +pilotage coûte plus de tokens que la délégation n'en économise. Le modèle local ne voit que la consigne et les fichiers. -Son brief doit se suffire à lui-même : -- la tâche, précise (signature, langue, format exact, cas limites) ; -- les fichiers en **chemins absolus** (MIAM les lit : ne les lis pas toi-même avant) ; -- le format (`texte`, `code`, `json`) et le fichier de `sortie` éventuel (dire si on peut l'écraser) ; -- comment vérifier (tests à lancer, clés JSON attendues) ; -- si besoin : un seuil de qualité (0 à 1, défaut 0,8), un preset imposé, ou « garder le modèle chargé ». Par défaut, - MIAM remplace le modèle chargé s'il est sous le seuil pour cette tâche (20 à 40 s). +- `type` : `code` (fonction, tests, script), `texte` (traduction, résumé court, notes de version, docstrings, commit), + `rapide` (lire beaucoup pour rendre peu). MIAM choisit le modèle, `seuil` vaut 0,8 par défaut ; +- `consigne` : autonome et précise (signature, langue, format exact, cas limites) ; +- `fichiers` : **chemins absolus**, `chemin:debut-fin` pour une partie. MIAM les lit : ne les lis pas avant ; +- `format` : `json` pour des faits extraits, `code` pour du code, sinon `texte` ; +- réponse longue : `sortie` + `retour="apercu"`, pour ne pas la relire ; +- `reflexion` : `off` par défaut, `bas`/`moyen`/`haut` si la tâche demande du raisonnement. -Plusieurs tâches indépendantes : plusieurs subagents, MIAM les met en file (une délégation à la fois sur le GPU) ; des -types différents peuvent recharger un modèle entre deux tâches. +Réponse « en file » : `suivre(demande_id, attente_s=45)` jusqu'au résultat, `annuler(demande_id)` pour abandonner. + +Refus de `deleguer` : `aucun preset testé` → `demarrer(preset="${user_config.preset_defaut}")`, `suivre`, puis le même +`deleguer` ; contexte dépassé → `modeles`, puis `preset` = le mieux noté dont le `contexte` suffit, sans `offload` si +possible ; autre refus → le dire à l'utilisateur. ## Ensuite -Relis le compte rendu : un résultat « raté » ou « partiel », tu le reprends toi-même. Code produit : relu, `ruff check`, -`ruff format --check` et tests verts avant de le garder. +Vérifie sans tout relire : `json_valide` et clés pour du JSON ; ruff et tests pour du code ; `tronque` vrai = réponse +coupée. Un échec : une seule nouvelle délégation avec une consigne corrigée, puis reprends la tâche toi-même. -MIAM injoignable (le compte rendu le dit) : le signaler à l'utilisateur (lancer MIAM et son serveur MCP, puis `/mcp` → -Reconnect sur `plugin:miam:miam`) et faire la tâche toi-même si elle est urgente. +MIAM injoignable (outil absent, connexion refusée) : le signaler à l'utilisateur (lancer MIAM et son serveur MCP, puis +`/mcp` → Reconnect sur `plugin:miam:miam`) et faire la tâche toi-même si elle est urgente. Bilan des délégations : outil `bilan` de MIAM. Notes et caractéristiques des presets : outil `modeles`.