Skip to content

[feat] expose forced tool calling for all providers #75

@csells

Description

@csells

e.g. how to do so for the openai responses API: https://www.perplexity.ai/search/openai-responses-api-forcing-t-QtUmmwv5TPipSgMwdrEBlg

To force tool calling with the OpenAI Responses API, set the tool_choice parameter so the model is not allowed to respond with plain content only.[1][2]

Ways to force tool calls

There are three relevant tool_choice modes when using tools with the Responses API.[2]

  • "auto" (default): The model may return normal content, tool calls, or both; it decides when to use tools.[3][2]
  • "required": The model must call one or more tools and will not stop with just a user-facing message; this is the general “always call a tool” switch.[4][5][1]
  • Specific tool: You can force exactly one particular tool by setting tool_choice to an object that names that tool (for function tools something like { "type": "function", "name": "get_weather" }, with the shape depending on the tool type in the Responses schema).[6][1]

Example with Responses API

In a responses.create call (Node-style pseudocode):

const response = await openai.responses.create({
  model: "gpt-5",
  input: "What is the weather in Paris?",
  tools: [
    {
      type: "function",
      function: {
        name: "get_weather",
        description: "Get current weather by city name",
        parameters: {
          type: "object",
          properties: {
            city: { type: "string" }
          },
          required: ["city"]
        }
      }
    }
  ],
  tool_choice: "required" // or a specific function by name
});
  • With tool_choice: "required", the model will respond with one or more tool_calls instead of just text, picking the appropriate tool from the tools array.[5][1][4]
  • If you instead pass a specific tool reference in tool_choice, the model will always call that tool and not any others for that request.[1][6]

Handling infinite loops / “always tool” behavior

If you force tools every time, your own orchestration code must decide when to stop forcing tools on subsequent turns (e.g., only force on the first turn, then switch tool_choice back to "auto" or "none" once tool outputs are fed back). This avoids the situation where each follow-up call is forced into generating another tool call instead of a final natural-language answer.[3]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions