TUIオーバーホールチケット
This commit is contained in:
parent
ca5a3d1152
commit
de3272fdfd
3
TODO.md
3
TODO.md
|
|
@ -7,7 +7,8 @@
|
|||
- [ ] モデル capability の責務を llm-worker 外へ → [tickets/llm-capability-ownership.md](tickets/llm-capability-ownership.md)
|
||||
- [ ] Pod オーケストレーション
|
||||
- [ ] 動的 Scope 変更 → [tickets/dynamic-scope.md](tickets/dynamic-scope.md)
|
||||
- [ ] protocol: ToolResult に summary を分離 → [tickets/protocol-tool-result-shape.md](tickets/protocol-tool-result-shape.md)
|
||||
- [ ] ネイティブ GUI クライアント MVP → [tickets/native-gui-mvp.md](tickets/native-gui-mvp.md)
|
||||
- [ ] TUI 拡充
|
||||
- [ ] フルスクリーン化によるオーバーホール → [tickets/tui-fullscreen-overhaul.md](tickets/tui-fullscreen-overhaul.md)
|
||||
- [ ] 新しい Pod を spawn する UI の設計 → [tickets/tui-pod-spawn-ui.md](tickets/tui-pod-spawn-ui.md)
|
||||
- [ ] ツール呼び出しのフレーム更新型表示 → [tickets/tui-tool-call-ui.md](tickets/tui-tool-call-ui.md)
|
||||
|
|
|
|||
34
tickets/protocol-tool-result-shape.md
Normal file
34
tickets/protocol-tool-result-shape.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# protocol: ToolResult に summary を分離する
|
||||
|
||||
## 背景
|
||||
|
||||
`protocol::Event::ToolResult` は現状 `{ id, output: String, is_error: bool }` で、ツール実装側の `llm_worker::tool::ToolOutput` が持っている **`summary: String`** を flatten して捨てている。
|
||||
|
||||
各 builtin tool は既に意味のある summary を返している:
|
||||
|
||||
- Write (`crates/tools/src/write.rs`): `Created /path (N bytes)` / `Overwrote /path (N bytes)`
|
||||
- Read / Edit / Glob / Grep も同様に構造化された要約を返している
|
||||
|
||||
TUI 側で「俯瞰ビュー」の 1 行サマリや status line の短縮表示に使いたいが、protocol に summary が無いため直接は取れない。`output` の先頭行を切るようなヒューリスティックは脆く、各ツールが意図した要約と一致しない。
|
||||
|
||||
本チケットは protocol 層の小さな拡張に閉じる。TUI 側での利用は後続のオーバーホールチケットで行う。
|
||||
|
||||
## 要件
|
||||
|
||||
- `Event::ToolResult` に `summary: String` を追加する
|
||||
- `output` と `is_error` は残す(用途が異なる: summary は 1 行、output は詳細本文)
|
||||
- ツール実装から流れてくる `ToolOutput.summary` がそのまま protocol に乗るように worker / pod 層を通す
|
||||
- `Event::History` の replay 経路でも summary が欠落しないこと(セッション再接続時に TUI が過去の ToolResult 表示を組み直せるため)
|
||||
|
||||
## 完了条件
|
||||
|
||||
- `Event::ToolResult` に `summary: String` が存在し、worker 側から流れてくる
|
||||
- 各 builtin tool (Read / Write / Edit / Glob / Grep) の `ToolOutput.summary` が TUI まで届く
|
||||
- `Event::History` replay でも summary が取得できる
|
||||
- 既存 TUI は summary を無視するだけで従前通り動く(UI 側での利用は別チケット)
|
||||
|
||||
## 範囲外
|
||||
|
||||
- `ToolOutput.content` の protocol 化。現時点では不要。必要になったら別チケット
|
||||
- summary 文言の規格化や整形。各ツール側の責務
|
||||
- TUI の summary 利用 (`tickets/tui-fullscreen-overhaul.md` で扱う)
|
||||
167
tickets/tui-fullscreen-overhaul.md
Normal file
167
tickets/tui-fullscreen-overhaul.md
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
# TUI: フルスクリーン化によるオーバーホール
|
||||
|
||||
## 背景
|
||||
|
||||
現在の TUI は **ratatui の inline viewport + `insert_before`** で動いている:
|
||||
|
||||
- `draw()` が描くのは画面下部の 3 行固定 (separator / status / input)
|
||||
- 履歴は `terminal.insert_before()` でその上に押し出し、ターミナル側のスクロールバックに残す
|
||||
- 一度 `insert_before` した行はアプリから書き換え不可
|
||||
|
||||
このモデルが以下の構造的課題を生んでいる:
|
||||
|
||||
1. **Input UX が貧弱**: Input は 1 行固定、複数行入力不可、ペーストすると長文が 1 行として流れる
|
||||
2. **リサイズでセパレーターが増殖**: ターミナル横幅が変わるたびに separator 行が再生成されてスクロールバックに流れ、履歴が汚れる
|
||||
3. **読み返し辛い**: TUI アプリ自身にスクロール機能がなく、ターミナル側スクロールバックに完全依存。折りたたみもフィルタリングもできない
|
||||
4. **ツール呼び出しが断片化**: `ToolCallStart` / `ToolCallDone` / `ToolResult` がそれぞれ別行として積まれ、1 呼び出しを連続した 1 ブロックとして見られない。`ToolCallArgsDelta` は **破棄されている** (`crates/tui/src/app.rs`)
|
||||
|
||||
個別対症療法では直しきれないため、**レンダリングモデルを alternate screen buffer + 全描画保持に切り替えるオーバーホール**として扱う。旧 `tui-tool-call-ui.md` は inline viewport 維持を前提にした設計だったため、本チケットに要件を吸収して削除する。
|
||||
|
||||
## 方針
|
||||
|
||||
- ratatui を alternate screen buffer で初期化し、inline viewport を捨てる
|
||||
- 全履歴を TUI アプリ内の state として保持、毎フレーム再描画
|
||||
- ターミナル側のスクロールバックには何も流さない(リサイズ時の汚染と永続履歴依存を同時に解消)
|
||||
- 履歴の見せ方をツール呼び出しやターン単位で集約可能にし、スクロール + 折りたたみ 3 段階で密度を変えられるようにする
|
||||
- ツール呼び出しは 1 呼び出し = 1 ブロック。ツール名で dispatch する **ツール毎レンダラ** のフレームワークを持つ
|
||||
- Input は複数行 / CJK / ペースト プレースホルダに対応
|
||||
|
||||
## 要件
|
||||
|
||||
### レンダリングモデル
|
||||
|
||||
- ratatui を alternate screen buffer で起動する。`insert_before` は使わない
|
||||
- アプリ終了時はスクロールバックに戻る(TUI が描いたものは残らない)
|
||||
- 再接続時は既存の `Event::History` で state を再構築する
|
||||
- ウィンドウリサイズは state を保ったまま再レイアウトする(セパレーター増殖等は発生しない)
|
||||
|
||||
### レイアウト
|
||||
|
||||
- 画面全体を以下で構成する:
|
||||
- 上部: 履歴ビュー(可変高さ、スクロール可)
|
||||
- 下部: ステータス行 (1 行) + Input エリア (可変高さ)
|
||||
- Input エリアが画面下部を占有しすぎないように上限を設ける(設計で決めること)
|
||||
|
||||
### 履歴モデル
|
||||
|
||||
- 最小単位は **ブロック**。種類: GreetingCard / TurnHeader / UserMessage / AssistantText / ToolCall / Notification / CompactEvent / TurnStats
|
||||
- ブロックは **ターン** にグループ化される。TurnHeader / UserMessage 〜 その turn の TurnStats までが 1 ターン
|
||||
- 履歴全体が state に保持され、モードに応じて各ブロックの見た目が変わる
|
||||
|
||||
### スクロール
|
||||
|
||||
- 行単位 / ページ単位のスクロール
|
||||
- ターン単位のジャンプ(前のターン / 次のターン / 先頭 / 末尾)
|
||||
- 末尾追従(常に最新を表示)は新規イベント到着でトリガ。ユーザーが手動で上にスクロールしている間は追従を停止
|
||||
|
||||
### 折りたたみモード
|
||||
|
||||
3 段階、全体トグルで切替。
|
||||
|
||||
- **detail**: 全ブロックを完全表示。ツールブロックは引数ストリーミング + 結果全体
|
||||
- **normal**: 実行中のツールブロックは detail と同じ。完了後は各ブロックが概ね 5〜6 行に収まるよう圧縮
|
||||
- **overview**: 各ブロックが 1 行。ツールブロックは `ToolResult.summary` をそのまま使う
|
||||
|
||||
### Input エリア
|
||||
|
||||
- 複数行、自動折り返し
|
||||
- CJK 含む Unicode 表示幅に基づく正しいカーソル位置 (`unicode-width`)
|
||||
- **ペースト プレースホルダ**: クリップボードから貼り付けられた文字列はプレースホルダ `[Clipboard #N | X chars, Y lines]` として入力バッファに挿入される。実テキストは裏で保持
|
||||
- プレースホルダは不可分(Backspace 1 回で全体が削除される。途中カーソルでの文字単位削除は不可)
|
||||
- 送信時にプレースホルダが実テキストに展開されて Pod に送られる(Pod 側には `#N` は見せない)
|
||||
- 番号付けの規則は設計で決めること
|
||||
- 既存キー操作(カーソル移動・削除)は複数行対応に拡張
|
||||
|
||||
### ツール UI フレームワーク
|
||||
|
||||
- ツール呼び出し 1 回 = 1 ブロック。`tool_use_id` で同一ブロックに集約
|
||||
- 各ブロックは以下の状態を遷移する:
|
||||
- **Pending**: `ToolCallStart` 受信、args 未確定
|
||||
- **Streaming**: `ToolCallArgsDelta` を連結中。ライブ反映
|
||||
- **Executing**: `ToolCallDone` 受信、args 確定、結果待ち
|
||||
- **Done / Error**: `ToolResult` 受信
|
||||
- **Incomplete**: `ToolResult` が来ないまま turn が終わった場合
|
||||
- ブロックの見た目は **ツール毎のレンダラ** が決める。ツール名で dispatch、マッチしなければデフォルトレンダラ
|
||||
- 並列ツール呼び出しは複数ブロックが同時に存在する。`tool_use_id` で振り分け
|
||||
- Streaming 中の args は生の文字列として連結し、途中の JSON を整形しようとしない(破綻する)
|
||||
|
||||
### 組み込みツールのレンダラ
|
||||
|
||||
実装対象: Read / Write / Edit / Glob / Grep / default。
|
||||
|
||||
- **Read**: 同一 turn 内で連続する Read 呼び出しを **1 ブロックに集約**する。normal / detail とも「読んだファイル数 + ファイルパスのリスト」を表示、中身は出さない。集約中のライブ表示は実行順に最大 3 行のスクロールウィンドウで読んだファイルを下から追加
|
||||
- **Write**: summary (Created / Overwrote をラベル色で区別) + 書き込まれた content の先頭 5 行。detail では content 全体
|
||||
- **Edit**: TUI 側 **ファイル content キャッシュ** から該当ファイルを引き、`args.old_string` / `args.new_string` の置換箇所に対して **前後 3 行の unified diff** を赤 / 緑で表示
|
||||
- **Glob**: `ToolResult.output` の先頭数行をそのまま表示
|
||||
- **Grep**: 同上
|
||||
- **default (未知ツール)**: normal で pretty JSON 化した args の先頭 3 行 + `ToolResult.output` の先頭 3 行。detail では全体
|
||||
|
||||
### ファイル content キャッシュ
|
||||
|
||||
Edit レンダラが diff を出すために TUI 側に持つ。責務は表示用で、ツール実装層の policy (`Tracker`) とは独立。
|
||||
|
||||
- Read レンダラが `ToolResult.output` からキャッシュに content を保存
|
||||
- Write レンダラが `args.content` でキャッシュを更新
|
||||
- Edit レンダラが `args.old_string` / `args.new_string` でローカル置換してキャッシュを更新
|
||||
- `Event::History` 再生時も同じ順序でキャッシュを再構築する
|
||||
|
||||
### 既存機能の移植
|
||||
|
||||
以下は現行 TUI に既にある機能で、新アーキテクチャでも保持する:
|
||||
|
||||
- Greeting カード表示
|
||||
- TurnHeader / UserMessage / AssistantText
|
||||
- Notification (Warn / Error レベル)
|
||||
- Compact 開始 / 完了 / 失敗
|
||||
- ターン終了時の統計 (requests / tokens)
|
||||
- Ctrl-C 2-tap でのアプリ終了 (Pod 自体は存続)
|
||||
- shutdown_confirm 挙動
|
||||
- Paused 状態での空 Enter → Resume
|
||||
- `Event::History` によるセッション再接続時の履歴復元
|
||||
|
||||
### 履歴再生
|
||||
|
||||
- `Event::History` を受けたとき、過去のツール呼び出しは **最終状態のブロック** として履歴モデルに組み直される
|
||||
- tool_call と tool_result の対応付け、および content キャッシュの再構築もこの経路で行う
|
||||
|
||||
### イベント欠落耐性
|
||||
|
||||
- プロバイダ起因でイベントが欠落したり順序が逆転しても panic しない
|
||||
- `ToolResult` が来ないまま `TurnEnd` が来た場合、該当ブロックは Incomplete として残す(握りつぶさず視覚化する)
|
||||
|
||||
## 設計で決めること
|
||||
|
||||
- **キーバインド**: スクロール / ターン移動 / モード切替 のキー割り当て
|
||||
- **折りたたみの粒度**: 全体トグルのみか、ターン単位の個別開閉も持たせるか
|
||||
- **Input エリアの高さ上限**: 画面の N% か絶対行数か
|
||||
- **ペースト番号付け**: TUI 起動中で通しか turn 毎にリセットするか
|
||||
- **normal モードの圧縮基準**: 5〜6 行は目安。ブロック種別毎の実装上の判断基準
|
||||
- **末尾追従の解除条件**: 上にスクロールした瞬間に解除するか、数行離れたら解除するか
|
||||
- **Read 集約の切れ目**: 「連続」の定義(別ツール呼び出しや assistant text が挟まったら切る / `ToolResult` の受信順で切る 等)
|
||||
|
||||
## 前提
|
||||
|
||||
- `tickets/protocol-tool-result-shape.md`: `Event::ToolResult` に `summary: String` が追加されていること
|
||||
|
||||
## 完了条件
|
||||
|
||||
- TUI が alternate screen buffer で起動し、アプリ終了でスクロールバックに何も残らない
|
||||
- ウィンドウリサイズで separator の増殖が発生しない
|
||||
- 既存機能 (greeting / turn / user / assistant / tool / notification / compact / stats / ctrl-c / paused / history) がすべて保持されている
|
||||
- 3 段モード (detail / normal / overview) で履歴の密度を切り替えられる
|
||||
- Input が複数行 / CJK / ペースト プレースホルダに対応している
|
||||
- ツール呼び出しが 1 ブロックとして表示され、start → args streaming → done → result の遷移が同じブロックの更新として見える
|
||||
- 組み込み 5 ツール (Read / Write / Edit / Glob / Grep) がそれぞれ専用レンダラで表示される
|
||||
- 未知ツールがデフォルトレンダラで表示される
|
||||
- 並列ツール呼び出しで `tool_use_id` が正しく振り分けられる
|
||||
- `ToolResult` が欠落したまま turn が終わった場合に該当ブロックが Incomplete として履歴に残り、panic しない
|
||||
- `Event::History` 再生で過去のツール呼び出しがブロックとして復元され、Edit レンダラ用の content キャッシュも再構築される
|
||||
|
||||
## 範囲外
|
||||
|
||||
- ツール実行のキャンセル / 介入 UI
|
||||
- 複数 Pod の spawn / 切替 UI (`tickets/tui-pod-spawn-ui.md`)
|
||||
- Markdown レンダリング / シンタックスハイライト / リッチ diff レンダリング
|
||||
- スクロールバック保存(仕様上出さない)
|
||||
- TUI 独自の履歴永続化(再接続時は Pod 側の `Event::History` に任せる)
|
||||
- 組み込みツールの `ToolOutput.content` 構造化 (protocol 拡張はスコープ外。必要になったら別チケット)
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
# TUI: ツール呼び出しをアクティブ領域内で更新型表示する
|
||||
|
||||
## 背景
|
||||
|
||||
現在の TUI はツール呼び出しを append-only のテキスト行として扱っており、1 回の呼び出しごとに `[tool] Read` / `[tool] Read done (128 bytes)` / `[tool result] ...` の**3〜4 行**が別々に積まれる。プロバイダがストリーミングで流してくる `ToolCallArgsDelta` は `crates/tui/src/app.rs:167` で丸ごと無視されており、**ユーザーはツールがどんな引数で呼ばれようとしているかを完了まで見られない**。
|
||||
|
||||
この制約は単なる実装漏れではなく、現行の**レンダリングモデルから来る構造的なもの**である。
|
||||
|
||||
### 現行レンダリングモデル
|
||||
|
||||
TUI は ratatui の **inline viewport + `insert_before`** で動いている:
|
||||
|
||||
- `crates/tui/src/ui.rs` の `draw()` で描く inline viewport は **separator / status / input の 3 行固定**
|
||||
- 履歴は `terminal.insert_before(height, ...)` で inline viewport の**上に押し出す**
|
||||
- 一度 `insert_before` で流した行はターミナルのスクロールバックに入り、**アプリから書き換え不能**になる
|
||||
|
||||
つまり現行アーキテクチャには「update 可能な領域」という概念が inline viewport の 3 行以外に存在しない。`ToolCallArgsDelta` を delta ごとに行として積むと履歴が爆発するので暫定的に捨てている、というのが現状の正確な理解。
|
||||
|
||||
### 追跡して書き換えるような API は存在しない
|
||||
|
||||
スクロールバックに入った内容は terminal emulator の private buffer に属し、ANSI / crossterm の層でも編集できない。ratatui 側にも「過去に insert した行を更新する」API は無い。書き換えできる唯一の場所は **毎フレーム再描画される inline viewport の内部**。
|
||||
|
||||
## 方針: アクティブ領域として inline viewport を拡張する
|
||||
|
||||
「書き換えできる場所でだけ書き換える」という一点で現行モデルと両立させる:
|
||||
|
||||
1. **inline viewport を可変高さにする**。現行の 3 行固定(separator / status / input)に加え、`active` 領域を上部に確保する。
|
||||
2. **進行中のツール呼び出しフレームを active 領域に保持**する。`ToolCallStart` でフレームを作り、`ToolCallArgsDelta` で毎フレーム再描画し、引数の流入をライブプレビューする。
|
||||
3. **完了 + 引き継ぎのタイミングで `insert_before` に格下げ**する。ツールが終わり、次のブロック(assistant text / 次の tool / turn end)が始まった時点で、そのフレームの最終状態を `insert_before` でスクロールバックに追い出し、履歴として immutable にする。
|
||||
4. **active 領域は常に最小限に保つ**。何も進行していないときは 0 行。ツールが複数並列で走っているときはそれぞれのフレーム分だけ膨らむ。
|
||||
|
||||
このモデルは現行のスクロールバック活用・コピペ親和性を保ったまま、進行中の部分だけを mutable にする最小侵襲のアプローチ。fullscreen TUI への移行(全履歴を state から毎フレーム描く大工事)は取らない。
|
||||
|
||||
## 要件
|
||||
|
||||
### レンダリングモデルの変更
|
||||
|
||||
- inline viewport を可変高さにし、active 領域 + 固定 3 行(separator / status / input)の構成にする。
|
||||
- active 領域が画面高さを侵食しすぎないように**上限**を設ける(上限超過時は active 内をスクロールまたは省略)。上限値の決め方は設計時に判断。
|
||||
|
||||
### フレームのライフサイクル
|
||||
|
||||
ツール呼び出し 1 回 = フレーム 1 個。tool_use_id で同一フレームに集約する。
|
||||
|
||||
- `ToolCallStart`: フレームを作り active 領域に追加。状態 = **Pending**(args 未確定)
|
||||
- `ToolCallArgsDelta`: フレーム内の argument preview に delta を連結し、次フレームで再描画。状態 = **Streaming**
|
||||
- `ToolCallDone`: args 受信完了。状態 = **Executing**(実行中)
|
||||
- `ToolResult`: 対応する `tool_use_id` のフレームに紐付ける。結果を取り込み、状態 = **Done** または **Error**
|
||||
- フレームが Done/Error になり、次のブロック(text / tool / turn end 等)が来た時点で `insert_before` に flush し active 領域から削除する
|
||||
|
||||
### 並列ツール呼び出し
|
||||
|
||||
- 複数の tool_use_id が同時に active 領域に存在できる。
|
||||
- イベントが interleave した順序で届いても tool_use_id で正しく振り分ける。
|
||||
- 並列実行の並び順は active 領域内で安定(開始順が望ましい)。
|
||||
|
||||
### 引数のライブプレビュー
|
||||
|
||||
- delta を**生の文字列として連結**し、そのまま表示する。途中の JSON を整形しようとしない(破綻する)。
|
||||
- プレビュー長に上限を設ける。1 フレームが active 領域を占有しないように折り畳みまたは省略。
|
||||
- 非常に長い引数(Write の `content` 等)は最小実装では省略でよい。展開キーは任意。
|
||||
|
||||
### 状態による視覚差異
|
||||
|
||||
- Pending / Streaming / Executing / Done / Error を色・枠線・アイコン等で区別する。
|
||||
- 完了フレームが `insert_before` で格下げされた後も、Done/Error のスタイルは履歴側に残る(insert_before に渡す時点で最終スタイルを焼き込む)。
|
||||
|
||||
### 結果の取り込み
|
||||
|
||||
- `ToolResult` はフレームに統合され、**別行として insert_before されない**。
|
||||
- 結果のサマリ(`ToolResult.summary`)はフレーム内にインライン表示。本体(`content`)は最小実装では省略または簡易表示。リッチレンダリングは別チケット。
|
||||
|
||||
### 履歴再生との共存
|
||||
|
||||
- セッション再開で `Event::History` を受けたときも、過去のツール呼び出しはフレーム化された最終状態で `insert_before` に流れる(active 領域には入らない)。
|
||||
- 現行の `App::restore_history`(`app.rs:240`)にも手が入る。tool_call + tool_result を 1 フレームに集約する経路が必要。
|
||||
|
||||
### イベントの欠落耐性
|
||||
|
||||
- プロバイダ起因でイベントが欠落したり順序が逆転しても panic しない。
|
||||
- `ToolResult` が来ないまま `TurnEnd` になった場合、active 領域のフレームは **Incomplete** 状態で flush する(握りつぶさず視覚化する)。
|
||||
|
||||
## 設計で決めること
|
||||
|
||||
- **active 領域の高さ上限**: 画面の N% か絶対行数か、超過時は active 内スクロールか自動折り畳みか
|
||||
- **フレームのデータモデル**: 既存 `OutputItem` に `ToolFrame` バリアントを足すか、active 領域専用の別コレクションとして持つか(後者の方が flush タイミングの制御が素直)
|
||||
- **flush のトリガー**: 「次のブロックが来たら flush」で十分か、時間経過やユーザー操作でも flush する必要があるか
|
||||
- **折り畳み / 展開**: 最小実装に含めるか、別チケットに切り出すか
|
||||
- **並列フレームの並び順**: 開始順 / 終了順 / 画面上の発生順
|
||||
- **Error と通知チャネルの使い分け**: ツール失敗はフレームの Error 状態で済ませるか、`tickets/tui-notification-channel.md` の通知にも流すか
|
||||
|
||||
## 完了条件
|
||||
|
||||
- `ToolCallArgsDelta` の内容が active 領域のフレーム内でライブに表示される。
|
||||
- 1 回のツール呼び出しが 1 フレームとして表示され、start → args streaming → done → result の遷移が同じ領域の更新として見える。
|
||||
- 完了フレームは次のブロック到着時に自動で `insert_before` に格下げされ、スクロールバックで immutable な履歴として残る。
|
||||
- 並列ツール呼び出しでフレームが混ざらない(tool_use_id で正しく振り分けられる)。
|
||||
- `ToolResult` が欠落したまま turn が終わった場合でもフレームが Incomplete として履歴に残り、panic しない。
|
||||
- セッション再開時に過去のツール呼び出しがフレーム形式で履歴に復元される。
|
||||
|
||||
## 範囲外
|
||||
|
||||
- **フルスクリーン TUI への移行**。inline viewport + insert_before の組合せを維持する。
|
||||
- **ツール結果そのもののリッチレンダリング**(Markdown 整形・シンタックスハイライト・diff 表示等)。本チケットはコンテナと状態遷移に集中する。
|
||||
- **ツール実行のキャンセル / 介入 UI**。ユーザーがフレームから操作を起こす仕組みは別チケット。
|
||||
- **プロバイダ側イベントスキーマの変更**。既存の `ToolCallStart` / `ToolCallArgsDelta` / `ToolCallDone` / `ToolResult` をそのまま使う。
|
||||
Loading…
Reference in New Issue
Block a user