[PUT-475] fix togetherai chat being broken + deprioritize them 🐛 (#2369)

This commit is contained in:
Daniel Salazar
2026-01-28 22:04:06 -08:00
committed by GitHub
parent 6daac664c6
commit 40f805f64b
5 changed files with 32 additions and 18 deletions

View File

@@ -25,7 +25,7 @@ const mandatoryRules = {
'no-use-before-define': ['error', {
'functions': false,
}],
'no-invalid-this': 'error',
'no-invalid-this': 'warn',
};
export default defineConfig([

View File

@@ -107,6 +107,7 @@ class AIInterfaceService extends BaseService {
stream: { type: 'flag' },
response: { type: 'json' },
model: { type: 'string' },
provider: { type: 'string', optional: true },
temperature: { type: 'number' },
max_tokens: { type: 'number' },
},

View File

@@ -25,7 +25,6 @@ import { Context } from '../../../util/context.js';
import { kv } from '../../../util/kvSingleton.js';
import BaseService from '../../BaseService.js';
import { BaseDatabaseAccessService } from '../../database/BaseDatabaseAccessService.js';
import { DB_WRITE } from '../../database/consts.js';
import { DriverService } from '../../drivers/DriverService.js';
import { TypedValue } from '../../drivers/meta/Runtime.js';
import { EventService } from '../../EventService.js';
@@ -35,19 +34,19 @@ import { normalize_tools_object } from '../utils/FunctionCalling.js';
import { extract_text, normalize_messages, normalize_single_message } from '../utils/Messages.js';
import Streaming from '../utils/Streaming.js';
import { ClaudeProvider } from './providers/ClaudeProvider/ClaudeProvider.js';
import { DeepSeekProvider } from './providers/DeepSeekProvider/DeepSeekProvider.js';
import { FakeChatProvider } from './providers/FakeChatProvider.js';
import { GeminiChatProvider } from './providers/GeminiProvider/GeminiChatProvider.js';
import { GroqAIProvider } from './providers/GroqAiProvider/GroqAIProvider.js';
import { MistralAIProvider } from './providers/MistralAiProvider/MistralAiProvider.js';
import { OllamaChatProvider } from './providers/OllamaProvider.js';
import { OpenAiChatProvider } from './providers/OpenAiProvider/OpenAiChatCompletionsProvider.js';
import { OpenAiResponsesChatProvider } from './providers/OpenAiProvider/OpenAiChatResponsesProvider.js';
import { OpenRouterProvider } from './providers/OpenRouterProvider/OpenRouterProvider.js';
import { TogetherAIProvider } from './providers/TogetherAiProvider/TogetherAIProvider.js';
import { IChatModel, IChatProvider, ICompleteArguments } from './providers/types.js';
import { UsageLimitedChatProvider } from './providers/UsageLimitedChatProvider.js';
import { OllamaChatProvider } from './providers/OllamaProvider.js';
import { DeepSeekProvider } from './providers/DeepSeekProvider/DeepSeekProvider.js';
import { XAIProvider } from './providers/XAIProvider/XAIProvider.js';
import { TogetherAIProvider } from './providers/TogetherAiProvider/TogetherAIProvider.js';
import { OpenRouterProvider } from './providers/OpenRouterProvider/OpenRouterProvider.js';
// Maximum number of fallback attempts when a model fails, including the first attempt
const MAX_FALLBACKS = 3 + 1; // includes first attempt
@@ -63,7 +62,7 @@ export class AIChatService extends BaseService {
}
get db (): BaseDatabaseAccessService {
return this.services.get('database').get(DB_WRITE, 'ai-service');
return this.services.get('database').get();
}
get errorService (): ErrorService {
@@ -218,12 +217,11 @@ export class AIChatService extends BaseService {
}
this.#modelIdMap[model.id].push({ ...model, provider: providerName });
if ( model.puterId ) {
if (model.aliases) {
if ( model.aliases ) {
model.aliases.push(model.puterId);
} else {
model.aliases = [model.puterId]
model.aliases = [model.puterId];
}
}
if ( model.aliases ) {
for ( let alias of model.aliases ) {
@@ -241,6 +239,14 @@ export class AIChatService extends BaseService {
}
}
this.#modelIdMap[model.id].sort((a, b) => {
// Sort togetherai provider models last
if ( a.provider === 'together-ai' && b.provider !== 'together-ai' ) {
return 1;
}
if ( b.provider === 'together-ai' && a.provider !== 'together-ai' ) {
return -1;
}
if ( a.costs[a.input_cost_key || 'input_tokens'] === b.costs[b.input_cost_key || 'input_tokens'] ) {
return a.id.length - b.id.length; // use shorter id since its likely the official one
}
@@ -279,7 +285,7 @@ export class AIChatService extends BaseService {
let { test_mode: testMode, response_metadata: resMetadata, intended_service: legacyProviderName } = clientDriverCall as { test_mode?: boolean; response_metadata: Record<string, unknown>; intended_service?: string };
const actor = Context.get('actor');
let intendedProvider = parameters.provider || legacyProviderName === AIChatService.SERVICE_NAME ? '' : legacyProviderName ; // should now all go through here
let intendedProvider = parameters.provider || (legacyProviderName === AIChatService.SERVICE_NAME ? '' : legacyProviderName); // should now all go through here
if ( !parameters.model && !intendedProvider ) {
intendedProvider = AIChatService.DEFAULT_PROVIDER;

View File

@@ -57,8 +57,8 @@ export class TogetherAIProvider implements IChatProvider {
context: model.context_length,
description: model.display_name,
costs_currency: 'usd-cents',
input_cost_key: 'prompt_tokens',
output_cost_key: 'completion_tokens',
input_cost_key: 'input',
output_cost_key: 'output',
costs: {
tokens: 1_000_000,
...model.pricing,
@@ -73,8 +73,8 @@ export class TogetherAIProvider implements IChatProvider {
name: 'Model Fallback Test 1',
context: 1000,
costs_currency: 'usd-cents',
input_cost_key: 'prompt_tokens',
output_cost_key: 'completion_tokens',
input_cost_key: 'input',
output_cost_key: 'output',
costs: {
tokens: 1_000_000,
prompt_tokens: 10,
@@ -115,7 +115,10 @@ export class TogetherAIProvider implements IChatProvider {
messages,
stream,
...(tools ? { tools } : {}),
...(max_tokens ? { max_tokens } : {}),
// TODO: make this better but togetherai doesn't handle max tokens properly at all
...(max_tokens ? { max_tokens: max_tokens - messages.reduce((acc, curr) => {
return acc + (curr.type === 'text' ? curr.text.length / 2 : 200);
}, 0) } : {}),
...(temperature ? { temperature } : {}),
...(stream ? { stream_options: { include_usage: true } } : {}),
} as Together.Chat.Completions.CompletionCreateParamsNonStreaming);

View File

@@ -736,6 +736,10 @@ class AI {
requestParams.max_tokens = userParams.max_tokens;
}
if ( userParams.provider ) {
requestParams.provider = userParams.provider;
}
// convert undefined to empty string so that .startsWith works
requestParams.model = requestParams.model ?? '';
@@ -745,11 +749,11 @@ class AI {
}
if ( userParams.driver ) {
driver = userParams.driver;
requestParams.provider = requestParams.provider || userParams.driver;
}
// Additional parameters to pass from userParams to requestParams
const PARAMS_TO_PASS = ['tools', 'response', 'reasoning', 'reasoning_effort', 'text', 'verbosity'];
const PARAMS_TO_PASS = ['tools', 'response', 'reasoning', 'reasoning_effort', 'text', 'verbosity', 'provider'];
for ( const name of PARAMS_TO_PASS ) {
if ( userParams[name] ) {
requestParams[name] = userParams[name];