Skip to content

TUI:subagent 会话不可输入,人无法直接给子 Agent 发消息 #37

Closed

Description

@lihaokun

agent-management(#23 / #35)之后,subagent 会话在 TUI 里仍然是只读的:看得见转录,打不了字。人想给子 Agent 发消息,只能回到父会话让模型去调 agent_send。

现状

packages/tui/src/routes/session/index.tsx:227:

const visible = createMemo(() => !session()?.parentID && permissions().length === 0 && questions().length === 0)

Prompt 只在 visible() 为真时渲染,而它要求 !session()?.parentID —— 任何子会话一律不给输入框,取而代之显示 SubagentFooter(标签、兄弟序号、token 用量、开销、跳转快捷键,纯信息栏)。

这一行在 dev 上是同一份(那边第 236 行),不是 #35 引入的。

为什么现在才值得改

旧模型下这个决定是对的:task 的 subagent 是一次性工人,会话只是存放转录的地方,没人在听,父亲那边的 task 工具在等一个特定返回值。

#35 之后前提没了:

  • agent_send 是一等的单向消息通道
  • 停掉的 Agent 靠 agent_send 唤回,所以 subagent 是持久且可寻址的
  • 「给某个 subagent 发一条消息」已经是模型日常在做的操作

也就是说,服务端管道早就通了 —— 缺的只是人这一侧的入口。

天真的改法是有害的

不能只放开 visible()。TUI 的 Prompt 提交时带的身份来自全局 UI 选择而非目标会话:

  • packages/tui/src/component/prompt/index.tsx:961,968 —— local.agent.current() / local.model.current()
  • 同文件 1095-1100 —— 这两个值直接进 session.prompt({ sessionID, agent, model, variant, ... })
  • packages/tui/src/context/local.tsx:78 —— 可选集合是 filter(a => a.mode !== "subagent" && !a.hidden),明确排除 subagent,且 agentStore 是全局单例,不按会话隔离

于是往一个 explore subagent 里打一行字,发出去的 agent 是你当前选中的主 Agent(build/plan…),createUserMessage 再用 setAgentModel 把它持久化写回子会话 —— subagent 当场被改写成另一个 Agent、另一个模型。

这与 #35 修掉的 P0 同类:agent_send 当初就是因为只传 parts 不传身份才出的事。

一个正确的版本需要什么

  1. 身份取自目标会话。 AgentInbox.deliver(packages/opencode/src/agent-management/inbox.ts)已经把规则写对了:读 target.agent / target.model,并把存着的 "default" variant 折回 undefined(否则一个来回就把「没选 variant」变成「选了 default」)。应当复用 deliverAsync 那条路,让规则只有一处 owner,而不是在 TUI 里再抄一遍。
  2. agent/model 选择器要处理。 子会话视图里那两个选择器要么隐藏,要么改成「更改这个 subagent 的模型」—— 那是另一个动作,需单独设计。
  3. 署名怎么写(主要的设计决定)。 agent_send 会加 [Agent message from <name> (<type>, <id>)] 和一行回复指引。人发的消息要不要标来源?不标,subagent 分不出「父亲让我做」和「人让我做」;要标,就得定一个「来自用户」的框,并且走同一套 AgentInbox.escapeField。
  4. 布局。 SubagentFooter 和 Prompt 目前是并列的两个 <Show>,同时显示需要安排。

已经安全、不必额外处理的

待定

  • 只做 TUI,还是 session-ui(网页/桌面)一起?后者的会话视图是另一套,且它的 subagent 卡片另有问题(running 直接读工具 part 状态,不看子会话)。

相关:#23、#35、#32、#34。与 #38同属 TUI 的 subagent 操作面。

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions