Skip to content

Commit afec21a

Browse files
authored
fix byok-opencode: route non-OpenAI openai-protocol hosts to @ai-sdk/openai-compatible (#5344)
The BYOK OpenCode path mapped protocol "openai" straight to @ai-sdk/openai (Responses API /responses) for every host, so providers that only serve /chat/completions (DeepSeek, vLLM, etc.) 404 on /responses. Route non-api.openai.com openai-protocol hosts to @ai-sdk/openai-compatible; real OpenAI stays on @ai-sdk/openai. Adds a DeepSeek regression test and corrects the vLLM test to openai-compatible.
1 parent 20a077f commit afec21a

2 files changed

Lines changed: 47 additions & 3 deletions

File tree

apps/daemon/src/runtimes/byok-opencode.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,15 @@ function isExactOrigin(value: string, origin: string): boolean {
158158
}
159159
}
160160

161+
function isRealOpenAIHost(baseUrl: string): boolean {
162+
if (!baseUrl) return true;
163+
try {
164+
return new URL(baseUrl).hostname === 'api.openai.com';
165+
} catch {
166+
return true;
167+
}
168+
}
169+
161170
function buildProviderEntry(
162171
protocol: ByokChatProviderConfig['protocol'],
163172
baseUrl: string,
@@ -207,11 +216,23 @@ function buildProviderEntry(
207216
},
208217
};
209218
case 'openai':
219+
// Real OpenAI speaks the Responses API via @ai-sdk/openai. Every other
220+
// host under the "openai" protocol (DeepSeek, vLLM, etc.) only serves
221+
// /chat/completions, so route it through @ai-sdk/openai-compatible.
222+
if (isRealOpenAIHost(baseUrl)) {
223+
return {
224+
npm: '@ai-sdk/openai',
225+
options: {
226+
...apiKeyOption,
227+
...(baseUrl ? { baseURL: baseUrl } : {}),
228+
},
229+
};
230+
}
210231
return {
211-
npm: '@ai-sdk/openai',
232+
npm: '@ai-sdk/openai-compatible',
212233
options: {
234+
baseURL: baseUrl,
213235
...apiKeyOption,
214-
...(baseUrl ? { baseURL: baseUrl } : {}),
215236
},
216237
};
217238
case 'senseaudio':

apps/daemon/tests/runtimes/byok-opencode.test.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,29 @@ describe('byok-opencode runtime config', () => {
7474
});
7575
});
7676

77+
it('routes OpenAI-protocol BYOK with a non-OpenAI base URL to the OpenAI-compatible provider package', () => {
78+
expect(buildOpenCodeByokProviderConfig(
79+
{ protocol: 'openai', apiKey: 'sk-deepseek', baseUrl: 'https://api.deepseek.com' },
80+
'deepseek-v4-pro',
81+
)?.config).toMatchObject({
82+
provider: {
83+
[BYOK_OPENCODE_PROVIDER_ID]: {
84+
npm: '@ai-sdk/openai-compatible',
85+
options: {
86+
baseURL: 'https://api.deepseek.com',
87+
apiKey: `{env:${BYOK_OPENCODE_API_KEY_ENV}}`,
88+
},
89+
},
90+
},
91+
});
92+
expect(buildOpenCodeByokProviderConfig(
93+
{ protocol: 'openai', apiKey: 'sk-openai', baseUrl: 'https://api.openai.com' },
94+
'deepseek-v4-pro',
95+
)?.config).toMatchObject({
96+
provider: { [BYOK_OPENCODE_PROVIDER_ID]: { npm: '@ai-sdk/openai' } },
97+
});
98+
});
99+
77100
it('normalizes origin-only native provider base URLs for OpenCode provider packages', () => {
78101
expect(buildOpenCodeByokProviderConfig(
79102
{ protocol: 'anthropic', apiKey: 'sk-ant', baseUrl: 'https://api.anthropic.com' },
@@ -272,7 +295,7 @@ describe('byok-opencode runtime config', () => {
272295
expect(out?.config).toMatchObject({
273296
provider: {
274297
[BYOK_OPENCODE_PROVIDER_ID]: {
275-
npm: '@ai-sdk/openai',
298+
npm: '@ai-sdk/openai-compatible',
276299
options: {
277300
baseURL: 'http://127.0.0.1:8000/v1',
278301
},

0 commit comments

Comments
 (0)