メインコンテンツへ移動
AIチュートリアル

fast-jev-compactionでClaude Codeのコンテキストを正確に保持する

fast-jev-compactionをnpmライブラリまたはClaude Codeプラグインとしてインストールし、使用する方法を学びます。このチュートリアルでは、Jevに基づく判断、設定オプション、カスタムトランスポートのサポート、失敗時の動作、重要なテキストを逐語的に保持しながら長いトランスクリプトを安全に短縮する手法について説明します。

fast-jev-compactionでClaude Codeのコンテキストを正確に保持する

fast-jev-compactionの機能

fast-jev-compactionは、長いエージェントのトランスクリプトを要約に書き換えずに短縮するためのnpmライブラリおよびClaude Codeプラグインです。代わりに、Jevモデルに古いツール呼び出しとツール結果をスコアリングさせ、設定可能なしきい値に従って保持、切り詰め、または削除します。

ユーザーとアシスタントのテキストは、元の順序のまま完全に保持されます。削除候補になるのは、ツール呼び出しと、それに対応する結果だけです。これにより、従来の要約で正確な制約、ファイルパス、コマンド、エラーメッセージが失われることを防ぎます。

リポジトリには、src/に再利用可能なパッケージ、hooks/と.claude-plugin/にClaude Codeの関数フックプラグインが含まれています。

短縮の仕組み

  1. 各tool_useは、tool_use_idを通じて対応するtool_resultとペアになります。

  2. 最初のメッセージ内の呼び出しと、最新のpreserveRecentMessages件のメッセージ内の呼び出しは固定され、変更されません。

  3. 完全な会話は、古いものから新しいものの順でJevに提示されます。この判断用の状態では、ツール結果の内容はok, 4213 chars (omitted)のような短い注記に置き換えられますが、ツール入力とテキストは利用できます。

  4. 固定されていない各呼び出しについて、Jevは2つの質問に答えます。その呼び出しを知っていることが今も重要か、そして完全な結果を逐語的に利用可能な状態で残す必要があるか、です。

  5. 返された確率をkeepThresholdと比較します。

  6. 孤立した結果を残さないようにトランスクリプトを再構築します。

判断結果

  • 結果のスコアがしきい値以上の場合、呼び出しと完全な結果の両方を保持します。

  • 呼び出しのスコアだけがしきい値以上の場合、呼び出しを残し、結果は先頭のtruncateHeadChars文字に注記を続けたものへ短縮します。

  • どちらのスコアもしきい値未満の場合、呼び出しと結果を一緒に削除します。

空になったメッセージは削除されます。変更が不要なメッセージは、同じオブジェクトとして返されます。

大きな履歴をJevのリクエストに収める

判断用の状態には、推定トークン数でデフォルトの上限25000があります。元の状態が大きすぎる場合、ライブラリはJevに表示する表現を段階的に短縮します。ツール入力を切り詰め、長いテキストを先頭と末尾を使って簡略化し、古いメッセージを折りたたみ、古い呼び出しを1行の記録に減らし、呼び出しのない古いメッセージを省略し、呼び出しだけを含む古いメッセージの連続をまとめます。

これらの変換はスコアリングに使う状態に影響しますが、最終的なトランスクリプトで保持されるテキストには影響しません。それでも状態を収められない場合、短縮処理はエラーをスローします。

質問もバッチに分割されるため、状態と質問を合わせた各リクエストは、デフォルトで30000に設定されているmaxRequestTokens未満に収まります。リクエストは同時実行され、判断結果は統合されます。

npmライブラリをインストールする

パッケージをインストールし、環境変数を通じてTypeSafe APIキーを指定します。

npm install fast-jev-compaction
export TYPESAFE_API_KEY=...

APIキーをコミットしたり、ソースファイルに直接記述したりしないでください。

デフォルトのクライアントはprocess.env.TYPESAFE_API_KEYを読み取ります。APIを呼び出す際にapiKeyオプションを指定することもできます。

トランスクリプトを短縮する

compactMessagesをインポートし、トランスクリプトを準備して、デフォルトと異なるオプションを渡します。

import {
  compactMessages,
  reductionRatio,
  type Message,
} from 'fast-jev-compaction';

