Skip to content

fix(openai): make object and created fields optional in CompletionResponse#1451

Open
DAMEK86 wants to merge 1 commit into0xPlaygrounds:mainfrom
DAMEK86:fix/azure-copilot-optional-fields
Open

fix(openai): make object and created fields optional in CompletionResponse#1451
DAMEK86 wants to merge 1 commit into0xPlaygrounds:mainfrom
DAMEK86:fix/azure-copilot-optional-fields

Conversation

@DAMEK86
Copy link

@DAMEK86 DAMEK86 commented Mar 2, 2026

Problem

Azure-flavored OpenAI endpoints (including GitHub Copilot API) return chat completion responses that omit the object and created fields. The current CompletionResponse struct requires both fields, causing deserialization to fail with:

missing field `object` at line X column Y

This prevents rig-core from being used with Azure OpenAI Service, GitHub Copilot API, and other Azure-flavored OpenAI-compatible endpoints.

Example: Standard OpenAI response (works today)

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "created": 1700000000,
  "model": "gpt-4o",
  "usage": { "prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15 }
}

Example: Azure/Copilot response (fails today, works after this PR)

{
  "id": "chatcmpl-xyz789",
  "model": "gpt-4o",
  "choices": [{ "index": 0, "message": { "role": "assistant", "content": "Review complete." }, "finish_reason": "stop", "content_filter_results": {} }],
  "usage": { "prompt_tokens": 20, "completion_tokens": 10, "total_tokens": 30 },
  "prompt_filter_results": [{ "prompt_index": 0 }]
}

Solution

Changed object from String to Option<String> and created from u64 to Option<u64>, both with #[serde(default)]. These fields are not accessed anywhere in rig-core's logic — they only participate in deserialization — so this is a fully backwards-compatible change.

Tests

Added two deserialization tests:

  • deserialize_standard_openai_response — confirms standard OpenAI responses still work
  • deserialize_azure_copilot_response_without_object_and_created — confirms Azure/Copilot responses now deserialize correctly

Verified with

  • GitHub Copilot API (chat completions via GHE) — end-to-end working
  • All existing tests pass

thx for this nice lib <3

CC @olFi95

Copy link
Collaborator

@joshua-mo-143 joshua-mo-143 left a comment

Choose a reason for hiding this comment

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

Are you guys using the OpenAI module? We have an Azure OpenAI provider module that might be better suited for this change

(edit: sorry please disregard the review - just wanted to comment but muscle memory kicked in 😅 )

@DAMEK86
Copy link
Author

DAMEK86 commented Mar 2, 2026

nono, it's fine. give me a bit to check if we can use it.
It was already a hassle to figure out which api is available on our ghe ;)

@DAMEK86
Copy link
Author

DAMEK86 commented Mar 2, 2026

Scraping over the GHE endpoints, it seems only the OpenAI protocol-based EP is available.

Copilot API uses {base}/chat/completions (no /openai/deployments/ prefix). So the Azure provider's URL pattern doesn't match the Copilot API.

┌─────────────────────────────────────────────────────────────┬────────────────┐
│ Endpoint                                                    │ Status         │
├─────────────────────────────────────────────────────────────┼────────────────┤
│ /chat/completions                                           │ ✅ 200 (works) │  
├─────────────────────────────────────────────────────────────┼────────────────┤
│ /openai/deployments/gpt-4o/chat/completions?api-version=... │ ❌ 404         │
├─────────────────────────────────────────────────────────────┼────────────────┤
│ /v1/chat/completions                                        │ ❌ 404         │  
├─────────────────────────────────────────────────────────────┼────────────────┤
│ /models                                                     │ ✅ 200         │
└─────────────────────────────────────────────────────────────┴────────────────┘
  

The idea is to reuse the GHE instead of a public GitHub Copilot subscription. I assume Azure uses a non-Copilot/OpenAI protocol.
If I can check something, pls let me know. Maybe I missed something while reverse engineering the API. Until then, this works right now ;)

@DAMEK86 DAMEK86 force-pushed the fix/azure-copilot-optional-fields branch 2 times, most recently from 676713c to 0fac6fa Compare March 2, 2026 14:34
@DAMEK86
Copy link
Author

DAMEK86 commented Mar 2, 2026

Update: It seems the copilot api is based on OpenAI and works quite well for their models; however, if we try to use Claude models, additional response handling is required.

I'm not sure whether this fits your rig design or if an additional OpenAI-derived copilot provider is a better fit.

