#Anthropic Reasoning Models don't using Reasoning Unless the Last Message is a User Message

5 messages · Page 1 of 1 (latest)

willow saffron
#

Anthropic reasoning model's work correctly when the last message in the messages list is a user message. However, this is not always the case. When working with agents that make tool calls, the user message will be followed by an assistant + tool(s) messages. When the last message is not a user message, the model doesn't use reasoning: It is like the reasoning_effort parameter gets ignored in this situation.

Anthropic models are arguably the best agentic models out there, and this bug degrades the performance of agentic workflows when using the models through OpenRouter. Hopefully this issue can get resolved quickly.

Sample code to replicate the issue is provided below. When using the OpenAI and Gemini models, the result will contain non empty reasoning and reasoning_details fields. When running the same code with Anthropic, no reasoning occurs. If you comment out the second message in the messages list, then all models, including the ones from Anthropic, will work as expected. I have also tested generations where the last message is a tool message, which occurs in our agentic workflows. I get the exact same issue with Anthropic models..

import requests
def call_openrouter(prompt, model="anthropic/claude-sonnet-4.5"):
url = "https://openrouter.ai/api/v1/chat/completions"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
data = {"model": model, "reasoning_effort": "low",
"messages": [
{"role": "user", "content": prompt},
{"role": "assistant", "content": "Answer: "} #When this is commented out, the model will reason.
]
}
response = requests.post(url, headers=headers, json=data,)
return response.json()
result = call_openrouter("What is the capital of France?")
result

Generation ID with reasoning not used: gen-1759271728-NJH6ykZRLXsf13bRBbLC
Generation ID that worked correctly: gen-1759271739-1dT1TRggPAFLDU05fSA0
@acoustic imp

solar auroraBOT
#

I'm an AI assistant - my answers may be incorrect and I cannot see screenshots. Please verify information with the OpenRouter docs.

You are correct that Anthropic models on OpenRouter require specific message sequencing for reasoning to function as expected in agentic workflows. According to the documentation:

  • "Preserving reasoning blocks is useful specifically for tool calling. When models like Claude invoke tools, it is pausing its construction of a response to await external information. When tool results are returned, the model will continue building that existing response. This necessitates preserving reasoning blocks during tool use, for a couple of reasons:

    • Reasoning continuity: The reasoning blocks capture the model’s step-by-step reasoning that led to tool requests. When you post tool results, including the original reasoning ensures the model can continue its reasoning from where it left off.
    • Context maintenance: While tool results appear as user messages in the API structure, they’re part of a continuous reasoning flow. Preserving reasoning blocks maintains this conceptual flow across multiple API calls."
  • "The reasoning_details functionality works identically across all supported reasoning models. You can easily switch between OpenAI reasoning models (like openai/gpt-5-mini) and Anthropic reasoning models (like anthropic/claude-sonnet-4) without changing your code structure.

  • If you want to pass reasoning back in context, you must pass reasoning blocks back to the API. This is useful for maintaining the model’s reasoning flow and conversation integrity."
    Quoted from Reasoning Tokens Guide

Summary:

  • Anthropic models expect the last ...

The author you are looking for could not be found.

#

...message in the conversation to be a user message to trigger new reasoning.

  • For agentic workflows, you need to preserve and pass back the reasoning block(s) in context when continuing after tool calls.
  • If the last message is not a user, new reasoning may not be generated, matching your observations.

If you are preserving and injecting reasoning as described and still see the issue, this may be a bug or limitation. Please provide these technical details and your generation IDs to OpenRouter support or mods for escalation.

For more detail, see the Reasoning Tokens Guide.

-# This is an automated response powered by Answer HQ. Use !mute to stop the bot from responding.

willow saffron
#

The automated response doesn't answer the question.
I attached a txt file with a full example using tool calling.

I also looked through an example from Anthropic(https://github.com/anthropics/claude-cookbooks/blob/main/tool_use/parallel_tools_claude_3_7_sonnet.ipynb).
It contains this code:
last_tool_call = response.content[1]
MESSAGES.append({"role": "assistant", "content": response.content})
MESSAGES.append(
{

    "role": "user",
    "content": [
        {
            "type": "tool_result",
            "tool_use_id": last_tool_call.id,
            "content": process_tool_with_maybe_batch(response.content[1].name, response.content[1].input),
        }
    ]
}

)
response = make_query_and_print_result(MESSAGES)

From this code, Anthropic labels tool result messages as user role messages. OpenRouter might not be setting this role correctly for tool results, which could cause reasoning to be turned off on Anthropic's side.

willow saffron
#

@acoustic imp Have you taken a look at this issue? We want to use Openrouter for our company's agentic processes, but this is a big blocker for that as it significantly degrades the performance.