Skip to content

fix(cursor): translate chat completion content blocks to Responses API input - #34782

Open
devin-ai-integration[bot] wants to merge 1 commit into
litellm_internal_stagingfrom
litellm_cursor_bridge_image_url
Open

fix(cursor): translate chat completion content blocks to Responses API input#34782
devin-ai-integration[bot] wants to merge 1 commit into
litellm_internal_stagingfrom
litellm_cursor_bridge_image_url

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • /cursor/chat/completions rejects any request containing images
  • Chat content blocks were fed raw into Responses API

How it solves it:

  • Run messages through the existing chat -> Responses converter
  • System messages now become instructions instead of raw input

Relevant issues

Fixes #34777

Linear ticket

Pre-Submission checklist

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Live proxy (python litellm/proxy/proxy_cli.py --config litellm/proxy/dev_config.yaml), real OpenAI call with a base64 PNG of a blue rectangle

Request body (req.json), built once and reused for both runs:

python -c "
from PIL import Image, ImageDraw
import base64, io, json
im=Image.new('RGB',(200,120),'white')
d=ImageDraw.Draw(im); d.rectangle([20,20,180,100],fill='blue')
b=io.BytesIO(); im.save(b,format='PNG')
enc=base64.b64encode(b.getvalue()).decode()
json.dump({'model':'gpt-5.5','messages':[{'role':'user','content':[{'type':'text','text':'What color is the rectangle in this image? Answer with one word.'},{'type':'image_url','image_url':{'url':'data:image/png;base64,'+enc}}]}]},open('req.json','w'))
"

Before, at 2412326:

curl -s -X POST http://localhost:4000/cursor/chat/completions \
  -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" -d @req.json
{"error":{"message":"litellm.BadRequestError: OpenAIException - {\n  \"error\": {\n    \"message\": \"Invalid value: 'text'. Supported values are: 'input_text', 'input_image', 'output_text', 'refusal', 'input_file', 'computer_screenshot', 'summary_text', and 'encrypted_content'.\",\n    \"type\": \"invalid_request_error\",\n    \"param\": \"input[0].content[0].type\",\n    \"code\": \"invalid_value\"\n  }\n}. Received Model Group=gpt-5.5\nAvailable Model Group Fallbacks=None","type":null,"param":null,"code":"400"}}

After, at 3bc9339 (same curl):

{"id":"chatcmpl-6001b2b4-8204-458c-8090-fcb543399620","created":1785157998,"model":"gpt-5.5","object":"chat.completion","choices":[{"finish_reason":"stop","index":0,"message":{"content":"Blue","role":"assistant"}}]}

(response truncated to the interesting fields; the model correctly read the image and answered "Blue")

Type

🐛 Bug Fix

Changes

cursor_chat_completions used to do data["input"] = data.pop("messages"), handing Chat-Completions-shaped content blocks (text, image_url) to a path that validates Responses API shapes (input_text, input_image), so every vision request died before reaching the provider. It now reuses responses_api_bridge.transformation_handler.convert_chat_completion_messages_to_responses_api, the same converter the completion-to-responses bridge uses, which maps text and image blocks, tool calls and tool outputs, and pulls system prompts out into instructions. Requests that already send Responses-shaped input are untouched

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

Link to Devin session: https://app.devin.ai/sessions/492caaec5f254cfa84612c8c00beb717

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR converts Cursor Chat Completions message payloads into Responses API inputs.

  • Reuses the existing chat-to-Responses converter for text, image, tool, and system-message handling.
  • Preserves requests that already provide a Responses API input.
  • Adds endpoint tests for image conversion, system instructions, and pass-through Responses input.

Confidence Score: 3/5

The PR should not merge until the conversion preserves assistant text accompanying tool calls and system prompts alongside explicit instructions.

The newly applied converter can silently remove two forms of conversation context on valid mixed-content request shapes, causing the provider to answer from an incomplete prompt.

Files Needing Attention: litellm/proxy/response_api_endpoints/endpoints.py

Important Files Changed

Filename Overview
litellm/proxy/response_api_endpoints/endpoints.py Adds message conversion but exposes loss of assistant text accompanying tool calls and drops converted system prompts when explicit instructions coexist.
tests/test_litellm/proxy/response_api_endpoints/test_endpoints.py Adds focused transformation coverage, but does not cover assistant content plus tool calls or combined system messages and explicit instructions.

Reviews (1): Last reviewed commit: "fix(cursor): translate chat completion c..." | Re-trigger Greptile

Comment on lines +343 to +345
) = responses_api_bridge.transformation_handler.convert_chat_completion_messages_to_responses_api(
data.pop("messages")
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Assistant text is dropped

When an assistant message contains both nonempty content and tool calls, the converter emits only the function-call items and skips the content branch, causing the assistant's text to disappear from subsequent conversation history.

Comment on lines +347 to +348
if instructions and not data.get("instructions"):
data["instructions"] = instructions

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 System instructions are discarded

When a request contains both a system message and a nonempty instructions field, conversion removes the system message from input but this guard prevents adding its text to instructions, causing that part of the prompt to be silently omitted.

@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/proxy/response_api_endpoints/endpoints.py 66.66% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_cursor_bridge_image_url (3bc9339) with litellm_internal_staging (2412326)

Open in CodSpeed

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.

Cursor bridge endpoint (/cursor/chat/completions) doesn't translate image_url content blocks to Responses API format

1 participant