4.9 KiB
4.9 KiB
TUI で role:system の system message を表示する
背景
Pod は user 入力の @<path> chip / /<slug> chip を submit 時に展開し、Item::system_message を pending_attachments 経由で worker.history に commit している:
@<path>ライブ submit:Pod::run→resolve_file_refs(crates/pod/src/pod.rs:825,852) →PodFsView::resolve_file_ref(crates/pod/src/fs_view.rs:119) で[File: <path>]\n<body>を生成- compact worker の auto-read:
mark_read_requiredで nominate された再読対象がPodFsView::render_auto_read(crates/pod/src/fs_view.rs:84) で[Auto-read file: <path>:<range>]\n<body>として乗る /<slug>ライブ submit:Pod::run→resolve_workflow_invocations(crates/pod/src/pod.rs:826,876) →crate::workflow::resolve_workflow_invocation(crates/pod/src/workflow/mod.rs:74) で[Workflow /<slug>]\n<body>と requires Knowledge 毎の[Workflow /<slug> requires Knowledge #<req>]\n<body>を生成
いずれも PodInterceptor::on_prompt_submit (crates/pod/src/ipc/interceptor.rs:114) で PromptAction::ContinueWith(extras) 経由で worker.history に commit され、history.json に永続化されている (CLAUDE.md「許される加工」原則に整合)。
問題
LLM のコンテキストには乗っているが TUI には何も出ない。TUI 側で role:system の Item が表示経路に乗っていないため:
- ライブ側: 解決済み system message を運ぶ broadcast event が
protocol::Eventに存在しない (crates/protocol/src/lib.rs:204–326)。UserMessageで@<path>//<slug>chip 自体は表示されるが、解決された本体は出ない。失敗時のみAlertで出るが、Alertはユーザー向け一過性通知で永続化されない (crates/protocol/src/lib.rs:328–348) ため表示経路として不適切。 - 履歴復元側:
App::restore_history(crates/tui/src/app.rs:650–702) の match がrole: "user"/"assistant"以外を_ => {}で握り潰す。history.json に system role で残っているのに resume 時に消える。
結果として「@<path> や /<slug> を submit したのに、本当に読まれたのか / 何が context に乗ったのか TUI からは判別できない」状態になっている。
要件
Item::system_message(role:system) を user / assistant メッセージと並列のログ要素として TUI に表示する一般的な仕組みを入れる。種別ごとの個別パッチではなく、role:system が来たら一律で表示経路に乗せる形にする。- 仕組みとして最小限カバーすべき system message:
[File: <path>](ライブ@<path>)[Auto-read file: <path>:<range>](compact 後の auto-read)[Workflow /<slug>][Workflow /<slug> requires Knowledge #<req>]
- 表示の単一の情報源は永続化された history (= history.json の role:system Item)。ライブ submit 時 / 履歴復元時 / 別 client subscribe 時 の三経路で同じ Block バリアントを通る。
- 表示は本文プレビュー(数行 + 残行数 / 切り詰め注記)程度で良い。
[Auto-read file: ...:<range>]の range ラベルは可視化する。workflow 本体と requires Knowledge は同じ workflow 起動に紐づく一連と分かる粒度で識別できる。 - 解決失敗時の従来経路は維持:
@<path>はAlert、workflow は user-invocation エラーとして即座に Pod から返る (Pod::validate_workflow_invocations)。
範囲外 / 非目標
<system-reminder>注入機構そのものの汎用化や、notify_wrapper 適用後の本文表示。これらは別所(session-todo-reminder等)。本チケットは表示側の仕組みのみで、将来<system-reminder>系が role:system Item として history に乗るようになれば、同じ表示経路にそのまま流れる前提。- 表示形式の凝った装飾(シンタックスハイライト / 折り畳み UI)。最初は素のテキストプレビューで十分。
model_invokation: trueのみの workflow(user_invocable=false)の表示は対象外。
完了条件
@<path>を submit すると、user message ブロックに続けて自動読み取り結果が TUI に出る。本文プレビューが視認できる。/<slug>を submit すると、workflow 起動結果のログ要素が TUI に出る。requiresがある場合は Knowledge 注入もそれと分かる形で出る。- compact 後の resume で
[Auto-read file: ...]が同じログ要素として復元・表示される。 - 別 client が後から subscribe して
Event::Historyを受けた場合も、同じログ要素として描画される。 - ライブ event と history 復元の表示が一致する(同じ Block バリアントを通る)。
- 解決失敗時の従来経路(
Alert/ user-invocation エラー)は維持される。