From fbb2080a6651293381eede9effda0d46ba8d9286 Mon Sep 17 00:00:00 2001 From: Daniel Salazar Date: Thu, 5 Feb 2026 16:30:45 -0800 Subject: [PATCH] fix: don't use ai aggregators if we have the model ourselves (#2424) * cleanup: eslint changes * fix: don't use ai aggregators if we have the model ourselves --- eslint.config.js | 7 +++++ .../MeteringService/MeteringService.ts | 2 +- .../costMaps/elevenlabsCostMap.ts | 1 + .../src/services/ai/chat/AIChatService.ts | 29 +++++++++++++++---- .../ClaudeProvider/ClaudeProvider.ts | 2 +- .../chat/providers/ClaudeProvider/models.ts | 2 +- 6 files changed, 34 insertions(+), 9 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 2eca21708..c87bacce9 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -59,6 +59,13 @@ export const rules = { 'no-use-before-define': ['error', { 'functions': false, }], + '@stylistic/array-bracket-spacing': ['error', 'never'], + '@stylistic/linebreak-style': ['error', 'unix'], + 'no-sequences': [ + 'error', { + allowInParentheses: false, + }, + ], }; const tsRules = { diff --git a/src/backend/src/services/MeteringService/MeteringService.ts b/src/backend/src/services/MeteringService/MeteringService.ts index 3c53ce487..1f551cf41 100644 --- a/src/backend/src/services/MeteringService/MeteringService.ts +++ b/src/backend/src/services/MeteringService/MeteringService.ts @@ -566,7 +566,7 @@ export class MeteringService { ]); const defaultSubscriptionId = defaultSubscriptionEvent.defaultSubscriptionId as unknown as (typeof SUB_POLICIES)[number]['id'] || defaultUserSubscriptionId; - const availablePolicies = [ ...availablePoliciesEvent.availablePolicies, ...SUB_POLICIES ]; + const availablePolicies = [...availablePoliciesEvent.availablePolicies, ...SUB_POLICIES]; const userSubscriptionId = userSubscriptionEvent.userSubscriptionId as unknown as typeof SUB_POLICIES[number]['id'] || defaultSubscriptionId; return availablePolicies.find(({ id }) => id === userSubscriptionId) || availablePolicies.find(({ id }) => id === defaultSubscriptionId)!; diff --git a/src/backend/src/services/MeteringService/costMaps/elevenlabsCostMap.ts b/src/backend/src/services/MeteringService/costMaps/elevenlabsCostMap.ts index d25ffaac5..29238064d 100644 --- a/src/backend/src/services/MeteringService/costMaps/elevenlabsCostMap.ts +++ b/src/backend/src/services/MeteringService/costMaps/elevenlabsCostMap.ts @@ -8,6 +8,7 @@ export const ELEVENLABS_COST_MAP = { 'elevenlabs:eleven_multilingual_v2:character': 18000 * 0.9, // using scale costs per additional char * 0.9 'elevenlabs:eleven_turbo_v2_5:character': 18000 * 0.9, // using scale costs per additional char * 0.9 + 'elevenlabs:eleven_turbo_v2:character': 18000 * 0.9, // using scale costs per additional char * 0.9 'elevenlabs:eleven_flash_v2_5:character': 9000 * 0.9, // using scale costs per additional char * 0.9 'elevenlabs:eleven_v3:character': 18000 * 0.9, // using scale costs per additional char * 0.9 'elevenlabs:eleven_multilingual_sts_v2:second': 300000 * 0.9, // using scale costs unit * 0.9 diff --git a/src/backend/src/services/ai/chat/AIChatService.ts b/src/backend/src/services/ai/chat/AIChatService.ts index 98b50dbc6..28168916d 100644 --- a/src/backend/src/services/ai/chat/AIChatService.ts +++ b/src/backend/src/services/ai/chat/AIChatService.ts @@ -20,6 +20,7 @@ import { createId as cuid2 } from '@paralleldrive/cuid2'; import { PassThrough } from 'stream'; import { APIError } from '../../../api/APIError.js'; +import { redisClient } from '../../../clients/redis/redisSingleton.js'; import { ErrorService } from '../../../modules/core/ErrorService.js'; import { Context } from '../../../util/context.js'; import BaseService from '../../BaseService.js'; @@ -45,7 +46,6 @@ import { OpenRouterProvider } from './providers/OpenRouterProvider/OpenRouterPro import { TogetherAIProvider } from './providers/TogetherAiProvider/TogetherAIProvider.js'; import { IChatModel, IChatProvider, ICompleteArguments } from './providers/types.js'; import { XAIProvider } from './providers/XAIProvider/XAIProvider.js'; -import { redisClient } from '../../../clients/redis/redisSingleton.js'; // Maximum number of fallback attempts when a model fails, including the first attempt const MAX_FALLBACKS = 3 + 1; // includes first attempt @@ -150,14 +150,14 @@ export class AIChatService extends BaseService { if ( xaiConfig && xaiConfig.apiKey ) { this.#providers['xai'] = new XAIProvider(xaiConfig, this.meteringService); } - const togetherConfig = this.config.providers?.['together-ai'] || this.global_config?.services?.['together-ai']; - if ( togetherConfig && togetherConfig.apiKey ) { - this.#providers['together-ai'] = new TogetherAIProvider(togetherConfig, this.meteringService); - } const openrouterConfig = this.config.providers?.['openrouter'] || this.global_config?.services?.['openrouter']; if ( openrouterConfig && openrouterConfig.apiKey ) { this.#providers['openrouter'] = new OpenRouterProvider(openrouterConfig, this.meteringService); } + const togetherConfig = this.config.providers?.['together-ai'] || this.global_config?.services?.['together-ai']; + if ( togetherConfig && togetherConfig.apiKey ) { + this.#providers['together-ai'] = new TogetherAIProvider(togetherConfig, this.meteringService); + } // ollama if local instance detected @@ -221,6 +221,23 @@ export class AIChatService extends BaseService { model.aliases = [model.puterId]; } } + + let exists = false; + if ( model.aliases ) { + for ( let alias of model.aliases ) { + if ( this.#modelIdMap[alias] && this.#modelIdMap[alias] !== this.#modelIdMap[model.id] ) { + if ( providerName === 'together-ai' || providerName === 'openrouter' ) { + delete this.#modelIdMap[model.id]; + exists = true; + break; + } + } + } + } + if ( exists ) { + continue; + } + if ( model.aliases ) { for ( let alias of model.aliases ) { alias = alias.trim().toLowerCase(); @@ -674,7 +691,7 @@ export class AIChatService extends BaseService { if ( targetModel.id.startsWith('openrouter:') || targetModel.id.startsWith('togetherai:') ) { [aiProvider, modelToSearch] = targetModel.id.replace('openrouter:', '').replace('togetherai:', '').toLowerCase().split('/'); } else { - [aiProvider, modelToSearch] = targetModel.provider!.toLowerCase().replace('gemini', 'google').replace('openai-completion', 'openai').replace('openai-responses', 'openai'), targetModel.id.toLowerCase(); + [aiProvider, modelToSearch] = [targetModel.provider!.toLowerCase().replace('gemini', 'google').replace('openai-completion', 'openai').replace('openai-responses', 'openai'), targetModel.id.toLowerCase()]; } const potentialMatches = models.filter(model => { diff --git a/src/backend/src/services/ai/chat/providers/ClaudeProvider/ClaudeProvider.ts b/src/backend/src/services/ai/chat/providers/ClaudeProvider/ClaudeProvider.ts index 7a11a76bb..5b5e1b044 100644 --- a/src/backend/src/services/ai/chat/providers/ClaudeProvider/ClaudeProvider.ts +++ b/src/backend/src/services/ai/chat/providers/ClaudeProvider/ClaudeProvider.ts @@ -244,7 +244,7 @@ export class ClaudeProvider implements IChatProvider { return 'container_upload'; })(); - delete task.contentPart.puter_path, + delete task.contentPart.puter_path; task.contentPart.type = contentBlockTypeForFileBasedOnMime; task.contentPart.source = { type: 'file', diff --git a/src/backend/src/services/ai/chat/providers/ClaudeProvider/models.ts b/src/backend/src/services/ai/chat/providers/ClaudeProvider/models.ts index 16b49b606..4178414fc 100644 --- a/src/backend/src/services/ai/chat/providers/ClaudeProvider/models.ts +++ b/src/backend/src/services/ai/chat/providers/ClaudeProvider/models.ts @@ -4,7 +4,7 @@ export const CLAUDE_MODELS: IChatModel[] = [ { puterId: 'anthropic:anthropic/claude-opus-4-6', id: 'claude-opus-4-6', - aliases: ['claude-opus-4-6-latest', 'claude-opus-4.6', 'anthropic/claude-opus-4-6'], + aliases: ['claude-opus-4-6-latest', 'claude-opus-4.6', 'claude-opus-4-6', 'anthropic/claude-opus-4-6'], name: 'Claude Opus 4.6', costs_currency: 'usd-cents', input_cost_key: 'input_tokens',