Skip to content

refactor(responses): extract shared format mapping between Responses API and Chat Completions bridges - #24417

Merged
Chesars merged 3 commits into
BerriAI:litellm_staging_03_23_2026from
Chesars:refactor/shared-format-mapping
Mar 23, 2026
Merged

refactor(responses): extract shared format mapping between Responses API and Chat Completions bridges#24417
Chesars merged 3 commits into
BerriAI:litellm_staging_03_23_2026from
Chesars:refactor/shared-format-mapping

Conversation

@Chesars

@Chesars Chesars commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

Fixes #21346

Pre-Submission checklist

  • I have Added testing in the tests/test_litellm/ directory, Adding at least 1 test is a hard requirement - see details
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Type

🧹 Refactoring

Changes

Both Responses API bridges (Responses→CC and CC→Responses) independently encoded the same field mapping knowledge across separate files with no cross-reference. This caused:

This PR extracts 4 shared mappings into litellm/responses/format_mapping.py:

# Mapping Before After
1 status ↔ finish_reason Two separate functions in two files Shared dicts + wrapper functions
2 provider_specific_fields extraction Normalize-to-dict boilerplate repeated 6x Single normalize_provider_specific_fields() helper
3 response_format ↔ text.format Two inverse functions in two files Paired functions in shared module
4 Usage field names (input_tokens ↔ prompt_tokens, etc.) ~90 lines duplicated per direction Paired functions in shared module

…API and Chat Completions bridges

Both bridges (Responses→CC and CC→Responses) independently encoded the
same field mapping knowledge. This extracts 4 shared mappings into a
single module so future changes only need to happen in one place.

Shared mappings:
- status ↔ finish_reason bidirectional dicts and functions
- response_format ↔ text.format paired conversion functions
- provider_specific_fields normalization helper
- usage field name translation (input_tokens ↔ prompt_tokens, etc.)

No behavioral changes — bridge methods now delegate to the shared module.
@vercel

vercel Bot commented Mar 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
litellm Ready Ready Preview, Comment Mar 23, 2026 2:50pm

Request Review

@codspeed-hq

codspeed-hq Bot commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 16 untouched benchmarks


Comparing Chesars:refactor/shared-format-mapping (4c9f866) with main (c89496f)

Open in CodSpeed

@greptile-apps

greptile-apps Bot commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extracts shared bidirectional mapping logic between the Responses API and Chat Completions bridges into a new litellm/responses/format_mapping.py module, eliminating ~6 occurrences of duplicated boilerplate across three files and establishing a single source of truth for status↔finish_reason, usage field, response_format↔text.format, and provider_specific_fields normalization.

Key changes:

  • New format_mapping.py: Seven public functions/constants covering all four mapping domains, with inline documentation of known asymmetries (e.g. "failed"/"cancelled" collapse to "stop", "text" format returns None in CC direction).
  • Mutation fix: response_api_usage_to_chat_usage now makes a defensive copy (dict(usage_input)) before mutating, preventing silent side-effects on the caller's dict — an improvement over the original utils.py code.
  • normalize_provider_specific_fields returns None (not {}) for unrecognized provider_specific_fields types, making the or short-circuit in litellm_completion_transformation/transformation.py:1545 safe.
  • Test coverage: New tests/test_litellm/responses/test_format_mapping.py provides thorough unit tests with roundtrip cases; no real network calls are made.
  • The test_from_dict test in TestResponseApiUsageToChatUsage only asserts prompt_tokens, missing assertions for completion_tokens and total_tokens which could allow future regressions to go undetected.

Confidence Score: 4/5

  • Safe to merge — purely a refactoring with no behavioral changes and solid test coverage
  • The extraction is semantically faithful to the original code in all four mapping domains. The one notable improvement (defensive dict copy in response_api_usage_to_chat_usage) is strictly safer than before. The only concern is one incomplete test assertion that weakens coverage rather than the production logic itself.
  • No files require special attention; the only minor issue is the incomplete assertions in tests/test_litellm/responses/test_format_mapping.py

Important Files Changed

Filename Overview
litellm/responses/format_mapping.py New shared module with 4 bidirectional mapping utilities. Well-structured with clear inline documentation of asymmetries. response_api_usage_to_chat_usage now correctly makes a defensive copy of dict input. Minor: status_to_finish_reason is defined but has no production call site yet.
litellm/completion_extras/litellm_responses_transformation/transformation.py Removes 6 occurrences of inline provider_specific_fields normalization boilerplate, replaced with normalize_provider_specific_fields(). Dead instance method _map_responses_status_to_finish_reason removed. Behaviorally equivalent after considering the shared helper now returns None (not {}) for unrecognized types.
litellm/responses/litellm_completion_transformation/transformation.py Removes ~130 lines of duplicated usage/format/status mapping logic, replaced with shared helpers. The or chain for normalize_provider_specific_fields(tool) or normalize_provider_specific_fields(function_definition) is safe since the helper returns None (falsy) rather than {}.
litellm/responses/utils.py Thin delegation to response_api_usage_to_chat_usage from the shared module. Behaviorally equivalent. Top-level import added for the shared function.
tests/test_litellm/responses/test_format_mapping.py New test file with comprehensive unit tests covering all 4 mapping functions in both directions, including roundtrip tests. Tests are purely unit tests with no network calls — compliant with the no-real-network-calls policy.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Before["Before (duplicated logic)"]
        direction TB
        A["completion_extras/\nlitellm_responses_transformation/\ntransformation.py\n(Responses→CC)"] -- "own copy of:\n• status→finish_reason\n• PSF normalization\n• text.format→response_format\n• Usage mapping" --> B["responses/\nlitellm_completion_transformation/\ntransformation.py\n(CC→Responses)"]
    end

    subgraph After["After (shared module)"]
        direction TB
        C["completion_extras/\nlitellm_responses_transformation/\ntransformation.py"] --> E["responses/format_mapping.py\n\nnormalize_provider_specific_fields()\nstatus_to_finish_reason()\nfinish_reason_to_status()\nresponse_format_to_text_format()\ntext_format_to_response_format()\nresponse_api_usage_to_chat_usage()\nchat_usage_to_response_api_usage()"]
        D["responses/\nlitellm_completion_transformation/\ntransformation.py"] --> E
        F["responses/utils.py\n(logging)"] --> E
    end
Loading

Comments Outside Diff (1)

  1. tests/test_litellm/responses/test_format_mapping.py, line 1095-1100 (link)

    P2 Incomplete test assertions in test_from_dict

    test_from_dict only asserts prompt_tokens but never validates completion_tokens or total_tokens. A future regression in the output_tokenscompletion_tokens mapping would pass this test silently.

    Rule Used: What: Flag any modifications to existing tests and... (source)

Reviews (3): Last reviewed commit: "fix: avoid mutating caller's dict and re..." | Re-trigger Greptile

Comment thread litellm/responses/utils.py
Comment thread litellm/responses/format_mapping.py
Comment thread litellm/responses/format_mapping.py Outdated
Comment thread litellm/responses/format_mapping.py Outdated
@Chesars
Chesars changed the base branch from main to litellm_staging_03_23_2026 March 23, 2026 15:51
@Chesars
Chesars merged commit 3f3d275 into BerriAI:litellm_staging_03_23_2026 Mar 23, 2026
38 of 39 checks passed
@Chesars
Chesars deleted the refactor/shared-format-mapping branch March 23, 2026 15:55
Chesars added a commit that referenced this pull request Apr 25, 2026
…-mapping"

This reverts commit 3f3d275, reversing
changes made to 498c113.
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
…mapping

refactor(responses): extract shared format mapping between Responses API and Chat Completions bridges
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
…-format-mapping"

This reverts commit 3f3d275, reversing
changes made to 498c113.
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.

Shared mapping utilities between Responses API and Chat Completions bridges

1 participant