Skip to content

OpenAIResponsesLlm drops the keys beside "result" in a tool's dict return #7836

Description

@adityasingh2400

🔴 Required Information

Describe the Bug:
OpenAIResponsesLlm drops every key except result from a tool's dict return. _serialize_json_value (integrations/openai/_openai_responses_llm.py) unwraps any mapping that has a non-None result key and sends only that value as the function_call_output. ADK wraps a non-dict tool return as exactly {"result": value}, but a tool's own dict can also have a result key next to other data. For example, {"result": "found 2 contracts", "contracts": [...], "next_page_token": "abc"} reaches the model as just found 2 contracts.

AnthropicLlm had the same bug, fixed in #7073: it now unwraps only when the keys are exactly {"result"}.

Steps to Reproduce:

  1. Give an LlmAgent using OpenAIResponsesLlm(model="gpt-5") a function tool that returns {"result": "found 2 contracts", "contracts": ["NDA-12", "MSA-7"], "next_page_token": "abc"}.
  2. Let the model call it and inspect the function_call_output item in the next responses.create input.

Expected Behavior:
The whole dict is sent as JSON. Only the bare {"result": value} wrapper is unwrapped.

Observed Behavior:

function_call_output sent to OpenAI: found 2 contracts

Environment Details:

  • ADK Library Version (pip show google-adk): 2.13.0 (also on main at 75fb788)
  • Desktop OS: macOS
  • Python Version (python -V): 3.11.16

Model Information:

  • Are you using LiteLLM: No
  • Which model is being used: gpt-5 via OpenAIResponsesLlm

🟡 Optional Information

Additional Context:

if 'result' in value and value['result'] is not None:
  result = value['result']
  if isinstance(result, str):
    return result
  return json.dumps(result, default=str)

How often has this issue occurred?:

  • Always (100%), for tool dicts that have a result key beside other keys

Activity

  1. added
    models[Component] This issue is related to model support
    on Oct 30, 2026
  2. surajksharma07 commented on Oct 30, 2026

    @surajksharma07
    Collaborator

    @adityasingh2400 Reproduced this on 2.13.0 and main: only “found 2 contracts” reaches the model while contracts/next_page_token get dropped.

    A workaround that worked locally: unwrap only when value.keys() == {'result'} in _serialize_json_value (the same rule AnthropicLlm got in #7073) so any other dict goes out as full JSON. Could you give that a try on your side and check that the bare {"result": x} returns and the MCP content outputs still behave the same?

    Once you’ve confirmed it holds up #7837 looks like the right place for it. Will flag it for review. #7847 looks like it covers the same change so it’s worth settling on one of the two.

  3. adityasingh2400 commented on Oct 31, 2026

    @adityasingh2400
    ContributorAuthor

    Thanks for reproducing it. #7837 already uses exactly that rule (value.keys() == {'result'}), and I re-checked both cases you mentioned on the PR branch:

    • A bare wrapper is still unwrapped. test_function_response_unwraps_adk_result_wrapper checks {"result": "sunny"} → sunny and {"result": [1, 2]} → [1, 2].
    • MCP content outputs are unchanged. The content branch returns before the result check is reached, and the existing test_function_response_serializes_mcp_content_as_text passes unmodified.

    tests/unittests/integrations/openai passes (227 tests). The PR also has an end-to-end run with a real Runner showing the full dict reaching function_call_output.

    On the duplicate: #7837 was opened with this issue, about three hours before #7847 (19:05 vs. 22:09 UTC), so I'd suggest keeping #7837. Happy to go with whichever you prefer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

models[Component] This issue is related to model support

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions