ストリーミングUI
Goa-AIストリーミングイベントを消費するリアルタイムユーザーインターフェースの構築。
Goa-AIは構造化されたイベントストリームを提供し、レスポンシブなリアルタイムUIの構築を可能にします。
ストリームイベント
Goa-AIは以下のイベントタイプを発行します:
AssistantReply– アシスタントテキストのチャンクPlannerThought– 思考/推論ブロックToolStart– ツール実行の開始ToolUpdate– ツールの進捗更新ToolEnd– 結果を伴うツール完了AgentRunStarted– 子エージェントラン(リンクあり)AwaitClarification– ユーザー入力を待機中AwaitExternalTools– 外部ツールを待機中Usage– トークン使用量メトリクスWorkflow– ワークフロー状態の変更
ストリームへの接続
type MySink struct{}
func (s *MySink) OnEvent(ctx context.Context, event stream.Event) error {
switch e := event.(type) {
case *stream.AssistantReply:
fmt.Printf("アシスタント: %s", e.Text)
case *stream.ToolStart:
fmt.Printf("ツール開始: %s", e.ToolID)
case *stream.ToolEnd:
fmt.Printf("ツール終了: %s", e.ToolID)
case *stream.AgentRunStarted:
fmt.Printf("子エージェント: %s (run: %s)", e.AgentID, e.ChildRunID)
}
return nil
}
// サブスクライブ
sink := &MySink{}
stop, err := rt.SubscribeRun(ctx, runID, sink)
if err != nil {
return err
}
defer stop()
UI設計パターン
チャットメッセージ
AssistantReplyイベントをバッファリングして、現在のメッセージコンテンツを構築:
const [message, setMessage] = useState("");
onEvent((event) => {
if (event.type === "assistant_reply") {
setMessage(prev => prev + event.text);
}
});
ツールステータス
ToolStartとToolEndを追跡してローディングインジケーターを表示:
const [activeTools, setActiveTools] = useState<Set<string>>(new Set());
onEvent((event) => {
if (event.type === "tool_start") {
setActiveTools(prev => new Set([...prev, event.toolCallId]));
}
if (event.type === "tool_end") {
setActiveTools(prev => {
const next = new Set(prev);
next.delete(event.toolCallId);
return next;
});
}
});
ネストされたエージェント
AgentRunStartedを使用して子エージェントのUIを作成:
onEvent((event) => {
if (event.type === "agent_run_started") {
// childRunIdでサブスクライブして子イベントを取得
subscribeToRun(event.childRunId);
}
});