Skip to content

fix(web): pending user-input Submit bypasses normal-send guards - #9319

Open
ImBIOS wants to merge 3 commits into
pingdotgg:mainfrom
ImBIOS:fix/web-pending-submit-swallowed-by-send-guards
Open

fix(web): pending user-input Submit bypasses normal-send guards#9319
ImBIOS wants to merge 3 commits into
pingdotgg:mainfrom
ImBIOS:fix/web-pending-submit-swallowed-by-send-guards

Conversation

@ImBIOS

@ImBIOS ImBIOS commented Sep 3, 2026

Copy link
Copy Markdown

Enabled Submit on the Input badge did nothing: the button enables on isComplete/canAdvance (ComposerPrimaryActions.tsx:147), but submitComposer (ChatComposer.tsx:1890) blocked on noProviderAvailable || isSendDisabled and ChatView.onSend (ChatView.tsx:5037) blocked on isSendBusy || isConnecting || threadDetailLoading || sendInFlight before reaching the pending branch. All silent, no toast.

Pending answers are a lightweight thread.user-input.respond — no provider, send context, or images needed — so route them first in both places. Only missing thread and environment-unavailable still block.

Fixes #9318. Distinct from #5454 (server No-session stuck, still open with #7987/#7463 open).

Verified by code-path inspection (no node_modules in sandbox, so no vp test run; existing composerSubmission.test.ts: pending-user-input dispatches on separate path covers the draft layer, this aligns the composer/view guards with it).

Built with Muse Spark via OpenCode.


Note

Medium Risk
Changes OpenCode inventory parsing and model/agent option handling across server and shared code, plus composer send routing; localized web guard reorder but touches a critical submit path.

Overview
Adds shared stripTerminalEscapes / sanitizeTerminalValue and applies them wherever OpenCode CLI stdout or model option strings are parsed or sent, so OSC title sequences and ANSI color codes no longer corrupt agent names, model slugs, skills JSON, or --version probes (avoiding Agent not found on polluted ids).

OpenCode paths updated: CLI parsers (parseModelsCliOutput, parseAgentListCliOutput, parseSkillsCliOutput), provider capability building, sendTurn / text-generation prompts (agent/variant), plus getProviderOptionStringSelectionValue, custom model slugs, and trimOrNull in shared model helpers. New parser tests cover polluted stdout.

Web (#9318): Pending user-input answers use thread.user-input.respond, so ChatComposer.submitComposer and ChatView.onSend handle activePendingProgress before normal-send guards (isSendBusy, connecting, provider availability). Submit/Next on the Input badge no longer stalls silently when a turn is busy.

Reviewed by Cursor Bugbot for commit e282152. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix pending user-input Submit to bypass normal-send guards and strip terminal escapes from OpenCode CLI output

  • Pending user-input submissions in ChatComposer and ChatView now dispatch through the pending-input path before provider-availability, send-busy, loading, and in-flight guards, so they are not blocked by an ordinary provider turn in progress.
  • Adds a shared stripTerminalEscapes sanitizer and sanitizeTerminalValue helper in packages/shared, exported via the stripTerminalEscapes subpath.
  • OpenCode CLI parsers (parseModelsCliOutput, parseAgentListCliOutput, parseSkillsCliOutput) and capability/status builders now strip terminal escape sequences from captured output before parsing or option construction, so polluted CLI output yields clean provider, model, agent, variant, and version identifiers.
  • Model-option accessors (getProviderOptionStringSelectionValue, normalizeCustomModelSlug, trimOrNull) now sanitize terminal escapes and whitespace before returning values, returning undefined/null for empty sanitized results.
  • Risk: getProviderOptionStringSelectionValue now returns undefined for non-string or empty-after-sanitize values where it previously returned the raw value; downstream consumers in OpenCodeAdapter and OpenCodeTextGeneration already handle undefined.
📊 Macroscope summarized e282152. 8 files reviewed, 3 issues evaluated, 0 issues filtered, 1 comment posted

🗂️ Filtered Issues

ImBIOS and others added 3 commits August 21, 2026 11:05
…tored agent selections

opencode <=1.18 writes ESC ]0;<cwd>: ready BEL to stdout for every
non-help command even when stdout is a pipe (agent list, models
--verbose, debug skill). T3's ChildProcessSpawner captures that stdout
via collectStreamAsString and the parsers stored a polluted agent id
like "\x1b]0;imbios: ready\x07build" in model_selection_json.

Later sendTurn used that polluted id and opencode rejected it with
"Agent not found: \"\x1b]0;imbios: ready\x07build\"" which was
surfaced as session.error UnknownError + a generic SessionPrompt
UnknownError wrapper (the stack the user pasted).

