update: Locked -> CacheLocked
This commit is contained in:
parent
a2f53d7879
commit
c281248bf8
|
|
@ -11,7 +11,7 @@ Rusty, Efficient, and Agentic LLM Client Library
|
||||||
- Tool System: Define tools as async functions. The Worker automatically parses LLM tool calls, executes them in parallel, and feeds results back.
|
- Tool System: Define tools as async functions. The Worker automatically parses LLM tool calls, executes them in parallel, and feeds results back.
|
||||||
- Hook System: Intercept execution flow with `before_tool_call`, `after_tool_call`, and `on_turn_end` hooks for validation, logging, or self-correction.
|
- Hook System: Intercept execution flow with `before_tool_call`, `after_tool_call`, and `on_turn_end` hooks for validation, logging, or self-correction.
|
||||||
- Event-Driven Streaming: Subscribe to real-time events (text deltas, tool calls, usage) for responsive UIs.
|
- Event-Driven Streaming: Subscribe to real-time events (text deltas, tool calls, usage) for responsive UIs.
|
||||||
- Cache-Aware State Management: Type-state pattern (`Mutable` → `Locked`) ensures KV cache efficiency by protecting the conversation prefix.
|
- Cache-Aware State Management: Type-state pattern (`Mutable` → `CacheLocked`) ensures KV cache efficiency by protecting the conversation prefix.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ RustのType-stateパターンを利用し、Workerの状態によって利用可
|
||||||
* 自由な編集が可能な状態。
|
* 自由な編集が可能な状態。
|
||||||
* システムプロンプトの設定・変更が可能。
|
* システムプロンプトの設定・変更が可能。
|
||||||
* メッセージ履歴の初期構築(ロード、編集)が可能。
|
* メッセージ履歴の初期構築(ロード、編集)が可能。
|
||||||
* **`Locked` (キャッシュ保護状態)**
|
* **`CacheLocked` (キャッシュ保護状態)**
|
||||||
* キャッシュの有効活用を目的とした、前方不変状態。
|
* キャッシュの有効活用を目的とした、前方不変状態。
|
||||||
* **システムプロンプトの変更不可**。
|
* **システムプロンプトの変更不可**。
|
||||||
* **既存メッセージ履歴の変更不可**(追記のみ許可)。
|
* **既存メッセージ履歴の変更不可**(追記のみ許可)。
|
||||||
|
|
@ -47,7 +47,7 @@ worker.history_mut().push(initial_message);
|
||||||
|
|
||||||
// 3. ロックしてLocked状態へ遷移
|
// 3. ロックしてLocked状態へ遷移
|
||||||
// これにより、ここまでのコンテキストが "Fixed Prefix" として扱われる
|
// これにより、ここまでのコンテキストが "Fixed Prefix" として扱われる
|
||||||
let mut locked_worker: Worker<Locked> = worker.lock();
|
let mut locked_worker: Worker<CacheLocked> = worker.lock();
|
||||||
|
|
||||||
// 4. 利用 (Locked状態)
|
// 4. 利用 (Locked状態)
|
||||||
// 実行は可能。新しいメッセージは履歴の末尾に追記される。
|
// 実行は可能。新しいメッセージは履歴の末尾に追記される。
|
||||||
|
|
@ -65,4 +65,4 @@ locked_worker.run(new_user_input).await?;
|
||||||
|
|
||||||
* **状態パラメータの導入**: `Worker<S: WorkerState>` の導入。
|
* **状態パラメータの導入**: `Worker<S: WorkerState>` の導入。
|
||||||
* **コンテキスト所有権の委譲**: `run` メソッドの引数でコンテキストを受け取るのではなく、`Worker` 内部に `history: Vec<Message>` を保持し管理する形へ移行する。
|
* **コンテキスト所有権の委譲**: `run` メソッドの引数でコンテキストを受け取るのではなく、`Worker` 内部に `history: Vec<Message>` を保持し管理する形へ移行する。
|
||||||
* **APIの分離**: `Mutable` 特有のメソッド(setter等)と、`Locked` でも使えるメソッド(実行、参照等)をトレイト境界で分離する。
|
* **APIの分離**: `Mutable` 特有のメソッド(setter等)と、`CacheLocked` でも使えるメソッド(実行、参照等)をトレイト境界で分離する。
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! LLMクライアント層
|
//! LLMクライアント層
|
||||||
//!
|
//!
|
||||||
//! 各LLMプロバイダと通信し、統一された[`Event`](crate::llm_client::event::Event)
|
//! 各LLMプロバイダと通信し、統一された[`Event`]
|
||||||
//! ストリームを出力します。
|
//! ストリームを出力します。
|
||||||
//!
|
//!
|
||||||
//! # サポートするプロバイダ
|
//! # サポートするプロバイダ
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! Worker状態
|
//! Worker状態
|
||||||
//!
|
//!
|
||||||
//! Type-stateパターンによるキャッシュ保護のための状態マーカー型。
|
//! Type-stateパターンによるキャッシュ保護のための状態マーカー型。
|
||||||
//! Workerは`Mutable` → `Locked`の状態遷移を持ちます。
|
//! Workerは`Mutable` → `CacheLocked`の状態遷移を持ちます。
|
||||||
|
|
||||||
/// Worker状態を表すマーカートレイト
|
/// Worker状態を表すマーカートレイト
|
||||||
///
|
///
|
||||||
|
|
@ -19,7 +19,7 @@ mod private {
|
||||||
/// - メッセージ履歴の編集(追加、削除、クリア)
|
/// - メッセージ履歴の編集(追加、削除、クリア)
|
||||||
/// - ツール・Hookの登録
|
/// - ツール・Hookの登録
|
||||||
///
|
///
|
||||||
/// `Worker::lock()`により[`Locked`]状態へ遷移できます。
|
/// `Worker::lock()`により[`CacheLocked`]状態へ遷移できます。
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
|
@ -42,7 +42,7 @@ pub struct Mutable;
|
||||||
impl private::Sealed for Mutable {}
|
impl private::Sealed for Mutable {}
|
||||||
impl WorkerState for Mutable {}
|
impl WorkerState for Mutable {}
|
||||||
|
|
||||||
/// ロック状態(キャッシュ保護)
|
/// キャッシュロック状態(キャッシュ保護)
|
||||||
///
|
///
|
||||||
/// この状態では以下の制限があります:
|
/// この状態では以下の制限があります:
|
||||||
/// - システムプロンプトの変更不可
|
/// - システムプロンプトの変更不可
|
||||||
|
|
@ -54,7 +54,7 @@ impl WorkerState for Mutable {}
|
||||||
/// `Worker::unlock()`により[`Mutable`]状態へ戻せますが、
|
/// `Worker::unlock()`により[`Mutable`]状態へ戻せますが、
|
||||||
/// キャッシュ保護が解除されることに注意してください。
|
/// キャッシュ保護が解除されることに注意してください。
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct Locked;
|
pub struct CacheLocked;
|
||||||
|
|
||||||
impl private::Sealed for Locked {}
|
impl private::Sealed for CacheLocked {}
|
||||||
impl WorkerState for Locked {}
|
impl WorkerState for CacheLocked {}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
ClientError, ConfigWarning, LlmClient, Request, RequestConfig,
|
ClientError, ConfigWarning, LlmClient, Request, RequestConfig,
|
||||||
ToolDefinition as LlmToolDefinition,
|
ToolDefinition as LlmToolDefinition,
|
||||||
},
|
},
|
||||||
state::{Locked, Mutable, WorkerState},
|
state::{CacheLocked, Mutable, WorkerState},
|
||||||
subscriber::{
|
subscriber::{
|
||||||
ErrorSubscriberAdapter, StatusSubscriberAdapter, TextBlockSubscriberAdapter,
|
ErrorSubscriberAdapter, StatusSubscriberAdapter, TextBlockSubscriberAdapter,
|
||||||
ToolUseBlockSubscriberAdapter, UsageSubscriberAdapter, WorkerSubscriber,
|
ToolUseBlockSubscriberAdapter, UsageSubscriberAdapter, WorkerSubscriber,
|
||||||
|
|
@ -131,7 +131,7 @@ impl<S: WorkerSubscriber + 'static> TurnNotifier for SubscriberTurnNotifier<S> {
|
||||||
/// # 状態遷移(Type-state)
|
/// # 状態遷移(Type-state)
|
||||||
///
|
///
|
||||||
/// - [`Mutable`]: 初期状態。システムプロンプトや履歴を自由に編集可能。
|
/// - [`Mutable`]: 初期状態。システムプロンプトや履歴を自由に編集可能。
|
||||||
/// - [`Locked`]: キャッシュ保護状態。`lock()`で遷移。前方コンテキストは不変。
|
/// - [`CacheLocked`]: キャッシュ保護状態。`lock()`で遷移。前方コンテキストは不変。
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
|
@ -174,7 +174,7 @@ pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
|
||||||
system_prompt: Option<String>,
|
system_prompt: Option<String>,
|
||||||
/// メッセージ履歴(Workerが所有)
|
/// メッセージ履歴(Workerが所有)
|
||||||
history: Vec<Message>,
|
history: Vec<Message>,
|
||||||
/// ロック時点での履歴長(Locked状態でのみ意味を持つ)
|
/// ロック時点での履歴長(CacheLocked状態でのみ意味を持つ)
|
||||||
locked_prefix_len: usize,
|
locked_prefix_len: usize,
|
||||||
/// ターンカウント
|
/// ターンカウント
|
||||||
turn_count: usize,
|
turn_count: usize,
|
||||||
|
|
@ -1254,11 +1254,11 @@ impl<C: LlmClient> Worker<C, Mutable> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ロックしてLocked状態へ遷移
|
/// ロックしてCacheLocked状態へ遷移
|
||||||
///
|
///
|
||||||
/// この操作により、現在のシステムプロンプトと履歴が「確定済みプレフィックス」として
|
/// この操作により、現在のシステムプロンプトと履歴が「確定済みプレフィックス」として
|
||||||
/// 固定される。以降は履歴への追記のみが可能となり、キャッシュヒットが保証される。
|
/// 固定される。以降は履歴への追記のみが可能となり、キャッシュヒットが保証される。
|
||||||
pub fn lock(self) -> Worker<C, Locked> {
|
pub fn lock(self) -> Worker<C, CacheLocked> {
|
||||||
let locked_prefix_len = self.history.len();
|
let locked_prefix_len = self.history.len();
|
||||||
Worker {
|
Worker {
|
||||||
client: self.client,
|
client: self.client,
|
||||||
|
|
@ -1283,10 +1283,10 @@ impl<C: LlmClient> Worker<C, Mutable> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Locked状態専用の実装
|
// CacheLocked状態専用の実装
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
impl<C: LlmClient> Worker<C, Locked> {
|
impl<C: LlmClient> Worker<C, CacheLocked> {
|
||||||
/// ロック時点のプレフィックス長を取得
|
/// ロック時点のプレフィックス長を取得
|
||||||
pub fn locked_prefix_len(&self) -> usize {
|
pub fn locked_prefix_len(&self) -> usize {
|
||||||
self.locked_prefix_len
|
self.locked_prefix_len
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! Worker状態管理のテスト
|
//! Worker状態管理のテスト
|
||||||
//!
|
//!
|
||||||
//! Type-stateパターン(Mutable/Locked)による状態遷移と
|
//! Type-stateパターン(Mutable/CacheLocked)による状態遷移と
|
||||||
//! ターン間の状態保持をテストする。
|
//! ターン間の状態保持をテストする。
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
@ -95,7 +95,7 @@ fn test_mutable_extend_history() {
|
||||||
// 状態遷移テスト
|
// 状態遷移テスト
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/// lock()でMutable -> Locked状態に遷移することを確認
|
/// lock()でMutable -> CacheLocked状態に遷移することを確認
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lock_transition() {
|
fn test_lock_transition() {
|
||||||
let client = MockLlmClient::new(vec![]);
|
let client = MockLlmClient::new(vec![]);
|
||||||
|
|
@ -108,13 +108,13 @@ fn test_lock_transition() {
|
||||||
// ロック
|
// ロック
|
||||||
let locked_worker = worker.lock();
|
let locked_worker = worker.lock();
|
||||||
|
|
||||||
// Locked状態でも履歴とシステムプロンプトにアクセス可能
|
// CacheLocked状態でも履歴とシステムプロンプトにアクセス可能
|
||||||
assert_eq!(locked_worker.get_system_prompt(), Some("System"));
|
assert_eq!(locked_worker.get_system_prompt(), Some("System"));
|
||||||
assert_eq!(locked_worker.history().len(), 2);
|
assert_eq!(locked_worker.history().len(), 2);
|
||||||
assert_eq!(locked_worker.locked_prefix_len(), 2);
|
assert_eq!(locked_worker.locked_prefix_len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// unlock()でLocked -> Mutable状態に遷移することを確認
|
/// unlock()でCacheLocked -> Mutable状態に遷移することを確認
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unlock_transition() {
|
fn test_unlock_transition() {
|
||||||
let client = MockLlmClient::new(vec![]);
|
let client = MockLlmClient::new(vec![]);
|
||||||
|
|
@ -172,7 +172,7 @@ async fn test_mutable_run_updates_history() {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Locked状態で複数ターンを実行し、履歴が正しく累積することを確認
|
/// CacheLocked状態で複数ターンを実行し、履歴が正しく累積することを確認
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_locked_multi_turn_history_accumulation() {
|
async fn test_locked_multi_turn_history_accumulation() {
|
||||||
// 2回のリクエストに対応するレスポンスを準備
|
// 2回のリクエストに対応するレスポンスを準備
|
||||||
|
|
@ -340,7 +340,7 @@ async fn test_unlock_edit_relock() {
|
||||||
// システムプロンプト保持のテスト
|
// システムプロンプト保持のテスト
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/// Locked状態でもシステムプロンプトが保持されることを確認
|
/// CacheLocked状態でもシステムプロンプトが保持されることを確認
|
||||||
#[test]
|
#[test]
|
||||||
fn test_system_prompt_preserved_in_locked_state() {
|
fn test_system_prompt_preserved_in_locked_state() {
|
||||||
let client = MockLlmClient::new(vec![]);
|
let client = MockLlmClient::new(vec![]);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user