Fix/shell#387
Open
makiroll1125 wants to merge 2 commits into
Open
Conversation
… instead of old list form that corrupted commands with embedded quote argument
makiroll1125
requested review from
ahmad-ajmal and
zfoong
and removed request for
ahmad-ajmal
July 17, 2026 05:06
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
run_shellcmd branch:app/data/action/run_shell.pynow invokes the Windowscmdshell viasubprocess.Popen(args, shell=use_shell, ...)withuse_shell = shell_choice == "cmd", passing the raw command string, instead of the old list-formargs = ["cmd.exe", "/d", "/s", "/c", command]passed toPopenwithoutshell=True.powershell/pwshbranches are untouched.chatInputSlice.tsgains adrafts: Record<string, string>map (keyed bylivingUIId ?? 'main') plussetDraftText/clearDraftTextreducers;store/selectors/chatInput.tsgains aselectDraftText(key)selector;Chat.tsx's composer text now reads/writes through Redux instead of a localuseState.agent_core/core/impl/llm/interface.py's_generate_byteplus_with_sessionand_generate_byteplus_with_prefix_cachenow populateerror/error_info_obj(viaclassify_llm_error) on their return dict whenever the underlying call raised, instead of discarding the caught exception and returning emptycontent.Why
run_shell: Python's automaticlist2cmdline()quoting for a list-formPopencall backslash-escapes embedded double quotes, butcmd.exe's own/C//Sargument parser doesn't understand backslash-escaped quotes, it expects literal, unescaped ones. Any command containing a quoted argument (e.g.claude -p "<prompt>") got corrupted before reaching the shell, silently breaking every such invocation rather than raising a clear error.useStatelived insideChat.tsx, whichreact-router's<Routes>fully unmounts when navigating to another tab (Settings, Tasks & Actions) so a draft in progress was destroyed on every tab switch. Moving it into thechatInputRedux slice (already mounted above the router) lets it survive route unmounts. It's keyed by conversation becauseChat.tsxis shared between the main Chat page and every Living UI project's chat panel, so a flat single field would have leaked one conversation's draft into another's.HTTPError) into a localexc_obj, but the finalreturndiscarded it, so a rate-limited or otherwise-failed call looked identical to "success with no content" (_finalize_session_responselogs a generic "LLM returned empty response" and can't distinguish it). Consecutive failures still aborted the agent after 5 tries, but with no rate-limit classification attached, so no backoff/retry-aware handling downstream ever fired. Five other provider paths in the same file (including BytePlus's own non-session path) already follow the correct pattern; the session/prefix-cache paths just hadn't been brought in line.How to test
run_shell: run arun_shellaction withshell: "cmd"and a command containing an embedded quoted argument (e.g.claude -p "test prompt"or anyfoo -x "a b"style invocation), in both foreground and background mode. Confirm the child process receives the argument intact (no stray literal quote characters), where previously it would fail to parse or resolve to a mangled path/argument.Chat draft persistence:
Type a draft in the main Chat input, navigate to a new tab such as Settings or Tasks & Actions, then navigate back and the draft should still be present.
BytePlus silent failures: mock/trigger a BytePlus API call that returns a 429 (or any non-2xx) response and confirm the returned dict now has
erroranderror_info_objset (error_info_obj.category == RATE_LIMITfor a 429), and that_finalize_session_responselogs a classified rate-limit error instead of "LLM returned empty response." If a live BytePlus key with rate-limit headroom is available, reproduce by issuing requests fast enough to hitModelAccountTpmRateLimitExceededand confirm the same.