Fix:
- packages/shared/src/stripTerminalEscapes.ts: shared OSC/CSI sanitizer
- apps/server/src/provider/opencodeRuntime.ts: strip before
  parseModels/Agent/Skills and via parse* entry points; keeps skills
  from silently degrading to [] when polluted
- apps/server/src/provider/Layers/OpenCodeProvider.ts: sanitize
  inventory agent names/variants and --version parsing; build clean
  capability option ids
- apps/server/src/provider/Layers/OpenCodeAdapter.ts &
  textGeneration/OpenCodeTextGeneration.ts: sanitize stored
  getModelSelectionStringOptionValue values before promptAsync
- packages/shared/src/model.ts: sanitize persisted option values and
  model slugs on read (repairs 3 polluted threads without DB migration)
- tests: add OSC/ANSI regression cases for both parsers

Polluted threads still read as clean via model.ts sanitizer; no
migration needed but DB can be cleaned with stripTerminalEscapes.

Fixes the reported UnknownError at SessionPrompt.createUserMessage
and the earlier "Agent not found" session.error.
Enabled Submit on the Input badge was swallowed silently: ComposerPrimaryActions only disables on isComplete/canAdvance, but submitComposer blocked on noProviderAvailable/isSendDisabled and ChatView.onSend blocked on isSendBusy/isConnecting/threadDetailLoading/sendInFlight before reaching the pending branch.

Pending answers use thread.user-input.respond and need no provider or send context, so route them first in both submitComposer and onSend. Only !activeThread and environment-unavailable still block.

Fixes pingdotgg#9318.

Built with Muse Spark via OpenCode.
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 3, 2026
* through `shell: true` spawns.
*/
const OSC_RE = /\x1b\].*?(?:\x07|\x1b\\)/g;
const CSI_RE = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;

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.

🟠 High src/stripTerminalEscapes.ts:17

stripTerminalEscapes leaves standard escape content in captured output, so affected agent headers and skills JSON remain corrupted and parsing fails. CHARSET_RE does not consume ESC */ESC +/ESC -/ESC ./ESC / designations, CSI_RE does not match colon-delimited parameters such as \x1b[38:2::255:0:0m, and SINGLE_ESC_RE removes only the DCS/PM/APC introducer and terminator while leaving payloads such as payload. Extend charset and CSI matching, and consume DCS/PM/APC strings through their ESC \ terminator before applying single-escape cleanup.

🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/shared/src/stripTerminalEscapes.ts around line 17:

`stripTerminalEscapes` leaves standard escape content in captured output, so affected agent headers and skills JSON remain corrupted and parsing fails. `CHARSET_RE` does not consume `ESC *`/`ESC +`/`ESC -`/`ESC .`/`ESC /` designations, `CSI_RE` does not match colon-delimited parameters such as `\x1b[38:2::255:0:0m`, and `SINGLE_ESC_RE` removes only the DCS/PM/APC introducer and terminator while leaving payloads such as `payload`. Extend charset and CSI matching, and consume DCS/PM/APC strings through their `ESC \` terminator before applying single-escape cleanup.

@ImBIOS

ImBIOS commented Sep 3, 2026

Copy link
Copy Markdown
Author

Verification (worktree t3code-0c23097b, node v24.19.0, pnpm 11.10.0):

  • pnpm install done — node_modules exists.
  • vp test run apps/web/src/components/chat/composerSubmission.test.ts apps/web/src/components/chat/ComposerPrimaryActions.test.tsx apps/web/src/pendingUserInput.test.ts → 3 files, 37 tests passed.
  • vp test run apps/web/src/components/ChatView.logic.test.ts apps/web/src/components/chat/ComposerPendingUserInputPanel.test.tsx → 2 files, 40 tests passed.
  • vp run --filter @t3tools/web typecheck → clean (tsgo --noEmit).

No repo-wide checks per contributing guide; change is web-only (ChatComposer + ChatView guard reorder). Mobile onSubmitUserInput already bypasses send guards, no change needed there.

@macroscopeapp

macroscopeapp Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Would Approve

Macroscope's review found this PR approvable — This is a bounded bug fix that restores the existing pending-input response path and removes terminal escape pollution from OpenCode data without schema or infrastructure changes. An unresolved High-severity finding flags incomplete handling of less-common escape sequences, so that correctness risk should be considered separately.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

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

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Submit button in Input status does nothing — enabled pending-user-input Submit is swallowed by normal-send guards

1 participant