BLOG

fast-jev-compaction décortiqué : faire abandonner la rédaction de résumés à la compression de Claude Code

Kael Zhang
Claude Code上下文压缩AI Agent
广告 · Advertisement

Démontage technique : Analyse des frameworks d’IA — explication, analyse, évaluation technique, jugement de valeur, mise en œuvre. Auteur : Yongliang


Le 19 septembre 2026, le dépôt tamaratran/fast-jev-compaction comptait 3 206 étoiles sur GitHub (au 19 septembre), est écrit en TypeScript, sous licence MIT, et a été créé le 17 septembre 2026 — soit il y a deux jours. Le package npm est en version 0.2.0, la liste des plugins Claude Code en 0.3.0, le dépôt contient 25 fichiers au total, pour environ 1850 lignes entre le code source, les hooks et les tests, le cœur (src) faisant environ 960 lignes, le plus gros fichier compact.ts en comptant 309. La compression de contexte (compaction) de Claude Code demande par défaut au modèle d’écrire un résumé pour remplacer l’ancien historique ; le résumé est avec perte — les chemins de fichiers, les erreurs précises, les contraintes peuvent disparaître. Ce plugin n’écrit pas de résumés, il ne fait que des suppressions : le contenu supprimé soit disparaît par paire, soit est conservé tel quel. Cet article décompose le sujet en six points : c’est quoi, où ça fait mal, comment le mécanisme tourne, trois endroits du code à voir, les limites et les coûts, et est-ce que ça vaut le coup.

I. C’est quoi

fast-jev-compaction est un plugin Claude Code : il prend en charge l’étape de compression de contexte, remplaçant « écrire un résumé » par « décision par paire ». Dans l’historique compressé, il n’y a plus de paragraphes reformulés par le modèle ; chaque appel d’outil n’a que trois issues possibles — conservation complète, conservation de l’appel sans le résultat, ou disparition conjointe de l’appel et du résultat. Le critère de jugement n’est pas un texte, mais deux probabilités.

Pour le comprendre, il faut d’abord connaître le modèle dont il dépend. Jev est un modèle commercial de TypeSafe, dont la ligne de produits s’appelle « system one » : il ne génère pas de texte mot à mot, mais sort une probabilité pour une série de questions données, permettant à l’agent de prendre des branches rapidement. Quelle phrase doit suivre quelle phrase, quel résultat doit rester dans le contexte, à ces carrefours « oui ou non », il donne directement un chiffre. Jev est lui-même une nouveauté de trois jours — durant ces trois jours, au moins 5 dépôts liés à jev sont apparus sur GitHub, browser-use/jev-ultrafast en obtenant 5 487, l’une des croissances les plus rapides. Un modèle entraînant une série de projets associés montre que la direction « utiliser des modèles probabilistes pour des décisions légères d’agent » prend de l’ampleur, et fast-jev-compaction est l’échantillon d’ingénierie le plus complet de ce vent. TypeSafe n’a pas publicisé la conception interne de Jev, cet article explique seulement comment ce plugin utilise son interface, sans inventer son architecture.

II. Le vrai point de douleur qu’il résout

La fenêtre de contexte des agents à longue conversation est limitée, quand elle est presque pleine, il faut compresser. L’approche dominante est le résumé par LLM : faire lire au modèle l’ancien historique et écrire une version condensée pour remplacer l’original. L’essence du résumé est de faire prendre des notes au modèle pour son futur soi — que noter, que jeter est décidé par un processus de génération, les erreurs ne laissent pas de trace. Les chemins de fichiers peuvent être réécrits en chemins approximatifs, les messages d’erreur précis peuvent être résumés en « il y a une erreur », les contraintes données par l’utilisateur (« ne touche pas à ce fichier ») peuvent être perdues lors de la condensation. Plus gênant encore, après compression, il n’y a aucun moyen de vérifier ce qui a été perdu, et quand trois heures plus tard le modèle modifie le mauvais fichier sur la base d’un résumé erroné, il est difficile de remonter la responsabilité à cette compression.

Ce plugin décompose le point de douleur très calmement : la grosse partie du contexte n’est pas le texte de chat, ce sont les appels d’outils et les résultats d’outils — une lecture de fichier fait quelques milliers de caractères, une sortie de test fait plus de dix mille, et après des dizaines de tours, ils mangent 90 % de l’espace. Ce qui doit vraiment être jugé, c’est « cet appel est-il encore important pour ce qui suit ». C’est une question à choix multiples, pas une question de rédaction. Les questions à choix multiples peuvent être confiées à un modèle qui sort des probabilités, les réponses peuvent être archivées ligne par ligne. La rédaction peut inventer, le choix multiple est au moins honnête.

III. Mécanisme : du appariement à la reconstruction

3.1 Appariement et pinned

La première étape consiste à découper la conversation en unités jugables. Chaque tool_use et tool_result correspondant sont appariés selon tool_use_id — lors de la suppression, l’appel et le résultat vont ensemble, et après reconstruction, il n’y aura pas de résultat orphelin sans appel. Le premier message et les derniers preserveRecentMessages (par défaut 6) sont marqués comme pinned, jamais traités, garantissant que le début et le présent de la conversation sont toujours complets.

3.2 Construction de l’état (state) envoyé à Jev

L’état envoyé à Jev est la conversation complète, la plus ancienne en premier. Tous les résultats d’outils sont remplacés par une courte note (de la forme ok, 4213 chars (omitted)), disant à Jev « ici il y a eu une lecture réussie, texte original 4213 caractères » ; les entrées d’outils sont entièrement sérialisées dans l’état ; les textes de l’utilisateur et de l’assistant sont conservés en intégralité, sans résumé. L’état a lui-même une limite de volume maxStateTokens (par défaut 25000), en cas de dépassement, dégradation par étapes : les entrées d’outils sont successivement coupées à 1000, 200, 60 caractères ; les longs textes gardent les 400 premiers et les 150 derniers caractères ; si ce n’est pas assez, on replie à partir du plus ancien message en [… N chars omitted …], les vieux appels d’outils sont écrasés en une ligne (de la forme t12 Read file_path=src/a.ts → ok 480ch) ; les messages pinned ne sont touchés qu’en dernier. Si toutes les étapes ne suffisent pas, une exception est levée directement, on ne force pas. Le nombre de tokens est une estimation de caractères : environ 1 token pour 6 lettres, la moitié pour les chiffres, 1 pour les autres symboles — ce n’est pas un vrai tokenizer, c’est bon marché, et n’introduit pas de dépendance de tokenisation.

3.3 Deux questions noul et traitement par lots

Pour chaque appel non pinned, le plugin pose deux questions à Jev. call_X : « est-il important pour la suite de savoir que cet appel a été lancé, avec quelle entrée ». result_X : « ce résultat a-t-il besoin d’être conservé en texte original, ne peut-on pas remplacer en relançant l’outil ». Les deux sont de type noul — Jev ne renvoie pas de texte, il crache juste une probabilité pour chaque question.

Les questions sont traitées par lots selon le volume. maxRequestTokens par défaut 30000 (limite Jev par requête 32000), moins le quota pris par l’état moins 20 tokens de frais d’enveloppe de requête, le reste est le budget de questions par lot. L’état est renvoyé en intégralité à chaque lot, toutes les questions du lot sont fusionnées dans une requête, les lots sont envoyés en concurrence et les réponses fusionnées. Plus l’état est gros, moins on peut mettre de questions par lot, dans les cas extrêmes il faut une requête toutes les quelques questions — c’est un coût inhérent à la conception, développé dans la section limites.

3.4 Décision et reconstruction

La règle de décision tient sur une ligne. decideCall juge dans l’ordre : pinned est conservé directement ; si keepResult est supérieur ou égal au seuil (par défaut 0,5), la paire est conservée ; sinon si keepCall est supérieur ou égal au seuil, l’appel lui-même est conservé, le résultat est tronqué aux truncateHeadChars (par défaut 300) premiers caractères, avec une note explicative — la note précise combien de caractères ont été tronqués, si c’est une erreur, et qu’on peut relancer l’outil ; si aucune probabilité ne passe, l’appel et le résultat sont supprimés par paire.

La reconstruction est faite par applyDecisions : les messages dont le contenu est perdu sont entièrement supprimés, les messages inchangés sont retournés tels quels (le même objet, zéro copie), les messages partiellement modifiés sont remplacés sur place. L’entrée-sortie est entièrement constituée de décisions structurées et de statistiques vérifiables (comptage de chaque type de décision, nombre de caractères avant/après compression, estimation de tokens de l’état, niveau de dégradation utilisé, nombre de requêtes envoyées), pas un prose.

IV. Trois endroits du code à voir

4.1 Les fonctions de lot et de décision dans compact.ts

compact.ts fait 309 lignes, c’est le plus gros fichier du dépôt, le tronc a quatre fonctions. questionsFor (compact.ts:56) génère deux questions noul pour chaque appel, l’énoncé intègre le nom de l’outil, l’id de l’appel, le nombre de caractères du résultat, donnant à Jev de quoi juger. batchCalls (compact.ts:73) fait les lots, l’algorithme de budget est transparent : maxRequestTokens moins l’état moins 20, on remplit tant qu’on peut, si les questions d’un seul appel dépassent le budget ça veut dire que l’état est trop gros, on lève une exception en précisant « l’état prend environ tant des 30000 ». decideCall (compact.ts:101) est le plus court passage du livre — pinned, seuil keepResult, seuil keepCall, else supprimer, quatre lignes. applyDecisions (compact.ts:149 et suite) s’occupe de la reconstruction, les commentaires écrivent les invariants très clairement : les appels supprimés disparaissent avec leurs résultats, les résultats supprimés gardent une tête bornée et une explication, les messages dont le contenu est perdu sont retirés, les messages inchangés retournent l’objet original.

4.2 Le point de terminaison et l’analyse noul dans request.ts

request.ts ne fait que 80 lignes, c’est tout le contrat d’interface. SYSTEM_ONE_URL pointe vers https://api.typesafe.ai/v1/systemone, le nom de modèle par défaut est jev-latest. buildJevRequest emballe model, state, questions dans un POST. parseJevResponse fait une validation draconienne du corps de retour : HTTP pas ok -> erreur, échec parsing JSON -> erreur, champ answers manquant -> erreur. noulAnswer prend le champ noul d’une réponse individuelle, champ manquant, pas un nombre, pas un nombre fini, erreur dans tous les cas. Le fichier n’a aucun endroit de tolérance silencieuse — tous les échecs deviennent des exceptions remontées, laissées à l’appelant pour le filet de sécurité.

4.3 Les conditions de déclenchement du hook

hooks/fast-jev.ts est la fine couche d’adaptation vers Claude Code. function hooks est une fonctionnalité précoce de Claude Code 2.1.274+, il faut l’activer dans settings.json ; une fois activé, le plugin est rappelé au turn.complete, vérifie le taux d’utilisation du contexte actuel, et ne déclenche la compression qu’à compactAtPercent (par défaut 60 %). Après déclenchement, on estime d’abord un tour, si le taux de compression n’atteint pas minReductionRatio (par défaut 25 %), on ne remplace pas l’historique, on ne fait pas un tour de jugement gratuit si ça ne vaut pas le coup. Toute exception — le service Jev tombe, les réponses sont tordues, il manque TYPESAFE_API_KEY, l’état ne tient pas — ne force pas, on retombe sur la compression par résumé intégrée de Claude Code. La configuration peut passer entièrement par userConfig du plugin : seuils, nombre de messages à garder, longueur de troncature, nom de modèle, tout est modifiable.

V. Limites et coûts

