supporting thinking for anthropic models (#3978)

* supporting thinking for anthropic models

* drop comments here

* thinking and tool calling support

* fix: properly mock tool use and text block types in Anthropic tests

- Updated the test for the Anthropic tool use conversation flow to include type attributes for mocked ToolUseBlock and text blocks, ensuring accurate simulation of tool interactions during testing.

* feat: add AnthropicThinkingConfig for enhanced thinking capabilities

This update introduces the AnthropicThinkingConfig class to manage thinking parameters for the Anthropic completion model. The LLM and AnthropicCompletion classes have been updated to utilize this new configuration. Additionally, new test cassettes have been added to validate the functionality of thinking blocks across interactions.
This commit is contained in:
Lorenze Jay
2025-12-08 15:34:54 -08:00
committed by GitHub
parent f2f994612c
commit 6125b866fd
11 changed files with 1605 additions and 73 deletions

View File

@@ -283,11 +283,54 @@ In this section, you'll find detailed examples that help you select, configure,
)
```
**Extended Thinking (Claude Sonnet 4 and Beyond):**
CrewAI supports Anthropic's Extended Thinking feature, which allows Claude to think through problems in a more human-like way before responding. This is particularly useful for complex reasoning, analysis, and problem-solving tasks.
```python Code
from crewai import LLM
# Enable extended thinking with default settings
llm = LLM(
model="anthropic/claude-sonnet-4",
thinking={"type": "enabled"},
max_tokens=10000
)
# Configure thinking with budget control
llm = LLM(
model="anthropic/claude-sonnet-4",
thinking={
"type": "enabled",
"budget_tokens": 5000 # Limit thinking tokens
},
max_tokens=10000
)
```
**Thinking Configuration Options:**
- `type`: Set to `"enabled"` to activate extended thinking mode
- `budget_tokens` (optional): Maximum tokens to use for thinking (helps control costs)
**Models Supporting Extended Thinking:**
- `claude-sonnet-4` and newer models
- `claude-3-7-sonnet` (with extended thinking capabilities)
**When to Use Extended Thinking:**
- Complex reasoning and multi-step problem solving
- Mathematical calculations and proofs
- Code analysis and debugging
- Strategic planning and decision making
- Research and analytical tasks
**Note:** Extended thinking consumes additional tokens but can significantly improve response quality for complex tasks.
**Supported Environment Variables:**
- `ANTHROPIC_API_KEY`: Your Anthropic API key (required)
**Features:**
- Native tool use support for Claude 3+ models
- Extended Thinking support for Claude Sonnet 4+
- Streaming support for real-time responses
- Automatic system message handling
- Stop sequences for controlled output
@@ -305,6 +348,7 @@ In this section, you'll find detailed examples that help you select, configure,
| Model | Context Window | Best For |
|------------------------------|----------------|-----------------------------------------------|
| claude-sonnet-4 | 200,000 tokens | Latest with extended thinking capabilities |
| claude-3-7-sonnet | 200,000 tokens | Advanced reasoning and agentic tasks |
| claude-3-5-sonnet-20241022 | 200,000 tokens | Latest Sonnet with best performance |
| claude-3-5-haiku | 200,000 tokens | Fast, compact model for quick responses |

View File

@@ -67,6 +67,7 @@ if TYPE_CHECKING:
from crewai.agent.core import Agent
from crewai.llms.hooks.base import BaseInterceptor
from crewai.llms.providers.anthropic.completion import AnthropicThinkingConfig
from crewai.task import Task
from crewai.tools.base_tool import BaseTool
from crewai.utilities.types import LLMMessage
@@ -585,6 +586,7 @@ class LLM(BaseLLM):
reasoning_effort: Literal["none", "low", "medium", "high"] | None = None,
stream: bool = False,
interceptor: BaseInterceptor[httpx.Request, httpx.Response] | None = None,
thinking: AnthropicThinkingConfig | dict[str, Any] | None = None,
**kwargs: Any,
) -> None:
"""Initialize LLM instance.

View File

@@ -3,8 +3,9 @@ from __future__ import annotations
import json
import logging
import os
from typing import TYPE_CHECKING, Any, cast
from typing import TYPE_CHECKING, Any, Literal, cast
from anthropic.types import ThinkingBlock
from pydantic import BaseModel
from crewai.events.types.llm_events import LLMCallType
@@ -22,8 +23,7 @@ if TYPE_CHECKING:
try:
from anthropic import Anthropic, AsyncAnthropic
from anthropic.types import Message
from anthropic.types.tool_use_block import ToolUseBlock
from anthropic.types import Message, TextBlock, ThinkingBlock, ToolUseBlock
import httpx
except ImportError:
raise ImportError(
@@ -31,6 +31,11 @@ except ImportError:
) from None
class AnthropicThinkingConfig(BaseModel):
type: Literal["enabled", "disabled"]
budget_tokens: int | None = None
class AnthropicCompletion(BaseLLM):
"""Anthropic native completion implementation.
@@ -52,6 +57,7 @@ class AnthropicCompletion(BaseLLM):
stream: bool = False,
client_params: dict[str, Any] | None = None,
interceptor: BaseInterceptor[httpx.Request, httpx.Response] | None = None,
thinking: AnthropicThinkingConfig | None = None,
**kwargs: Any,
):
"""Initialize Anthropic chat completion client.
@@ -97,6 +103,10 @@ class AnthropicCompletion(BaseLLM):
self.top_p = top_p
self.stream = stream
self.stop_sequences = stop_sequences or []
self.thinking = thinking
self.previous_thinking_blocks: list[ThinkingBlock] = []
# Model-specific settings
self.is_claude_3 = "claude-3" in model.lower()
self.supports_tools = True
@property
@@ -326,6 +336,12 @@ class AnthropicCompletion(BaseLLM):
if tools and self.supports_tools:
params["tools"] = self._convert_tools_for_interference(tools)
if self.thinking:
if isinstance(self.thinking, AnthropicThinkingConfig):
params["thinking"] = self.thinking.model_dump()
else:
params["thinking"] = self.thinking
return params
def _convert_tools_for_interference(
@@ -365,6 +381,34 @@ class AnthropicCompletion(BaseLLM):
return anthropic_tools
def _extract_thinking_block(
self, content_block: Any
) -> ThinkingBlock | dict[str, Any] | None:
"""Extract and format thinking block from content block.
Args:
content_block: Content block from Anthropic response
Returns:
Dictionary with thinking block data including signature, or None if not a thinking block
"""
if content_block.type == "thinking":
thinking_block = {
"type": "thinking",
"thinking": content_block.thinking,
}
if hasattr(content_block, "signature"):
thinking_block["signature"] = content_block.signature
return thinking_block
if content_block.type == "redacted_thinking":
redacted_block = {"type": "redacted_thinking"}
if hasattr(content_block, "thinking"):
redacted_block["thinking"] = content_block.thinking
if hasattr(content_block, "signature"):
redacted_block["signature"] = content_block.signature
return redacted_block
return None
def _format_messages_for_anthropic(
self, messages: str | list[LLMMessage]
) -> tuple[list[LLMMessage], str | None]:
@@ -374,6 +418,7 @@ class AnthropicCompletion(BaseLLM):
- System messages are separate from conversation messages
- Messages must alternate between user and assistant
- First message must be from user
- When thinking is enabled, assistant messages must start with thinking blocks
Args:
messages: Input messages
@@ -398,8 +443,29 @@ class AnthropicCompletion(BaseLLM):
system_message = cast(str, content)
else:
role_str = role if role is not None else "user"
content_str = content if content is not None else ""
formatted_messages.append({"role": role_str, "content": content_str})
if isinstance(content, list):
formatted_messages.append({"role": role_str, "content": content})
elif (
role_str == "assistant"
and self.thinking
and self.previous_thinking_blocks
):
structured_content = cast(
list[dict[str, Any]],
[
*self.previous_thinking_blocks,
{"type": "text", "text": content if content else ""},
],
)
formatted_messages.append(
LLMMessage(role=role_str, content=structured_content)
)
else:
content_str = content if content is not None else ""
formatted_messages.append(
LLMMessage(role=role_str, content=content_str)
)
# Ensure first message is from user (Anthropic requirement)
if not formatted_messages:
@@ -449,7 +515,6 @@ class AnthropicCompletion(BaseLLM):
if tool_uses and tool_uses[0].name == "structured_output":
structured_data = tool_uses[0].input
structured_json = json.dumps(structured_data)
self._emit_call_completed_event(
response=structured_json,
call_type=LLMCallType.LLM_CALL,
@@ -477,15 +542,22 @@ class AnthropicCompletion(BaseLLM):
from_agent,
)
# Extract text content
content = ""
thinking_blocks: list[ThinkingBlock] = []
if response.content:
for content_block in response.content:
if hasattr(content_block, "text"):
content += content_block.text
else:
thinking_block = self._extract_thinking_block(content_block)
if thinking_block:
thinking_blocks.append(cast(ThinkingBlock, thinking_block))
if thinking_blocks:
self.previous_thinking_blocks = thinking_blocks
content = self._apply_stop_words(content)
self._emit_call_completed_event(
response=content,
call_type=LLMCallType.LLM_CALL,
@@ -540,6 +612,16 @@ class AnthropicCompletion(BaseLLM):
final_message: Message = stream.get_final_message()
thinking_blocks: list[ThinkingBlock] = []
if final_message.content:
for content_block in final_message.content:
thinking_block = self._extract_thinking_block(content_block)
if thinking_block:
thinking_blocks.append(cast(ThinkingBlock, thinking_block))
if thinking_blocks:
self.previous_thinking_blocks = thinking_blocks
usage = self._extract_anthropic_token_usage(final_message)
self._track_token_usage_internal(usage)
@@ -644,7 +726,26 @@ class AnthropicCompletion(BaseLLM):
follow_up_params = params.copy()
# Add Claude's tool use response to conversation
assistant_message = {"role": "assistant", "content": initial_response.content}
assistant_content: list[
ThinkingBlock | ToolUseBlock | TextBlock | dict[str, Any]
] = []
for block in initial_response.content:
thinking_block = self._extract_thinking_block(block)
if thinking_block:
assistant_content.append(thinking_block)
elif block.type == "tool_use":
assistant_content.append(
{
"type": "tool_use",
"id": block.id,
"name": block.name,
"input": block.input,
}
)
elif hasattr(block, "text"):
assistant_content.append({"type": "text", "text": block.text})
assistant_message = {"role": "assistant", "content": assistant_content}
# Add user message with tool results
user_message = {"role": "user", "content": tool_results}
@@ -663,12 +764,20 @@ class AnthropicCompletion(BaseLLM):
follow_up_usage = self._extract_anthropic_token_usage(final_response)
self._track_token_usage_internal(follow_up_usage)
# Extract final text content
final_content = ""
thinking_blocks: list[ThinkingBlock] = []
if final_response.content:
for content_block in final_response.content:
if hasattr(content_block, "text"):
final_content += content_block.text
else:
thinking_block = self._extract_thinking_block(content_block)
if thinking_block:
thinking_blocks.append(cast(ThinkingBlock, thinking_block))
if thinking_blocks:
self.previous_thinking_blocks = thinking_blocks
final_content = self._apply_stop_words(final_content)

View File

@@ -0,0 +1,220 @@
interactions:
- request:
body: '{"max_tokens":4096,"messages":[{"role":"user","content":"What is the weather
in Tokyo? Use the get_weather tool."}],"model":"claude-sonnet-4-5","stream":false,"tools":[{"name":"get_weather","description":"Get
the current weather in a given location","input_schema":{"type":"object","properties":{"location":{"type":"string","description":"The
city and state, e.g. San Francisco, CA"},"unit":{"type":"string","enum":["celsius","fahrenheit"],"description":"The
unit of temperature"}},"required":["location"]}}]}'
headers:
accept:
- application/json
accept-encoding:
- ACCEPT-ENCODING-XXX
anthropic-version:
- '2023-06-01'
connection:
- keep-alive
content-length:
- '509'
content-type:
- application/json
host:
- api.anthropic.com
user-agent:
- X-USER-AGENT-XXX
x-stainless-arch:
- X-STAINLESS-ARCH-XXX
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- X-STAINLESS-OS-XXX
x-stainless-package-version:
- 0.71.1
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.13.3
x-stainless-timeout:
- NOT_GIVEN
method: POST
uri: https://api.anthropic.com/v1/messages
response:
body:
string: !!binary |
H4sIAAAAAAAAAwAAAP//dJBBS8NAEIX/isx5A0k0he5NhR60FRG9KLKsmzGJ3eyku7O1JeS/SyLV
qnic9703j5keWirRggRjdSwxCeQccnKWFEme5kU6z+cgoClBQhsqlWYXp6+rl+a8NrvIzfbuMqti
tnkEAbzvcHRhCLpCEODJjoIOoQmsHYMAQ47RMcin/uBnIqtiwEPLOEeVZuf0sFjla7pZhkUw17Pd
m1veEghwuh1zFbJ6R801+jHqusgge7BkNDfkQMI9rfckTq50px0Mw7OAwNQpjzpM/Kh5AgE3EZ1B
kC5aKyBOd8j+c7liWqMLIGd5KsBoU6MyHqcy9dPxxT3q8j92yI4F2NXYotdWFe1f/zfN6t90EECR
j6WiEBDQbxuDihv0IGH8fql9CcPwAQAA//8DAI8uRSjwAQAA
headers:
CF-RAY:
- CF-RAY-XXX
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Mon, 08 Dec 2025 23:16:56 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
X-Robots-Tag:
- none
anthropic-organization-id:
- ANTHROPIC-ORGANIZATION-ID-XXX
anthropic-ratelimit-input-tokens-limit:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-input-tokens-remaining:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-input-tokens-reset:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-RESET-XXX
anthropic-ratelimit-output-tokens-limit:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-output-tokens-remaining:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-output-tokens-reset:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-RESET-XXX
anthropic-ratelimit-requests-limit:
- '50'
anthropic-ratelimit-requests-remaining:
- '49'
anthropic-ratelimit-requests-reset:
- '2025-12-08T23:16:54Z'
anthropic-ratelimit-tokens-limit:
- ANTHROPIC-RATELIMIT-TOKENS-LIMIT-XXX
anthropic-ratelimit-tokens-remaining:
- ANTHROPIC-RATELIMIT-TOKENS-REMAINING-XXX
anthropic-ratelimit-tokens-reset:
- ANTHROPIC-RATELIMIT-TOKENS-RESET-XXX
cf-cache-status:
- DYNAMIC
request-id:
- REQUEST-ID-XXX
retry-after:
- '5'
strict-transport-security:
- STS-XXX
x-envoy-upstream-service-time:
- '2925'
status:
code: 200
message: OK
- request:
body: "{\"max_tokens\":4096,\"messages\":[{\"role\":\"user\",\"content\":\"What
is the weather in Tokyo? Use the get_weather tool.\"},{\"role\":\"assistant\",\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_01AoUFM2koNLsFscK6xjnLPo\",\"name\":\"get_weather\",\"input\":{\"location\":\"Tokyo,
Japan\"}}]},{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"toolu_01AoUFM2koNLsFscK6xjnLPo\",\"content\":\"The
weather in Tokyo, Japan is sunny and 72\xB0F\"}]}],\"model\":\"claude-sonnet-4-5\",\"stream\":false,\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get
the current weather in a given location\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"location\":{\"type\":\"string\",\"description\":\"The
city and state, e.g. San Francisco, CA\"},\"unit\":{\"type\":\"string\",\"enum\":[\"celsius\",\"fahrenheit\"],\"description\":\"The
unit of temperature\"}},\"required\":[\"location\"]}}]}"
headers:
accept:
- application/json
accept-encoding:
- ACCEPT-ENCODING-XXX
anthropic-version:
- '2023-06-01'
connection:
- keep-alive
content-length:
- '814'
content-type:
- application/json
host:
- api.anthropic.com
user-agent:
- X-USER-AGENT-XXX
x-stainless-arch:
- X-STAINLESS-ARCH-XXX
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- X-STAINLESS-OS-XXX
x-stainless-package-version:
- 0.71.1
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.13.3
x-stainless-timeout:
- NOT_GIVEN
method: POST
uri: https://api.anthropic.com/v1/messages
response:
body:
string: !!binary |
H4sIAAAAAAAAA3SQ3UoDMRBGXyXMlcKubGOrNreiiHdC70RCTIZu2t3Jmky0a9l36jP0yWSLxT+8
GvjOGWb4ttAGhw0osI3JDssUiJDLaTkrZSVn1VzOoQDvQEGblrqaTN9bvlmt7qYPmytif++e1+cX
CAVw3+FoYUpmOQYxNGNgUvKJDTEUYAMxEoN63B59xs1IDkPBokbxhoZrjMKTWIR1H4RPwuYYkbjp
RcpEvTDkxKXc727Fiem6GDa+NYxNL6Tc765Pz2B4KiBx6HREkwKBAiSnOUeCT5DwJSNZBEW5aQrI
h7fVFjx1mTWHNVICdVlNCrDG1qhtRMM+kP5pVEce0bj/2HF3PIBdjS1G0+hZ+9f/opP6Nx0KCJm/
R1IWkDC+eouaPUZQMJbtTHQwDB8AAAD//wMAkp8os98BAAA=
headers:
CF-RAY:
- CF-RAY-XXX
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Mon, 08 Dec 2025 23:16:59 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
X-Robots-Tag:
- none
anthropic-organization-id:
- ANTHROPIC-ORGANIZATION-ID-XXX
anthropic-ratelimit-input-tokens-limit:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-input-tokens-remaining:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-input-tokens-reset:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-RESET-XXX
anthropic-ratelimit-output-tokens-limit:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-output-tokens-remaining:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-output-tokens-reset:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-RESET-XXX
anthropic-ratelimit-requests-limit:
- '50'
anthropic-ratelimit-requests-remaining:
- '49'
anthropic-ratelimit-requests-reset:
- '2025-12-08T23:16:58Z'
anthropic-ratelimit-tokens-limit:
- ANTHROPIC-RATELIMIT-TOKENS-LIMIT-XXX
anthropic-ratelimit-tokens-remaining:
- ANTHROPIC-RATELIMIT-TOKENS-REMAINING-XXX
anthropic-ratelimit-tokens-reset:
- ANTHROPIC-RATELIMIT-TOKENS-RESET-XXX
cf-cache-status:
- DYNAMIC
request-id:
- REQUEST-ID-XXX
retry-after:
- '1'
strict-transport-security:
- STS-XXX
x-envoy-upstream-service-time:
- '2878'
status:
code: 200
message: OK
version: 1

View File

@@ -8,8 +8,6 @@ interactions:
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate, zstd
Connection:
- keep-alive
Content-Length:
@@ -17,9 +15,11 @@ interactions:
Content-Type:
- application/json
User-Agent:
- CrewAI-CLI/1.3.0
- X-USER-AGENT-XXX
X-Crewai-Version:
- 1.3.0
accept-encoding:
- ACCEPT-ENCODING-XXX
method: POST
uri: https://app.crewai.com/crewai_plus/api/v1/tracing/batches
response:
@@ -37,61 +37,31 @@ interactions:
cache-control:
- no-store
content-security-policy:
- 'default-src ''self'' *.app.crewai.com app.crewai.com; script-src ''self''
''unsafe-inline'' *.app.crewai.com app.crewai.com https://cdn.jsdelivr.net/npm/apexcharts
https://www.gstatic.com https://run.pstmn.io https://apis.google.com https://apis.google.com/js/api.js
https://accounts.google.com https://accounts.google.com/gsi/client https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css.map
https://*.google.com https://docs.google.com https://slides.google.com https://js.hs-scripts.com
https://js.sentry-cdn.com https://browser.sentry-cdn.com https://www.googletagmanager.com
https://js-na1.hs-scripts.com https://js.hubspot.com http://js-na1.hs-scripts.com
https://bat.bing.com https://cdn.amplitude.com https://cdn.segment.com https://d1d3n03t5zntha.cloudfront.net/
https://descriptusercontent.com https://edge.fullstory.com https://googleads.g.doubleclick.net
https://js.hs-analytics.net https://js.hs-banner.com https://js.hsadspixel.net
https://js.hscollectedforms.net https://js.usemessages.com https://snap.licdn.com
https://static.cloudflareinsights.com https://static.reo.dev https://www.google-analytics.com
https://share.descript.com/; style-src ''self'' ''unsafe-inline'' *.app.crewai.com
app.crewai.com https://cdn.jsdelivr.net/npm/apexcharts; img-src ''self'' data:
*.app.crewai.com app.crewai.com https://zeus.tools.crewai.com https://dashboard.tools.crewai.com
https://cdn.jsdelivr.net https://forms.hsforms.com https://track.hubspot.com
https://px.ads.linkedin.com https://px4.ads.linkedin.com https://www.google.com
https://www.google.com.br; font-src ''self'' data: *.app.crewai.com app.crewai.com;
connect-src ''self'' *.app.crewai.com app.crewai.com https://zeus.tools.crewai.com
https://connect.useparagon.com/ https://zeus.useparagon.com/* https://*.useparagon.com/*
https://run.pstmn.io https://connect.tools.crewai.com/ https://*.sentry.io
https://www.google-analytics.com https://edge.fullstory.com https://rs.fullstory.com
https://api.hubspot.com https://forms.hscollectedforms.net https://api.hubapi.com
https://px.ads.linkedin.com https://px4.ads.linkedin.com https://google.com/pagead/form-data/16713662509
https://google.com/ccm/form-data/16713662509 https://www.google.com/ccm/collect
https://worker-actionkit.tools.crewai.com https://api.reo.dev; frame-src ''self''
*.app.crewai.com app.crewai.com https://connect.useparagon.com/ https://zeus.tools.crewai.com
https://zeus.useparagon.com/* https://connect.tools.crewai.com/ https://docs.google.com
https://drive.google.com https://slides.google.com https://accounts.google.com
https://*.google.com https://app.hubspot.com/ https://td.doubleclick.net https://www.googletagmanager.com/
https://www.youtube.com https://share.descript.com'
- CSP-FILTERED
expires:
- '0'
permissions-policy:
- camera=(), microphone=(self), geolocation=()
- PERMISSIONS-POLICY-XXX
pragma:
- no-cache
referrer-policy:
- strict-origin-when-cross-origin
- REFERRER-POLICY-XXX
strict-transport-security:
- max-age=63072000; includeSubDomains
- STS-XXX
vary:
- Accept
x-content-type-options:
- nosniff
- X-CONTENT-TYPE-XXX
x-frame-options:
- SAMEORIGIN
- X-FRAME-OPTIONS-XXX
x-permitted-cross-domain-policies:
- none
- X-PERMITTED-XXX
x-request-id:
- 4124c4ce-02cf-4d08-9b0b-8983c2e9da6e
- X-REQUEST-ID-XXX
x-runtime:
- '0.073764'
- X-RUNTIME-XXX
x-xss-protection:
- 1; mode=block
- X-XSS-PROTECTION-XXX
status:
code: 401
message: Unauthorized
@@ -99,10 +69,12 @@ interactions:
body: '{"max_tokens":4096,"messages":[{"role":"user","content":"Say hello in one
word"}],"model":"claude-3-5-haiku-20241022","stop_sequences":["\nObservation:","\nThought:"],"stream":false}'
headers:
User-Agent:
- X-USER-AGENT-XXX
accept:
- application/json
accept-encoding:
- gzip, deflate, zstd
- ACCEPT-ENCODING-XXX
anthropic-version:
- '2023-06-01'
connection:
@@ -113,16 +85,14 @@ interactions:
- application/json
host:
- api.anthropic.com
user-agent:
- Anthropic/Python 0.71.0
x-stainless-arch:
- arm64
- X-STAINLESS-ARCH-XXX
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- MacOS
- X-STAINLESS-OS-XXX
x-stainless-package-version:
- 0.71.0
x-stainless-retry-count:
@@ -145,7 +115,7 @@ interactions:
0ab7TSeBWPh7tBbIlF6dIcWOEiTmoqxOFtP0AQAA//8DAM5WvkqaAQAA
headers:
CF-RAY:
- 99a939a5a931556e-EWR
- CF-RAY-XXX
Connection:
- keep-alive
Content-Encoding:
@@ -161,19 +131,19 @@ interactions:
X-Robots-Tag:
- none
anthropic-organization-id:
- SCRUBBED-ORG-ID
- ANTHROPIC-ORGANIZATION-ID-XXX
anthropic-ratelimit-input-tokens-limit:
- '400000'
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-input-tokens-remaining:
- '400000'
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-input-tokens-reset:
- '2025-11-07T01:58:22Z'
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-RESET-XXX
anthropic-ratelimit-output-tokens-limit:
- '80000'
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-output-tokens-remaining:
- '80000'
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-output-tokens-reset:
- '2025-11-07T01:58:22Z'
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-RESET-XXX
anthropic-ratelimit-requests-limit:
- '4000'
anthropic-ratelimit-requests-remaining:
@@ -181,22 +151,128 @@ interactions:
anthropic-ratelimit-requests-reset:
- '2025-11-07T01:58:22Z'
anthropic-ratelimit-tokens-limit:
- '480000'
- ANTHROPIC-RATELIMIT-TOKENS-LIMIT-XXX
anthropic-ratelimit-tokens-remaining:
- '480000'
- ANTHROPIC-RATELIMIT-TOKENS-REMAINING-XXX
anthropic-ratelimit-tokens-reset:
- '2025-11-07T01:58:22Z'
- ANTHROPIC-RATELIMIT-TOKENS-RESET-XXX
cf-cache-status:
- DYNAMIC
request-id:
- req_011CUshbL7CEVoner91hUvxL
- REQUEST-ID-XXX
retry-after:
- '41'
strict-transport-security:
- max-age=31536000; includeSubDomains; preload
- STS-XXX
x-envoy-upstream-service-time:
- '390'
status:
code: 200
message: OK
- request:
body: '{"max_tokens":4096,"messages":[{"role":"user","content":"Say hello in one
word"}],"model":"claude-3-5-haiku-20241022","stop_sequences":["\nObservation:","\nThought:"],"stream":false}'
headers:
User-Agent:
- X-USER-AGENT-XXX
accept:
- application/json
accept-encoding:
- ACCEPT-ENCODING-XXX
anthropic-version:
- '2023-06-01'
connection:
- keep-alive
content-length:
- '182'
content-type:
- application/json
host:
- api.anthropic.com
x-api-key:
- X-API-KEY-XXX
x-stainless-arch:
- X-STAINLESS-ARCH-XXX
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- X-STAINLESS-OS-XXX
x-stainless-package-version:
- 0.71.1
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.13.3
x-stainless-timeout:
- NOT_GIVEN
method: POST
uri: https://api.anthropic.com/v1/messages
response:
body:
string: !!binary |
H4sIAAAAAAAAA3SQ3UrEMBCFn8VznUJb7SJ5gr2UvRCsSAjJ7Da2TbrJRFxK3126WPzDq4HzfTMD
Z8YYLA2QMIPOlorboik67fpc1GV9V5V1DQFnITGmkyqr+9Qe7e78+HRpjw87v3ev7aHqIcCXiVaL
UtIngkAMwxrolFxi7RkCJngmz5DP8+Yzva/kOiT27gbLi0DiMKlIOgUPCfJWcY4enyDROZM3BOnz
MAjk60c5w/kps+LQk0+QVS1gtOlImUiaXfDqp1BuPJK2/7Ftd71PU0cjRT2oZvzrf9Gq+00XgZD5
e9QIJIpvzpBiRxESa0tWR4tl+QAAAP//AwD8cXPFlwEAAA==
headers:
CF-RAY:
- CF-RAY-XXX
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Mon, 08 Dec 2025 23:16:53 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
X-Robots-Tag:
- none
anthropic-organization-id:
- ANTHROPIC-ORGANIZATION-ID-XXX
anthropic-ratelimit-input-tokens-limit:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-input-tokens-remaining:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-input-tokens-reset:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-RESET-XXX
anthropic-ratelimit-output-tokens-limit:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-output-tokens-remaining:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-output-tokens-reset:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-RESET-XXX
anthropic-ratelimit-requests-limit:
- '50'
anthropic-ratelimit-requests-remaining:
- '49'
anthropic-ratelimit-requests-reset:
- '2025-12-08T23:16:53Z'
anthropic-ratelimit-tokens-limit:
- ANTHROPIC-RATELIMIT-TOKENS-LIMIT-XXX
anthropic-ratelimit-tokens-remaining:
- ANTHROPIC-RATELIMIT-TOKENS-REMAINING-XXX
anthropic-ratelimit-tokens-reset:
- ANTHROPIC-RATELIMIT-TOKENS-RESET-XXX
cf-cache-status:
- DYNAMIC
request-id:
- REQUEST-ID-XXX
retry-after:
- '8'
strict-transport-security:
- STS-XXX
x-envoy-upstream-service-time:
- '787'
status:
code: 200
message: OK
version: 1

View File

@@ -0,0 +1,126 @@
interactions:
- request:
body: '{"max_tokens":10000,"messages":[{"role":"user","content":"What is the weather
in Tokyo?"}],"model":"claude-sonnet-4-5","stream":false,"thinking":{"type":"enabled","budget_tokens":5000}}'
headers:
accept:
- application/json
accept-encoding:
- ACCEPT-ENCODING-XXX
anthropic-version:
- '2023-06-01'
connection:
- keep-alive
content-length:
- '185'
content-type:
- application/json
host:
- api.anthropic.com
user-agent:
- X-USER-AGENT-XXX
x-stainless-arch:
- X-STAINLESS-ARCH-XXX
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- X-STAINLESS-OS-XXX
x-stainless-package-version:
- 0.71.1
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.13.3
x-stainless-timeout:
- NOT_GIVEN
method: POST
uri: https://api.anthropic.com/v1/messages
response:
body:
string: !!binary |
H4sIAAAAAAAAAwAAAP//hFVrj+o4Ev0rVr7s7O00JAGahzRa0bxC84YGGrZXLeMUiYljB9tJCFf9
31fhNnNnZmd3PyWqOnXqJZ/6bkTCA2a0DMJw4sGjEpyDfqw+1h4dy6lZTadpmAb1jJYRKf/Dsgfg
Vdv9ST1+al/t3kvWSeIXf2qYhs5jKFCgFPbBMA0pWGHASlGlMdeGaRDBNXBttP75/Y7XAeUh5X7B
cP9tGa8BoESBRFQhrAojwgeRaKQDQCSRErhGGWAdFBiOXkWYixJyRQYpSBMNkSf43zQKcAoIEwJK
IS2QBMweNY0AUX4UMsKaCm4iyglLvCLJn6k9rHEJTXIUcpEx8HxAGVaIYaVREntYg1ekb8eSMuRY
TtVEmHtoiAjmXGh0kCJTcKuacg2Sg0ZC3itiNIXfUimQKSWgSu/8nQ+RCkTCPMTgR8+3YRRFIB1g
/TNBLEVKvb+ayW/93SpSie+D0ii4MUCOyI3+SLmHdEDVHwJ0AJECloIqGaahqM+xTmSxrZ5s9zrh
btgJ/M4obC8ZsU8T3o93TetY8/pVt3fci+XbzOVVq532q7bUM5aH9u706kAY1li2GuW1jnjDy3CK
K/tDm4t0Mn1acPs68OIHPK5cen4+rV+kNbPPIc9pb9cUuDs9QJj3Hfck/dpuPit3htmRLy13OdqP
uwoLCINtvb0YP7+yZXm1cYUgzqT66k4vR/fkjLuV5/LTotv3H5y8F6mK9ZIHo5h0iTv39+csFbLh
KuY4ad1K7PVll6rRbtWojuPJaMP5sgJil8p501KOb9sg8kN3zsrTNVUTubuU49W41h7U6udhuuzt
JmR+rcrKJhpEvaeH/np2PU8228VyF70t7CteXb1pLGu9cfttvhjMppVKN58fZjpq5OdrZp+sN+vc
S7flfjbw1dSqNoP9au/t1Xw8TC+Lq+1tGxWyGdU5cdsv17W7SSOezfx9vm12t1XyvI8lX0+qtex6
mSWxPM5ZNdo48m3aPETNbcweqoNyeA12+DDrdSZzq45P9ejhnK7eukPhAJvMJ+58dGls6KWfDUG/
dJyUOits6/6s6VcuwyEf6u3zYr3PdTaLyy6ez8rts3jbdkV7WXE3Z3/uhlfRC+gwTrJsu5tdgvoq
0Lt1J6Zrfap0r76V9222kN6ETp96h9eVHciTnZEsV/vJ0KLrRKqkPH1ggZOchnI/G0yvEmqBOK3W
y12WEG8wEAv9/FQDl0+U7ngz1wl0I2o07Oilweq6606PnK27dqZk+OqoZtOz+4faQZ7K+YWOus2X
ALrj8kUNO711KJ6S7KE6AE0vp8bJy3pqVyV4I3btxa+/Gp/mT7WCS6Fjt0/L+L8q8xevsYReBfLh
fyuZiXKR/HiirUIO7BL69m0FWJIACc4oh2/fWmgghM8AvRu3mDvJu4GOQiIaReBRrAFJUAnT6p07
Bcv2K1UGB0U1qDKOY1WwdQIg4Z2kRERkojYhyRfeLGTrHrvmHkhfioR777xSsI4FwQwpkUgCN7ZC
wF9wjDmagAYhBRM+LTBtHzjJ0S+nCJd8UTrFf79rmELieKSEYlY0AASrouh3PlTFrCQgzPPiRPgI
mIKve/Cj9ZscogBYfBtcRnVgIpWQAGGFfOAgMUOE0aiYx++VTkiUFXp6X4AWCC4xEI28RBapPHo8
wm1HCrASXP3D+PyXaSgt4g95sxgtA7j3oRPJjS+HgnMCnIDR4gljppHcLmLru0F5nOgPLULgymhV
K6ZBMAngg0i41fPxR4B190vA3n/z3WMLfogDiIpmP2rRf+J/eu3gz95P0xCJ/r3JbjZN4+sofWgK
0mgZxR33sPSMz89/AwAA//8DAHYWWLc6CAAA
headers:
CF-RAY:
- CF-RAY-XXX
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Mon, 08 Dec 2025 23:16:46 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
X-Robots-Tag:
- none
anthropic-organization-id:
- ANTHROPIC-ORGANIZATION-ID-XXX
anthropic-ratelimit-input-tokens-limit:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-input-tokens-remaining:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-input-tokens-reset:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-RESET-XXX
anthropic-ratelimit-output-tokens-limit:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-output-tokens-remaining:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-output-tokens-reset:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-RESET-XXX
anthropic-ratelimit-requests-limit:
- '50'
anthropic-ratelimit-requests-remaining:
- '49'
anthropic-ratelimit-requests-reset:
- '2025-12-08T23:16:42Z'
anthropic-ratelimit-tokens-limit:
- ANTHROPIC-RATELIMIT-TOKENS-LIMIT-XXX
anthropic-ratelimit-tokens-remaining:
- ANTHROPIC-RATELIMIT-TOKENS-REMAINING-XXX
anthropic-ratelimit-tokens-reset:
- ANTHROPIC-RATELIMIT-TOKENS-RESET-XXX
cf-cache-status:
- DYNAMIC
request-id:
- REQUEST-ID-XXX
retry-after:
- '18'
strict-transport-security:
- STS-XXX
x-envoy-upstream-service-time:
- '5323'
status:
code: 200
message: OK
version: 1

View File

@@ -0,0 +1,223 @@
interactions:
- request:
body: '{"max_tokens":10000,"messages":[{"role":"user","content":"What is 2+2?"}],"model":"claude-sonnet-4-5","stream":false,"thinking":{"type":"enabled","budget_tokens":5000}}'
headers:
accept:
- application/json
accept-encoding:
- ACCEPT-ENCODING-XXX
anthropic-version:
- '2023-06-01'
connection:
- keep-alive
content-length:
- '168'
content-type:
- application/json
host:
- api.anthropic.com
user-agent:
- X-USER-AGENT-XXX
x-stainless-arch:
- X-STAINLESS-ARCH-XXX
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- X-STAINLESS-OS-XXX
x-stainless-package-version:
- 0.71.1
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.13.3
x-stainless-timeout:
- NOT_GIVEN
method: POST
uri: https://api.anthropic.com/v1/messages
response:
body:
string: !!binary |
H4sIAAAAAAAAAwAAAP//dJLdb6JAFMX/FXJfxRYRaiXpgyBWRUWL1W03GzKFW5gCMzoz+NHG/31j
s6b7kX26N/d37nk55wMqnmIJDiQlqVNsSs4YqqbVtJumYdpG1+yCDjQFByqZxUbLfrrnbbbmviff
CkymnYQVaw90UMcNnlUoJckQdBC8PB+IlFQqwhTokHCmkClwvn9c9CqnrKAsOztcVgeWOZUalRrR
JK02JWpEUJVXqGiibWuUinJ2pZkNU8NtTUqpWVegg6QZI6oWZ19fSdcrnkZennlB0ZuJ0MLOIjy6
qvHNvB08B5Pd8n3GF/1VtFxNh24/DFTKDGNxrKXqNKrAnRxfa9MO5tNxa3egHd9dmWxNl3u339tG
9iiaR362t7j0/OzAR8FBDSzik/7sbbBqlf25mppe+3kYRaN9+PDipTvSLY1FL+nMn94X7nZ/W6yv
3f6Lz/aLyEvUMN+LxwVVue8+d6zVhJuV1XhI6oEf2kExOzbE22sg0+MAxxNx2/W4Ox6HlXcUUk4H
vcZ4yPq9Sfry3l0ak32xnOQh3gyvw0Pa8zPf9GxXLML8cOD123o93QwiI9i6nYA/3vf8OzjpX3ng
4ZzU53DA1Bqaqd1pFpx+6CAV38QCieQMHECWxqoWDH4BidsaWYLgsLosdag/e+B8AGWbWsWKF8gk
OFZbh4QkOcaJQHIOMv5TYFy4QJL+j11+z/64ybFCQcrYrv7Vf9FW/jc96cBr9fupfaODRLGjCcaK
ogAHzuVNiUjhdPoJAAD//wMAg2mrwC8DAAA=
headers:
CF-RAY:
- CF-RAY-XXX
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Mon, 08 Dec 2025 23:16:49 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
X-Robots-Tag:
- none
anthropic-organization-id:
- ANTHROPIC-ORGANIZATION-ID-XXX
anthropic-ratelimit-input-tokens-limit:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-input-tokens-remaining:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-input-tokens-reset:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-RESET-XXX
anthropic-ratelimit-output-tokens-limit:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-output-tokens-remaining:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-output-tokens-reset:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-RESET-XXX
anthropic-ratelimit-requests-limit:
- '50'
anthropic-ratelimit-requests-remaining:
- '49'
anthropic-ratelimit-requests-reset:
- '2025-12-08T23:16:48Z'
anthropic-ratelimit-tokens-limit:
- ANTHROPIC-RATELIMIT-TOKENS-LIMIT-XXX
anthropic-ratelimit-tokens-remaining:
- ANTHROPIC-RATELIMIT-TOKENS-REMAINING-XXX
anthropic-ratelimit-tokens-reset:
- ANTHROPIC-RATELIMIT-TOKENS-RESET-XXX
cf-cache-status:
- DYNAMIC
request-id:
- REQUEST-ID-XXX
retry-after:
- '12'
strict-transport-security:
- STS-XXX
x-envoy-upstream-service-time:
- '2856'
status:
code: 200
message: OK
- request:
body: '{"max_tokens":10000,"messages":[{"role":"user","content":"What is 2+2?"},{"role":"assistant","content":[{"type":"thinking","thinking":"This
is a simple arithmetic question. 2+2 equals 4.","signature":"EtsBCkYIChgCKkANrO4e7QOyBt+X28FZKLvTzNoQDVSTVMHBDOKtdn00Qyust7+mKBLyfu25KPMJ1vxi7EBV2nWiTwBDAqS5ISPSEgw4osCEgxoIKxtF4aEaDNjFV1lDPtM2C3ZHSSIwORbCdva9l0QAc7PYzQBqw8kW/BDbEnwQSCctHhwrUQithEBZ74VLo2m4+RcuFEO5KkNy+rjfKsdyFeJLr89CoBJJOmCyrssMFA+JHnDALdbz9T0LwkTLhOe6H/OxdAEgE2C5BrQOhxxoujWWMpFS0KqB7KoUGAE="},{"type":"text","text":"2
+ 2 = 4"}]},{"role":"user","content":"Now what is 3+3?"}],"model":"claude-sonnet-4-5","stream":false,"thinking":{"type":"enabled","budget_tokens":5000}}'
headers:
accept:
- application/json
accept-encoding:
- ACCEPT-ENCODING-XXX
anthropic-version:
- '2023-06-01'
connection:
- keep-alive
content-length:
- '681'
content-type:
- application/json
host:
- api.anthropic.com
user-agent:
- X-USER-AGENT-XXX
x-stainless-arch:
- X-STAINLESS-ARCH-XXX
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- X-STAINLESS-OS-XXX
x-stainless-package-version:
- 0.71.1
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.13.3
x-stainless-timeout:
- NOT_GIVEN
method: POST
uri: https://api.anthropic.com/v1/messages
response:
body:
string: !!binary |
H4sIAAAAAAAAAwAAAP//dJNbb6M6FIX/CvJraHMloUjnIQ3kMmlC0twgp0eRC65xDDbxBWiq/PcR
1enMnDOaJ2+vb+0tS3v5A2Q8RilwQJRCHaM7yRlD6q53Z911Wh2r9dB5ACYgMXBAJvGp1W7bBTnn
4TYQx7au1CoYL577Z2AC9Z6j2oWkhBgBEwie1gKUkkgFmQImiDhTiCng/P3x5VcJYZQwXE/4Kh2w
TZChJRIGkQaUtWhkyFDciGAa6RQqZHSNhtG9f2Ev7LMy/jL69WWbEPnZZUglIMGJeuOihCI2oCAq
yZAikXHRSCrC2T0wgSSYQaVF/RiPl6MRDWejBI/m9HFdFAPfb0yOdNmerfc9Ee6myaaa+ZDCp7Et
bD9/L9tRZ5i6h1Ased8uWb7GXFTBDodb9O73vP3+mDM3X1yJUmz62qcevo4vawpVY0Xd89i1OYau
HwyHVdWa0zXlj15ejWbl7Im/40vTf+Zv8/BirXfNRXXsjTw6ecKKe24yvdi+aqy+Na1goi2LQuEd
usXy29YuxoQ8zNnzfBc2r738cPQyP2FMb9rhBq0C5R47MztIBslGXadYD9iqd5i/Tjaj4fUabPYB
brx2znKnhVxG8nieoIjuznNKS68bHIdnSp8a7fWbJmG5aJ6FG8aTbnYY0NLdqsmisdTTnPD+Opk9
uOW+wj2sg2ZYbK3eqhjIhb3NCrfCj+Bm/gwBqup4fB4O+LFPcPvHBFLx/CQQlJwBByAWn5QWDPwL
JLpoxCIEHKbT1AT6M3zOByAs1+qkOEVMAqc/MEEEowSdIoFgvfrTfw2tLy4QjP/Evnrr+ShPUIYE
TE9W9rv/J20n/6c3E3CtfpWsrgkkEgWJ0EkRJIAD6h8TQxGD2+07AAAA//8DADmgnx6kAwAA
headers:
CF-RAY:
- CF-RAY-XXX
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Mon, 08 Dec 2025 23:16:52 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
X-Robots-Tag:
- none
anthropic-organization-id:
- ANTHROPIC-ORGANIZATION-ID-XXX
anthropic-ratelimit-input-tokens-limit:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-input-tokens-remaining:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-input-tokens-reset:
- ANTHROPIC-RATELIMIT-INPUT-TOKENS-RESET-XXX
anthropic-ratelimit-output-tokens-limit:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-LIMIT-XXX
anthropic-ratelimit-output-tokens-remaining:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-REMAINING-XXX
anthropic-ratelimit-output-tokens-reset:
- ANTHROPIC-RATELIMIT-OUTPUT-TOKENS-RESET-XXX
anthropic-ratelimit-requests-limit:
- '50'
anthropic-ratelimit-requests-remaining:
- '49'
anthropic-ratelimit-requests-reset:
- '2025-12-08T23:16:51Z'
anthropic-ratelimit-tokens-limit:
- ANTHROPIC-RATELIMIT-TOKENS-LIMIT-XXX
anthropic-ratelimit-tokens-remaining:
- ANTHROPIC-RATELIMIT-TOKENS-REMAINING-XXX
anthropic-ratelimit-tokens-reset:
- ANTHROPIC-RATELIMIT-TOKENS-RESET-XXX
cf-cache-status:
- DYNAMIC
request-id:
- REQUEST-ID-XXX
retry-after:
- '9'
strict-transport-security:
- STS-XXX
x-envoy-upstream-service-time:
- '2431'
status:
code: 200
message: OK
version: 1

View File

@@ -0,0 +1,219 @@
interactions:
- request:
body: '{"max_tokens":4096,"messages":[{"role":"user","content":"What is the weather
in Tokyo? Use the get_weather tool."}],"model":"claude-sonnet-4-5","stream":false,"tools":[{"name":"get_weather","description":"Get
the current weather in a given location","input_schema":{"type":"object","properties":{"location":{"type":"string","description":"The
city and state, e.g. San Francisco, CA"},"unit":{"type":"string","enum":["celsius","fahrenheit"],"description":"The
unit of temperature"}},"required":["location"]}}]}'
headers:
accept:
- application/json
accept-encoding:
- gzip, deflate, zstd
anthropic-version:
- '2023-06-01'
connection:
- keep-alive
content-length:
- '509'
content-type:
- application/json
host:
- api.anthropic.com
user-agent:
- Anthropic/Python 0.71.0
x-stainless-arch:
- arm64
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- MacOS
x-stainless-package-version:
- 0.71.0
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.13.3
x-stainless-timeout:
- NOT_GIVEN
method: POST
uri: https://api.anthropic.com/v1/messages
response:
body:
string: !!binary |
H4sIAAAAAAAAA3SQzU7DMBCE32XPjpQEUqhviCKkcmn5qVQhZBlnSaI6drDXlDbKuyMHFQqI4843
s6PdHlpbogYOSstQYuKtMUjJaVIkeZoX6TSfAoOmBA6tr0SaPSwXLrt7uZ6vFup9ttpfLCd0WwED
2nUYXei9rBAYOKujIL1vPElDwEBZQ2gI+GN/8JO1WgSPh5Y4B5FmV/a52p5Xs9nkBqv1fJ81u/Xl
GTAwso25CklsUVKNLkZNFwh4D9oqSY01wOHebnYWhuGJgSfbCYfSj+CocgQeXwMahcBN0JpBGA/g
/edWQXaDxgOf5CkDJVWNQjkcW8RPxxd3KMv/2CEbC7CrsUUntSjav/5vmtW/6cDABjqWihMGHt1b
o1BQgw44xLeX0pUwDB8AAAD//wMA6heqv+kBAAA=
headers:
CF-RAY:
- 9a4c0d75ba3d6800-SJC
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 26 Nov 2025 20:14:34 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
X-Robots-Tag:
- none
anthropic-organization-id:
- 32982f3d-354e-4063-a1d9-6e3e0361bcfe
anthropic-ratelimit-input-tokens-limit:
- '30000'
anthropic-ratelimit-input-tokens-remaining:
- '30000'
anthropic-ratelimit-input-tokens-reset:
- '2025-11-26T20:14:33Z'
anthropic-ratelimit-output-tokens-limit:
- '8000'
anthropic-ratelimit-output-tokens-remaining:
- '8000'
anthropic-ratelimit-output-tokens-reset:
- '2025-11-26T20:14:34Z'
anthropic-ratelimit-requests-limit:
- '50'
anthropic-ratelimit-requests-remaining:
- '49'
anthropic-ratelimit-requests-reset:
- '2025-11-26T20:14:32Z'
anthropic-ratelimit-tokens-limit:
- '38000'
anthropic-ratelimit-tokens-remaining:
- '38000'
anthropic-ratelimit-tokens-reset:
- '2025-11-26T20:14:33Z'
cf-cache-status:
- DYNAMIC
request-id:
- req_011CVX7YqtSMhTjqLnjZvaj1
retry-after:
- '28'
strict-transport-security:
- max-age=31536000; includeSubDomains; preload
x-envoy-upstream-service-time:
- '2874'
status:
code: 200
message: OK
- request:
body: "{\"max_tokens\":4096,\"messages\":[{\"role\":\"user\",\"content\":\"What
is the weather in Tokyo? Use the get_weather tool.\"},{\"role\":\"assistant\",\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_01Eobgw8gDD6KegYJz1iyYC7\",\"name\":\"get_weather\",\"input\":{\"location\":\"Tokyo\"}}]},{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"toolu_01Eobgw8gDD6KegYJz1iyYC7\",\"content\":\"The
weather in Tokyo is sunny and 72\xB0F\"}]}],\"model\":\"claude-sonnet-4-5\",\"stream\":false,\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get
the current weather in a given location\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"location\":{\"type\":\"string\",\"description\":\"The
city and state, e.g. San Francisco, CA\"},\"unit\":{\"type\":\"string\",\"enum\":[\"celsius\",\"fahrenheit\"],\"description\":\"The
unit of temperature\"}},\"required\":[\"location\"]}}]}"
headers:
accept:
- application/json
accept-encoding:
- gzip, deflate, zstd
anthropic-version:
- '2023-06-01'
connection:
- keep-alive
content-length:
- '800'
content-type:
- application/json
host:
- api.anthropic.com
user-agent:
- Anthropic/Python 0.71.0
x-stainless-arch:
- arm64
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- MacOS
x-stainless-package-version:
- 0.71.0
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.13.3
x-stainless-timeout:
- NOT_GIVEN
method: POST
uri: https://api.anthropic.com/v1/messages
response:
body:
string: !!binary |
H4sIAAAAAAAAA3SQTWrDMBBGryJm1YJcHNE0RMsGktLu2mxKKUZYQ6zGHjnSqIkJvlPOkJMVh4b+
0dXA994ww7eHxlusQUNZm2Qxi54IObvOxpnK1TifqilIcBY0NHFV5KO5fWsebv32WW0XT/d3oxnu
HhcbkMBdi4OFMZoVgoTg6yEwMbrIhhgklJ4YiUG/7M8+424gp6FhWaHYouEKg3Akln7deeGiKFMI
SFx3IiaiThiyYqKOh7m4MG0b/M41hrHuhFLHw+zyCvpXCZF9WwQ00RNoQLIFp0DwCSJuElKJoCnV
tYR0elvvwVGbuGC/Roqgb6YTCaUpKyzKgIadp+KnkZ95QGP/Y+fd4QC2FTYYTF2Mm7/+Fx1Vv2kv
wSf+HiklIWJ4dyUW7DCAhqFsa4KFvv8AAAD//wMANWIHid8BAAA=
headers:
CF-RAY:
- 9a4c0d886f9e6800-SJC
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 26 Nov 2025 20:14:36 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
X-Robots-Tag:
- none
anthropic-organization-id:
- 32982f3d-354e-4063-a1d9-6e3e0361bcfe
anthropic-ratelimit-input-tokens-limit:
- '30000'
anthropic-ratelimit-input-tokens-remaining:
- '30000'
anthropic-ratelimit-input-tokens-reset:
- '2025-11-26T20:14:36Z'
anthropic-ratelimit-output-tokens-limit:
- '8000'
anthropic-ratelimit-output-tokens-remaining:
- '8000'
anthropic-ratelimit-output-tokens-reset:
- '2025-11-26T20:14:36Z'
anthropic-ratelimit-requests-limit:
- '50'
anthropic-ratelimit-requests-remaining:
- '49'
anthropic-ratelimit-requests-reset:
- '2025-11-26T20:14:35Z'
anthropic-ratelimit-tokens-limit:
- '38000'
anthropic-ratelimit-tokens-remaining:
- '38000'
anthropic-ratelimit-tokens-reset:
- '2025-11-26T20:14:36Z'
cf-cache-status:
- DYNAMIC
request-id:
- req_011CVX7Z4is92Sz8oA63UNxC
retry-after:
- '26'
strict-transport-security:
- max-age=31536000; includeSubDomains; preload
x-envoy-upstream-service-time:
- '2240'
status:
code: 200
message: OK
version: 1

View File

@@ -0,0 +1,122 @@
interactions:
- request:
body: '{"max_tokens":10000,"messages":[{"role":"user","content":"What is the weather
in Tokyo?"}],"model":"claude-sonnet-4-5","stream":false,"thinking":{"type":"enabled","budget_tokens":5000}}'
headers:
accept:
- application/json
accept-encoding:
- gzip, deflate
anthropic-version:
- '2023-06-01'
connection:
- keep-alive
content-length:
- '185'
content-type:
- application/json
host:
- api.anthropic.com
user-agent:
- Anthropic/Python 0.75.0
x-stainless-arch:
- arm64
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- MacOS
x-stainless-package-version:
- 0.75.0
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.13.3
x-stainless-timeout:
- NOT_GIVEN
method: POST
uri: https://api.anthropic.com/v1/messages
response:
body:
string: !!binary |
H4sIAAAAAAAAAwAAAP//hJNdr6o4GIX/SsPNXIjbD/xAk3OhiIiyZasI4uxkUmkFBFpsy4f75Pz3
CU72PjOTyZyrNm/WWu9K0+e7lFGEU2kqBSksEG5zSggW7UF72O53+8PupD+RZClG0lTKePhHtzeo
vMQjm621jXbB3apfy6MTbyRZEo8cNyrMOQyxJEuMps0Ach5zAYmQZCmgRGAipOnv3z/1IopJEpOw
Sfi8TiUnwqDgmIGYA8ibIcgwgBdaCCAiDIKCMUwEqDAUUSMjwKHJg76AFa1wiZkMTIAo+U2ACJYY
wCDAnANBAcMwbYs4wyAmV8oyKGJKZBCTIC1Qs+ff0QElKG5E/AWYgEe0SBFI8bNHBhJCKyAiKIAJ
AtjsyxktY/RfFb/WAUgQ4EUYYi5A9AzADxA8k68xQUBEMf+74UWSJR6HBIqCNY+ms2ShJb6pRaG2
SRYxKo4IGeFJ88ywQ4ptYvST/ai6kfRUWkZy7GgByjU9+ugeNMtZwbi/qm19TY38SJR0LLbWSHGx
07MyVd3ODVsYt4Uefhw42u+9QutPWpfwEnG4WIR6vP6YxC70t7hUiWZWSydeP4I7bUX9JOrtkJJk
W9VLbgfDHSmm+qhIoYxXd7O3UtTOCfOQ3CLYJYwNB2dFW/Y295nG3BmZ7V6z1ezijBkcdWsbovTi
ozl8qOb6TrpZy7xdnVw7l4OROuK0YMVB25da2FuuD+Ftm26LnZLYnRPOjGprCe1YuaWXtd7Ouj9z
W/PCNy3DCvhmtwwYsxfeil6KfWtvJZdKqz+83B7ekxQRmrVUdDesszLcLOqxPTg583l/fbtk+n2j
L2Z1NkrXTgdmV66og+H89Co67jLprVl5K7eHFJdmHYyx0XH7kbtfDpA6r52ra9rzYbgx/OH4auuW
r78Nc3j3rkd/sIJqy1F07VR4F19bmG8t1PU8pYv2+0FL7O4DrF1VcVQ1Ha3z0l5lll/Dw80IcN7P
B8GEr6+FueP2Yuzl+s7P6t79sRlN5gGH/Gzs3XNkcMUux841JxVx+ditJxd2sm5vNTyIdc4mxGDG
TP8m/ZB/QonrBtfnMZV+SdLnF0dQQBlw+sWCwGkKHrT4BbPv5J04FIRY/C81V8r+csjPzCcv03fS
BlqEg+TLUuELjwXmII2Tr24vAc3kpnzxjwFlX4KQlk3WAUMWROBPusqlJYIYCMJ/JfRJYVhcHwhz
EY8KHvW0EppMMZM104l5KIvMf5fMOD7xmq86VXSgsqPZaaU7qnFZDiotHNJbQR24T1D8ac4hKC81
X1Rh8IvkwSa79NYtBxZ1hwwfvfO9NezUdQ8xhzW3OtqPvOn9Zh+O62JuUp2MqO61IXsFl9YuXELO
61YDXJgX82rzcEXTY0Mp+6AjOHmhliCdziUKfYCE5wIxoFaKcw2VubjbN7ISStbZP0EStednDRk2
A7SJmF9C/xScrDyCu//YOlvvRxgwIrLTF+Nf/RfdDr/p1JAv+fvR9vK0oYT4Yg10tojUUv1uOo4d
TdM7AAAA//8DANemNnfhBgAA
headers:
CF-RAY:
- 9a4b033548b28ea2-SJC
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 26 Nov 2025 17:12:50 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
X-Robots-Tag:
- none
anthropic-organization-id:
- 32982f3d-354e-4063-a1d9-6e3e0361bcfe
anthropic-ratelimit-input-tokens-limit:
- '30000'
anthropic-ratelimit-input-tokens-remaining:
- '30000'
anthropic-ratelimit-input-tokens-reset:
- '2025-11-26T17:12:47Z'
anthropic-ratelimit-output-tokens-limit:
- '8000'
anthropic-ratelimit-output-tokens-remaining:
- '8000'
anthropic-ratelimit-output-tokens-reset:
- '2025-11-26T17:12:51Z'
anthropic-ratelimit-requests-limit:
- '50'
anthropic-ratelimit-requests-remaining:
- '49'
anthropic-ratelimit-requests-reset:
- '2025-11-26T17:12:46Z'
anthropic-ratelimit-tokens-limit:
- '38000'
anthropic-ratelimit-tokens-remaining:
- '38000'
anthropic-ratelimit-tokens-reset:
- '2025-11-26T17:12:47Z'
cf-cache-status:
- DYNAMIC
request-id:
- req_011CVWsgwRugLxGNv45mLXEL
retry-after:
- '13'
strict-transport-security:
- max-age=31536000; includeSubDomains; preload
x-envoy-upstream-service-time:
- '4553'
status:
code: 200
message: OK
version: 1

View File

@@ -0,0 +1,222 @@
interactions:
- request:
body: '{"max_tokens":10000,"messages":[{"role":"user","content":"What is 2+2?"}],"model":"claude-sonnet-4-5","stream":false,"thinking":{"type":"enabled","budget_tokens":5000}}'
headers:
accept:
- application/json
accept-encoding:
- gzip, deflate, zstd
anthropic-version:
- '2023-06-01'
connection:
- keep-alive
content-length:
- '168'
content-type:
- application/json
host:
- api.anthropic.com
user-agent:
- Anthropic/Python 0.71.0
x-stainless-arch:
- arm64
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- MacOS
x-stainless-package-version:
- 0.71.0
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.13.3
x-stainless-timeout:
- NOT_GIVEN
method: POST
uri: https://api.anthropic.com/v1/messages
response:
body:
string: !!binary |
H4sIAAAAAAAAAwAAAP//dJJbj6JAEIX/CqlXcBYRvJDMg3hXcJzVZS6bDelAIS1NI3SjMhP/+4bJ
mtlL9qkq9Z06L+e8Q5ZHyMCGkJEqwpbIOUfZMltWy9ANSx8YA9CARmBDJvaB3u4f1kXqmPlrvvR4
bJXhjPgHAhrI+oiNCoUgewQNypw1ByIEFZJwCRqEOZfIJdjf3296mVCeUr5vHG6rDbuECoUKhSiC
ZkeGCimpTDKUNFSKCoWkOb9TDNVQsKgIE4p5BxoIuudEVmXjO5HCGaUvi1GyH63S4bp8MLH3+FA7
Un02+tPXlXvava3zx7G/3fne3Bk/rGTEdf2xroTsqdnKceu4MqzVxlu2Txfamzi+wZ/o7uyMh8XW
Wmw328n+re7HQ8PR1fPQWnS445HxzBlZbvW6e/Gn5y9fu2W9OO85O0cTGlvr5dOa0faCvYzbh03/
sLSQMevLud1zlt8G7i5Vaxx1J3PuRjKLfS9i4bQbs1W6nsre2J+5SVTIPHGeLxezyJz+YrU69rzB
UFW9tt6J5Xanmt5hM68HmPiX43qiP81JTsL5crjR3W6x8NLTQZI4RDyQlI3dDpkNJ/dw1T7zwEuT
1MewwVBUxVDuFROuPzQQMj8GJRKRc7ABeRTIquTwCwgsKuQhgs0rxjSoPnpgvwPlx0oGMk+RC7DN
jgYhCRMMwhJJE2Twp0C/8RJJ9D92+2388ZhghiVhgZX9q/+k7eRvetUgr+Tvp05XA4HliYYYSIol
2NCUNyJlBNfrTwAAAP//AwD5LVCFLwMAAA==
headers:
CF-RAY:
- 9a4bfbbe0e3b26b0-SJC
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 26 Nov 2025 20:02:28 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
X-Robots-Tag:
- none
anthropic-organization-id:
- 32982f3d-354e-4063-a1d9-6e3e0361bcfe
anthropic-ratelimit-input-tokens-limit:
- '30000'
anthropic-ratelimit-input-tokens-remaining:
- '30000'
anthropic-ratelimit-input-tokens-reset:
- '2025-11-26T20:02:28Z'
anthropic-ratelimit-output-tokens-limit:
- '8000'
anthropic-ratelimit-output-tokens-remaining:
- '8000'
anthropic-ratelimit-output-tokens-reset:
- '2025-11-26T20:02:28Z'
anthropic-ratelimit-requests-limit:
- '50'
anthropic-ratelimit-requests-remaining:
- '49'
anthropic-ratelimit-requests-reset:
- '2025-11-26T20:02:26Z'
anthropic-ratelimit-tokens-limit:
- '38000'
anthropic-ratelimit-tokens-remaining:
- '38000'
anthropic-ratelimit-tokens-reset:
- '2025-11-26T20:02:28Z'
cf-cache-status:
- DYNAMIC
request-id:
- req_011CVX6dM9aWdpYdmnHARrXh
retry-after:
- '35'
strict-transport-security:
- max-age=31536000; includeSubDomains; preload
x-envoy-upstream-service-time:
- '2775'
status:
code: 200
message: OK
- request:
body: '{"max_tokens":10000,"messages":[{"role":"user","content":"What is 2+2?"},{"role":"assistant","content":[{"type":"thinking","thinking":"This
is a simple arithmetic question. 2+2 equals 4.","signature":"EtsBCkYIChgCKkANrO4e7QOyBt+X28FZKLvTzNoQDVSTVMHBDOKtdn00Qyust7+mKBLyfu25KPMJ1vxi7EBV2nWiTwBDAqS5ISPSEgzy8fA2B0+wA5I3nBMaDGBC5LuZTYVFw/R6ryIwgnlwdEif5NJWNli1IlYD1jP8jJ5ell5/w17BJU9LTk+yeC6EHnLdtmfVMdlcF6flKkNFt7DVGLhdqtohBXxx4qmB8IKKp7M9A++M103ftST+4MjPHy9ehVxpNE0WHaoacHJAP0L6qIMkvjtafceejaklDL3aGAE="},{"type":"text","text":"2
+ 2 = 4"}]},{"role":"user","content":"Now what is 3+3?"}],"model":"claude-sonnet-4-5","stream":false,"thinking":{"type":"enabled","budget_tokens":5000}}'
headers:
accept:
- application/json
accept-encoding:
- gzip, deflate, zstd
anthropic-version:
- '2023-06-01'
connection:
- keep-alive
content-length:
- '681'
content-type:
- application/json
host:
- api.anthropic.com
user-agent:
- Anthropic/Python 0.71.0
x-stainless-arch:
- arm64
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- MacOS
x-stainless-package-version:
- 0.71.0
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.13.3
x-stainless-timeout:
- NOT_GIVEN
method: POST
uri: https://api.anthropic.com/v1/messages
response:
body:
string: !!binary |
H4sIAAAAAAAAAwAAAP//dJJbc6JAEIX/CtWvwURQUajKAyJe4jUGEd3aokYYYQQGZIYIpvzvW6TW
zV5qn7qrv9PnoU9/QJL6OAYNvBgVPm6wlFLMG+1GpyE35U5TlVUQgfigQcICtynZg93JKmUrP676
RqRcncXr69QCEXiV4VqFGUMBBhHyNK4HiDHCOKIcRPBSyjHloH37uOt5SGhEaFA73FsNrJAwgTAB
CYzniAQhP6b5BeW+gHLCwwRz4gnnAjNOUvootIQHoSU8C8ojiMBIQBEv8trdLMy+Ee0mRhgY08gI
9Y01WlOyUZFMl14fIV5J64dSyTpWheyNtLyO+PRQIUXfT9vKcdsbt9DSsQeDUElOUknG22wgq6dg
G7wtV/tqli2cuRlc5Hn/Ye4508nQGPOu1UMDw5A27y1HovHTm9l2SjK5TJq0v8/R1hm3PX2SssQJ
omsvvRpnc9gcGvP4YNtqudKV1L6envbtWVZZzswazgev2ctwx6ZR5G+qve33jd1ZL9F40euG0bmX
RM1DNl322Vtw6q6k97EtKX7lqNZMduyhWarkOsbt6cqXuvEmLC7labY4X4/Julr3DnpyGnkv567p
B3pRViPdfIab+JUOLuvcPosGv84Mt+8iMJ5mbo4RSylogKnv8iKn8BMwfC4w9TBotIhjEYrPr9A+
gNCs4C5PI0wZaEpXBA95IXa9HKM6TfdPQfPOc4z8/7H7bu2PsxAnOEex20n+1X9RKfyb3kRIC/77
qKWKwHD+TjzscoJz0KB+ZR/lPtxuPwAAAP//AwBO51LgPQMAAA==
headers:
CF-RAY:
- 9a4bfbd00b1426b0-SJC
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 26 Nov 2025 20:02:31 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
X-Robots-Tag:
- none
anthropic-organization-id:
- 32982f3d-354e-4063-a1d9-6e3e0361bcfe
anthropic-ratelimit-input-tokens-limit:
- '30000'
anthropic-ratelimit-input-tokens-remaining:
- '30000'
anthropic-ratelimit-input-tokens-reset:
- '2025-11-26T20:02:30Z'
anthropic-ratelimit-output-tokens-limit:
- '8000'
anthropic-ratelimit-output-tokens-remaining:
- '8000'
anthropic-ratelimit-output-tokens-reset:
- '2025-11-26T20:02:31Z'
anthropic-ratelimit-requests-limit:
- '50'
anthropic-ratelimit-requests-remaining:
- '49'
anthropic-ratelimit-requests-reset:
- '2025-11-26T20:02:29Z'
anthropic-ratelimit-tokens-limit:
- '38000'
anthropic-ratelimit-tokens-remaining:
- '38000'
anthropic-ratelimit-tokens-reset:
- '2025-11-26T20:02:30Z'
cf-cache-status:
- DYNAMIC
request-id:
- req_011CVX6dZXDfHGDm98QN81RZ
retry-after:
- '30'
strict-transport-security:
- max-age=31536000; includeSubDomains; preload
x-envoy-upstream-service-time:
- '2540'
status:
code: 200
message: OK
version: 1

View File

@@ -12,8 +12,11 @@ from crewai.task import Task
@pytest.fixture(autouse=True)
def mock_anthropic_api_key():
"""Automatically mock ANTHROPIC_API_KEY for all tests in this module."""
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "test-key"}):
"""Automatically mock ANTHROPIC_API_KEY for all tests in this module if not already set."""
if "ANTHROPIC_API_KEY" not in os.environ:
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "test-key"}):
yield
else:
yield
@@ -63,6 +66,7 @@ def test_anthropic_tool_use_conversation_flow():
with patch.object(completion.client.messages, 'create') as mock_create:
# Mock initial response with tool use - need to properly mock ToolUseBlock
mock_tool_use = Mock(spec=ToolUseBlock)
mock_tool_use.type = "tool_use"
mock_tool_use.id = "tool_123"
mock_tool_use.name = "get_weather"
mock_tool_use.input = {"location": "San Francisco"}
@@ -75,6 +79,7 @@ def test_anthropic_tool_use_conversation_flow():
# Mock final response after tool result - properly mock text content
mock_text_block = Mock()
mock_text_block.type = "text"
# Set the text attribute as a string, not another Mock
mock_text_block.configure_mock(text="Based on the weather data, it's a beautiful day in San Francisco with sunny skies and 75°F temperature.")
@@ -698,3 +703,167 @@ def test_anthropic_stop_sequences_sent_to_api():
assert result is not None
assert isinstance(result, str)
assert len(result) > 0
@pytest.mark.vcr(filter_headers=["authorization", "x-api-key"])
def test_anthropic_thinking():
"""Test that thinking is properly handled and thinking params are passed to messages.create"""
from unittest.mock import patch
from crewai.llms.providers.anthropic.completion import AnthropicCompletion
llm = LLM(
model="anthropic/claude-sonnet-4-5",
thinking={"type": "enabled", "budget_tokens": 5000},
max_tokens=10000
)
assert isinstance(llm, AnthropicCompletion)
original_create = llm.client.messages.create
captured_params = {}
def capture_and_call(**kwargs):
captured_params.update(kwargs)
return original_create(**kwargs)
with patch.object(llm.client.messages, 'create', side_effect=capture_and_call):
result = llm.call("What is the weather in Tokyo?")
assert result is not None
assert isinstance(result, str)
assert len(result) > 0
assert "thinking" in captured_params
assert captured_params["thinking"] == {"type": "enabled", "budget_tokens": 5000}
assert captured_params["model"] == "claude-sonnet-4-5"
assert captured_params["max_tokens"] == 10000
assert "messages" in captured_params
assert len(captured_params["messages"]) > 0
@pytest.mark.vcr(filter_headers=["authorization", "x-api-key"])
def test_anthropic_thinking_blocks_preserved_across_turns():
"""Test that thinking blocks are stored and included in subsequent API calls across turns"""
from unittest.mock import patch
from crewai.llms.providers.anthropic.completion import AnthropicCompletion
llm = LLM(
model="anthropic/claude-sonnet-4-5",
thinking={"type": "enabled", "budget_tokens": 5000},
max_tokens=10000
)
assert isinstance(llm, AnthropicCompletion)
# Capture all messages.create calls to verify thinking blocks are included
original_create = llm.client.messages.create
captured_calls = []
def capture_and_call(**kwargs):
captured_calls.append(kwargs)
return original_create(**kwargs)
with patch.object(llm.client.messages, 'create', side_effect=capture_and_call):
# First call - establishes context and generates thinking blocks
messages = [{"role": "user", "content": "What is 2+2?"}]
first_result = llm.call(messages)
# Verify first call completed
assert first_result is not None
assert isinstance(first_result, str)
assert len(first_result) > 0
# Verify thinking blocks were stored after first response
assert len(llm.previous_thinking_blocks) > 0, "No thinking blocks stored after first call"
first_thinking = llm.previous_thinking_blocks[0]
assert first_thinking["type"] == "thinking"
assert "thinking" in first_thinking
assert "signature" in first_thinking
# Store the thinking block content for comparison
stored_thinking_content = first_thinking["thinking"]
stored_signature = first_thinking["signature"]
# Second call - should include thinking blocks from first call
messages.append({"role": "assistant", "content": first_result})
messages.append({"role": "user", "content": "Now what is 3+3?"})
second_result = llm.call(messages)
# Verify second call completed
assert second_result is not None
assert isinstance(second_result, str)
# Verify at least 2 API calls were made
assert len(captured_calls) >= 2, f"Expected at least 2 API calls, got {len(captured_calls)}"
# Verify second call includes thinking blocks in assistant message
second_call_messages = captured_calls[1]["messages"]
# Should have: user message + assistant message (with thinking blocks) + follow-up user message
assert len(second_call_messages) >= 2
# Find the assistant message in the second call
assistant_message = None
for msg in second_call_messages:
if msg["role"] == "assistant" and isinstance(msg.get("content"), list):
assistant_message = msg
break
assert assistant_message is not None, "Assistant message with list content not found in second call"
assert isinstance(assistant_message["content"], list)
# Verify thinking block is included in assistant message content
thinking_found = False
for block in assistant_message["content"]:
if isinstance(block, dict) and block.get("type") == "thinking":
thinking_found = True
assert "thinking" in block
assert "signature" in block
# Verify it matches what was stored from the first call
assert block["thinking"] == stored_thinking_content
assert block["signature"] == stored_signature
break
assert thinking_found, "Thinking block not found in assistant message content in second call"
@pytest.mark.vcr(filter_headers=["authorization", "x-api-key"])
def test_anthropic_function_calling():
"""Test that function calling is properly handled"""
llm = LLM(model="anthropic/claude-sonnet-4-5")
def get_weather(location: str) -> str:
return f"The weather in {location} is sunny and 72°F"
tools = [
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The unit of temperature"
}
},
"required": ["location"]
}
}
]
result = llm.call(
"What is the weather in Tokyo? Use the get_weather tool.",
tools=tools,
available_functions={"get_weather": get_weather}
)
assert result is not None
assert isinstance(result, str)
assert len(result) > 0
# Verify the response includes information about Tokyo's weather
assert "tokyo" in result.lower() or "72" in result