refactor: add stream_content() abstract method to Provider#276
Merged
refactor: add stream_content() abstract method to Provider#276
Conversation
3 tasks
…() concrete Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace stream_text() with stream_content() returning Content objects (ContentText/ContentThinking) instead of raw strings on all five provider implementations: Anthropic, OpenAI, Google, OpenAI Completions, and Snowflake. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…g for content='all' - Add content_text() helper to extract displayable text from Content objects - Thread content_mode parameter from _chat_impl to _submit_turns - Use stream_content() instead of stream_text() in streaming loops - Yield ContentThinking objects when content="all" mode is active - Use model_construct() for streaming ContentText to avoid the whitespace-to-"[empty string]" validator corrupting raw chunks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Handle thinking parts in non-streaming Google responses by checking
part.get("thought") and emitting ContentThinking. Also add CHANGELOG
entry for the stream_content() refactor.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
40b7a4e to
c20438a
Compare
- Add ContentThinking to all content="all" overload return types so callers know they can receive thinking content during streaming - Restore reasoning_summary_text.done separator in OpenAI provider that was accidentally dropped during the stream_content() refactor - Revert unrelated formatting changes to _content_expand.py and _parallel.py to keep the PR focused Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add overloads to _submit_turns/_submit_turns_async so content_mode="text" narrows return type to Generator[str], fixing ChatResponse type mismatch - Fix Google provider stream_content() optional subscript error by guarding against None candidates before indexing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR refactors the provider streaming interface to return structured
Contentobjects instead of raw strings, mirroring ellmer'sstream_text()→stream_content()refactor. This is the foundation for upcoming partial turn preservation and cooperative stream cancellation (#279).Motivation
Currently, each provider's
stream_text()method returnsOptional[str], which loses type information about what kind of content was streamed (plain text vs. thinking/reasoning). By switching tostream_content()that returnsOptional[Content](specificallyContentTextorContentThinking), we can:content="all"to yieldContentThinkingobjects rather than plain stringsContentobjects to a partialAssistantTurnduring streaming, so if the stream is interrupted, the accumulated content is preservedChanges
chatlas/_provider.py:stream_text()is no longer abstract. New abstractstream_content()returnsOptional[Content]. The concretestream_text()delegates tostream_content()and extracts the text string (preserving backwards compatibility for any code that callsstream_text()directly)All providers (
_provider_anthropic.py,_provider_openai.py,_provider_google.py,_provider_openai_completions.py,_provider_snowflake.py): Renamedstream_text()→stream_content(), now returnContentText.model_construct()orContentThinkingas appropriate. Usesmodel_construct()to bypass Pydantic'sContentTextvalidator that corrupts whitespace-only streaming chunks (e.g.,"\n"→"[empty string]")chatlas/_chat.py:_submit_turnsand_submit_turns_asyncnow callstream_content()instead ofstream_text(). Whencontent="all",ContentThinkingobjects are yielded directly (not as strings), allowing callers to distinguish thinking from text contentGoogle provider: Replaced the
chunk.textshortcut with explicitparts[0]access to correctly detectthought=Trueon parts and returnContentThinkingfor thinking contentTest plan
content="text"(the default)🤖 Generated with Claude Code