@joshua-mo-143
Copy link
Collaborator

Hmmmmm. I think at this point an OpenAI derived copilot provider may fit the purpose better. It's quite easy to get Claude or another model to simply spin up the necessary provider code anyway and then we can move as required.

The main issue with just adding it onto the OpenAI Chat Completions API is that if we add too many fields onto it, it's going to start diverging which will be quite bad in the future if we need to spin up more providers based on the original OpenAI integration

DAMEK86 added a commit to DAMEK86/rig that referenced this pull request Mar 10, 2026
…rsing

The Copilot API exposes an OpenAI-compatible /chat/completions endpoint
but omits several response fields that the standard OpenAI specification
requires (object, created, finish_reason). This provider derives from
the OpenAI module, reusing its request/message types while relaxing the
response contract with Option<T> + serde(default).

Key differences from the OpenAI provider:
- CompletionResponse.object: Option<String> (omitted by Copilot API)
- CompletionResponse.created: Option<u64> (omitted by Copilot API)
- Choice.finish_reason: Option<String> (omitted by Claude via Copilot)
- ApiErrorResponse handles both 'message' and 'error' field shapes
- Bearer auth with COPILOT_API_KEY / GITHUB_TOKEN env vars
- Completions-only (no embeddings, image, audio, transcription)

Addresses review feedback on PR 0xPlaygrounds#1451: creates a dedicated provider
instead of patching optional fields onto the OpenAI module.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
DAMEK86 added a commit to DAMEK86/rig that referenced this pull request Mar 10, 2026
…rsing

The Copilot API exposes an OpenAI-compatible /chat/completions endpoint
but omits several response fields that the standard OpenAI specification
requires (object, created, finish_reason). This provider derives from
the OpenAI module, reusing its request/message types while relaxing the
response contract with Option<T> + serde(default).

Key differences from the OpenAI provider:
- CompletionResponse.object: Option<String> (omitted by Copilot API)
- CompletionResponse.created: Option<u64> (omitted by Copilot API)
- Choice.finish_reason: Option<String> (omitted by Claude via Copilot)
- ApiErrorResponse handles both 'message' and 'error' field shapes
- Bearer auth with COPILOT_API_KEY / GITHUB_TOKEN env vars
- Completions-only (no embeddings, image, audio, transcription)
- Well-known model constants for GPT-4o, Claude Sonnet 4, Gemini Flash, o3-mini
  (non-exhaustive — users should pass model name as string for newer models)

Addresses review feedback on PR 0xPlaygrounds#1451: creates a dedicated provider
instead of patching optional fields onto the OpenAI module.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DAMEK86
Copy link
Author

DAMEK86 commented Mar 12, 2026

@joshua-mo-143 do u like a new MR for the topic, or is overriding the current one fine for u?

It took a bit to create and verify the new implementation ;)

@joshua-mo-143
Copy link
Collaborator

@joshua-mo-143 do u like a new MR for the topic, or is overriding the current one fine for u?

It took a bit to create and verify the new implementation ;)

Overriding the current one is OK

@DAMEK86 DAMEK86 force-pushed the fix/azure-copilot-optional-fields branch from ec3c17d to 74c928c Compare March 12, 2026 13:24
…rsing

The Copilot API exposes an OpenAI-compatible /chat/completions endpoint
but omits several response fields that the standard OpenAI specification
requires (object, created, finish_reason). This provider derives from
the OpenAI module, reusing its request/message types while relaxing the
response contract with Option<T> + serde(default).

Key differences from the OpenAI provider:
- CompletionResponse.object: Option<String> (omitted by Copilot API)
- CompletionResponse.created: Option<u64> (omitted by Copilot API)
- Choice.finish_reason: Option<String> (omitted by Claude via Copilot)
- ApiErrorResponse handles both 'message' and 'error' field shapes
- Bearer auth with COPILOT_API_KEY / GITHUB_TOKEN env vars
- Completions-only (no embeddings, image, audio, transcription)
- Well-known model constants for GPT-4o, Claude Sonnet 4, Gemini Flash, o3-mini
  (non-exhaustive — users should pass model name as string for newer models)

Addresses review feedback on PR 0xPlaygrounds#1451: creates a dedicated provider
instead of patching optional fields onto the OpenAI module.
@DAMEK86 DAMEK86 force-pushed the fix/azure-copilot-optional-fields branch from 74c928c to b949ace Compare March 12, 2026 19:11
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.

2 participants