セッション
ADK-Rust におけるセッションは、会話コンテキストの管理を提供し、エージェントが複数のやり取りにわたって状態を維持できるようにします。セッションは、会話履歴(イベント)と、会話全体を通じて保持される任意の状態データを保存します。
概要
セッションは、ユーザーとエージェントの間の 1 回の会話を表します。各セッションは次の特性を持ちます。
- 一意の識別子を持つ
- アプリケーション(
app_name)とユーザー(user_id)に属する - イベントの一覧(会話履歴)を含む
- 状態データ(キーと値のペア)を保持する
- 最終更新時刻を追跡する
セッショントレイト
Session トレイトは、セッションオブジェクトのインターフェースを定義します。
use adk_session::{Events, State};
use chrono::{DateTime, Utc};
pub trait Session: Send + Sync {
/// Unique session identifier
fn id(&self) -> &str;
/// Application name this session belongs to
fn app_name(&self) -> &str;
/// User identifier
fn user_id(&self) -> &str;
/// Access session state
fn state(&self) -> &dyn State;
/// Access conversation events
fn events(&self) -> &dyn Events;
/// Last time the session was updated
fn last_update_time(&self) -> DateTime<Utc>;
}
SessionService トレイト
SessionService トレイトは、セッションを管理するための操作を定義します。
use adk_session::{CreateRequest, GetRequest, ListRequest, DeleteRequest, Event, Session};
use adk_core::Result;
use async_trait::async_trait;
#[async_trait]
pub trait SessionService: Send + Sync {
/// Create a new session
async fn create(&self, req: CreateRequest) -> Result<Box<dyn Session>>;
/// Retrieve an existing session
async fn get(&self, req: GetRequest) -> Result<Box<dyn Session>>;
/// List all sessions for an app/user
async fn list(&self, req: ListRequest) -> Result<Vec<Box<dyn Session>>>;
/// Delete a session
async fn delete(&self, req: DeleteRequest) -> Result<()>;
/// Append an event to a session
async fn append_event(&self, session_id: &str, event: Event) -> Result<()>;
}
リクエストタイプ
CreateRequest
use adk_session::CreateRequest;
use std::collections::HashMap;
let request = CreateRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: None, // Auto-generate UUID if None
state: HashMap::new(), // Initial state
};
GetRequest
use adk_session::GetRequest;
let request = GetRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: "session_abc".to_string(),
num_recent_events: Some(10), // Limit events returned
after: None, // Filter events after timestamp
};
ListRequest
use adk_session::ListRequest;
let request = ListRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
};
DeleteRequest
use adk_session::DeleteRequest;
let request = DeleteRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: "session_abc".to_string(),
};
SessionService の実装
バックエンドの選択
ADK-Rust は複数のセッションサービス実装を提供します。
| 実装 | フィーチャーフラグ | ユースケース |
|---|---|---|
InMemorySessionService | (none) | 開発、テスト、単一インスタンス |
SqliteSessionService | sqlite | 単一ノードの永続化 |
PostgresSessionService | postgres | 本番用リレーショナル永続化 |
RedisSessionService | redis | 低レイテンシのインメモリ永続化 |
MongoSessionService | mongodb | ドキュメント指向の永続化 |
Neo4jSessionService | neo4j | グラフデータベース永続化 |
FirestoreSessionService | firestore | Google Cloud Firestore |
VertexAiSessionService | vertex-session | Vertex AI セッション API |
vertex-session も adk-rust アンブレラクレートによって再エクスポートされます:
[dependencies]
adk-rust = { version = "2.0.0", features = ["vertex-session"] }
VertexAiSessionService
VertexAiSessionService は GA v1 Vertex AI Agent
Engine Session API を通じてセッションを永続化します。Application Default Credentials を使用し、
数値の reasoning-engine ID またはその完全なリソース名のいずれかを受け入れます:
use adk_session::{VertexAiSessionConfig, VertexAiSessionService};
let config = VertexAiSessionConfig::new("my-project", "us-central1")
.with_reasoning_engine("1234567890");
let service = VertexAiSessionService::new_with_adc(config)?;
識別の分離
公開セッション ID は常に CreateRequest に渡された ID、または ID が渡されない場合にローカルで
生成された UUID です。バックエンドは完全な (app_name, user_id, session_id) タプルから Vertex リソース
ID を導出し、バージョン付きの識別子マーカーをセッション状態に永続化します。
| プロパティ | 動作 |
|---|---|
| 論理 ID | create、get、list、append、delete 全体で保持される |
| リモート ID | 完全な識別情報から導出される決定論的な 63 文字の adk1-… ID |
| 識別子マーカー | 保護された状態として保存され、公開セッション状態から削除される |
| 共有推論エンジン | 同じ論理 ID を持つセッションは、アプリとユーザーごとに分離されたままになる |
| 予約済み状態 | create state と event state の差分では識別子マーカーを設定できない |
バックエンドは、すべての ID スコープ付き操作の前に、マーカーと計算された resource ID の両方を検証します。計算された resource にマーカーが存在しない、または一致しない場合は、別のテナントの session ではなく、破損として扱われます。
旧 session の移行
Python ADK および pre-v2 の session は、logical ID を直接使用し、identity marker を省略する場合があります。互換性は、reasoning-engine の parent をどのように選択するかに依存します:
| 設定 | 未マーキングのセッションの動作 |
|---|---|
| 固定されていない reasoning engine | app_name が先頭ゼロなしの正規化された非ゼロの数値 reasoning-engine ID である場合にのみ有効 |
| 固定された reasoning engine | デフォルトでは無効 |
固定エンジンと allow_unmarked_sessions_for_app("app") | そのアプリに対してのみ有効 |
use adk_session::{VertexAiSessionConfig, VertexAiSessionService};
let config = VertexAiSessionConfig::new("my-project", "us-central1")
.with_reasoning_engine("1234567890");
let service = VertexAiSessionService::new_with_adc(config)?
.allow_unmarked_sessions_for_app("legacy-app");
重要: マークのない session は app の所有権を証明しません。固定エンジン互換オプションは、指定された app がその reasoning engine 内の legacy sessions を排他的に所有している場合にのみ有効にしてください。厳密な
user_idの一致は引き続き適用されます。マーク付きの direct resources、予約済みのadk1-namespace、そして computed/direct の曖昧性は fail closed します。
legacy の append_event(session_id, event) API でも、ちょうど 1 つの cached app/user scope が必要です。まず create、get、または list を呼び出すか、append_event_for_identity() を直接使用してください。cache は bounded なので、長時間稼働する process は、scope が evict された後に古い session を再度 get するか list する必要があります。
エンドポイントと event の忠実性
| 場所 | デフォルトエンドポイント |
|---|---|
global | https://aiplatform.googleapis.com |
us | https://aiplatform.us.rep.googleapis.com |
eu | https://aiplatform.eu.rep.googleapis.com |
| リージョナルロケーション | https://LOCATION-aiplatform.googleapis.com |
カスタムエンドポイントは、Google の認可ヘッダーと完全なセッション/イベントペイロードを受け取るため、信頼されたオリジンでなければなりません。コンストラクションは、エンドポイントが userinfo、パス、クエリ、またはフラグメントを含まない HTTPS オリジンでない限り失敗します。テスト用にはループバック HTTP が許可されます。リダイレクトは無効です。
本番環境の境界
| 境界 | デフォルト |
|---|---|
Vertex user_id | 最大 128 Unicode スカラー値 |
| 接続の期限 | 10 秒 |
| Credential-header の期限 | 30 seconds |
| HTTP request の期限 | 120 seconds |
| 長時間実行オペレーションのポーリング | 120 seconds |
| エンコードされた request body | create/append request ごとに 64 MiB |
| デコードされた応答本文 | 1 回の応答あたりおよび 1 回のページ分割リスト操作全体で 64 MiB |
| ページネーション経過時間 | 完全なリスト操作で 120 秒 |
| ページトークン | 64 KiB |
| JSON と Vertex Struct のネスト | 64 レベル |
with_max_request_bytes() は送信ボディのバジェットを変更し、
with_max_response_bytes() は両方の受信ボディのバジェットを変更し、
with_pagination_timeout() はリスト全体の期限を変更します。高いボディ上限は
デフォルトの割り当て保護を弱めます。これらの上限は、
並行呼び出し全体に対してではなく、各 request、response、または list operation ごとに独立して適用されます。
これらはバイト単位のバジェットであり、JSON のパースと base64 デコード後の
プロセス全体のメモリ上限ではありません。
with_credentials() は失敗する可能性があります。これは endpoint を検証し、制限付きで redirect 無効の HTTP client を構築するためです。
recent-event の上限と timestamp の下限は events.list に押し込まれます。
backend は recent-event の上限が満たされるまで descending ページのみを要求し、その後 ascending の時系列順に戻します。num_recent_events = 0
は event-list endpoint を呼び出しません。
create、delete、append の HTTP 408/5xx、transport/body、malformed 2xx、
または無効な successful-result の失敗は、service が mutation を commit した後に発生する可能性があります。これらは
session.vertex.{create,delete,append}_outcome_ambiguous を
retry.should_retry = false 付きで返します。create または delete が operation name を返した後は、
transport/status の失敗や malformed または無効な successful responses を poll する際に
同じ再試行不可の曖昧性 contract を使い、operation name を含めます。
手動で再試行する前に、対象の session、operation、または event list を確認してください。
終端の done: true operation error は、その代わりに既知の失敗結果です。
それは session.vertex.operation_failed とカテゴリ由来の retry hint を保持します。
HTTP 4xx の直接的な rejection のうち 408 以外は、引き続き確定的です。429 は
再試行可能です。operation が受理された後の poll の失敗は、429 を含め、すべて
曖昧で再試行不可です。backend は内部で throttle も retry もしません。
アプリケーションレベルの concurrency と retry policy を見積もるには、現在の Vertex AI
quotas
を使用してください。
無視された GA v1 canary は、Application Default Credentials が設定された既存の reasoning engine に対してのみ実行してください。
これは 1 つの session と 1 つの代表的な event を create および delete します。engine を create または delete することはありません。
ADK_VERTEX_LIVE_TEST=1 \
GOOGLE_CLOUD_PROJECT=PROJECT_ID \
GOOGLE_CLOUD_LOCATION=LOCATION \
GOOGLE_CLOUD_REASONING_ENGINE_ID=REASONING_ENGINE_ID \
cargo test -p adk-session --features vertex-session \
--test session_contract_vertex test_vertex_live_ga_v1_canary \
-- --ignored --exact --nocapture
Canonical Vertex content、Google ADK rawEvent fields、および任意の
rawEvent Struct 値は、静かなデータ損失なしに round-trip します。任意の Struct
値は opaque のままです。reappend は元のすべての key と value を保持し、予約済みの
_adkRust envelope を追加するため、その envelope を削除すると元の
Struct が得られます。既存の malformed な _adkRust key は fail closed します。Google ADK
projection は、Struct に空でない string id、numeric timestamp、および string invocationId と author がある場合でも best-effort です。
互換性のない content、actions、metadata、または optional fields は canonical SessionEvent を拒否しません。
GA v1 FunctionCall と FunctionResponse の wire messages には id がありません。
ID を持つ ADK function parts と、空または非 canonical な Base64 thought-signature
bytes は、損失のない private rawEvent path を使用します。Part.mediaResolution は、
その他すべてが有効な canonical part である場合に、bounded な JSON object を受け入れます。トップレベルの
inlineData/fileData displayName values は、展開済みの GA
wire から受け入れられます。ADK projection はこれらの provider-only fields を省きますが、canonical な sidecar は reappend をまたいでそれらを保持します。private-envelope validation は、integer または Struct-normalized な 1.0 schema versions を受け入れ、省略された proto3 の default scalar fields を空の private 値と同等とみなし、安全な integer/double-normalized な Vertex Struct 値を意味的に比較し、正確な private scalar presence を復元します。
InMemorySessionService
session をメモリ内に保存します。開発、テスト、単一インスタンスのデプロイに最適です。
use adk_session::{InMemorySessionService, SessionService, CreateRequest};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Create the service
let session_service = InMemorySessionService::new();
// Create a session
let session = session_service.create(CreateRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: None,
state: HashMap::new(),
}).await?;
println!("Session ID: {}", session.id());
println!("App: {}", session.app_name());
println!("User: {}", session.user_id());
Ok(())
}
SqliteSessionService
session を SQLite database に保存します。永続化が必要な開発および単一ノードのデプロイに適しています。
use adk_session::{SqliteSessionService, SessionService, CreateRequest};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Connect to database
let session_service = SqliteSessionService::new("sqlite:sessions.db").await?;
// Run migrations to create tables
session_service.migrate().await?;
// Create a session
let session = session_service.create(CreateRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: None,
state: HashMap::new(),
}).await?;
println!("Session persisted: {}", session.id());
Ok(())
}
Note:
SqliteSessionServiceにはsqlitefeature flag が必要です:adk-session = { version = "2.0.0", features = ["sqlite"] }
PostgresSessionService
session を PostgreSQL に保存します。本番のマルチノードデプロイに適しています。
use adk_session::{PostgresSessionService, SessionService, CreateRequest};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let session_service = PostgresSessionService::new(
"postgres://user:pass@localhost:5432/mydb"
).await?;
session_service.migrate().await?;
let session = session_service.create(CreateRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: None,
state: HashMap::new(),
}).await?;
println!("Session persisted: {}", session.id());
Ok(())
}
Note:
postgresfeature flag が必要です:adk-session = { version = "2.0.0", features = ["postgres"] }
MongoSessionService
session を MongoDB に保存します。スタンドアロンとレプリカセットの両方のデプロイをそのままサポートします。
起動時に、MongoSessionService::new() は、接続された MongoDB インスタンスがレプリカセットの一部かどうかを、hello command を発行して自動検出します。レプリカセット(またはシャードクラスタ)が検出されると、すべての multi-document write は原子性のために transaction を使用します。スタンドアロンのデプロイでは、operation は transaction なしで順次実行されます。upsert ベースの write は冪等であるため、部分的な失敗があっても state は回復可能なままです。
use adk_session::{MongoSessionService, SessionService, CreateRequest};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Works with both standalone and replica-set MongoDB
let session_service = MongoSessionService::new(
"mongodb://user:pass@localhost:27017",
"my_sessions_db",
).await?;
// Run migrations (creates indexes)
session_service.migrate().await?;
// Check deployment mode
if session_service.supports_transactions() {
println!("Replica set detected — transactions enabled");
} else {
println!("Standalone mode — sequential writes");
}
let session = session_service.create(CreateRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: None,
state: HashMap::new(),
}).await?;
println!("Session persisted: {}", session.id());
Ok(())
}
Note:
mongodbfeature flag が必要です:adk-session = { version = "2.0.0", features = ["mongodb"] }
MongoDB deployment modes
| デプロイ | トランザクション | 動作 |
|---|---|---|
| スタンドアロン | いいえ | シーケンシャルな upsert、冪等な書き込み |
| レプリカセット | はい | マルチドキュメント ACID トランザクション |
| シャーディングクラスタ | はい | マルチドキュメント ACID トランザクション |
retryWrites=false の接続文字列パラメータは、スタンドアロン展開ではもはや不要です。サービスがこれを透過的に処理します。
MongoDB コレクション
MongoSessionService は 4 つのコレクションを使用します:
sessions— session-level state を持つ session documentsevents—session_idで関連付けられた event documentsapp_states—app_nameをキーとする application-level stateuser_states—(app_name, user_id)をキーとする user-level state
Neo4jSessionService
Neo4j では sessions をグラフノードとして保存します。sessions、events、state tiers 間の関係はグラフエッジとしてモデル化されます。
use adk_session::{Neo4jSessionService, SessionService, CreateRequest};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let session_service = Neo4jSessionService::new(
"bolt://localhost:7687",
"neo4j",
"password",
).await?;
session_service.migrate().await?;
let session = session_service.create(CreateRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: None,
state: HashMap::new(),
}).await?;
println!("Session persisted: {}", session.id());
Ok(())
}
Note:
neo4jfeature flag が必要です:adk-session = { version = "2.0.0", features = ["neo4j"] }
RedisSessionService
Redis に sessions を保存します。低レイテンシ、高スループットの展開に最適です。
use adk_session::{RedisSessionService, RedisSessionConfig};
let config = RedisSessionConfig::new("redis://localhost:6379");
let session_service = RedisSessionService::new(config).await?;
Note:
redisfeature flag が必要です:adk-session = { version = "2.0.0", features = ["redis"] }
スキーマ移行
データベースを利用するすべての session service(SQLite、PostgreSQL、MongoDB、Neo4j)には、バージョン管理された forward-only の migration system が含まれます。Migrations は _schema_migrations registry table に記録されます。
暗号化されたセッション
任意の SessionService を EncryptedSession でラップして、AES-256-GCM を使用して session state を保存時に暗号化します。encrypted-session feature flag が必要です。
adk-session = { version = "2.0.0", features = ["encrypted-session"] }
基本的な使用法
use adk_session::{EncryptedSession, EncryptionKey, InMemorySessionService};
// Generate a random 256-bit key
let key = EncryptionKey::generate();
// Or load from environment variable (base64-encoded)
// let key = EncryptionKey::from_env("SESSION_ENCRYPTION_KEY")?;
// Wrap any session service
let inner = InMemorySessionService::new();
let service = EncryptedSession::new(inner, key, vec![]);
// Use exactly like any other SessionService — encryption is transparent
let session = service.create(CreateRequest { /* ... */ }).await?;
State は JSON にシリアライズされ、ランダムな 96-bit nonce で暗号化され、inner service には [nonce || ciphertext] として保存されます。復号は読み取り時に透過的に行われます。
鍵のローテーション
古い鍵で暗号化されたデータの読み取りをサポートするために、前の鍵を渡します:
let new_key = EncryptionKey::generate();
let old_key = EncryptionKey::from_env("OLD_SESSION_KEY")?;
let service = EncryptedSession::new(inner, new_key, vec![old_key]);
読み取り時には、まず現在の鍵が試されます。復号に失敗した場合は、各前の鍵が順番に試されます。前の鍵で成功すると、データは自動的に現在の鍵で再暗号化されます。
鍵の管理
// Generate random key
let key = EncryptionKey::generate();
// Load from base64-encoded environment variable
let key = EncryptionKey::from_env("MY_KEY")?;
// Create from raw 32 bytes
let key = EncryptionKey::from_bytes(&[0u8; 32])?;
// Access raw bytes (e.g., for storing securely)
let bytes: &[u8; 32] = key.as_bytes();
マイグレーションの実行
データベースを利用する service を構築した後に migrate() を呼び出します。これは冪等であり、起動のたびに呼び出しても安全です:
use adk_session::SqliteSessionService;
let service = SqliteSessionService::new("sqlite:sessions.db").await?;
service.migrate().await?;
スキーマバージョンの確認
let version = service.schema_version().await?;
println!("Current schema version: {version}");
ベースライン検出
migration system が追加される前に作成された既存の database がある場合、migrate() は既存の tables を検出して、すでに適用済みとして登録します。これにより破壊的な再作成を回避し、段階的な導入が可能になります。
マイグレーションの保証
- Forward-only: Migrations は順番に適用され、ロールバックされることはありません
- Idempotent:
migrate()を複数回実行しても安全です - Checksummed: 各 migration は SHA-256 checksum で追跡され、改ざんを検出します
- Atomic: PostgreSQL migrations は同時実行を防ぐために advisory locks を使用します
セッションのライフサイクル
1. 作成
Sessions は CreateRequest で作成されます。session_id が提供されない場合、UUID が自動的に生成されます。
use adk_session::{InMemorySessionService, SessionService, CreateRequest};
use std::collections::HashMap;
let service = InMemorySessionService::new();
// Create with auto-generated ID
let session = service.create(CreateRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: None,
state: HashMap::new(),
}).await?;
// Create with specific ID
let session = service.create(CreateRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: Some("my-custom-id".to_string()),
state: HashMap::new(),
}).await?;
2. 取得
セッションを識別子で取得します:
use adk_session::GetRequest;
let session = service.get(GetRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: "session_abc".to_string(),
num_recent_events: None,
after: None,
}).await?;
println!("Retrieved session: {}", session.id());
println!("Events: {}", session.events().len());
3. イベントの追加
会話の進行に応じて、events は sessions に追加されます。通常は Runner が処理しますが、手動でも実行できます:
use adk_session::Event;
let event = Event::new("invocation_123");
service.append_event(session.id(), event).await?;
4. 一覧表示
ユーザーのすべての sessions を一覧表示します:
use adk_session::ListRequest;
let sessions = service.list(ListRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
}).await?;
for session in sessions {
println!("Session: {} (updated: {})",
session.id(),
session.last_update_time()
);
}
5. 削除
不要になったら session を削除します:
use adk_session::DeleteRequest;
service.delete(DeleteRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: "session_abc".to_string(),
}).await?;
Runner での Sessions の使用
Agents を実行するとき、sessions は通常 Runner によって管理されます。Runner は次の処理を行います:
- session を作成または取得する
- session context を agent に渡す
- 会話の進行に応じて events を追加する
- agent のアクションに基づいて session state を更新する
use adk_rust::prelude::*;
use adk_rust::{SessionId, UserId};
use adk_runner::{Runner, RunnerConfig};
use adk_session::InMemorySessionService;
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
let api_key = std::env::var("GOOGLE_API_KEY")?;
let model = Arc::new(GeminiModel::new(&api_key, "gemini-2.5-flash")?);
let agent = LlmAgentBuilder::new("assistant")
.model(model)
.instruction("You are a helpful assistant.")
.build()?;
let session_service = Arc::new(InMemorySessionService::new());
// Create runner with session service
let runner = Runner::new(RunnerConfig {
app_name: "my_app".to_string(),
agent: Arc::new(agent),
session_service,
artifact_service: None,
memory_service: None,
run_config: None,
})?;
// Run with user and session IDs
let user_content = Content::new("user").with_text("Hello!");
let stream = runner.run(
UserId::new("user_123")?,
SessionId::new("session_abc")?,
user_content,
).await?;
Ok(())
}
型付き Session ID
Session 操作では AdkIdentity — AppName、UserId、SessionId の型付き composite — を使用して、sessions を曖昧さなく指定します。これにより parameter ordering のバグを排除し、マルチテナント分離を保証します。
型付き Session 操作
SessionService は、既存の文字列ベースの API と並んで型付きメソッドを提供します:
use adk_core::{AdkIdentity, AppName, SessionId, UserId};
use adk_session::{AppendEventRequest, Event, SessionService};
let identity = AdkIdentity::new(
AppName::try_from("my_app")?,
UserId::try_from("user_123")?,
SessionId::try_from("session_abc")?,
);
// Typed append — uses the full (app, user, session) triple
let event = Event::new("inv_001");
service.append_event_for_identity(AppendEventRequest {
identity: identity.clone(),
event,
}).await?;
// Typed get and delete
let session = service.get_for_identity(&identity).await?;
service.delete_for_identity(&identity).await?;
すべての session backend(in-memory、SQLite、PostgreSQL、Redis、MongoDB、Firestore、Neo4j、Vertex)は、型付き identity path をサポートします。従来の append_event(&str, ...) メソッドは、後方互換性のために引き続き利用できます。
新しいコードでは、append_event_for_identity() とその他の型付き identity helper を推奨します。従来の append_event(&str, ...) path は migration のためにのみ保持されており、内部呼び出し元が完全に AdkIdentity に移行した後に将来的な廃止を予定している、最初の従来型 identity API です。
マルチテナントの安全性
型付き identity を使うと、同じ raw session_id を共有しつつ、app_name または user_id が異なる 2 つの session は、常に正しくアドレス指定されます:
let tenant_a = AdkIdentity::new(
AppName::try_from("app-a")?,
UserId::try_from("alice")?,
SessionId::try_from("shared-session-id")?,
);
let tenant_b = AdkIdentity::new(
AppName::try_from("app-b")?,
UserId::try_from("bob")?,
SessionId::try_from("shared-session-id")?,
);
// These address completely different sessions
assert_ne!(tenant_a, tenant_b);
Sessions から Identity を読み取る
Session trait は、既存の session から identity を抽出するための型付き helper を提供します:
let session = service.get(get_request).await?;
// Get the full session identity
let identity = session.try_identity()?;
// Or individual typed fields
let app = session.try_app_name()?;
let user = session.try_user_id()?;
let sid = session.try_session_id()?;
3 つの identity layer(auth、session、execution)について詳しくは、Core Types — Identity を参照してください。
Events
Events trait は、会話履歴へのアクセスを提供します:
pub trait Events: Send + Sync {
/// Get all events
fn all(&self) -> Vec<Event>;
/// Get number of events
fn len(&self) -> usize;
/// Get event at index
fn at(&self, index: usize) -> Option<&Event>;
/// Check if empty
fn is_empty(&self) -> bool;
}
session から events にアクセスします:
let events = session.events();
println!("Total events: {}", events.len());
for event in events.all() {
println!("Event {} by {} at {}",
event.id,
event.author,
event.timestamp
);
}
完全な例
use adk_session::{
InMemorySessionService, SessionService,
CreateRequest, GetRequest, ListRequest, DeleteRequest,
Event, KEY_PREFIX_USER,
};
use serde_json::json;
use std::collections::HashMap;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let service = InMemorySessionService::new();
// Create session with initial state
let mut initial_state = HashMap::new();
initial_state.insert(format!("{}name", KEY_PREFIX_USER), json!("Alice"));
initial_state.insert("topic".to_string(), json!("Getting started"));
let session = service.create(CreateRequest {
app_name: "demo".to_string(),
user_id: "alice".to_string(),
session_id: None,
state: initial_state,
}).await?;
println!("Created session: {}", session.id());
// Check state
let state = session.state();
println!("User name: {:?}", state.get("user:name"));
println!("Topic: {:?}", state.get("topic"));
// Append an event
let event = Event::new("inv_001");
service.append_event(session.id(), event).await?;
// Retrieve session with events
let session = service.get(GetRequest {
app_name: "demo".to_string(),
user_id: "alice".to_string(),
session_id: session.id().to_string(),
num_recent_events: None,
after: None,
}).await?;
println!("Events: {}", session.events().len());
// List all sessions
let sessions = service.list(ListRequest {
app_name: "demo".to_string(),
user_id: "alice".to_string(),
}).await?;
println!("Total sessions: {}", sessions.len());
// Delete session
service.delete(DeleteRequest {
app_name: "demo".to_string(),
user_id: "alice".to_string(),
session_id: session.id().to_string(),
}).await?;
println!("Session deleted");
Ok(())
}
関連項目
- State Management - プレフィックスを使った session state の管理
- Context Compaction - LLM context size の削減
- Events - event structure と actions
- Runner - sessions を使った agent 実行
Previous: ← MCP Tools | Next: State Management →