Cursor Agent sends Responses API format to /chat/completions endpoint

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

When using a custom LLM provider via LiteLLM proxy configured with the OpenAI-compatible /chat/completions endpoint, Cursor Agent mode sends requests in OpenAI Responses API format instead of Chat Completions format. LiteLLM’s /chat/completions handler expects standard Chat Completions format, causing 400/500 errors.

Specific issues observed:

  • Request body uses input: […] instead of messages: […]
  • Responses API-only parameters are sent: store, include, prompt_cache_retention, previous_response_id, truncation, reasoning (as a dict), text (as a format object)
  • Tools are sent in flat Responses API format {“type”:“function”,“name”:“…”} instead of nested Chat Completions format {“type”:“function”,“function”:{“name”:“…”}}
  • Non-standard tool types are sent, e.g. {“type”:“custom”,“name”:“ApplyPatch”,…} with a grammar-based format field that has no equivalent in Chat Completions

Steps to Reproduce

  1. In Cursor settings, configure a custom LLM provider pointing to a LiteLLM proxy /chat/completions endpoint
  2. Select a model served by that provider
  3. Open the Agent panel and send any message
  4. Observe the request received by LiteLLM — it will be in Responses API format rather than Chat Completions format

Expected Behavior

Cursor should send requests to the /chat/completions endpoint in standard OpenAI Chat Completions format — specifically:

  • messages: […] as the conversation payload
  • Tools in nested format {“type”:“function”,“function”:{…}}
  • Only Chat Completions-compatible parameters

Operating System

Windows 10/11

Version Information

Version: 2.5.25 (user setup)
VSCode Version: 1.105.1
Commit: 7150844152b426ed50d2b68dd6b33b5c5beb73c0
Date: 2026-02-24T07:17:49.417Z
Build Type: Stable
Release Track: Default
Electron: 39.4.0
Chromium: 142.0.7444.265
Node.js: 22.22.0
V8: 14.2.231.22-electron.0
OS: Windows_NT x64 10.0.26100

For AI issues: which model did you use?

This occurs with any model configured through a custom LiteLLM provider. Confirmed with gpt-5.1 served via Azure OpenAI through LiteLLM proxy.

Additional Information

A workaround is possible but requires monkey-patching LiteLLM’s _read_request_body function at startup to intercept and convert the Responses API format to Chat Completions format before the request reaches the router. The patch needs to handle:

  • Converting input → messages
  • Converting flat tool definitions to nested function format
  • Converting {“type”:“custom”,…} tools to standard function tools
  • Converting reasoning: {“effort”: “…”} → reasoning_effort: “…”
  • Converting text: {“format”: {…}} → response_format
  • Stripping all remaining Responses API-only parameters

The fact that this workaround is needed at all — and its complexity — illustrates how far the Agent request format deviates from the Chat Completions spec on the /chat/completions endpoint.

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey, thanks for the report, this is a known issue.

What’s happening: when using BYOK with a base URL override, Cursor Agent sends an OpenAI Responses API payload (input, flat tool format, etc.) to the /chat/completions endpoint instead of using the Chat Completions format.

Related threads about the same issue:

The team is aware. There’s no ETA for a fix yet, but your detailed report, especially the breakdown of all the format mismatches, really helps with prioritization.

For now, the main solution is the workaround you already found, intercept and convert the payload on the proxy side. Another approach some users take is to avoid the base URL override and use Cursor’s built-in API routing, if that fits your setup.

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

I’m trying to use a custom openai compatible provider.
This looks like a bug in how Cursor is constructing the request to send to the AI provider

The error is saying that the API request being sent is malformed. Specifically:

  1. Missing messages array: The request is supposed to include a messages field (the conversation history to send to the AI), but it’s undefined - it’s not being included at all.

  2. 18 broken tool definitions: All the tools being sent have issues:

    • They’re missing a required function object
    • The type field has invalid values (showing “function” or “custom” when the API only accepts “web_search” or “web_search_preview”)

Steps to Reproduce

Setup OpenAi apikey with a custom base url.

Operating System

MacOS

Version Information

