- SDK
- Thinking (Reasoning)
SDK
Thinking (Reasoning)
Enable step-by-step reasoning in conversations via the SDK
Pass a thinking object on send_message / sendMessage to let the model reason before responding. Omit it or set null to disable. Pass {} for provider defaults.
thinking is a per-turn parameter — pass it on every call where you want reasoning enabled.
import asyncio
from backboard import BackboardClient
async def main():
client = BackboardClient(api_key="YOUR_API_KEY")
response = await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="openai",
model_name="o3",
thinking={"effort": "high"},
stream=False
)
print(response.reasoning)
print(response.content)
if __name__ == "__main__":
asyncio.run(main())
Fields
| Field | Type | Description |
|---|---|---|
effort | string | Reasoning depth: low, medium, high, or max |
budget_tokens | integer | Max tokens for internal reasoning |
max_tokens | integer | Max tokens for reasoning output |
exclude_reasoning | boolean | Omit reasoning traces from response |
Provider Support
| Provider | Supported Fields | Example |
|---|---|---|
| OpenAI | effort | {"effort": "high"} |
| Anthropic | effort, budget_tokens | {"effort": "high"} |
| AWS Bedrock | effort, budget_tokens | {"effort": "high"} |
| Google (Gemini 2.5) | budget_tokens | {"budget_tokens": 8192} |
| Google (Gemini 3) | effort | {"effort": "high"} |
| xAI | effort | {"effort": "high"} |
| OpenRouter | max_tokens, exclude_reasoning | {"max_tokens": 4096} |
| Cerebras | max_tokens, exclude_reasoning | {"max_tokens": 4096} |
Provider Details
OpenAI: Models: o1, o3, o4, gpt-5 series. Default effort: medium.
Anthropic: Claude Opus 4.7 and newer (including Opus 5 and Fable 5) use adaptive thinking — pass effort (low, medium, high, max); budget_tokens is not accepted for these models. Older models (Claude 3.7 Sonnet, Sonnet 4, Opus 4–4.6) use budget_tokens (min 1,024). Backboard routes to the correct mode automatically.
AWS Bedrock: Bedrock-hosted Anthropic Claude models. Claude Opus 4.7 and newer (including Opus 5 and Fable 5) use adaptive thinking — pass effort; budget_tokens is rejected for these models. Older Bedrock Claude models accept budget_tokens (min 1,024) or effort. Backboard routes to the correct mode automatically.
Google (Gemini 2.5): Max budget: 32,768 (Pro) / 24,576 (others).
Google (Gemini 3): Uses effort (low through max). Thinking is on by default.
xAI: Reasoning models — grok-4.3 and its aliases grok-latest, grok-3*, grok-4*, grok-4-fast-reasoning, grok-4-1-fast-reasoning, grok-3-mini* — accept effort (low, medium, high, max); max maps to xAI’s highest level. Omit thinking to avoid setting a Backboard control (xAI’s own default is low); pass {} for Backboard’s default medium. The *-non-reasoning variants do not support effort.
OpenRouter / Cerebras: Use max_tokens (int > 0) and exclude_reasoning (bool).
Best for complex tasks: math, code generation, multi-step reasoning, analysis.
Thinking uses extra tokens and adds latency. Skip it for simple questions.
Non-Streaming Examples
OpenAI
Python
JavaScript
TypeScript
import asyncio
from backboard import BackboardClient
async def main():
client = BackboardClient(api_key="YOUR_API_KEY")
response = await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="openai",
model_name="o3",
thinking={"effort": "high"},
stream=False
)
print(response.reasoning)
print(response.content)
if __name__ == "__main__":
asyncio.run(main())
Anthropic
Use effort for Claude Opus 4.7+ (adaptive thinking). Use budget_tokens for older models.
Python
JavaScript
TypeScript
# Claude Opus 4.7+ — use effort
response = await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="anthropic",
model_name="claude-opus-4-7-20250501",
thinking={"effort": "high"},
stream=False
)
print(response.reasoning)
print(response.content)
AWS Bedrock
Use effort for Claude Opus 4.7+ on Bedrock. Use budget_tokens for older Bedrock Claude models.
Python
JavaScript
TypeScript
response = await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="aws-bedrock",
model_name="anthropic.claude-opus-4-7",
thinking={"effort": "high"},
stream=False
)
print(response.reasoning)
print(response.content)
Google (Gemini 2.5)
Python
JavaScript
TypeScript
response = await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="google",
model_name="gemini-2.5-pro",
thinking={"budget_tokens": 8192},
stream=False
)
print(response.reasoning)
print(response.content)
Google (Gemini 3)
Python
JavaScript
TypeScript
response = await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="google",
model_name="gemini-3.1-pro-preview",
thinking={"effort": "high"},
stream=False
)
print(response.reasoning)
print(response.content)
xAI
Python
JavaScript
TypeScript
response = await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="xai",
model_name="grok-4.3",
thinking={"effort": "high"},
stream=False
)
print(response.reasoning)
print(response.content)
OpenRouter
Python
JavaScript
TypeScript
response = await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="openrouter",
model_name="minimax/minimax-m1",
thinking={"max_tokens": 4096},
stream=False
)
print(response.reasoning)
print(response.content)
Cerebras
Python
JavaScript
TypeScript
response = await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="cerebras",
model_name="z-ai/glm-4.7",
thinking={},
stream=False
)
print(response.reasoning)
print(response.content)
Streaming Examples
Same as above but with stream=True. The model thinks first, then streams the response.
OpenAI
Python
JavaScript
TypeScript
async for chunk in await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="openai",
model_name="o3",
thinking={"effort": "high"},
stream=True
):
t = chunk.get("type")
if t == "reasoning_streaming":
print(chunk.get("content", ""), end="", flush=True)
elif t == "reasoning_ended":
print("\n---------Reasoning Ended, Response Started---------")
elif t == "content_streaming":
print(chunk.get("content", ""), end="", flush=True)
Anthropic
Python
JavaScript
TypeScript
async for chunk in await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="anthropic",
model_name="claude-opus-4-7-20250501",
thinking={"effort": "high"},
stream=True
):
t = chunk.get("type")
if t == "reasoning_streaming":
print(chunk.get("content", ""), end="", flush=True)
elif t == "reasoning_ended":
print("\n---------Reasoning Ended, Response Started---------")
elif t == "content_streaming":
print(chunk.get("content", ""), end="", flush=True)
AWS Bedrock
Python
JavaScript
TypeScript
async for chunk in await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="aws-bedrock",
model_name="anthropic.claude-opus-4-7",
thinking={"effort": "high"},
stream=True
):
t = chunk.get("type")
if t == "reasoning_streaming":
print(chunk.get("content", ""), end="", flush=True)
elif t == "reasoning_ended":
print("\n---------Reasoning Ended, Response Started---------")
elif t == "content_streaming":
print(chunk.get("content", ""), end="", flush=True)
Google (Gemini 2.5)
Python
JavaScript
TypeScript
async for chunk in await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="google",
model_name="gemini-2.5-pro",
thinking={"budget_tokens": 8192},
stream=True
):
t = chunk.get("type")
if t == "reasoning_streaming":
print(chunk.get("content", ""), end="", flush=True)
elif t == "reasoning_ended":
print("\n---------Reasoning Ended, Response Started---------")
elif t == "content_streaming":
print(chunk.get("content", ""), end="", flush=True)
Google (Gemini 3)
Python
JavaScript
TypeScript
async for chunk in await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="google",
model_name="gemini-3.1-pro-preview",
thinking={"effort": "high"},
stream=True
):
t = chunk.get("type")
if t == "reasoning_streaming":
print(chunk.get("content", ""), end="", flush=True)
elif t == "reasoning_ended":
print("\n---------Reasoning Ended, Response Started---------")
elif t == "content_streaming":
print(chunk.get("content", ""), end="", flush=True)
xAI
Python
JavaScript
TypeScript
async for chunk in await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="xai",
model_name="grok-4.3",
thinking={"effort": "high"},
stream=True
):
t = chunk.get("type")
if t == "reasoning_streaming":
print(chunk.get("content", ""), end="", flush=True)
elif t == "reasoning_ended":
print("\n---------Reasoning Ended, Response Started---------")
elif t == "content_streaming":
print(chunk.get("content", ""), end="", flush=True)
OpenRouter
Python
JavaScript
TypeScript
async for chunk in await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="openrouter",
model_name="minimax/minimax-m1",
thinking={"max_tokens": 4096},
stream=True
):
t = chunk.get("type")
if t == "reasoning_streaming":
print(chunk.get("content", ""), end="", flush=True)
elif t == "reasoning_ended":
print("\n---------Reasoning Ended, Response Started---------")
elif t == "content_streaming":
print(chunk.get("content", ""), end="", flush=True)
Cerebras
Python
JavaScript
TypeScript
async for chunk in await client.send_message(
"A driver was going the wrong way down a one-way street. He passed several police officers, but they did not stop him. Why? Think step by step.",
llm_provider="cerebras",
model_name="z-ai/glm-4.7",
thinking={},
stream=True
):
t = chunk.get("type")
if t == "reasoning_streaming":
print(chunk.get("content", ""), end="", flush=True)
elif t == "reasoning_ended":
print("\n---------Reasoning Ended, Response Started---------")
elif t == "content_streaming":
print(chunk.get("content", ""), end="", flush=True)
Check Model Support
models = await client.list_models(supports_thinking=True, model_type="llm")
for m in models:
print(f"{m.provider}/{m.name}")
See Models for details.