From e95aa81e00d2dac43ff6ad196279661e041cb3ec Mon Sep 17 00:00:00 2001 From: Neal Shah <30693865+ProgrammerIn-wonderland@users.noreply.github.com> Date: Mon, 19 Jan 2026 00:01:47 +0530 Subject: [PATCH] OpenAI web_search support (#2299) --- .../OpenAiChatCompletionsProvider.ts | 10 +++++++++- .../OpenAiChatResponsesProvider.ts | 20 +++++++++++++------ .../src/services/ai/chat/providers/types.ts | 2 +- .../src/services/ai/utils/FunctionCalling.js | 5 +++++ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/backend/src/services/ai/chat/providers/OpenAiProvider/OpenAiChatCompletionsProvider.ts b/src/backend/src/services/ai/chat/providers/OpenAiProvider/OpenAiChatCompletionsProvider.ts index 7c8672542..5b754bb1a 100644 --- a/src/backend/src/services/ai/chat/providers/OpenAiProvider/OpenAiChatCompletionsProvider.ts +++ b/src/backend/src/services/ai/chat/providers/OpenAiProvider/OpenAiChatCompletionsProvider.ts @@ -99,8 +99,16 @@ export class OpenAiChatProvider implements IChatProvider { return this.#defaultModel; } - async complete ({ messages, model, max_tokens, moderation, tools, verbosity, stream, reasoning, reasoning_effort, temperature, text }: ICompleteArguments): ReturnType + async complete (params: ICompleteArguments): ReturnType { + let { messages, model, max_tokens, moderation, tools, verbosity, stream, reasoning, reasoning_effort, temperature, text } = params; + if ( tools?.filter((e: any) => e.type === 'web_search').length ) { + // User is trying to use openai-responses only tool web_search. + // We should pass it to that service + const aiChat = (Context.get('services') as any).get('ai-chat'); + const openAIresponses = aiChat.getProvider('openai-responses')!; + return await openAIresponses.complete!(params); + } // Validate messages if ( ! Array.isArray(messages) ) { throw new Error('`messages` must be an array'); diff --git a/src/backend/src/services/ai/chat/providers/OpenAiProvider/OpenAiChatResponsesProvider.ts b/src/backend/src/services/ai/chat/providers/OpenAiProvider/OpenAiChatResponsesProvider.ts index 3e66f3428..357e5cc37 100644 --- a/src/backend/src/services/ai/chat/providers/OpenAiProvider/OpenAiChatResponsesProvider.ts +++ b/src/backend/src/services/ai/chat/providers/OpenAiProvider/OpenAiChatResponsesProvider.ts @@ -79,12 +79,16 @@ export class OpenAiResponsesChatProvider implements IChatProvider { * Returns an array of available AI models with their pricing information. * Each model object includes an ID and cost details (currency, tokens, input/output rates). */ - models () { + models (extra_params) { + if ( extra_params?.no_restrictions ) + { + return OPEN_AI_MODELS; + } return OPEN_AI_MODELS.filter(e => e.responses_api_only === true); } list () { - const models = this.models(); + const models = this.models({ no_restrictions: false }); const modelNames: string[] = []; for ( const model of models ) { modelNames.push(model.id); @@ -109,7 +113,7 @@ export class OpenAiResponsesChatProvider implements IChatProvider { model = model ?? this.#defaultModel; - const modelUsed = (this.models()).find(m => [m.id, ...(m.aliases || [])].includes(model)) || (this.models()).find(m => m.id === this.getDefaultModel())!; + const modelUsed = (this.models({ no_restrictions: true })).find(m => [m.id, ...(m.aliases || [])].includes(model)) || (this.models(({ no_restrictions: true })).find(m => m.id === this.getDefaultModel())!); // messages.unshift({ // role: 'system', @@ -186,9 +190,13 @@ export class OpenAiResponsesChatProvider implements IChatProvider { if ( tools ) { // Unravel tools to OpenAI Responses API format tools = (tools as any).map((e) => { - const tool = e.function; - tool.type = 'function'; - return tool; + if ( e.type === 'function' ) { + const tool = e.function; + tool.type = 'function'; + return tool; + } else { + return e; + } }); } diff --git a/src/backend/src/services/ai/chat/providers/types.ts b/src/backend/src/services/ai/chat/providers/types.ts index 2b3801cbb..d63d13a29 100644 --- a/src/backend/src/services/ai/chat/providers/types.ts +++ b/src/backend/src/services/ai/chat/providers/types.ts @@ -39,7 +39,7 @@ export interface ICompleteArguments { } export interface IChatProvider { - models(): IChatModel[] | Promise + models(extra_params?: any): IChatModel[] | Promise list(): string[] | Promise checkModeration (text: string): Promise<{ flagged: boolean; diff --git a/src/backend/src/services/ai/utils/FunctionCalling.js b/src/backend/src/services/ai/utils/FunctionCalling.js index d9046617a..a1a18c282 100644 --- a/src/backend/src/services/ai/utils/FunctionCalling.js +++ b/src/backend/src/services/ai/utils/FunctionCalling.js @@ -41,6 +41,11 @@ export const normalize_json_schema = (schema) => { export const normalize_tools_object = (tools) => { for ( let i = 0 ; i < tools.length ; i++ ) { const tool = tools[i]; + + if ( tool.type === 'web_search' ) { + // OpenAI Responses specific + continue; + } let normalized_tool = {}; const normalize_function = fn => {