BLOG
fast-jev-compaction 解析:Claude Code の圧縮で要約生成を諦めさせる
技術解説:AI技術フレームワークの解析——説明、分析、技術評価、価値判断、実運用。著者:永亮
2026年9月19日、tamaratran/fast-jev-compaction はGitHubで3,206個のスター(9月19日時点)を獲得しており、TypeScriptで書かれ、MITライセンスの下で提供されています。リポジトリは2026年9月17日に作成されました——つまり2日前です。npmパッケージのバージョンは0.2.0、Claude Codeプラグインマニフェストは0.3.0で、リポジトリ全体で25ファイル、ソースコードとフック、テストを合わせて約1850行、コアのsrcは約960行、最大の単一ファイルはcompact.tsで309行です。Claude Codeのコンテキスト圧縮(compaction)はデフォルトでモデルに要約を書かせて古い履歴を置き換えますが、要約は情報を損ないます——ファイルパス、正確なエラー、制約条件などが失われる可能性があります。このプラグインは要約を書かず、削除のみを行い、削除された内容はペアごとに消えるか、原文が保持されます。この記事では、6つの項目に分けて解説します:何か、どこが痛いのか、仕組みの変換、ソースコードで見るべき3箇所、境界とコスト、価値はあるかどうか。
一、これは何か
fast-jev-compaction はClaude Codeのプラグインです:コンテキスト圧縮のステップを引き継ぎ、「要約を書く」ことを「ペアごとの裁定」に置き換えます。圧縮後の履歴にはモデルによる要約の段落はなく、各ツール呼び出しの結末は3つしかありません——完全保持、呼び出しのみ保持して結果は破棄、呼び出しと結果が一緒に消える。判断の根拠は文章ではなく、2つの確率です。
これを理解するには、依存しているモデルを知る必要があります。JevはTypeSafe社の商用モデルで、製品ラインは「system one」と呼ばれます:テキストを逐次生成するのではなく、与えられた一連の質問に対してそれぞれ確率を出力し、エージェントが迅速に分岐できるようにします。どの文をどの文に繋ぐべきか、どの結果をコンテキストに残すべきか、といった「イエスかノーか」の分岐点に対して、直接数値を返します。Jev自体は3日前に登場したばかりの新事物です——この3日間でGitHubに少なくとも5つのjev系リポジトリが登場し、browser-use/jev-ultrafastは5,487個のスターを獲得しており、その中で最も急成長しているものの1つです。1つのモデルが一連の関連プロジェクトを生み出していることは、「確率モデルを使ってエージェントの軽量な意思決定を行う」という方向性が台頭しつつあることを示しており、fast-jev-compactionはこの流れの中で最も完全なエンジニアリングサンプルです。Jevの内部設計はTypeSafeによって公開されていませんが、この記事ではプラグインがそのインターフェースをどう使っているかに焦点を当て、架空のアーキテクチャについては述べません。
二、解決すべき真の痛点
長時間会話を行うエージェントのコンテキストウィンドウは限られており、満杯に近づくと圧縮が必要です。主流のアプローチはLLMに要約を書かせることです:モデルに古い履歴を読ませ、要約版を書いて原文を置き換えます。要約の本質は、モデルが未来の自分のためにノートを取らせることです——何を記録し、何を捨てるかは生成プロセスによって決定され、エラーが発生しても痕跡が残りません。ファイルパスが近似パスに書き換えられたり、正確なエラーメッセージが「エラーがあった」と概括されたり、ユーザーが指定した制約(「このファイルを触らないで」)が圧縮時に失われたりする可能性があります。さらに厄介なのは、圧縮後に何が失われたかを確認する手段がなくなり、3時間後にモデルが誤った要約に基づいて間違ったファイルを変更したとしても、その責任をその圧縮にまで遡るのは困難です。
このプラグインは痛点の分析を非常に冷静に行っています:コンテキストの大部分はチャットテキストではなく、ツール呼び出しとツールの結果です——1回のファイル読み取りで数千文字、1回のテスト出力で上万文字、数十ラウンドも経過すれば、それらが9割のスペースを消費します。そして本当に判断が必要なのは、「この呼び出しは今後のことにまだ重要か」ということです。これは選択問題であり、記述問題ではありません。選択問題は確率を出力するモデルに任せることができ、回答は1件ずつ記録できます。記述は捏造しますが、選択問題は少なくとも誠実です。
三、仕組み:ペアリングから再構築まで
3.1 ペアリングとpinned
最初のステップは、会話を裁定可能な単位に分解することです。各 tool_use と対応する tool_result を tool_use_id でペアにします——削除時に呼び出しと結果は運命を共にし、再構築後に呼び出しのない宙ぶらりんな結果が現れることはありません。最初のメッセージと最新の preserveRecentMessages 件(デフォルト6)は pinned としてマークされ、永遠に処理されず、会話の冒頭と現在が常に完全であることを保証します。
3.2 Jevへ送るstateの構築
Jevに送信される state は完全な会話で、最も古いものが先頭です。すべてのツール結果は1行の短い注釈(ok, 4213 chars (omitted) のような形式)に置き換えられ、Jevに対して「ここで成功した読み取りが行われ、原文は4213文字である」ことを伝えます。ツールの入力は完全に state にシリアライズされます。ユーザーとアシスタントのテキストは全量保持され、要約されません。state 自体にも maxStateTokens(デフォルト25000)というサイズ上限があり、超過する場合は段階的にダウングレードされます:ツールの入力は順に1000、200、60文字に切り詰められます。長いテキストは先頭400文字と末尾150文字を保持します。それでも足りない場合は、最も古いメッセージから [… N chars omitted …] に折りたたまれ、古いツール呼び出しは1行に圧縮されます(t12 Read file_path=src/a.ts → ok 480ch のような形式)。pinned されたメッセージは最後に変更されます。すべての段階を経ても収まらない場合は、例外をスローし、無理に押し込みません。トークン数は文字推定です:英字6文字で約1トークン、数字は半分、その他の記号はそれぞれ約1個——真のトークナイザではなく、安価で、トークン化の依存関係も持ち込みません。
3.3 2つのnoul問題とバッチ処理
pinned されていない各呼び出しに対して、プラグインはJevに2つの質問をします。call_X:「この呼び出しが行われたこと、そしてどのような入力を伴っていたかを知っていることが、今後のことに重要か」。result_X:「この結果は原文を保持する必要があるか、ツールを再実行することでは代替できないか」。どちらも noul タイプです——Jevはテキストを返さず、各質問に対して1つの確率を吐き出します。
質問はサイズに基づいてバッチ処理されます。maxRequestTokens はデフォルトで30000(Jevの単一リクエスト上限は32000)で、state が占める分と20トークンのリクエストエンベロープのオーバーヘッドを差し引いた残りの予算が、1バッチで持てる質問数です。state はバッチごとに全量再送され、バッチ内のすべての質問は1つのリクエストにマージされ、各バッチは並列で送信され、回答はマージされます。state が大きくなるほど、1バッチに詰め込める質問数は減り、極端な場合は数件の質問ごとにリクエストを送る必要があります——これは設計上のコストであり、境界の節で展開します。
3.4 決定と再構築
決定ルールは1行で書けます。decideCall は順番に判断します:pinned は直接保持。keepResult が閾値(デフォルト0.5)以上ならペアごと保持。そうでなければ keepCall が閾値以上なら、呼び出し自体を保持し、結果は先頭 truncateHeadChars(デフォルト300)文字を残して切り詰め、1行の説明を付け加えます——説明には何文字切り詰めたか、エラーかどうか、必要ならツールを再実行できることが明記されます。両方の確率が閾値を超えない場合、呼び出しと結果はペアごと削除されます。
再構築は applyDecisions によって行われます:内容がすべて削除されたメッセージは行ごと削除され、変更されなかったメッセージはそのまま返されます(同じオブジェクト、ゼロコピー)、部分的に変更されたメッセージはその場で置換されます。入出力の全プロセスは、構造化された決定と再確認可能な統計(各決定のカウント、圧縮前後の文字数、stateの推定トークン数、使用したダウングレード段階、送信したリクエスト数)であり、散文ではありません。
四、ソースコードで見るべき3箇所
4.1 compact.ts のバッチ処理と決定関数
compact.ts は309行で、リポジトリ内最大のファイルであり、メインとなる関数は4つだけです。questionsFor(compact.ts:56)は各呼び出しに対して2つのnoul問題を生成し、問題文にツール名、呼び出しID、結果の文字数を織り込み、Jevが判断する際の根拠とします。batchCalls(compact.ts:73)はバッチ処理を行い、予算アルゴリズムは透明です:maxRequestTokens から state と20を引き、収まるだけ詰め込みます。単一の呼び出しの問題自体が予算を超えている場合は、state が大きすぎることを意味し、例外をスローしてエラーメッセージに「state が30000のうちの約どれくらいを占めているか」を明記します。decideCall(compact.ts:101)は全体で最短の部分です——pinned、keepResultの閾値、keepCallの閾値、else 削除、の4行です。applyDecisions(compact.ts:149以降)は再構築を担当し、コメントは不変量を非常に明確に記述しています:削除された呼び出しは結果と共に消え、結果を削除して保持する場合は有界なヘッダと説明を残し、内容を失ったメッセージは削除し、変更されなかったメッセージは元のオブジェクトを返します。
4.2 request.ts のエンドポイントとnoul解析
request.ts はわずか80行で、インターフェース契約のすべてです。SYSTEM_ONE_URL は https://api.typesafe.ai/v1/systemone を指し、デフォルトのモデル名は jev-latest です。buildJevRequest は model、state、questions を1つのPOSTにパッケージ化します。parseJevResponse はレスポンスボディに対して厳格な検証を行います:HTTPがOKでなければエラー、JSON解析失敗でエラー、answers フィールドが欠けていればエラー。noulAnswer は単一の回答の noul フィールドを取得し、フィールド欠如、数値以外、有限数以外の場合はすべて例外をスローします。ファイル全体に静かなエラー処理はありません——すべての失敗は例外となって上位に伝播し、呼び出し元がフォールバックを決定します。
4.3 フックのトリガー条件
hooks/fast-jev.ts はClaude Codeからのコールバックを受け取る薄いアダプタ層です。function hooks はClaude Code 2.1.274+の初期機能であり、settings.json で opt-in する必要があります。有効にすると、プラグインは turn.complete 時にコールバックされ、現在のコンテキスト使用率を確認し、compactAtPercent(デフォルト60%)に達して初めて圧縮をトリガーします。トリガー後、まず1ラウンドの推定を行い、圧縮率が minReductionRatio(デフォルト25%)に満たない場合は履歴を置き換えず、判断だけ行って終わるという無駄なことはしません。Jevサービスのダウン、回答の異常、TYPESAFE_API_KEY の欠如、state の容量超過など、いかなる例外も無理にせず、Claude Codeの組み込み要約圧縮にフォールバックします。設定はすべてプラグインの userConfig で行えます:閾値、保持件数、切り詰め長、モデル名が個別に変更可能です。
五、境界とコスト
公式のLimitationsは4つあり、そのまま転記します。第一、ツール呼び出しのみを処理し、テキストメッセージは出力側では決して短くされません(それらはJevが見る state でのみ短縮されます)——コンテキストがチャットテキストによって肥大化している場合、このプラグインは役に立ちません。第二、トークン数は文字推定であり、真のトークナイザではないため、予算の判断には誤差があります。第三、原文を丸ごと覚えておくべき言葉があります:「1つの確率は安全に削除できる証明ではなく、アシスタントは常にツールを再実行できる」——0.5の閾値は安全ラインではなく、経験則です。第四、state はリクエストごとに全量再送されるため、履歴が上限に近づくと数件の質問ごとにリクエストが必要になり、トークンコストは履歴の長さに比例して増加します。ヘビーユーザーはこの計算を理解しておく必要があります。
疑問点は3つあり、断定せず疑問点として記述します。決定の品質はJevという1つの商用モデルの確率キャリブレーションに完全に依存しており、リポジトリには統合テストのベンチマーク数値がなく、READMEにはベンチマーク表がなく、圧縮の良さを確認できる第三者のメトリクスもありません。プラグインのエコシステムはClaude Codeのバージョンと強く結合しており、function hooks 自体が2.1.274+の初期機能であるため、インターフェースが変更されればプラグインも追随する必要があります。リポジトリの歴史は2日しかなく、本番環境での長時間会話のパフォーマンスは誰も検証しておらず、2日で3,206スターは概念の人気であり、安定性の保証ではありません。
六、価値と適用対象
これは「コンテキスト圧縮」という古い問題に対する新しい解決策です——要約という記述問題を選択問題に変え、その代償として意思決定権を商用の確率モデルにアウトソースします。明らかに適している人々はいます:毎日Claude Codeで長時間会話を行い、要約によってコンテキストを失って痛い目を見た人、npmパッケージと環境変数を設定するだけで試せるコストは低いです。エージェントエンジニアリングやコンテキスト管理の研究をしている人、このリポジトリの1850行は一晩で読み切れ、確率モデルをエージェントの意思決定ループに組み込むクリーンなサンプルです。明らかに適していない人々もいます:会話データをサードパーティAPIに送りたくない人——state は完全な会話であり、あなたのコードとエラーが含まれます。会話自体が長くなく、組み込みの要約で十分な人。検証可能な圧縮品質の保証を必要とするチーム、READMEにベンチマークがないため、現在その保証は提供できません。
筆者の見解:Jevを使わなくても、このアイデアは移植できる可能性が高いです。noul問題の本質は一連のオプションにスコアを付けることであり、logitsを出力できる小さなモデルなら何でもこなせます——ローカルで3Bクラスの小さなモデルを走らせ、call_X と result_X の2つの質問に対して「イエス」の確率を出力させ、Jevのリモート呼び出しを置き換えれば、データはマシンから出ず、呼び出しコストはゼロになります。代償はキャリブレーションの品質が保証されず、閾値を自分で調整する必要があることです。このプロジェクトで本当に持ち帰るべき価値はプラグインそのものではなく、この質問の仕方かもしれません:コンテキストを圧縮するのにモデルに作文をさせる必要はなく、選択問題をさせ、確率閾値に基づいて実行すればよいのです。
結論
fast-jev-compaction は約1850行のコードで1つの問いに答えています:コンテキスト圧縮は必ず要約を書く必要があるのか? その答えは「いいえ」です。ツール呼び出しは長時間会話のコンテキストの大部分を占めており、「残すか削除するか」は選択問題であり、Jevのようなオプションの確率を出力するモデルに答えさせることができます。ソースコードでは、この判断は非常に具体的に実装されています:呼び出しは tool_use_id でペアにされ、最初と最新の6件は pinned されて永遠に処理されず、state は完全に構築され、ツール結果は短い注釈に置き換えられ、超過時は4段階でダウングレードされます。各呼び出しには2つのnoul問題が投げかけられ、30000トークンの予算に基づいてバッチ並列処理され、0.5の閾値で keep / drop_result / drop_call の3段階を裁定し、再構築時に宙ぶらりんな結果がないことを保証します。フック側では turn.complete で60%の使用率を確認してトリガーし、圧縮率が25%未満なら置き換えを諦め、失敗時は組み込み要約にフォールバックします。コストも明確です:トークンは推定値であり、確率は削除の安全性の証明ではなく、state は全量再送され、品質にはベンチマーク数値がありません。2日で3,206スターは概念の人気であり、それはJevという3日前の新事物と同じ船に乗っています——エージェントのコンテキスト管理を行う人々にとって、これは読む価値のあるソースコードです。一般ユーザーにとっては、いくつかのバージョンが経過するのを待った方がよいでしょう。
参考情報
- tamaratran/fast-jev-compaction README(位置づけ、設定表、Limitations、Claude Codeプラグイン説明、function hooksバージョン要件)
- ソースコード(ローカルclone):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、例外フォールバック)
- リポジトリデータ:3,206★、MIT、2026-09-17作成、npm 0.2.0、プラグインマニフェスト 0.3.0、25ファイル約1850行(2026-09-19時点)