Skip to content

セッションの永続化

アシスタントは終了時にセッションの状態を自動的に保存し、次回の起動時に再開するかどうかを尋ねます。 これにより、セッション間の連続性が確保されます。アシスタントは、どのファイルが存在していたか、またそれらが変更されたかどうかを把握しているため、前回のセッションの続きから再開できます。

Agent Assistのメモリー

LLM自体は会話を記憶しません。 保存すべきサーバー側のチャットや会話IDはありません。 LLMの観点から見ると、アーキテクチャはステートレスです。

  • pydantic-ai + OpenAI互換API:エージェントは、DataRobot LLM Gatewayを介してOpenAI Chat Completions APIと通信するOpenAIChatModelを使用します。 このAPIはステートレスです。サーバー側の会話スレッドはありません。 すべてのリクエストでは、リクエスト本文にメッセージの全履歴が送信され、サーバーはそれ以前のやり取りを一切記憶していません。

  • message_history:これは、完全にクライアント側で管理されるlist[ModelMessage]です。 agent.iter(user_input, message_history=message_history)を呼び出すたびに、完全な履歴がLLMに送信されます。 応答が届くと、agent_run.all_messages()は新しいやり取りも含めた更新後のリストを返します。 このプロセスにおいて、サーバーは「チャットID」や「会話ID」を追跡したり、考慮したりすることはありません。

つまり、次のようになります。

  • プロセスが終了すると、message_historyリストは消滅し、LLMは会話を記憶しません。
  • 会話が再開された際に、生の履歴をすべて再生し直すことは、トークンの制限やツールの結果が古くなっていることなどの理由から、高コストで脆弱になります。
  • セッションの継続性は、圧縮コンテキストの注入によって実現されます。つまり、会話が再開される際、その会話における行動や決定事項の要約が、システムのプロンプトに注入されます。

セッションの永続化の詳細

セッションの永続化により、会話履歴は圧縮された形式で保存されます。具体的には、最近のメッセージの末尾部分と、それ以前のやり取りの要約、および軽量なメタデータが含まれます。 再開時、アシスタントはこのデータから(reconstruct_history() を通じて)トリミングされた message_history を再構築し、システムプロンプトに再開コンテキストブロックを注入します。 追跡される軽量なメタデータは以下のとおりです。

アーティファクト 目的
セッションIDとタイムスタンプ 識別情報と最新性 - 「最後に会話したのはいつですか?」
agent_spec.mdのパス ユーザーがエージェントを設計していたかどうか。
ファイルマニフェスト(SHA256ハッシュ) アシスタントがオフラインの間にファイルが変更されたかどうかを検出します。 マニフェストに含まれていないファイルは検出されません(検出するにはワークスペース全体のスキャンが必要となります)。
_session_deleted セッションがユーザーによって削除されたかどうか。

コンテキストの注入

エージェントの会話が再開されると、build_resume_context()は以前に保存されたセッション状態からテキストブロックを構築し、pydantic-aiの@agent.system_prompt(dynamic=True)デコレーターを使用して、それをエージェントのシステムプロンプトに注入します。 このデコレーターはエージェントの実行ごとに再評価されるため、以下のようになります。

  • 再開時:エージェントはセッションのコンテキスト(ID、タイムスタンプ、ファイルの変更、要約、決定事項)を確認できます。
  • /resetの後:動的プロンプトは""を返し、エージェントは何も認識しません。
  • 通常の操作中:プロンプトは起動時に設定された内容を返します。

このブロックは、エージェントに過去のセッションに関する情報を認識させるための、ユーザーには見えないシステムプロンプトの内容として機能します。

セッションライフサイクルの詳細

終了したセッションが再開されると、次のようなブロックがシステムプロンプトに注入されます(ユーザーには見えません)。

# Resumed Session Context
This is a resumed session (ID: a1b2c3d4e5f6).
Originally started: 2026-03-30 10:15 UTC
Last active: 2026-03-31 14:22 UTC

Agent specification file: agent_spec.md

## Previous Session Summary
User designed a customer support agent with three tools. Model selection
was GPT-5 via the DataRobot model catalog. Spec was saved but not yet
implemented in code.

## Key Decisions Made
- Selected GPT-5 as the agent model for strong reasoning capability
- Chose REST API tools over SDK wrappers for portability
- Deferred authentication configuration to implementation phase

## File Changes Since Last Session
- agent_spec.md: modified

IMPORTANT: You are resuming a previous session. Review the context above
before proceeding. If the user's request seems to continue prior work,
use this context. If they start a new topic, proceed normally. 

/reset/new)を実行すると、このブロックは消え、動的プロンプトは空の文字列を返します。

新規起動(以前のセッションなし)

以前のセッションが存在しない場合、エージェントが初めて起動するとき

  1. 起動時に、SessionState()はランダムな12文字の16進数IDを持つ新しいセッションを作成します。
  2. ユーザーはエージェントとやり取りします。
  3. 終了時、SessionLifecycle.snapshot_and_save()は現在のファイルマニフェストを取得し、その後、SessionManager.save()がセッションファイルとactive_{pid}.jsonポインターを書き込みます。

再開(既存のセッション)

エージェントが以前のセッションを再開する場合

  1. 起動時、SessionManager.load()active_{pid}.jsonを読み取り、指定されたセッションファイルをロードします。
  2. ユーザーには、前回のセッションを再開するかどうかを尋ねるプロンプトが表示されます。

    Previous session found (last active: 2026-03-31 14:22 UTC)
    Resume previous session? [Y/n] 
    

  3. はい:既存のSessionStateが引き継がれます(同じID、ディスク上の同じファイル)。 build_resume_context()は、セッション情報とドリフト検出結果を使用してシステムプロンプトブロックを構築します。

  4. いいえ:新しいSessionState()が作成されます。 古いセッションファイルは孤立したファイル(小、<1KB)としてディスクに残ります。 新しいセッションの終了時の自動保存により、active_{pid}.jsonが新しいIDを指すように更新されます。
  5. 構築されたシステムプロンプトは、pydantic-aiの@agent.system_prompt(dynamic=True)を使用してエージェントに注入されます。

セッションのリセット

ユーザーが/reset/new)を実行した場合

  1. agent_spec.mdまたはテンプレートディレクトリが存在する場合、削除前にユーザーに確認が求められます。
  2. ファイルが存在しない場合でも、/resetは常に次の処理を行います。
  3. メモリー内の会話履歴(message_history = None)をクリアします。
  4. 新しいIDを持つ新規のSessionState()を作成します。
  5. 永続化されたセッションファイルとactive_{pid}.jsonポインターを削除します。
  6. システムプロンプトから動的再開コンテキストをクリアします。
  7. 終了時の自動保存による復活を防ぐために、_session_deleted = Trueを設定します。
  8. /resetの後にユーザーが対話を続けた場合、エージェントの最初の応答が成功すると、自動保存が再び有効になり(_session_deleted = False)、新しいセッションが保持されます。

セッションの保存

ユーザーが/saveを実行した場合

  1. SessionLifecycle.explicit_save()agent_spec_pathを更新し、現在のワークスペースからfile_manifestを再構築します
  2. SessionManager.save() writes the session file and updates active_{pid}.json
  3. 以前の/resetによって無効になっていた場合、自動保存を再度有効にします

セッション終了(自動保存)

通常のシャットダウン、Ctrl+C、またはクラッシュによりエージェントが終了した場合

  1. chat()内のfinallyブロックは、終了、Ctrl+C、またはクラッシュ時に実行されます。
  2. _session_deletedTrueの場合(その後の対話なしで/resetによって設定された場合)、自動保存はスキップされます
  3. それ以外の場合は、ワークスペースの状態のスナップショットを作成して永続化します。

セッションのスラッシュコマンド

アシスタントは、セッション管理用の次のスラッシュコマンドをサポートしています。

Command 説明
/save セッションのチェックポイントをただちに作成します。 書き込む前に、現在のagent_spec.md状態とファイルマニフェストのスナップショットを作成します。
/reset (/new) 常に会話履歴をクリアし、保存されたセッションを削除し、システムプロンプトから再開コンテキストを削除します。 agent_spec.mdまたはテンプレートディレクトリが存在する場合は、削除する前に確認を求めます。 次のエージェントターンは完全にクリーンな状態で開始されます。
/checkpoint セッションのチェックポイントを一覧表示するか、番号を指定して復元します(/checkpoint [number])。
/compact 会話履歴を圧縮してトークンの使用量を減らします。
/resume セッションのシステムプロンプトに現在注入されている再開コンテキストを表示します。

ファイルドリフト検出

