-
Notifications
You must be signed in to change notification settings - Fork 2.7k
feat: Support Anthropic extended thinking and interleaved thinking #1744
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 3 commits
54a9f7a
543d192
8ab9357
c8d5e4a
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 |
---|---|---|
|
@@ -62,6 +62,9 @@ class StreamingState: | |
# Fields for real-time function call streaming | ||
function_call_streaming: dict[int, bool] = field(default_factory=dict) | ||
function_call_output_idx: dict[int, int] = field(default_factory=dict) | ||
# Store accumulated thinking text and signature for Anthropic compatibility | ||
thinking_text: str = "" | ||
thinking_signature: str | None = None | ||
|
||
|
||
class SequenceNumber: | ||
|
@@ -101,6 +104,19 @@ async def handle_stream( | |
|
||
delta = chunk.choices[0].delta | ||
|
||
# Handle thinking blocks from Anthropic (for preserving signatures) | ||
if hasattr(delta, "thinking_blocks") and delta.thinking_blocks: | ||
for block in delta.thinking_blocks: | ||
if isinstance(block, dict): | ||
# Accumulate thinking text | ||
thinking_text = block.get("thinking", "") | ||
if thinking_text: | ||
state.thinking_text += thinking_text | ||
# Store signature if present | ||
signature = block.get("signature") | ||
if signature: | ||
state.thinking_signature = signature | ||
|
||
# Handle reasoning content for reasoning summaries | ||
if hasattr(delta, "reasoning_content"): | ||
reasoning_content = delta.reasoning_content | ||
|
@@ -527,7 +543,19 @@ async def handle_stream( | |
|
||
# include Reasoning item if it exists | ||
if state.reasoning_content_index_and_output: | ||
outputs.append(state.reasoning_content_index_and_output[1]) | ||
reasoning_item = state.reasoning_content_index_and_output[1] | ||
# Store thinking text in content and signature in encrypted_content | ||
if state.thinking_text: | ||
# Add thinking text as a Content object | ||
if not reasoning_item.content: | ||
reasoning_item.content = [] | ||
reasoning_item.content.append( | ||
Content(text=state.thinking_text, type="reasoning_text") | ||
) | ||
# Store signature in encrypted_content | ||
if state.thinking_signature: | ||
reasoning_item.encrypted_content = state.thinking_signature | ||
Comment on lines
545
to
+557
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. [P1] Streaming path drops thinking block when Anthropic redacts reasoning text The streaming handler only appends a Useful? React with 👍 / 👎. 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. @codex This is the same as above. 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. To use Codex here, create an environment for this repo. |
||
outputs.append(reasoning_item) | ||
|
||
# include text or refusal content if they exist | ||
if state.text_content_index_and_output or state.refusal_content_index_and_output: | ||
|
Uh oh!
There was an error while loading. Please reload this page.