Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,6 @@ jest.mock('@librechat/api', () => ({
jest.requireActual('@librechat/api').resolveAdmittedCodeEnvironmentDecision(...args),
resolvePersistableCodeEnvironmentDecision: (...args) =>
jest.requireActual('@librechat/api').resolvePersistableCodeEnvironmentDecision(...args),
getCodeWorkspaceSelections: jest.fn(),
createMCPRuntimeRequestBody: ({
messageId,
conversationId,
Expand Down Expand Up @@ -702,9 +701,6 @@ describe('createResponse controller', () => {
async (stream) => {
const api = require('@librechat/api');
const db = require('~/models');
api.getCodeWorkspaceSelections.mockReturnValueOnce([
{ environmentId: 'machine', workspaceId: 'stale-project' },
]);
api.validateResponseRequest.mockReturnValueOnce({
request: {
model: 'agent-123',
Expand All @@ -725,7 +721,6 @@ describe('createResponse controller', () => {
expect.anything(),
);
expect(db.saveConvo.mock.calls.at(-1)[1]).not.toHaveProperty('codeWorkspaces');
expect(api.getCodeWorkspaceSelections).not.toHaveBeenCalled();
},
);

Expand Down
1 change: 0 additions & 1 deletion api/server/services/Files/provision.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,5 @@ module.exports = {
loadCodeApiKey: (...args) => getService().loadCodeApiKey(...args),
provisionToCodeEnv: (...args) => getService().provisionToCodeEnv(...args),
provisionToVectorDB: (...args) => getService().provisionToVectorDB(...args),
checkCodeEnvFileAlive: (...args) => getService().checkCodeEnvFileAlive(...args),
checkSessionsAlive: (...args) => getService().checkSessionsAlive(...args),
};
184 changes: 0 additions & 184 deletions api/utils/tokens.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const {
matchModelName,
processModelData,
getModelMaxTokens,
maxOutputTokensMap,
findMatchingPattern,
} = require('@librechat/api');

Expand Down Expand Up @@ -591,49 +590,6 @@ describe('getModelMaxTokens', () => {
maxTokensMap[EModelEndpoint.openAI]['glm-4.5-air'],
);
});

test('should return correct max output tokens for GPT-5 models', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
const gpt5Models = [
'gpt-5',
'gpt-5.1',
'gpt-5.2',
'gpt-5.3',
'gpt-5.4',
'gpt-5.4-pro',
'gpt-5.5',
'gpt-5.5-pro',
'gpt-5.6',
'gpt-5.6-terra',
'gpt-5.6-luna',
'gpt-5-mini',
'gpt-5-nano',
'gpt-5-pro',
'gpt-5.2-pro',
];
for (const model of gpt5Models) {
expect(getModelMaxOutputTokens(model)).toBe(maxOutputTokensMap[EModelEndpoint.openAI][model]);
expect(getModelMaxOutputTokens(model, EModelEndpoint.openAI)).toBe(
maxOutputTokensMap[EModelEndpoint.openAI][model],
);
expect(getModelMaxOutputTokens(model, EModelEndpoint.azureOpenAI)).toBe(
maxOutputTokensMap[EModelEndpoint.azureOpenAI][model],
);
}
});

test('should return correct max output tokens for GPT-OSS models', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
['gpt-oss-20b', 'gpt-oss-120b'].forEach((model) => {
expect(getModelMaxOutputTokens(model)).toBe(maxOutputTokensMap[EModelEndpoint.openAI][model]);
expect(getModelMaxOutputTokens(model, EModelEndpoint.openAI)).toBe(
maxOutputTokensMap[EModelEndpoint.openAI][model],
);
expect(getModelMaxOutputTokens(model, EModelEndpoint.azureOpenAI)).toBe(
maxOutputTokensMap[EModelEndpoint.azureOpenAI][model],
);
});
});
});

describe('findMatchingPattern - longest match wins', () => {
Expand Down Expand Up @@ -1060,45 +1016,6 @@ describe('Meta Models Tests', () => {
});
});

describe('DeepSeek Max Output Tokens', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');

test('should return correct max output tokens for deepseek-chat', () => {
const expected = maxOutputTokensMap[EModelEndpoint.openAI]['deepseek-chat'];
expect(getModelMaxOutputTokens('deepseek-chat')).toBe(expected);
expect(getModelMaxOutputTokens('deepseek-chat', EModelEndpoint.openAI)).toBe(expected);
expect(getModelMaxOutputTokens('deepseek-chat', EModelEndpoint.custom)).toBe(expected);
});

test('should return correct max output tokens for deepseek-reasoner', () => {
const expected = maxOutputTokensMap[EModelEndpoint.openAI]['deepseek-reasoner'];
expect(getModelMaxOutputTokens('deepseek-reasoner')).toBe(expected);
expect(getModelMaxOutputTokens('deepseek-reasoner', EModelEndpoint.openAI)).toBe(expected);
expect(getModelMaxOutputTokens('deepseek-reasoner', EModelEndpoint.custom)).toBe(expected);
});

test('should return correct max output tokens for deepseek-r1', () => {
const expected = maxOutputTokensMap[EModelEndpoint.openAI]['deepseek-r1'];
expect(getModelMaxOutputTokens('deepseek-r1')).toBe(expected);
expect(getModelMaxOutputTokens('deepseek-r1', EModelEndpoint.openAI)).toBe(expected);
});

test('should return correct max output tokens for deepseek base pattern', () => {
const expected = maxOutputTokensMap[EModelEndpoint.openAI]['deepseek'];
expect(getModelMaxOutputTokens('deepseek')).toBe(expected);
expect(getModelMaxOutputTokens('deepseek-v3')).toBe(expected);
});

test('should handle DeepSeek models with provider prefixes for max output tokens', () => {
expect(getModelMaxOutputTokens('deepseek/deepseek-chat')).toBe(
maxOutputTokensMap[EModelEndpoint.openAI]['deepseek-chat'],
);
expect(getModelMaxOutputTokens('openrouter/deepseek-reasoner')).toBe(
maxOutputTokensMap[EModelEndpoint.openAI]['deepseek-reasoner'],
);
});
});

describe('processModelData with Meta models', () => {
test('should process Meta model data correctly', () => {
const input = {
Expand Down Expand Up @@ -1447,13 +1364,6 @@ describe('Claude Model Tests', () => {
);
});

it('should return correct max output tokens for Claude Opus 4.6 (128K)', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
expect(getModelMaxOutputTokens('claude-opus-4-6', EModelEndpoint.anthropic)).toBe(
maxOutputTokensMap[EModelEndpoint.anthropic]['claude-opus-4-6'],
);
});

it('should handle Claude Opus 4.6 model name variations', () => {
const modelVariations = [
'claude-opus-4-6',
Expand Down Expand Up @@ -1497,13 +1407,6 @@ describe('Claude Model Tests', () => {
);
});

it('should return correct max output tokens for Claude Opus 4.7 (128K)', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
expect(getModelMaxOutputTokens('claude-opus-4-7', EModelEndpoint.anthropic)).toBe(
maxOutputTokensMap[EModelEndpoint.anthropic]['claude-opus-4-7'],
);
});

it('should match model names correctly for Claude Opus 4.7', () => {
const modelVariations = [
'claude-opus-4-7',
Expand All @@ -1528,13 +1431,6 @@ describe('Claude Model Tests', () => {
);
});

it('should return correct max output tokens for Claude Opus 4.8 (128K)', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
expect(getModelMaxOutputTokens('claude-opus-4-8', EModelEndpoint.anthropic)).toBe(
maxOutputTokensMap[EModelEndpoint.anthropic]['claude-opus-4-8'],
);
});

it('should match model names correctly for Claude Opus 4.8', () => {
const modelVariations = [
'claude-opus-4-8',
Expand All @@ -1559,13 +1455,6 @@ describe('Claude Model Tests', () => {
);
});

it('should return correct max output tokens for Claude Opus 5 (128K)', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
expect(getModelMaxOutputTokens('claude-opus-5', EModelEndpoint.anthropic)).toBe(
maxOutputTokensMap[EModelEndpoint.anthropic]['claude-opus-5'],
);
});

it('should match model names correctly for Claude Opus 5', () => {
const modelVariations = [
'claude-opus-5',
Expand All @@ -1590,13 +1479,6 @@ describe('Claude Model Tests', () => {
);
});

it('should return correct max output tokens for Claude Fable 5 (128K)', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
expect(getModelMaxOutputTokens('claude-fable-5', EModelEndpoint.anthropic)).toBe(
maxOutputTokensMap[EModelEndpoint.anthropic]['claude-fable-5'],
);
});

it('should match model names correctly for Claude Fable 5', () => {
const modelVariations = [
'claude-fable-5',
Expand All @@ -1621,13 +1503,6 @@ describe('Claude Model Tests', () => {
);
});

it('should return correct max output tokens for Claude Mythos 5 (128K)', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
expect(getModelMaxOutputTokens('claude-mythos-5', EModelEndpoint.anthropic)).toBe(
maxOutputTokensMap[EModelEndpoint.anthropic]['claude-mythos-5'],
);
});

it('should match model names correctly for Claude Mythos 5', () => {
const modelVariations = [
'claude-mythos-5',
Expand All @@ -1650,14 +1525,6 @@ describe('Claude Model Tests', () => {
expect(getModelMaxTokens('claude-mythos-5-1', EModelEndpoint.anthropic)).toBe(1000000);
});

it('should return correct max output tokens for Claude Fable 5.1 (128K)', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
expect(maxOutputTokensMap[EModelEndpoint.anthropic]['claude-fable-5-1']).toBe(128000);
expect(maxOutputTokensMap[EModelEndpoint.anthropic]['claude-mythos-5-1']).toBe(128000);
expect(getModelMaxOutputTokens('claude-fable-5-1', EModelEndpoint.anthropic)).toBe(128000);
expect(getModelMaxOutputTokens('claude-mythos-5-1', EModelEndpoint.anthropic)).toBe(128000);
});

it('should match model names correctly for Claude Fable 5.1 without collapsing to Fable 5', () => {
const modelVariations = [
'claude-fable-5-1',
Expand Down Expand Up @@ -1692,16 +1559,6 @@ describe('Claude Model Tests', () => {
);
});

it('should return correct max output tokens for Claude Sonnet 4.6 (128K)', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
expect(getModelMaxOutputTokens('claude-sonnet-4-6', EModelEndpoint.anthropic)).toBe(
maxOutputTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4-6'],
);
expect(getModelMaxOutputTokens('claude-sonnet-4.6', EModelEndpoint.anthropic)).toBe(
maxOutputTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4.6'],
);
});

it('should return correct context length for Claude Sonnet 4.7+ aliases (1M)', () => {
[
'claude-sonnet-4-7',
Expand All @@ -1721,37 +1578,6 @@ describe('Claude Model Tests', () => {
expect(getModelMaxTokens('anthropic.claude-4-10-sonnet', EModelEndpoint.bedrock)).toBe(1000000);
});

it('should return correct max output tokens for Claude Sonnet 4.7+ aliases (128K)', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
[
'claude-sonnet-4-7',
'claude-sonnet-4.7',
'claude-sonnet-4-8',
'claude-sonnet-4.8',
'claude-sonnet-4-9',
'claude-sonnet-4.9',
'claude-sonnet-4-10',
'claude-sonnet-4.10',
'claude-4-10-sonnet',
'claude-4.10-sonnet',
].forEach((model) => {
expect(getModelMaxOutputTokens(model, EModelEndpoint.anthropic)).toBe(128000);
});
});

it('should not treat dated Claude Sonnet 4 IDs as Claude Sonnet 4.6+ aliases', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
expect(getModelMaxTokens('claude-sonnet-4-20250514', EModelEndpoint.anthropic)).toBe(
maxTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4'],
);
expect(getModelMaxOutputTokens('claude-sonnet-4-20250514', EModelEndpoint.anthropic)).toBe(
maxOutputTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4'],
);
expect(getModelMaxTokens('claude-4-20250514-sonnet', EModelEndpoint.bedrock)).toBe(
maxTokensMap[EModelEndpoint.bedrock]['claude-4'],
);
});

it('should keep double-digit Claude Sonnet 4 minor names when matching models', () => {
expect(matchModelName('claude-sonnet-4-10', EModelEndpoint.anthropic)).toBe(
'claude-sonnet-4-10',
Expand Down Expand Up @@ -1808,16 +1634,6 @@ describe('Claude Model Tests', () => {
);
});

it('should return correct max output tokens for Claude Sonnet 5 (128K)', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
expect(getModelMaxOutputTokens('claude-sonnet-5', EModelEndpoint.anthropic)).toBe(
maxOutputTokensMap[EModelEndpoint.anthropic]['claude-sonnet-5'],
);
expect(getModelMaxOutputTokens('claude-sonnet-5', EModelEndpoint.anthropic)).toBe(
getModelMaxOutputTokens('claude-sonnet-4-6', EModelEndpoint.anthropic),
);
});

it('should not match Claude Sonnet 5 against Claude Sonnet 4 keys', () => {
const modelVariations = [
'claude-sonnet-5',
Expand Down
4 changes: 0 additions & 4 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ export default [
files: ['**/*.ts', '**/*.tsx'],
// Package, E2E, and root integration tests are not part of the client
// TypeScript project. They still get the recommended rules above.
ignores: ['packages/**/*', 'client/vite.config.ts', 'e2e/**/*', 'src/tests/**/*'],
ignores: ['packages/**/*', 'client/vite.config.ts', 'e2e/**/*'],
plugins: {
'@typescript-eslint': typescriptEslintEslintPlugin,
jest: fixupPluginRules(jest),
Expand Down
4 changes: 0 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading