mirror of
https://gitee.com/zhangsken/opencode.git
synced 2026-10-23 17:18:57 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 03690bbbdb | |||
| 7137b3276b |
@@ -293,7 +293,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/alibaba": "1.0.17",
|
||||
"@ai-sdk/amazon-bedrock": "4.0.158",
|
||||
"@ai-sdk/amazon-bedrock": "4.0.112",
|
||||
"@ai-sdk/anthropic": "3.0.82",
|
||||
"@ai-sdk/azure": "3.0.88",
|
||||
"@ai-sdk/cerebras": "2.0.41",
|
||||
@@ -568,7 +568,7 @@
|
||||
"@actions/github": "6.0.1",
|
||||
"@agentclientprotocol/sdk": "0.21.0",
|
||||
"@ai-sdk/alibaba": "1.0.17",
|
||||
"@ai-sdk/amazon-bedrock": "4.0.158",
|
||||
"@ai-sdk/amazon-bedrock": "4.0.112",
|
||||
"@ai-sdk/anthropic": "3.0.82",
|
||||
"@ai-sdk/azure": "3.0.88",
|
||||
"@ai-sdk/cerebras": "2.0.60",
|
||||
@@ -1173,7 +1173,7 @@
|
||||
|
||||
"@ai-sdk/alibaba": ["@ai-sdk/alibaba@1.0.17", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZbE+U5bWz2JBc5DERLowx5+TKbjGBE93LqKZAWvuEn7HOSQMraxFMZuc0ST335QZJAyfBOzh7m1mPQ+y7EaaoA=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.158", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.111", "@ai-sdk/openai": "3.0.98", "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.46", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-yZebHEszUzPLsK+Rq5sVZJkJj7EYDgY+Lz36IGf/RSkSC5LOMDbVKoQ55S8xNzJqVjUDqlWuZiQzg40HQslmCw=="],
|
||||
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.112", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.81", "@ai-sdk/openai": "3.0.67", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-PsSh7a6qW+3kQXPs1kD4wDwuZby0t1PIaB6j/1aMKmPFJ5LxcIcULLMF/bjITLt5o/8lc0t6TXIwG0zlhH7uZw=="],
|
||||
|
||||
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.82", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-WKKou2wbhGGYV8PSALAPyV2YY4nfCqCPkyBzYtJtDA9yCcIFwsbtkTNgg7bqtLCVzeEsY7wwxRoCWy+EMfrw/A=="],
|
||||
|
||||
@@ -5641,13 +5641,13 @@
|
||||
|
||||
"@ai-sdk/alibaba/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.111", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.46" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-atgBW8jZPr/KuaKX5FvDIHuXBI8VCol6kVeoD4P0657+VXR73QsLogXQVN/Zt5FHtq9WzpdIZseCJiXPqkgwwA=="],
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.81", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-B1JDd9Ugq9R5AgIaW3674lhGCMMYJcPUxnrZh8fzbGojgg4QvHFRv6eZahGQAUsmGHbcf74G9bdSBDLWQGY2GA=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/openai": ["@ai-sdk/openai@3.0.98", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.46" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-nAvp8pVOUJ3znJHRzZs54Y7CJQSikOW1Ty7LTdtQT+/pgtAwqhuKd8oaXbiW2xQaYBdH2i8o9AcEpcUdXIyF+g=="],
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/openai": ["@ai-sdk/openai@3.0.67", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-oAiGC9eWG7IgtdsdS74bOCnAAHarAfTJhWN9x5INwnWPekL802AvF+0I5DvLzIF1MIRmNw4N8mPSL/GUVbX9Mw=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/provider": ["@ai-sdk/provider@3.0.15", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-XeZW1CcDF2GMbH4wejW6xBRI2QCOgnkVYUnxoeDadB1mf85riL2bMUeDoh+6gJ/r4mjNfzUPW8OjLjvwTP0u1Q=="],
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/provider": ["@ai-sdk/provider@3.0.10", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.46", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8", "undici": "^6.28.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-tEtld97plCFiYevsJuOkGkeuhQndeMWFBVrJS4AjnbD5AqrNSXRCe0p+BZ3Cju/sxDeeZ9ym3q9YUV8fASA7aQ=="],
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.14", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.1", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw=="],
|
||||
|
||||
@@ -6589,8 +6589,6 @@
|
||||
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils/undici": ["undici@6.28.0", "", {}, "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA=="],
|
||||
|
||||
"@ai-sdk/anthropic/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||
|
||||
"@ai-sdk/azure/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"nodeModules": {
|
||||
"x86_64-linux": "sha256-Be1I6OG6UitofhcGu2BeNzevmoQXc4Or5r/NPzwtft4=",
|
||||
"aarch64-linux": "sha256-O+d+26CQIjZ08Rn8Qm3IytdDqIMbPdhzaGOZeUKAvIU=",
|
||||
"aarch64-darwin": "sha256-ObS50y/oy6fM9wSGUL/wx6O0+fTWHC04mXJNd7w/2Z0=",
|
||||
"x86_64-darwin": "sha256-eoR7ZSyH62Fq2ZaW2b2QqU2FC97rYxTMeEe+djT0nto="
|
||||
"x86_64-linux": "sha256-yQ8EIxxYkzlEWIMY/UiIR+7lbGBuizsoehMPZzFA65Y=",
|
||||
"aarch64-linux": "sha256-JF9VVgnl5QUZ430fqb5Qu8y0kchYJ00LO3FbYcd0lBM=",
|
||||
"aarch64-darwin": "sha256-f3Tu6eu463NWcHgr7dupfD/zUTh26bJ6N2vVXuEyi6c=",
|
||||
"x86_64-darwin": "sha256-miv9Sv4KdhD0UIi2O5LVS1wQOfq29IV+9S+BvIzAvgo="
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ function ModelSelectorPopoverV2View(props: {
|
||||
<For each={groups()}>
|
||||
{(group) => (
|
||||
<MenuV2.Group>
|
||||
<MenuV2.GroupLabel class="sticky top-0 z-10 gap-2 bg-v2-background-bg-layer-01 px-3">
|
||||
<MenuV2.GroupLabel class="gap-2 px-3">
|
||||
<span class="min-w-0 truncate">{group.items[0].provider.name}</span>
|
||||
</MenuV2.GroupLabel>
|
||||
<MenuV2.RadioGroup value={props.current()}>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { APIEvent } from "@solidjs/start"
|
||||
import { waitUntil } from "@opencode-ai/console-resource"
|
||||
import type { DownloadPlatform } from "../types"
|
||||
|
||||
const prodAssetNames: Record<string, string> = {
|
||||
@@ -31,34 +30,14 @@ export async function GET({ params: { platform, channel } }: APIEvent) {
|
||||
const assetName = channel === "stable" ? prodAssetNames[platform] : betaAssetNames[platform]
|
||||
if (!assetName) return new Response(null, { status: 404 })
|
||||
|
||||
const latest = await fetch(
|
||||
const resp = await fetch(
|
||||
`https://github.com/anomalyco/${channel === "stable" ? "opencode" : "opencode-beta"}/releases/latest/download/${assetName}`,
|
||||
{ redirect: "manual" },
|
||||
)
|
||||
const location = latest.headers.get("location")
|
||||
if (!location) return new Response(null, { status: 502 })
|
||||
|
||||
const key = new Request(location)
|
||||
const cache = (caches as CacheStorage & { default: Cache }).default
|
||||
const cached = await cache.match(key)
|
||||
if (cached) return download(cached, platform, "HIT")
|
||||
|
||||
const resp = await fetch(location)
|
||||
if (!resp.ok) return resp
|
||||
|
||||
const headers = new Headers(resp.headers)
|
||||
headers.set("cache-control", "public, max-age=31536000, immutable")
|
||||
headers.delete("set-cookie")
|
||||
const result = new Response(resp.body, { status: resp.status, statusText: resp.statusText, headers })
|
||||
waitUntil(cache.put(key, result.clone()))
|
||||
return download(result, platform, "MISS")
|
||||
}
|
||||
|
||||
function download(resp: Response, platform: string, cache: "HIT" | "MISS") {
|
||||
const downloadName = downloadNames[platform]
|
||||
|
||||
const headers = new Headers(resp.headers)
|
||||
if (downloadName) headers.set("content-disposition", `attachment; filename="${downloadName}"`)
|
||||
headers.set("x-opencode-cache", cache)
|
||||
|
||||
return new Response(resp.body, { status: resp.status, statusText: resp.statusText, headers })
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/alibaba": "1.0.17",
|
||||
"@ai-sdk/amazon-bedrock": "4.0.158",
|
||||
"@ai-sdk/amazon-bedrock": "4.0.112",
|
||||
"@ai-sdk/anthropic": "3.0.82",
|
||||
"@ai-sdk/azure": "3.0.88",
|
||||
"@ai-sdk/cerebras": "2.0.41",
|
||||
|
||||
@@ -45,18 +45,9 @@ function oauth(http: HttpClient.HttpClient) {
|
||||
authorize: () =>
|
||||
Effect.gen(function* () {
|
||||
const device = yield* post(http, `${defaultServer}/auth/device/code`, { client_id: clientID }, Device)
|
||||
const verification = yield* Effect.try({
|
||||
try: () => {
|
||||
const url = new URL(device.verification_uri_complete, `${defaultServer}/`)
|
||||
if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error("expected HTTP(S)")
|
||||
return url
|
||||
},
|
||||
catch: (cause) =>
|
||||
new Error(`Invalid device verification URL: ${cause instanceof Error ? cause.message : String(cause)}`),
|
||||
})
|
||||
return {
|
||||
mode: "auto" as const,
|
||||
url: verification.href,
|
||||
url: `${defaultServer}${device.verification_uri_complete}`,
|
||||
instructions: `Enter code: ${device.user_code}`,
|
||||
callback: poll(http, defaultServer, device.device_code, Duration.seconds(device.interval)),
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { HttpClient, HttpClientResponse } from "effect/unstable/http"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { Credential } from "@opencode-ai/core/credential"
|
||||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
@@ -15,16 +14,14 @@ import { PluginTestLayer } from "./fixture"
|
||||
|
||||
const it = testEffect(PluginTestLayer)
|
||||
|
||||
const addPlugin = Effect.fn(function* (http?: HttpClient.HttpClient) {
|
||||
const addPlugin = Effect.fn(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
const events = yield* EventV2.Service
|
||||
const integration = yield* Integration.Service
|
||||
const client = yield* HttpClient.HttpClient
|
||||
yield* OpencodePlugin.effect(host).pipe(
|
||||
Effect.provideService(EventV2.Service, events),
|
||||
Effect.provideService(Integration.Service, integration),
|
||||
Effect.provideService(HttpClient.HttpClient, http ?? client),
|
||||
)
|
||||
})
|
||||
|
||||
@@ -85,63 +82,6 @@ describe("OpencodePlugin", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("resolves origin-rooted device verification URLs", () =>
|
||||
Effect.gen(function* () {
|
||||
const http = HttpClient.make((request) =>
|
||||
Effect.succeed(
|
||||
HttpClientResponse.fromWeb(
|
||||
request,
|
||||
Response.json({
|
||||
device_code: "device",
|
||||
user_code: "user",
|
||||
verification_uri_complete: "/console/device?user_code=user&client_id=opencode-cli",
|
||||
expires_in: 60,
|
||||
interval: 60,
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
yield* addPlugin(http)
|
||||
const integration = yield* Integration.Service
|
||||
const attempt = yield* integration.connection.oauth({
|
||||
integrationID: Integration.ID.make("opencode"),
|
||||
methodID: Integration.MethodID.make("device"),
|
||||
inputs: {},
|
||||
})
|
||||
expect(attempt.url).toBe("https://opencode.ai/console/device?user_code=user&client_id=opencode-cli")
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("rejects malformed device verification URLs", () =>
|
||||
Effect.gen(function* () {
|
||||
const http = HttpClient.make((request) =>
|
||||
Effect.succeed(
|
||||
HttpClientResponse.fromWeb(
|
||||
request,
|
||||
Response.json({
|
||||
device_code: "device",
|
||||
user_code: "user",
|
||||
verification_uri_complete: "http://[::1",
|
||||
expires_in: 60,
|
||||
interval: 60,
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
yield* addPlugin(http)
|
||||
const integration = yield* Integration.Service
|
||||
const error = yield* integration.connection
|
||||
.oauth({
|
||||
integrationID: Integration.ID.make("opencode"),
|
||||
methodID: Integration.MethodID.make("device"),
|
||||
inputs: {},
|
||||
})
|
||||
.pipe(Effect.flip)
|
||||
expect(error).toBeInstanceOf(Integration.AuthorizationError)
|
||||
expect(String(error.cause)).toContain("Invalid device verification URL")
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("loads providers and models from the connected OpenCode server", () =>
|
||||
Effect.acquireUseRelease(
|
||||
Effect.sync(() => {
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"@actions/github": "6.0.1",
|
||||
"@agentclientprotocol/sdk": "0.21.0",
|
||||
"@ai-sdk/alibaba": "1.0.17",
|
||||
"@ai-sdk/amazon-bedrock": "4.0.158",
|
||||
"@ai-sdk/amazon-bedrock": "4.0.112",
|
||||
"@ai-sdk/anthropic": "3.0.82",
|
||||
"@ai-sdk/azure": "3.0.88",
|
||||
"@ai-sdk/cerebras": "2.0.60",
|
||||
|
||||
@@ -396,18 +396,10 @@ const layer: Layer.Layer<Service, never, AccountRepo.Service | HttpClient.HttpCl
|
||||
const parsed = yield* HttpClientResponse.schemaBodyJson(DeviceAuth)(response).pipe(
|
||||
mapAccountServiceError("Failed to decode response"),
|
||||
)
|
||||
const verification = yield* Effect.try({
|
||||
try: () => {
|
||||
const url = new URL(parsed.verification_uri_complete, `${normalizedServer}/`)
|
||||
if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error("expected HTTP(S)")
|
||||
return url.href
|
||||
},
|
||||
catch: (cause) => new AccountServiceError({ message: "Invalid device verification URL", cause }),
|
||||
})
|
||||
return new Login({
|
||||
code: parsed.device_code,
|
||||
user: parsed.user_code,
|
||||
url: verification,
|
||||
url: `${normalizedServer}${parsed.verification_uri_complete}`,
|
||||
server: normalizedServer,
|
||||
expiry: parsed.expires_in,
|
||||
interval: parsed.interval,
|
||||
|
||||
@@ -1094,21 +1094,6 @@ export const ConfigProvidersResult = Schema.Struct({
|
||||
export type ConfigProvidersResult = Types.DeepMutable<Schema.Schema.Type<typeof ConfigProvidersResult>>
|
||||
|
||||
export function toPublicInfo(provider: Info): Info {
|
||||
const result = cloneInfo(provider)
|
||||
for (const model of Object.values(result.models)) {
|
||||
if (model.cost.experimentalOver200K) continue
|
||||
if (model.cost.tiers?.length !== 1) continue
|
||||
const [tier] = model.cost.tiers
|
||||
model.cost.experimentalOver200K = {
|
||||
input: tier.input,
|
||||
output: tier.output,
|
||||
cache: { ...tier.cache },
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function cloneInfo(provider: Info): Info {
|
||||
return JSON.parse(
|
||||
JSON.stringify(
|
||||
{
|
||||
@@ -1217,8 +1202,8 @@ function cost(c: ModelsDev.Model["cost"]): Model["cost"] {
|
||||
write: c?.cache_write ?? 0,
|
||||
},
|
||||
}
|
||||
const tiers =
|
||||
c?.tiers?.map((item) => ({
|
||||
if (c?.tiers) {
|
||||
result.tiers = c.tiers.map((item) => ({
|
||||
input: item.input,
|
||||
output: item.output,
|
||||
cache: {
|
||||
@@ -1226,19 +1211,18 @@ function cost(c: ModelsDev.Model["cost"]): Model["cost"] {
|
||||
write: item.cache_write ?? 0,
|
||||
},
|
||||
tier: item.tier,
|
||||
})) ?? []
|
||||
const legacy = c?.context_over_200k
|
||||
if (legacy && tiers.length === 0)
|
||||
tiers.push({
|
||||
input: legacy.input,
|
||||
output: legacy.output,
|
||||
}))
|
||||
}
|
||||
if (c?.context_over_200k) {
|
||||
result.experimentalOver200K = {
|
||||
cache: {
|
||||
read: legacy.cache_read ?? 0,
|
||||
write: legacy.cache_write ?? 0,
|
||||
read: c.context_over_200k.cache_read ?? 0,
|
||||
write: c.context_over_200k.cache_write ?? 0,
|
||||
},
|
||||
tier: { type: "context", size: 200_000 },
|
||||
})
|
||||
if (tiers.length > 0) result.tiers = tiers
|
||||
input: c.context_over_200k.input,
|
||||
output: c.context_over_200k.output,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1394,7 +1378,7 @@ const layer = Layer.effect(
|
||||
const cfg = yield* config.get()
|
||||
const modelsDev = yield* modelsDevSvc.get()
|
||||
const catalog = mapValues(modelsDev, fromModelsDevProvider)
|
||||
const database = mapValues(catalog, cloneInfo)
|
||||
const database = mapValues(catalog, toPublicInfo)
|
||||
|
||||
const providers: Record<ProviderV2.ID, Info> = {} as Record<ProviderV2.ID, Info>
|
||||
const languages = new Map<string, LanguageModelV3>()
|
||||
@@ -1498,20 +1482,6 @@ const layer = Layer.effect(
|
||||
if (model.id && model.id !== modelID) return modelID
|
||||
return existingModel?.name ?? modelID
|
||||
})
|
||||
const legacy = existingModel?.cost.tiers?.length ? undefined : model.cost?.context_over_200k
|
||||
const tiers = legacy
|
||||
? [
|
||||
...(existingModel?.cost.tiers?.filter(
|
||||
(item) => item.tier.type !== "context" || item.tier.size !== 200_000,
|
||||
) ?? []),
|
||||
{
|
||||
input: legacy.input,
|
||||
output: legacy.output,
|
||||
cache: { read: legacy.cache_read ?? 0, write: legacy.cache_write ?? 0 },
|
||||
tier: { type: "context" as const, size: 200_000 },
|
||||
},
|
||||
]
|
||||
: existingModel?.cost.tiers
|
||||
const parsedModel: Model = {
|
||||
id: ModelV2.ID.make(modelID),
|
||||
api: {
|
||||
@@ -1558,7 +1528,6 @@ const layer = Layer.effect(
|
||||
read: model?.cost?.cache_read ?? existingModel?.cost?.cache.read ?? 0,
|
||||
write: model?.cost?.cache_write ?? existingModel?.cost?.cache.write ?? 0,
|
||||
},
|
||||
tiers,
|
||||
},
|
||||
options: mergeDeep(existingModel?.options ?? {}, model.options ?? {}),
|
||||
limit: {
|
||||
|
||||
@@ -1303,13 +1303,13 @@ export function options(input: {
|
||||
}
|
||||
}
|
||||
|
||||
// Generic OpenAI-compatible APIs do not necessarily support OpenAI's verbosity parameter.
|
||||
// Only enable the default for integrations known to implement it.
|
||||
// Only set textVerbosity for non-chat gpt-5.x models
|
||||
// Chat models (e.g. gpt-5.2-chat-latest) only support "medium" verbosity
|
||||
if (
|
||||
input.model.api.id.includes("gpt-5.") &&
|
||||
!input.model.api.id.includes("codex") &&
|
||||
!input.model.api.id.includes("-chat") &&
|
||||
(input.model.api.npm === "@ai-sdk/openai" || input.model.api.npm === "@ai-sdk/amazon-bedrock/mantle")
|
||||
input.model.providerID !== "azure"
|
||||
) {
|
||||
result["textVerbosity"] = "low"
|
||||
}
|
||||
|
||||
@@ -380,7 +380,10 @@ export const getUsage = (input: { model: Provider.Model; usage: Usage; metadata?
|
||||
const costInfo =
|
||||
input.model.cost?.tiers
|
||||
?.filter((item) => item.tier.type === "context" && contextTokens > item.tier.size)
|
||||
.sort((a, b) => b.tier.size - a.tier.size)[0] ?? input.model.cost
|
||||
.sort((a, b) => b.tier.size - a.tier.size)[0] ??
|
||||
(input.model.cost?.experimentalOver200K && contextTokens > 200_000
|
||||
? input.model.cost.experimentalOver200K
|
||||
: input.model.cost)
|
||||
const totalNanoAiu = input.metadata?.["copilot"]?.["totalNanoAiu"]
|
||||
return {
|
||||
cost:
|
||||
|
||||
@@ -10,7 +10,6 @@ import { Account } from "../../src/account/account"
|
||||
import {
|
||||
AccessToken,
|
||||
AccountID,
|
||||
AccountServiceError,
|
||||
AccountTransportError,
|
||||
DeviceCode,
|
||||
Login,
|
||||
@@ -72,18 +71,18 @@ const deviceTokenClient = (body: unknown, status = 400) =>
|
||||
const poll = (body: unknown, status = 400) =>
|
||||
Account.Service.use((s) => s.poll(login())).pipe(Effect.provide(live(deviceTokenClient(body, status))))
|
||||
|
||||
it.live("login resolves origin-rooted verification URLs from servers with base paths", () =>
|
||||
it.live("login normalizes trailing slashes in the provided server URL", () =>
|
||||
Effect.gen(function* () {
|
||||
const seen: Array<string> = []
|
||||
const client = HttpClient.make((req) =>
|
||||
Effect.gen(function* () {
|
||||
seen.push(`${req.method} ${req.url}`)
|
||||
|
||||
if (req.url === "https://one.example.com/console/auth/device/code") {
|
||||
if (req.url === "https://one.example.com/auth/device/code") {
|
||||
return json(req, {
|
||||
device_code: "device-code",
|
||||
user_code: "user-code",
|
||||
verification_uri_complete: "/console/device?user_code=user-code",
|
||||
verification_uri_complete: "/device?user_code=user-code",
|
||||
expires_in: 600,
|
||||
interval: 5,
|
||||
})
|
||||
@@ -93,31 +92,11 @@ it.live("login resolves origin-rooted verification URLs from servers with base p
|
||||
}),
|
||||
)
|
||||
|
||||
const result = yield* Account.use.login("https://one.example.com/console/").pipe(Effect.provide(live(client)))
|
||||
const result = yield* Account.use.login("https://one.example.com/").pipe(Effect.provide(live(client)))
|
||||
|
||||
expect(seen).toEqual(["POST https://one.example.com/console/auth/device/code"])
|
||||
expect(result.server).toBe("https://one.example.com/console")
|
||||
expect(result.url).toBe("https://one.example.com/console/device?user_code=user-code")
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("login rejects malformed device verification URLs", () =>
|
||||
Effect.gen(function* () {
|
||||
const client = HttpClient.make((req) =>
|
||||
Effect.succeed(
|
||||
json(req, {
|
||||
device_code: "device-code",
|
||||
user_code: "user-code",
|
||||
verification_uri_complete: "http://[::1",
|
||||
expires_in: 600,
|
||||
interval: 5,
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
const error = yield* Effect.flip(Account.use.login("https://one.example.com").pipe(Effect.provide(live(client))))
|
||||
expect(error).toBeInstanceOf(AccountServiceError)
|
||||
if (error instanceof AccountServiceError) expect(error.message).toBe("Invalid device verification URL")
|
||||
expect(seen).toEqual(["POST https://one.example.com/auth/device/code"])
|
||||
expect(result.server).toBe("https://one.example.com")
|
||||
expect(result.url).toBe("https://one.example.com/device?user_code=user-code")
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -566,81 +566,6 @@ it.instance(
|
||||
},
|
||||
)
|
||||
|
||||
it.instance(
|
||||
"model config preserves catalog cost tiers",
|
||||
Effect.gen(function* () {
|
||||
yield* set("REQUESTY_API_KEY", "test-api-key")
|
||||
const providers = yield* list
|
||||
const provider = providers[ProviderV2.ID.make("requesty")]
|
||||
const model = provider.models["google/gemini-2.5-pro"]
|
||||
expect(model.cost.tiers).toEqual([
|
||||
{
|
||||
input: 2.5,
|
||||
output: 15,
|
||||
cache: { read: 0.25, write: 0 },
|
||||
tier: { type: "context", size: 200_000 },
|
||||
},
|
||||
])
|
||||
expect(model.cost.experimentalOver200K).toBeUndefined()
|
||||
expect(Provider.toPublicInfo(provider).models["google/gemini-2.5-pro"].cost.experimentalOver200K).toEqual({
|
||||
input: 2.5,
|
||||
output: 15,
|
||||
cache: { read: 0.25, write: 0 },
|
||||
})
|
||||
}),
|
||||
{
|
||||
config: {
|
||||
provider: {
|
||||
requesty: {
|
||||
models: {
|
||||
"google/gemini-2.5-pro": {
|
||||
cost: {
|
||||
input: 1.25,
|
||||
output: 10,
|
||||
context_over_200k: { input: 4, output: 16, cache_read: 0.4 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
it.instance(
|
||||
"legacy model config pricing is normalized into a context tier",
|
||||
Effect.gen(function* () {
|
||||
const providers = yield* list
|
||||
expect(providers[ProviderV2.ID.make("legacy")].models.legacy.cost.tiers).toEqual([
|
||||
{
|
||||
input: 4,
|
||||
output: 16,
|
||||
cache: { read: 0.4, write: 0 },
|
||||
tier: { type: "context", size: 200_000 },
|
||||
},
|
||||
])
|
||||
}),
|
||||
{
|
||||
config: {
|
||||
provider: {
|
||||
legacy: {
|
||||
npm: "@ai-sdk/openai-compatible",
|
||||
options: { apiKey: "test-api-key" },
|
||||
models: {
|
||||
legacy: {
|
||||
cost: {
|
||||
input: 1.25,
|
||||
output: 10,
|
||||
context_over_200k: { input: 4, output: 16, cache_read: 0.4 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
it.instance(
|
||||
"model config preserves explicitly empty models.dev variants",
|
||||
Effect.gen(function* () {
|
||||
@@ -1476,18 +1401,10 @@ test("mode options and cost are derived from the base model", () => {
|
||||
input: 2.5,
|
||||
output: 15,
|
||||
cache_read: 0.25,
|
||||
tiers: [
|
||||
{
|
||||
input: 5,
|
||||
output: 22.5,
|
||||
cache_read: 0.5,
|
||||
tier: { type: "context", size: 272_000 },
|
||||
},
|
||||
],
|
||||
context_over_200k: {
|
||||
input: 4,
|
||||
output: 20,
|
||||
cache_read: 0.4,
|
||||
input: 5,
|
||||
output: 22.5,
|
||||
cache_read: 0.5,
|
||||
},
|
||||
},
|
||||
limit: {
|
||||
@@ -1532,49 +1449,11 @@ test("mode options and cost are derived from the base model", () => {
|
||||
const pro = Provider.fromModelsDevProvider(provider).models["gpt-5.6-sol-pro"]
|
||||
expect(pro.api.id).toEqual("gpt-5.6-sol")
|
||||
expect(pro.options).toEqual({ reasoningMode: "pro", serviceTier: "priority" })
|
||||
expect(model.cost.tiers).toEqual([
|
||||
{
|
||||
input: 5,
|
||||
output: 22.5,
|
||||
cache: { read: 0.5, write: 0 },
|
||||
tier: { type: "context", size: 272_000 },
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test("legacy models.dev pricing is normalized into a context tier", () => {
|
||||
const provider = {
|
||||
id: "legacy",
|
||||
name: "Legacy",
|
||||
env: [],
|
||||
npm: "@ai-sdk/openai-compatible",
|
||||
models: {
|
||||
legacy: {
|
||||
id: "legacy",
|
||||
name: "Legacy",
|
||||
release_date: "2026-01-01",
|
||||
attachment: false,
|
||||
reasoning: false,
|
||||
temperature: true,
|
||||
tool_call: true,
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 2,
|
||||
context_over_200k: { input: 3, output: 4, cache_read: 0.3 },
|
||||
},
|
||||
limit: { context: 1_000_000, output: 32_000 },
|
||||
},
|
||||
},
|
||||
} as unknown as ModelsDev.Provider
|
||||
|
||||
expect(Provider.fromModelsDevProvider(provider).models.legacy.cost.tiers).toEqual([
|
||||
{
|
||||
input: 3,
|
||||
output: 4,
|
||||
cache: { read: 0.3, write: 0 },
|
||||
tier: { type: "context", size: 200_000 },
|
||||
},
|
||||
])
|
||||
expect(model.cost.experimentalOver200K).toEqual({
|
||||
input: 5,
|
||||
output: 22.5,
|
||||
cache: { read: 0.5, write: 0 },
|
||||
})
|
||||
})
|
||||
|
||||
test("models.dev normalization fills required response fields", () => {
|
||||
|
||||
@@ -523,7 +523,6 @@ describe("ProviderTransform.options - gpt-5 textVerbosity", () => {
|
||||
expect(result.reasoningEffort).toBe("medium")
|
||||
expect(result.reasoningSummary).toBeUndefined()
|
||||
expect(result.include).toBeUndefined()
|
||||
expect(result.textVerbosity).toBeUndefined()
|
||||
})
|
||||
|
||||
test("azure chat completions omit Responses-only reasoning options after variants merge", async () => {
|
||||
@@ -3247,6 +3246,8 @@ describe("ProviderTransform sampling defaults - Gemini", () => {
|
||||
"gemini-3-5-flash-lite",
|
||||
"gemini-3.6-flash",
|
||||
"gemini-3-6-flash",
|
||||
"gemini-3.7-flash",
|
||||
"gemini-3-7-flash",
|
||||
"gemini-4-pro",
|
||||
"gemini-future",
|
||||
])("omits deprecated sampling controls for %s", (id) => {
|
||||
|
||||
@@ -1830,7 +1830,7 @@ describe("SessionNs.getUsage", () => {
|
||||
expect(result.cost).toBe(0.04473525)
|
||||
})
|
||||
|
||||
test("uses the matching context cost tier", () => {
|
||||
test("uses matching context cost tier before over-200k fallback", () => {
|
||||
const model = createModel({
|
||||
context: 1_000_000,
|
||||
output: 32_000,
|
||||
@@ -1852,6 +1852,11 @@ describe("SessionNs.getUsage", () => {
|
||||
tier: { type: "context", size: 500_000 },
|
||||
},
|
||||
],
|
||||
experimentalOver200K: {
|
||||
input: 100,
|
||||
output: 100,
|
||||
cache: { read: 100, write: 100 },
|
||||
},
|
||||
},
|
||||
})
|
||||
const result = SessionNs.getUsage({
|
||||
@@ -1868,7 +1873,7 @@ describe("SessionNs.getUsage", () => {
|
||||
expect(result.cost).toBe(2.75 + 0.6 + 0.05)
|
||||
})
|
||||
|
||||
test("uses base pricing when no context cost tier matches", () => {
|
||||
test("falls back to over-200k pricing when no cost tier matches", () => {
|
||||
const model = createModel({
|
||||
context: 1_000_000,
|
||||
output: 32_000,
|
||||
@@ -1884,6 +1889,11 @@ describe("SessionNs.getUsage", () => {
|
||||
tier: { type: "context", size: 500_000 },
|
||||
},
|
||||
],
|
||||
experimentalOver200K: {
|
||||
input: 3,
|
||||
output: 4,
|
||||
cache: { read: 0.3, write: 1.5 },
|
||||
},
|
||||
},
|
||||
})
|
||||
const result = SessionNs.getUsage({
|
||||
@@ -1891,7 +1901,7 @@ describe("SessionNs.getUsage", () => {
|
||||
usage: usage({ inputTokens: 300_000, outputTokens: 100_000, totalTokens: 400_000 }),
|
||||
})
|
||||
|
||||
expect(result.cost).toBe(0.3 + 0.2)
|
||||
expect(result.cost).toBe(0.9 + 0.4)
|
||||
})
|
||||
|
||||
test.each(["@ai-sdk/anthropic", "@ai-sdk/amazon-bedrock", "@ai-sdk/google-vertex/anthropic"])(
|
||||
|
||||
@@ -812,8 +812,7 @@ function ModelTrendSection(props: {
|
||||
<div data-slot="tooltip-divider" />
|
||||
<p>
|
||||
<span data-slot="tooltip-label">
|
||||
<i data-kind={props.lineTone === "active" ? "users" : "tokens"} />
|
||||
<span data-slot="tooltip-name">{props.rowLabel}</span>
|
||||
<i data-kind={props.lineTone === "active" ? "users" : "tokens"} /> {props.rowLabel}
|
||||
</span>
|
||||
<b>{props.formatValue(props.value(active.point))}</b>
|
||||
</p>
|
||||
|
||||
@@ -473,15 +473,13 @@ function LabUsageSection(props: { lab: ModelCatalogLab; data: StatsLabData | nul
|
||||
<div data-slot="tooltip-divider" />
|
||||
<p>
|
||||
<span data-slot="tooltip-label">
|
||||
<i data-kind="tokens" />
|
||||
<span data-slot="tooltip-name">{i18n.t("lab.dailyTokens")}</span>
|
||||
<i data-kind="tokens" /> {i18n.t("lab.dailyTokens")}
|
||||
</span>
|
||||
<b>{formatTokens(active.point.tokens)}</b>
|
||||
</p>
|
||||
<p>
|
||||
<span data-slot="tooltip-label">
|
||||
<i data-kind="users" />
|
||||
<span data-slot="tooltip-name">{i18n.t("model.uniqueUsers")}</span>
|
||||
<i data-kind="users" /> {i18n.t("model.uniqueUsers")}
|
||||
</span>
|
||||
<b>{formatUsers(active.point.users)}</b>
|
||||
</p>
|
||||
|
||||
@@ -1590,13 +1590,6 @@ body {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="chart-tooltip"] [data-slot="tooltip-name"] {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="chart-tooltip"] [data-slot="tooltip-divider"] {
|
||||
height: 1px;
|
||||
margin: 4px -16px 2px;
|
||||
@@ -1684,7 +1677,7 @@ body {
|
||||
|
||||
[data-page="stats"] :is([data-section="top-models"], [data-section="unique-users"]) [data-component="chart-tooltip"] p {
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 1ch;
|
||||
gap: 4px;
|
||||
height: 16px;
|
||||
margin: 4px 0 0;
|
||||
padding: 0 8px;
|
||||
@@ -4730,7 +4723,7 @@ body {
|
||||
|
||||
[data-page="stats"] [data-component="model-usage-chart"] [data-component="chart-tooltip"] p {
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 1ch;
|
||||
gap: 4px;
|
||||
height: 20px;
|
||||
margin: 8px 0;
|
||||
padding: 0 8px;
|
||||
|
||||
@@ -568,8 +568,8 @@ function TopModelsChart(props: {
|
||||
style={{
|
||||
background: getRankColor(item.segment.model, item.index, segmentOrder(), usageColors),
|
||||
}}
|
||||
/>
|
||||
<span data-slot="tooltip-name">{item.segment.model}</span>
|
||||
/>{" "}
|
||||
{item.segment.model}
|
||||
</span>
|
||||
<b>{formatUsageChartValue(item.segment.value, metric())}</b>
|
||||
</p>
|
||||
|
||||
@@ -188,8 +188,8 @@ https://opencode.ai/zen/v1/models
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -195,8 +195,8 @@ Podržavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**.
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -195,8 +195,8 @@ Vi understøtter en pay-as-you-go-model. Nedenfor er priserne **pr. 1M tokens**.
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -184,8 +184,8 @@ Wir unterstützen ein Pay-as-you-go-Modell. Unten findest du die Preise **pro 1M
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -195,8 +195,8 @@ Admitimos un modelo de pago por uso. A continuación se muestran los precios **p
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -184,8 +184,8 @@ Nous prenons en charge un modèle de paiement à l'utilisation. Vous trouverez c
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -195,8 +195,8 @@ Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**.
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
@@ -221,7 +221,7 @@ Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**.
|
||||
| GPT 5 Codex | $1.07 | $8.50 | $0.107 | - |
|
||||
| GPT 5 Nano | $0.05 | $0.40 | $0.005 | - |
|
||||
|
||||
**GPT 5.6 Sol:** I prezzi mostrati includono uno sconto del 50% fino al 18 septembre 2026.
|
||||
**GPT 5.6 Sol:** I prezzi mostrati includono uno sconto del 50% fino al 18 settembre 2026.
|
||||
|
||||
**DeepSeek V4 Flash / Pro:** Gli orari Peak sono 01:00-04:00 e 06:00-10:00 UTC; tutti gli altri orari sono Off-Peak. [Scopri di più](https://api-docs.deepseek.com/quick_start/pricing/).
|
||||
|
||||
|
||||
@@ -184,8 +184,8 @@ https://opencode.ai/zen/v1/models
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -184,8 +184,8 @@ https://opencode.ai/zen/v1/models
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -195,8 +195,8 @@ Vi støtter en pay-as-you-go-modell. Nedenfor er prisene **per 1M tokens**.
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -195,8 +195,8 @@ Obsługujemy model pay-as-you-go. Poniżej znajdują się ceny **za 1M tokenów*
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -184,8 +184,8 @@ Oferecemos um modelo pay-as-you-go. Abaixo estão os preços **por 1M tokens**.
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -195,8 +195,8 @@ https://opencode.ai/zen/v1/models
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -186,8 +186,8 @@ https://opencode.ai/zen/v1/models
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -184,8 +184,8 @@ Kullandıkça öde modelini destekliyoruz. Aşağıda **1M token başına** fiya
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -195,8 +195,8 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**.
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -184,8 +184,8 @@ https://opencode.ai/zen/v1/models
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
@@ -189,8 +189,8 @@ https://opencode.ai/zen/v1/models
|
||||
| Grok 4.5 (> 200K tokens) | $4.00 | $12.00 | $0.60 | - |
|
||||
| Grok Build 0.1 | $1.00 | $2.00 | $0.20 | - |
|
||||
| Muse Spark 1.2 | $1.25 | $4.25 | $0.15 | - |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.00 | $10.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $4.00 | $15.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Sol (≤ 272K tokens) | $2.50 | $15.00 | $0.25 | $3.125 |
|
||||
| GPT 5.6 Sol (> 272K tokens) | $5.00 | $22.50 | $0.50 | $6.25 |
|
||||
| GPT 5.6 Terra (≤ 272K tokens) | $2.00 | $12.00 | $0.20 | $2.50 |
|
||||
| GPT 5.6 Terra (> 272K tokens) | $4.00 | $18.00 | $0.40 | $5.00 |
|
||||
| GPT 5.6 Luna (≤ 272K tokens) | $0.20 | $1.20 | $0.02 | $0.25 |
|
||||
|
||||
Reference in New Issue
Block a user