mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-08-29 10:22:42 +00:00
Identify OrcaRouter route ids as the routed model, not a branded label
This commit is contained in:
parent
5b25641440
commit
dcab9a451c
3 changed files with 34 additions and 24 deletions
|
|
@ -11,7 +11,7 @@
|
|||
- **`CODEBURN_CACHE_SCOPE=all` forces a full session-cache read.** A ranged query reads only the month shards that can contribute a turn to it, which is a real behaviour change on a warm cache; this is the escape hatch for the case where a number looks wrong and you want to know whether the scoped read is why. Set it and every load ignores its scope and reads every shard, one-shot runs and the resident `codeburn serve` alike. It is a read policy, not an input to any cache fingerprint: setting or unsetting it re-parses nothing and invalidates nothing.
|
||||
|
||||
### Added (OrcaRouter)
|
||||
- **OrcaRouter sessions now price and label like the model they route to.** OrcaRouter is a gateway that exposes route ids (`orcarouter/auto`, `orcarouter/fusion`, …) plus plain upstream ids (`deepseek/deepseek-v4-pro`), and reports the upstream id that actually ran in the completion response's `model` field. The `orcarouter/` prefix is now a routing wrapper like `cmd/` / `antigravity/`, so a routed spelling prices at its upstream LiteLLM row instead of $0; the smart route `orcarouter/auto` aliases to a fast Sonnet rate and the fusion routes alias to their current `openai/gpt-oss-120b` target, each keeping a branded route label (like the other `*-auto` presets); and an unknown vendor nested inside the route still fails closed.
|
||||
- **OrcaRouter sessions now price and label like the model they route to.** OrcaRouter is a gateway that exposes route ids (`orcarouter/auto`, `orcarouter/fusion`, …) plus plain upstream ids (`deepseek/deepseek-v4-pro`), and reports the upstream id that actually ran in the completion response's `model` field. The `orcarouter/` prefix is now a routing wrapper like `cmd/` / `antigravity/`, so a routed spelling prices at its upstream LiteLLM row instead of $0; the smart route `orcarouter/auto` aliases to a fast Sonnet rate and the fusion routes alias to their current `openai/gpt-oss-120b` target, so display and report identity match those routed models; and an unknown vendor nested inside the route still fails closed.
|
||||
|
||||
### Added (Windows)
|
||||
- **`codeburn menubar` installs and launches the tray app on Windows.** The same command that installs the macOS menubar now does the Windows one, through the same pinned-release path: it resolves `windows-v<cliVersion>`, falls back to a scan of the newest `windows-v*` release carrying both assets when that tag has none, downloads the `.msi` with the same retry and backoff, and verifies its sha256 before anything executes it — a mismatch aborts without ever handing the file to the installer. It then runs `msiexec` out of `%SystemRoot%\System32` (never a bare name, so nothing dropped next to the CLI can impersonate it) with `/i <msi> /passive /norestart`, treats exit 3010 as installed-pending-restart and 1602 as a cancelled install rather than failures, and launches the exe named by the product's Uninstall registry key. An already-installed matching version skips the download and just launches; `--force` reinstalls.
|
||||
|
|
|
|||
|
|
@ -290,8 +290,9 @@ export async function loadPricing(): Promise<void> {
|
|||
|
||||
// Known model name variants that providers emit but LiteLLM/fallback don't index under.
|
||||
// OMP emits 'anthropic--claude-4.6-opus' (double-dash, dot version, tier-last).
|
||||
// getCanonicalName strips a KNOWN vendor/router prefix first, so only the
|
||||
// post-strip forms need to be listed here.
|
||||
// getCanonicalName strips a KNOWN vendor/router prefix first unless the
|
||||
// full cleaned id itself is an alias (orcarouter/auto). Post-strip forms
|
||||
// still cover every other entry here.
|
||||
const BUILTIN_ALIASES: Record<string, string> = {
|
||||
'anthropic--claude-4.6-opus': 'claude-opus-4-6',
|
||||
'anthropic--claude-4.6-sonnet': 'claude-sonnet-4-6',
|
||||
|
|
@ -347,11 +348,12 @@ const BUILTIN_ALIASES: Record<string, string> = {
|
|||
// OrcaRouter's smart route. The route picks a model per request; at the time
|
||||
// of writing it lands on a Qwen/Llama flash model, so a fast Sonnet rate is
|
||||
// the honest estimate until the route's target stabilizes (mirrors the
|
||||
// `*-auto` presets above).
|
||||
// `*-auto` presets above). Display and report identity follow this target.
|
||||
'orcarouter/auto': 'claude-sonnet-4-5',
|
||||
// OrcaRouter's fusion routes currently serve openai/gpt-oss-120b (verified
|
||||
// live 2026-08). If the gateway re-routes them, these drift like any other
|
||||
// preset estimate; they keep a priced row instead of reporting $0.
|
||||
// preset estimate; they keep a priced row instead of reporting $0. Display
|
||||
// and report identity follow this target, not a branded route label.
|
||||
'orcarouter/fusion': 'openai/gpt-oss-120b',
|
||||
'orcarouter/fusion-flash': 'openai/gpt-oss-120b',
|
||||
'orcarouter/fusion-mini': 'openai/gpt-oss-120b',
|
||||
|
|
@ -785,12 +787,21 @@ function resolveAlias(model: string): string {
|
|||
return model
|
||||
}
|
||||
function getCanonicalName(model: string): string {
|
||||
return stripKnownFirstNamespace(
|
||||
model
|
||||
.replace(/@.*$/, '')
|
||||
.replace(/-\d{8}$/, '')
|
||||
.replace(/\[[^\]]*\]$/, ''),
|
||||
)
|
||||
const cleaned = model
|
||||
.replace(/@.*$/, '')
|
||||
.replace(/-\d{8}$/, '')
|
||||
.replace(/\[[^\]]*\]$/, '')
|
||||
// Full-id aliases (orcarouter/auto) must stay visible so resolveAlias can
|
||||
// see them. Stripping first would leave a leaf (`auto`) with no mapping.
|
||||
// Nested wrappers without an alias still peel as before.
|
||||
if (Object.hasOwn(userAliases, cleaned) || Object.hasOwn(BUILTIN_ALIASES, cleaned)) {
|
||||
return cleaned
|
||||
}
|
||||
const lowercase = cleaned.toLowerCase()
|
||||
if (lowercase !== cleaned && Object.hasOwn(BUILTIN_ALIASES, lowercase)) {
|
||||
return cleaned
|
||||
}
|
||||
return stripKnownFirstNamespace(cleaned)
|
||||
}
|
||||
|
||||
/// Alias-resolved identity for report merge. Display names stay cosmetic —
|
||||
|
|
@ -1167,14 +1178,6 @@ const autoModelNames: Record<string, string> = {
|
|||
'openclaw-auto': 'OpenClaw (auto)',
|
||||
'qwen-auto': 'Qwen (auto)',
|
||||
'kimi-auto': 'Kimi (auto)',
|
||||
// OrcaRouter route ids. The smart route routes per request and the fusion
|
||||
// routes resolve to a gateway-picked upstream, so each keeps its branded
|
||||
// route label rather than the current upstream's display name. Prices are
|
||||
// aliased in BUILTIN_ALIASES to the route's current target.
|
||||
'orcarouter/auto': 'OrcaRouter (auto)',
|
||||
'orcarouter/fusion': 'OrcaRouter Fusion',
|
||||
'orcarouter/fusion-flash': 'OrcaRouter Fusion Flash',
|
||||
'orcarouter/fusion-mini': 'OrcaRouter Fusion Mini',
|
||||
'codex-auto-review': 'Codex Auto Review',
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -218,6 +218,13 @@ describe('resolveCanonicalModelId', () => {
|
|||
expect(resolveCanonicalModelId('claude-opus-4.6')).toBe('claude-opus-4-6')
|
||||
expect(resolveCanonicalModelId('kimi-code')).toBe('kimi-k2-thinking')
|
||||
expect(resolveCanonicalModelId('cline-pass/kimi-k3')).toBe('kimi-k3')
|
||||
expect(resolveCanonicalModelId('orcarouter/auto')).toBe(resolveCanonicalModelId('claude-sonnet-4-5'))
|
||||
expect(resolveCanonicalModelId('orcarouter/fusion')).toBe(resolveCanonicalModelId('openai/gpt-oss-120b'))
|
||||
expect(resolveCanonicalModelId('orcarouter/fusion-flash')).toBe(resolveCanonicalModelId('openai/gpt-oss-120b'))
|
||||
expect(resolveCanonicalModelId('orcarouter/fusion-mini')).toBe(resolveCanonicalModelId('openai/gpt-oss-120b'))
|
||||
expect(resolveCanonicalModelId('orcarouter/deepseek/deepseek-v4-pro')).toBe(
|
||||
resolveCanonicalModelId('deepseek/deepseek-v4-pro'),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -282,11 +289,11 @@ describe('getShortModelName', () => {
|
|||
expect(getShortModelName('cp/cline-pass/glm-5.3')).toBe('GLM-5.3')
|
||||
// OrcaRouter route ids peel to the upstream id, which keeps the upstream label.
|
||||
expect(getShortModelName('orcarouter/deepseek/deepseek-v4-pro')).toBe('DeepSeek v4 Pro')
|
||||
// The route ids keep their branded labels (like the other `*-auto` presets).
|
||||
expect(getShortModelName('orcarouter/auto')).toBe('OrcaRouter (auto)')
|
||||
expect(getShortModelName('orcarouter/fusion')).toBe('OrcaRouter Fusion')
|
||||
expect(getShortModelName('orcarouter/fusion-flash')).toBe('OrcaRouter Fusion Flash')
|
||||
expect(getShortModelName('orcarouter/fusion-mini')).toBe('OrcaRouter Fusion Mini')
|
||||
// Route ids display as the model they route to, not a branded gateway label.
|
||||
expect(getShortModelName('orcarouter/auto')).toBe(getShortModelName('claude-sonnet-4-5'))
|
||||
expect(getShortModelName('orcarouter/fusion')).toBe(getShortModelName('openai/gpt-oss-120b'))
|
||||
expect(getShortModelName('orcarouter/fusion-flash')).toBe(getShortModelName('openai/gpt-oss-120b'))
|
||||
expect(getShortModelName('orcarouter/fusion-mini')).toBe(getShortModelName('openai/gpt-oss-120b'))
|
||||
// Grok Build prices via the grok-build-0.1 sibling.
|
||||
expect(getShortModelName('grok-build')).toBe('Grok Build')
|
||||
expect(getShortModelName('grok-build-0.1')).toBe('Grok Build')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue