opencode icon indicating copy to clipboard operation
opencode copied to clipboard

Azure OpenAi generated URL is wrong? (/v1/) added in between

Open enlilz opened this issue 6 months ago • 21 comments

It seems that the generated URL for the Azure OpenAI service is adding a /v1/ in between. If I'm wrong and it has something todo with my config, I'm sorry then please point me to the problem and close the issue.

using opencode version 0.3.110

my custom provider config:

{
  "$schema": "https://opencode.ai/config.json",
  "model": "Foundry/o3-mini",
  "provider": {
    "Foundry": {
      "npm": "@ai-sdk/azure",
      "name": "Foundry",
      "options": {
        "baseURL": "https://<removed>.openai.azure.com/openai/deployments/o3-mini",
        "apiKey": "{env:AZURE_KEY_O3MINI}",
        "apiVersion": "2025-01-01-preview"
      },
      "models": {
        "o3-mini": {
          "name": "o3-mini"
        }
      }
    }
  }
}

Accual used URL

https://removed.openai.azure.com/openai/deployments/o3-mini/v1/chat/completions?api-version=2025-01-01-preview

Expected URL (as by Azure OpenAi

https://removed.openai.azure.com/openai/deployments/o3-mini/chat/completions?api-version=2025-01-01-preview

the error message where you can see that the used url was wrong

{
    "error": {
        "name": "AI_APICallError",
        "url": "https://<removed>.openai.azure.com/openai/deployments/o3-mini/v1/chat/completions?api-version=2025-01-01-preview",
        "requestBodyValues": {
            "model": "o3-mini",
            "max_completion_tokens": 32000,
            "messages": [
                {
                    "role": "developer",
                    "content": "<removed>"
                },
                {
                    "role": "developer",
                    "content": "<removed>"
                },
                {
                    "role": "user",
                    "content": "write bash hello world"
                }
            ],
            "tools": ["<removed>"],
            "tool_choice": "auto",
            "stream": true,
            "stream_options": {
                "include_usage": true
            }
        },
        "statusCode": 404,
        "responseHeaders": {
            "apim-request-id": "3b1a9292-9501-4f88-9389-38613332b4e7",
            "content-length": "56",
            "content-type": "application/json",
            "date": "Fri, 01 Aug 2025 12:11:05 GMT",
            "strict-transport-security": "max-age=31536000; includeSubDomains; preload",
            "x-content-type-options": "nosniff"
        },
        "responseBody": {
            "error": {
                "code": "404",
                "message": "Resource not found"
            }
        },
        "isRetryable": false,
        "data": {
            "error": {
                "message": "Resource not found",
                "code": "404"
            }
        }
    }
}

Azure OpenAi curl example example

curl -X POST "https://<removed>.openai.azure.com/openai/deployments/o3-mini/chat/completions?api-version=2025-01-01-preview \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $AZURE_API_KEY" \
    -d '{
        "messages": [
            {
                "role": "user",
                "content": "I am going to Paris, what should I see?"
            }
        ],
        "max_completion_tokens": 100000,
        "model": "o3-mini"
    }'

enlilz avatar Aug 01 '25 15:08 enlilz

To me, it looks like ai-sdk updated to the more current Azure API which includes /v1/ in the path:

https://github.com/vercel/ai/issues/7372

For me, in my opencode/config.json, I changed my "baseURL" from:

"https:<url>/openai/deployments" to:

"https:<url>/openai/"

I also deleted the apiVersion as it seemed to not be supported now.

mhumphriestx avatar Aug 08 '25 15:08 mhumphriestx

No every Azure OpenAI endpoint supports the /v1 - this needs to be optional

alexhupfer avatar Aug 12 '25 07:08 alexhupfer

ISTM that Azure does not provide great documentation of the new API when you're adding a new deployment.

AFAICT it is mostly possible to exchange the following (i.e. the "old style"):

https://<removed>.openai.azure.com/openai/deployments/<deployment>/chat/completions?api-version=2025-01-01-preview

with

https://<removed>.openai.azure.com/openai/v1/chat/completions?api-version=preview

