Skip to content

Session interprets inbox text as slash commands, so a pipeline agent step's prompt executes operator commands — slash belongs to the client #3595

Description

@tya5

[lead-coder] — ★ owner 裁定により設計が確定した件。 実装が設計に反しています。

owner の設計(2026-08-01、裁定)

「スラッシュコマンドの解釈は tui 側の想定だよ。inbox につまれたものはスラッシュコマンドとして解釈されない。されるんだとするとそれが不具合」

🔴 実装は逆になっています

src/reyn/runtime/session.py:5613  async def _handle_user_message(self, text: str, *, chain_id: str)
src/reyn/runtime/session.py:5617      if text.startswith("/"):
src/reyn/runtime/session.py:5618          if await self._maybe_handle_slash(text):

_handle_user_messageinbox から来たものを処理する経路です。呼び出し元は2つ:

呼び出し元 何を渡すか
_run_turn_body(kind == "user") キューに積まれた user メッセージ
_handle_pipeline_result パイプラインの終了結果

帰結(挙動テストで実測済み、tests/test_3561_spawn_session_seam_reachability.py:181

agent ステップのモデル出力が、operator コマンドとして実行されます。

  1. agent ステップが /session new ... というテキストを返す
  2. 本番のテンプレート差し込み executor._interpolate_prompt が、それを次の agent ステップの promptそのまま入れる
  3. その prompt が _handle_user_message に届く
  4. text.startswith("/") で slash として実行され、セッションが生まれる

★ 同テストは「セッションが生まれた」ことに加え scripted.calls == 1(= 到達ターンで LLM 呼び出しが増えていない)も assert しています。∴ 2つ目のワーカーはモデルに相談しておらず、短絡してコマンドが実行されたことの witness です。

★ 判定に「形」を使っています

text.startswith("/") は、文字列の形を嗅いで 「これは operator の命令か、モデルに読ませる中身か」を決めています。

★ reyn の恒久方針は {kind, ...} の typed discriminated union を使い、形で嗅ぎ分けないことです。★ agent ステップの promptモデルに読ませる中身 で、operator のコマンドではありません。両者が同じ扉を通り、扉の内側で形判定されているのが欠陥の本体です。

【MEASURED】スラッシュのディスパッチは現在どこにあるか

ディスパッチしているか
runtime/session.py:5617 ここだけ
runtime/session.py:3097 /answer のみの狭い先回り経路(Composer からの、キュー前の入力。性質が違う)
interfaces/repl/stream_client.py:175,184 / か見て介入ルーティング/reply-seen を決めるだけ
interfaces/inline/textual_chat/completion.py:463 ❌ 補完メニューの表示だけ

★★ ∴ スラッシュのディスパッチは session 層のこの1箇所にしか存在しません。 修正は「TUI へ 移す」ではなく「TUI 側に 作り、session 層から 消す」です。

🟡 未決 — スコープ(owner 確認中)

  • (A) スラッシュは TUI だけが持つ。--cui など他クライアントからは使えなくなる
  • (B) スラッシュを提供するクライアントがそれぞれ自前でディスパッチする(TUI + --cui 双方に実装)

★ owner の文言は「tui 側の想定」なので (A) と読めますが、--cui から /model 等が使えなくなるのは可視の挙動変更なので確認中です。決まるまで着手しないでください。

/answer(介入への回答)の先回り経路(:3097)を一緒に動かすかも、(A)/(B) が決まってから詰めます。

★ 依存関係 — 先に読んでください

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions