Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Bug fixes

* `ChatSnowflake()` now supports Anthropic extended thinking content (e.g. from `claude-sonnet-5`) in both streaming and non-streaming responses. Previously, the thinking deltas sent by Snowflake Cortex raised `ValueError: Unexpected streaming delta type: anthropic`.

* `ChatBedrock()` (with the default `api="converse"`) no longer sends assistant turns with an empty `content` array, which Converse rejects. This happens when a response carries no content blocks, for example when a guardrail intervenes before the model produces any. A `"[empty string]"` placeholder is sent instead, matching how empty text content is already normalized. (#426)


Expand Down
2 changes: 1 addition & 1 deletion chatlas/_content_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def content_image_file(
"Install it with `pip install pillow-heif`, or pass "
"`resize='none'` to send the original bytes without resizing."
)
pillow_heif.register_heif_opener()
pillow_heif.register_heif_opener() # pyright: ignore[reportPrivateImportUsage]

if resize == "none":
with open(path, "rb") as image_file:
Expand Down
37 changes: 36 additions & 1 deletion chatlas/_provider_snowflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
Content,
ContentJson,
ContentText,
ContentThinking,
ContentThinkingDelta,
ContentToolRequest,
ContentToolResult,
)
Expand Down Expand Up @@ -389,7 +391,12 @@ def stream_content(self, chunk, completion, turns=()) -> list[Content]:
if not chunk.choices:
return []
delta = chunk.choices[0].delta
if delta is None or "content" not in delta:
if delta is None:
return []
if delta.get("type") == "anthropic":
thinking = delta["content_list"][-1]["anthropic"]["thinking"].get("thinking")
return [ContentThinkingDelta(thinking=thinking)] if thinking else []
if "content" not in delta:
return []
return [ContentText.model_construct(text=delta["content"])]

Expand Down Expand Up @@ -457,6 +464,24 @@ def stream_merge_chunks(self, completion, chunk):
# if we don't find it, just append to the end
# this shouldn't happen, but just in case
content_list.append({"type": "text", "text": text})
elif new_delta["type"] == "anthropic":
# Extended thinking blocks stream in as a "thinking" fragment
# followed by a "signature" fragment, both under the same item.
new_thinking = new_content_list[-1]["anthropic"]["thinking"]
for i in range(len(content_list) - 1, -1, -1):
if content_list[i].get("type") == "anthropic":
thinking = content_list[i]["anthropic"]["thinking"]
if "thinking" in new_thinking:
thinking["thinking"] = (
thinking.get("thinking", "") + new_thinking["thinking"]
)
if "signature" in new_thinking:
thinking["signature"] = (
thinking.get("signature", "") + new_thinking["signature"]
)
break
else:
content_list.append(new_content_list[-1])
else:
raise ValueError(
f"Unexpected streaming delta type: {new_delta['type']}. Please report this issue."
Expand Down Expand Up @@ -582,6 +607,16 @@ def _as_turn(self, completion: "Completion", has_data_model: bool) -> AssistantT
contents.append(ContentJson(value=data))
else:
contents.append(ContentText(text=content["text"]))
elif "anthropic" in content:
thinking = content["anthropic"].get("thinking", {})
contents.append(
ContentThinking(
thinking=thinking.get("thinking", ""),
extra={"signature": thinking["signature"]}
if "signature" in thinking
else None,
)
)
elif "tool_use_id" in content:
params = content.get("input", "{}")
try:
Expand Down
6 changes: 6 additions & 0 deletions chatlas/data/bedrock_apis.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@
"openai.gpt-5.6-luna": "responses",
"openai.gpt-5.6-sol": "responses",
"openai.gpt-5.6-terra": "responses",
"openai.gpt-daybreak-blue-5.6-sol": "responses",
"us-gov-east-1/openai.gpt-5.4": "responses",
"us-gov-east-1/xai.grok-4.6": "responses",
"us-gov-west-1/google.gemma-4-26b-a4b": "responses",
"us-gov-west-1/google.gemma-4-31b": "responses",
"us-gov-west-1/google.gemma-4-e2b": "responses",
"us-gov-west-1/openai.gpt-5.4": "responses",
"us-gov-west-1/openai.gpt-5.6-luna": "responses",
"us-gov-west-1/openai.gpt-5.6-terra": "responses",
"us-gov-west-1/xai.grok-4.3": "responses",
"us-gov-west-1/xai.grok-4.6": "responses",
"xai.grok-4.3": "responses"
}
Loading