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};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -8,21 +9,38 @@ use serde::{Deserialize, Serialize};
|
||||||
// Core Event Types (from llm_client layer)
|
// 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)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
// Meta events (not tied to a block)
|
/// ハートビート
|
||||||
Ping(PingEvent),
|
Ping(PingEvent),
|
||||||
|
/// トークン使用量
|
||||||
Usage(UsageEvent),
|
Usage(UsageEvent),
|
||||||
|
/// ストリームのステータス変化
|
||||||
Status(StatusEvent),
|
Status(StatusEvent),
|
||||||
|
/// エラー発生
|
||||||
Error(ErrorEvent),
|
Error(ErrorEvent),
|
||||||
|
|
||||||
// Block lifecycle events
|
/// ブロック開始(テキスト、ツール使用等)
|
||||||
BlockStart(BlockStart),
|
BlockStart(BlockStart),
|
||||||
|
/// ブロックの差分データ
|
||||||
BlockDelta(BlockDelta),
|
BlockDelta(BlockDelta),
|
||||||
|
/// ブロック正常終了
|
||||||
BlockStop(BlockStop),
|
BlockStop(BlockStop),
|
||||||
|
/// ブロック中断
|
||||||
BlockAbort(BlockAbort),
|
BlockAbort(BlockAbort),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
//! Handler/Kind関連の型定義
|
//! Handler/Kind型
|
||||||
//!
|
//!
|
||||||
//! Timeline層でのイベント処理に使用するトレイトとKind定義
|
//! Timeline層でイベントを処理するためのトレイト。
|
||||||
|
//! カスタムハンドラを実装してTimelineに登録することで、
|
||||||
|
//! ストリームイベントを受信できます。
|
||||||
|
|
||||||
use crate::event::*;
|
use crate::event::*;
|
||||||
|
|
||||||
|
|
@ -8,10 +10,11 @@ use crate::event::*;
|
||||||
// Kind Trait
|
// Kind Trait
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/// Kindはイベント型のみを定義する
|
/// イベント種別を定義するマーカートレイト
|
||||||
///
|
///
|
||||||
/// スコープはHandler側で定義するため、同じKindに対して
|
/// 各Kindは対応するイベント型を指定します。
|
||||||
/// 異なるスコープを持つHandlerを登録できる
|
/// HandlerはこのKindに対して実装され、同じKindに対して
|
||||||
|
/// 異なるScope型を持つ複数のHandlerを登録できます。
|
||||||
pub trait Kind {
|
pub trait Kind {
|
||||||
/// このKindに対応するイベント型
|
/// このKindに対応するイベント型
|
||||||
type Event;
|
type Event;
|
||||||
|
|
@ -21,9 +24,39 @@ pub trait Kind {
|
||||||
// Handler Trait
|
// 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> {
|
pub trait Handler<K: Kind> {
|
||||||
/// Handler固有のスコープ型
|
/// Handler固有のスコープ型
|
||||||
|
///
|
||||||
|
/// ブロック開始時に`Default::default()`で生成され、
|
||||||
|
/// ブロック終了時に破棄されます。
|
||||||
type Scope: Default;
|
type Scope: Default;
|
||||||
|
|
||||||
/// イベントを処理する
|
/// イベントを処理する
|
||||||
|
|
|
||||||
|
|
@ -101,15 +101,50 @@ pub enum HookError {
|
||||||
// WorkerHook Trait
|
// WorkerHook Trait
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/// Worker Hook trait
|
/// ターンの進行・ツール実行に介入するためのトレイト
|
||||||
///
|
///
|
||||||
/// ターンの進行・メッセージ・ツール実行に対して介入するためのトレイト。
|
/// Hookを使うと、メッセージ送信前、ツール実行前後、ターン終了時に
|
||||||
/// デフォルト実装では何も行わずContinueを返す。
|
/// 処理を挟んだり、実行をキャンセルしたりできます。
|
||||||
|
///
|
||||||
|
/// # 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]
|
#[async_trait]
|
||||||
pub trait WorkerHook: Send + Sync {
|
pub trait WorkerHook: Send + Sync {
|
||||||
/// メッセージ送信前
|
/// メッセージ送信前に呼ばれる
|
||||||
///
|
///
|
||||||
/// リクエストに含まれるメッセージリストを改変できる。
|
/// リクエストに含まれるメッセージリストを参照・改変できます。
|
||||||
|
/// `ControlFlow::Abort`を返すとターンが中断されます。
|
||||||
async fn on_message_send(
|
async fn on_message_send(
|
||||||
&self,
|
&self,
|
||||||
_context: &mut Vec<crate::Message>,
|
_context: &mut Vec<crate::Message>,
|
||||||
|
|
@ -117,16 +152,17 @@ pub trait WorkerHook: Send + Sync {
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ツール実行前
|
/// ツール実行前に呼ばれる
|
||||||
///
|
///
|
||||||
/// 実行をキャンセルしたり、引数を書き換えることができる。
|
/// ツール呼び出しの引数を書き換えたり、実行をスキップしたりできます。
|
||||||
|
/// `ControlFlow::Skip`を返すとこのツールの実行がスキップされます。
|
||||||
async fn before_tool_call(&self, _tool_call: &mut ToolCall) -> Result<ControlFlow, HookError> {
|
async fn before_tool_call(&self, _tool_call: &mut ToolCall) -> Result<ControlFlow, HookError> {
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ツール実行後
|
/// ツール実行後に呼ばれる
|
||||||
///
|
///
|
||||||
/// 結果を書き換えたり、隠蔽したりできる。
|
/// ツールの実行結果を書き換えたり、隠蔽したりできます。
|
||||||
async fn after_tool_call(
|
async fn after_tool_call(
|
||||||
&self,
|
&self,
|
||||||
_tool_result: &mut ToolResult,
|
_tool_result: &mut ToolResult,
|
||||||
|
|
@ -134,9 +170,11 @@ pub trait WorkerHook: Send + Sync {
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ターン終了時
|
/// ターン終了時に呼ばれる
|
||||||
///
|
///
|
||||||
/// 生成されたメッセージを検査し、必要ならリトライを指示できる。
|
/// 生成されたメッセージを検査し、必要なら追加メッセージで継続を指示できます。
|
||||||
|
/// `TurnResult::ContinueWithMessages`を返すと、指定したメッセージを追加して
|
||||||
|
/// 次のターンに進みます。
|
||||||
async fn on_turn_end(&self, _messages: &[crate::Message]) -> Result<TurnResult, HookError> {
|
async fn on_turn_end(&self, _messages: &[crate::Message]) -> Result<TurnResult, HookError> {
|
||||||
Ok(TurnResult::Finish)
|
Ok(TurnResult::Finish)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
//! worker-types - LLMワーカーで使用される型定義
|
//! worker-types - LLMワーカーの型定義
|
||||||
//!
|
//!
|
||||||
//! このクレートは以下を提供します:
|
//! このクレートは`worker`クレートで使用される型を提供します。
|
||||||
//! - Event: llm_client層からのフラットなイベント列挙
|
//! 通常は直接使用せず、`worker`クレート経由で利用してください。
|
||||||
//! - Kind/Handler: タイムライン層でのイベント処理トレイト
|
//!
|
||||||
//! - Tool: ツール定義トレイト
|
//! ```ignore
|
||||||
//! - Hook: Worker層での介入用トレイト
|
//! use worker::{Event, Message, Tool, WorkerHook};
|
||||||
//! - Message: メッセージ型
|
//! ```
|
||||||
//! - 各種イベント構造体
|
|
||||||
|
|
||||||
mod event;
|
mod event;
|
||||||
mod handler;
|
mod handler;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
//! メッセージ型定義
|
//! メッセージ型
|
||||||
//!
|
//!
|
||||||
//! LLM会話で使用されるメッセージ構造
|
//! LLMとの会話で使用されるメッセージ構造。
|
||||||
|
//! [`Message::user`]や[`Message::assistant`]で簡単に作成できます。
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -14,7 +15,19 @@ pub enum Role {
|
||||||
Assistant,
|
Assistant,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// メッセージ
|
/// 会話のメッセージ
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// use worker::Message;
|
||||||
|
///
|
||||||
|
/// // ユーザーメッセージ
|
||||||
|
/// let user_msg = Message::user("Hello!");
|
||||||
|
///
|
||||||
|
/// // アシスタントメッセージ
|
||||||
|
/// let assistant_msg = Message::assistant("Hi there!");
|
||||||
|
/// ```
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
/// ロール
|
/// ロール
|
||||||
|
|
@ -62,6 +75,13 @@ pub enum ContentPart {
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
/// ユーザーメッセージを作成
|
/// ユーザーメッセージを作成
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// use worker::Message;
|
||||||
|
/// let msg = Message::user("こんにちは");
|
||||||
|
/// ```
|
||||||
pub fn user(content: impl Into<String>) -> Self {
|
pub fn user(content: impl Into<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
role: Role::User,
|
role: Role::User,
|
||||||
|
|
@ -70,6 +90,9 @@ impl Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// アシスタントメッセージを作成
|
/// アシスタントメッセージを作成
|
||||||
|
///
|
||||||
|
/// 通常はWorker内部で自動生成されますが、
|
||||||
|
/// 履歴の初期化などで手動作成も可能です。
|
||||||
pub fn assistant(content: impl Into<String>) -> Self {
|
pub fn assistant(content: impl Into<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
role: Role::Assistant,
|
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 {
|
pub fn tool_result(tool_use_id: impl Into<String>, content: impl Into<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
role: Role::User,
|
role: Role::User,
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,41 @@
|
||||||
//! Worker状態マーカー型
|
//! Worker状態
|
||||||
//!
|
//!
|
||||||
//! Type-stateパターンによるキャッシュ保護のための状態定義
|
//! Type-stateパターンによるキャッシュ保護のための状態マーカー型。
|
||||||
|
//! Workerは`Mutable` → `Locked`の状態遷移を持ちます。
|
||||||
|
|
||||||
/// Worker状態を表すマーカートレイト
|
/// Worker状態を表すマーカートレイト
|
||||||
///
|
///
|
||||||
/// このトレイトはシールされており、外部から実装することはできない。
|
/// このトレイトはシールされており、外部から実装することはできません。
|
||||||
pub trait WorkerState: private::Sealed + Send + Sync + 'static {}
|
pub trait WorkerState: private::Sealed + Send + Sync + 'static {}
|
||||||
|
|
||||||
mod private {
|
mod private {
|
||||||
pub trait Sealed {}
|
pub trait Sealed {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 変更可能状態
|
/// 編集可能状態
|
||||||
///
|
///
|
||||||
/// この状態では以下の操作が可能:
|
/// この状態では以下の操作が可能です:
|
||||||
/// - システムプロンプトの設定・変更
|
/// - システムプロンプトの設定・変更
|
||||||
/// - メッセージ履歴の編集(追加、削除、クリア)
|
/// - メッセージ履歴の編集(追加、削除、クリア)
|
||||||
/// - ツール・Hookの登録
|
/// - ツール・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)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct Mutable;
|
pub struct Mutable;
|
||||||
|
|
||||||
|
|
@ -27,12 +44,15 @@ impl WorkerState for Mutable {}
|
||||||
|
|
||||||
/// ロック状態(キャッシュ保護)
|
/// ロック状態(キャッシュ保護)
|
||||||
///
|
///
|
||||||
/// この状態では以下の制限がある:
|
/// この状態では以下の制限があります:
|
||||||
/// - システムプロンプトの変更不可
|
/// - システムプロンプトの変更不可
|
||||||
/// - 既存メッセージ履歴の変更不可(末尾への追記のみ)
|
/// - 既存メッセージ履歴の変更不可(末尾への追記のみ)
|
||||||
///
|
///
|
||||||
/// 実行(`run`)はこの状態で行うことが推奨される。
|
/// LLM APIのKVキャッシュヒットを保証するため、
|
||||||
/// キャッシュヒットを保証するため、前方のコンテキストは不変となる。
|
/// 実行時にはこの状態の使用が推奨されます。
|
||||||
|
///
|
||||||
|
/// `Worker::unlock()`により[`Mutable`]状態へ戻せますが、
|
||||||
|
/// キャッシュ保護が解除されることに注意してください。
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct Locked;
|
pub struct Locked;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! WorkerSubscriber - Worker層のイベント購読トレイト
|
//! イベント購読
|
||||||
//!
|
//!
|
||||||
//! Timeline層のHandler機構の薄いラッパーとして設計され、
|
//! LLMからのストリーミングイベントをリアルタイムで受信するためのトレイト。
|
||||||
//! UIへのストリーミング表示やリアルタイムフィードバックを可能にする。
|
//! UIへのストリーム表示やプログレス表示に使用します。
|
||||||
|
|
||||||
use crate::{ErrorEvent, StatusEvent, TextBlockEvent, ToolCall, ToolUseBlockEvent, UsageEvent};
|
use crate::{ErrorEvent, StatusEvent, TextBlockEvent, ToolCall, ToolUseBlockEvent, UsageEvent};
|
||||||
|
|
||||||
|
|
@ -9,39 +9,42 @@ use crate::{ErrorEvent, StatusEvent, TextBlockEvent, ToolCall, ToolUseBlockEvent
|
||||||
// WorkerSubscriber Trait
|
// WorkerSubscriber Trait
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/// Worker層の統合Subscriberトレイト
|
/// LLMからのストリーミングイベントを購読するトレイト
|
||||||
///
|
///
|
||||||
/// Timeline層のHandler機構をラップし、以下のイベントを一括で購読できる:
|
/// Workerに登録すると、テキスト生成やツール呼び出しのイベントを
|
||||||
/// - ブロックイベント(スコープ管理あり): Text, ToolUse
|
/// リアルタイムで受信できます。UIへのストリーム表示に最適です。
|
||||||
/// - 単発イベント: Usage, Status, Error
|
|
||||||
/// - 累積イベント(Worker層で追加): TextComplete, ToolCallComplete
|
|
||||||
/// - ターン制御: TurnStart, TurnEnd
|
|
||||||
///
|
///
|
||||||
/// # 使用例
|
/// # 受信できるイベント
|
||||||
|
///
|
||||||
|
/// - **ブロックイベント**: テキスト、ツール使用(スコープ付き)
|
||||||
|
/// - **メタイベント**: 使用量、ステータス、エラー
|
||||||
|
/// - **完了イベント**: テキスト完了、ツール呼び出し完了
|
||||||
|
/// - **ターン制御**: ターン開始、ターン終了
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// struct MyUI {
|
/// use worker::{WorkerSubscriber, TextBlockEvent};
|
||||||
/// chat_view: ChatView,
|
|
||||||
/// }
|
|
||||||
///
|
///
|
||||||
/// impl WorkerSubscriber for MyUI {
|
/// struct StreamPrinter;
|
||||||
/// type TextBlockScope = String;
|
|
||||||
/// type ToolUseBlockScope = ToolComponent;
|
|
||||||
///
|
///
|
||||||
/// fn on_text_block(&mut self, buffer: &mut String, event: &TextBlockEvent) {
|
/// impl WorkerSubscriber for StreamPrinter {
|
||||||
/// match event {
|
/// type TextBlockScope = ();
|
||||||
/// TextBlockEvent::Delta(text) => {
|
/// type ToolUseBlockScope = ();
|
||||||
/// buffer.push_str(text);
|
///
|
||||||
/// self.chat_view.update(buffer);
|
/// 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) {
|
/// 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 {
|
pub trait WorkerSubscriber: Send {
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,90 @@
|
||||||
|
//! ツール定義
|
||||||
|
//!
|
||||||
|
//! LLMから呼び出し可能なツールを定義するためのトレイト。
|
||||||
|
//! 通常は`#[tool]`マクロを使用して自動実装します。
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// ツール実行時のエラー
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ToolError {
|
pub enum ToolError {
|
||||||
|
/// 引数が不正
|
||||||
#[error("Invalid argument: {0}")]
|
#[error("Invalid argument: {0}")]
|
||||||
InvalidArgument(String),
|
InvalidArgument(String),
|
||||||
|
/// 実行に失敗
|
||||||
#[error("Execution failed: {0}")]
|
#[error("Execution failed: {0}")]
|
||||||
ExecutionFailed(String),
|
ExecutionFailed(String),
|
||||||
|
/// 内部エラー
|
||||||
#[error("Internal error: {0}")]
|
#[error("Internal error: {0}")]
|
||||||
Internal(String),
|
Internal(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ツール定義トレイト
|
/// LLMから呼び出し可能なツールを定義するトレイト
|
||||||
///
|
///
|
||||||
/// ユーザー定義のツールはこれを実装し、Workerに登録される。
|
/// ツールはLLMが外部リソースにアクセスしたり、
|
||||||
/// 通常は `#[tool]` マクロによって自動生成される。
|
/// 計算を実行したりするために使用します。
|
||||||
|
///
|
||||||
|
/// # 実装方法
|
||||||
|
///
|
||||||
|
/// 通常は`#[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]
|
#[async_trait]
|
||||||
pub trait Tool: Send + Sync {
|
pub trait Tool: Send + Sync {
|
||||||
/// ツール名 (LLMが識別に使用)
|
/// ツール名(LLMが識別に使用)
|
||||||
fn name(&self) -> &str;
|
fn name(&self) -> &str;
|
||||||
|
|
||||||
/// ツールの説明 (LLMへのプロンプトに含まれる)
|
/// ツールの説明(LLMへのプロンプトに含まれる)
|
||||||
fn description(&self) -> &str;
|
fn description(&self) -> &str;
|
||||||
|
|
||||||
/// 引数のJSON Schema
|
/// 引数のJSON Schema
|
||||||
|
///
|
||||||
|
/// LLMはこのスキーマに従って引数を生成します。
|
||||||
fn input_schema(&self) -> Value;
|
fn input_schema(&self) -> Value;
|
||||||
|
|
||||||
/// 実行関数
|
/// ツールを実行する
|
||||||
/// JSON文字列を受け取り、デシリアライズして元のメソッドを実行し、結果を返す
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `input_json` - LLMが生成したJSON形式の引数
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// 実行結果の文字列。この内容がLLMに返されます。
|
||||||
async fn execute(&self, input_json: &str) -> Result<String, ToolError>;
|
async fn execute(&self, input_json: &str) -> Result<String, ToolError>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,39 @@
|
||||||
//! worker - LLMワーカーのメイン実装
|
//! worker - LLMワーカーライブラリ
|
||||||
//!
|
//!
|
||||||
//! このクレートは以下を提供します:
|
//! LLMとの対話を管理するコンポーネントを提供します。
|
||||||
//! - Worker: ターン制御を行う高レベルコンポーネント
|
//!
|
||||||
//! - Timeline: イベントストリームの状態管理とハンドラーへのディスパッチ
|
//! # 主要なコンポーネント
|
||||||
//! - LlmClient: LLMプロバイダとの通信
|
//!
|
||||||
//! - 型消去されたHandler実装
|
//! - [`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;
|
pub mod llm_client;
|
||||||
mod subscriber_adapter;
|
mod subscriber_adapter;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,19 @@
|
||||||
//! LLMクライアント層
|
//! LLMクライアント層
|
||||||
//!
|
//!
|
||||||
//! LLMプロバイダと通信し、統一された`Event`ストリームを出力する。
|
//! 各LLMプロバイダと通信し、統一された[`Event`](crate::Event)ストリームを出力します。
|
||||||
|
//!
|
||||||
|
//! # サポートするプロバイダ
|
||||||
|
//!
|
||||||
|
//! - Anthropic (Claude)
|
||||||
|
//! - OpenAI (GPT-4, etc.)
|
||||||
|
//! - Google (Gemini)
|
||||||
|
//! - Ollama (ローカルLLM)
|
||||||
//!
|
//!
|
||||||
//! # アーキテクチャ
|
//! # アーキテクチャ
|
||||||
//!
|
//!
|
||||||
//! - **client**: `LlmClient` trait定義
|
//! - [`LlmClient`] - プロバイダ共通のtrait
|
||||||
//! - **scheme**: APIスキーマ(リクエスト/レスポンス変換)
|
//! - `providers`: プロバイダ固有のクライアント実装
|
||||||
//! - **providers**: プロバイダ固有のHTTPクライアント実装
|
//! - `scheme`: APIスキーマ(リクエスト/レスポンス変換)
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
//! Timeline層の実装
|
//! Timeline層
|
||||||
//!
|
//!
|
||||||
//! イベントストリームを受信し、登録されたHandlerへディスパッチする
|
//! LLMからのイベントストリームを受信し、登録されたHandlerにディスパッチします。
|
||||||
|
//! 通常はWorker経由で使用しますが、直接使用することも可能です。
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
|
@ -10,9 +11,11 @@ use worker_types::*;
|
||||||
// Type-erased Handler
|
// Type-erased Handler
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/// 型消去されたHandler trait
|
/// 型消去された`Handler` trait
|
||||||
///
|
///
|
||||||
/// 各Handlerは独自のScope型を持つため、Timelineで保持するには型消去が必要
|
/// 各Handlerは独自のScope型を持つため、Timelineで保持するには型消去が必要です。
|
||||||
|
/// 通常は直接使用せず、`Timeline::on_text_block()`などのメソッド経由で
|
||||||
|
/// 自動的にラップされます。
|
||||||
pub trait ErasedHandler<K: Kind>: Send {
|
pub trait ErasedHandler<K: Kind>: Send {
|
||||||
/// イベントをディスパッチ
|
/// イベントをディスパッチ
|
||||||
fn dispatch(&mut self, event: &K::Event);
|
fn dispatch(&mut self, event: &K::Event);
|
||||||
|
|
@ -22,7 +25,7 @@ pub trait ErasedHandler<K: Kind>: Send {
|
||||||
fn end_scope(&mut self);
|
fn end_scope(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handler<K>からErasedHandler<K>へのラッパー
|
/// `Handler<K>`を`ErasedHandler<K>`として扱うためのラッパー
|
||||||
pub struct HandlerWrapper<H, K>
|
pub struct HandlerWrapper<H, K>
|
||||||
where
|
where
|
||||||
H: Handler<K>,
|
H: Handler<K>,
|
||||||
|
|
@ -316,13 +319,34 @@ where
|
||||||
// Timeline
|
// Timeline
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/// Timeline - イベントストリームの状態管理とディスパッチ
|
/// イベントストリームの管理とハンドラへのディスパッチ
|
||||||
///
|
///
|
||||||
/// # 責務
|
/// LLMからのイベントを受信し、登録されたハンドラに振り分けます。
|
||||||
/// 1. Eventストリームを受信
|
/// ブロック系イベントはスコープ管理付きで処理されます。
|
||||||
/// 2. Block系イベントをBlockKindごとのライフサイクルイベントに変換
|
///
|
||||||
/// 3. 各Handlerごとのスコープの生成・管理
|
/// # Examples
|
||||||
/// 4. 登録されたHandlerへの登録順ディスパッチ
|
///
|
||||||
|
/// ```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 {
|
pub struct Timeline {
|
||||||
// Meta系ハンドラー
|
// Meta系ハンドラー
|
||||||
usage_handlers: Vec<Box<dyn ErasedHandler<UsageKind>>>,
|
usage_handlers: Vec<Box<dyn ErasedHandler<UsageKind>>>,
|
||||||
|
|
|
||||||
|
|
@ -82,20 +82,40 @@ impl<S: WorkerSubscriber + 'static> TurnNotifier for SubscriberTurnNotifier<S> {
|
||||||
// Worker
|
// Worker
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/// Worker - ターン制御コンポーネント
|
/// LLMとの対話を管理する中心コンポーネント
|
||||||
///
|
///
|
||||||
/// Type-stateパターンによりキャッシュ保護を実現する。
|
/// ユーザーからの入力を受け取り、LLMにリクエストを送信し、
|
||||||
|
/// ツール呼び出しがあれば自動的に実行してターンを進行させます。
|
||||||
///
|
///
|
||||||
/// # 状態
|
/// # 状態遷移(Type-state)
|
||||||
/// - `Mutable`: 初期状態。システムプロンプトや履歴を自由に編集可能。
|
|
||||||
/// - `Locked`: キャッシュ保護状態。前方コンテキストは不変となり、追記のみ可能。
|
|
||||||
///
|
///
|
||||||
/// # 責務
|
/// - [`Mutable`]: 初期状態。システムプロンプトや履歴を自由に編集可能。
|
||||||
/// - LLMへのリクエスト送信とレスポンス処理
|
/// - [`Locked`]: キャッシュ保護状態。`lock()`で遷移。前方コンテキストは不変。
|
||||||
/// - ツール呼び出しの収集と実行
|
///
|
||||||
/// - Hookによる介入の提供
|
/// # 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> {
|
pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
|
||||||
/// LLMクライアント
|
/// LLMクライアント
|
||||||
client: C,
|
client: C,
|
||||||
|
|
@ -128,13 +148,37 @@ pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
||||||
/// WorkerSubscriberを登録
|
/// イベント購読者を登録する
|
||||||
///
|
///
|
||||||
/// Subscriberは以下のイベントを受け取ることができる:
|
/// 登録したSubscriberは、LLMからのストリーミングイベントを
|
||||||
/// - ブロックイベント: on_text_block, on_tool_use_block
|
/// リアルタイムで受信できます。UIへのストリーム表示などに利用します。
|
||||||
/// - 単発イベント: on_usage, on_status, on_error
|
///
|
||||||
/// - 累積イベント: on_text_complete, on_tool_call_complete
|
/// # 受信できるイベント
|
||||||
/// - ターン制御: on_turn_start, on_turn_end
|
///
|
||||||
|
/// - **ブロックイベント**: `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) {
|
pub fn subscribe<Sub: WorkerSubscriber + 'static>(&mut self, subscriber: Sub) {
|
||||||
let subscriber = Arc::new(Mutex::new(subscriber));
|
let subscriber = Arc::new(Mutex::new(subscriber));
|
||||||
|
|
||||||
|
|
@ -159,7 +203,19 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
||||||
.push(Box::new(SubscriberTurnNotifier { subscriber }));
|
.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) {
|
pub fn register_tool(&mut self, tool: impl Tool + 'static) {
|
||||||
let name = tool.name().to_string();
|
let name = tool.name().to_string();
|
||||||
self.tools.insert(name, Arc::new(tool));
|
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) {
|
pub fn add_hook(&mut self, hook: impl WorkerHook + 'static) {
|
||||||
self.hooks.push(Box::new(hook));
|
self.hooks.push(Box::new(hook));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user