Skip to content

feat(opencode): add STEER support for busy TUI sessions - #14815

Closed
dhiyaancnirmal wants to merge 1 commit into
anomalyco:devfrom
dhiyaancnirmal:codex/steer-busy-sessions
Closed

dhiyaancnirmal wants to merge 1 commit into
anomalyco:devfrom
dhiyaancnirmal:codex/steer-busy-sessions

Conversation

@dhiyaancnirmal

Copy link
Copy Markdown

Issue for this PR

Closes #9454

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Adds STEER support for busy sessions in opencode (TUI + API path).

Included in this PR:

  • session.steer server route / SDK generation support used by the TUI
  • busy-session steer submission in the TUI with a configurable shortcut (input_steer_submit)
  • immediate steer message visibility in the transcript while the agent is still running
  • transcript export support for steer messages
  • prompt-dispatch fixes touched during STEER integration (Home->session transition timing and queued prompt input clearing)
  • opt-in local tmux TUI E2E harness + basic coverage

How did you verify your code works?

  • manual TUI verification of the busy-session STEER flow and related prompt-dispatch behavior touched by this change
  • cd packages/opencode && ~/.bun/bin/bun test --timeout 120000 test/cli/tui/prompt-submit-routing.test.ts test/cli/tui/transcript.test.ts test/session/prompt.test.ts test/config/config.test.ts test/cli/tui/tmux.e2e.test.ts
  • cd packages/opencode && OPENCODE_TUI_E2E=1 ~/.bun/bin/bun test --timeout 60000 test/cli/tui/tmux.e2e.test.ts
  • PATH="$HOME/.bun/bin:$PATH" ~/.bun/bin/bun turbo typecheck

Screenshots / recordings

Not included (TUI keyboard/timing behavior change).

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

If you do not follow this template your PR will be automatically rejected.

Copilot AI left a comment

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.

Pull request overview

This pull request adds STEER (Steering) support for busy TUI sessions in opencode, allowing users to provide guidance to the AI agent during execution without aborting the in-flight processing. This is an experimental feature similar to what's available in Codex, addressing issue #9454 which requested better compatibility with Codex features.

Changes:

  • Added /session/{sessionID}/steer API endpoint and SDK generation for queuing user guidance messages
  • Implemented TUI keyboard shortcuts (input_steer_submit with default alt+return,super+return,ctrl+return) for submitting steer messages while the session is busy
  • Added immediate persistence and visibility of steer messages in the transcript and TUI with a "STEER" badge
  • Implemented opt-in tmux-based E2E test harness for TUI testing

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/sdk/js/src/v2/gen/types.gen.ts Generated TypeScript types for the new session.steer API endpoint including request/response types
packages/sdk/js/src/v2/gen/sdk.gen.ts Generated SDK client method for the steer operation with parameter building and error handling
packages/opencode/test/session/prompt.test.ts Comprehensive test coverage for steer functionality including idle fallback, busy queue draining, persistence, and edge cases
packages/opencode/test/config/config.test.ts Test verifying default input_steer_submit keybinding configuration
packages/opencode/test/cli/tui/transcript.test.ts Tests for transcript formatting of steer messages with markdown preservation
packages/opencode/test/cli/tui/tmux.e2e.test.ts End-to-end tests using tmux harness for TUI rendering and session routing
packages/opencode/test/cli/tui/tmux-harness.ts New tmux-based E2E test harness for automated TUI testing
packages/opencode/test/cli/tui/prompt-submit-routing.test.ts Tests for prompt submit routing logic including steer key detection and request success validation
packages/opencode/src/session/prompt.ts Core steer implementation: queue management, persistence via writeSteer, and integration with session loop for draining steer messages
packages/opencode/src/server/routes/session.ts Server route definition for POST /session/{sessionID}/steer with validation and 202 response
packages/opencode/src/config/config.ts Added input_steer_submit keybinding configuration with default shortcuts
packages/opencode/src/cli/cmd/tui/util/transcript.ts Transcript formatting support for steer messages with "Steer:" prefix
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx UI changes to display steer messages with "STEER" badge and treat them as visible text in user messages
packages/opencode/src/cli/cmd/tui/component/prompt/submit-routing.ts New routing logic to handle steer vs normal prompt submission based on session state and intent
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx Integrated steer submission: keyboard handling, API calls, fallback to normal prompt when idle, and UI hints

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

expect(parts.length).toBe(3)
const timestamps = parts.map((part) => part.metadata?.steer_timestamp)
expect(timestamps.every((x) => typeof x === "number")).toBe(true)
expect(parts.map((part) => part.text).toSorted()).toEqual(["first", "second", "third"])

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

The test name suggests that steer messages should be "drained in timestamp order", but the test only verifies that all three messages exist using .toSorted() which sorts the array for comparison. The test doesn't actually verify that the messages are stored or retrieved in timestamp order. Consider either:

  1. Renaming the test to reflect that it only checks for existence of all messages
  2. Adding assertions that verify the actual order matches the timestamp order (e.g., checking that the steer_timestamp values in the parts array are in ascending order)
Suggested change
expect(parts.map((part) => part.text).toSorted()).toEqual(["first", "second", "third"])
// verify that steer messages are drained in timestamp order
const texts = parts.map((part) => part.text)
expect(texts).toEqual(["first", "second", "third"])
const sortedTimestamps = [...(timestamps as number[])].toSorted((a, b) => a - b)
expect(timestamps).toEqual(sortedTimestamps)

Copilot uses AI. Check for mistakes.
Comment on lines +315 to +322
async function drainSteerQueue(input: {
sessionID: string
user: MessageV2.User
}) {
const match = state()[input.sessionID]
if (!match || match.steerQueue.length === 0) return false
return match.steerQueue.splice(0).length > 0
}

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

The drainSteerQueue function empties the steer queue using splice(0) but doesn't utilize the queued items. While the steer messages are already persisted to the database via writeSteer, the queue contains timestamp information that could be useful for ordering. Currently, there's no guarantee that steer messages will be processed in timestamp order if multiple steer calls happen rapidly. Consider sorting the queue by timestamp before draining, or document why timestamp ordering is not necessary.

Copilot uses AI. Check for mistakes.
parameters: {
sessionID: string
directory?: string
text?: string

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

The text parameter is marked as optional in the TypeScript signature (text?: string) but the server-side validation requires it to be a non-empty string (z.string().trim().min(1)). This inconsistency could lead to runtime validation errors when calling the API without providing the text parameter. The SDK should mark this parameter as required to match the server validation: change text?: string to text: string.

Suggested change
text?: string
text: string

Copilot uses AI. Check for mistakes.
@dhiyaancnirmal dhiyaancnirmal closed this by deleting the head repository Feb 27, 2026
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.

[FEATURE]: Codex CLi feature/harness compatibility when using codex models

2 participants