Skip to content

feat(tui): steer running subagents from their view - #14702

Merged
intentionally-left-nil merged 14 commits into
Kilo-Org:mainfrom
calebnorman:allow-subagent-steering-in-tui
Oct 2, 2026
Merged

intentionally-left-nil merged 14 commits into
Kilo-Org:mainfrom
calebnorman:allow-subagent-steering-in-tui

Conversation

@calebnorman

@calebnorman calebnorman commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Depends on #14701 (double Esc interrupts a subagent from its view). Both branches are on the same main, and this branch contains #14701, so until #14701 lands this PR's diff also shows its changes. This PR's own changes: calebnorman/kilocode@implement-esc-interrupt-and-fix-ctrl-c-exit...allow-subagent-steering-in-tui

What

When viewing a running subagent in the TUI, the prompt is now available so the user can steer that subagent directly. The steer goes through the normal session prompt queue, and the parent agent is notified with an INFO message on the shared agent board, sent from the subagent to its parent with the steering text.

In a subagent view the prompt makes it clear you are steering the subagent, not talking to the parent: it takes the subagent's color (matching the subagent footer), replaces the primary agent/model row with Steering <agent> · <model>, and uses a Steer the <agent> subagent... placeholder.

Why

Subagent views were read-only, so the only way to redirect a subagent was through the parent agent. Steering the child directly is faster, but the parent must learn about it; otherwise it keeps reasoning from a plan its child no longer follows.

Design notes and constraints

  • Steering is marked explicitly, not inferred. The task tool's own prompts to a child session are also non-synthetic text on a session with a parentID, so "human text on a child session" would post a false notice on every subagent launch and task_id resume. The TUI marks the typed text part with metadata.kind = "subagent_steer", and only marked parts produce a notice. Other clients (VS Code, SDK callers) don't notify until they opt in with the same mark.
  • Plain steering prompts only. Shell mode and slash commands (including the client-side /cost and /memory) are off in subagent views: ! and / are typed as text, the / command list doesn't open, and slash text is sent as a plain steer. This keeps the PR to one tested input path.
  • The child keeps its own agent and model. A steer sends the child's agent, model, and variant. Sending the primary selection would run the child as the primary agent (dropping agent-level restrictions such as explore's), and the server persists that choice onto the child session.
  • Only running subagents accept input. A steer on a finished child would start a new turn whose result never reaches the parent. While the child runs, the steer is queued behind the current turn, so its result flows back through the task tool.
  • The notice fires only for turns that will run. It is posted after the paused and noReply early returns in prompt admission. Its body is excerpted against the board's 4 KiB limit after JSON escaping, and failures are logged without failing the prompt.
  • Keys in subagent views follow feat(cli): interrupt a subagent from its view with double Esc #14701, with the prompt mounted.

Known limitations

  • The board doesn't wake the parent. It sees the notice with its next tool result.
  • A queued steer removed from the queue before it runs still leaves its notice.
  • The prompt keeps an unsent draft when it unmounts (upstream behavior), so a steer half-typed when the subagent finishes reappears in the next prompt shown, such as the parent's.

Before:

before

After:

after

@calebnorman
calebnorman marked this pull request as ready for review September 30, 2026 21:41
@kilo-code-bot

kilo-code-bot Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (14 files)
  • .changeset/tui-subagent-esc-interrupt.md
  • .changeset/tui-subagent-steering.md
  • packages/opencode/test/session/prompt.test.ts
  • packages/tui/src/component/prompt/autocomplete.tsx
  • packages/tui/src/component/prompt/index.tsx
  • packages/tui/src/config/keybind.ts
  • packages/tui/src/kilocode/double-press.ts
  • packages/tui/src/kilocode/steer-label.tsx
  • packages/tui/src/kilocode/steer.ts
  • packages/tui/src/routes/session/index.tsx
  • packages/tui/src/routes/session/subagent-footer.tsx
  • packages/tui/test/kilocode/double-press.test.ts
  • packages/tui/test/kilocode/steer.test.ts
  • packages/tui/test/kilocode/subagent-view.test.tsx
Previous Review Summaries (2 snapshots, latest commit 71c42fb)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 71c42fb)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/tui/src/routes/session/index.tsx 1253 The new higher-priority navigation layer is enabled for every session, not just subagent views, so it may swallow arrow keys on an empty prompt in primary sessions and break prompt-history recall / horizontal cursor movement.
Files Reviewed (10 files)
  • .changeset/tui-subagent-steering.md - no issues
  • packages/opencode/src/kilocode/cli/cmd/tui/component/memory-prompt.tsx - no issues
  • packages/opencode/src/kilocode/session/steering.ts - no issues
  • packages/opencode/src/session/prompt.ts - no issues
  • packages/opencode/test/kilocode/session-steering.test.ts - no issues
  • packages/tui/src/component/prompt/autocomplete.tsx - no issues
  • packages/tui/src/component/prompt/index.tsx - no issues (incremental changes)
  • packages/tui/src/kilocode/steer.ts - no issues (incremental changes)
  • packages/tui/src/routes/session/index.tsx - 1 issue (carried, active inline comment)
  • packages/tui/test/kilocode/steer.test.ts - no issues (incremental changes)

