Files
wehub-resource-sync d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:20:55 +08:00

235 lines
9.0 KiB
TypeScript

/**
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
import {
getBaseModelProviders,
getHostedModels,
orderModelIdsByReleaseDate,
PROVIDER_DEFINITIONS,
} from '@/providers/models'
/** Maps a lowercased model ID to its provider's index in the catalog. */
const PROVIDER_INDEX_BY_MODEL = new Map<string, number>()
/** Maps a lowercased model ID to its release time (ms), or null when undated. */
const RELEASE_TIME_BY_MODEL = new Map<string, number | null>()
for (const [providerIndex, provider] of Object.values(PROVIDER_DEFINITIONS).entries()) {
for (const model of provider.models) {
const id = model.id.toLowerCase()
PROVIDER_INDEX_BY_MODEL.set(id, providerIndex)
RELEASE_TIME_BY_MODEL.set(id, model.releaseDate ? Date.parse(model.releaseDate) : null)
}
}
describe('orderModelIdsByReleaseDate', () => {
it('keeps provider grouping order intact', () => {
const ordered = orderModelIdsByReleaseDate(Object.keys(getBaseModelProviders()))
let lastProviderIndex = -1
const seenProviders = new Set<number>()
for (const id of ordered) {
const providerIndex = PROVIDER_INDEX_BY_MODEL.get(id.toLowerCase())
expect(providerIndex).toBeDefined()
// A provider's models must form one contiguous run: once we leave a provider
// we never return to it.
if (providerIndex !== lastProviderIndex) {
expect(seenProviders.has(providerIndex as number)).toBe(false)
seenProviders.add(providerIndex as number)
lastProviderIndex = providerIndex as number
}
}
})
it('sorts models within a provider newest-first by release date', () => {
const ordered = orderModelIdsByReleaseDate(Object.keys(getBaseModelProviders()))
for (let i = 1; i < ordered.length; i++) {
const prev = ordered[i - 1].toLowerCase()
const curr = ordered[i].toLowerCase()
if (PROVIDER_INDEX_BY_MODEL.get(prev) !== PROVIDER_INDEX_BY_MODEL.get(curr)) continue
const prevTime = RELEASE_TIME_BY_MODEL.get(prev)
const currTime = RELEASE_TIME_BY_MODEL.get(curr)
// Dated models precede undated ones; among dated models, newer precedes older.
if (prevTime == null) {
expect(currTime).toBeNull()
} else if (currTime != null) {
expect(prevTime).toBeGreaterThanOrEqual(currTime)
}
}
})
it('preserves the cross-provider grouping order given in the input', () => {
// Pick the first model of two different providers and feed the second provider
// first; the helper must keep that provider's group ahead of the other.
const byProvider = new Map<number, string[]>()
for (const id of Object.keys(getBaseModelProviders())) {
const providerIndex = PROVIDER_INDEX_BY_MODEL.get(id.toLowerCase()) as number
const bucket = byProvider.get(providerIndex) ?? []
bucket.push(id)
byProvider.set(providerIndex, bucket)
}
const providerIndexes = [...byProvider.keys()]
expect(providerIndexes.length).toBeGreaterThanOrEqual(2)
const [firstProvider, secondProvider] = providerIndexes
const fromFirst = byProvider.get(firstProvider) as string[]
const fromSecond = byProvider.get(secondProvider) as string[]
// Input order intentionally leads with the second provider.
const input = [fromSecond[0], fromFirst[0]]
const ordered = orderModelIdsByReleaseDate(input)
expect(PROVIDER_INDEX_BY_MODEL.get(ordered[0].toLowerCase())).toBe(secondProvider)
expect(PROVIDER_INDEX_BY_MODEL.get(ordered[1].toLowerCase())).toBe(firstProvider)
})
it('places unknown model IDs last, preserving their input order', () => {
const known = Object.keys(getBaseModelProviders())[0]
const ordered = orderModelIdsByReleaseDate(['mystery-a', known, 'mystery-b'])
expect(ordered[0]).toBe(known)
expect(ordered.slice(1)).toEqual(['mystery-a', 'mystery-b'])
})
it('is case-insensitive when matching catalog IDs', () => {
const id = Object.keys(getBaseModelProviders())[0]
const ordered = orderModelIdsByReleaseDate([id.toUpperCase()])
expect(ordered).toEqual([id.toUpperCase()])
})
it('returns an empty array for empty input', () => {
expect(orderModelIdsByReleaseDate([])).toEqual([])
})
it('does not add or drop any IDs', () => {
const input = Object.keys(getBaseModelProviders())
const ordered = orderModelIdsByReleaseDate(input)
expect([...ordered].sort()).toEqual([...input].sort())
})
})
describe('sakana provider definition', () => {
const sakana = PROVIDER_DEFINITIONS.sakana
it('is registered with fugu as the default model', () => {
expect(sakana).toBeDefined()
expect(sakana.id).toBe('sakana')
expect(sakana.defaultModel).toBe('fugu')
expect(sakana.modelPatterns).toEqual([/^fugu/])
})
it('exposes fugu and fugu-ultra with a 1M context window', () => {
expect(sakana.models.map((m) => m.id)).toEqual(['fugu', 'fugu-ultra'])
for (const model of sakana.models) {
expect(model.contextWindow).toBe(1000000)
}
})
it('prices both models at the documented fugu-ultra ceiling', () => {
for (const model of sakana.models) {
expect(model.pricing.input).toBe(5)
expect(model.pricing.output).toBe(30)
expect(model.pricing.cachedInput).toBe(0.5)
}
})
it('routes bare fugu model IDs to the sakana provider', () => {
const baseModels = getBaseModelProviders()
expect(baseModels.fugu).toBe('sakana')
expect(baseModels['fugu-ultra']).toBe('sakana')
})
})
describe('nvidia provider definition', () => {
const nvidia = PROVIDER_DEFINITIONS.nvidia
const expectedModels = [
{ id: 'nvidia/llama-3.1-nemotron-70b-instruct', contextWindow: 128000 },
{ id: 'nvidia/llama-3.1-nemotron-ultra-253b-v1', contextWindow: 131072 },
{ id: 'nvidia/llama-3.3-nemotron-super-49b-v1.5', contextWindow: 131072 },
{ id: 'nvidia/nemotron-3-nano-30b-a3b', contextWindow: 262144 },
{ id: 'nvidia/nemotron-3-super-120b-a12b', contextWindow: 1048576 },
{ id: 'nvidia/nemotron-3-ultra-550b-a55b', contextWindow: 1048576 },
]
it('is registered with the current-gen Super model as the default', () => {
expect(nvidia).toBeDefined()
expect(nvidia.id).toBe('nvidia')
expect(nvidia.defaultModel).toBe('nvidia/nemotron-3-super-120b-a12b')
expect(nvidia.modelPatterns).toEqual([/^nvidia\//])
})
it('exposes all six Nemotron models with the documented context windows', () => {
expect(nvidia.models.map((m) => m.id)).toEqual(expectedModels.map((m) => m.id))
for (const expected of expectedModels) {
const model = nvidia.models.find((m) => m.id === expected.id)
expect(model?.contextWindow).toBe(expected.contextWindow)
}
})
it('routes every nvidia model ID to the nvidia provider', () => {
const baseModels = getBaseModelProviders()
for (const expected of expectedModels) {
expect(baseModels[expected.id]).toBe('nvidia')
}
})
})
describe('zai provider definition', () => {
const zai = PROVIDER_DEFINITIONS.zai
const expectedModels = [
{ id: 'glm-5.2', contextWindow: 1000000 },
{ id: 'glm-5.1', contextWindow: 200000 },
{ id: 'glm-5', contextWindow: 200000 },
{ id: 'glm-5-turbo', contextWindow: 200000 },
{ id: 'glm-4.7', contextWindow: 200000 },
{ id: 'glm-4.7-flashx', contextWindow: 200000 },
{ id: 'glm-4.6', contextWindow: 200000 },
{ id: 'glm-4.5', contextWindow: 128000 },
{ id: 'glm-4.5-air', contextWindow: 128000 },
{ id: 'glm-4.5-x', contextWindow: 128000 },
{ id: 'glm-4.5-airx', contextWindow: 128000 },
{ id: 'glm-4-32b-0414-128k', contextWindow: 128000 },
]
it('is registered with a bare glm-4.6 as the default model', () => {
expect(zai).toBeDefined()
expect(zai.id).toBe('zai')
expect(zai.defaultModel).toBe('glm-4.6')
expect(zai.defaultModel.startsWith('zai/')).toBe(false)
// No fallback pattern — an unscoped `/^glm/` would overmatch unrelated self-hosted
// "glm-*" models and misroute them to Z.ai's hosted billing.
expect(zai.modelPatterns).toEqual([])
})
it('exposes every GLM model with the documented context window', () => {
expect(zai.models.map((m) => m.id)).toEqual(expectedModels.map((m) => m.id))
for (const expected of expectedModels) {
const model = zai.models.find((m) => m.id === expected.id)
expect(model?.contextWindow).toBe(expected.contextWindow)
}
})
it('routes every bare glm-* model ID to the zai provider', () => {
const baseModels = getBaseModelProviders()
for (const expected of expectedModels) {
expect(baseModels[expected.id]).toBe('zai')
}
})
it('is included in getHostedModels since Sim provides the Z.ai key server-side', () => {
expect(getHostedModels()).toContain('glm-4.6')
})
})
describe('xai provider definition', () => {
const xai = PROVIDER_DEFINITIONS.xai
it('is registered with grok-4.5 as the default model', () => {
expect(xai).toBeDefined()
expect(xai.id).toBe('xai')
expect(xai.defaultModel).toBe('grok-4.5')
})
it('is included in getHostedModels since Sim provides the xAI key server-side', () => {
expect(getHostedModels()).toContain('grok-4.5')
})
})