Les Limitations officielles sont au nombre de quatre, retransmises telles quelles. Premièrement, on ne traite que les appels d’outils, les messages texte ne sont jamais raccourcis en sortie (ils ne sont qu’abrégés dans l’état vu par Jev) — si votre contexte est gonflé par le texte de chat, ce plugin ne vous aidera pas. Deuxièmement, le nombre de tokens est une estimation de caractères, pas un vrai tokenizer, le jugement de budget a des écarts. Troisièmement, phrase à retenir en entier : « une probabilité n’est pas une preuve que la suppression est sûre, l’assistant peut toujours relancer l’outil » — le seuil de 0,5 n’est pas une ligne de sécurité, c’est une ligne empirique. Quatrièmement, l’état est renvoyé en intégralité à chaque requête, quand l’historique est proche de la limite, il faut une requête toutes les quelques questions, le coût en tokens croît linéairement avec la longueur de l’historique, les utilisateurs intensifs doivent savoir compter.

Trois points de doute, on écrit seulement le doute, pas le verdict. La qualité de la décision mise tout sur l’étalonnage des probabilités d’un seul modèle commercial Jev, le dépôt n’a aucun chiffre de référence de tests d’intégration, le README n’a pas de tableau de benchmark, la qualité de la compression n’a pas de métrique vérifiable par un tiers. L’écosystème de plugins est étroitement couplé à la version de Claude Code, function hooks est une fonctionnalité précoce de 2.1.274+, si l’interface bouge, le plugin doit suivre. Le dépôt n’a que deux jours d’historique, personne n’a vérifié la performance en production sur les longues conversations, 3 206 étoiles en deux jours, c’est l’engouement pour le concept, pas une caution de stabilité.

VI. Est-ce que ça vaut le coup et pour qui

C’est une nouvelle solution à un vieux problème de « compression de contexte » — transformer le devoir de rédaction de résumé en questionnaire à choix multiples, le prix étant d’externaliser le pouvoir de décision à un modèle probabiliste commercial. Les gens faits pour ça sont clairs : ceux qui utilisent Claude Code tous les jours pour de longues conversations et qui ont été mordus par des pertes de contexte via résumé, le coût d’essayer est bas, c’est une histoire de package npm et de variable d’environnement ; ceux qui font de l’ingénierie d’agents et étudient la gestion de contexte, ce dépôt de 1850 lignes se lit en une soirée, c’est un échantillon propre pour fourrer un modèle probabiliste dans la boucle de décision d’agent. Ceux pour qui ça ne convient pas sont tout aussi clairs : ceux qui ne veulent pas envoyer les données de conversation à une API tierce — l’état est la conversation complète, avec votre code et vos erreurs ; ceux dont les conversations ne sont pas longues et dont le résumé intégré suffit ; les équipes qui ont besoin d’une promesse de qualité de compression vérifiable, le README n’a pas de benchmark, cette promesse ne peut pas être donnée pour l’instant.

Point de vue de l’auteur : si on n’utilise pas Jev, cette idée peut-elle être portée ? Très probablement oui. L’essence des questions noul est de noter un groupe d’options, n’importe quel petit modèle capable de sortir des logits peut le faire — faire tourner un petit modèle de niveau 3B localement, sortir la probabilité de « oui » pour les deux questions call_X et result_X, remplacer l’appel distant à Jev, les données ne sortent pas de la machine, le coût d’appel tombe à zéro, le prix est que la qualité de l’étalonnage n’est garantie par personne, il faut régler le seuil soi-même. Ce que ce projet vaut vraiment la peine d’emporter, ce n’est pas forcément le plugin lui-même, mais cette façon de questionner : pour compresser le contexte, il ne faut pas forcément faire écrire une dissertation au modèle, le faire faire un choix multiple, puis exécuter selon le seuil de probabilité.

Conclusion

