feat: Introduce event timeline and handler system
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
//! Timeline使用例
|
||||
//!
|
||||
//! 設計ドキュメントに基づいたTimelineの使用パターンを示すサンプル
|
||||
|
||||
use worker::{
|
||||
Event, Handler, TextBlockEvent, TextBlockKind, Timeline,
|
||||
ToolUseBlockEvent, ToolUseBlockKind, UsageEvent, UsageKind,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
// シミュレートされたイベントストリーム
|
||||
let events = simulate_llm_response();
|
||||
|
||||
// Timelineを作成し、ハンドラーを登録
|
||||
let mut timeline = Timeline::new();
|
||||
|
||||
// Usage収集ハンドラー
|
||||
timeline.on_usage(UsageAccumulator::new());
|
||||
|
||||
// テキスト収集ハンドラー
|
||||
timeline.on_text_block(TextCollector::new());
|
||||
|
||||
// ツール呼び出し収集ハンドラー
|
||||
timeline.on_tool_use_block(ToolCallCollector::new());
|
||||
|
||||
// イベントをディスパッチ
|
||||
for event in &events {
|
||||
timeline.dispatch(event);
|
||||
}
|
||||
|
||||
println!("Timeline example completed!");
|
||||
println!("Events processed: {}", events.len());
|
||||
}
|
||||
|
||||
/// LLMレスポンスをシミュレート
|
||||
fn simulate_llm_response() -> Vec<Event> {
|
||||
vec![
|
||||
// テキストブロック
|
||||
Event::text_block_start(0),
|
||||
Event::text_delta(0, "Hello, "),
|
||||
Event::text_delta(0, "I can help you with that."),
|
||||
Event::text_block_stop(0, None),
|
||||
// 使用量
|
||||
Event::usage(100, 50),
|
||||
// ツール呼び出し
|
||||
Event::tool_use_start(1, "call_abc123", "get_weather"),
|
||||
Event::tool_input_delta(1, r#"{"city":"#),
|
||||
Event::tool_input_delta(1, r#""Tokyo"}"#),
|
||||
Event::tool_use_stop(1),
|
||||
// 最終的な使用量
|
||||
Event::usage(100, 75),
|
||||
]
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Example Handlers (defined in example, not in library)
|
||||
// =============================================================================
|
||||
|
||||
/// 使用量を累積するハンドラー
|
||||
struct UsageAccumulator {
|
||||
total_tokens: u64,
|
||||
}
|
||||
|
||||
impl UsageAccumulator {
|
||||
fn new() -> Self {
|
||||
Self { total_tokens: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<UsageKind> for UsageAccumulator {
|
||||
type Scope = ();
|
||||
fn on_event(&mut self, _scope: &mut (), usage: &UsageEvent) {
|
||||
self.total_tokens += usage.total_tokens.unwrap_or(0);
|
||||
}
|
||||
}
|
||||
|
||||
/// テキストを収集するハンドラー
|
||||
struct TextCollector {
|
||||
results: Vec<String>,
|
||||
}
|
||||
|
||||
impl TextCollector {
|
||||
fn new() -> Self {
|
||||
Self { results: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<TextBlockKind> for TextCollector {
|
||||
type Scope = String;
|
||||
fn on_event(&mut self, buffer: &mut String, event: &TextBlockEvent) {
|
||||
match event {
|
||||
TextBlockEvent::Start(_) => {}
|
||||
TextBlockEvent::Delta(s) => buffer.push_str(s),
|
||||
TextBlockEvent::Stop(_) => {
|
||||
self.results.push(std::mem::take(buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ツール呼び出しを収集するハンドラー
|
||||
struct ToolCallCollector {
|
||||
calls: Vec<(String, String)>, // (name, args)
|
||||
}
|
||||
|
||||
impl ToolCallCollector {
|
||||
fn new() -> Self {
|
||||
Self { calls: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ToolCallScope {
|
||||
name: String,
|
||||
args: String,
|
||||
}
|
||||
|
||||
impl Handler<ToolUseBlockKind> for ToolCallCollector {
|
||||
type Scope = ToolCallScope;
|
||||
fn on_event(&mut self, scope: &mut ToolCallScope, event: &ToolUseBlockEvent) {
|
||||
match event {
|
||||
ToolUseBlockEvent::Start(s) => scope.name = s.name.clone(),
|
||||
ToolUseBlockEvent::InputJsonDelta(json) => scope.args.push_str(json),
|
||||
ToolUseBlockEvent::Stop(_) => {
|
||||
self.calls.push((
|
||||
std::mem::take(&mut scope.name),
|
||||
std::mem::take(&mut scope.args),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user