Skip to content

Python: Send empty text for GitHubCopilotAgent tool results without text - #10272

Open
Aditya Kumar (Aditya-XR) wants to merge 1 commit into
microsoft:mainfrom
Aditya-XR:fix/copilot-tool-result-repr
Open

Aditya Kumar (Aditya-XR) wants to merge 1 commit into
microsoft:mainfrom
Aditya-XR:fix/copilot-tool-result-repr

Conversation

@Aditya-XR

@Aditya-XR Aditya Kumar (Aditya-XR) commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Motivation & Context

When a function tool given to GitHubCopilotAgent produces no text, the model receives the repr of a Python list as the tool result, for example [<agent_framework._types.Content object at 0x77287488b230>]. This happens when the tool returns None, an empty string, or only rich content such as an image.

The tool adapter falls back to str(result) when there is no text. That was correct while FunctionTool.invoke returned a string, but since #4331 it returns a list of Content items, so the fallback now produces the list repr.

Description & Review Guide

  • What are the major changes?

    The adapter in _tool_to_copilot_tool now sends the joined text as is:

                     text = "\n".join(c.text for c in result if c.type == "text" and c.text)
                     return ToolResult(
    -                    text_result_for_llm=text or str(result),
    +                    text_result_for_llm=text,
                         result_type="success",
                     )

    A new parametrized test, test_tool_handler_returns_empty_text_when_tool_returns_no_text, covers a tool that returns None, "" and only an image. Without the fix all three cases fail, because text_result_for_llm is the Content list repr.

  • What is the impact of these changes?

    Tools without a text result now report an empty string to the model instead of a repr with a memory address. Tools that return text are unchanged. For a tool that returns only rich content, the existing "does not support rich tool content" warning is still logged and the result text is empty.

  • What do you want reviewers to focus on?

    An empty string is what the Copilot SDK sends for a handler that returns None (copilot.tools._normalize_result), and what ClaudeAgent sends in the same case, so I used the same value here.

Related Issue

Fixes #10271

This is a one-line correction of a leftover str(result) fallback from #4331, so I opened it together with the issue.

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: I used Claude Code as an assistant to help find the bug and to draft the fix, the test, the linked issue and this description. I did the final review myself: I read and understood every change, checked the repro and test results, and made the final decisions on what to submit.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

The Copilot tool adapter fell back to str(result) when a tool produced no
text. Since tool results became lists of Content items, that fallback sends
the list repr ("[<agent_framework._types.Content object at 0x...>]") to the
model for tools that return None, an empty string, or only rich content.

Send the joined text as is, so these tools report an empty result like the
Copilot SDK does for a handler that returns None.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@eavanvalkenburg

Copy link
Copy Markdown
Member

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAF Automated Review — Iteration 1

Result: No findings
Scope: full PR (1 commit(s)): f9103266c669
Model: gpt-5.6-sol

Overview

The PR removes an obsolete fallback that stringified the list[Content] returned by FunctionTool.invoke, and instead forwards the joined text or an empty string. The new parametrized test covers None, empty-string, and rich-only returns, while the unchanged warning and error paths preserve existing guardrails. Empty text is consistent with the SDK normalization path and the Claude provider adapter, and no publishable Critical, High, or Medium issue was established.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.

This branch was successfully deployed

1 active deployment
github-app-auth — f9103266 Deployed Nov 11, 2026 by Aditya-XR via add_label #27617
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: GitHubCopilotAgent sends a Python object repr as the tool result when a tool returns no text

3 participants