-
Notifications
You must be signed in to change notification settings - Fork 67
fix(anthropic): add support for Claude thinking API #671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
d97bd7e
8efeee6
e45441b
55e294e
2004e2d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,223 @@ | ||
| { | ||
| "log": { | ||
| "_recordingName": "Test Anthropic instrumentation/should set attributes in span for beta messages with thinking", | ||
| "creator": { | ||
| "comment": "persister:fs", | ||
| "name": "Polly.JS", | ||
| "version": "6.0.6" | ||
| }, | ||
| "entries": [ | ||
| { | ||
| "_id": "36fcbb1741e0f2a632c89d8c928a5d53", | ||
| "_order": 0, | ||
| "cache": {}, | ||
| "request": { | ||
| "bodySize": 192, | ||
| "cookies": [], | ||
| "headers": [ | ||
| { | ||
| "name": "accept", | ||
| "value": "application/json" | ||
| }, | ||
| { | ||
| "name": "anthropic-beta", | ||
| "value": "interleaved-thinking-2025-05-14" | ||
| }, | ||
| { | ||
| "name": "anthropic-version", | ||
| "value": "2023-06-01" | ||
| }, | ||
| { | ||
| "name": "content-type", | ||
| "value": "application/json" | ||
| }, | ||
| { | ||
| "name": "user-agent", | ||
| "value": "Anthropic/JS 0.56.0" | ||
| }, | ||
| { | ||
| "name": "x-stainless-arch", | ||
| "value": "arm64" | ||
| }, | ||
| { | ||
| "name": "x-stainless-lang", | ||
| "value": "js" | ||
| }, | ||
| { | ||
| "name": "x-stainless-os", | ||
| "value": "MacOS" | ||
| }, | ||
| { | ||
| "name": "x-stainless-package-version", | ||
| "value": "0.56.0" | ||
| }, | ||
| { | ||
| "name": "x-stainless-retry-count", | ||
| "value": "0" | ||
| }, | ||
| { | ||
| "name": "x-stainless-runtime", | ||
| "value": "node" | ||
| }, | ||
| { | ||
| "name": "x-stainless-runtime-version", | ||
| "value": "v20.11.1" | ||
| }, | ||
| { | ||
| "name": "x-stainless-timeout", | ||
| "value": "600" | ||
| } | ||
| ], | ||
| "headersSize": 584, | ||
| "httpVersion": "HTTP/1.1", | ||
| "method": "POST", | ||
| "postData": { | ||
| "mimeType": "application/json", | ||
| "params": [], | ||
| "text": "{\"max_tokens\":2048,\"messages\":[{\"role\":\"user\",\"content\":\"What is 2+2? Think through this step by step.\"}],\"model\":\"claude-opus-4-1-20250805\",\"thinking\":{\"type\":\"enabled\",\"budget_tokens\":1024}}" | ||
| }, | ||
| "queryString": [ | ||
| { | ||
| "name": "beta", | ||
| "value": "true" | ||
| } | ||
| ], | ||
| "url": "https://api.anthropic.com/v1/messages?beta=true" | ||
| }, | ||
| "response": { | ||
| "bodySize": 1570, | ||
| "content": { | ||
| "mimeType": "application/json", | ||
| "size": 1570, | ||
| "text": "{\"id\":\"msg_018V3xGyrq6nc25GVuWiaKHx\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-opus-4-1-20250805\",\"content\":[{\"type\":\"thinking\",\"thinking\":\"This is a very simple arithmetic question. The user is asking for 2+2, which equals 4. They've asked me to think through it step by step, so I should show the basic addition process even though it's elementary.\",\"signature\":\"EvsCCkYIBhgCKkDcMyQ9Uh8CsGT5WmyeuwbI5yYSB1cbUyx5DC/zqmUMb0n5Zyi+Oz/fXpxGLJUmfnKp3zXuuOhybxupMRhBmK+3EgxVj1F8BGfmpqpOxjcaDIbIp9dBQHkej5KsTyIwJDTMjuH/q/vu4Pk/Zf4w9htqsZOPLfYdg/EbXIdeBNV4sJ6Jtiu+KzBg4O5fTgjPKuIBuD8ob8cR9xna6cV8JHxfUT9IeX3huQ2oF/vJC/99vqn4F//OEjiN8kCKPlJo28+S72odghUyF8TUITL/UIBWZ3kcQtwCdmytlB1+2Bld5osVVmOi4KApBkl9cRTOemDzkJHBFmhJ1AuUyZ2Fl2hVGmE2ACE8CPYU+iCZpZX2l4tWCT2M1wCaNTwNSqHcQtC/C0H9geP6Vyc2K2P6TcUIuUv8CFVIdqwcYDnbREhlY2Jv7nmaVDSraCvCXWj3Y/sQulDsBOqp6drQAITcWPJI8wbDmw8fIEhcCyujlcpanKzBhhgB\"},{\"type\":\"text\",\"text\":\"I'll work through this simple addition step by step.\\n\\n**Step 1:** Identify what we're adding\\n- We have two numbers: 2 and 2\\n- We need to add them together\\n\\n**Step 2:** Perform the addition\\n- Start with the first number: 2\\n- Add the second number: + 2\\n- When we combine 2 items with 2 more items, we get 4 items total\\n\\n**Step 3:** State the result\\n- 2 + 2 = 4\\n\\nThe answer is **4**.\"}],\"stop_reason\":\"end_turn\",\"stop_sequence\":null,\"usage\":{\"input_tokens\":49,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"cache_creation\":{\"ephemeral_5m_input_tokens\":0,\"ephemeral_1h_input_tokens\":0},\"output_tokens\":186,\"service_tier\":\"standard\"}}" | ||
| }, | ||
| "cookies": [], | ||
| "headers": [ | ||
| { | ||
| "name": "anthropic-organization-id", | ||
| "value": "617d109c-a187-4902-889d-689223d134aa" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-input-tokens-limit", | ||
| "value": "2000000" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-input-tokens-remaining", | ||
| "value": "2000000" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-input-tokens-reset", | ||
| "value": "2025-08-21T11:41:58Z" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-output-tokens-limit", | ||
| "value": "400000" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-output-tokens-remaining", | ||
| "value": "400000" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-output-tokens-reset", | ||
| "value": "2025-08-21T11:42:02Z" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-requests-limit", | ||
| "value": "4000" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-requests-remaining", | ||
| "value": "3999" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-requests-reset", | ||
| "value": "2025-08-21T11:41:57Z" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-tokens-limit", | ||
| "value": "2400000" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-tokens-remaining", | ||
| "value": "2400000" | ||
| }, | ||
| { | ||
| "name": "anthropic-ratelimit-tokens-reset", | ||
| "value": "2025-08-21T11:41:58Z" | ||
| }, | ||
| { | ||
| "name": "cf-cache-status", | ||
| "value": "DYNAMIC" | ||
| }, | ||
| { | ||
| "name": "cf-ray", | ||
| "value": "9729dd411cdd6756-ATL" | ||
| }, | ||
| { | ||
| "name": "connection", | ||
| "value": "keep-alive" | ||
| }, | ||
| { | ||
| "name": "content-encoding", | ||
| "value": "gzip" | ||
| }, | ||
| { | ||
| "name": "content-type", | ||
| "value": "application/json" | ||
| }, | ||
| { | ||
| "name": "date", | ||
| "value": "Thu, 21 Aug 2025 11:42:02 GMT" | ||
| }, | ||
| { | ||
| "name": "request-id", | ||
| "value": "req_011CSLo11ceKMKF1kTBWoKxZ" | ||
| }, | ||
| { | ||
| "name": "server", | ||
| "value": "cloudflare" | ||
| }, | ||
| { | ||
| "name": "strict-transport-security", | ||
| "value": "max-age=31536000; includeSubDomains; preload" | ||
| }, | ||
| { | ||
| "name": "transfer-encoding", | ||
| "value": "chunked" | ||
| }, | ||
| { | ||
| "name": "via", | ||
| "value": "1.1 google" | ||
| }, | ||
| { | ||
| "name": "x-envoy-upstream-service-time", | ||
| "value": "5555" | ||
| }, | ||
| { | ||
| "name": "x-robots-tag", | ||
| "value": "none" | ||
| } | ||
| ], | ||
| "headersSize": 1098, | ||
| "httpVersion": "HTTP/1.1", | ||
| "redirectURL": "", | ||
| "status": 200, | ||
| "statusText": "OK" | ||
| }, | ||
| "startedDateTime": "2025-08-21T11:41:56.089Z", | ||
| "time": 6594, | ||
| "timings": { | ||
| "blocked": -1, | ||
| "connect": -1, | ||
| "dns": -1, | ||
| "receive": 0, | ||
| "send": 0, | ||
| "ssl": -1, | ||
| "wait": 6594 | ||
| } | ||
| } | ||
| ], | ||
| "pages": [], | ||
| "version": "1.2" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -45,6 +45,9 @@ import type { | |||||||||||||||||||||||||||||||||
| Message, | ||||||||||||||||||||||||||||||||||
| MessageStreamEvent, | ||||||||||||||||||||||||||||||||||
| } from "@anthropic-ai/sdk/resources/messages"; | ||||||||||||||||||||||||||||||||||
| import type { | ||||||||||||||||||||||||||||||||||
| MessageCreateParamsNonStreaming as BetaMessageCreateParamsNonStreaming, | ||||||||||||||||||||||||||||||||||
| } from "@anthropic-ai/sdk/resources/beta/messages"; | ||||||||||||||||||||||||||||||||||
| import type { Stream } from "@anthropic-ai/sdk/streaming"; | ||||||||||||||||||||||||||||||||||
| import type { APIPromise, BaseAnthropic } from "@anthropic-ai/sdk"; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
@@ -72,6 +75,11 @@ export class AnthropicInstrumentation extends InstrumentationBase { | |||||||||||||||||||||||||||||||||
| "create", | ||||||||||||||||||||||||||||||||||
| this.patchAnthropic("chat", module), | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| this._wrap( | ||||||||||||||||||||||||||||||||||
| module.Anthropic.Beta.Messages.prototype, | ||||||||||||||||||||||||||||||||||
| "create", | ||||||||||||||||||||||||||||||||||
| this.patchAnthropic("chat", module), | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| protected init(): InstrumentationModuleDefinition { | ||||||||||||||||||||||||||||||||||
|
|
@@ -97,6 +105,11 @@ export class AnthropicInstrumentation extends InstrumentationBase { | |||||||||||||||||||||||||||||||||
| "create", | ||||||||||||||||||||||||||||||||||
| this.patchAnthropic("chat", moduleExports), | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| this._wrap( | ||||||||||||||||||||||||||||||||||
| moduleExports.Anthropic.Beta.Messages.prototype, | ||||||||||||||||||||||||||||||||||
| "create", | ||||||||||||||||||||||||||||||||||
| this.patchAnthropic("chat", moduleExports), | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+106
to
+110
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Same guard needed in automatic patch() path. Mirror the safety check here to prevent - this._wrap(
- moduleExports.Anthropic.Beta.Messages.prototype,
- "create",
- this.patchAnthropic("chat", moduleExports),
- );
+ if (moduleExports?.Anthropic?.Beta?.Messages?.prototype?.create) {
+ this._wrap(
+ moduleExports.Anthropic.Beta.Messages.prototype,
+ "create",
+ this.patchAnthropic("chat", moduleExports),
+ );
+ } else {
+ this._diag.debug(
+ "Anthropic Beta.Messages.create not found; skipping beta patch"
+ );
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| return moduleExports; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
@@ -108,6 +121,7 @@ export class AnthropicInstrumentation extends InstrumentationBase { | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| this._unwrap(moduleExports.Anthropic.Completions.prototype, "create"); | ||||||||||||||||||||||||||||||||||
| this._unwrap(moduleExports.Anthropic.Messages.prototype, "create"); | ||||||||||||||||||||||||||||||||||
| this._unwrap(moduleExports.Anthropic.Beta.Messages.prototype, "create"); | ||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Guard unwrap to match conditional wrapping. Unwrapping an undefined prototype will also throw. Protect the unwrap with the same shape check. - this._unwrap(moduleExports.Anthropic.Beta.Messages.prototype, "create");
+ if (moduleExports?.Anthropic?.Beta?.Messages?.prototype) {
+ this._unwrap(moduleExports.Anthropic.Beta.Messages.prototype, "create");
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| private patchAnthropic( | ||||||||||||||||||||||||||||||||||
|
|
@@ -202,6 +216,13 @@ export class AnthropicInstrumentation extends InstrumentationBase { | |||||||||||||||||||||||||||||||||
| attributes[SpanAttributes.LLM_REQUEST_TOP_P] = params.top_p; | ||||||||||||||||||||||||||||||||||
| attributes[SpanAttributes.LLM_TOP_K] = params.top_k; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // Handle thinking parameters (for beta messages) | ||||||||||||||||||||||||||||||||||
| const betaParams = params as BetaMessageCreateParamsNonStreaming; | ||||||||||||||||||||||||||||||||||
| if (betaParams.thinking && betaParams.thinking.type === "enabled") { | ||||||||||||||||||||||||||||||||||
| attributes["llm.request.thinking.type"] = betaParams.thinking.type; | ||||||||||||||||||||||||||||||||||
| attributes["llm.request.thinking.budget_tokens"] = betaParams.thinking.budget_tokens; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (type === "completion") { | ||||||||||||||||||||||||||||||||||
| attributes[SpanAttributes.LLM_REQUEST_MAX_TOKENS] = | ||||||||||||||||||||||||||||||||||
| params.max_tokens_to_sample; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Guard Beta.Messages patching for SDK versions without Beta API.
Accessing
module.Anthropic.Beta.Messages.prototypeunconditionally can throw on older@anthropic-ai/sdkversions. Add a structural guard to avoid runtime errors and log that Beta patching is skipped.Apply this diff:
📝 Committable suggestion
🤖 Prompt for AI Agents