Responses API Function Calling Tool Specs vs Completions API

So, I have been using a tool spec format for Completions API whihc works fantastical, but is throwing errors with respect to Responses API tool spec.

The docs aren’t showing me what changed with respect to function spec between the two, so not sure where the changes have happend.

Can someone guide

error:

Unable to generate ChatCompletion/Response Exception: Error code: 400 - {'error': {'message': "Missing required parameter: 'tools[0].name'.", 'type': 'invalid_request_error', 'param': 'tools[0].name', 'code': 'missing_required_parameter'}}

openai.BadRequestError('Error code: 400 - {\'error\': {\'message\': "Missing required parameter: \'tools[0].name\'.", \'type\': \'invalid_request_error\', \'param\': \'tools[0].name\', \'code\': \'missing_required_parameter\'}}')

Tool spec I use:

[{'type': 'function', 'function': {'name': 'GoalAgentSchema', 'description': 'Schema for Goal Agent to assess, reason and discuss the overall strategy with the user on their \ninitial query before suggesting final plan and recommendation.', 'parameters': {'type': 'object', 'properties': {'user_query': {'description': 'The user query or request that the agent is responding to.', 'type': 'string'}, 'reasoning': {'description': "Step-by-step reasoning to assess the user's query. Ask follow up questions to clarify if needed", 'items': {'$ref': '#/$defs/ChainOfThought'}, 'maxItems': 8, 'minItems': 3, 'type': 'array'}, 'response': {'description': "The agent's response to the user query, including any follow-up questions or clarifications.", 'type': 'string'}, 'user_goal': {'description': 'The goal or objective of the user based on the user query.', 'type': 'string'}}}, 'required': ['user_query', 'reasoning', 'response', 'user_goal']}, 'strict': True}]

I get this by passing any pydantic schema or function to a script that converts it into function calling tool specs as needed by OAI API for tools

def transform_pydantic_to_tool_spec(model_schema: Type[BaseModel]) -> tuple[list[dict], list[dict]]:
    """
    Generates an OpenAI specification dictionary for a given Pydantic model schema.
    This specification is used for the Function Calling feature.

    Also returns a TOOL_MAPPING dictionary.

    Args:
        model_schema (Type[BaseModel]): Pydantic model class.

    Returns:
        tuple[list[dict], list[dict]]: A tuple containing a list with the tool spec and a list with the TOOL_MAPPING dictionary.
    """

    # Convert the Pydantic schema to JSON schema
    schema_dict = model_schema.model_json_schema()

    # Define the initial structure of spec with all necessary placeholders
    spec = {
        "name": schema_dict.get('title', ''),
        "description": schema_dict.get('description', ''),
        "parameters": {
            "type": schema_dict.get('type', 'object'),
            "properties": {},
        },
        "required": schema_dict.get('required', [])
    }

    # Remove 'title' from each property and reformat the schema
    reformatted_properties = {}
    for key, value in schema_dict['properties'].items():
        new_value = {k: v for k, v in value.items() if k != 'title'}
        reformatted_properties[key] = new_value

    # Add property to parameters
    spec['parameters']['properties'] = reformatted_properties

    # Final structure for OpenAI function calling
    final_tool_spec = {
        "type": "function",
        "function": spec,
        "strict": True  # To support structured output
    }

    TOOL_MAPPING = {final_tool_spec["function"]["name"]: model_schema}

    return [final_tool_spec]

I just figured the issue is:

  • For the OpenAI Completions API, the tools parameter expects a list of function specs (each with a “type”: “function” and a “function” key).

  • For the OpenAI Responses API, the tools parameter expects a list of function specs, but the “name” key must be at the top level of each tool dict, not nested under “function”.

  • The error is because the Responses API expects:

    {
      "type": "function",
      "name": ...,
      "description": ...,
      "parameters": {...},
      "required": [...]
    }
    

    (i.e., “name”, “description”, “parameters”, “required” at the top level, not under “function”).

Isn’t this idiotic that a small nuance change is needed for both API otherwise it would not return the output? Why can’t we have same tool specs criteria for both?

3 Likes