const transcript: Message[] = [
  {
    role: 'user',
    text: 'Fix the failing test. Never edit src/generated.',
    toolUses: [],
  },
  {
    role: 'assistant',
    text: '',
    toolUses: [
      {
        tool_use_id: 'toolu_1',
        tool: 'Read',
        input: { file_path: 'src/a.ts' },
      },
    ],
  },
  {
    role: 'user',
    text: '',
    toolUses: [],
    toolResults: [
      { tool_use_id: 'toolu_1', text: '…file contents…' },
    ],
  },
];

const result = await compactMessages(transcript, {
  preserveRecentMessages: 4,
});

console.log(result.messages);
console.log(result.decisions);
console.log(result.stats);

エクスポートされるMessage型はClaude CodeのSessionMessageのサブセットであるため、Claude Codeのセッション・トランスクリプトをそのままパッケージに渡せます。

短縮する価値があったか確認する

このパッケージがエクスポートするreductionRatioを使うと、短縮した履歴を使用するかどうかをアプリケーションで判断できます。

const result = await compactMessages(transcript);

if (reductionRatio(result) < 0.25) {
  // Keep the original transcript or use another fallback.
} else {
  // Continue with result.messages.
}

結果の統計には、短縮前後のメッセージ数と文字数、理由別にまとめた判断数、推定状態サイズ、使用した収容段階、Jevリクエスト数が含まれます。

短縮動作を設定する

主なオプションは次のとおりです。

  • apiKey: TypeSafe APIキー。デフォルトはTYPESAFE_API_KEYです。

  • model: Jevモデル名。デフォルトはjev-latestです。

  • baseUrl: System Oneエンドポイント。デフォルトはhttps://api.typesafe.ai/v1/systemoneです。

  • fetch: 注入可能なfetch実装。特にテストで役立ちます。

  • goal: 状態に含める継続中のタスクの説明。デフォルトでは、直近3件のユーザープロンプトが使用されます。

  • keepThreshold: 呼び出しまたは完全な結果を保持するために必要な最小確率。デフォルトは0.5です。

  • preserveRecentMessages: 変更できない最新メッセージの数。デフォルトは6です。最初のメッセージも常に保持されます。

  • maxStateTokens: 判断用状態の推定トークン上限。デフォルトは25000です。

  • maxRequestTokens: 1回のリクエストにおける、状態と質問を合わせた推定上限。デフォルトは30000です。

  • truncateHeadChars: 結果を切り詰める際に保持する先頭文字数。デフォルトは300です。

const result = await compactMessages(transcript, {
  goal: 'Fix the test without editing generated files',
  keepThreshold: 0.6,
  preserveRecentMessages: 8,
  truncateHeadChars: 500,
});

keepThresholdを高くすると、より高い保持確率が必要になるため、より多くのツールアクティビティが削除される可能性があります。確率は削除が安全であることの証明ではないため、代表的なトランスクリプトを使ってしきい値の変更を評価してください。

カスタムJevトランスポートを使用する

組み込みのTypeSafeクライアントが環境に合わない場合は、エクスポートされたJevAskerインターフェースを実装してください。ask(state, questions)メソッドが必要です。その後、compactMessagesの代わりにcompact(messages, asker, options)を呼び出します。

このパッケージでは、HTTPリクエストボディを構築するbuildJevRequestと、レスポンスを検証するparseJevResponseもエクスポートしています。より専門的な統合向けに、さらに低レベルの構成要素も利用できます。

  • collectToolCallsは呼び出しとその結果を対応付けます。

  • fitStateは設定されたサイズ上限内に収まるよう状態を準備します。

  • batchCallsは質問を複数のリクエストに分割します。

  • decideCallはスコアを保持、切り詰め、削除の判断に変換します。

  • applyDecisionsはメッセージ履歴を再構築します。

Claude Codeプラグインをインストールする

このプラグインにはClaude Code 2.1.274以降が必要です。関数フックは早期アクセス機能であるため、Claude Codeの実行環境で有効にしてください。たとえば、環境設定を~/.claude/settings.jsonに追加します。

{
  "env": {
    "CLAUDE_CODE_ENABLE_FUNCTION_HOOKS": "1",
    "TYPESAFE_API_KEY": "<your key>"
  }
}

リポジトリをプラグインマーケットプレイスとして追加し、プラグインをインストールします。

