Skip to content

feat(ocr): add Cohere Parse support for cohere and azure_ai - #39862

Open
mateo-berri wants to merge 3 commits into
litellm_internal_stagingfrom
litellm_lit_6992_cohere_parse
Open

feat(ocr): add Cohere Parse support for cohere and azure_ai#39862
mateo-berri wants to merge 3 commits into
litellm_internal_stagingfrom
litellm_lit_6992_cohere_parse

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • /v1/ocr cannot serve Cohere Parse: cohere/ returns 500, Azure Foundry deployments 404
  • A customer needs Cohere Parse through LiteLLM on Cohere and Azure AI Foundry

How it solves it:

  • New cohere OCR config posting to Cohere's POST /v2/parse
  • azure_ai routes deployments named with both cohere and parse (the catalog default Cohere-parse-v5) to Foundry's Cohere Parse API, inlining remote images
  • Cost map entries bill Cohere Parse at $0.0015 a page on both providers
  • Health checks (/health, background health checks, the UI Test Connection button) probe each OCR deployment with a document its provider accepts: a new BaseOCRConfig.get_health_check_document() hook keeps the shared PDF for Mistral and Document Intelligence and sends a 1x1 PNG data URI for Cohere Parse, so Cohere Parse deployments no longer show as unhealthy
  • cohere gains ocr in the provider endpoint matrix served by /public/providers
  • The docs page entries for both providers are in litellm-docs#1215, which merges after this
  • SageMaker-hosted Parse is out of scope: no SageMaker deployment was exercised, so nothing is claimed for it

User Flow

Before: a proxy admin adds Cohere Parse to model_list and every /v1/ocr request fails before any text comes back

  1. They add cohere-parse (cohere/parse-v5.0 with their Cohere API key) and azure-cohere-parse (azure_ai/Cohere-parse-v5 with their Foundry endpoint and key) to model_list and start the proxy
  2. They send POST https://litellm-domain/v1/ocr with {"model": "cohere-parse", "document": {"type": "image_url", "image_url": "https://.../receipt.png"}}
  3. They get HTTP 500 litellm.APIConnectionError: OCR is not supported for provider: cohere
  4. They send the same POST https://litellm-domain/v1/ocr with "model": "azure-cohere-parse"
  5. They get HTTP 404 NotFoundError: Azure_aiException - {"error":{"code":"api_not_supported","message":"Requested API is currently not supported"}}
  6. No page text comes back from either call, so there is nothing to bill
  7. GET https://litellm-domain/health lists both deployments under unhealthy_endpoints with those same errors

After: the same two requests return the parsed page as markdown with a page count and a per-page cost

  1. They add cohere-parse (cohere/parse-v5.0 with their Cohere API key) and azure-cohere-parse (azure_ai/Cohere-parse-v5 with their Foundry endpoint and key) to model_list and start the proxy
  2. They send POST https://litellm-domain/v1/ocr with {"model": "cohere-parse", "document": {"type": "image_url", "image_url": "https://.../receipt.png"}}
  3. They get HTTP 200 with {"pages": [{"index": 0, "markdown": "# PLACE FACE UP ON DASH ..."}], "model": "parse-v5.0", "usage_info": {"pages_processed": 1}, "object": "ocr"} and the header x-litellm-response-cost: 0.0015
  4. They send the same POST https://litellm-domain/v1/ocr with "model": "azure-cohere-parse"
  5. They get HTTP 200 with the same page shape from their Foundry deployment, even though Foundry itself refuses to fetch https:// image URLs
  6. Adding "output_format": "blocks" returns Cohere's block layout under pages[].blocks, and "req_format": "native" returns Cohere's own response body unchanged
  7. Sending a document_url or a PDF gets HTTP 400 Cohere Parse only accepts image_url documents (an image URL or a base64 image data URI); document_url and PDF inputs are not supported. instead of a provider error, and every successful call carries x-litellm-response-cost: 0.0015, the per-page price spend tracking uses
  8. Uploading the image as a multipart file field instead of a URL (-F model=cohere-parse -F file=@receipt.png, or -F model=azure-cohere-parse) returns the same page at the same cost from either deployment
  9. GET https://litellm-domain/health lists both deployments under healthy_endpoints (the UI Test Connection button runs that same probe)

Relevant issues

Supersedes #39427

Linear ticket

Resolves LIT-6992

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • The handful of test files covering my change pass locally, e.g. uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*, make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
  • 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

