.NET: Python: [Bug]: Persistent PowerShell LocalShellTool returns empty stdout for commands that output objects
Maintainer thường phản hồi trong vòng 1 ngày
Đánh giá
Issue này chưa được đánh giá.
Mô tả
Description
LocalShellTool in its default mode="persistent" returns an empty stdout for any PowerShell command whose output gets formatted as a table or list. That includes Get-Location / pwd, anything piped through Select-Object, Get-Process, and [pscustomobject]. The command succeeds with exit_code=0, but the agent gets nothing back. Once an object has been written, plain strings that come after it in the same command are lost too. mode="stateless" returns all of this output.
This happens on Windows, where PowerShell is the default shell, and with pwsh on Linux, so it isn't Windows-specific.
Cause: ShellSession._build_script runs the command as & { try { Invoke-Expression $__af_cmd; ... } finally { [Console]::WriteLine('<sentinel>_' + $__af_rc) } } and leaves formatting to the host. The host's Out-Default only flushes table/list formatting when the outer pipeline ends, which is after the script block has returned. By then finally has already written the sentinel straight to [Console]. So the formatted output lands after the sentinel in the stdout buffer, and _run_locked throws it away, since it keeps only the bytes before the sentinel and then clears the buffer. Plain strings survive only because Out-Default writes them immediately.
The .NET ShellSession already handles this. BuildScript in dotnet/src/Microsoft.Agents.AI.Tools.Shell/ShellSession.cs formats the output inside the try, with the comment: "Without this, pwsh defers Out-Default formatting until the script block returns and the sentinel races ahead of the user's output in the byte stream."
Expected: persistent mode returns the same stdout as stateless mode.
Code Sample
import asyncio
import re
import shutil
from agent_framework.tools import LocalShellTool
POWERSHELL = shutil.which("pwsh") or shutil.which("powershell")
SHELLS = {
# the argv LocalShellTool uses by default on Windows
"persistent": [POWERSHELL, "-NoLogo", "-NoProfile", "-NonInteractive", "-Command", "-"],
"stateless": [POWERSHELL],
}
COMMANDS = [
"Get-Location",
"Get-Item $PSHOME | Select-Object Name",
"[pscustomobject]@{ Name = 'an object' }; Write-Output 'a string after it'",
"Write-Output 'just a string'",
]
async def main() -> None:
for mode, shell in SHELLS.items():
async with LocalShellTool(mode=mode, shell=shell) as tool:
for command in COMMANDS:
result = await tool.run(command)
stdout = re.sub(r"\x1b\[[0-9;?]*[A-Za-z]", "", result.stdout).strip() # drop terminal escape codes
print(f"{mode:<10} exit_code={result.exit_code} stdout={stdout!r}")
print(f"{'':<10} ^ {command}")
asyncio.run(main())
Output on main with Linux (Debian 12, PowerShell 7.6.6):
persistent exit_code=0 stdout=''
^ Get-Location
persistent exit_code=0 stdout=''
^ Get-Item $PSHOME | Select-Object Name
persistent exit_code=0 stdout=''
^ [pscustomobject]@{ Name = 'an object' }; Write-Output 'a string after it'
persistent exit_code=0 stdout='just a string'
^ Write-Output 'just a string'
stateless exit_code=0 stdout='Path\n----\n/tmp'
^ Get-Location
stateless exit_code=0 stdout='Name\n----\n7'
^ Get-Item $PSHOME | Select-Object Name
stateless exit_code=0 stdout='Name\n----\nan object\na string after it'
^ [pscustomobject]@{ Name = 'an object' }; Write-Output 'a string after it'
stateless exit_code=0 stdout='just a string'
^ Write-Output 'just a string'
I get the same result on Windows 11 with PowerShell 7.6.6 and with Windows PowerShell 5.1, and the same with the default LocalShellTool() there, without passing shell=.
Error Messages / Stack Traces
None. The empty stdout comes back with exit_code=0.
Package Versions
agent-framework-tools: 1.0.0b261002, agent-framework-core: 1.20.0 (source checkout of main at e9857bd75)
Python Version
Python 3.13
Additional Context
- The persistent PowerShell tests in
python/packages/tools/tests/test_local_shell_tool.pyonly check plain strings and exit codes, so none of them covers output PowerShell formats as a table. The re-anchor test, for example, reads(Get-Location).Path, which returns a string and so doesn't hit this. PlainGet-Locationwould. - Fix: format the output inside the
try, beforefinallywrites the sentinel:Invoke-Expression $__af_cmd | Out-Default;. Unlike a per-objectOut-String, this keeps PowerShell's normal formatting (one table per command). Exit codes for native failures, cmdlet errors,throw, and$LASTEXITCODEreadback stay the same. I'll open a PR with this and a regression test.
- Ngôn ngữ chính
- Python
- Star
- 13.9k
- Fork
- 2.4k
- Merge trung bình
- 1 ngày 16 giờ
- Pull request đã merge (30 ngày)
- 432
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của microsoft/agent-framework
-
Python: raw-data content mappings lose annotations and attachment metadataCó thể đã có người làm @moonbox3 đã nhận 6 ngày trước. Đang mởpython triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
microsoft/agent-framework#8632 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Python: Clarify when to use platformCó thể đã có người làm @eavanvalkenburg đã nhận 5 ngày trước. Đang mởpython triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
microsoft/agent-framework#8599 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
.NET Compaction - Update docs to refer to `AIContextProvider` deep diveCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở.NET compaction documentation
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 82/100
microsoft/agent-framework#4629 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Python: [Bug]: Public stream close does not release delegated provider responsesCó thể đã có người làm @eavanvalkenburg đã nhận hôm nay. Đang mởag-ui python reproduced
microsoft/agent-framework#9099 · 1 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Python: [Bug]: AZURE_OPENAI_API_VERSION is ignored by the OpenAI clients on the Azure routeCó thể đã có người làm @eavanvalkenburg đã nhận hôm nay. Đang mởagents python reproduced
microsoft/agent-framework#9097 · 1 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của microsoft/agent-framework
Issue tương tự
-
needs-human needs-triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
gke-labs/kube-agents#2400 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Device Details tables: FS/SF columns contradict each other (nfet_01v8 Vt row, pfet_01v8 Idsat row)Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
google/skywater-pdk#450 ·
-
Drained trajectory arrays are overwritten when the sequence buffer is reusedCó thể đã có người làm @sylvesterkaczmarek đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
google-deepmind/bsuite#56 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
LearningCircuit/local-deep-research#7206 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[TASK] Document technology stackĐang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
chingu-voyages/V62-tier3-team-33#285 ·
Maintainer thường phản hồi trong vòng 1 ngày