From 6d87da90d15640c42756e61f20b50bd8617c94db Mon Sep 17 00:00:00 2001 From: Hare Date: Wed, 14 Jan 2026 16:30:41 +0900 Subject: [PATCH] Bump llm-worker to 0.2.1 --- Cargo.lock | 2 +- docs/spec/worker_design.md | 118 +++++++++++++++++++++---------------- llm-worker/Cargo.toml | 2 +- 3 files changed, 70 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 42c9b2e..443dbf8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -708,7 +708,7 @@ checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "llm-worker" -version = "0.2.0" +version = "0.2.1" dependencies = [ "async-trait", "clap", diff --git a/docs/spec/worker_design.md b/docs/spec/worker_design.md index 767b3eb..257ab99 100644 --- a/docs/spec/worker_design.md +++ b/docs/spec/worker_design.md @@ -31,41 +31,48 @@ graph TD Workerは以下のループ(ターン)を実行します。 -1. **Start Turn**: `Worker::run(messages)` 呼び出し -2. **Hook: OnMessageSend**: - * ユーザーメッセージの改変、バリデーション、キャンセルが可能。 - * コンテキストへのシステムプロンプト注入などもここで行う想定。 -3. **Request & Stream**: - * LLMへリクエスト送信。イベントストリーム開始。 - * `Timeline`によるイベント処理。 -4. **Tool Handling (Parallel)**: - * レスポンス内に含まれる全てのTool Callを収集。 - * 各Toolに対して **Hook: BeforeToolCall** を実行(実行可否、引数改変)。 - * 許可されたToolを**並列実行 (`join_all`)**。 - * 各Tool実行後に **Hook: AfterToolCall** を実行(結果の確認、加工)。 -5. **Next Request Decision**: - * Tool実行結果がある場合 -> 結果をMessageとしてContextに追加し、**Step 3へ戻る** (自動ループ)。 - * Tool実行がない場合 -> Step 6へ。 -6. **Hook: OnTurnEnd**: - * 最終的な応答に対するチェック(Lint/Fmt)。 - * エラーがある場合、エラーメッセージをContextに追加して **Step 3へ戻る** ことで自己修正を促せる。 - * 問題なければターン終了。 +1. **Start Turn**: `Worker::run(messages)` 呼び出し +2. **Hook: OnMessageSend**: + - ユーザーメッセージの改変、バリデーション、キャンセルが可能。 + - コンテキストへのシステムプロンプト注入などもここで行う想定。 +3. **Request & Stream**: + - LLMへリクエスト送信。イベントストリーム開始。 + - `Timeline`によるイベント処理。 +4. **Tool Handling (Parallel)**: + - レスポンス内に含まれる全てのTool Callを収集。 + - 各Toolに対して **Hook: BeforeToolCall** を実行(実行可否、引数改変)。 + - 許可されたToolを**並列実行 (`join_all`)**。 + - 各Tool実行後に **Hook: AfterToolCall** を実行(結果の確認、加工)。 +5. **Next Request Decision**: + - Tool実行結果がある場合 -> 結果をMessageとしてContextに追加し、**Step + 3へ戻る** (自動ループ)。 + - Tool実行がない場合 -> Step 6へ。 +6. **Hook: OnTurnEnd**: + - 最終的な応答に対するチェック(Lint/Fmt)。 + - エラーがある場合、エラーメッセージをContextに追加して **Step 3へ戻る** + ことで自己修正を促せる。 + - 問題なければターン終了。 ## Tool 設計 ### アーキテクチャ概要 -Rustの静的型付けシステムとLLMの動的なツール呼び出し(文字列による指定)を、**Trait Object** と **動的ディスパッチ** を用いて接続します。 +Rustの静的型付けシステムとLLMの動的なツール呼び出し(文字列による指定)を、**Trait +Object** と **動的ディスパッチ** を用いて接続します。 -1. **共通インターフェース (`Tool` Trait)**: 全てのツールが実装すべき共通の振る舞い(メタデータ取得と実行)を定義します。 -2. **ラッパー生成 (`#[tool]` Macro)**: ユーザー定義のメソッドをラップし、`Tool` Traitを実装した構造体を自動生成します。 -3. **レジストリ (`HashMap`)**: Workerは動的ディスパッチ用に `HashMap>` でツールを管理します。 +1. **共通インターフェース (`Tool` Trait)**: + 全てのツールが実装すべき共通の振る舞い(メタデータ取得と実行)を定義します。 +2. **ラッパー生成 (`#[tool]` Macro)**: ユーザー定義のメソッドをラップし、`Tool` + Traitを実装した構造体を自動生成します。 +3. **レジストリ (`HashMap`)**: Workerは動的ディスパッチ用に + `HashMap>` でツールを管理します。 この仕組みにより、「名前からツールを探し、JSON引数を型変換して関数を実行する」フローを安全に実現します。 ### 1. Tool Trait 定義 -ツールが最低限持つべきインターフェースです。`Send + Sync` を必須とし、マルチスレッド(並列実行)に対応します。 +ツールが最低限持つべきインターフェースです。`Send + Sync` +を必須とし、マルチスレッド(並列実行)に対応します。 ```rust #[async_trait] @@ -113,7 +120,8 @@ impl MyApp { **マクロ展開後のイメージ (擬似コード):** -マクロは、元のメソッドに対応する**ラッパー構造体**を生成します。このラッパーが `Tool` Trait を実装します。 +マクロは、元のメソッドに対応する**ラッパー構造体**を生成します。このラッパーが +`Tool` Trait を実装します。 ```rust // 1. 引数をデシリアライズ用の中間構造体に変換 @@ -155,15 +163,18 @@ impl Tool for GetUserTool { ### 3. Workerによる実行フロー -Workerは生成されたラッパー構造体を `Box` として保持し、以下のフローで実行します。 +Workerは生成されたラッパー構造体を `Box` +として保持し、以下のフローで実行します。 -1. **登録**: アプリケーション開始時、コンテキスト(`MyApp`)から各ツールのラッパー(`GetUserTool`)を生成し、WorkerのMapに登録。 -2. **解決**: LLMからのレスポンスに含まれる `ToolUse { name: "get_user", ... }` を受け取る。 -3. **検索**: `name` をキーに Map から `Box` を取得。 -4. **実行**: - * `tool.execute(json)` を呼び出す。 - * 内部で `serde_json` による型変換とメソッド実行が行われる。 - * 結果が返る。 +1. **登録**: + アプリケーション開始時、コンテキスト(`MyApp`)から各ツールのラッパー(`GetUserTool`)を生成し、WorkerのMapに登録。 +2. **解決**: LLMからのレスポンスに含まれる `ToolUse { name: "get_user", ... }` + を受け取る。 +3. **検索**: `name` をキーに Map から `Box` を取得。 +4. **実行**: + - `tool.execute(json)` を呼び出す。 + - 内部で `serde_json` による型変換とメソッド実行が行われる。 + - 結果が返る。 これにより、型安全性を保ちつつ、動的なツール実行が可能になります。 @@ -171,8 +182,9 @@ Workerは生成されたラッパー構造体を `Box` として保持 ### コンセプト -* **制御の介入**: ターンの進行、メッセージの内容、ツールの実行に対して介入します。 -* **Contextへのアクセス**: メッセージ履歴(Context)を読み書きできます。 +- **制御の介入**: + ターンの進行、メッセージの内容、ツールの実行に対して介入します。 +- **Contextへのアクセス**: メッセージ履歴(Context)を読み書きできます。 ### Hook Trait @@ -219,7 +231,8 @@ pub enum OnTurnEndResult { ### Tool Call Context -`before_tool_call` / `after_tool_call` は、ツール実行の文脈を含む入力を受け取る。 +`before_tool_call` / `after_tool_call` +は、ツール実行の文脈を含む入力を受け取る。 ```rust pub struct ToolCallContext { @@ -237,17 +250,20 @@ pub struct ToolResultContext { ## 実装方針 -1. **Worker Struct**: - * `Timeline`を所有。 - * `Handler`として「ToolCallCollector」をTimelineに登録。 - * `stream`終了後に収集したToolCallを処理するロジックを持つ。 +1. **Worker Struct**: + - `Timeline`を所有。 + - `Handler`として「ToolCallCollector」をTimelineに登録。 + - `stream`終了後に収集したToolCallを処理するロジックを持つ。 + - **履歴管理**: `set_history`, `with_messages`, `history_mut` + 等を通じて、会話履歴の注入や編集を可能にする。 -2. **Tool Executor Handler**: - * Timeline上ではツール実行を行わず、あくまで「ToolCallブロックの収集」に徹する(Toolの実行は非同期かつ並列で、ストリーム終了後あるいはブロック確定後に行うため)。 - * ただし、リアルタイム性を重視する場合(ストリーミング中にToolを実行開始等)は将来的な拡張とするが、現状は「結果が揃うのを待って」という要件に従い、収集フェーズと実行フェーズを分ける。 +2. **Tool Executor Handler**: + - Timeline上ではツール実行を行わず、あくまで「ToolCallブロックの収集」に徹する(Toolの実行は非同期かつ並列で、ストリーム終了後あるいはブロック確定後に行うため)。 + - ただし、リアルタイム性を重視する場合(ストリーミング中にToolを実行開始等)は将来的な拡張とするが、現状は「結果が揃うのを待って」という要件に従い、収集フェーズと実行フェーズを分ける。 -3. **worker-macros**: - * `syn`, `quote` を用いて、関数定義から `Tool` トレイト実装と `InputSchema` (schemars利用) を生成。 +3. **worker-macros**: + - `syn`, `quote` を用いて、関数定義から `Tool` トレイト実装と `InputSchema` + (schemars利用) を生成。 ## Worker Event API 設計 @@ -256,6 +272,7 @@ pub struct ToolResultContext { Workerは内部でイベントを処理し結果を返しますが、UIへのストリーミング表示やリアルタイムフィードバックには、イベントを外部に公開する仕組みが必要です。 **要件**: + 1. テキストデルタをリアルタイムでUIに表示 2. ツール呼び出しの進行状況を表示 3. ブロック完了時に累積結果を受け取る @@ -264,10 +281,10 @@ Workerは内部でイベントを処理し結果を返しますが、UIへのス Worker APIは **Timeline層のHandler機構の薄いラッパー** として設計します。 -| 層 | 目的 | 提供するもの | -|---|------|-------------| -| **Handler (Timeline層)** | 内部実装、役割分離 | スコープ管理 + Deltaイベント | -| **Worker Event API** | ユーザー向け利便性 | Handler露出 + Completeイベント追加 | +| 層 | 目的 | 提供するもの | +| ------------------------ | ------------------ | ---------------------------------- | +| **Handler (Timeline層)** | 内部実装、役割分離 | スコープ管理 + Deltaイベント | +| **Worker Event API** | ユーザー向け利便性 | Handler露出 + Completeイベント追加 | Handlerのスコープ管理パターン(Start→Delta→End)をそのまま活かしつつ、累積済みのCompleteイベントも追加提供します。 @@ -448,7 +465,8 @@ impl Worker { ### 設計上のポイント 1. **Handlerの再利用**: 既存のHandler traitをそのまま活用 -2. **スコープ管理の維持**: ブロックイベントはStart→Delta→Endのライフサイクルを保持 +2. **スコープ管理の維持**: + ブロックイベントはStart→Delta→Endのライフサイクルを保持 3. **選択的購読**: on_*で必要なイベントだけ、またはSubscriberで一括 4. **累積イベントの追加**: Worker層でComplete系イベントを追加提供 5. **後方互換性**: 従来の`run()`も引き続き使用可能 diff --git a/llm-worker/Cargo.toml b/llm-worker/Cargo.toml index e0f2d04..727ed92 100644 --- a/llm-worker/Cargo.toml +++ b/llm-worker/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "llm-worker" description = "A library for building autonomous LLM-powered systems" -version = "0.2.0" +version = "0.2.1" publish.workspace = true edition.workspace = true license.workspace = true