.NET: [Bug]: Shell="cmd" echoes commands containing quotes instead of executing them and reports exit 0
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
調査の方向性
Start in ShellResolver.StatelessArgvForCommand, which builds the cmd /d /c argv, and in the Cmd branch of LocalShellExecutor.RunStatelessAsync, where the elements are added through ProcessStartInfo.ArgumentList. Run the 25-line reproduction on Windows to confirm that quoted commands are echoed with exit 0. Done means quoted commands such as echo "quoted value" return the correct stdout with the right exit code on Windows. Wait for maintainer agreement on the /s approach before you start.
索引モデルが issue の本文から書いたものです。
説明
Observed Behavior
LocalShellExecutor in stateless mode with Shell = "cmd" does not execute commands that contain double quotes. It prints the command text as if it were the program output and reports ExitCode == 0, so the caller has no signal that nothing ran.
LocalShellExecutor.RunAsync("powershell -NoProfile -Command \"Write-Output hello\"")
stdout: Write-Output hello ExitCode: 0 <-- command echoed, never executed
LocalShellExecutor.RunAsync("echo \"quoted value\"")
stdout: \"quoted value\" ExitCode: 0 <-- quotes arrived escaped as \" and were printed
The second case shows the mechanism: the child process receives the quote as literal \". For commands that do run despite this, their arguments are corrupted the same way.
This is the shape models emit all the time, for example powershell -NoProfile -Command "...", git commit -m "message", or echo "text". On Windows the tool silently returns a success with wrong output, which is worse than an error because the model has no reason to retry.
Expected Behavior
Quoted commands execute normally:
RunAsync("powershell -NoProfile -Command \"Write-Output hello\"") -> stdout: hello ExitCode: 0
RunAsync("echo \"quoted value\"") -> stdout: "quoted value" ExitCode: 0
Steps to Reproduce
- On Windows, create a console project targeting
net10.0and addMicrosoft.Agents.AI.Tools.Shell(prerelease). - Construct
LocalShellExecutorinShellMode.StatelesswithShell = "cmd". RunAsynca command containing a double quote, for examplepowershell -NoProfile -Command "Write-Output hello".- Observe
Stdout == "Write-Output hello"withExitCode == 0: the command was echoed, not executed.
Minimal Reproduction
using Microsoft.Agents.AI.Tools.Shell;
await using var shell = new LocalShellExecutor(new LocalShellExecutorOptions
{
Mode = ShellMode.Stateless,
Shell = "cmd",
AcknowledgeUnsafe = true, // unrelated to this bug: only disables the approval wrapper
WorkingDirectory = Directory.GetCurrentDirectory(),
Timeout = TimeSpan.FromSeconds(30),
});
var nested = await shell.RunAsync("powershell -NoProfile -Command \"Write-Output hello\"", default);
Console.WriteLine($"stdout=[{nested.Stdout.Trim()}] exit={nested.ExitCode}");
// actual: stdout=[Write-Output hello] exit=0
// expected: stdout=[hello] exit=0
var quoted = await shell.RunAsync("echo \"quoted value\"", default);
Console.WriteLine($"stdout=[{quoted.Stdout.Trim()}] exit={quoted.ExitCode}");
// actual: stdout=[\"quoted value\"] exit=0
// expected: stdout=["quoted value"] exit=0
Error Messages and Stack Traces
None. That is part of the problem: no exception, no stderr, exit code 0.
Package Versions
Microsoft.Agents.AI.Tools.Shell1.27.0-preview.261030.1- (transitive)
Microsoft.Agents.AI.Abstractions1.27.0,Microsoft.Extensions.AI10.10.0
.NET Version
.NET 10.0.402 SDK, runtime 10.0.9.
Operating System
Windows
Regression
Unknown
Additional Context
Cause. ShellResolver.StatelessArgvForCommand builds cmd /d /c <command> and LocalShellExecutor.RunStatelessAsync adds each element through ProcessStartInfo.ArgumentList. .NET escapes " as \" when it flattens ArgumentList into a command line, and cmd.exe has no notion of an escaped quote, so it terminates the /c argument at the first \" and treats the rest as text to print. cmd.exe documents /s as the way to pass a full command line: with /s, the outer pair of quotes is stripped and the remainder is used verbatim.
Suggested fix. For ShellKind.Cmd, bypass ArgumentList and set the command line as a single Arguments string:
startInfo.Arguments = $"/d /s /c \"{command}\"";
That is the same approach powershell/bash do not need, so it can stay inside the Cmd branch of RunStatelessAsync.
The persistent path (ShellSession) uses the same ArgumentList for its launch argv, but since persistent mode is not supported for cmd.exe, only stateless is affected.
Workaround. Build the command line manually for cmd instead of going through ArgumentList (what a downstream consumer does today), or avoid cmd by using Shell = "pwsh", which changes how bash-style commands in model output behave.
AI assistance. The analysis, the reproduction program and this report were prepared with an AI coding assistant. Every command output quoted here was produced by actually running the reproduction; none of it is predicted or paraphrased. Package versions, API names and source references were checked against the published package and the repository's main branch.
Verification. Reproduced locally before filing:
- OS: Windows 10.0.26300.9711
- SDK: .NET SDK 10.0.402, runtime 10.0.9
- Package:
Microsoft.Agents.AI.Tools.Shell1.27.0-preview.261030.1 - How:
dotnet runon the 25-line console project in Minimal Reproduction above - Output:
stdout=[Write-Output hello] exit=0,stdout=[\"quoted value\"] exit=0
Acknowledgements
- I searched existing issues and did not find a duplicate (searched
cmd quote,ArgumentList,LocalShellExecutor,Tools.Shell, and open issues/PRs withshellin the title; every existing shell issue targets the other SDK implementation, none target the .NET one). - I personally verified this behavior and the reproduction details are authentic.
- I will wait for explicit maintainer agreement before starting implementation of a non-trivial change.
- 主要言語
- Python
- スター
- 14.5k
- フォーク
- 2.6k
- 平均マージ
- 2日 13時間
- マージ済み PR(30日)
- 335
環境構築
このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
microsoft/agent-framework のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
microsoft/agent-framework#9946 ·
メンテナーはふだん 1 日以内に返信
-
.NET: [Issue]: Function invocation middleware receives tool results as JsonElement, which the docs do not mention対応中かも @LHB0317 が 1 日前に担当しました。 オープン.NET triage
難易度 1/5 1時間未満 初心者へのやさしさ 72/100
microsoft/agent-framework#9918 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
Python: [Bug]: native Windows --files paths skip changed-package tasks対応中かも @ktz03 が 6 日前に担当しました。 オープンneeds-maintainer-triage python triage
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
microsoft/agent-framework#9742 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
-
.NET triage
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
microsoft/agent-framework#9704 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
Python: FileSessionStore.set fails on Windows for long session IDs because its temp file name is 38 characters longer than the snapshot対応中かも @Sonica-B が 7 日前に担当しました。 オープンpython ready-for-implementation
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
microsoft/agent-framework#9682 · 担当者 2 名 ·
メンテナーはふだん 1 日以内に返信
microsoft/agent-framework の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
enhancement good first issue
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
elviskahoro/sdk-python-attio#144 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
メンテナーはふだん 1 日以内に返信
-
RenyiELBO raises TypeError when model has no sample sites対応中かも @alibb007 が今日担当しました。 オープン
難易度 1/5 1時間未満 初心者へのやさしさ 85/100
メンテナーはふだん 1 日以内に返信
-
[Bug]: Four evaluation scripts unpack init_memmachine_params's five return values into three namesオープン
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
MemMachine/MemMachine#1911 ·
メンテナーはふだん 3 日以内に返信