diff --git a/src/backend/src/modules/puterai/AIChatService.js b/src/backend/src/modules/puterai/AIChatService.js index 0bad5e0308..a71e6a9de4 100644 --- a/src/backend/src/modules/puterai/AIChatService.js +++ b/src/backend/src/modules/puterai/AIChatService.js @@ -396,7 +396,7 @@ class AIChatService extends BaseService { if ( model_max_tokens ) { parameters.max_tokens = Math.floor(Math.min(parameters.max_tokens ?? Number.POSITIVE_INFINITY, max_allowed_output_tokens, - model_max_tokens)); + model_max_tokens - (Math.ceil(text.length / 4)))); } try { ret = await svc_driver.call_new_({ diff --git a/src/backend/src/modules/puterai/OpenRouterService.js b/src/backend/src/modules/puterai/OpenRouterService.js index 150a8ee740..520eb2692f 100644 --- a/src/backend/src/modules/puterai/OpenRouterService.js +++ b/src/backend/src/modules/puterai/OpenRouterService.js @@ -126,8 +126,7 @@ class OpenRouterService extends BaseService { const actor = Context.get('actor'); messages = await OpenAIUtil.process_input_messages(messages); - - const completion = await this.openai.chat.completions.create({ + const sdk_params = { messages, model: model ?? this.get_default_model(), ...(tools ? { tools } : {}), @@ -137,7 +136,9 @@ class OpenRouterService extends BaseService { ...(stream ? { stream_options: { include_usage: true }, } : {}), - }); + } + + const completion = await this.openai.chat.completions.create(sdk_params); const modelDetails = (await this.models_()).find(m => m.id === 'openrouter:' + model); const rawPriceModelDetails = (await this.models_(true)).find(m => m.id === 'openrouter:' + model); diff --git a/src/backend/src/modules/puterai/lib/OpenAIUtil.js b/src/backend/src/modules/puterai/lib/OpenAIUtil.js index 6f21510896..52d8305674 100644 --- a/src/backend/src/modules/puterai/lib/OpenAIUtil.js +++ b/src/backend/src/modules/puterai/lib/OpenAIUtil.js @@ -120,8 +120,9 @@ const create_chat_stream_handler = ({ const choice = chunk.choices[0]; - if ( choice.delta.reasoning_content ){ - textblock.addReasoning(choice.delta.reasoning_content); + // Deepseek returns choice.delta.reasoning_content, openrouter returns choice.delta.reasoning. + if ( choice.delta.reasoning_content || choice.delta.reasoning ) { + textblock.addReasoning(choice.delta.reasoning_content || choice.delta.reasoning); // Q: Why don't "continue" to next chunk here? // A: For now, reasoning_content and content never appear together, but I’m not sure if they’ll always be mutually exclusive. }