mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-05-01 16:30:15 +00:00
Add OMP provider support and model alias mapping
- Add OMP provider reading from ~/.omp/agent/sessions (same JSONL format as Pi, shared parser) - Parameterize discoverSessionsInDir with provider name so sessions carry correct provider field - Add BUILTIN_ALIASES for proxy model name variants (anthropic--claude-* double-dash format) that don't match LiteLLM keys - Add model-alias CLI command for user-defined name mappings - Wire setModelAliases into preAction after config load - Add modelAliases field to CodeburnConfig - Update README: OMP in provider table, model-alias section
This commit is contained in:
parent
b0d7a8b678
commit
79e67f0bc9
9 changed files with 507 additions and 17 deletions
135
tests/models.test.ts
Normal file
135
tests/models.test.ts
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
import { describe, it, expect, afterEach } from 'vitest'
|
||||
import { getModelCosts, getShortModelName, calculateCost, setModelAliases } from '../src/models.js'
|
||||
|
||||
// Tests run without loadPricing — fallback pricing only.
|
||||
// setModelAliases resets between tests to avoid cross-contamination.
|
||||
afterEach(() => setModelAliases({}))
|
||||
|
||||
describe('builtin aliases - getModelCosts', () => {
|
||||
it('resolves anthropic--claude-4.6-opus', () => {
|
||||
expect(getModelCosts('anthropic--claude-4.6-opus')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('resolves anthropic--claude-4.6-sonnet', () => {
|
||||
expect(getModelCosts('anthropic--claude-4.6-sonnet')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('resolves anthropic--claude-4.5-opus', () => {
|
||||
expect(getModelCosts('anthropic--claude-4.5-opus')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('resolves anthropic--claude-4.5-sonnet', () => {
|
||||
expect(getModelCosts('anthropic--claude-4.5-sonnet')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('resolves anthropic--claude-4.5-haiku', () => {
|
||||
expect(getModelCosts('anthropic--claude-4.5-haiku')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('resolves double-wrapped anthropic/anthropic--claude-4.6-opus', () => {
|
||||
expect(getModelCosts('anthropic/anthropic--claude-4.6-opus')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('resolves double-wrapped anthropic/anthropic--claude-4.6-sonnet', () => {
|
||||
expect(getModelCosts('anthropic/anthropic--claude-4.6-sonnet')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('resolves double-wrapped anthropic/anthropic--claude-4.5-haiku', () => {
|
||||
expect(getModelCosts('anthropic/anthropic--claude-4.5-haiku')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('OMP opus resolves to same pricing as canonical claude-opus-4-6', () => {
|
||||
expect(getModelCosts('anthropic--claude-4.6-opus')).toEqual(getModelCosts('claude-opus-4-6'))
|
||||
})
|
||||
|
||||
it('OMP sonnet resolves to same pricing as canonical claude-sonnet-4-6', () => {
|
||||
expect(getModelCosts('anthropic--claude-4.6-sonnet')).toEqual(getModelCosts('claude-sonnet-4-6'))
|
||||
})
|
||||
|
||||
it('OMP haiku resolves to same pricing as canonical claude-haiku-4-5', () => {
|
||||
expect(getModelCosts('anthropic--claude-4.5-haiku')).toEqual(getModelCosts('claude-haiku-4-5'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('builtin aliases - getShortModelName', () => {
|
||||
it('anthropic--claude-4.6-opus -> Opus 4.6', () => {
|
||||
expect(getShortModelName('anthropic--claude-4.6-opus')).toBe('Opus 4.6')
|
||||
})
|
||||
|
||||
it('anthropic--claude-4.6-sonnet -> Sonnet 4.6', () => {
|
||||
expect(getShortModelName('anthropic--claude-4.6-sonnet')).toBe('Sonnet 4.6')
|
||||
})
|
||||
|
||||
it('anthropic--claude-4.5-opus -> Opus 4.5', () => {
|
||||
expect(getShortModelName('anthropic--claude-4.5-opus')).toBe('Opus 4.5')
|
||||
})
|
||||
|
||||
it('anthropic--claude-4.5-sonnet -> Sonnet 4.5', () => {
|
||||
expect(getShortModelName('anthropic--claude-4.5-sonnet')).toBe('Sonnet 4.5')
|
||||
})
|
||||
|
||||
it('anthropic--claude-4.5-haiku -> Haiku 4.5', () => {
|
||||
expect(getShortModelName('anthropic--claude-4.5-haiku')).toBe('Haiku 4.5')
|
||||
})
|
||||
|
||||
it('anthropic/anthropic--claude-4.6-opus -> Opus 4.6', () => {
|
||||
expect(getShortModelName('anthropic/anthropic--claude-4.6-opus')).toBe('Opus 4.6')
|
||||
})
|
||||
})
|
||||
|
||||
describe('user aliases via setModelAliases', () => {
|
||||
it('user alias resolves for getModelCosts', () => {
|
||||
setModelAliases({ 'my-internal-model': 'claude-sonnet-4-6' })
|
||||
expect(getModelCosts('my-internal-model')).toEqual(getModelCosts('claude-sonnet-4-6'))
|
||||
})
|
||||
|
||||
it('user alias resolves for getShortModelName', () => {
|
||||
setModelAliases({ 'my-internal-model': 'claude-opus-4-6' })
|
||||
expect(getShortModelName('my-internal-model')).toBe('Opus 4.6')
|
||||
})
|
||||
|
||||
it('user alias overrides builtin', () => {
|
||||
// Remap an OMP key to a different canonical target
|
||||
setModelAliases({ 'anthropic--claude-4.6-opus': 'claude-sonnet-4-5' })
|
||||
expect(getModelCosts('anthropic--claude-4.6-opus')).toEqual(getModelCosts('claude-sonnet-4-5'))
|
||||
})
|
||||
|
||||
it('resetting aliases restores builtins', () => {
|
||||
setModelAliases({ 'anthropic--claude-4.6-opus': 'claude-sonnet-4-5' })
|
||||
setModelAliases({})
|
||||
// Back to builtin: should resolve as opus pricing, not sonnet
|
||||
expect(getModelCosts('anthropic--claude-4.6-opus')).toEqual(getModelCosts('claude-opus-4-6'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('calculateCost - OMP names produce non-zero cost', () => {
|
||||
it('calculates cost for anthropic--claude-4.6-opus', () => {
|
||||
expect(calculateCost('anthropic--claude-4.6-opus', 1000, 200, 0, 0, 0)).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('calculates cost for anthropic/anthropic--claude-4.6-sonnet', () => {
|
||||
expect(calculateCost('anthropic/anthropic--claude-4.6-sonnet', 1000, 200, 0, 0, 0)).toBeGreaterThan(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('existing model names still resolve', () => {
|
||||
it('canonical claude-opus-4-6', () => {
|
||||
expect(getModelCosts('claude-opus-4-6')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('canonical claude-sonnet-4-5', () => {
|
||||
expect(getModelCosts('claude-sonnet-4-5')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('date-stamped claude-sonnet-4-20250514', () => {
|
||||
expect(getModelCosts('claude-sonnet-4-20250514')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('pinned claude-sonnet-4-6@20250929', () => {
|
||||
expect(getModelCosts('claude-sonnet-4-6@20250929')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('anthropic/-prefixed anthropic/claude-opus-4-6', () => {
|
||||
expect(getModelCosts('anthropic/claude-opus-4-6')).not.toBeNull()
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue