docs: Tidying up comments
This commit is contained in:
parent
2487d1ece7
commit
9233bb9163
109
.agent/workflows/documentation.md
Normal file
109
.agent/workflows/documentation.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
---
|
||||
description: ドキュメントコメントの書き方ガイドライン
|
||||
---
|
||||
|
||||
# ドキュメントコメント スタイルガイド
|
||||
|
||||
## 基本原則
|
||||
|
||||
1. **利用者視点で書く**: 「何をするものか」「どう使うか」を先に、「なぜそう実装したか」は後に
|
||||
2. **型パラメータはバッククォートで囲む**: `Handler<K>` ✓ / Handler<K> ✗
|
||||
3. **Examplesは`worker::`パスで書く**: re-export先のパスを使用
|
||||
|
||||
## 構造テンプレート
|
||||
|
||||
```rust
|
||||
/// [1行目: 何をするものか - 利用者が最初に知りたいこと]
|
||||
///
|
||||
/// [詳細説明: いつ使うか、なぜ使うか、注意点など]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use worker::SomeType;
|
||||
///
|
||||
/// let instance = SomeType::new();
|
||||
/// instance.do_something();
|
||||
/// ```
|
||||
///
|
||||
/// # Notes (オプション)
|
||||
///
|
||||
/// 実装上の注意事項や制限があれば記載
|
||||
pub struct SomeType { ... }
|
||||
```
|
||||
|
||||
## 良い例・悪い例
|
||||
|
||||
### 構造体/Trait
|
||||
|
||||
```rust
|
||||
// ❌ 悪い例(実装視点)
|
||||
/// Handler<K>からErasedHandler<K>へのラッパー
|
||||
/// 各Handlerは独自のScope型を持つため、Timelineで保持するには型消去が必要
|
||||
|
||||
// ✅ 良い例(利用者視点)
|
||||
/// `Handler<K>`を`ErasedHandler<K>`として扱うためのラッパー
|
||||
///
|
||||
/// 通常は直接使用せず、`Timeline::on_text_block()`などのメソッド経由で
|
||||
/// 自動的にラップされます。
|
||||
```
|
||||
|
||||
### メソッド
|
||||
|
||||
```rust
|
||||
// ❌ 悪い例(処理内容の説明のみ)
|
||||
/// ツールを登録する
|
||||
|
||||
// ✅ 良い例(何が起きるか、どう使うか)
|
||||
/// ツールを登録する
|
||||
///
|
||||
/// 登録されたツールはLLMからの呼び出しで自動的に実行されます。
|
||||
/// 同名のツールを登録した場合、後から登録したものが優先されます。
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use worker::{Worker, Tool};
|
||||
///
|
||||
/// worker.register_tool(MyTool::new());
|
||||
/// ```
|
||||
```
|
||||
|
||||
### 型パラメータ
|
||||
|
||||
```rust
|
||||
// ❌ HTMLタグとして解釈されてしまう
|
||||
/// Handler<K>を保持するフィールド
|
||||
|
||||
// ✅ バッククォートで囲む
|
||||
/// `Handler<K>`を保持するフィールド
|
||||
```
|
||||
|
||||
## ドキュメントの配置
|
||||
|
||||
| 項目 | 配置場所 |
|
||||
|-----|---------|
|
||||
| 型/trait/関数のdoc | 定義元のクレート(worker-types等) |
|
||||
| モジュールdoc (`//!`) | 各クレートのlib.rsに書く |
|
||||
| 実装詳細 | 実装コメント (`//`) を使用 |
|
||||
| 利用者向けでない内部型 | `#[doc(hidden)]`または`pub(crate)` |
|
||||
|
||||
## Examplesのuseパス
|
||||
|
||||
re-exportされる型のExamplesでは、最終的な公開パスを使用:
|
||||
|
||||
```rust
|
||||
// worker-types/src/tool.rs でも
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use worker::Tool; // ✓ worker_types::Tool ではなく
|
||||
/// ```
|
||||
```
|
||||
|
||||
## チェックリスト
|
||||
|
||||
- [ ] 1行目は「何をするものか」を利用者視点で説明しているか
|
||||
- [ ] 型パラメータ (`<T>`, `<K>` 等) はバッククォートで囲んでいるか
|
||||
- [ ] 主要なpub APIにはExamplesがあるか
|
||||
- [ ] Examplesの`use`パスは`worker::`になっているか
|
||||
- [ ] `cargo doc --no-deps`で警告が出ないか
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
//! イベント型定義
|
||||
//! イベント型
|
||||
//!
|
||||
//! llm_client層が出力するフラットなイベント列挙と関連型
|
||||
//! LLMからのストリーミングレスポンスを表現するイベント型。
|
||||
//! Timeline層がこのイベントを受信し、ハンドラにディスパッチします。
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -8,21 +9,38 @@ use serde::{Deserialize, Serialize};
|
|||
// Core Event Types (from llm_client layer)
|
||||
// =============================================================================
|
||||
|
||||
/// llm_client層が出力するフラットなイベント列挙
|
||||
/// LLMからのストリーミングイベント
|
||||
///
|
||||
/// Timeline層がこのイベントストリームを受け取り、ブロック構造化を行う
|
||||
/// 各LLMプロバイダからのレスポンスは、この`Event`のストリームとして
|
||||
/// 統一的に処理されます。
|
||||
///
|
||||
/// # イベントの種類
|
||||
///
|
||||
/// - **メタイベント**: `Ping`, `Usage`, `Status`, `Error`
|
||||
/// - **ブロックイベント**: `BlockStart`, `BlockDelta`, `BlockStop`, `BlockAbort`
|
||||
///
|
||||
/// # ブロックのライフサイクル
|
||||
///
|
||||
/// テキストやツール呼び出しは、`BlockStart` → `BlockDelta`(複数) → `BlockStop`
|
||||
/// の順序でイベントが発生します。
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Event {
|
||||
// Meta events (not tied to a block)
|
||||
/// ハートビート
|
||||
Ping(PingEvent),
|
||||
/// トークン使用量
|
||||
Usage(UsageEvent),
|
||||
/// ストリームのステータス変化
|
||||
Status(StatusEvent),
|
||||
/// エラー発生
|
||||
Error(ErrorEvent),
|
||||
|
||||
// Block lifecycle events
|
||||
/// ブロック開始(テキスト、ツール使用等)
|
||||
BlockStart(BlockStart),
|
||||
/// ブロックの差分データ
|
||||
BlockDelta(BlockDelta),
|
||||
/// ブロック正常終了
|
||||
BlockStop(BlockStop),
|
||||
/// ブロック中断
|
||||
BlockAbort(BlockAbort),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
//! Handler/Kind関連の型定義
|
||||
//! Handler/Kind型
|
||||
//!
|
||||
//! Timeline層でのイベント処理に使用するトレイトとKind定義
|
||||
//! Timeline層でイベントを処理するためのトレイト。
|
||||
//! カスタムハンドラを実装してTimelineに登録することで、
|
||||
//! ストリームイベントを受信できます。
|
||||
|
||||
use crate::event::*;
|
||||
|
||||
|
|
@ -8,10 +10,11 @@ use crate::event::*;
|
|||
// Kind Trait
|
||||
// =============================================================================
|
||||
|
||||
/// Kindはイベント型のみを定義する
|
||||
/// イベント種別を定義するマーカートレイト
|
||||
///
|
||||
/// スコープはHandler側で定義するため、同じKindに対して
|
||||
/// 異なるスコープを持つHandlerを登録できる
|
||||
/// 各Kindは対応するイベント型を指定します。
|
||||
/// HandlerはこのKindに対して実装され、同じKindに対して
|
||||
/// 異なるScope型を持つ複数のHandlerを登録できます。
|
||||
pub trait Kind {
|
||||
/// このKindに対応するイベント型
|
||||
type Event;
|
||||
|
|
@ -21,9 +24,39 @@ pub trait Kind {
|
|||
// Handler Trait
|
||||
// =============================================================================
|
||||
|
||||
/// Kindに対する処理を定義し、自身のスコープ型も決定する
|
||||
/// イベントを処理するハンドラトレイト
|
||||
///
|
||||
/// 特定の`Kind`に対するイベント処理を定義します。
|
||||
/// `Scope`はブロックのライフサイクル中に保持される状態です。
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::{Handler, TextBlockKind, TextBlockEvent};
|
||||
///
|
||||
/// struct TextCollector {
|
||||
/// texts: Vec<String>,
|
||||
/// }
|
||||
///
|
||||
/// impl Handler<TextBlockKind> for TextCollector {
|
||||
/// type Scope = String; // ブロックごとのバッファ
|
||||
///
|
||||
/// fn on_event(&mut self, buffer: &mut String, event: &TextBlockEvent) {
|
||||
/// match event {
|
||||
/// TextBlockEvent::Delta(text) => buffer.push_str(text),
|
||||
/// TextBlockEvent::Stop(_) => {
|
||||
/// self.texts.push(std::mem::take(buffer));
|
||||
/// }
|
||||
/// _ => {}
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Handler<K: Kind> {
|
||||
/// Handler固有のスコープ型
|
||||
///
|
||||
/// ブロック開始時に`Default::default()`で生成され、
|
||||
/// ブロック終了時に破棄されます。
|
||||
type Scope: Default;
|
||||
|
||||
/// イベントを処理する
|
||||
|
|
|
|||
|
|
@ -101,15 +101,50 @@ pub enum HookError {
|
|||
// WorkerHook Trait
|
||||
// =============================================================================
|
||||
|
||||
/// Worker Hook trait
|
||||
/// ターンの進行・ツール実行に介入するためのトレイト
|
||||
///
|
||||
/// ターンの進行・メッセージ・ツール実行に対して介入するためのトレイト。
|
||||
/// デフォルト実装では何も行わずContinueを返す。
|
||||
/// Hookを使うと、メッセージ送信前、ツール実行前後、ターン終了時に
|
||||
/// 処理を挟んだり、実行をキャンセルしたりできます。
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::{WorkerHook, ControlFlow, HookError, ToolCall, TurnResult, Message};
|
||||
///
|
||||
/// struct ValidationHook;
|
||||
///
|
||||
/// #[async_trait::async_trait]
|
||||
/// impl WorkerHook for ValidationHook {
|
||||
/// async fn before_tool_call(&self, call: &mut ToolCall) -> Result<ControlFlow, HookError> {
|
||||
/// // 危険なツールをブロック
|
||||
/// if call.name == "delete_all" {
|
||||
/// return Ok(ControlFlow::Skip);
|
||||
/// }
|
||||
/// Ok(ControlFlow::Continue)
|
||||
/// }
|
||||
///
|
||||
/// async fn on_turn_end(&self, messages: &[Message]) -> Result<TurnResult, HookError> {
|
||||
/// // 条件を満たさなければ追加メッセージで継続
|
||||
/// if messages.len() < 3 {
|
||||
/// return Ok(TurnResult::ContinueWithMessages(vec![
|
||||
/// Message::user("Please elaborate.")
|
||||
/// ]));
|
||||
/// }
|
||||
/// Ok(TurnResult::Finish)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # デフォルト実装
|
||||
///
|
||||
/// すべてのメソッドにはデフォルト実装があり、何も行わず`Continue`を返します。
|
||||
/// 必要なメソッドのみオーバーライドしてください。
|
||||
#[async_trait]
|
||||
pub trait WorkerHook: Send + Sync {
|
||||
/// メッセージ送信前
|
||||
/// メッセージ送信前に呼ばれる
|
||||
///
|
||||
/// リクエストに含まれるメッセージリストを改変できる。
|
||||
/// リクエストに含まれるメッセージリストを参照・改変できます。
|
||||
/// `ControlFlow::Abort`を返すとターンが中断されます。
|
||||
async fn on_message_send(
|
||||
&self,
|
||||
_context: &mut Vec<crate::Message>,
|
||||
|
|
@ -117,16 +152,17 @@ pub trait WorkerHook: Send + Sync {
|
|||
Ok(ControlFlow::Continue)
|
||||
}
|
||||
|
||||
/// ツール実行前
|
||||
/// ツール実行前に呼ばれる
|
||||
///
|
||||
/// 実行をキャンセルしたり、引数を書き換えることができる。
|
||||
/// ツール呼び出しの引数を書き換えたり、実行をスキップしたりできます。
|
||||
/// `ControlFlow::Skip`を返すとこのツールの実行がスキップされます。
|
||||
async fn before_tool_call(&self, _tool_call: &mut ToolCall) -> Result<ControlFlow, HookError> {
|
||||
Ok(ControlFlow::Continue)
|
||||
}
|
||||
|
||||
/// ツール実行後
|
||||
/// ツール実行後に呼ばれる
|
||||
///
|
||||
/// 結果を書き換えたり、隠蔽したりできる。
|
||||
/// ツールの実行結果を書き換えたり、隠蔽したりできます。
|
||||
async fn after_tool_call(
|
||||
&self,
|
||||
_tool_result: &mut ToolResult,
|
||||
|
|
@ -134,9 +170,11 @@ pub trait WorkerHook: Send + Sync {
|
|||
Ok(ControlFlow::Continue)
|
||||
}
|
||||
|
||||
/// ターン終了時
|
||||
/// ターン終了時に呼ばれる
|
||||
///
|
||||
/// 生成されたメッセージを検査し、必要ならリトライを指示できる。
|
||||
/// 生成されたメッセージを検査し、必要なら追加メッセージで継続を指示できます。
|
||||
/// `TurnResult::ContinueWithMessages`を返すと、指定したメッセージを追加して
|
||||
/// 次のターンに進みます。
|
||||
async fn on_turn_end(&self, _messages: &[crate::Message]) -> Result<TurnResult, HookError> {
|
||||
Ok(TurnResult::Finish)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
//! worker-types - LLMワーカーで使用される型定義
|
||||
//! worker-types - LLMワーカーの型定義
|
||||
//!
|
||||
//! このクレートは以下を提供します:
|
||||
//! - Event: llm_client層からのフラットなイベント列挙
|
||||
//! - Kind/Handler: タイムライン層でのイベント処理トレイト
|
||||
//! - Tool: ツール定義トレイト
|
||||
//! - Hook: Worker層での介入用トレイト
|
||||
//! - Message: メッセージ型
|
||||
//! - 各種イベント構造体
|
||||
//! このクレートは`worker`クレートで使用される型を提供します。
|
||||
//! 通常は直接使用せず、`worker`クレート経由で利用してください。
|
||||
//!
|
||||
//! ```ignore
|
||||
//! use worker::{Event, Message, Tool, WorkerHook};
|
||||
//! ```
|
||||
|
||||
mod event;
|
||||
mod handler;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! メッセージ型定義
|
||||
//! メッセージ型
|
||||
//!
|
||||
//! LLM会話で使用されるメッセージ構造
|
||||
//! LLMとの会話で使用されるメッセージ構造。
|
||||
//! [`Message::user`]や[`Message::assistant`]で簡単に作成できます。
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -14,7 +15,19 @@ pub enum Role {
|
|||
Assistant,
|
||||
}
|
||||
|
||||
/// メッセージ
|
||||
/// 会話のメッセージ
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::Message;
|
||||
///
|
||||
/// // ユーザーメッセージ
|
||||
/// let user_msg = Message::user("Hello!");
|
||||
///
|
||||
/// // アシスタントメッセージ
|
||||
/// let assistant_msg = Message::assistant("Hi there!");
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Message {
|
||||
/// ロール
|
||||
|
|
@ -62,6 +75,13 @@ pub enum ContentPart {
|
|||
|
||||
impl Message {
|
||||
/// ユーザーメッセージを作成
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::Message;
|
||||
/// let msg = Message::user("こんにちは");
|
||||
/// ```
|
||||
pub fn user(content: impl Into<String>) -> Self {
|
||||
Self {
|
||||
role: Role::User,
|
||||
|
|
@ -70,6 +90,9 @@ impl Message {
|
|||
}
|
||||
|
||||
/// アシスタントメッセージを作成
|
||||
///
|
||||
/// 通常はWorker内部で自動生成されますが、
|
||||
/// 履歴の初期化などで手動作成も可能です。
|
||||
pub fn assistant(content: impl Into<String>) -> Self {
|
||||
Self {
|
||||
role: Role::Assistant,
|
||||
|
|
@ -78,6 +101,9 @@ impl Message {
|
|||
}
|
||||
|
||||
/// ツール結果メッセージを作成
|
||||
///
|
||||
/// Worker内部でツール実行後に自動生成されます。
|
||||
/// 通常は直接作成する必要はありません。
|
||||
pub fn tool_result(tool_use_id: impl Into<String>, content: impl Into<String>) -> Self {
|
||||
Self {
|
||||
role: Role::User,
|
||||
|
|
|
|||
|
|
@ -1,24 +1,41 @@
|
|||
//! Worker状態マーカー型
|
||||
//! Worker状態
|
||||
//!
|
||||
//! Type-stateパターンによるキャッシュ保護のための状態定義
|
||||
//! Type-stateパターンによるキャッシュ保護のための状態マーカー型。
|
||||
//! Workerは`Mutable` → `Locked`の状態遷移を持ちます。
|
||||
|
||||
/// Worker状態を表すマーカートレイト
|
||||
///
|
||||
/// このトレイトはシールされており、外部から実装することはできない。
|
||||
/// このトレイトはシールされており、外部から実装することはできません。
|
||||
pub trait WorkerState: private::Sealed + Send + Sync + 'static {}
|
||||
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
/// 変更可能状態
|
||||
/// 編集可能状態
|
||||
///
|
||||
/// この状態では以下の操作が可能:
|
||||
/// この状態では以下の操作が可能です:
|
||||
/// - システムプロンプトの設定・変更
|
||||
/// - メッセージ履歴の編集(追加、削除、クリア)
|
||||
/// - ツール・Hookの登録
|
||||
///
|
||||
/// `lock()` によって `Locked` 状態へ遷移できる。
|
||||
/// `Worker::lock()`により[`Locked`]状態へ遷移できます。
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::Worker;
|
||||
///
|
||||
/// let mut worker = Worker::new(client)
|
||||
/// .system_prompt("You are helpful.");
|
||||
///
|
||||
/// // 履歴を編集可能
|
||||
/// worker.push_message(Message::user("Hello"));
|
||||
/// worker.clear_history();
|
||||
///
|
||||
/// // ロックして保護状態へ
|
||||
/// let locked = worker.lock();
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Mutable;
|
||||
|
||||
|
|
@ -27,12 +44,15 @@ impl WorkerState for Mutable {}
|
|||
|
||||
/// ロック状態(キャッシュ保護)
|
||||
///
|
||||
/// この状態では以下の制限がある:
|
||||
/// この状態では以下の制限があります:
|
||||
/// - システムプロンプトの変更不可
|
||||
/// - 既存メッセージ履歴の変更不可(末尾への追記のみ)
|
||||
///
|
||||
/// 実行(`run`)はこの状態で行うことが推奨される。
|
||||
/// キャッシュヒットを保証するため、前方のコンテキストは不変となる。
|
||||
/// LLM APIのKVキャッシュヒットを保証するため、
|
||||
/// 実行時にはこの状態の使用が推奨されます。
|
||||
///
|
||||
/// `Worker::unlock()`により[`Mutable`]状態へ戻せますが、
|
||||
/// キャッシュ保護が解除されることに注意してください。
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Locked;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! WorkerSubscriber - Worker層のイベント購読トレイト
|
||||
//! イベント購読
|
||||
//!
|
||||
//! Timeline層のHandler機構の薄いラッパーとして設計され、
|
||||
//! UIへのストリーミング表示やリアルタイムフィードバックを可能にする。
|
||||
//! LLMからのストリーミングイベントをリアルタイムで受信するためのトレイト。
|
||||
//! UIへのストリーム表示やプログレス表示に使用します。
|
||||
|
||||
use crate::{ErrorEvent, StatusEvent, TextBlockEvent, ToolCall, ToolUseBlockEvent, UsageEvent};
|
||||
|
||||
|
|
@ -9,39 +9,42 @@ use crate::{ErrorEvent, StatusEvent, TextBlockEvent, ToolCall, ToolUseBlockEvent
|
|||
// WorkerSubscriber Trait
|
||||
// =============================================================================
|
||||
|
||||
/// Worker層の統合Subscriberトレイト
|
||||
/// LLMからのストリーミングイベントを購読するトレイト
|
||||
///
|
||||
/// Timeline層のHandler機構をラップし、以下のイベントを一括で購読できる:
|
||||
/// - ブロックイベント(スコープ管理あり): Text, ToolUse
|
||||
/// - 単発イベント: Usage, Status, Error
|
||||
/// - 累積イベント(Worker層で追加): TextComplete, ToolCallComplete
|
||||
/// - ターン制御: TurnStart, TurnEnd
|
||||
/// Workerに登録すると、テキスト生成やツール呼び出しのイベントを
|
||||
/// リアルタイムで受信できます。UIへのストリーム表示に最適です。
|
||||
///
|
||||
/// # 使用例
|
||||
/// # 受信できるイベント
|
||||
///
|
||||
/// - **ブロックイベント**: テキスト、ツール使用(スコープ付き)
|
||||
/// - **メタイベント**: 使用量、ステータス、エラー
|
||||
/// - **完了イベント**: テキスト完了、ツール呼び出し完了
|
||||
/// - **ターン制御**: ターン開始、ターン終了
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// struct MyUI {
|
||||
/// chat_view: ChatView,
|
||||
/// }
|
||||
/// use worker::{WorkerSubscriber, TextBlockEvent};
|
||||
///
|
||||
/// impl WorkerSubscriber for MyUI {
|
||||
/// type TextBlockScope = String;
|
||||
/// type ToolUseBlockScope = ToolComponent;
|
||||
/// struct StreamPrinter;
|
||||
///
|
||||
/// fn on_text_block(&mut self, buffer: &mut String, event: &TextBlockEvent) {
|
||||
/// match event {
|
||||
/// TextBlockEvent::Delta(text) => {
|
||||
/// buffer.push_str(text);
|
||||
/// self.chat_view.update(buffer);
|
||||
/// }
|
||||
/// _ => {}
|
||||
/// impl WorkerSubscriber for StreamPrinter {
|
||||
/// type TextBlockScope = ();
|
||||
/// type ToolUseBlockScope = ();
|
||||
///
|
||||
/// fn on_text_block(&mut self, _: &mut (), event: &TextBlockEvent) {
|
||||
/// if let TextBlockEvent::Delta(text) = event {
|
||||
/// print!("{}", text); // リアルタイム出力
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn on_text_complete(&mut self, text: &str) {
|
||||
/// self.chat_view.add_to_history(text);
|
||||
/// println!("\n--- Complete: {} chars ---", text.len());
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Workerに登録
|
||||
/// worker.subscribe(StreamPrinter);
|
||||
/// ```
|
||||
pub trait WorkerSubscriber: Send {
|
||||
// =========================================================================
|
||||
|
|
|
|||
|
|
@ -1,33 +1,90 @@
|
|||
//! ツール定義
|
||||
//!
|
||||
//! LLMから呼び出し可能なツールを定義するためのトレイト。
|
||||
//! 通常は`#[tool]`マクロを使用して自動実装します。
|
||||
|
||||
use async_trait::async_trait;
|
||||
use serde_json::Value;
|
||||
use thiserror::Error;
|
||||
|
||||
/// ツール実行時のエラー
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ToolError {
|
||||
/// 引数が不正
|
||||
#[error("Invalid argument: {0}")]
|
||||
InvalidArgument(String),
|
||||
/// 実行に失敗
|
||||
#[error("Execution failed: {0}")]
|
||||
ExecutionFailed(String),
|
||||
/// 内部エラー
|
||||
#[error("Internal error: {0}")]
|
||||
Internal(String),
|
||||
}
|
||||
|
||||
/// ツール定義トレイト
|
||||
/// LLMから呼び出し可能なツールを定義するトレイト
|
||||
///
|
||||
/// ユーザー定義のツールはこれを実装し、Workerに登録される。
|
||||
/// 通常は `#[tool]` マクロによって自動生成される。
|
||||
/// ツールはLLMが外部リソースにアクセスしたり、
|
||||
/// 計算を実行したりするために使用します。
|
||||
///
|
||||
/// # 実装方法
|
||||
///
|
||||
/// 通常は`#[tool]`マクロを使用して自動実装します:
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::tool;
|
||||
///
|
||||
/// #[tool(description = "Search the web for information")]
|
||||
/// async fn search(query: String) -> String {
|
||||
/// // 検索処理
|
||||
/// format!("Results for: {}", query)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # 手動実装
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::{Tool, ToolError};
|
||||
/// use serde_json::{json, Value};
|
||||
///
|
||||
/// struct MyTool;
|
||||
///
|
||||
/// #[async_trait::async_trait]
|
||||
/// impl Tool for MyTool {
|
||||
/// fn name(&self) -> &str { "my_tool" }
|
||||
/// fn description(&self) -> &str { "My custom tool" }
|
||||
/// fn input_schema(&self) -> Value {
|
||||
/// json!({
|
||||
/// "type": "object",
|
||||
/// "properties": {
|
||||
/// "query": { "type": "string" }
|
||||
/// },
|
||||
/// "required": ["query"]
|
||||
/// })
|
||||
/// }
|
||||
/// async fn execute(&self, input: &str) -> Result<String, ToolError> {
|
||||
/// Ok("result".to_string())
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[async_trait]
|
||||
pub trait Tool: Send + Sync {
|
||||
/// ツール名 (LLMが識別に使用)
|
||||
/// ツール名(LLMが識別に使用)
|
||||
fn name(&self) -> &str;
|
||||
|
||||
/// ツールの説明 (LLMへのプロンプトに含まれる)
|
||||
/// ツールの説明(LLMへのプロンプトに含まれる)
|
||||
fn description(&self) -> &str;
|
||||
|
||||
/// 引数のJSON Schema
|
||||
///
|
||||
/// LLMはこのスキーマに従って引数を生成します。
|
||||
fn input_schema(&self) -> Value;
|
||||
|
||||
/// 実行関数
|
||||
/// JSON文字列を受け取り、デシリアライズして元のメソッドを実行し、結果を返す
|
||||
/// ツールを実行する
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `input_json` - LLMが生成したJSON形式の引数
|
||||
///
|
||||
/// # Returns
|
||||
/// 実行結果の文字列。この内容がLLMに返されます。
|
||||
async fn execute(&self, input_json: &str) -> Result<String, ToolError>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,39 @@
|
|||
//! worker - LLMワーカーのメイン実装
|
||||
//! worker - LLMワーカーライブラリ
|
||||
//!
|
||||
//! このクレートは以下を提供します:
|
||||
//! - Worker: ターン制御を行う高レベルコンポーネント
|
||||
//! - Timeline: イベントストリームの状態管理とハンドラーへのディスパッチ
|
||||
//! - LlmClient: LLMプロバイダとの通信
|
||||
//! - 型消去されたHandler実装
|
||||
//! LLMとの対話を管理するコンポーネントを提供します。
|
||||
//!
|
||||
//! # 主要なコンポーネント
|
||||
//!
|
||||
//! - [`Worker`] - LLMとの対話を管理する中心コンポーネント
|
||||
//! - [`Tool`] - LLMから呼び出し可能なツール
|
||||
//! - [`WorkerHook`] - ターン進行への介入
|
||||
//! - [`WorkerSubscriber`] - ストリーミングイベントの購読
|
||||
//!
|
||||
//! # Quick Start
|
||||
//!
|
||||
//! ```ignore
|
||||
//! use worker::{Worker, Message};
|
||||
//!
|
||||
//! // Workerを作成
|
||||
//! let mut worker = Worker::new(client)
|
||||
//! .system_prompt("You are a helpful assistant.");
|
||||
//!
|
||||
//! // ツールを登録(オプション)
|
||||
//! worker.register_tool(my_tool);
|
||||
//!
|
||||
//! // 対話を実行
|
||||
//! let history = worker.run("Hello!").await?;
|
||||
//! ```
|
||||
//!
|
||||
//! # キャッシュ保護
|
||||
//!
|
||||
//! KVキャッシュのヒット率を最大化するには、[`Worker::lock()`]で
|
||||
//! ロック状態に遷移してから実行してください。
|
||||
//!
|
||||
//! ```ignore
|
||||
//! let mut locked = worker.lock();
|
||||
//! locked.run("user input").await?;
|
||||
//! ```
|
||||
|
||||
pub mod llm_client;
|
||||
mod subscriber_adapter;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,19 @@
|
|||
//! LLMクライアント層
|
||||
//!
|
||||
//! LLMプロバイダと通信し、統一された`Event`ストリームを出力する。
|
||||
//! 各LLMプロバイダと通信し、統一された[`Event`](crate::Event)ストリームを出力します。
|
||||
//!
|
||||
//! # サポートするプロバイダ
|
||||
//!
|
||||
//! - Anthropic (Claude)
|
||||
//! - OpenAI (GPT-4, etc.)
|
||||
//! - Google (Gemini)
|
||||
//! - Ollama (ローカルLLM)
|
||||
//!
|
||||
//! # アーキテクチャ
|
||||
//!
|
||||
//! - **client**: `LlmClient` trait定義
|
||||
//! - **scheme**: APIスキーマ(リクエスト/レスポンス変換)
|
||||
//! - **providers**: プロバイダ固有のHTTPクライアント実装
|
||||
//! - [`LlmClient`] - プロバイダ共通のtrait
|
||||
//! - `providers`: プロバイダ固有のクライアント実装
|
||||
//! - `scheme`: APIスキーマ(リクエスト/レスポンス変換)
|
||||
|
||||
pub mod client;
|
||||
pub mod error;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! Timeline層の実装
|
||||
//! Timeline層
|
||||
//!
|
||||
//! イベントストリームを受信し、登録されたHandlerへディスパッチする
|
||||
//! LLMからのイベントストリームを受信し、登録されたHandlerにディスパッチします。
|
||||
//! 通常はWorker経由で使用しますが、直接使用することも可能です。
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
|
@ -10,9 +11,11 @@ use worker_types::*;
|
|||
// Type-erased Handler
|
||||
// =============================================================================
|
||||
|
||||
/// 型消去されたHandler trait
|
||||
/// 型消去された`Handler` trait
|
||||
///
|
||||
/// 各Handlerは独自のScope型を持つため、Timelineで保持するには型消去が必要
|
||||
/// 各Handlerは独自のScope型を持つため、Timelineで保持するには型消去が必要です。
|
||||
/// 通常は直接使用せず、`Timeline::on_text_block()`などのメソッド経由で
|
||||
/// 自動的にラップされます。
|
||||
pub trait ErasedHandler<K: Kind>: Send {
|
||||
/// イベントをディスパッチ
|
||||
fn dispatch(&mut self, event: &K::Event);
|
||||
|
|
@ -22,7 +25,7 @@ pub trait ErasedHandler<K: Kind>: Send {
|
|||
fn end_scope(&mut self);
|
||||
}
|
||||
|
||||
/// Handler<K>からErasedHandler<K>へのラッパー
|
||||
/// `Handler<K>`を`ErasedHandler<K>`として扱うためのラッパー
|
||||
pub struct HandlerWrapper<H, K>
|
||||
where
|
||||
H: Handler<K>,
|
||||
|
|
@ -316,13 +319,34 @@ where
|
|||
// Timeline
|
||||
// =============================================================================
|
||||
|
||||
/// Timeline - イベントストリームの状態管理とディスパッチ
|
||||
/// イベントストリームの管理とハンドラへのディスパッチ
|
||||
///
|
||||
/// # 責務
|
||||
/// 1. Eventストリームを受信
|
||||
/// 2. Block系イベントをBlockKindごとのライフサイクルイベントに変換
|
||||
/// 3. 各Handlerごとのスコープの生成・管理
|
||||
/// 4. 登録されたHandlerへの登録順ディスパッチ
|
||||
/// LLMからのイベントを受信し、登録されたハンドラに振り分けます。
|
||||
/// ブロック系イベントはスコープ管理付きで処理されます。
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::{Timeline, Handler, TextBlockKind, TextBlockEvent};
|
||||
///
|
||||
/// struct MyHandler;
|
||||
/// impl Handler<TextBlockKind> for MyHandler {
|
||||
/// type Scope = String;
|
||||
/// fn on_event(&mut self, buffer: &mut String, event: &TextBlockEvent) {
|
||||
/// if let TextBlockEvent::Delta(text) = event {
|
||||
/// buffer.push_str(text);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let mut timeline = Timeline::new();
|
||||
/// timeline.on_text_block(MyHandler);
|
||||
/// ```
|
||||
///
|
||||
/// # サポートするイベント種別
|
||||
///
|
||||
/// - **メタ系**: Usage, Ping, Status, Error
|
||||
/// - **ブロック系**: TextBlock, ThinkingBlock, ToolUseBlock
|
||||
pub struct Timeline {
|
||||
// Meta系ハンドラー
|
||||
usage_handlers: Vec<Box<dyn ErasedHandler<UsageKind>>>,
|
||||
|
|
|
|||
|
|
@ -82,20 +82,40 @@ impl<S: WorkerSubscriber + 'static> TurnNotifier for SubscriberTurnNotifier<S> {
|
|||
// Worker
|
||||
// =============================================================================
|
||||
|
||||
/// Worker - ターン制御コンポーネント
|
||||
/// LLMとの対話を管理する中心コンポーネント
|
||||
///
|
||||
/// Type-stateパターンによりキャッシュ保護を実現する。
|
||||
/// ユーザーからの入力を受け取り、LLMにリクエストを送信し、
|
||||
/// ツール呼び出しがあれば自動的に実行してターンを進行させます。
|
||||
///
|
||||
/// # 状態
|
||||
/// - `Mutable`: 初期状態。システムプロンプトや履歴を自由に編集可能。
|
||||
/// - `Locked`: キャッシュ保護状態。前方コンテキストは不変となり、追記のみ可能。
|
||||
/// # 状態遷移(Type-state)
|
||||
///
|
||||
/// # 責務
|
||||
/// - LLMへのリクエスト送信とレスポンス処理
|
||||
/// - ツール呼び出しの収集と実行
|
||||
/// - Hookによる介入の提供
|
||||
/// - ターンループの制御
|
||||
/// - 履歴の所有と管理
|
||||
/// - [`Mutable`]: 初期状態。システムプロンプトや履歴を自由に編集可能。
|
||||
/// - [`Locked`]: キャッシュ保護状態。`lock()`で遷移。前方コンテキストは不変。
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::{Worker, Message};
|
||||
///
|
||||
/// // Workerを作成してツールを登録
|
||||
/// let mut worker = Worker::new(client)
|
||||
/// .system_prompt("You are a helpful assistant.");
|
||||
/// worker.register_tool(my_tool);
|
||||
///
|
||||
/// // 対話を実行
|
||||
/// let history = worker.run("Hello!").await?;
|
||||
/// ```
|
||||
///
|
||||
/// # キャッシュ保護が必要な場合
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut worker = Worker::new(client)
|
||||
/// .system_prompt("...");
|
||||
///
|
||||
/// // 履歴を設定後、ロックしてキャッシュを保護
|
||||
/// let mut locked = worker.lock();
|
||||
/// locked.run("user input").await?;
|
||||
/// ```
|
||||
pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
|
||||
/// LLMクライアント
|
||||
client: C,
|
||||
|
|
@ -128,13 +148,37 @@ pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
|
|||
// =============================================================================
|
||||
|
||||
impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
||||
/// WorkerSubscriberを登録
|
||||
/// イベント購読者を登録する
|
||||
///
|
||||
/// Subscriberは以下のイベントを受け取ることができる:
|
||||
/// - ブロックイベント: on_text_block, on_tool_use_block
|
||||
/// - 単発イベント: on_usage, on_status, on_error
|
||||
/// - 累積イベント: on_text_complete, on_tool_call_complete
|
||||
/// - ターン制御: on_turn_start, on_turn_end
|
||||
/// 登録したSubscriberは、LLMからのストリーミングイベントを
|
||||
/// リアルタイムで受信できます。UIへのストリーム表示などに利用します。
|
||||
///
|
||||
/// # 受信できるイベント
|
||||
///
|
||||
/// - **ブロックイベント**: `on_text_block`, `on_tool_use_block`
|
||||
/// - **メタイベント**: `on_usage`, `on_status`, `on_error`
|
||||
/// - **完了イベント**: `on_text_complete`, `on_tool_call_complete`
|
||||
/// - **ターン制御**: `on_turn_start`, `on_turn_end`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::{Worker, WorkerSubscriber, TextBlockEvent};
|
||||
///
|
||||
/// struct MyPrinter;
|
||||
/// impl WorkerSubscriber for MyPrinter {
|
||||
/// type TextBlockScope = ();
|
||||
/// type ToolUseBlockScope = ();
|
||||
///
|
||||
/// fn on_text_block(&mut self, _: &mut (), event: &TextBlockEvent) {
|
||||
/// if let TextBlockEvent::Delta(text) = event {
|
||||
/// print!("{}", text);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// worker.subscribe(MyPrinter);
|
||||
/// ```
|
||||
pub fn subscribe<Sub: WorkerSubscriber + 'static>(&mut self, subscriber: Sub) {
|
||||
let subscriber = Arc::new(Mutex::new(subscriber));
|
||||
|
||||
|
|
@ -159,7 +203,19 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
.push(Box::new(SubscriberTurnNotifier { subscriber }));
|
||||
}
|
||||
|
||||
/// ツールを登録
|
||||
/// ツールを登録する
|
||||
///
|
||||
/// 登録されたツールはLLMからの呼び出しで自動的に実行されます。
|
||||
/// 同名のツールを登録した場合、後から登録したものが優先されます。
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::Worker;
|
||||
/// use my_tools::SearchTool;
|
||||
///
|
||||
/// worker.register_tool(SearchTool::new());
|
||||
/// ```
|
||||
pub fn register_tool(&mut self, tool: impl Tool + 'static) {
|
||||
let name = tool.name().to_string();
|
||||
self.tools.insert(name, Arc::new(tool));
|
||||
|
|
@ -172,7 +228,28 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Hookを追加
|
||||
/// Hookを追加する
|
||||
///
|
||||
/// Hookはターンの進行・ツール実行に介入できます。
|
||||
/// 複数のHookを登録した場合、登録順に実行されます。
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use worker::{Worker, WorkerHook, ControlFlow, ToolCall};
|
||||
///
|
||||
/// struct LoggingHook;
|
||||
///
|
||||
/// #[async_trait::async_trait]
|
||||
/// impl WorkerHook for LoggingHook {
|
||||
/// async fn before_tool_call(&self, call: &mut ToolCall) -> Result<ControlFlow, HookError> {
|
||||
/// println!("Calling tool: {}", call.name);
|
||||
/// Ok(ControlFlow::Continue)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// worker.add_hook(LoggingHook);
|
||||
/// ```
|
||||
pub fn add_hook(&mut self, hook: impl WorkerHook + 'static) {
|
||||
self.hooks.push(Box::new(hook));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user