claude plugin marketplace add tamaratran/fast-jev-compaction
claude plugin install fast-jev-compaction@fast-jev-compaction

インストーラーでは、しきい値やtruncateHeadCharsなどのオプションが表示されます。APIキーのオプションはデフォルトのままにして、環境変数のTYPESAFE_API_KEYを使用してください。

Claude Codeを再起動するか、次を実行します。

/reload-plugins

有効化すると、/compactと自動コンパクションの両方がJevフックを経由します。置き換えに成功すると、fast-jev-compaction: kept N/M messages, no summary (...)のようなトーストが表示されます。Jevが失敗した場合や削減が不十分な場合、フックはClaude Code組み込みの要約にフォールバックします。

チェックアウトからプラグインを直接実行する

公開やインストールを行わずにリポジトリをテストできます。

CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude --plugin-dir .

このコマンドはリポジトリのルートから実行してください。

高度な使用方法

作業中の内容を保護する

最近のツール出力が再利用される可能性が高い場合は、preserveRecentMessagesを増やしてください。これらのメッセージ内の呼び出しは固定され、削除や切り詰めができなくなります。

明確な目標を指定する

デフォルトの目標は、直近3件のユーザープロンプトから導出されます。長時間にわたるセッションや内容が変化するセッションでは、goalを明示的に設定すると、Jevに継続中のタスクをより明確に伝えられます。

統計情報でフォールバックポリシーを定義する

すべてのコンパクション済み結果を自動的に受け入れるのではなく、result.statsとreductionRatio(result)を確認してください。短いセッションでは、元のトランスクリプトを置き換えるほどの削減が得られない場合があります。

エラーに備える

Jevが失敗した場合、形式の不正なデータを返した場合、必須キーが欠落している場合、または状態上限内に収まらない履歴を受け取った場合、コンパクションは例外をスローします。ライブラリ呼び出しをエラーハンドリングで囲み、必要に応じて元のトランスクリプトを保持するか、別のコンパクション戦略を呼び出してください。Claude Codeフックはすでに組み込みの要約にフォールバックします。

リクエストコストを理解する

フィッティング済みの完全な状態は、質問バッチごとに繰り返し送信されます。そのため、状態上限近くまである履歴では、少数の質問グループごとに大きなリクエストが1回ずつ必要になる可能性があります。上限を調整する際は、result.statsのリクエスト数を確認してください。

ネットワークリクエストなしでテストする

リポジトリのユニットテストでは偽のJev実装を使用し、TypeSafeには一切接続しません。カスタムJevAskerまたは注入したfetch実装を使えば、アプリケーションのテストでも同じ方法を利用できます。

開発コマンド

リポジトリで作業する場合は、依存関係をインストールして利用可能なチェックを実行します。

npm install
npm run typecheck
npm test
npm run build
npm run validate:plugin
TYPESAFE_API_KEY="$(cat ~/.typesafe_key)" npm run demo

demoコマンドは実際のネットワーク接続チェックを実行します。リポジトリには、demo/JevDemo にmacOS SwiftUIアニメーションも含まれています。このアニメーションは用意されたトランスクリプトでコンパクションを表現するもので、APIは呼び出しません。

demo/JevDemo/build.sh

アプリ内でスペースキーを押すと、アニメーションを再生できます。

重要な制限事項

  • 削除または切り詰められるのは、ツール呼び出しとその結果のみです。テキストメッセージは出力内で変更されません。

  • トークン数は、トークナイザーではなく文字パターンから算出した推定値です。

  • Jevの確率は、結果を安全に削除できることを保証しません。ただし、必要に応じてアシスタントが削除されたツール呼び出しを再実行できます。

  • 各リクエストバッチでは状態全体が繰り返し送信されるため、設定した上限に近い履歴ではコストが増加する可能性があります。

まとめ

fast-jev-compactionは、古くなったツールアクティビティを選択的に削除しながらユーザーとアシスタントのテキストを保持することで、情報が失われる会話要約に代わる手段を提供します。アプリケーションレベルの制御にはnpm APIを、自動連携にはClaude Codeプラグインを使用してください。また、付属のしきい値、保持設定、統計情報、フォールバック動作を利用して、ワークフローに合わせてコンパクションを調整できます。