Skip to content

BaseModel tool arguments come back as dict not BaseModel #298

Description

@jamesbraza

Trying to use a complex BaseModel as a tool argument with GPT 5:

import asyncio

from pydantic import BaseModel, Field

from aviary.core import Environment, Message, Tool, ToolSelector


class ComplexArg(BaseModel):
    arg: int = Field(description="Some integer argument.")


def some_tool(arg: ComplexArg) -> None:
    """Do something.

    Args:
        arg: Some complex argument.
    """


async def main() -> None:
    selector = ToolSelector("gpt-5-mini-2025-08-07")
    tool_request_message = await selector(
        messages=[Message(content="Will this work?")],
        tools=[Tool.from_function(some_tool)],
    )
    (tool_call,) = tool_request_message.tool_calls
    assert isinstance(tool_call.function.arguments, dict)
    assert isinstance(tool_call.function.arguments.get("arg"), ComplexArg)


if __name__ == "__main__":
    asyncio.run(main())

It won't work as of fhaviary==0.24.3 because:

  1. GPT 5 will propose the tool request's arguments as a str
  2. ToolCallFunction deserializes the arguments to dict here
  3. Environment.exec_tool_calls doesn't auto-cast to the BaseModel

We should either:

  • Find a way to store the desired BaseModel in the ToolRequestMessage (perhaps in the info field)
  • Deserialize per the tool's JSON schema in Environment.exec_tool_calls

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions