From 3d7b34f923628b4032f27b6a844eac93c5b66dbd Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 19 Feb 2026 12:06:21 -0600 Subject: [PATCH 1/3] fix: add `last_render_height` to custom LiveRender for rich >= 14.3.0 compat Closes #268 Co-Authored-By: Claude Opus 4.6 --- chatlas/_live_render.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/chatlas/_live_render.py b/chatlas/_live_render.py index a4f6e172..4f55e8f2 100644 --- a/chatlas/_live_render.py +++ b/chatlas/_live_render.py @@ -37,6 +37,13 @@ def __init__( self.vertical_overflow = vertical_overflow self._shape: Optional[Tuple[int, int]] = None + @property + def last_render_height(self) -> int: + """The number of lines in the last render (0 if nothing was rendered).""" + if self._shape is None: + return 0 + return self._shape[1] + def set_renderable(self, renderable: RenderableType) -> None: """Set a new renderable. From 06d3eff48c7e12e13d43fdbf8fc80ca8631a16fb Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 19 Feb 2026 18:00:19 -0600 Subject: [PATCH 2/3] fix: update Anthropic provider for SDK v0.82+ compatibility The Anthropic SDK (v0.82+) introduced breaking changes that caused three CI failures: 1. **WebFetchBlock attribute error**: The SDK now returns proper `BetaWebFetchBlock` objects for `web_fetch_tool_result` content instead of raw dicts. Updated code to use `getattr()` for URL extraction and `model_dump()` for serialization. 2. **VCR cassette body mismatch**: The SDK added a `caller` field (serialized as `null`) to `WebSearchToolResultBlock` and `ServerToolUseBlock`. This caused VCR body matching to fail on multi-turn tests. Fixed by manually constructing the `extra` dict from known API fields (consistent with how `server_tool_use` was already handled) rather than using `model_dump()` directly. 3. **Outdated provider types**: New models (claude-opus-4-6, claude-sonnet-4-6), tool types (CodeExecutionTool, MemoryTool, WebFetchTool, etc.), and parameters (container, inference_geo, ThinkingConfigAdaptiveParam) were added. Regenerated types via `make update-types`. Co-Authored-By: Claude Opus 4.6 --- chatlas/_provider_anthropic.py | 33 ++++++++++++++++++++--------- chatlas/types/anthropic/_submit.py | 34 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/chatlas/_provider_anthropic.py b/chatlas/_provider_anthropic.py index 7a95c0de..fca0c871 100644 --- a/chatlas/_provider_anthropic.py +++ b/chatlas/_provider_anthropic.py @@ -825,32 +825,45 @@ def _as_turn(self, completion: Message, has_data_model=False) -> AssistantTurn: urls: list[str] = [] if isinstance(content.content, list): urls = [x.url for x in content.content] + # Manually construct the extra dict to avoid SDK-internal + # fields (e.g., "caller") that the API doesn't accept + extra = { + "type": content.type, + "tool_use_id": content.tool_use_id, + "content": [ + x.model_dump() for x in content.content + ] + if isinstance(content.content, list) + else content.content.model_dump(), + } contents.append( ContentToolResponseSearch( urls=urls, - extra=content.model_dump(), + extra=extra, ) ) elif content.type == "web_fetch_tool_result": # N.B. type checker thinks this is unreachable due to # ToolUnionParam not including BetaWebFetchTool20250910Param - # yet. Also, at run-time, the SDK is currently giving non-sense - # of type(content) == TextBlock, but it doesn't even fit that - # shape?!? Anyway, content.content has a dict with the content - # we want. - content_fetch = cast("dict", getattr(content, "content", {})) - if not content_fetch: + # yet. + content_fetch = getattr(content, "content", None) + if content_fetch is None: raise ValueError( "web_fetch_tool_result content is empty. Please report this issue." ) + # content_fetch is a BetaWebFetchBlock (has .url) or + # BetaWebFetchToolResultErrorBlock (error case) + url = getattr(content_fetch, "url", "failed") + # Manually construct the extra dict to avoid SDK-internal + # fields (e.g., "caller") that the API doesn't accept extra = { - "type": "web_fetch_tool_result", + "type": content.type, "tool_use_id": content.tool_use_id, # type: ignore - "content": content_fetch, + "content": content_fetch.model_dump(exclude_none=True), } contents.append( ContentToolResponseFetch( - url=content_fetch.get("url", "failed"), + url=url, extra=extra, ) ) diff --git a/chatlas/types/anthropic/_submit.py b/chatlas/types/anthropic/_submit.py index f013e53c..de02d6bd 100644 --- a/chatlas/types/anthropic/_submit.py +++ b/chatlas/types/anthropic/_submit.py @@ -6,8 +6,15 @@ from typing import Iterable, Literal, Mapping, Optional, Sequence, TypedDict, Union import anthropic +import anthropic.types.cache_control_ephemeral_param +import anthropic.types.code_execution_tool_20250522_param +import anthropic.types.code_execution_tool_20250825_param +import anthropic.types.code_execution_tool_20260120_param +import anthropic.types.memory_tool_20250818_param import anthropic.types.message_param +import anthropic.types.output_config_param import anthropic.types.text_block_param +import anthropic.types.thinking_config_adaptive_param import anthropic.types.thinking_config_disabled_param import anthropic.types.thinking_config_enabled_param import anthropic.types.tool_bash_20250124_param @@ -16,10 +23,15 @@ import anthropic.types.tool_choice_none_param import anthropic.types.tool_choice_tool_param import anthropic.types.tool_param +import anthropic.types.tool_search_tool_bm25_20251119_param +import anthropic.types.tool_search_tool_regex_20251119_param import anthropic.types.tool_text_editor_20250124_param import anthropic.types.tool_text_editor_20250429_param import anthropic.types.tool_text_editor_20250728_param +import anthropic.types.web_fetch_tool_20250910_param +import anthropic.types.web_fetch_tool_20260209_param import anthropic.types.web_search_tool_20250305_param +import anthropic.types.web_search_tool_20260209_param class SubmitInputArgs(TypedDict, total=False): @@ -27,6 +39,8 @@ class SubmitInputArgs(TypedDict, total=False): messages: Iterable[anthropic.types.message_param.MessageParam] model: Union[ Literal[ + "claude-opus-4-6", + "claude-sonnet-4-6", "claude-opus-4-5-20251101", "claude-opus-4-5", "claude-3-7-sonnet-latest", @@ -50,6 +64,16 @@ class SubmitInputArgs(TypedDict, total=False): ], str, ] + cache_control: Union[ + anthropic.types.cache_control_ephemeral_param.CacheControlEphemeralParam, + None, + anthropic.Omit, + ] + container: Union[str, None, anthropic.Omit] + inference_geo: Union[str, None, anthropic.Omit] + output_config: ( + anthropic.types.output_config_param.OutputConfigParam | anthropic.Omit + ) service_tier: Union[Literal["auto", "standard_only"], anthropic.Omit] stop_sequences: Union[Sequence[str], anthropic.Omit] stream: Union[Literal[False], Literal[True], anthropic.Omit] @@ -60,6 +84,7 @@ class SubmitInputArgs(TypedDict, total=False): thinking: Union[ anthropic.types.thinking_config_enabled_param.ThinkingConfigEnabledParam, anthropic.types.thinking_config_disabled_param.ThinkingConfigDisabledParam, + anthropic.types.thinking_config_adaptive_param.ThinkingConfigAdaptiveParam, anthropic.Omit, ] tool_choice: Union[ @@ -74,10 +99,19 @@ class SubmitInputArgs(TypedDict, total=False): Union[ anthropic.types.tool_param.ToolParam, anthropic.types.tool_bash_20250124_param.ToolBash20250124Param, + anthropic.types.code_execution_tool_20250522_param.CodeExecutionTool20250522Param, + anthropic.types.code_execution_tool_20250825_param.CodeExecutionTool20250825Param, + anthropic.types.code_execution_tool_20260120_param.CodeExecutionTool20260120Param, + anthropic.types.memory_tool_20250818_param.MemoryTool20250818Param, anthropic.types.tool_text_editor_20250124_param.ToolTextEditor20250124Param, anthropic.types.tool_text_editor_20250429_param.ToolTextEditor20250429Param, anthropic.types.tool_text_editor_20250728_param.ToolTextEditor20250728Param, anthropic.types.web_search_tool_20250305_param.WebSearchTool20250305Param, + anthropic.types.web_fetch_tool_20250910_param.WebFetchTool20250910Param, + anthropic.types.web_search_tool_20260209_param.WebSearchTool20260209Param, + anthropic.types.web_fetch_tool_20260209_param.WebFetchTool20260209Param, + anthropic.types.tool_search_tool_bm25_20251119_param.ToolSearchToolBm25_20251119Param, + anthropic.types.tool_search_tool_regex_20251119_param.ToolSearchToolRegex20251119Param, ] ], anthropic.Omit, From 46d56124a89057e662180d0f05a81953d0620639 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 19 Feb 2026 18:21:02 -0600 Subject: [PATCH 3/3] chore: update OpenAI response types for context_management param Co-Authored-By: Claude Opus 4.6 --- chatlas/types/openai/_submit_responses.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/chatlas/types/openai/_submit_responses.py b/chatlas/types/openai/_submit_responses.py index cb569df6..8ddfa966 100644 --- a/chatlas/types/openai/_submit_responses.py +++ b/chatlas/types/openai/_submit_responses.py @@ -43,6 +43,11 @@ class SubmitInputArgs(TypedDict, total=False): background: Union[bool, None, openai.Omit] + context_management: Union[ + Iterable[openai.types.responses.response_create_params.ContextManagement], + None, + openai.Omit, + ] conversation: Union[ str, openai.types.responses.response_conversation_param.ResponseConversationParam,