From 8a84e32cf60405bd0776f62b522674d240a17721 Mon Sep 17 00:00:00 2001 From: BugIsGod <87571967+bugisthegod@users.noreply.github.com> Date: Wed, 8 Apr 2026 13:01:49 +0100 Subject: [PATCH] fix(ai): use @ai-sdk/openai-compatible for third-party providers (#19438) ## Summary: I found a bug: 404 call when I use third-party providers (I used deepseek). I found the final request url is: `https://api.deepseek.com/v1/responses' `if we use createOpenAI. But the correct one should be `https://api.provider.com/v1/chat/completions` for the thirty provider. So I replace createOpenAI with createOpenAICompatible in the openai-compatible provider path. **Reproduction**: Add DeepSeek as a new AI provider (deepseek-chat, deepseek-reasoner) Also check the source code in Open Code project, they also use createOpenAICompatible for the @ai-sdk/openai-compatible scenario image official docs: https://ai-sdk.dev/providers/openai-compatible-providers https://ai-sdk.dev/providers/ai-sdk-providers/openai image ## Before deepseek before ## After deepseek after ## Backend error log ```json [1] [Nest] 50907 - 07/04/2026, 23:48:57 LOG [ChatExecutionService] Starting chat execution with model deepseek/deepseek-chat, 4 active tools [1] APICallError [AI_APICallError]: Not Found [1] at /Users/abel/Documents/Code/twenty/node_modules/@ai-sdk/provider-utils/dist/index.js:2512:14 [1] at process.processTicksAndRejections (node:internal/process/task_queues:105:5) [1] at async postToApi (/Users/abel/Documents/Code/twenty/node_modules/@ai-sdk/provider-utils/dist/index.js:2373:28) [1] at async OpenAIResponsesLanguageModel.doStream (/Users/abel/Documents/Code/twenty/node_modules/@ai-sdk/openai/dist/index.js:4925:50) [1] at async fn (/Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:7106:27) [1] at async /Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:2340:24 [1] at async _retryWithExponentialBackoff (/Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:2599:12) [1] at async streamStep (/Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:7063:17) [1] at async fn (/Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:7455:9) [1] at async /Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:2340:24 { [1] cause: undefined, [1] url: 'https://api.deepseek.com/v1/responses', [1] requestBodyValues: { [1] model: 'deepseek-chat', [1] input: [ [Object], [Object] ], [1] temperature: undefined, [1] top_p: undefined, [1] max_output_tokens: undefined, [1] conversation: undefined, [1] max_tool_calls: undefined, [1] metadata: undefined, [1] parallel_tool_calls: undefined, [1] previous_response_id: undefined, [1] store: undefined, [1] user: undefined, [1] instructions: undefined, [1] service_tier: undefined, [1] include: undefined, [1] prompt_cache_key: undefined, [1] prompt_cache_retention: undefined, [1] safety_identifier: undefined, [1] top_logprobs: undefined, [1] truncation: undefined, [1] tools: [ [Object], [Object], [Object], [Object] ], [1] tool_choice: 'auto', [1] stream: true [1] }, [1] statusCode: 404, [1] responseHeaders: { [1] 'access-control-allow-credentials': 'true', [1] connection: 'keep-alive', [1] 'content-length': '0', [1] date: 'Tue, 07 Apr 2026 22:48:57 GMT', [1] server: 'elb', [1] 'strict-transport-security': 'max-age=31536000; includeSubDomains; preload', [1] vary: 'origin, access-control-request-method, access-control-request-headers', [1] via: '1.1 83867089cd39052cd05f9e04909bedde.cloudfront.net (CloudFront)', [1] 'x-amz-cf-id': 'O4b0VTi9Q1VVmTmq6czGlEWst7IPnAQl544hB7uIvfnSphBvUKbZTw==', [1] 'x-amz-cf-pop': 'DUB56-P3', [1] 'x-cache': 'Error from cloudfront', [1] 'x-content-type-options': 'nosniff', [1] 'x-ds-trace-id': 'a90e91809d285170338ef077f67ae2be' [1] }, [1] responseBody: '', [1] isRetryable: false, [1] data: undefined, [1] Symbol(vercel.ai.error): true, [1] Symbol(vercel.ai.error.AI_APICallError): true [1] } [1] Exception Captured [1] undefined [1] [ [1] NoOutputGeneratedError [AI_NoOutputGeneratedError]: No output generated. Check the stream for errors. [1] at Object.flush (/Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:6656:103) [1] at invokePromiseCallback (node:internal/webstreams/util:172:10) [1] at Object. (node:internal/webstreams/util:177:23) [1] at transformStreamDefaultSinkCloseAlgorithm (node:internal/webstreams/transformstream:621:43) [1] at node:internal/webstreams/transformstream:379:11 [1] at writableStreamDefaultControllerProcessClose (node:internal/webstreams/writablestream:1162:28) [1] at writableStreamDefaultControllerAdvanceQueueIfNeeded (node:internal/webstreams/writablestream:1253:5) [1] at writableStreamDefaultControllerClose (node:internal/webstreams/writablestream:1220:3) [1] at writableStreamClose (node:internal/webstreams/writablestream:722:3) [1] at writableStreamDefaultWriterClose (node:internal/webstreams/writablestream:1091:10) { [1] cause: undefined, [1] Symbol(vercel.ai.error): true, [1] Symbol(vercel.ai.error.AI_NoOutputGeneratedError): true [1] } [1] ] [1] [Nest] 50907 - 07/04/2026, 23:48:59 LOG [BullMQDriver] Job 24 with name StreamAgentChatJob processed on queue ai-stream-queue in 2756.63ms --- packages/twenty-server/package.json | 1 + .../services/sdk-provider-factory.service.ts | 12 ++++----- yarn.lock | 26 +++++++++++++++++++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/packages/twenty-server/package.json b/packages/twenty-server/package.json index 17826ee1fe..d7c9daa9b3 100644 --- a/packages/twenty-server/package.json +++ b/packages/twenty-server/package.json @@ -20,6 +20,7 @@ "@ai-sdk/google": "^3.0.30", "@ai-sdk/mistral": "^3.0.20", "@ai-sdk/openai": "^3.0.30", + "@ai-sdk/openai-compatible": "^2.0.40", "@ai-sdk/provider-utils": "^4.0.15", "@ai-sdk/xai": "^3.0.57", "@aws-sdk/client-lambda": "3.1001.0", diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-models/services/sdk-provider-factory.service.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-models/services/sdk-provider-factory.service.ts index 0f2b979ab4..d3c1cda9b9 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-models/services/sdk-provider-factory.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-models/services/sdk-provider-factory.service.ts @@ -8,6 +8,7 @@ import { createAnthropic, type AnthropicProvider } from '@ai-sdk/anthropic'; import { createGoogleGenerativeAI } from '@ai-sdk/google'; import { createMistral } from '@ai-sdk/mistral'; import { createOpenAI, type OpenAIProvider } from '@ai-sdk/openai'; +import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; import { createXai } from '@ai-sdk/xai'; import { type LanguageModel } from 'ai'; import { type AiSdkPackage } from 'twenty-shared/ai'; @@ -80,11 +81,7 @@ export class SdkProviderFactoryService { } getRawOpenAIProvider(providerName: string): OpenAIProvider | undefined { - return this.getRawProvider( - providerName, - AI_SDK_OPENAI, - AI_SDK_OPENAI_COMPATIBLE, - ); + return this.getRawProvider(providerName, AI_SDK_OPENAI); } clearCache(): void { @@ -158,9 +155,10 @@ export class SdkProviderFactoryService { throw new Error('baseUrl is required for openai-compatible providers'); } - const provider = createOpenAI({ + const provider = createOpenAICompatible({ + name: config.name ?? 'openai-compatible', baseURL: config.baseUrl, - apiKey: config.apiKey ?? '', + ...(config.apiKey && { apiKey: config.apiKey }), }); return { diff --git a/yarn.lock b/yarn.lock index 8faa35e882..4b872317e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -113,6 +113,18 @@ __metadata: languageName: node linkType: hard +"@ai-sdk/openai-compatible@npm:^2.0.40": + version: 2.0.41 + resolution: "@ai-sdk/openai-compatible@npm:2.0.41" + dependencies: + "@ai-sdk/provider": "npm:3.0.8" + "@ai-sdk/provider-utils": "npm:4.0.23" + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + checksum: 10c0/3f91ad098edfedff46d9fa14b015fa46e235cc460cfdf45f1fb3f5114baa625684436770993aa7b969dbbf5f835a640e062c75cbf3ae72bd746ce6a37f2636f2 + languageName: node + linkType: hard + "@ai-sdk/openai@npm:^3.0.30": version: 3.0.34 resolution: "@ai-sdk/openai@npm:3.0.34" @@ -177,6 +189,19 @@ __metadata: languageName: node linkType: hard +"@ai-sdk/provider-utils@npm:4.0.23": + version: 4.0.23 + resolution: "@ai-sdk/provider-utils@npm:4.0.23" + dependencies: + "@ai-sdk/provider": "npm:3.0.8" + "@standard-schema/spec": "npm:^1.1.0" + eventsource-parser: "npm:^3.0.6" + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + checksum: 10c0/06e0aaf95eef47617d87709f78e321c87d26663bae16e68e9776a4bced8d78823d4c1514ac5e5e7dcb74f24a2e37152bc6b6eb1e31c9f0f77e54a020993c276a + languageName: node + linkType: hard + "@ai-sdk/provider@npm:2.0.1": version: 2.0.1 resolution: "@ai-sdk/provider@npm:2.0.1" @@ -60472,6 +60497,7 @@ __metadata: "@ai-sdk/google": "npm:^3.0.30" "@ai-sdk/mistral": "npm:^3.0.20" "@ai-sdk/openai": "npm:^3.0.30" + "@ai-sdk/openai-compatible": "npm:^2.0.40" "@ai-sdk/provider-utils": "npm:^4.0.15" "@ai-sdk/xai": "npm:^3.0.57" "@aws-sdk/client-lambda": "npm:3.1001.0"