(The model name should be provided in the json body.)

meanderix avatar Aug 12 '25 08:08 meanderix

I tried to create a new model but at the creation process i did not get any opportunity to select the API type also not when i try to edit them after the creation.

after some Microsoft doc digging i found this.

Only a subset of dataplane authoring features are currently supported with the v1 API. A subset of dataplane inference and dataplane authoring features are supported with the v1 preview API.

Azure OpenAI in Azure AI Foundry Models v1 REST API reference

The rest of the article covers our new v1 preview API release of the Azure OpenAI data plane inference specification. Learn more in our API lifecycle guide. If you're looking for documentation on the latest GA API release, refer to the latest GA data plane inference API

Azure OpenAI in Azure AI Foundry Models REST API v1 preview reference

so i guess, "some" party have already adopted the v1 API but i guess mostly there eval and grading endpoints

enlilz avatar Aug 13 '25 08:08 enlilz

+1 for making it optional.

In my company we also have endpoints like:

  • https://....azure-api.net/openai/deployments/gpt-5/chat/completions?api-version=2025-01-01-preview

and it gets generated by opencode like:

  • https://....azure-api.net/openai/deployments/gpt-5/v1/chat/completions?api-version=2025-01-01-preview

I had to add LiteLLM in between with such opencode.json:

{
    "$schema": "https://opencode.ai/config.json",
    "provider": {
        "mycompany": {
            "npm": "@ai-sdk/openai-compatible",
            "name": "MyCompany Azure OpenAI",
            "options": {
                "baseURL": "http://0.0.0.0:4000/",
                "apiKey": "...",
                "headers": {
                    "api-key": "..."
                }
            },
            "models": {
                "mycompany-gpt-5": {
                    "name": "MyCompany GPT-5"
                },
                "mycompany-gpt-4.1": {
                    "name": "MyCompany GPT-4.1"
                }
            }
        }
    },
    "model": "mycompany/mycompany-gpt-4.1"
}

Can I help providing a fix?

tbrandenburg avatar Aug 15 '25 06:08 tbrandenburg

@tbrandenburg I think a fix would be welcome, go ahead

rekram1-node avatar Aug 15 '25 13:08 rekram1-node

Hej guys,

I found this setting in Vercel's AI SDK: https://github.com/vercel/ai/blob/main/content/providers/01-ai-sdk-providers/04-azure.mdx?plain=1#L89

I would probably go down this way.

Other ideas?

tbrandenburg avatar Aug 16 '25 06:08 tbrandenburg

Hej guys,

I found this setting in Vercel's AI SDK: https://github.com/vercel/ai/blob/main/content/providers/01-ai-sdk-providers/04-azure.mdx?plain=1#L89

I would probably go down this way.

Other ideas?

my thoughts: if that could be configurable via the provider configuration in opencode that might be nice, since we will not know when Microsoft decides to switch complete to the new API or old deployments might keep using the old style even after.

enlilz avatar Aug 16 '25 11:08 enlilz

Hej guys,

I found this setting in Vercel's AI SDK: https://github.com/vercel/ai/blob/main/content/providers/01-ai-sdk-providers/04-azure.mdx?plain=1#L89

I would probably go down this way.

Other ideas?

This seems to work for chat completions, but not the responses API

alexhupfer avatar Aug 19 '25 08:08 alexhupfer

Stupid question (currently travelling just with my mobile): Is opencode using the Azure responses API?

tbrandenburg avatar Aug 19 '25 19:08 tbrandenburg

@tbrandenburg yes: https://github.com/sst/opencode/blob/40bdbf92a368952812954f512b8ded56fc5cb1dd/packages/opencode/src/provider/provider.ts#L48-L56

rekram1-node avatar Aug 19 '25 20:08 rekram1-node

Hej guys,

diving deeper I realized that the JSON-options are actually passed to the provider creation method. So I tried running with:

