mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-09 20:58:29 +00:00
fix(copilot): handle zero billing batch size (#36123)
This commit is contained in:
parent
b4665a8bf8
commit
b8374b5a7c
4 changed files with 92 additions and 6 deletions
|
|
@ -99,7 +99,7 @@ function build(key: string, remote: SelectableItem, url: string, prev?: Model):
|
|||
: undefined
|
||||
const prices = remote.billing?.token_prices
|
||||
// Copilot prices are AIC per billing batch; OpenCode stores USD per million tokens.
|
||||
const usdPerMillion = prices ? 10_000 / prices.batch_size : 0
|
||||
const usdPerMillion = prices && prices.batch_size > 0 ? 10_000 / prices.batch_size : 0
|
||||
|
||||
const model: CopilotModel = {
|
||||
id: key,
|
||||
|
|
|
|||
|
|
@ -1071,11 +1071,17 @@ export type ConfigProvidersResult = Types.DeepMutable<Schema.Schema.Type<typeof
|
|||
|
||||
export function toPublicInfo(provider: Info): Info {
|
||||
return JSON.parse(
|
||||
JSON.stringify(provider, (_, value) => {
|
||||
JSON.stringify(
|
||||
{
|
||||
...provider,
|
||||
models: Object.fromEntries(Object.entries(provider.models).filter(([, model]) => Schema.is(Model)(model))),
|
||||
},
|
||||
(_, value) => {
|
||||
if (typeof value === "function" || typeof value === "symbol" || value === undefined) return undefined
|
||||
if (typeof value === "bigint") return value.toString()
|
||||
return value
|
||||
}),
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,6 +187,60 @@ test("converts Copilot AIC token prices to USD per million tokens", async () =>
|
|||
expect(models["ignored-non-chat-record"]).toBeUndefined()
|
||||
})
|
||||
|
||||
test("uses zero cost when Copilot reports a zero billing batch size", async () => {
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
data: [
|
||||
{
|
||||
model_picker_enabled: true,
|
||||
id: "mercury-alpha",
|
||||
name: "Mercury Alpha",
|
||||
version: "mercury-alpha-2026-07-09",
|
||||
billing: {
|
||||
token_prices: {
|
||||
batch_size: 0,
|
||||
default: {
|
||||
input_price: 0,
|
||||
output_price: 0,
|
||||
cache_price: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
capabilities: {
|
||||
family: "mercury",
|
||||
limits: {
|
||||
max_context_window_tokens: 128000,
|
||||
max_output_tokens: 16384,
|
||||
max_prompt_tokens: 128000,
|
||||
},
|
||||
supports: {
|
||||
streaming: true,
|
||||
tool_calls: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
{ status: 200 },
|
||||
),
|
||||
),
|
||||
) as unknown as typeof fetch
|
||||
|
||||
const model = (await CopilotModels.get("https://api.githubcopilot.com")).models["mercury-alpha"]
|
||||
|
||||
expect(model.cost).toEqual({
|
||||
input: 0,
|
||||
output: 0,
|
||||
cache: {
|
||||
read: 0,
|
||||
write: 0,
|
||||
},
|
||||
})
|
||||
expect(JSON.stringify(model)).not.toContain("null")
|
||||
})
|
||||
|
||||
test("records Copilot advertised responses endpoint for non-GPT model IDs", async () => {
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve(
|
||||
|
|
|
|||
|
|
@ -1426,6 +1426,32 @@ test("models.dev normalization fills required response fields", () => {
|
|||
expect(model.release_date).toBe("")
|
||||
})
|
||||
|
||||
test("public provider info omits invalid models", () => {
|
||||
const provider = Provider.fromModelsDevProvider({
|
||||
id: "test",
|
||||
name: "Test",
|
||||
env: [],
|
||||
models: {
|
||||
valid: {
|
||||
id: "valid",
|
||||
name: "Valid",
|
||||
cost: { input: 1, output: 1 },
|
||||
limit: { context: 128_000, output: 16_000 },
|
||||
},
|
||||
},
|
||||
} as unknown as ModelsDev.Provider)
|
||||
provider.models.invalid = {
|
||||
...provider.models.valid,
|
||||
id: ModelV2.ID.make("invalid"),
|
||||
cost: { ...provider.models.valid.cost, input: Number.NaN },
|
||||
}
|
||||
|
||||
const result = Provider.toPublicInfo(provider)
|
||||
|
||||
expect(result.models.valid).toBeDefined()
|
||||
expect(result.models.invalid).toBeUndefined()
|
||||
})
|
||||
|
||||
it.instance("model variants are generated for reasoning models", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* set("ANTHROPIC_API_KEY", "test-api-key")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue