diff --git a/packages/core/src/integrations/openai/OpenAIEmbeddingGenerator.ts b/packages/core/src/integrations/openai/OpenAIEmbeddingGenerator.ts index 6989ec521..db0330f2f 100644 --- a/packages/core/src/integrations/openai/OpenAIEmbeddingGenerator.ts +++ b/packages/core/src/integrations/openai/OpenAIEmbeddingGenerator.ts @@ -15,6 +15,7 @@ export class OpenAIEmbeddingGenerator implements EmbeddingGenerator { const api = new OpenAI({ apiKey: this.#settings.openAiKey, organization: this.#settings.openAiOrganization, + baseURL: this.#settings.openAiEndpoint, dangerouslyAllowBrowser: true, // It's fine in Rivet }); diff --git a/packages/core/src/model/nodes/ChatNodeBase.ts b/packages/core/src/model/nodes/ChatNodeBase.ts index 06df5157c..80647e77d 100644 --- a/packages/core/src/model/nodes/ChatNodeBase.ts +++ b/packages/core/src/model/nodes/ChatNodeBase.ts @@ -22,7 +22,6 @@ import type { Inputs, Outputs } from '../GraphProcessor.js'; import { cleanHeaders, getInputOrData } from '../../utils/inputs.js'; import type { InternalProcessContext } from '../ProcessContext.js'; import { chatMessageToOpenAIChatCompletionMessage } from '../../utils/chatMessageToOpenAIChatCompletionMessage.js'; -import { DEFAULT_CHAT_ENDPOINT } from '../../utils/defaults.js'; import type { TokenizerCallInfo } from '../../integrations/Tokenizer.js'; import { addWarning } from '../../utils/outputs.js'; import retry from 'p-retry'; @@ -1008,7 +1007,8 @@ export const ChatNodeBase = { const isMultiResponse = data.useNumberOfChoicesInput || (data.numberOfChoices ?? 1) > 1; // Resolve to final endpoint if configured in ProcessContext - const configuredEndpoint = endpoint || context.settings.openAiEndpoint || DEFAULT_CHAT_ENDPOINT; + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; + const configuredEndpoint = endpoint || `${baseUrl}/chat/completions`; const resolvedEndpointAndHeaders = context.getChatNodeEndpoint ? await context.getChatNodeEndpoint(configuredEndpoint, finalModel) : { diff --git a/packages/core/src/plugins/openai/nodes/AttachAssistantFileNode.ts b/packages/core/src/plugins/openai/nodes/AttachAssistantFileNode.ts index 7cac1e67d..0ba319fa7 100644 --- a/packages/core/src/plugins/openai/nodes/AttachAssistantFileNode.ts +++ b/packages/core/src/plugins/openai/nodes/AttachAssistantFileNode.ts @@ -120,7 +120,8 @@ export const AttachAssistantFileNodeImpl: PluginNodeImpl = { throw new Error('OpenAI key is not set.'); } + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; const url = assistantId.trim() - ? `https://api.openai.com/v1/assistants/${assistantId}` - : 'https://api.openai.com/v1/assistants'; + ? `${baseUrl}/assistants/${assistantId}` + : `${baseUrl}/assistants`; const response = await fetch(url, { method: 'POST', diff --git a/packages/core/src/plugins/openai/nodes/CreateThreadMessageNode.ts b/packages/core/src/plugins/openai/nodes/CreateThreadMessageNode.ts index 6985be9d8..2eb495062 100644 --- a/packages/core/src/plugins/openai/nodes/CreateThreadMessageNode.ts +++ b/packages/core/src/plugins/openai/nodes/CreateThreadMessageNode.ts @@ -194,7 +194,8 @@ export const CreateThreadMessageNodeImpl: PluginNodeImpl = { return message as CreateMessageBody; }); - const url = threadId.trim() ? `https://api.openai.com/v1/threads/${threadId}` : 'https://api.openai.com/v1/threads'; + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; + const url = threadId.trim() ? `${baseUrl}/threads/${threadId}` : `${baseUrl}/threads`; if (threadId && messages.length > 0) { throw new Error('Cannot provide messages when modifying an existing thread.'); diff --git a/packages/core/src/plugins/openai/nodes/DeleteAssistantNode.ts b/packages/core/src/plugins/openai/nodes/DeleteAssistantNode.ts index 24074d23f..ca9c45967 100644 --- a/packages/core/src/plugins/openai/nodes/DeleteAssistantNode.ts +++ b/packages/core/src/plugins/openai/nodes/DeleteAssistantNode.ts @@ -99,7 +99,8 @@ export const DeleteAssistantNodeImpl: PluginNodeImpl = { throw new Error('OpenAI key is not set.'); } - const response = await fetch(`https://api.openai.com/v1/assistants/${assistantId}`, { + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; + const response = await fetch(`${baseUrl}/assistants/${assistantId}`, { method: 'DELETE', headers: { 'OpenAI-Beta': 'assistants=v1', diff --git a/packages/core/src/plugins/openai/nodes/DeleteThreadNode.ts b/packages/core/src/plugins/openai/nodes/DeleteThreadNode.ts index 8640854ad..a118dc383 100644 --- a/packages/core/src/plugins/openai/nodes/DeleteThreadNode.ts +++ b/packages/core/src/plugins/openai/nodes/DeleteThreadNode.ts @@ -90,7 +90,8 @@ export const DeleteThreadNodeImpl: PluginNodeImpl = { throw new Error('OpenAI key is not set.'); } - const response = await fetch(`https://api.openai.com/v1/threads/${threadId}`, { + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; + const response = await fetch(`${baseUrl}/threads/${threadId}`, { method: 'DELETE', headers: { 'OpenAI-Beta': 'assistants=v1', diff --git a/packages/core/src/plugins/openai/nodes/GetAssistantNode.ts b/packages/core/src/plugins/openai/nodes/GetAssistantNode.ts index d9b96cbff..9c728f94d 100644 --- a/packages/core/src/plugins/openai/nodes/GetAssistantNode.ts +++ b/packages/core/src/plugins/openai/nodes/GetAssistantNode.ts @@ -106,7 +106,8 @@ export const GetAssistantNodeImpl: PluginNodeImpl = { throw new Error('OpenAI key is not set.'); } - const response = await fetch(`https://api.openai.com/v1/assistants/${assistantId}`, { + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; + const response = await fetch(`${baseUrl}/assistants/${assistantId}`, { method: 'GET', headers: { 'OpenAI-Beta': 'assistants=v1', diff --git a/packages/core/src/plugins/openai/nodes/GetOpenAIFileNode.ts b/packages/core/src/plugins/openai/nodes/GetOpenAIFileNode.ts index df3dda2cc..990f061fe 100644 --- a/packages/core/src/plugins/openai/nodes/GetOpenAIFileNode.ts +++ b/packages/core/src/plugins/openai/nodes/GetOpenAIFileNode.ts @@ -96,7 +96,8 @@ export const GetOpenAIFileNodeImpl: PluginNodeImpl = { throw new Error('OpenAI key is not set.'); } - const url = `https://api.openai.com/v1/files/${fileId}`; + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; + const url = `${baseUrl}/files/${fileId}`; const response = await fetch(url, { method: 'GET', diff --git a/packages/core/src/plugins/openai/nodes/GetThreadNode.ts b/packages/core/src/plugins/openai/nodes/GetThreadNode.ts index a4edc3246..ffe3b877a 100644 --- a/packages/core/src/plugins/openai/nodes/GetThreadNode.ts +++ b/packages/core/src/plugins/openai/nodes/GetThreadNode.ts @@ -104,7 +104,8 @@ export const GetThreadNodeImpl: PluginNodeImpl = { throw new Error('OpenAI key is not set.'); } - const response = await fetch(`https://api.openai.com/v1/threads/${threadId}`, { + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; + const response = await fetch(`${baseUrl}/threads/${threadId}`, { method: 'GET', headers: { 'OpenAI-Beta': 'assistants=v1', diff --git a/packages/core/src/plugins/openai/nodes/ListAssistantsNode.ts b/packages/core/src/plugins/openai/nodes/ListAssistantsNode.ts index f14a868b5..18ba7c39e 100644 --- a/packages/core/src/plugins/openai/nodes/ListAssistantsNode.ts +++ b/packages/core/src/plugins/openai/nodes/ListAssistantsNode.ts @@ -212,7 +212,8 @@ ${ } const query = new URLSearchParams(queryParams); - const url = `https://api.openai.com/v1/assistants?${query.toString()}`; + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; + const url = `${baseUrl}/assistants?${query.toString()}`; const response = await fetch(url, { method: 'GET', diff --git a/packages/core/src/plugins/openai/nodes/ListOpenAIFilesNode.ts b/packages/core/src/plugins/openai/nodes/ListOpenAIFilesNode.ts index 308ff17a2..a0ddb6d5a 100644 --- a/packages/core/src/plugins/openai/nodes/ListOpenAIFilesNode.ts +++ b/packages/core/src/plugins/openai/nodes/ListOpenAIFilesNode.ts @@ -98,7 +98,8 @@ export const ListOpenAIFilesNodeImpl: PluginNodeImpl = { throw new Error('OpenAI key is not set.'); } - const url = `https://api.openai.com/v1/files?purpose=${purpose}`; + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; + const url = `${baseUrl}/files?purpose=${purpose}`; const response = await fetch(url, { method: 'GET', diff --git a/packages/core/src/plugins/openai/nodes/ListThreadMessagesNode.ts b/packages/core/src/plugins/openai/nodes/ListThreadMessagesNode.ts index 5dd3b0aad..281ff3737 100644 --- a/packages/core/src/plugins/openai/nodes/ListThreadMessagesNode.ts +++ b/packages/core/src/plugins/openai/nodes/ListThreadMessagesNode.ts @@ -238,7 +238,8 @@ ${ } const query = new URLSearchParams(queryParams); - const url = `https://api.openai.com/v1/threads/${threadId}/messages?${query.toString()}`; + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; + const url = `${baseUrl}/threads/${threadId}/messages?${query.toString()}`; const response = await fetch(url, { method: 'GET', diff --git a/packages/core/src/plugins/openai/nodes/RunThreadNode.ts b/packages/core/src/plugins/openai/nodes/RunThreadNode.ts index b3e06cc61..d747f23c3 100644 --- a/packages/core/src/plugins/openai/nodes/RunThreadNode.ts +++ b/packages/core/src/plugins/openai/nodes/RunThreadNode.ts @@ -380,6 +380,7 @@ export const RunThreadNodeImpl: PluginNodeImpl = { async process(data, inputData, context) { const threadId = getInputOrData(data, inputData, 'threadId'); const assistantId = getInputOrData(data, inputData, 'assistantId'); + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; let metadata = data.metadata.reduce( (acc, { key, value }) => { @@ -448,7 +449,7 @@ export const RunThreadNodeImpl: PluginNodeImpl = { ? arrayizeDataValue(unwrapDataValue(messagesInput)).map((message) => coerceToThreadMessage(message)) : []; - response = await fetch('https://api.openai.com/v1/threads/runs', { + response = await fetch(`${baseUrl}/threads/runs`, { method: 'POST', headers: { 'OpenAI-Beta': 'assistants=v1', @@ -465,7 +466,7 @@ export const RunThreadNodeImpl: PluginNodeImpl = { }), }); } else { - response = await fetch(`https://api.openai.com/v1/threads/${threadId}/runs`, { + response = await fetch(`${baseUrl}/threads/${threadId}/runs`, { method: 'POST', headers: { 'OpenAI-Beta': 'assistants=v1', @@ -509,7 +510,7 @@ export const RunThreadNodeImpl: PluginNodeImpl = { order: 'desc', } satisfies OpenAIPaginationQuery); - const url = `https://api.openai.com/v1/threads/${body.thread_id}/runs/${body.id}/steps?${query.toString()}`; + const url = `${baseUrl}/threads/${body.thread_id}/runs/${body.id}/steps?${query.toString()}`; const response = await fetch(url, { method: 'GET', headers: { @@ -547,7 +548,7 @@ export const RunThreadNodeImpl: PluginNodeImpl = { const messageId = step.step_details.message_creation.message_id; const messageResponse = await fetch( - `https://api.openai.com/v1/threads/${body.thread_id}/messages/${messageId}`, + `${baseUrl}/threads/${body.thread_id}/messages/${messageId}`, { method: 'GET', headers: { @@ -598,7 +599,7 @@ export const RunThreadNodeImpl: PluginNodeImpl = { latestBody.status === 'queued' || latestBody.status === 'requires_action' ) { - const runResponse = await fetch(`https://api.openai.com/v1/threads/${body.thread_id}/runs/${body.id}`, { + const runResponse = await fetch(`${baseUrl}/threads/${body.thread_id}/runs/${body.id}`, { method: 'GET', headers: { 'OpenAI-Beta': 'assistants=v1', @@ -681,7 +682,7 @@ export const RunThreadNodeImpl: PluginNodeImpl = { })); const submitResponse = await fetch( - `https://api.openai.com/v1/threads/${body.thread_id}/runs/${body.id}/submit_tool_outputs`, + `${baseUrl}/threads/${body.thread_id}/runs/${body.id}/submit_tool_outputs`, { method: 'POST', headers: { @@ -720,7 +721,7 @@ export const RunThreadNodeImpl: PluginNodeImpl = { }); const listStepsResponsePromise = await fetch( - `https://api.openai.com/v1/threads/${body.thread_id}/runs/${body.id}/steps?${listStepsQuery.toString()}`, + `${baseUrl}/threads/${body.thread_id}/runs/${body.id}/steps?${listStepsQuery.toString()}`, { method: 'GET', headers: { @@ -738,7 +739,7 @@ export const RunThreadNodeImpl: PluginNodeImpl = { } satisfies OpenAIPaginationQuery); const messagesResponsePromise = await fetch( - `https://api.openai.com/v1/threads/${body.thread_id}/messages?${getMessagesQuery.toString()}`, + `${baseUrl}/threads/${body.thread_id}/messages?${getMessagesQuery.toString()}`, { method: 'GET', headers: { diff --git a/packages/core/src/plugins/openai/nodes/UploadFileNode.ts b/packages/core/src/plugins/openai/nodes/UploadFileNode.ts index 22abdbb2e..6c579e6e5 100644 --- a/packages/core/src/plugins/openai/nodes/UploadFileNode.ts +++ b/packages/core/src/plugins/openai/nodes/UploadFileNode.ts @@ -124,7 +124,8 @@ export const UploadFileNodeImpl: PluginNodeImpl = { formData.append('purpose', purpose); formData.append('file', file); - const response = await fetch('https://api.openai.com/v1/files', { + const baseUrl = context.settings.openAiEndpoint ?? 'https://api.openai.com/v1'; + const response = await fetch(`${baseUrl}/files`, { method: 'POST', headers: { Authorization: `Bearer ${context.settings.openAiKey}`, diff --git a/packages/core/src/utils/defaults.ts b/packages/core/src/utils/defaults.ts index 7ffc76f88..d73a3bce1 100644 --- a/packages/core/src/utils/defaults.ts +++ b/packages/core/src/utils/defaults.ts @@ -1,3 +1 @@ -export const DEFAULT_CHAT_ENDPOINT = 'https://api.openai.com/v1/chat/completions'; - export const DEFAULT_CHAT_NODE_TIMEOUT = 30_000;