{
    "$schema": "https://opencode.ai/config.json",
    "provider": {
        "azure": {
            "npm": "@ai-sdk/azure",
            "name": "MyCompany Azure OpenAI",
            "options": {
                "baseURL": "https://mycompany.azure-api.net/openai/",
                "useDeploymentBasedUrls": true,
                "apiKey": "...",
                "apiVersion": "2024-12-01-preview",
                "headers": {
                    "api-key": "..."
                }
            },
            "models": {
                "gpt-5": {
                    "name": "MyCompany GPT-5"
                }
            }
        }
    },
    "model": "azure/gpt-5"
}

And it worked! 🎉

Out of the logs I could see that the URL used is: https://mycompany.azure-api.net/openai/deployments/gpt-5/chat/completions?api-version=2024-12-01-preview

I also think that Responses API is supported looking at https://github.com/vercel/ai/blob/main/packages/azure/src/azure-openai-provider.ts#L153.

Can somebody else test as well?

tbrandenburg avatar Aug 20 '25 13:08 tbrandenburg

we're not using deployments for the responses API just https://subdomain.openai.azure.com/openai/responses?api-version=2025-03-01-preview - so this does not work either.

alexhupfer avatar Aug 20 '25 13:08 alexhupfer

worth noting responses api is not available in every region at the time of writing this our internally allowed deployment regions are not in that list.

fermumen avatar Aug 20 '25 14:08 fermumen

we're not using deployments for the responses API just https://subdomain.openai.azure.com/openai/responses?api-version=2025-03-01-preview - so this does not work either.

Which results into a contribution to Vercel's SDK and how it is building the URL, right?

tbrandenburg avatar Aug 20 '25 15:08 tbrandenburg

using the config flag, changes the url back from v1 to deployments "useDeploymentBasedUrls": true,

but now i can see that the url that is generated is a "responses" not chat completion

so the newly generated URL is

https://resourcename.cognitiveservices.azure.com/openai/deployments/o4-mini/responses?api-version=2025-01-01-preview

but should be

https://resourcename.cognitiveservices.azure.com/openai/deployments/o4-mini/chat/completions?api-version=2025-01-01-preview

is there another flag i can set in the config to make it aware that the model is chat completion not responses?

not sure if that is the correct code part

opencode/packages/opencode/src/provider/provider.ts

azure: async () => { return { autoload: false, async getModel(sdk: any, modelID: string) { return sdk.responses(modelID) }, options: {}, } }, and if i understand the VercelAI code correctly there should also be the option to load

completion(deploymentId: string): LanguageModelV2; instead of responses(deploymentId: string): LanguageModelV2;

so that this should be like that?

opencode/packages/opencode/src/provider/provider.ts

azure: async () => { return { autoload: false, async getModel(sdk: any, modelID: string) { return sdk.completion(modelID) }, options: {}, } },

now if we should have something in the config file that lets us decide if we want/need completion or responses for the model, that might do the trick?

apology if i hallucinate a solution here that might not be as easy as i think

enlilz avatar Aug 24 '25 19:08 enlilz

i gave it a try for a fix, feedback would be appreciated. not sure if i got the "correct" solution for the issue, but at least it worked in my tests that the URL is generated correctly and opencode (in the dev Version) was able to use my Azure OpenAi models now.

enlilz avatar Sep 08 '25 17:09 enlilz

just wanted to see if there is any update? would my pr be an acceptable solution for the issue ?

enlilz avatar Oct 08 '25 17:10 enlilz

I will take a look at it when I get a chance today or tmr, if I don't have feedback for you soon just @ me and i will get to it

currently wrapping up work at my day job but i will have a lot more bandwidth to be able to review and help very soon

rekram1-node avatar Oct 08 '25 19:10 rekram1-node

added a PR for updating the docs with additional information on azure provider configuration - including the changes made in the PR to this issue.

enlilz avatar Oct 13 '25 20:10 enlilz

After spending a couple days poking at this, I managed to get the /deployments/%Model%/chat/completions API working as described in this comment: https://github.com/anomalyco/opencode/issues/1508#issuecomment-3206393616, but due to my company's API deployment not using /v1/responses (just /responses) I was failing to get any of the non-deployment endpoints to work.