Fix these issues in Kilo Cloud

Previous review (commit 46eff1d)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/tui/src/routes/session/index.tsx 1253 The new higher-priority navigation layer is enabled for every session, not just subagent views, so it may swallow arrow keys on an empty prompt in primary sessions and break prompt-history recall / horizontal cursor movement.
Files Reviewed (8 files)
  • .changeset/tui-subagent-steering.md - no issues
  • packages/opencode/src/kilocode/session/steering.ts - no issues
  • packages/opencode/src/session/prompt.ts - no issues
  • packages/opencode/test/kilocode/session-steering.test.ts - no issues
  • packages/tui/src/component/prompt/index.tsx - no issues
  • packages/tui/src/kilocode/steer.ts - no issues
  • packages/tui/src/routes/session/index.tsx - 1 issue
  • packages/tui/test/kilocode/steer.test.ts - no issues

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

@marius-kilocode

Copy link
Copy Markdown
Collaborator

This looks good

  • board messages are submitted as INFO to notify the parent
  • steering seems to work

Suggested improvements:

  • UX wise it feels like I am missing the info that I am steering the subagent, currently it looks like i have full control
  • There is a range of things that still work while steering but don't make sense in practise or don't work in-flight (e.g. /variant). It would even make sense to disable slash commands (and anything else that should not work) during subagent steering completely to avoid the complexity that arises with all of those edge cases completely)

@marius-kilocode

Copy link
Copy Markdown
Collaborator

Btw, a little gif or screenshots help us usually to reduce review effort for such changes.

@marius-kilocode marius-kilocode left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should fix shell and slash command issues before merge

Caleb Norman and others added 6 commits October 1, 2026 13:09
The subagent-view prompt takes the subagent's color, replaces the
primary agent/model row with "Steering <agent> · <model>", and uses a
"Steer the <agent> subagent..." placeholder, so it no longer looks like
the parent's prompt.

Also reconcile the steering prompt with Kilo-Org#14701's subagent-view keys:
Esc belongs to the footer's subagent interrupt, an open autocomplete
list outranks it, and a typed steer keeps ctrl+c (clear) and ctrl+d
(delete) instead of arming the double-press exit.
const subagent = useSubagent(() => props.sessionID)
const steer = createMemo(() => !!subagent())
createEffect(() => {
if (steer() && store.mode === "shell") setStore("mode", "normal")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting state like this from an effect is a code smell. What is this trying to solve for, and why is this done on every render, as an effect?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. It existed for one case: prompt history is shared across sessions, so recalling a !cmd entry with ↑ in a subagent view would put the prompt into shell mode, which subagent views don't support. (In Solid it only reran when steer() or store.mode changed, not on every render, but reacting to state with an effect is the wrong shape.) I'll replace this with with a guard instead at the two history-recall setters, so a recalled shell entry comes back as plain text. The ! key is already off in subagent views, and submit never runs shell from one.

Caleb Norman added 2 commits October 1, 2026 16:49
…rl-c-exit' into allow-subagent-steering-in-tui
The subagent-view prompt reset shell mode from a createEffect. The only
way into shell mode there is recalling a shared history entry (the `!`
key is already off, and each session mounts a fresh prompt), so guard
the two history-recall setters directly and drop the effect.
calebnorman and others added 2 commits October 2, 2026 10:52
…rl-c-exit' into allow-subagent-steering-in-tui

# Conflicts:
#	packages/tui/test/kilocode/subagent-view.test.tsx
@marius-kilocode

Copy link
Copy Markdown
Collaborator

P2: Variant/agent controls still work outside slash input. The prompt still advertises ctrl+t variants at prompt/index.tsx:1875. The global shortcuts and command-palette actions remain enabled in app.tsx:698–747. However, submitting steering overrides those selections with the child’s saved agent/model/variant. This leaves exactly the confusing interaction you wanted to avoid: a control changes a local preference but does not change the steered child. Disable the irrelevant actions while steering and hide their hints.

-> can you check if ctrl t is really disabled?

P2: Removing queued steering leaves a misleading parent notification. The backend posts the INFO notice before the queued steering actually runs, at session/prompt.ts:1491–1493. If the queued message is deleted, the parent can still read that the child was redirected, although the child never processes it. The author explicitly documents this limitation. Posting when the queued work starts would avoid that mismatch.

Is that true? And is this fixed in one of the other PR's?

Caleb Norman and others added 2 commits October 2, 2026 13:56
…g-in-tui

Move this PR's subagent-view key changes into useSubagentKeys() with the
rest of the subagent keys: the arrow navigation layer and the exit
double-press both yield while a steer is typed.
@intentionally-left-nil
intentionally-left-nil merged commit 76bcfd4 into Kilo-Org:main Oct 2, 2026
33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants