Skip to content

tui: question tool steals focus from open rename dialog #52767

Closed

Description

@reisi007

Description

The session rename dialog (opened via right-click → Rename) stays visible but stops accepting input when the agent calls the question tool. Keyboard focus sits on the ask prompt behind it. After I answer the questions, focus is not returned to the rename dialog — the only way to dismiss it is Esc, which discards the rename.

Looks like the same focus-stealing bug as #14799 (input.focus() on the main prompt pulling focus off the rename dialog), except the trigger here is an arriving question rather than subagent spawns. Worth checking whether the questions() dependency in that effect is actually fixed on 2.0.20.

Plugins

None. ~/.config/opencode/plugins/opencode-stats is a dangling symlink, so nothing loads.

OpenCode version

2.0.20 (latest release)

Steps to reproduce

  1. Start a session and let the agent work.
  2. Right-click the session in the session list → Rename.
  3. Leave the rename dialog open.
  4. Agent calls question with options.
  5. Type in the rename field — keys go to the ask prompt instead.

Screenshot and/or share link

None, terminal-only observation.

Operating System

macOS 27.0.0 (Darwin 27.0.0, arm64)

Terminal

Apple Terminal (TERM=xterm-256color, COLORTERM=truecolor)

Activity

  1. added
    needs:complianceThis means the issue will auto-close after 2 hours.
    and removed
    needs:complianceThis means the issue will auto-close after 2 hours.
    on Oct 2, 2026
  2. github-actions commented on Oct 2, 2026

    @github-actions
    Contributor

    Thanks for updating the issue with the required details!

  3. yassine-safraoui commented on Oct 21, 2026

    @yassine-safraoui

    It steals focus from everything lol, I had command palette open and a question appeared in the active thread, so I hit escape to close the command palette and answer question, aaand the question was canceled, gone, heck i can't even see the question that was asked

  4. opencodejr commented on Oct 28, 2026

    @opencodejr

    Thanks for the report. I could reproduce this on 2.0.20, and it still happens on the latest dev (891a020).

    What I ran: the agent works for a few seconds and then calls question with options. While it works, I right-click the session tab → Rename and leave the dialog open.

    What happens:

    • Ordinary letters typed after the question appears still go into the rename field.
    • The question form's shortcut keys are still active behind the dialog. Pressing 2 picked and submitted "Option B" for the question, and the 2 never reached the rename field. The form's other shortcut keys (h/l/j/k, arrows, Enter, Esc) are probably affected the same way.

    In my runs, Enter still applied the rename after the question had been answered, and I couldn't get the dialog stuck as you describe. If plain letters (not just digits or shortcut keys) go to the question for you, please say which keys you typed.

    The recording and screenshots below show it, and the script below reproduces it. The cause seems close to #14799 (the background prompt keeps acting while a dialog is open), but this time it's the question form.

    recording.mp4

    Screenshot

    Screenshot

    Reproduction script (drive.ts)
    // Repro for #52767: the question form steals keyboard focus from an open "Rename session" dialog.
    import { Effect, Stream } from "effect"
    import { Llm, OpenCodeDriver } from "opencode-drive"
    
    export default OpenCodeDriver.use(
      {
        ...(process.env.OC_DEV ? { opencode: { dev: process.env.OC_DEV } } : {}),
        tui: { recording: true, keypressOverlay: true },
      },
      ({ ui, llm }) =>
        Effect.gen(function* () {
          // The agent "works" for a few seconds, then calls the question tool.
          // Title-generation requests (detected by their prompt) get a fixed title.
          let main = 0
          yield* llm.serve((request) => {
            if (JSON.stringify(request.body).includes("Reply with a title")) return Stream.make(Llm.text("OpenCode Drive"))
            main++
            if (main === 1)
              return Stream.make(
                Llm.text("Working on it..."),
                Llm.pause(8000),
                Llm.toolCall({
                  index: 0,
                  id: "call_question",
                  name: "question",
                  input: {
                    questions: [
                      {
                        question: "Which approach should I take?",
                        header: "Approach",
                        options: [
                          { label: "Option A", description: "First approach" },
                          { label: "Option B", description: "Second approach" },
                        ],
                      },
                    ],
                  },
                }),
                Llm.finish("tool-calls"),
              )
            return Stream.make(Llm.text("Thanks, done."))
          })
          yield* ui.submit("Do some work and then ask me a question")
          yield* ui.waitFor("Do some work and then ask", { timeout: 30000 })
          yield* Effect.sleep(1500)
    
          // Open the rename dialog while the agent is still working.
          // Right-click the session tab -> Rename (as in the report).
          yield* ui.mouse({ action: "down", x: 12, y: 0, button: "right" })
          yield* ui.mouse({ action: "up", x: 12, y: 0, button: "right" })
          yield* Effect.sleep(500)
          yield* ui.screenshot("0-context-menu")
          yield* ui.waitFor("Rename")
          yield* ui.mouse({ action: "move", x: 15, y: 2 })
          yield* ui.mouse({ action: "down", x: 15, y: 2, button: "left" })
          yield* ui.mouse({ action: "up", x: 15, y: 2, button: "left" })
          yield* ui.waitFor("Rename session")
          yield* ui.type("abc")
          yield* Effect.sleep(500)
          yield* ui.screenshot("1-rename-open-typing-works")
    
          // The question arrives while the rename dialog is still open.
          yield* Effect.sleep(9000) // the question arrives ~8s after the response starts
          yield* Effect.sleep(800)
          yield* ui.screenshot("2-question-arrived")
    
          // Type into what should be the rename field.
          for (const ch of ["x", "y", "z"]) yield* ui.press(ch)
          yield* Effect.sleep(800)
          yield* ui.screenshot("3-typed-after-question")
          // Digits and arrows are question-form shortcuts; they should still go to the dialog.
          yield* ui.press("2")
          yield* ui.arrow("down")
          yield* Effect.sleep(500)
          yield* ui.screenshot("4-digit-and-arrow")
          // Confirm the rename: the dialog should close and the tab title change.
          yield* ui.enter()
          yield* Effect.sleep(1500)
          yield* ui.screenshot("5-after-enter")
          // Now answer the question; it should still be pending.
          yield* ui.enter()
          yield* Effect.sleep(1500)
          yield* ui.screenshot("6-answered")
        }),
    )

    Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions