Skip to content

bug(opencode): prompts sent to a just-started OpenCode Terminal pane are silently lost #877

Closed

Description

@Juliusolsson05

Status (quality-loop audit, 2026-09-25)

Landed: #882 moved production delivery to prompt_async (opencodeTerminalSession.ts:364-399), distinguishing not-ready from unknown outcomes.

Remaining: The package live test still pastes via pasteAndSubmit after a 10 s grace, so it never exercises the production path, and there has been no real-TUI confirmation.

Acceptance: The live test calls submitPrompt immediately after start() and the prompt commits as a user record, on OpenCode 1.18.3x.

Original report

What happens

A prompt delivered to an OpenCode Terminal pane that has just started, or was just woken, is pasted before the TUI's composer accepts input:

  1. The TUI discards the paste.
  2. Delivery still returns { ok: true, acceptance: { kind: 'transport' } }.
  3. The pane sits idle with an empty composer, while the caller believes the prompt was sent.

Paths that hit this:

  • AI Workspace agents.create { provider: 'opencode', providerRuntime: 'terminal' } followed by agents.prompt (src/renderer/src/workspace/control/agents.ts:195-233).
  • Agent Management send-prompt / agents.prompt to a parked OpenCode Terminal pane (src/renderer/src/workspace/hook/index.ts:725-748).
  • Remote-client prompts right after a wake.

Orchestration create_agent is not affected: it always spawns the structured runtime.

This compounds with #875: agents.create (terminal) → agents.prompt → observations.wait(settled) reports "accepted", then only timeouts, while the prompt is gone.

Why

  • Readiness is a guess. src/providers/opencode/runtime/opencodeTerminalSession.ts marks input ready at the first PTY byte + TUI_READY_GRACE_MS = 250.
  • Delivery is fire-and-forget. deliverPromptText waits only for that gate, then writes one bracketed paste + \r.
  • Acceptance is transport-only. src/providers/opencode/runtime/promptDelivery.ts reports acceptance as soon as the write returns. Nothing checks that the TUI took the prompt (session.status busy, or a committed user message).
  • No renderer wait either. src/renderer/src/workspace/hook/actions/session.ts skips the readiness wait for terminal runtimes, so wake-then-send goes straight to this gate.
  • The live test hides it. packages/opencode-terminal-headless/src/OpencodeTerminalHeadless.live.test.ts pastes only after the live channel connects, first paint, and a fixed 10 s wait. That is not the production rule.

Evidence

  • Live runs, 2026-09-11 (OpenCode 1.18.30). The package's live test failed with OPENCODE_TERMINAL_HEADLESS_LIVE_GRACE_MS=250 and again with =3000. The only package event in 120 s was live:true, and the TUI tail showed an empty composer. Both runs pasted after the live channel connected, which is later than production pastes.
  • Stage 0 recordings (packages/opencode-terminal-headless/testing/fixtures/live/*.json):
    • The first PTY output came 4.2–6.2 s after spawn.
    • Instance-scoped HTTP requests only answered at 6.4–15.7 s.
    • Every successful paste came at least 5.3 s after the first output.
  • Not a new regression. The 250 ms grace is the same on origin/main.

Suggested fix

  • Better readiness. Replace "first byte + 250 ms" with a signal proven against recordings, e.g. the live channel's first answered instance-scoped request, plus whatever margin a live sweep shows is needed.
  • Observable acceptance. After pasting, wait for busy or a committed user record from opencode-terminal-headless. If neither arrives within N s, return a retry-safe not-accepted failure. The dropped paste leaves the composer empty, so one retry should not duplicate — verify that live first.
  • Or skip pasting. Deliver through the TUI's own server (POST /session/:id/prompt_async), which acknowledges on the server side.
  • Test the real path. Point the live test at the production readiness and delivery path.

Acceptance

  • The live test passes without the grace override.
  • A delivery that never shows busy or a user commit is reported as a failure.
  • A unit test proves readiness does not resolve on the first PTY byte alone.

Refs #864

Metadata

Metadata

Assignees

No one assigned

    Labels

    class:C1-prompt-deliveryPrompt delivery inferred from the terminal screenprovider:opencodeAffects OpenCode integrationsev:P1Core flow broken or badly degradedtype:bugSomething works wrong

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions