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