Setup (shared by both legs): one proxy per leg, each started with python litellm/proxy/proxy_cli.py --config config.yaml --port <port> --num_workers 2 (two uvicorn workers, single instance, no database, LITELLM_LOCAL_MODEL_COST_MAP=True, keys read from .env). The Before leg is a detached worktree at the merge base 2151dcb on port 56915, the After leg is the PR tip 004a820 on port 37572. Both legs run the same curl script; the only difference is which commit the proxy was booted from

model_list:
  - model_name: cohere-parse
    litellm_params:
      model: cohere/parse-v5.0
      api_key: os.environ/COHERE_API_KEY
  - model_name: azure-cohere-parse
    litellm_params:
      model: azure_ai/Cohere-parse-v5
      api_base: os.environ/AZURE_AI_API_BASE
      api_key: os.environ/AZURE_AI_API_KEY
general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY

The Azure side is a Foundry resource with the catalog model Cohere-parse-v5 deployed under that same name (GlobalStandard, 3 requests a minute, so both legs sleep between Azure calls). The document is the public receipt image https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png

Before (2151dcb)

cohere_markdown

curl -s -D - http://localhost:56915/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}}'
http 500
x-litellm-call-id: bd4f9ab4-1aad-4155-b2e5-4fca500b3c07
x-litellm-response-cost: 0
{"error": {"message": "litellm.APIConnectionError: OCR is not supported for provider: cohere", "type": "internal_server_error", "param": null, "code": "500"}}

cohere_blocks

curl -s -D - http://localhost:56915/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}, "output_format": "blocks"}'
http 500
x-litellm-call-id: 38575015-f36c-4f6b-8c3a-6a95fa7a22f8
x-litellm-response-cost: 0
{"error": {"message": "litellm.APIConnectionError: OCR is not supported for provider: cohere", "type": "internal_server_error", "param": null, "code": "500"}}

cohere_native

curl -s -D - http://localhost:56915/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}, "req_format": "native"}'
http 500
x-litellm-call-id: 0b923b5f-dce6-49aa-b7aa-4789f0a078aa
x-litellm-response-cost: 0
{"error": {"message": "litellm.APIConnectionError: OCR is not supported for provider: cohere", "type": "internal_server_error", "param": null, "code": "500"}}

cohere_pdf_rejected

curl -s -D - http://localhost:56915/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "cohere-parse", "document": {"type": "document_url", "document_url": "https://arxiv.org/pdf/2201.04234"}}'
http 500
x-litellm-call-id: c42128ee-627d-468b-a214-079d8361b556
x-litellm-response-cost: 0
{"error": {"message": "litellm.APIConnectionError: OCR is not supported for provider: cohere", "type": "internal_server_error", "param": null, "code": "500"}}

cohere_bad_output_format

curl -s -D - http://localhost:56915/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}, "output_format": "html"}'
http 500
x-litellm-call-id: 02b2b9bb-1ef2-412f-ba26-aad285280986
x-litellm-response-cost: 0
{"error": {"message": "litellm.APIConnectionError: OCR is not supported for provider: cohere", "type": "internal_server_error", "param": null, "code": "500"}}

azure_markdown

curl -s -D - http://localhost:56915/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "azure-cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}}'
http 404
x-litellm-call-id: d809eb3b-8b42-4c22-a179-16c646505c2e
x-litellm-response-cost: 0
{"error": {"message": "litellm.NotFoundError: NotFoundError: Azure_aiException - {\"error\":{\"code\":\"api_not_supported\",\"message\":\"Requested API is currently not supported\",\"details\":\"Requested API is currently not supported\"}}. Received Model Group=azure-cohere-parse
Available Model Group Fallbacks=None", "type": "invalid_request_error", "param": null, "code": "404"}}

azure_blocks

curl -s -D - http://localhost:56915/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "azure-cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}, "output_format": "blocks"}'
http 404
x-litellm-call-id: e580fc66-512c-4367-81c0-114684209a85
x-litellm-response-cost: 0
{"error": {"message": "litellm.NotFoundError: NotFoundError: Azure_aiException - {\"error\":{\"code\":\"api_not_supported\",\"message\":\"Requested API is currently not supported\",\"details\":\"Requested API is currently not supported\"}}. Received Model Group=azure-cohere-parse
Available Model Group Fallbacks=None", "type": "invalid_request_error", "param": null, "code": "404"}}

azure_native

curl -s -D - http://localhost:56915/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "azure-cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}, "req_format": "native"}'
http 400
x-litellm-call-id: ba7a8d68-3370-4d1a-9054-7ceace594aa5
x-litellm-response-cost: 0
{"error": {"message": "litellm.UnsupportedParamsError: `req_format='native'` is not supported for provider: azure_ai, model: Cohere-parse-v5. Received Model Group=azure-cohere-parse
Available Model Group Fallbacks=None", "type": "invalid_request_error", "param": null, "code": "400"}}

azure_pdf_rejected

curl -s -D - http://localhost:56915/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "azure-cohere-parse", "document": {"type": "document_url", "document_url": "https://arxiv.org/pdf/2201.04234"}}'
http 404
x-litellm-call-id: 8452251e-2f9b-4cd9-930f-964739e4f8c2
x-litellm-response-cost: 0
{"error": {"message": "litellm.NotFoundError: NotFoundError: Azure_aiException - {\"error\":{\"code\":\"api_not_supported\",\"message\":\"Requested API is currently not supported\",\"details\":\"Requested API is currently not supported\"}}. Received Model Group=azure-cohere-parse
Available Model Group Fallbacks=None", "type": "invalid_request_error", "param": null, "code": "404"}}

cohere_multipart_file

curl -s -D - http://localhost:56915/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -F model=cohere-parse -F file=@receipt.png
http 500
x-litellm-response-cost: 0
{"error": {"message": "litellm.APIConnectionError: OCR is not supported for provider: cohere", "type": "internal_server_error", "param": null, "code": "500"}}

health

curl -s http://localhost:56915/health -H 'Authorization: Bearer $LITELLM_MASTER_KEY'
http 200
{
 "healthy_count": 0,
 "unhealthy_count": 2,
 "healthy_endpoints": [],
 "unhealthy_endpoints": [
  {
   "allow_client_keepalive_override": false,
   "use_in_pass_through": false,
   "use_litellm_proxy": false,
   "use_xai_oauth": false,
   "merge_reasoning_content_in_choices": false,
   "model": "cohere/parse-v5.0",
   "max_tokens": 16,
   "cache": {
    "no-cache": true
   },
   "error": "litellm.BadRequestError: CohereException - {\"id\":\"16688a57-9f4e-4435-a7ea-e1bdbb323589\",\"message\":\"invalid request: model 'parse-v5.0' is not compatible with this API\"}
stack trace: Traceback (most recent call last):
  File \"/Users/mateo/Development/litellm-worktrees/litellm_lit_6992_qa_base/litellm/llms/custom_httpx/llm_http_handler.py\", line 334, in _make_common_async_call
    response = await async_httpx_client.post(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File \"/Users/mateo/Development/litellm-worktrees/litellm_lit_6992_qa_base/litellm/litellm_core_utils/logging_utils.py\", line 300, in async_wrapper
    result: Final = await func(*args, **kwargs)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File \"/Users/mateo/Development/litellm-worktrees/litellm_lit_6992_qa_base/litellm/llms/custom_httpx/http_handler.py\", line 740, in post
    await _raise_masked_async_error(e, stream)
  File \"/Users/mateo/Development/litellm-worktrees/litellm_lit_6992_qa_base/litellm/llms/custom_httpx/http_handler.py\", line 505, in _raise_masked_async_error
    raise MaskedHTTP

After (004a820)

cohere_markdown

curl -s -D - http://localhost:37572/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}}'
http 200
x-litellm-call-id: 200a9cbd-e0e9-4643-bfb6-a59616a22bba
x-litellm-model-id: ccbab1568cbd684d618a718e68188aaf8e17f30d6d815b5123ea6b458c9f00a2
x-litellm-response-cost: 0.0015
x-litellm-response-cost-original: 0.0015
x-litellm-response-cost-discount-amount: 0.0
x-litellm-response-cost-margin-amount: 0.0
x-litellm-response-cost-margin-percent: 0.0
x-litellm-response-cost-input: 0.0015
x-litellm-response-cost-output: 0.0
x-litellm-response-cost-tool-usage: 0.0
{"pages": [{"index": 0, "markdown": "# PLACE FACE UP ON DASH
## CITY OF PALO ALTO

NOT VALID FOR
ONSTREET PARKING

Expiration Date/Time
**11:59 PM**
**AUG 19, 2024**

Purchase Date/Time: 01:34pm Aug 19, 2024
Total Due: $15.00
Total Paid: $15.00
Ticket #: 000058883
S/N #: 520117260957
Setting: Permit Machines
Mach Name: Civic Center

Rate: Daily Parking
Pmt Type: CC (Swipe)

#****-1224, Visa

DISPLAY FACE UP ON DASH

PERMIT EXPIRES
AT MIDNIGHT

![A vertical green strip running along the right edge of the receipt. It contains white text reading \"RECEIPT\" and \"PARKING RECEIPT\" repeated multiple times.](img-0)", "images": [{"image_base64": null, "bbox": {"top_left

cohere_blocks

curl -s -D - http://localhost:37572/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}, "output_format": "blocks"}'
http 200
x-litellm-call-id: 0846fe4d-9b1f-4240-85eb-a8ac42c4f63b
x-litellm-model-id: ccbab1568cbd684d618a718e68188aaf8e17f30d6d815b5123ea6b458c9f00a2
x-litellm-response-cost: 0.0015
x-litellm-response-cost-original: 0.0015
x-litellm-response-cost-discount-amount: 0.0
x-litellm-response-cost-margin-amount: 0.0
x-litellm-response-cost-margin-percent: 0.0
x-litellm-response-cost-input: 0.0015
x-litellm-response-cost-output: 0.0
x-litellm-response-cost-tool-usage: 0.0
{"pages": [{"index": 0, "markdown": "", "images": null, "dimensions": null, "blocks": [{"type": "text", "text": {"content": "# PLACE FACE UP ON DASH
## CITY OF PALO ALTO

NOT VALID FOR
ONSTREET PARKING

Expiration Date/Time
**11:59 PM**
**AUG 19, 2024**

Purchase Date/Time: 01:34pm Aug 19, 2024
Total Due: $15.00
Total Paid: $15.00
Ticket #: 000058883
S/N #: 520117260957
Setting: Permit Machines
Mach Name: Civic Center

Rate: Daily Parking
Pmt Type: CC (Swipe)

#****-1224, Visa

DISPLAY FACE UP ON DASH

PERMIT EXPIRES
AT MIDNIGHT"}}, {"type": "image", "image": {"id": "img-0", "description": "A vertical green strip running along the right edge of the receipt. It conta

cohere_native

curl -s -D - http://localhost:37572/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}, "req_format": "native"}'
http 200
x-litellm-call-id: 0c39a3d2-f828-48ce-8c44-cf1224b107b1
x-litellm-model-id: ccbab1568cbd684d618a718e68188aaf8e17f30d6d815b5123ea6b458c9f00a2
x-litellm-response-cost: 0.0015
x-litellm-response-cost-original: 0.0015
x-litellm-response-cost-discount-amount: 0.0
x-litellm-response-cost-margin-amount: 0.0
x-litellm-response-cost-margin-percent: 0.0
x-litellm-response-cost-input: 0.0015
x-litellm-response-cost-output: 0.0
x-litellm-response-cost-tool-usage: 0.0
{"id": "2cf7a457-b598-4d53-ac49-f2c5ea87e38e", "pages": [{"index": 0, "type": "markdown", "markdown": {"content": "# PLACE FACE UP ON DASH
## CITY OF PALO ALTO

NOT VALID FOR
ONSTREET PARKING

Expiration Date/Time
**11:59 PM**
**AUG 19, 2024**

Purchase Date/Time: 01:34pm Aug 19, 2024
Total Due: $15.00
Total Paid: $15.00
Ticket #: 000058883
S/N #: 520117260957
Setting: Permit Machines
Mach Name: Civic Center

Rate: Daily Parking
Pmt Type: CC (Swipe)

#****-1224, Visa

DISPLAY FACE UP ON DASH

PERMIT EXPIRES
AT MIDNIGHT

![A vertical green strip running along the right edge of the receipt. It contains white text reading \"RECEIPT\" and \"PARKING RECEIPT\" repeated 

cohere_pdf_rejected

curl -s -D - http://localhost:37572/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "cohere-parse", "document": {"type": "document_url", "document_url": "https://arxiv.org/pdf/2201.04234"}}'
http 400
x-litellm-call-id: 1c283ce0-ed98-48d4-b4b2-919b40f4ab8b
x-litellm-response-cost: 0
{"error": {"message": "litellm.BadRequestError: Cohere Parse only accepts `image_url` documents (an image URL or a base64 image data URI); `document_url` and PDF inputs are not supported.. Received Model Group=cohere-parse
Available Model Group Fallbacks=None", "type": "invalid_request_error", "param": null, "code": "400"}}

cohere_bad_output_format

curl -s -D - http://localhost:37572/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}, "output_format": "html"}'
http 400
x-litellm-call-id: e254fde0-208b-4532-91d8-16f8933dc704
x-litellm-response-cost: 0
{"error": {"message": "litellm.UnsupportedParamsError: Invalid `output_format`: 'html'. Expected one of markdown, blocks.. Received Model Group=cohere-parse
Available Model Group Fallbacks=None", "type": "invalid_request_error", "param": null, "code": "400"}}

azure_markdown

curl -s -D - http://localhost:37572/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "azure-cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}}'
http 200
x-litellm-call-id: 223e5964-b293-4001-bf29-36eddbb53f1d
x-litellm-model-id: bb22d5e6d925387ab3312077001ed3ba01105ae9bf9ee568ad8e466d21edca92
x-litellm-response-cost: 0.0015
x-litellm-response-cost-original: 0.0015
x-litellm-response-cost-discount-amount: 0.0
x-litellm-response-cost-margin-amount: 0.0
x-litellm-response-cost-margin-percent: 0.0
x-litellm-response-cost-input: 0.0015
x-litellm-response-cost-output: 0.0
x-litellm-response-cost-tool-usage: 0.0
{"pages": [{"index": 0, "markdown": "# PLACE FACE UP ON DASH
## CITY OF PALO ALTO

NOT VALID FOR
ONSTREET PARKING

Expiration Date/Time
**11:59 PM**
**AUG 19, 2024**

Purchase Date/Time: 01:34pm Aug 19, 2024
Total Due: $15.00
Total Paid: $15.00
Ticket #: 000058883
S/N #: 520117260957
Setting: Permit Machines
Mach Name: Civic Center

Rate: Daily Parking
Pmt Type: CC (Swipe)

#****-1224, Visa

DISPLAY FACE UP ON DASH

PERMIT EXPIRES
AT MIDNIGHT

![A vertical green strip running along the right edge of the receipt. It contains white text reading \"RECEIPT\" and \"PARKING RECEIPT\" repeated multiple times.](img-0)", "images": [{"image_base64": null, "bbox": {"top_left

azure_blocks

curl -s -D - http://localhost:37572/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "azure-cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}, "output_format": "blocks"}'
http 200
x-litellm-call-id: 809ebd73-0ced-4702-b63e-f52c15cdc411
x-litellm-model-id: bb22d5e6d925387ab3312077001ed3ba01105ae9bf9ee568ad8e466d21edca92
x-litellm-response-cost: 0.0015
x-litellm-response-cost-original: 0.0015
x-litellm-response-cost-discount-amount: 0.0
x-litellm-response-cost-margin-amount: 0.0
x-litellm-response-cost-margin-percent: 0.0
x-litellm-response-cost-input: 0.0015
x-litellm-response-cost-output: 0.0
x-litellm-response-cost-tool-usage: 0.0
{"pages": [{"index": 0, "markdown": "", "images": null, "dimensions": null, "blocks": [{"type": "text", "text": {"content": "# PLACE FACE UP ON DASH
## CITY OF PALO ALTO

NOT VALID FOR
ONSTREET PARKING

Expiration Date/Time
**11:59 PM**
**AUG 19, 2024**

Purchase Date/Time: 01:34pm Aug 19, 2024
Total Due: $15.00
Total Paid: $15.00
Ticket #: 000058883
S/N #: 520117260957
Setting: Permit Machines
Mach Name: Civic Center

Rate: Daily Parking
Pmt Type: CC (Swipe)

#****-1224, Visa

DISPLAY FACE UP ON DASH

PERMIT EXPIRES
AT MIDNIGHT"}}, {"type": "image", "image": {"id": "img-0", "description": "A vertical green strip running along the right edge of the receipt. It conta

azure_native

curl -s -D - http://localhost:37572/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "azure-cohere-parse", "document": {"type": "image_url", "image_url": "https://raw.githubusercontent.com/mistralai/cookbook/refs/heads/main/mistral/ocr/receipt.png"}, "req_format": "native"}'
http 200
x-litellm-call-id: 19975190-0971-469f-854b-d9814a24d8bc
x-litellm-model-id: bb22d5e6d925387ab3312077001ed3ba01105ae9bf9ee568ad8e466d21edca92
x-litellm-response-cost: 0.0015
x-litellm-response-cost-original: 0.0015
x-litellm-response-cost-discount-amount: 0.0
x-litellm-response-cost-margin-amount: 0.0
x-litellm-response-cost-margin-percent: 0.0
x-litellm-response-cost-input: 0.0015
x-litellm-response-cost-output: 0.0
x-litellm-response-cost-tool-usage: 0.0
{"id": "a9f40406-5529-48b2-b200-59c29788a70a", "pages": [{"index": 0, "type": "markdown", "markdown": {"content": "# PLACE FACE UP ON DASH
## CITY OF PALO ALTO

NOT VALID FOR
ONSTREET PARKING

Expiration Date/Time
**11:59 PM**
**AUG 19, 2024**

Purchase Date/Time: 01:34pm Aug 19, 2024
Total Due: $15.00
Total Paid: $15.00
Ticket #: 000058883
S/N #: 520117260957
Setting: Permit Machines
Mach Name: Civic Center

Rate: Daily Parking
Pmt Type: CC (Swipe)

#****-1224, Visa

DISPLAY FACE UP ON DASH

PERMIT EXPIRES
AT MIDNIGHT

![A vertical green strip running along the right edge of the receipt. It contains white text reading \"RECEIPT\" and \"PARKING RECEIPT\" repeated 

azure_pdf_rejected

curl -s -D - http://localhost:37572/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -H 'Content-Type: application/json' -d '{"model": "azure-cohere-parse", "document": {"type": "document_url", "document_url": "https://arxiv.org/pdf/2201.04234"}}'
http 400
x-litellm-call-id: 08c20bbe-5b75-4d96-9011-db29b1dde226
x-litellm-response-cost: 0
{"error": {"message": "litellm.BadRequestError: Cohere Parse only accepts `image_url` documents (an image URL or a base64 image data URI); `document_url` and PDF inputs are not supported.. Received Model Group=azure-cohere-parse
Available Model Group Fallbacks=None", "type": "invalid_request_error", "param": null, "code": "400"}}

cohere_multipart_file

curl -s -D - http://localhost:37572/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -F model=cohere-parse -F file=@receipt.png
http 200
x-litellm-model-id: ccbab1568cbd684d618a718e68188aaf8e17f30d6d815b5123ea6b458c9f00a2
x-litellm-response-cost: 0.0015
x-litellm-response-cost-original: 0.0015
x-litellm-response-cost-discount-amount: 0.0
x-litellm-response-cost-margin-amount: 0.0
x-litellm-response-cost-margin-percent: 0.0
x-litellm-response-cost-input: 0.0015
x-litellm-response-cost-output: 0.0
x-litellm-response-cost-tool-usage: 0.0
{"pages": [{"index": 0, "markdown": "# PLACE FACE UP ON DASH
## CITY OF PALO ALTO

NOT VALID FOR
ONSTREET PARKING

Expiration Date/Time
**11:59 PM**
**AUG 19, 2024**

Purchase Date/Time: 01:34pm Aug 19, 2024
Total Due: $15.00
Total Paid: $15.00
Ticket #: 000058883
S/N #: 520117260957
Setting: Permit Machines
Mach Name: Civic Center

Rate: Daily Parking
Pmt Type: CC (Swipe)

#*

azure_cohere_multipart_file

curl -s -D - http://localhost:37572/v1/ocr -H 'Authorization: Bearer $LITELLM_MASTER_KEY' -F model=azure-cohere-parse -F file=@receipt.png
http 200
x-litellm-model-id: bb22d5e6d925387ab3312077001ed3ba01105ae9bf9ee568ad8e466d21edca92
x-litellm-response-cost: 0.0015
x-litellm-response-cost-original: 0.0015
x-litellm-response-cost-discount-amount: 0.0
x-litellm-response-cost-margin-amount: 0.0
x-litellm-response-cost-margin-percent: 0.0
x-litellm-response-cost-input: 0.0015
x-litellm-response-cost-output: 0.0
x-litellm-response-cost-tool-usage: 0.0
{"pages": [{"index": 0, "markdown": "# PLACE FACE UP ON DASH
## CITY OF PALO ALTO

NOT VALID FOR
ONSTREET PARKING

Expiration Date/Time
**11:59 PM**
**AUG 19, 2024**

Purchase Date/Time: 01:34pm Aug 19, 2024
Total Due: $15.00
Total Paid: $15.00
Ticket #: 000058883
S/N #: 520117260957
Setting: Permit Machines
Mach Name: Civic Center

Rate: Daily Parking
Pmt Type: CC (Swipe)

#*

health

curl -s http://localhost:37572/health -H 'Authorization: Bearer $LITELLM_MASTER_KEY'
http 200
{
 "healthy_count": 2,
 "unhealthy_count": 0,
 "healthy_endpoints": [
  {
   "allow_client_keepalive_override": false,
   "use_in_pass_through": false,
   "use_litellm_proxy": false,
   "use_xai_oauth": false,
   "merge_reasoning_content_in_choices": false,
   "model": "cohere/parse-v5.0",
   "cache": {
    "no-cache": true
   },
   "model_id": "ccbab1568cbd684d618a718e68188aaf8e17f30d6d815b5123ea6b458c9f00a2"
  },
  {
   "api_base": "https://devinfoundryqa33856.services.ai.azure.com",
   "allow_client_keepalive_override": false,
   "use_in_pass_through": false,
   "use_litellm_proxy": false,
   "use_xai_oauth": false,
   "merge_reasoning_content_in_choices": false,
   "model": "azure_ai/Cohere-parse-v5",
   "cache": {
    "no-cache": true
   },
   "model_id": "bb22d5e6d925387ab3312077001ed3ba01105ae9bf9ee568ad8e466d21edca92"
  }
 ],
 "unhealthy_endpoints": []
}

Health check at the previous tip d3a179f

Before the health-check hook, every Cohere Parse deployment failed its ocr health probe because the shared PDF document was sent to Parse. The same two SDK calls (real keys, no proxy) at the previous tip:

$ cd <worktree at d3a179f988> && python - <<'PY'
import asyncio, litellm, os
print(asyncio.run(litellm.ahealth_check(model_params={"model": "cohere/parse-v5.0"}, mode="ocr"))["error"][:170])
print(asyncio.run(litellm.ahealth_check(model_params={"model": "azure_ai/Cohere-parse-v5", "api_base": os.environ["AZURE_AI_API_BASE"], "api_key": os.environ["AZURE_AI_API_KEY"]}, mode="ocr"))["error"][:170])
PY
litellm.BadRequestError: Cohere Parse only accepts `image_url` documents (an image URL or a base64 image data URI); `document_url` and PDF inputs are not supported.
litellm.BadRequestError: Cohere Parse only accepts `image_url` documents (an image URL or a base64 image data URI); `document_url` and PDF inputs are not supported.

Type

🆕 New Feature

Caveats (if any)

Medium

  • Azure AI Foundry routing keys on the deployment name: a name carrying both cohere and parse goes to Cohere Parse, anything else (parse-v5, north-parse) stays on the Mistral OCR path and gets the Mistral 404 it gets today. Foundry takes the body's model as the deployment name, so the LiteLLM model name has to be the deployment name and there is no per-deployment override; the workaround is a deployment name with both words, which the catalog default Cohere-parse-v5 has. Cost tracking keys on the name too: only azure_ai/Cohere-parse-v5 is in the cost map, so a deployment under another name records $0 spend with a warning log unless its entry sets model_info.base_model: azure_ai/Cohere-parse-v5. The docs (litellm-docs#1215) state both rules
  • The Foundry passthrough route (/azure_ai/... with the deployment's own URL) is not touched here: that failure is owned by fix(azure_ai): add passthrough config so router-model relays reach the deployment's own endpoint #39863 (LIT-7022). Until it lands, /v1/ocr is the working path for Foundry Cohere Parse

Low

  • PDF and document_url inputs return 400 by design because the live Cohere Parse API rejects anything but PNG, JPEG, WebP, and GIF today; if Cohere adds PDF support the guard has to be relaxed
  • Only the cohere/ prefix routes to Parse; cohere_chat/parse-v5.0 is not accepted
  • An api_base that already ends in /v1 gets /v2/parse appended verbatim, so Cohere-compatible gateways must be configured with the host only
  • Spend-log rows were not inspected: the QA rig runs without a database, so spend is evidenced by the x-litellm-response-cost header only
  • The azure_ai/Cohere-parse-v5 cost map entry carries Cohere's list price ($1.50 per 1,000 pages): Azure's Foundry Cohere pricing page has no Parse row and the Foundry catalog's View pricing link points at Cohere's blog, so the entry needs updating if Azure publishes its own row, and until then a Foundry invoice can differ from what LiteLLM records
  • The UI Test Connection button was not clicked on the rig (it needs a database); the probe it runs, ahealth_check with no mode, was called live for both models and came back healthy after resolving ocr from the cost map
  • A Foundry deployment whose name is not in the cost map (say azure_ai/my-parse-deploy) health-checks as chat unless model_info.mode: ocr is set, the same convention every other non-chat model follows
  • Foundry Cohere Parse is a Preview model (retirement date 2026-12-15, carried as the cost map entry's deprecation_date for /model/deprecations) and intermittently answers api_not_supported or RateLimitReached on valid requests; LiteLLM surfaces those as NotFoundError and RateLimitError, and the same call succeeds on retry
  • No tests/e2e/ case or coverage-registry row is added; coverage is unit tests plus the live curl legs below
  • Every health probe of a Cohere Parse deployment is a real one-page Parse call and bills $0.0015; at a 5-minute background health check interval that is about $0.43 a day per deployment
  • Any cohere/... model sent to /v1/ocr gets the Parse config, so a non-Parse Cohere model fails at Cohere's API rather than with a LiteLLM error
  • COHERE_API_BASE is not read for OCR (only an explicit api_base is), matching the Mistral OCR config, which ignores MISTRAL_API_BASE the same way
  • The Rust OCR bridge bypass (supports_rust_bridge() returning False for both configs) is covered by unit tests only; the live legs ran the Python path
  • The multipart file upload has an After leg on both providers but a Before leg only on Cohere; at the merge base the Foundry deployment takes the same Mistral OCR path as the JSON Before leg and gets the same api_not_supported 404
  • The docs land separately in litellm-docs#1215 after this merges, and SageMaker-hosted Parse is out of scope (nothing was exercised there)
  • CircleCI proxy_store_model_in_db_tests is red on this branch only: staging's test(store_model_in_db): assert the 400 contract in the unknown-model spend log test #39842 relaxed that spend-log assertion after this branch's merge base (LIT-6949 tracks the flake), so the merge onto staging fixes it

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
  • 004a820 passes /live-pr-risk

@codspeed-hq

codspeed-hq Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_lit_6992_cohere_parse (004a820) with litellm_internal_staging (aea5358)

Open in CodSpeed

@greptile-apps

greptile-apps Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds Cohere Parse OCR support for direct Cohere and Azure AI Foundry deployments, including request and response transformations, image inlining for Foundry, native responses, health-check inputs, endpoint metadata, pricing, and focused tests

  • Routes Azure deployments containing both Cohere and Parse identifiers to the Foundry Cohere Parse endpoint
  • Normalizes markdown, block, image, and billed-page response data
  • Uses provider-appropriate image documents for Cohere Parse health checks
  • Adds per-page pricing and OCR capability metadata

Confidence Score: 5/5

The PR appears safe to merge with no new actionable failures identified

The changes since the previous review correctly add provider-specific health-check documents and capability metadata without introducing a confirmed regression. The earlier Azure routing thread was manually resolved without explanation

Important Files Changed

Filename Overview
litellm/llms/cohere/ocr/transformation.py Implements Cohere Parse request validation, transformation, response normalization, native payload handling, and image-only health checks
litellm/llms/azure_ai/ocr/cohere_parse_transformation.py Adapts Cohere Parse for Azure AI Foundry authentication, endpoint construction, and remote-image inlining
litellm/litellm_core_utils/health_check_helpers.py Selects health-check documents through each provider’s OCR configuration
litellm/llms/azure_ai/ocr/common_utils.py Adds Cohere Parse selection while retaining existing Document Intelligence and Mistral routing
litellm/ocr/main.py Lets provider OCR configurations opt out of the Rust bridge
model_prices_and_context_window.json Adds OCR mode and per-page pricing for direct and Azure-hosted Cohere Parse models

Reviews (3): Last reviewed commit: "fix(ocr): send each provider a health-ch..." | Re-trigger Greptile

Comment thread litellm/llms/azure_ai/ocr/common_utils.py Outdated
@codecov

codecov Bot commented Sep 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.52475% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/llms/cohere/ocr/transformation.py 97.05% 4 Missing ⚠️
...m/llms/azure_ai/ocr/cohere_parse_transformation.py 97.43% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri mateo-berri added run-ci and removed run-ci labels Sep 5, 2026
@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

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.

Stale Bugbot comment from a previous run.

Health checks probed every OCR deployment with a PDF, which Cohere Parse
rejects, so /health, background health checks, and the UI Test Connection
button marked Cohere Parse deployments unhealthy. BaseOCRConfig gains a
get_health_check_document hook (PDF by default) that CohereParseConfig
overrides with a 1x1 PNG data URI. cohere also gains ocr in the provider
endpoint matrix
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri mateo-berri added run-ci and removed run-ci labels Sep 5, 2026
@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 004a820. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant