Python: [Bug]: Local shell results are sent to OpenAI as exit 0, even when the command failed or timed out
Los mantenedores suelen responder en 1 día
@eavanvalkenburg ya está trabajando en esto.
Desde el 1/10/2026.
Evaluación
Este issue todavía no se ha evaluado.
Descripción
Description
When a local shell tool runs through the OpenAI Responses client, its result goes back as a shell_call_output whose structured outcome is always {"type": "exit", "exit_code": 0}. That holds when the command exited non-zero and when it timed out. stderr is also sent inside stdout, and the stderr field is empty.
The cause is a mismatch between two packages:
LocalShellTool.as_function()returnsShellResult.format_for_model(), a single string such as"stderr: oops\n\nexit_code: 1"(agent_framework_tools/shell/_tool.py:314;DockerShellTooldoes the same at_docker.py:805).RawOpenAIChatClient._to_shell_call_output_payload(agent_framework_openai/_chat_client.py:2391) can buildstdout,stderr,exit_codeandtimed_outfrom a mapping. Given a string, it puts the whole text instdoutand falls back toexit_code = 0, because there is no exception.
So the model receives a structured outcome that contradicts the text next to it: a failed command reported as success, and a timeout reported as a clean exit rather than the payload's dedicated {"type": "timeout"}.
Expected: outcome matches the command's real result (exit_code: 3, exit_code: 1, {"type": "timeout"}), and stderr goes in stderr.
Actual: outcome is {"type": "exit", "exit_code": 0} in all three cases below.
Code Sample
import asyncio
import tempfile
from agent_framework import Content
from agent_framework.openai import OpenAIChatClient
from agent_framework_tools.shell import LocalShellTool
async def main() -> None:
shell = LocalShellTool(mode="stateless", workdir=tempfile.mkdtemp(), approval_mode="never_require",
acknowledge_unsafe=True, timeout=2)
shell_tool = OpenAIChatClient.get_shell_tool(func=shell.as_function())
# PowerShell syntax (Windows); on Linux/macOS use e.g. "echo oops >&2; exit 1" and "sleep 5".
for command in ("exit 3", "[Console]::Error.WriteLine('oops'); exit 1", "Start-Sleep 5"):
result = await shell_tool.invoke(arguments={"command": command}) # what the function loop receives
payload = OpenAIChatClient._to_shell_call_output_payload(Content.from_function_result(call_id="c", result=result))
print(f"$ {command}\n tool text : {result[0].text!r}\n sent : {payload}")
asyncio.run(main())
Error Messages / Stack Traces
$ exit 3
tool text : 'exit_code: 3'
sent : [{'stdout': 'exit_code: 3', 'stderr': '', 'outcome': {'type': 'exit', 'exit_code': 0}}]
$ [Console]::Error.WriteLine('oops'); exit 1
tool text : 'stderr: oops\r\n\nexit_code: 1'
sent : [{'stdout': 'stderr: oops\r\n\nexit_code: 1', 'stderr': '', 'outcome': {'type': 'exit', 'exit_code': 0}}]
$ Start-Sleep 5
tool text : '[command timed out]\nexit_code: 15'
sent : [{'stdout': '[command timed out]\nexit_code: 15', 'stderr': '', 'outcome': {'type': 'exit', 'exit_code': 0}}]
Package Versions
agent-framework-core: 1.19.0, agent-framework-openai: 1.14.4, agent-framework-tools: 1.0.0b260918
Python Version
Python 3.13.13 (Windows 11, PowerShell)
Additional Context
- Reproduced on the released packages above, in a fresh environment, and on
mainat7634356a1. - Only the OpenAI shell path is affected. With Anthropic's
bash_*tool the result goes back as atool_resultcarrying the text (withis_errorset only on an exception), and a plain function tool sends the text as its output, so neither has a structured exit code to contradict it. - Proposed fix: have the shell tools return their structured result alongside the text, and have the OpenAI payload builder use it. Core already defines
Content.from_shell_command_output(stdout=, stderr=, exit_code=, timed_out=), which the OpenAI and Anthropic clients use today for inbound hosted shell output. The local tools could emit the same content, and_to_shell_call_output_payloadcould buildstdout,stderrand theexit/timeoutoutcome from it. Providers that take text keep receivingformat_for_model()'s output, so nothing changes for them. Reading the exit code back out of the text would be a smaller change, but it would tie the payload to a display format. - This crosses
agent-framework-toolsandagent-framework-openai, and changes how shell results are serialized, whichdocs/specs/004-python-function-calling-loop.mdcovers, so I'd like a maintainer's OK on this direction first. I'm happy to take it.
- Lenguaje dominante
- Python
- Estrellas
- 14k
- Forks
- 2.5k
- Merge medio
- 2 d 4 h
- PR fusionados (30 d)
- 403
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de microsoft/agent-framework
-
Python: [Bug]: Out-of-range Cosmos memory search parameters silently disable retrievalPosiblemente ocupada @eavanvalkenburg la tomó hace 1 día. Abiertopython
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
microsoft/agent-framework#9317 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
Python: [Bug]: A non-positive MCP request timeout silently disables the timeoutPosiblemente ocupada @jpalvarezl la tomó hace 1 día. Abiertopython
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
microsoft/agent-framework#9313 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
Python: [Bug]: Content.from_dict leaves the nested content of image generation and MCP server tool results as plain dictsPosiblemente ocupada @eavanvalkenburg la tomó hace 1 día. Abiertopython
Dificultad 2/5 1-3 horas Aptitud para principiantes 77/100
microsoft/agent-framework#9303 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
.NET: Proposal: add an llms.txtAbierto.NET python triage
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
microsoft/agent-framework#9092 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Python: raw-data content mappings lose annotations and attachment metadataPosiblemente ocupada @moonbox3 la tomó hace 14 días. Abiertopython triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
microsoft/agent-framework#8632 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
Todos los issues de microsoft/agent-framework
Issues similares
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 72/100
-
[Bug]: Importing weave changes the process-wide localePosiblemente ocupada @himanshu748 la tomó hoy. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
-
UX
Dificultad 1/5 Menos de una hora Aptitud para principiantes 72/100
mediajunkie/piper-morgan-product#2008 · 2 comentarios ·