Version: 3.1.17
VSCode Version: 1.105.1
Commit: fce1e9ab7844f9ea35793da01e634aa7e50bce90
Date: 2026-04-19T19:33:58.189Z
Layout: editor
Build Type: Stable
Release Track: Default
Electron: 39.8.1
Chromium: 142.0.7444.265
Node.js: 22.22.1
V8: 14.2.231.22-electron.0
OS: Darwin arm64 25.3.0

For AI issues: which model did you use?

GPT 5.4

For AI issues: add Request ID with privacy disabled

Request ID: 4012efee-db83-494c-a919-bbffed5aff25

Does this stop you from using Cursor

Yes - Cursor is unusable

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

I am new to Cursor and using it with an OpenAI-compatible base URL. I set the OpenAI Base URL and Model in the Cursor IDE under Settings → Models → API Keys. Then I clicked Toggle Agents and sent a message to GPT 5.5 with medium reasoning.

I first got this error from my OpenAI-compatible endpoint:

Missing required parameter: ‘messages’

To debug, I put a small logging proxy in front of my endpoint and captured the request shape. When digging into it it appears that Cursor sends:

POST /openai/v1/chat/completions

But the JSON body is Responses API shaped, not Chat Completions shaped. It includes fields like:
{
“model”: “gpt-5.5”,
“input”: […],
“stream”: true,
“include”: [“reasoning.encrypted_content”],
“reasoning”: {“effort”: “medium”, “summary”: “auto”},
“text”: {“verbosity”: “low”},
“stream_options”: {“include_usage”: true}
}

This gets rejected by a Chat-Completions compatible endpoint because chat/completions expects messages, not input.

Then I tested a proxy workaround by:

  1. Rewriting /openai/v1/chat/completions to /openai/v1/responses.
  2. Remove stream_options from the request. From what I can tell, the Responses API supports stream_options: {"include_obfuscation": false}, but Cursor is sending stream_options: {"include_usage": true}, which seems specific to the Chat Completions API. This needed to be removed for the Responses request to succeed.
  3. Forwarding the Responses-shaped body upstream.

That makes the upstream request succeed. However, Cursor still does not render anything unless the proxy also translates the Responses SSE output back into Chat Completions streaming chunks using choices[].delta.

So Cursor appears to be using:

  • Request path: Chat Completions
  • Request body: Responses API
  • Expected output parser: Chat Completions streaming

Steps to Reproduce

Steps to reproduce:

  1. Configure Cursor with a custom OpenAI-compatible base URL.
  2. Use model gpt-5.5 with reasoning enabled.
  3. Send any prompt.
  4. Log the outbound request path and top-level JSON body keys.
  5. Observe that Cursor posts to /chat/completions with a Responses-style input body.

Expected Behavior

Expected behavior should be one of:

  1. Send Responses-shaped bodies to /v1/responses and parse Responses shaped results
  2. Or send Chat Completions-shaped bodies to /v1/chat/completions and parse Chat Completions chunks.

Operating System

MacOS

Version Information

Version: 3.2.14
VSCode Version: 1.105.1
Commit: 6e821a7fc68d5ce5b4ab821f73fe4137e0851e60
Date: 2026-04-28T13:25:40.706Z
Layout: editor
Build Type: Stable
Release Track: Default
Electron: 39.8.1
Chromium: 142.0.7444.265
Node.js: 22.22.1
V8: 14.2.231.22-electron.0
OS: Darwin arm64 25.3.0

For AI issues: which model did you use?

GPT 5.5

Does this stop you from using Cursor

No - Cursor works, but with this issue

It would be nice to get this prioritized and supported. There are a good number of dupes and reports spanning the past few months on this now and it’s a very opaque user experience that took me quite a while to diagnose what was going on. This behaves as if it is supported, and then fails strangely and unclearly.

Hey folks, I ran into the same issue and ended up building a small bridge for this:

It’s for Cursor OpenAI-compatible BYOK setups where Cursor sends a Responses-style payload to /v1/chat/completions, while still expecting Chat Completions-shaped streaming chunks back.

What it does:

  • accepts Cursor’s /v1/chat/completions request
  • detects Responses-style payloads
  • forwards them to an upstream /v1/responses endpoint
  • converts Responses API JSON/SSE back into Chat Completions format
  • optionally overrides reasoning.effort for selected models

I’m currently using it with an OpenAI-compatible gateway and GPT-5-style models, and it makes Cursor Agent usable again for that setup.

It’s not an official fix, just a pragmatic little compatibility bridge until Cursor handles this natively. Hope it helps someone else save a few hours of head-scratching :slight_smile:

Hey, thanks to both of you for the updates in this thread.

@JohnPostlethwait: I agree the UX here is confusing. The setup looks supported, then it fails in a weird way. We’re tracking the issue, and extra reports help us prioritize it. I can’t share an ETA for a fix yet. When I have an update, I’ll post it here.

@xiatian11: Thanks for the community bridge. It looks like a reasonable, pragmatic workaround for anyone stuck on BYOK with OpenAI-compatible gateways. It’s not an official solution and we don’t support it, but it’s useful for users who need to get unblocked right now.

Hey all!

This issue appears to be fixed now.

Could you give it a try and let us know, just in case there’s a different issue here?

This still is not working for me. I get the “User API Key Rate limit exceeded” just like I did before. The two steps are add a valid (for the endpoint) API key in the “OpenAI API Key” field, and a “Override OpenAI Bae URL” and every message I send to the GPT models gets the same “limit exceeded” message.

Tracing the call through it seems to use the completions API, and the call actually does get proxied all the way through to OpenAI and back, but Cursor itself as a client seems to handle it poorly when it comes back.

Happy to find any debug logs or traces you need to debug this further if you give me instructions for how to gather those.

Hey John, thanks for testing and getting back with the details.

Quick clarification on the fix Colin mentioned. It only specifically handled routing for gpt-5.5. For other GPT models via Override OpenAI Base URL, the behavior you’re describing is still on our radar. We’re tracking the issue, but I can’t share an ETA for a fix yet.

Your note that the request reaches OpenAI and returns, but Cursor mishandles the response and shows User API Key Rate limit exceeded, is really helpful since that doesn’t look like a real upstream rate limit. To log this as a separate case and avoid mixing it up with real rate limits, could you share:

  1. The exact GPT model, your Cursor version (Help > About), and your OS.
  2. The Request ID with Privacy Mode turned off:
    • Cursor Settings Ctrl+Shift+J > General > switch Privacy Mode to Share Data (if the toggle is locked, it’s enabled by your team admin).
    • Open the chat with the error > the ... menu in the top right > Copy Request ID.
  3. From your proxy: the request path and the top-level keys in the body (does it use input or messages, what do tools look like), plus what OpenAI returned and how Cursor logged it.

With that, we can confirm if it’s the same bug or a separate issue. Let me know.

Hey all,

The issue should be fully resolved now. Please give it another try!

When testing with GPT 5.5 I am still having an issue it looks like Cursor is still calling Chat Completions endpoint while sending a Responses style custom tool.

With GPT 5.5 selected, Agent mode, and an OpenAI-compatible base URL, Cursor is still calling:

POST /chat/completions

The captured request is Chat Completions shaped at the top level:

top_level_keys: [‘messages’, ‘model’, ‘stream’, ‘stream_options’, ‘tools’, ‘user’]
has input: false
has messages: true

But one of the tools is still Responses-style:

tool[7]: {
“type”: “custom”,
“name”: “ApplyPatch”,
“format”: {
“type”: “grammar”,

}
}

When this is sent through to OpenAI, OpenAI rejects it with:

Missing required parameter: ‘tools[7].custom’

Expected behavior should be one of:

  1. If Cursor calls /v1/chat/completions, it should send Chat Completions-compatible custom tools, with the custom payload nested under tools[i].custom.

  2. If Cursor wants to send Responses-style custom tools like { "type": "custom", "name": ..., "format": ... }, it should call /v1/responses instead

Hi @KungFuPanda!

This looks like the same issue as over here, and it should be something you can fix if you’re forwarding the requests yourself.