From 831236a563445ba3d74b890b84093551b7f2a96b Mon Sep 17 00:00:00 2001 From: VAIBHAVSING Date: Fri, 3 Oct 2025 16:05:59 +0530 Subject: [PATCH 1/2] feat[openrouter]: add openrouter user tracking --- server/utils/AiProviders/openRouter/index.js | 54 +++++++++++++------- server/utils/chats/apiChatHandler.js | 3 ++ server/utils/chats/stream.js | 2 + 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/server/utils/AiProviders/openRouter/index.js b/server/utils/AiProviders/openRouter/index.js index 7a0fc1c355f..6d54a2727f8 100644 --- a/server/utils/AiProviders/openRouter/index.js +++ b/server/utils/AiProviders/openRouter/index.js @@ -238,22 +238,30 @@ class OpenRouterLLM { ]; } - async getChatCompletion(messages = null, { temperature = 0.7 }) { + async getChatCompletion(messages = null, { temperature = 0.7, user = null }) { if (!(await this.isValidChatCompletionModel(this.model))) throw new Error( `OpenRouter chat: ${this.model} is not valid for chat completion!` ); + const requestOptions = { + model: this.model, + messages, + temperature, + // This is an OpenRouter specific option that allows us to get the reasoning text + // before the token text. + include_reasoning: true, + }; + + // Add user tracking if user information is available + // This enables OpenRouter's user tracking features for multi-user systems + if (user?.id) { + requestOptions.user = String(user.id); + } + const result = await LLMPerformanceMonitor.measureAsyncFunction( this.openai.chat.completions - .create({ - model: this.model, - messages, - temperature, - // This is an OpenRouter specific option that allows us to get the reasoning text - // before the token text. - include_reasoning: true, - }) + .create(requestOptions) .catch((e) => { throw new Error(e.message); }) @@ -279,22 +287,30 @@ class OpenRouterLLM { }; } - async streamGetChatCompletion(messages = null, { temperature = 0.7 }) { + async streamGetChatCompletion(messages = null, { temperature = 0.7, user = null }) { if (!(await this.isValidChatCompletionModel(this.model))) throw new Error( `OpenRouter chat: ${this.model} is not valid for chat completion!` ); + const requestOptions = { + model: this.model, + stream: true, + messages, + temperature, + // This is an OpenRouter specific option that allows us to get the reasoning text + // before the token text. + include_reasoning: true, + }; + + // Add user tracking if user information is available + // This enables OpenRouter's user tracking features for multi-user systems + if (user?.id) { + requestOptions.user = String(user.id); + } + const measuredStreamRequest = await LLMPerformanceMonitor.measureStream( - this.openai.chat.completions.create({ - model: this.model, - stream: true, - messages, - temperature, - // This is an OpenRouter specific option that allows us to get the reasoning text - // before the token text. - include_reasoning: true, - }), + this.openai.chat.completions.create(requestOptions), messages // We have to manually count the tokens // OpenRouter has a ton of providers and they all can return slightly differently diff --git a/server/utils/chats/apiChatHandler.js b/server/utils/chats/apiChatHandler.js index d433df19291..0871e1c33cf 100644 --- a/server/utils/chats/apiChatHandler.js +++ b/server/utils/chats/apiChatHandler.js @@ -307,6 +307,7 @@ async function chatSync({ const { textResponse, metrics: performanceMetrics } = await LLMConnector.getChatCompletion(messages, { temperature: workspace?.openAiTemp ?? LLMConnector.defaultTemp, + user, }); if (!textResponse) { @@ -649,6 +650,7 @@ async function streamChat({ const { textResponse, metrics: performanceMetrics } = await LLMConnector.getChatCompletion(messages, { temperature: workspace?.openAiTemp ?? LLMConnector.defaultTemp, + user, }); completeText = textResponse; metrics = performanceMetrics; @@ -664,6 +666,7 @@ async function streamChat({ } else { const stream = await LLMConnector.streamGetChatCompletion(messages, { temperature: workspace?.openAiTemp ?? LLMConnector.defaultTemp, + user, }); completeText = await LLMConnector.handleStream(response, stream, { uuid }); metrics = stream.metrics; diff --git a/server/utils/chats/stream.js b/server/utils/chats/stream.js index 893a69415d5..3935f461bde 100644 --- a/server/utils/chats/stream.js +++ b/server/utils/chats/stream.js @@ -248,6 +248,7 @@ async function streamChatWithWorkspace( const { textResponse, metrics: performanceMetrics } = await LLMConnector.getChatCompletion(messages, { temperature: workspace?.openAiTemp ?? LLMConnector.defaultTemp, + user, }); completeText = textResponse; @@ -264,6 +265,7 @@ async function streamChatWithWorkspace( } else { const stream = await LLMConnector.streamGetChatCompletion(messages, { temperature: workspace?.openAiTemp ?? LLMConnector.defaultTemp, + user, }); completeText = await LLMConnector.handleStream(response, stream, { uuid, From 6d4cc6c7394cfef5b4183f37db7d29db352246ae Mon Sep 17 00:00:00 2001 From: VAIBHAVSING Date: Fri, 3 Oct 2025 16:25:53 +0530 Subject: [PATCH 2/2] feat : refractor code --- server/utils/AiProviders/openRouter/index.js | 59 ++++++++------------ 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/server/utils/AiProviders/openRouter/index.js b/server/utils/AiProviders/openRouter/index.js index 6d54a2727f8..542b3fe675c 100644 --- a/server/utils/AiProviders/openRouter/index.js +++ b/server/utils/AiProviders/openRouter/index.js @@ -244,24 +244,19 @@ class OpenRouterLLM { `OpenRouter chat: ${this.model} is not valid for chat completion!` ); - const requestOptions = { - model: this.model, - messages, - temperature, - // This is an OpenRouter specific option that allows us to get the reasoning text - // before the token text. - include_reasoning: true, - }; - - // Add user tracking if user information is available - // This enables OpenRouter's user tracking features for multi-user systems - if (user?.id) { - requestOptions.user = String(user.id); - } - const result = await LLMPerformanceMonitor.measureAsyncFunction( this.openai.chat.completions - .create(requestOptions) + .create({ + model: this.model, + messages, + temperature, + // This is an OpenRouter specific option that allows us to get the reasoning text + // before the token text. + include_reasoning: true, + // Add user tracking if user information is available + // This enables OpenRouter's user tracking features for multi-user systems + ...(user ? { user } : {}), + }) .catch((e) => { throw new Error(e.message); }) @@ -287,31 +282,25 @@ class OpenRouterLLM { }; } - async streamGetChatCompletion(messages = null, { temperature = 0.7, user = null }) { + async streamGetChatCompletion(messages = null, { temperature = 0.7 }) { if (!(await this.isValidChatCompletionModel(this.model))) throw new Error( `OpenRouter chat: ${this.model} is not valid for chat completion!` ); - const requestOptions = { - model: this.model, - stream: true, - messages, - temperature, - // This is an OpenRouter specific option that allows us to get the reasoning text - // before the token text. - include_reasoning: true, - }; - - // Add user tracking if user information is available - // This enables OpenRouter's user tracking features for multi-user systems - if (user?.id) { - requestOptions.user = String(user.id); - } - const measuredStreamRequest = await LLMPerformanceMonitor.measureStream( - this.openai.chat.completions.create(requestOptions), - messages + this.openai.chat.completions.create({ + model: this.model, + stream: true, + messages, + temperature, + // This is an OpenRouter specific option that allows us to get the reasoning text + // before the token text. + include_reasoning: true, + // Add user tracking if user information is available + // This enables OpenRouter's user tracking features for multi-user systems + ...(user ? { user } : {}), + }), // We have to manually count the tokens // OpenRouter has a ton of providers and they all can return slightly differently // some return chunk.usage on STOP, some do it after stop, its inconsistent.