Based on the table from this PR updating the documentation, it looks like the only two options directly supported for endpoints are /v1/... or /deployments/..., which tracks with what seems to be the only two options @ai-sdk/azure will give you from createAzure.url shown here.

I eventually managed to solve this with a short custom opencode plugin that just patches the URL before each request on the fly, which seems to work pretty well from my short testing so far. A couple of caveats with this approach:

  • It only seems to work if you use the official azure provider, I haven't managed to create a custom myprovider that achieves the same results
  • Model ID gpt-5-codex didn't seem to work, but gpt-5.1-codex, gpt-5.1-codex-mini, gpt-5.1, and gpt-5 seem to work fine (these are the only ones I have access to on our instance so that's all I could test)
  • The custom loader to patch the URLs is only used if you have an entry for the provider in your ~/.config/opencode/auth.json file:
    • The plugin is skipped if the provider doesn't have an auth config here
    • Which is determined by reading the providerID field from auth.json here

The plugin to patch the urls is just this file placed at ~/.config/opencode/plugin/patch_endpoint.ts: (I know basically no typescript/javascript, so bear with me here and make suggestions if you have them)

import type { Plugin } from "@opencode-ai/plugin"

export const PatchApiEndpoint: Plugin = async (ctx) => {
  return {
    auth: {
      provider: "azure",
      methods: [],
      loader: async (_auth, _provider) => {
        await ctx.client.app.log({
          body: { service: "patch-api-endpoint", level: "info", message: "Loader initialized..." }
        })

        return {
          fetch: async (url: string | URL | Request, init?: RequestInit) => {
            const oldUrl = url instanceof Request ? url.url : String(url)
            const newUrl = new URL(oldUrl.replace("/v1/responses","/responses"))

            ctx.client.app.log({
              body: {
                service: "patch-api-endpoint",
                level: "info",
                message: "Patching API Endpoint",
                extra: { oldUrl: oldUrl, newUrl: newUrl.toString()  },
              }
            })

            return fetch(newUrl.toString(), init)
          },
        }
      },
    },
  }
}

export default PatchApiEndpoint

~/.local/share/opencode/auth.json:

{
  "azure": {
    "type": "api",
    "key": "file:~/.config/opencode/my_custom_ai.key"
}

~/.config/opencode/opencode.jsonc:

{
    "$schema": "https://opencode.ai/config.json",
    "enabled_providers": ["azure"],
    "share": "disabled",
    "autoupdate": "notify",
    "provider": {
        "azure": {
            "name": "MyCustomAI",
            "whitelist": ["gpt-5.1-codex", "gpt-5", "gpt-5.1-codex-mini", "gpt-5.1"], // These are the models that seemed to work for me, YMMV
            "options": {
                "baseURL": "https://api.my_custom_ai.com/openai",
                "useDeploymentBasedUrls": false,
                "apiVersion": "2025-03-01-preview",
                "headers": {
                    "api-key": "{file:~/.config/opencode/my_custom_ai.key}"
                }
            }
        },
    }
}

then after making any request with one of the models I get this in my log file:

$ rg 'oldUrl' 2026-01-07T050321.log
INFO  2026-01-07T05:03:35 +0ms service=patch-api-endpoint oldUrl=https://api.my_custom_ai.com/openai/v1/responses?api-version=2025-03-01-preview newUrl=https://api.my_custom_ai.com/openai/responses?api-version=2025-03-01-preview Patching API Endpoint
INFO  2026-01-07T05:03:35 +0ms service=patch-api-endpoint oldUrl=https://api.my_custom_ai.com/openai/v1/responses?api-version=2025-03-01-preview newUrl=https://api.my_custom_ai.com/openai/responses?api-version=2025-03-01-preview Patching API Endpoint
INFO  2026-01-07T05:03:35 +0ms service=patch-api-endpoint oldUrl=https://api.my_custom_ai.com/openai/v1/responses?api-version=2025-03-01-preview newUrl=https://api.my_custom_ai.com/openai/responses?api-version=2025-03-01-preview Patching API Endpoint

Hope this is helpful to anyone else trying this.

brokenbyte avatar Jan 07 '26 05:01 brokenbyte