fix(web): pending user-input Submit bypasses normal-send guards - #9319
fix(web): pending user-input Submit bypasses normal-send guards#9319ImBIOS wants to merge 3 commits into
Conversation
…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.
| * through `shell: true` spawns. | ||
| */ | ||
| const OSC_RE = /\x1b\].*?(?:\x07|\x1b\\)/g; | ||
| const CSI_RE = /\x1b\[[0-9;?]*[ -/]*[@-~]/g; |
There was a problem hiding this comment.
🟠 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.
|
Verification (worktree
No repo-wide checks per contributing guide; change is web-only (ChatComposer + ChatView guard reorder). Mobile |
ApprovabilityVerdict: 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:
Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more. |
Enabled Submit on the Input badge did nothing: the button enables on isComplete/canAdvance (
ComposerPrimaryActions.tsx:147), butsubmitComposer(ChatComposer.tsx:1890) blocked onnoProviderAvailable || isSendDisabledandChatView.onSend(ChatView.tsx:5037) blocked onisSendBusy || isConnecting || threadDetailLoading || sendInFlightbefore 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 pathcovers 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/sanitizeTerminalValueand 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--versionprobes (avoidingAgent not foundon polluted ids).OpenCode paths updated: CLI parsers (
parseModelsCliOutput,parseAgentListCliOutput,parseSkillsCliOutput), provider capability building,sendTurn/ text-generation prompts (agent/variant), plusgetProviderOptionStringSelectionValue, custom model slugs, andtrimOrNullin shared model helpers. New parser tests cover polluted stdout.Web (#9318): Pending user-input answers use
thread.user-input.respond, soChatComposer.submitComposerandChatView.onSendhandleactivePendingProgressbefore 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
ChatComposerandChatViewnow 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.stripTerminalEscapessanitizer andsanitizeTerminalValuehelper inpackages/shared, exported via thestripTerminalEscapessubpath.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.getProviderOptionStringSelectionValue,normalizeCustomModelSlug,trimOrNull) now sanitize terminal escapes and whitespace before returning values, returningundefined/nullfor empty sanitized results.getProviderOptionStringSelectionValuenow returnsundefinedfor non-string or empty-after-sanitize values where it previously returned the raw value; downstream consumers inOpenCodeAdapterandOpenCodeTextGenerationalready handleundefined.📊 Macroscope summarized e282152. 8 files reviewed, 3 issues evaluated, 0 issues filtered, 1 comment posted
🗂️ Filtered Issues