Skip to content

fix: Enable Snowflake tool calling via Responses API - #58

Merged
josemaria-vilaplana merged 5 commits into
carto/mainfrom
fix/snowflake-tool-calling
Dec 12, 2025
Merged

fix: Enable Snowflake tool calling via Responses API#58
josemaria-vilaplana merged 5 commits into
carto/mainfrom
fix/snowflake-tool-calling

Conversation

@josemaria-vilaplana

Copy link
Copy Markdown

Summary

Completes Snowflake tool calling support for Responses API by fixing critical transformation issues.

Changes

  • Default tool_choice="auto" when tools present but not specified in Responses API
  • Fix tool_choice format transformation for Snowflake (string → object format)
  • Remove name field from tool_choice for "auto" type (only for "required")
  • Add custom streaming handler to transform Claude tool_use to OpenAI tool_calls format
  • Fix message transformations to include both content and content_list fields
  • Add comprehensive unit tests for Responses API → Snowflake transformation layer

Impact

Enables full tool calling functionality for Snowflake Cortex via Responses API. Before these fixes:

  • Tool calling via Responses API: ❌ (tools never called)
  • Streaming with tool calls: ❌ (tool_use blocks lost)
  • Tool choice transformation: ❌ (wrong format)

After these fixes: All working ✅

Test Plan

  • Added 3 new unit tests for tool_choice defaulting logic
  • Existing Snowflake tool transformation tests pass
  • Tested end-to-end with Responses API + Snowflake + Claude Sonnet 4.5

🤖 Generated with Claude Code

  - Add PAT token detection with pat/ prefix handling
  - Strip pat/ prefix and set PROGRAMMATIC_ACCESS_TOKEN header type
  - Add custom streaming handler for Claude models missing 'created' field
  - Fix tool_choice transformation and defaulting
  - Add streaming handler and tool_use response transformation
  - Complete message format with content + content_list fields
Resolved conflicts by:
- Keeping both message transformation tests and streaming handler tests
- Using SnowflakeStreamingHandler (with tool_use transformation) instead of SnowflakeChatCompletionStreamingHandler
- Adding get_model_response_iterator method to return custom streaming handler
Fixes "content or contentList must be provided" error when using
previous_response_id to continue conversations after tool execution.

Problem: Snowflake/Claude creates empty assistant messages (content: None
or "") when deciding to only call tools, resulting in consecutive assistant
messages. When these are loaded from session history, they fail Snowflake's
validation requiring either content or content_list.

Solution:
- Added _filter_empty_assistant_messages() method to remove assistant
  messages with no content and no tool_calls
- Applied filtering to all session loading paths (Redis and spend logs)
- Applied filtering to Redis storage to prevent storing empty messages

This ensures conversation history is clean regardless of whether it's
loaded from Redis (fast path) or spend logs (fallback path).
Fixes CI test failures:
1. Change empty content placeholder from space " " to empty string ""
   - Snowflake accepts empty string as valid content
   - Tests expect "" for None content normalization

2. Update tool_choice test to expect object format
   - Snowflake requires tool_choice as objects: {"type": "auto"}
   - String format caused "invalid request" errors in production
   - Test now validates correct transformation behavior

These changes ensure tests match the working production behavior.

@mateo-di mateo-di left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@josemaria-vilaplana
josemaria-vilaplana merged commit 0679959 into carto/main Dec 12, 2025
5 of 6 checks passed
@josemaria-vilaplana
josemaria-vilaplana deleted the fix/snowflake-tool-calling branch December 12, 2025 19:10
mateo-di added a commit that referenced this pull request Feb 10, 2026
…, #58

Port 5 CARTO features that were silently dropped during the v1.81.0
upstream sync due to class hierarchy refactoring:

- Add SnowflakeStreamingHandler for missing 'created' field and
  Claude-format tool_use -> OpenAI tool_calls transformation
- Add _transform_messages() for role="tool" -> Snowflake content_list
- Enhance _transform_tool_choice() to convert strings to Snowflake
  object format (e.g. "auto" -> {"type": "auto"})
- Add get_model_response_iterator() override
- Default tool_choice to "auto" when tools present in Responses API

Also adds .github/carto-features.yml manifest to track critical
customizations and prevent future sync regressions.
mateo-di added a commit that referenced this pull request Feb 10, 2026
Static registry of critical CARTO customizations that must survive
upstream syncs. The resolver should verify all patterns exist after
every sync to prevent silent feature regressions (like the OCI Gemini
and Snowflake tool calling drops in v1.81.0).

Tracks: OCI Gemini (#68), Snowflake streaming/tool calling (#38, #58),
Azure URL stripping (#70), JSON repair (#54), Redis sessions (#16).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants