Files
nexu-io__open-design/apps/web/tests/state/maxTokens.test.ts
Sid b4d6e2e095 Refresh Ollama Cloud choices for recent models (#4943)
Ollama Cloud BYOK still uses curated model lists because live discovery is disabled for that protocol. The public Ollama tags endpoint now includes newer cloud models reported in #4911, but the Settings/onboarding pickers still offered the older static set.

This updates both the generic Ollama suggestions and the managed Ollama Cloud preset so the picker surfaces the same recent models everywhere. The max-token override table is updated at the same time so newly selectable models do not fall through to the unknown-model 8192 token default.

Constraint: Ollama Cloud model discovery remains disabled in the app, so the picker still depends on curated tables

Rejected: Change existing cloud suffix/tag names from PR #4716 | that separate draft already owns broken existing IDs and changing them here would mix scopes

Confidence: high

Scope-risk: narrow

Directive: Keep SUGGESTED_MODELS_BY_PROTOCOL.ollama, the Ollama Cloud KNOWN_PROVIDERS models, and Ollama max-token overrides in sync when adding curated cloud models

Tested: pnpm exec vitest run -c vitest.config.ts tests/state/api-protocols.test.ts tests/state/maxTokens.test.ts tests/state/config.test.ts tests/components/SettingsDialog.execution.test.tsx --maxWorkers=2

Tested: pnpm --filter @open-design/web typecheck

Tested: pnpm guard

Tested: pnpm typecheck

Tested: pnpm --filter @open-design/web test

Not-tested: Live Ollama Cloud API request with a user key

Related: #4911
2026-07-02 09:51:04 +00:00

97 lines
4.3 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import litellmData from '../../src/state/litellm-models.json';
import {
effectiveMaxTokens,
FALLBACK_MAX_TOKENS,
MAX_MAX_TOKENS,
MIN_MAX_TOKENS,
modelMaxTokensDefault,
} from '../../src/state/maxTokens';
describe('modelMaxTokensDefault', () => {
it('falls through to LiteLLM data for canonical Anthropic ids', () => {
// 64k for the 4.5 line is the upstream value; this guards against the
// sync script silently dropping or rewriting these entries.
expect(modelMaxTokensDefault('claude-sonnet-4-5')).toBe(64000);
expect(modelMaxTokensDefault('claude-opus-4-5')).toBe(64000);
expect(modelMaxTokensDefault('claude-haiku-4-5')).toBe(64000);
});
it('lets OVERRIDES win over LiteLLM data', () => {
// mimo-v2.5-pro is not in LiteLLM, so this asserts the OVERRIDES path
// (not the LiteLLM path) supplied the answer.
expect((litellmData.models as Record<string, number>)['mimo-v2.5-pro']).toBeUndefined();
expect(modelMaxTokensDefault('mimo-v2.5-pro')).toBe(32768);
});
it('returns DeepSeek v4 output caps from OVERRIDES (not in LiteLLM upstream)', () => {
// DeepSeek v4 models are not tracked by LiteLLM as of 2026-05-07,
// so OVERRIDES must supply 384K to avoid falling back to 8192.
expect((litellmData.models as Record<string, number>)['deepseek-v4-pro']).toBeUndefined();
expect((litellmData.models as Record<string, number>)['deepseek-v4-flash']).toBeUndefined();
expect(modelMaxTokensDefault('deepseek-v4-pro')).toBe(384000);
expect(modelMaxTokensDefault('deepseek-v4-flash')).toBe(384000);
});
it('keeps recent Ollama Cloud models out of the unknown-model fallback', () => {
expect(modelMaxTokensDefault('glm-5.2')).toBe(131072);
expect(modelMaxTokensDefault('kimi-k2.7-code')).toBe(131072);
});
it('returns FALLBACK_MAX_TOKENS for unknown ids', () => {
expect(modelMaxTokensDefault('definitely-not-a-real-model-x9z')).toBe(FALLBACK_MAX_TOKENS);
expect(FALLBACK_MAX_TOKENS).toBe(8192);
});
});
describe('effectiveMaxTokens', () => {
it('honors an explicit user override over the model default', () => {
expect(effectiveMaxTokens({ maxTokens: 12345, model: 'claude-sonnet-4-5' })).toBe(12345);
});
it('uses the model default when no override is set', () => {
expect(effectiveMaxTokens({ model: 'mimo-v2.5-pro' })).toBe(32768);
expect(effectiveMaxTokens({ model: 'claude-sonnet-4-5' })).toBe(64000);
});
it('falls back to FALLBACK_MAX_TOKENS for unknown models with no override', () => {
expect(effectiveMaxTokens({ model: 'unknown-model' })).toBe(FALLBACK_MAX_TOKENS);
});
});
describe('effectiveMaxTokens override validation', () => {
// Stale localStorage, hand-edited config, or future schema drift can put
// anything in cfg.maxTokens. The Settings UI advertises a [1024, 200000]
// integer-stepped range, and the daemon proxy already clamps `> 0`, so
// we tighten this entry point to match the advertised contract.
it('rejects negative overrides and falls back to the model default', () => {
expect(effectiveMaxTokens({ maxTokens: -5, model: 'claude-sonnet-4-5' })).toBe(64000);
});
it('rejects zero', () => {
expect(effectiveMaxTokens({ maxTokens: 0, model: 'claude-sonnet-4-5' })).toBe(64000);
});
it('rejects overrides below MIN_MAX_TOKENS', () => {
expect(effectiveMaxTokens({ maxTokens: MIN_MAX_TOKENS - 1, model: 'claude-sonnet-4-5' })).toBe(64000);
});
it('rejects overrides above MAX_MAX_TOKENS', () => {
expect(effectiveMaxTokens({ maxTokens: MAX_MAX_TOKENS + 1, model: 'claude-sonnet-4-5' })).toBe(64000);
expect(effectiveMaxTokens({ maxTokens: 999_999_999, model: 'claude-sonnet-4-5' })).toBe(64000);
});
it('rejects non-integer overrides', () => {
expect(effectiveMaxTokens({ maxTokens: 123.9, model: 'claude-sonnet-4-5' })).toBe(64000);
expect(effectiveMaxTokens({ maxTokens: Number.NaN, model: 'claude-sonnet-4-5' })).toBe(64000);
expect(effectiveMaxTokens({ maxTokens: Number.POSITIVE_INFINITY, model: 'claude-sonnet-4-5' })).toBe(64000);
});
it('accepts the boundary values exactly', () => {
expect(effectiveMaxTokens({ maxTokens: MIN_MAX_TOKENS, model: 'claude-sonnet-4-5' })).toBe(MIN_MAX_TOKENS);
expect(effectiveMaxTokens({ maxTokens: MAX_MAX_TOKENS, model: 'claude-sonnet-4-5' })).toBe(MAX_MAX_TOKENS);
});
});