再開時に、アシスタントは追跡対象ファイルのSHA256ハッシュを保存されたマニフェストと比較します。 これにより、次の3つのケースが検出されます。

  • 変更なし:ハッシュが一致します。カウント(「1つの追跡対象ファイルが変更されていません」)として報告されます。
  • 変更あり:ファイルは存在しますがハッシュが異なります。<file>: modifiedとしてリストされます。
  • 削除済み:ファイルはマニフェストにありましたが、現在は存在しません。<file>: deletedとしてリストされます。

ファイルドリフト検出

マニフェストにない新しいファイルは検出されません(それには完全なワークスペーススキャンが必要になります)。

これにより、セッション間でアシスタントの外部でワークスペースファイルが変更されたときに、アシスタントがユーザーに警告する(または自身の動作を調整する)ことができます。

コンポーネントマップ

次のコンポーネントはセッション管理を担います。

コンポーネント 位置 役割
SessionState session/models.py Pydanticモデル—永続化された状態のスキーマ。
SessionManager session/manager.py セッションJSONファイルのCRUD操作。
SessionLifecycle session/lifecycle.py セッション状態、メッセージ履歴、再開コンテキスト、および削除フラグを保持します。状態遷移の不変条件を強制します。システムプロンプト注入用の再開コンテキストを構築します。
ファイルシステムヘルパー helpers/filesystem.py SHA256ハッシュ、パス検証、マニフェスト構築、ドリフト検出。
パスヘルパー helpers/paths.py プロジェクト設定のパスからディレクトリ名への解決。
確認UI ui/confirm.py 破壊的アクションの確認ダイアログ(循環インポートを断ち切るために分離されています)。
メインループ main.py ライフサイクルオーケストレーション(再開プロンプト、SessionLifecycleへの委譲)。
コマンドハンドラー commands/handlers.py /saveおよび/resetセッション操作。
CommandContext commands/base.py セッション参照をコマンドハンドラーに伝達します。

ストレージレイアウト

セッション状態は、プロジェクト設定ディレクトリの~/.config/datarobot/agent_assist/projects/<name>_<hash>/sessions/に保存されます。

~/.config/datarobot/agent_assist/projects/
  my-project_a1b2c3d4/
    sessions/
      a1b2c3d4e5f6.json   # per-session state file
      active_<pid>.json    # pointer to current session (one per terminal PID) 

各セッションファイルには次のフィールドが含まれています。

フィールド 説明
schema_version 前方互換性のためのスキーマバージョン(現在は3)。
session_id 12文字の16進数識別子。
created_at セッション作成のUTCタイムスタンプ。
updated_at 最終保存のUTCタイムスタンプ。
agent_spec_path エージェント仕様への相対パス、またはnull。
file_manifest 追跡対象ファイルの{relative_path: sha256_hex}
summary LLMが抽出した以前のセッションのナラティブサマリー、またはnull。
decisions 以前のセッションから抽出された主な決定事項。
recent_messages 再開時に再構築された、シリアル化された最近の会話メッセージ(圧縮の末尾)。
compacted_history_summary 圧縮された古いメッセージのサマリー、またはnull。
checkpoint_count セッションに書き込まれた最新のチェックポイント番号(情報提供のみ。ライブファイルカウントではありません)。
phase 現在の会話フェーズ(設計 / コード / デプロイ)、またはnull。

セキュリティ

  • パストラバーサル保護:すべてのマニフェストパスは、ファイルI/Oの前にワークスペースディレクトリ内で解決されるように、(helpers/filesystem.pyの)is_safe_relative_path()を介して検証されます。 ../シーケンスを含む改ざんされたマニフェストは、暗黙のうちにスキップされます。
  • シンボリックリンクの拒否build_file_manifest()およびdetect_file_drift()は、TOCTOU(time-of-check-to-time-of-use)シンボリックリンク攻撃に対する多層防御としてシンボリックリンクをスキップします。 セッション間にシンボリックリンクに置き換えられたファイルは、削除済みとして報告されます。
  • セッションIDの検証:セッションIDは、ファイルパスを構築する前に厳密な^[a-f0-9]{12}$正規表現に対して検証され、巧妙に作られたポインターファイルによるパスインジェクションを防ぎます。
  • セッションファイルにシークレットが含まれない:セッション状態にはメタデータ(タイムスタンプ、ハッシュ、パス)のみが含まれます。 APIキー、会話のコンテンツ、およびユーザー入力は永続化されません。