fast-jev-compaction répond avec environ 1850 lignes de code à une question : la compression de contexte doit-elle forcément écrire un résumé ? Sa réponse est non. Les appels d’outils constituent la grosse partie du contexte des longues conversations, « garder ou supprimer » est un choix multiple, qui peut être laissé à un modèle comme Jev qui sort des probabilités d’options. Dans le code source, ce jugement est très concret : les appels sont appariés par tool_use_id, le premier et les 6 derniers sont pinned et jamais traités, l’état est construit intégralement, les résultats d’outils remplacés par des notes courtes, dégradé en quatre paliers si dépassement, chaque appel reçoit deux questions noul, traité par lots concurrents selon un budget de 30000 tokens, seuil de 0,5 pour trancher entre keep / drop_result / drop_call, la reconstruction garantit qu’il n’y a pas de résultat orphelin ; côté hook, on vérifie à turn.complete l’utilisation à 60 % pour déclencher, si le taux de compression est inférieur à 25 % on abandonne le remplacement, en cas d’échec on retombe sur le résumé intégré. Les coûts sont aussi clairs : les tokens sont estimés, la probabilité n’est pas une preuve de sécurité de suppression, l’état est renvoyé en intégralité, la qualité n’a pas de chiffres de référence. 3 206 étoiles en deux jours, c’est l’engouement pour le concept qui monte, il est lié sur le même bateau que Jev cette nouveauté de trois jours — pour ceux qui font la gestion de contexte d’agent, c’est une lecture de code source qui vaut le coup ; pour l’utilisateur moyen, attendez qu’il tourne quelques versions.

Sources de référence

  • tamaratran/fast-jev-compaction README (positionnement, table de configuration, Limitations, explication du plugin Claude Code, exigences de version function hooks)
  • Code source (clone local) : src/compact.ts (DEFAULT_OPTIONS, questionsFor, batchCalls, decideCall, applyDecisions), src/state.ts (collectToolCalls, estimateTokens, fitState, INPUT_CHARS=[1000,200,60], TEXT_HEAD=400/TEXT_TAIL=150), src/request.ts (SYSTEM_ONE_URL, DEFAULT_MODEL, buildJevRequest, parseJevResponse, noulAnswer), hooks/fast-jev.ts (compactAtPercent, minReductionRatio, repli en cas d’exception)
  • Données du dépôt : 3 206★, MIT, créé le 2026-09-17, npm 0.2.0, liste de plugins 0.3.0, 25 fichiers environ 1850 lignes (au 2026-09-19)
广告 · Advertisement

Questions fréquentes

Que fait fast-jev-compaction ?

Un plugin Claude Code : il prend en charge l'étape de compression de contexte, sans rédiger de résumés, uniquement des suppressions. Chaque tool_use et tool_result sont appariés par tool_use_id. Après compression, chaque appel d'outil n'a que trois issues : conservation complète, conservation de l'appel sans le résultat (le résultat est tronqué à 300 caractères avec une note), ou disparition complète de la paire. Le dépôt compte 25 fichiers et environ 1850 lignes de TypeScript, créé le 2026-09-17, obtenant 3206 étoiles en deux jours.

Comment fonctionne son mécanisme de décision ?

L'état (state) envoyé à Jev (modèle probabiliste commercial de TypeSafe) est la conversation complète : les résultats des outils sont remplacés par une courte note, les entrées d'outils sont entièrement sérialisées, le texte est conservé en intégralité, dégradé en quatre paliers au-delà de 25000 tokens. Chaque appel non épinglé (pinned) reçoit deux questions noul : est-il important de savoir que cet appel a été lancé, et le texte original du résultat est-il indispensable ? Les questions sont posées par lots concurrents selon un budget de 30000 tokens. Si la probabilité keepResult dépasse 0,5, la paire est conservée ; sinon, si keepCall dépasse 0,5, l'appel est conservé et le résultat tronqué ; si aucun ne dépasse, la paire est supprimée. Le premier message et les 6 derniers messages sont épinglés et jamais traités.

Quels sont les coûts et les limites par rapport à la compression par résumé officielle ?

Il y a quatre coûts : le nombre de tokens est une estimation de caractères et non un vrai tokenizer ; « une probabilité n'est pas une preuve de suppression sûre », le seuil de 0,5 est empirique et non une ligne de sécurité ; l'état est renvoyé en intégralité à chaque requête, près de la limite historique, il faut une requête toutes les quelques questions ; la qualité de la compression n'a pas de chiffres de référence tiers, et le dépôt n'a que deux jours d'historique, étroitement couplé aux premiers hooks de Claude Code. L'état est la conversation complète incluant le code et les erreurs, il ne convient pas à ceux qui ne veulent pas envoyer de données à une API tierce.