From 6685b3d09ac497ff6cdacc46c949d1d2b6ea2435 Mon Sep 17 00:00:00 2001 From: amosblomqvist Date: Fri, 23 Oct 2026 17:25:10 +0300 Subject: [PATCH] fix: use native Pi identity and refresh provider catalogs --- package-lock.json | 256 ++++++------ package.json | 4 +- src/agent/models.ts | 10 +- src/agent/subagents/pdf-reader.ts | 5 + src/agent/subagents/pi-run.ts | 6 +- src/agent/subagents/visual-maker.ts | 5 + src/agent/teacher-agent.ts | 8 +- src/core/auth-keys.ts | 2 +- src/core/prices.ts | 574 ++++++++++++++------------ tests/auth-provider-keys.test.ts | 4 +- tests/extraction.test.ts | 29 +- tests/openrouter-free-models.test.ts | 58 +++ tests/provider-neutral-agents.test.ts | 47 ++- tests/session-identity.test.ts | 192 +++++++++ tests/usage.test.ts | 6 +- 15 files changed, 792 insertions(+), 414 deletions(-) create mode 100644 tests/openrouter-free-models.test.ts create mode 100644 tests/session-identity.test.ts diff --git a/package-lock.json b/package-lock.json index f3906c4..6b612e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,8 @@ "version": "0.3.3", "license": "AGPL-3.0-only", "dependencies": { - "@earendil-works/pi-agent-core": "1.0.2", - "@earendil-works/pi-ai": "1.0.2", + "@earendil-works/pi-agent-core": "1.4.0", + "@earendil-works/pi-ai": "1.4.0", "@mozilla/readability": "^0.6.0", "@radix-ui/react-use-controllable-state": "^1.2.6", "@resvg/resvg-js": "^2.6.2", @@ -145,16 +145,16 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.978.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.978.1.tgz", - "integrity": "sha512-LbY9aGsEiznDWmUc30Nwv3aIX/+dbwTx8KfS0yOC3NPYMO+O91e6jkT1azf34FwjOndq8/Q+RcVVZz5xnerwdg==", + "version": "3.978.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.978.5.tgz", + "integrity": "sha512-ruI0AWqcrfL20XDS6SwZIJFPOBZ6N0ADa9nLzWlBhxk1aoUjbUX3JkTR9vEmk7o35XpAHi68ahZ4T6RE2U9XyA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.974.6", + "@aws-sdk/types": "^3.975.0", "@aws-sdk/xml-builder": "^3.972.41", "@aws/lambda-invoke-store": "^0.3.0", - "@smithy/core": "^3.35.0", - "@smithy/signature-v4": "^5.7.3", + "@smithy/core": "^3.36.1", + "@smithy/signature-v4": "^5.7.4", "@smithy/types": "^4.19.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -164,14 +164,14 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.72", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.72.tgz", - "integrity": "sha512-xTKO/FWJPozTIXbozVnVGoNBhaGba8TBcx+KyUjRVeOlXE+dUc7GTR1cLvu0uTdIdmemzaFbqqCshXeZA1fZew==", + "version": "3.972.76", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.76.tgz", + "integrity": "sha512-YxmL1Ar7bV9ZkJvtv+lj+MF6le76NnZnbmgySyZuxpZaCv0/1lZ3KxKy6RIj1h9ui2hWnVjZxbmTMeO0y/NrQA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/core": "^3.978.5", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, @@ -180,14 +180,14 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.74", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.74.tgz", - "integrity": "sha512-u91E/hT8f4d1xy0Jl7VG4nVKJ3lxbrZkoBTeSVoJdWBiSEUMwMS/9+e0H/aJVQV//Lt5wuzP+E69v4aRSsNTmw==", + "version": "3.972.78", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.78.tgz", + "integrity": "sha512-3VHknDRngoebsaqyT1iR75b5cBT2zfEtODK6yYmYltljkK1HEAQLs2FEd1IpWqAeOYdMGaG9wikngWLTufY7RA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/core": "^3.978.5", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/fetch-http-handler": "^5.8.0", "@smithy/node-http-handler": "^4.12.1", "@smithy/types": "^4.19.0", @@ -198,21 +198,21 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.973.17", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.17.tgz", - "integrity": "sha512-ged4KXdBkvIC81bLvNHHuQKdKak/VXhQTR1NWYTTqW0474nlmsxy9O/vlgTIohDDWH3xpBdtVMZRyjb+DnocDA==", + "version": "3.973.21", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.21.tgz", + "integrity": "sha512-aLx9hbCX6mGAyv4ZZd8UagJ4RASHVJw6BFDSIyuKmLkqNL6H47EjBPK6qaJ4B5TDV6mc+vMa0SJFYyo4mkvVQg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/credential-provider-env": "^3.972.72", - "@aws-sdk/credential-provider-http": "^3.972.74", - "@aws-sdk/credential-provider-login": "^3.972.79", - "@aws-sdk/credential-provider-process": "^3.972.72", - "@aws-sdk/credential-provider-sso": "^3.973.16", - "@aws-sdk/credential-provider-web-identity": "^3.972.78", - "@aws-sdk/nested-clients": "^3.997.46", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/core": "^3.978.5", + "@aws-sdk/credential-provider-env": "^3.972.76", + "@aws-sdk/credential-provider-http": "^3.972.78", + "@aws-sdk/credential-provider-login": "^3.972.83", + "@aws-sdk/credential-provider-process": "^3.972.76", + "@aws-sdk/credential-provider-sso": "^3.973.20", + "@aws-sdk/credential-provider-web-identity": "^3.972.82", + "@aws-sdk/nested-clients": "^3.997.50", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/credential-provider-imds": "^4.5.2", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" @@ -222,15 +222,15 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.79", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.79.tgz", - "integrity": "sha512-L+Z85anONJd8MaiuraO4wRxATCdEejBZ3K3eymzWI5JPXa9sOS9CkIm72PBKqXKX+Z9p9NGMX5AIMXm0LEflgw==", + "version": "3.972.83", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.83.tgz", + "integrity": "sha512-9bJU6FjRacF4FK/QHf8Dyxhur7B1grRj8C1Yh4IkpoFW2exQflPdCv0VrbemLW9ZctLNle+AE7TETs9KNvuLYg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/nested-clients": "^3.997.46", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/core": "^3.978.5", + "@aws-sdk/nested-clients": "^3.997.50", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, @@ -239,19 +239,19 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.84", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.84.tgz", - "integrity": "sha512-oHt854odINVwzwsh+c5x69j0ajm4DbqqqVJ+O1ECsCIZeMDAbzFpXItaqP7UZstJj/ATdTk/KFSH0LaNAgV+kA==", + "version": "3.972.88", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.88.tgz", + "integrity": "sha512-AG0KID5qhQPzrFkh5b0Cws1Amytvzo0L0Xj6hMgJXEwD6ZXAqninDhSNAWJiN5zU4YVVZnuidnqwPwYJ04IamA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.72", - "@aws-sdk/credential-provider-http": "^3.972.74", - "@aws-sdk/credential-provider-ini": "^3.973.17", - "@aws-sdk/credential-provider-process": "^3.972.72", - "@aws-sdk/credential-provider-sso": "^3.973.16", - "@aws-sdk/credential-provider-web-identity": "^3.972.78", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/credential-provider-env": "^3.972.76", + "@aws-sdk/credential-provider-http": "^3.972.78", + "@aws-sdk/credential-provider-ini": "^3.973.21", + "@aws-sdk/credential-provider-process": "^3.972.76", + "@aws-sdk/credential-provider-sso": "^3.973.20", + "@aws-sdk/credential-provider-web-identity": "^3.972.82", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/credential-provider-imds": "^4.5.2", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" @@ -261,14 +261,14 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.72", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.72.tgz", - "integrity": "sha512-rLIp2xbMjX/k9/od7APpqq1ZgXXnV0pOL1Th3ZsL8Wu0TRtBsDTVS8iPqcfRFcHakFxPvR04OSTv2ka2qOb/2A==", + "version": "3.972.76", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.76.tgz", + "integrity": "sha512-pdhKFTXv1zPYhh92MTlp0jVbLWvUEV9v+rziuEkoskGGQ2iJskxHTO38nA8UAbT/N4IM3n8OZJ9rIY5IBO15/A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/core": "^3.978.5", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, @@ -277,16 +277,16 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.973.16", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.16.tgz", - "integrity": "sha512-IGihaJfFZYacJJr/odqILCoK7W/mvrZ7cuK7ECn3sAu4vLC6u0V8bS7mCGbdugJ8Aum2tnvqmx0F2MRFp2rn9g==", + "version": "3.973.20", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.20.tgz", + "integrity": "sha512-DlxrAB3MnjNLx/da7b89W+3DyJQYso/q7Ns15MsST2IV2nkAYQOYTUCaffNSjgrpMP99Dm2mV2jxzcbyF94ZfA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/nested-clients": "^3.997.46", - "@aws-sdk/token-providers": "3.1138.0", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/core": "^3.978.5", + "@aws-sdk/nested-clients": "^3.997.50", + "@aws-sdk/token-providers": "3.1155.0", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, @@ -295,15 +295,15 @@ } }, "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { - "version": "3.1138.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1138.0.tgz", - "integrity": "sha512-GpyAr0DD63YOEmYFM6Df+gJuIgC92MMTiBK4FTKfxii5MJ9ge20epR7LyroulscYlG89J+ZB2ivFDPjvfQhzdw==", + "version": "3.1155.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1155.0.tgz", + "integrity": "sha512-iIcQnYLhWuq9qOLQbIWFrxF3PF0svVeZvHnUS4DUnO4zUFmFHIyGyjqrntXG+e/5PUgfavV0pYfDIKHxTzN2LA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/nested-clients": "^3.997.46", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/core": "^3.978.5", + "@aws-sdk/nested-clients": "^3.997.50", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, @@ -312,15 +312,15 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.78", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.78.tgz", - "integrity": "sha512-/y9WvNtlcPBGLR0qc1a+9J/xtYZfVczvLUOuXaVWylzttH7ewsxwHtjmiJSolNrVSDorIxHGHMU61CbonRkmwA==", + "version": "3.972.82", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.82.tgz", + "integrity": "sha512-LUo46IqPTJ4xKBsrLuoaxiv/D2GTBCcFDMD1y3jKIqPR/p7Rw14RJFZ0iRWftqZtyLPQX9JMGnSi3mBu4y/pNA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/nested-clients": "^3.997.46", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/core": "^3.978.5", + "@aws-sdk/nested-clients": "^3.997.50", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, @@ -329,13 +329,13 @@ } }, "node_modules/@aws-sdk/eventstream-handler-node": { - "version": "3.972.35", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.35.tgz", - "integrity": "sha512-a8xilRoRaalvSPZdfrs0VY3/BPc0uYhXW56Z/k6nmZ5Vk430LHeowf9APIPq8utM3tMJSNGSSuJMlB9YrPsN+A==", + "version": "3.972.38", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.38.tgz", + "integrity": "sha512-K7vPKNstDlavHFZgbmcFdJOFIyowsevjddycRziRBbtXH/D9z+i9juCnH17liwSX9T8fJiDQzlEYkRtxkR+1vA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, @@ -344,13 +344,13 @@ } }, "node_modules/@aws-sdk/middleware-eventstream": { - "version": "3.972.30", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.30.tgz", - "integrity": "sha512-B6gvZlcnRBNWraKgyEjKsbhv+VjtbyHmpU7hmtTHzXpDSxHPpCJnYLpglEOOsF+SFne20DbZC5IVC1aNr2Pb4A==", + "version": "3.972.33", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.33.tgz", + "integrity": "sha512-8QUt39D/dk5tdV7rLvIfMMI/ilQff4zth7mkMKpVOLM+M5AQ9W3nPxFVuHQANevmVWi4T5MlxqfKV4Q2drYeBA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, @@ -359,16 +359,16 @@ } }, "node_modules/@aws-sdk/middleware-websocket": { - "version": "3.972.54", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.54.tgz", - "integrity": "sha512-bhESdru8u8KosziH8jcVta/NM/dNreeRz2+2aU86si5bfBYOiJ6IiqD+9U4URUcU5WJO3Yw+jO3GLDIHlscXMQ==", + "version": "3.972.58", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.58.tgz", + "integrity": "sha512-/BvocdloKozx/zFr4benH+9J1ywB/2dYFHPWNUdo0CBCe00gTm0HPflOq8MH6cuCTbnywSrscGq0/LheN59teQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/core": "^3.978.5", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/fetch-http-handler": "^5.8.0", - "@smithy/signature-v4": "^5.7.3", + "@smithy/signature-v4": "^5.7.4", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, @@ -377,15 +377,15 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.46", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.46.tgz", - "integrity": "sha512-oRxtBcka/JGHGs9l9p9IVajGoTP8vTPmoAzdHGy4Qcy9P5vPnDf6nhIeM/COQNY9k/OahImTRaLkHftoXvfcmQ==", + "version": "3.997.50", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.50.tgz", + "integrity": "sha512-nKb8qu4QsnpZTq/6JIXc72mzuzfh7BK4sUQkpQznPec2z4W7Ob2xYkcM4i5e1yGTBnbJVeFv/0sf3jcz85hclA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/signature-v4-multi-region": "^3.996.47", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", + "@aws-sdk/core": "^3.978.5", + "@aws-sdk/signature-v4-multi-region": "^3.996.49", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.36.1", "@smithy/fetch-http-handler": "^5.8.0", "@smithy/node-http-handler": "^4.12.1", "@smithy/types": "^4.19.0", @@ -396,13 +396,13 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.47", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.47.tgz", - "integrity": "sha512-Zk08macMvQTHzQJCLJVkOlviVoqwYMrpXv4lmLN7b7sAbiMoOK7Go0NYdR5UeF+MW8LIbRmwrNy9u/5VvX1U5g==", + "version": "3.996.49", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.49.tgz", + "integrity": "sha512-nvuAZNRrRRVCiARRKsYlQ0VnXiEQiq7vXPH+UA+LSo+kN3Djl9eo/V2r0udkw85PnsNshmv2Em1clld5M3j67w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.974.6", - "@smithy/signature-v4": "^5.7.3", + "@aws-sdk/types": "^3.975.0", + "@smithy/signature-v4": "^5.7.4", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, @@ -428,9 +428,9 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.974.6", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.6.tgz", - "integrity": "sha512-v/clNZzZnDxGyvpHMOGpJKVXFAExJzUNAAjaWGdcx8QAcXLGwTaOkw33p5SHAi0YAioK32xB3hWwOekRVfmfKg==", + "version": "3.975.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.975.0.tgz", + "integrity": "sha512-WQlhs6juByzWOzj5fwxOx0mPJaEqMcG/sDpl3Id61B3XhKE63xY+0QWcnG+sWR/sCfprmreyUo1lM7IKZmHMzw==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.19.0", @@ -463,9 +463,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.10.tgz", + "integrity": "sha512-NpugTzbKgGrNe45Ui32cN8vCFFMxVtP/9rtfwv0nP5FRDAjvYBxJcLVpYA9mr1jxP6cnIT7x9LUzuDTbWYYNRA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -484,12 +484,12 @@ "license": "Apache-2.0" }, "node_modules/@earendil-works/pi-agent-core": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-1.0.2.tgz", - "integrity": "sha512-VRfewY1R5mbedJzlm01PxdCmqU8QrSXjXXhV50bp6rvVuT8YYQv1inTXRY4YzssmGAYpkC2rXipJKP5BpBFXew==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-1.4.0.tgz", + "integrity": "sha512-PoKY84SKUwnt7S5QBZaGUqfNO1kjP3KHpHUA9QpFTj4cOjaVWMYIcBPJ6FDRCdE8Zen9OSECQUd0uUfVgtSmgA==", "license": "MIT", "dependencies": { - "@earendil-works/pi-ai": "^1.0.2", + "@earendil-works/pi-ai": "1.4.0", "typebox": "1.3.27" }, "engines": { @@ -497,14 +497,14 @@ } }, "node_modules/@earendil-works/pi-ai": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-1.0.2.tgz", - "integrity": "sha512-JP59xGlSAQ/HhQ6EHN5qmneBlWfDyu6FPPryAvAaSo8A38ubAsEpS9YisCM5Jbbns0srrDffLZonE0OXorHI5A==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-1.4.0.tgz", + "integrity": "sha512-hQM/C4+1w8rHYACzDDf+0vQMnEnpzIop1tptIERVgR3ZeT/hHSzBNG8PaWPgxWQjqSeKCyBZSyp8uTT6eKK1pQ==", "license": "MIT", "dependencies": { "@anthropic-ai/sdk": "0.129.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", - "@earendil-works/pi-telemetry": "^1.0.2", + "@earendil-works/pi-telemetry": "1.4.0", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", @@ -558,9 +558,9 @@ } }, "node_modules/@earendil-works/pi-telemetry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-1.0.2.tgz", - "integrity": "sha512-Ev5h9TE8nEXHCfRKhWj0qpUFhQgVqNteS95vsM2KNGRGm533vOO2ruDPaEwImBKPMBKXy4omz3D6V2cm41gLOQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-1.4.0.tgz", + "integrity": "sha512-MLIfowwUYIY65jSjMX82paZOrX/NTvLk6D08h+3Jq42a99RzUOewzuCR0zOlPul3D6UBfddat76VT6LvsHEs1w==", "license": "MIT", "engines": { "node": ">=22.19.0" @@ -4727,9 +4727,9 @@ } }, "node_modules/@smithy/core": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.35.1.tgz", - "integrity": "sha512-i4YPS4B6ts7bjn7UwLnGjiZdprOvHvgGobFZsYK3GIY3E5hIqtj0rReU69BcTpGp+fvtraSNXeG1l+jtJvF55w==", + "version": "3.36.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.36.2.tgz", + "integrity": "sha512-oRw0rB9QSUiCZfEs23G5F4Af+b2rQt1lItIICWu5IejFNd+uPM8SWqiKLMpQ6bX1Q7slsLbjuoE2niErFtkVPQ==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.19.0", diff --git a/package.json b/package.json index 78509c7..1a744fe 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,8 @@ "desktop:dist": "rm -rf dist .next/standalone && next build && node scripts/build-server.mjs && node scripts/smoke-server.mjs && DEVELOPER_DIR=${DEVELOPER_DIR:-/Applications/Xcode.app/Contents/Developer} APPLE_KEYCHAIN_PROFILE=LH_NOTARY APPLE_TEAM_ID=JS6XN22HY6 electron-builder --mac --arm64" }, "dependencies": { - "@earendil-works/pi-agent-core": "1.0.2", - "@earendil-works/pi-ai": "1.0.2", + "@earendil-works/pi-agent-core": "1.4.0", + "@earendil-works/pi-ai": "1.4.0", "@mozilla/readability": "^0.6.0", "@radix-ui/react-use-controllable-state": "^1.2.6", "@resvg/resvg-js": "^2.6.2", diff --git a/src/agent/models.ts b/src/agent/models.ts index 012e829..80bc11e 100644 --- a/src/agent/models.ts +++ b/src/agent/models.ts @@ -11,6 +11,14 @@ import { builtinProviders } from "@earendil-works/pi-ai/providers/all"; import type { ThinkingLevel } from "@earendil-works/pi-agent-core"; import { type ModelRole } from "../../config.ts"; import { DEFAULT_THINKING_ORDER } from "../core/settings.ts"; +import packageMetadata from "../../package.json" with { type: "json" }; + +/** App identity is immutable and shared by Models and every native Agent. + * Agent's default Pi attribution otherwise overrides the Models identity. */ +export const APP_IDENTITY = Object.freeze({ + userAgent: Object.freeze({ custom: `learnharness/${packageMetadata.version}` }), + attribution: Object.freeze({ name: packageMetadata.name, url: packageMetadata.homepage }), +}); /** * The one engine factory every agent's model comes from (the pi-ai swap, @@ -47,7 +55,7 @@ let collection: ReturnType | undefined; * keyPresent. */ export function piModels() { if (!collection) { - collection = createModels(); + collection = createModels({ identity: APP_IDENTITY }); for (const provider of builtinProviders()) collection.setProvider(provider); } return collection; diff --git a/src/agent/subagents/pdf-reader.ts b/src/agent/subagents/pdf-reader.ts index cc2085b..462a3e3 100644 --- a/src/agent/subagents/pdf-reader.ts +++ b/src/agent/subagents/pdf-reader.ts @@ -1,3 +1,4 @@ +import { randomUUID } from "node:crypto"; import type { AssistantMessage, Message, ToolResultMessage, Usage, Tool } from "@earendil-works/pi-ai"; import { normalizeContext } from "@earendil-works/pi-ai"; import { Type } from "typebox"; @@ -183,6 +184,7 @@ export async function runPdfReaderAgent( // BYOK (owner, 2026-09-22): the level rides the injected engine — no // factory pin to consult (engine.level is the resolved/clamped value). const reasoning = engine.level; + const sessionId = randomUUID(); const prompt = [ `PDF path: ${pdfPath}`, `Question (what the teacher needs from this document): ${input.question || "(no question — give a structural overview)"}`, @@ -207,6 +209,7 @@ export async function runPdfReaderAgent( INSTRUCTIONS, messages, toolDeclarations, + sessionId, reasoning, opts.abortSignal, opts.chatId ? providerEventObserver(opts.chatId, "job:pdfReader") : undefined, @@ -395,6 +398,7 @@ async function streamOnce( systemPrompt: string, messages: Message[], tools: Tool[], + sessionId: string, reasoning: ThinkingLevel | undefined, abortSignal?: AbortSignal, onProviderStreamEvent?: ProviderEventObserver, @@ -403,6 +407,7 @@ async function streamOnce( // and tool declarations fold into a leading system message. // normalizeContext is the library's only Context→TranscriptContext entry. const stream = engine.streamFn(engine.model, normalizeContext({ systemPrompt, messages, tools }), { + sessionId, reasoning: reasoning && reasoning !== "off" ? reasoning : undefined, signal: abortSignal, onProviderStreamEvent: onProviderStreamEvent as never, diff --git a/src/agent/subagents/pi-run.ts b/src/agent/subagents/pi-run.ts index 796ed17..453a0f7 100644 --- a/src/agent/subagents/pi-run.ts +++ b/src/agent/subagents/pi-run.ts @@ -1,6 +1,7 @@ import { Agent, type AgentEvent, type AgentMessage, type AgentTool } from "@earendil-works/pi-agent-core"; import type { AssistantMessage, ToolResultMessage, Usage } from "@earendil-works/pi-ai"; -import { piEngineFor, type PiEngine } from "../models.ts"; +import { randomUUID } from "node:crypto"; +import { APP_IDENTITY, piEngineFor, type PiEngine } from "../models.ts"; import { providerEventObserver } from "../provider-events.ts"; import type { ModelRole } from "../../../config.ts"; @@ -64,6 +65,9 @@ export async function runSubagent(tools: AgentTool[], opts: SubagentRu // Debug recorder (owner, 2026-10-04): raw provider events per job run. const providerEvents = opts.chatId ? providerEventObserver(opts.chatId, `job:${opts.role}`) : undefined; const agent = new Agent({ + identity: APP_IDENTITY, + // One unsaved conversation per invocation, stable through every turn. + sessionId: randomUUID(), initialState: { systemPrompt: opts.systemPrompt, model: engine.model, diff --git a/src/agent/subagents/visual-maker.ts b/src/agent/subagents/visual-maker.ts index 9fb6e3b..8daac95 100644 --- a/src/agent/subagents/visual-maker.ts +++ b/src/agent/subagents/visual-maker.ts @@ -1,3 +1,4 @@ +import { randomUUID } from "node:crypto"; import type { AssistantMessage, Message, Tool, ToolResultMessage, Usage } from "@earendil-works/pi-ai"; import { normalizeContext } from "@earendil-works/pi-ai"; import { Type } from "typebox"; @@ -142,6 +143,7 @@ export async function runVisualMaker(input: VisualMakerInput, opts: VisualMakerO // BYOK (owner, 2026-09-22): the level rides the injected engine — no // factory pin to consult (engine.level is the resolved/clamped value). const reasoning = engine.level; + const sessionId = randomUUID(); const prompt = [ "Brief for ONE precise figure (from the teacher, verbatim — it is everything you know):", brief, @@ -164,6 +166,7 @@ export async function runVisualMaker(input: VisualMakerInput, opts: VisualMakerO INSTRUCTIONS, messages, toolDeclarations, + sessionId, reasoning, opts.abortSignal, opts.chatId ? providerEventObserver(opts.chatId, "job:visualMaker") : undefined, @@ -317,6 +320,7 @@ async function streamOnce( systemPrompt: string, messages: Message[], tools: Tool[], + sessionId: string, reasoning: ThinkingLevel | undefined, abortSignal?: AbortSignal, onProviderStreamEvent?: ProviderEventObserver, @@ -325,6 +329,7 @@ async function streamOnce( // and tool declarations fold into a leading system message. // normalizeContext is the library's only Context→TranscriptContext entry. const stream = engine.streamFn(engine.model, normalizeContext({ systemPrompt, messages, tools }), { + sessionId, reasoning: reasoning && reasoning !== "off" ? reasoning : undefined, signal: abortSignal, onProviderStreamEvent: onProviderStreamEvent as never, diff --git a/src/agent/teacher-agent.ts b/src/agent/teacher-agent.ts index 0aca5c8..892320f 100644 --- a/src/agent/teacher-agent.ts +++ b/src/agent/teacher-agent.ts @@ -4,7 +4,7 @@ import { invalidInputResult, questionResult } from "./tool-execute.ts"; import { providerEventObserver } from "./provider-events.ts"; import type { Usage } from "@earendil-works/pi-ai"; import { PATHS } from "../../config.ts"; -import { piEngineFor, type PiEngine } from "./models.ts"; +import { APP_IDENTITY, piEngineFor, type PiEngine } from "./models.ts"; import { effectivePromptSegments } from "./prompt-segments.ts"; import { askUserQuestionTool, @@ -116,7 +116,9 @@ export interface AgentBuildOptions { * fresh per turn, honoring enabled overrides (switch on + file * exists); absent → the cached pure-source composition. */ promptSwitches?: Record; - /** Debug: when set AND LH_PROVIDER_EVENTS=1, raw provider stream events + /** Native conversation identity: the existing persisted chat id, reused + * across reconstructed prober, teacher, and practice Agents. + * Debug: when set AND LH_PROVIDER_EVENTS=1, raw provider stream events * (pre-normalization) append to data/debug/provider-events/ * .jsonl via providerEventObserver — the GLM-truncation / * DeepSeek-id incident layer. Absent or env-off → no observer. */ @@ -177,6 +179,8 @@ function baseAgentOptions(kind: AgentKind, opts: AgentBuildOptions, tools: Agent // the normal no-observer path (tests, env-off). const providerEvents = opts.chatId ? providerEventObserver(opts.chatId, kind) : undefined; const agent = new Agent({ + identity: APP_IDENTITY, + sessionId: opts.chatId, initialState: { systemPrompt, model: engine.model, diff --git a/src/core/auth-keys.ts b/src/core/auth-keys.ts index d6d4285..e8e5cc9 100644 --- a/src/core/auth-keys.ts +++ b/src/core/auth-keys.ts @@ -77,7 +77,7 @@ export interface AuthProviderInfo { * * EXCLUDED by owner spec — providers whose auth is not a plain key this * wave: github-copilot (OAuth), amazon-bedrock (AWS creds), google-vertex - * (ADC), azure-openai-responses (needs a base URL), the cloudflare + * (ADC), azure (needs a base URL), the cloudflare * account-scoped pair. Anthropic keeps ANTHROPIC_API_KEY only — its * AUTH_TOKEN/OAUTH_TOKEN alternates stay env-only. openai-codex exposes * no env-key (naturally absent). Providers sharing one env var (moonshotai diff --git a/src/core/prices.ts b/src/core/prices.ts index eca9337..c7bc803 100644 --- a/src/core/prices.ts +++ b/src/core/prices.ts @@ -48,6 +48,7 @@ export const PRICES: Record = { "amazon-bedrock:anthropic.claude-fable-5": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "amazon-bedrock:anthropic.claude-fable-5-1": { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 }, "amazon-bedrock:anthropic.claude-haiku-4-5-20251001-v1:0": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, + "amazon-bedrock:anthropic.claude-haiku-5-5": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "amazon-bedrock:anthropic.claude-opus-4-1-20250805-v1:0": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }, "amazon-bedrock:anthropic.claude-opus-4-5-20251101-v1:0": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "amazon-bedrock:anthropic.claude-opus-4-6-v1": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, @@ -57,12 +58,13 @@ export const PRICES: Record = { "amazon-bedrock:anthropic.claude-sonnet-4-5-20250929-v1:0": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "amazon-bedrock:anthropic.claude-sonnet-4-6": { input: 3.3, output: 16.5, cacheRead: 0.33, cacheWrite: 4.125 }, "amazon-bedrock:anthropic.claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, - "amazon-bedrock:anthropic.claude-sonnet-5-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, + "amazon-bedrock:anthropic.claude-sonnet-5-5": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, "amazon-bedrock:apac.amazon.nova-lite-v1:0": { input: 0.063, output: 0.252, cacheRead: 0.01575, cacheWrite: 0.063 }, "amazon-bedrock:apac.amazon.nova-micro-v1:0": { input: 0.037, output: 0.148, cacheRead: 0.00925, cacheWrite: 0.037 }, "amazon-bedrock:apac.amazon.nova-pro-v1:0": { input: 0.84, output: 3.36, cacheRead: 0.21, cacheWrite: 0.84 }, "amazon-bedrock:apac.anthropic.claude-sonnet-4-20250514-v1:0": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "amazon-bedrock:au.anthropic.claude-haiku-4-5-20251001-v1:0": { input: 1.1, output: 5.5, cacheRead: 0.11, cacheWrite: 1.375 }, + "amazon-bedrock:au.anthropic.claude-haiku-5-5": { input: 0.11, output: 0.55, cacheRead: 0.011, cacheWrite: 0.1375 }, "amazon-bedrock:au.anthropic.claude-opus-4-6-v1": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, "amazon-bedrock:au.anthropic.claude-opus-4-7": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, "amazon-bedrock:au.anthropic.claude-opus-4-8": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, @@ -80,6 +82,7 @@ export const PRICES: Record = { "amazon-bedrock:eu.amazon.nova-pro-v1:0": { input: 0.92, output: 3.68, cacheRead: 0.23, cacheWrite: 0.92 }, "amazon-bedrock:eu.anthropic.claude-fable-5": { input: 11, output: 55, cacheRead: 1.1, cacheWrite: 13.75 }, "amazon-bedrock:eu.anthropic.claude-haiku-4-5-20251001-v1:0": { input: 1.1, output: 5.5, cacheRead: 0.11, cacheWrite: 1.375 }, + "amazon-bedrock:eu.anthropic.claude-haiku-5-5": { input: 0.11, output: 0.55, cacheRead: 0.011, cacheWrite: 0.1375 }, "amazon-bedrock:eu.anthropic.claude-opus-4-5-20251101-v1:0": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, "amazon-bedrock:eu.anthropic.claude-opus-4-6-v1": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, "amazon-bedrock:eu.anthropic.claude-opus-4-7": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, @@ -90,11 +93,13 @@ export const PRICES: Record = { "amazon-bedrock:eu.anthropic.claude-sonnet-4-5-20250929-v1:0": { input: 3.3, output: 16.5, cacheRead: 0.33, cacheWrite: 4.125 }, "amazon-bedrock:eu.anthropic.claude-sonnet-4-6": { input: 3.3, output: 16.5, cacheRead: 0.33, cacheWrite: 4.125 }, "amazon-bedrock:eu.anthropic.claude-sonnet-5": { input: 2.2, output: 11, cacheRead: 0.22, cacheWrite: 2.75 }, + "amazon-bedrock:eu.anthropic.claude-sonnet-5-5": { input: 2.2, output: 11, cacheRead: 0.11, cacheWrite: 2.75 }, "amazon-bedrock:eu.mistral.pixtral-large-2502-v1:0": { input: 2, output: 6, cacheRead: 0, cacheWrite: 0 }, "amazon-bedrock:global.amazon.nova-2-lite-v1:0": { input: 0.3, output: 2.5, cacheRead: 0.075, cacheWrite: 0.3 }, "amazon-bedrock:global.anthropic.claude-fable-5": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "amazon-bedrock:global.anthropic.claude-fable-5-1": { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 }, "amazon-bedrock:global.anthropic.claude-haiku-4-5-20251001-v1:0": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, + "amazon-bedrock:global.anthropic.claude-haiku-5-5": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "amazon-bedrock:global.anthropic.claude-opus-4-5-20251101-v1:0": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "amazon-bedrock:global.anthropic.claude-opus-4-6-v1": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "amazon-bedrock:global.anthropic.claude-opus-4-7": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, @@ -105,7 +110,7 @@ export const PRICES: Record = { "amazon-bedrock:global.anthropic.claude-sonnet-4-5-20250929-v1:0": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "amazon-bedrock:global.anthropic.claude-sonnet-4-6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "amazon-bedrock:global.anthropic.claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, - "amazon-bedrock:global.anthropic.claude-sonnet-5-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, + "amazon-bedrock:global.anthropic.claude-sonnet-5-5": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, "amazon-bedrock:global.moonshotai.kimi-k3": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "amazon-bedrock:global.openai.gpt-5.6-luna": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, "amazon-bedrock:global.openai.gpt-5.6-sol": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, @@ -116,6 +121,7 @@ export const PRICES: Record = { "amazon-bedrock:global.openai.gpt-6.1-sol": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, "amazon-bedrock:global.xai.grok-4.6": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "amazon-bedrock:global.xai.grok-4.7": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, + "amazon-bedrock:global.zai.glm-5.3": { input: 1.68, output: 5.28, cacheRead: 0.312, cacheWrite: 2.1 }, "amazon-bedrock:google.gemma-4-26b-a4b": { input: 0.13, output: 0.4, cacheRead: 0, cacheWrite: 0 }, "amazon-bedrock:google.gemma-4-31b": { input: 0.14, output: 0.4, cacheRead: 0, cacheWrite: 0 }, "amazon-bedrock:google.gemma-4-e2b": { input: 0.04, output: 0.08, cacheRead: 0, cacheWrite: 0 }, @@ -126,6 +132,7 @@ export const PRICES: Record = { "amazon-bedrock:in.openai.gpt-5.6-terra": { input: 2.2, output: 13.2, cacheRead: 0.22, cacheWrite: 2.75 }, "amazon-bedrock:jp.amazon.nova-2-lite-v1:0": { input: 0.396, output: 3.311, cacheRead: 0.099, cacheWrite: 0.396 }, "amazon-bedrock:jp.anthropic.claude-haiku-4-5-20251001-v1:0": { input: 1.1, output: 5.5, cacheRead: 0.11, cacheWrite: 1.375 }, + "amazon-bedrock:jp.anthropic.claude-haiku-5-5": { input: 0.11, output: 0.55, cacheRead: 0.011, cacheWrite: 0.1375 }, "amazon-bedrock:jp.anthropic.claude-opus-4-7": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, "amazon-bedrock:jp.anthropic.claude-opus-4-8": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, "amazon-bedrock:jp.anthropic.claude-opus-5": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, @@ -188,6 +195,7 @@ export const PRICES: Record = { "amazon-bedrock:us.anthropic.claude-fable-5": { input: 11, output: 55, cacheRead: 1.1, cacheWrite: 13.75 }, "amazon-bedrock:us.anthropic.claude-fable-5-1": { input: 11, output: 55, cacheRead: 0.275, cacheWrite: 13.75 }, "amazon-bedrock:us.anthropic.claude-haiku-4-5-20251001-v1:0": { input: 1.1, output: 5.5, cacheRead: 0.11, cacheWrite: 1.375 }, + "amazon-bedrock:us.anthropic.claude-haiku-5-5": { input: 0.11, output: 0.55, cacheRead: 0.011, cacheWrite: 0.1375 }, "amazon-bedrock:us.anthropic.claude-opus-4-1-20250805-v1:0": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }, "amazon-bedrock:us.anthropic.claude-opus-4-5-20251101-v1:0": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, "amazon-bedrock:us.anthropic.claude-opus-4-6-v1": { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, @@ -199,6 +207,7 @@ export const PRICES: Record = { "amazon-bedrock:us.anthropic.claude-sonnet-4-5-20250929-v1:0": { input: 3.3, output: 16.5, cacheRead: 0.33, cacheWrite: 4.125 }, "amazon-bedrock:us.anthropic.claude-sonnet-4-6": { input: 3.3, output: 16.5, cacheRead: 0.33, cacheWrite: 4.125 }, "amazon-bedrock:us.anthropic.claude-sonnet-5": { input: 2.2, output: 11, cacheRead: 0.22, cacheWrite: 2.75 }, + "amazon-bedrock:us.anthropic.claude-sonnet-5-5": { input: 2.2, output: 11, cacheRead: 0.11, cacheWrite: 2.75 }, "amazon-bedrock:us.meta.llama3-1-70b-instruct-v1:0": { input: 0.72, output: 0.72, cacheRead: 0, cacheWrite: 0 }, "amazon-bedrock:us.meta.llama3-1-8b-instruct-v1:0": { input: 0.22, output: 0.22, cacheRead: 0, cacheWrite: 0 }, "amazon-bedrock:us.meta.llama3-3-70b-instruct-v1:0": { input: 0.72, output: 0.72, cacheRead: 0, cacheWrite: 0 }, @@ -217,6 +226,7 @@ export const PRICES: Record = { "amazon-bedrock:us.writer.palmyra-x5-v1:0": { input: 0.6, output: 6, cacheRead: 0, cacheWrite: 0 }, "amazon-bedrock:us.xai.grok-4.6": { input: 2.2, output: 6.6, cacheRead: 0.55, cacheWrite: 0 }, "amazon-bedrock:us.xai.grok-4.7": { input: 2.2, output: 6.6, cacheRead: 0.55, cacheWrite: 0 }, + "amazon-bedrock:us.zai.glm-5.3": { input: 1.848, output: 5.808, cacheRead: 0.3432, cacheWrite: 2.31 }, "amazon-bedrock:writer.palmyra-x4-v1:0": { input: 2.5, output: 10, cacheRead: 0, cacheWrite: 0 }, "amazon-bedrock:writer.palmyra-x5-v1:0": { input: 0.6, output: 6, cacheRead: 0, cacheWrite: 0 }, "amazon-bedrock:xai.grok-4.3": { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, @@ -231,6 +241,7 @@ export const PRICES: Record = { "anthropic:claude-fable-5-1": { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 }, "anthropic:claude-haiku-4-5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, "anthropic:claude-haiku-4-5-20251001": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, + "anthropic:claude-haiku-5-5": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "anthropic:claude-opus-4-5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "anthropic:claude-opus-4-5-20251101": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "anthropic:claude-opus-4-6": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, @@ -242,78 +253,70 @@ export const PRICES: Record = { "anthropic:claude-sonnet-4-5-20250929": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "anthropic:claude-sonnet-4-6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "anthropic:claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, - "anthropic:claude-sonnet-5-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, - "azure-openai-responses:gpt-4": { input: 30, output: 60, cacheRead: 0, cacheWrite: 0 }, - "azure-openai-responses:gpt-4-turbo": { input: 10, output: 30, cacheRead: 0, cacheWrite: 0 }, - "azure-openai-responses:gpt-4.1": { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, - "azure-openai-responses:gpt-4.1-mini": { input: 0.4, output: 1.6, cacheRead: 0.1, cacheWrite: 0 }, - "azure-openai-responses:gpt-4.1-nano": { input: 0.1, output: 0.4, cacheRead: 0.025, cacheWrite: 0 }, - "azure-openai-responses:gpt-4o": { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, - "azure-openai-responses:gpt-4o-2024-05-13": { input: 5, output: 15, cacheRead: 0, cacheWrite: 0 }, - "azure-openai-responses:gpt-4o-2024-08-06": { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, - "azure-openai-responses:gpt-4o-2024-11-20": { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, - "azure-openai-responses:gpt-4o-mini": { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, - "azure-openai-responses:gpt-5": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, - "azure-openai-responses:gpt-5-chat-latest": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, - "azure-openai-responses:gpt-5-mini": { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, - "azure-openai-responses:gpt-5-nano": { input: 0.05, output: 0.4, cacheRead: 0.005, cacheWrite: 0 }, - "azure-openai-responses:gpt-5-pro": { input: 15, output: 120, cacheRead: 0, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.1": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.2": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.2-chat-latest": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.2-pro": { input: 21, output: 168, cacheRead: 0, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.3-chat-latest": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.3-codex": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.3-codex-spark": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.4": { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.4-mini": { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.4-nano": { input: 0.2, output: 1.25, cacheRead: 0.02, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.4-pro": { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.5": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.5-pro": { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, - "azure-openai-responses:gpt-5.6-luna": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, - "azure-openai-responses:gpt-5.6-sol": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, - "azure-openai-responses:gpt-5.6-terra": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, - "azure-openai-responses:gpt-6-astra": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, - "azure-openai-responses:gpt-6-luna": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, - "azure-openai-responses:gpt-6-sol": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, - "azure-openai-responses:gpt-6.1-sol": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, - "azure-openai-responses:gpt-daybreak-blue-latest": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, - "azure-openai-responses:gpt-daybreak-red-latest": { input: 12.5, output: 75, cacheRead: 1.25, cacheWrite: 15.625 }, - "azure-openai-responses:gpt-realtime-2.1": { input: 4, output: 24, cacheRead: 0.4, cacheWrite: 0 }, - "azure-openai-responses:o1": { input: 15, output: 60, cacheRead: 7.5, cacheWrite: 0 }, - "azure-openai-responses:o1-pro": { input: 150, output: 600, cacheRead: 0, cacheWrite: 0 }, - "azure-openai-responses:o3": { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, - "azure-openai-responses:o3-mini": { input: 1.1, output: 4.4, cacheRead: 0.55, cacheWrite: 0 }, - "azure-openai-responses:o3-pro": { input: 20, output: 80, cacheRead: 0, cacheWrite: 0 }, - "azure-openai-responses:o4-mini": { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, + "anthropic:claude-sonnet-5-5": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, + "azure:deepseek-v4-pro": { input: 1.925, output: 3.828, cacheRead: 0.165, cacheWrite: 0 }, + "azure:gpt-4": { input: 30, output: 60, cacheRead: 0, cacheWrite: 0 }, + "azure:gpt-4-turbo": { input: 10, output: 30, cacheRead: 0, cacheWrite: 0 }, + "azure:gpt-4.1": { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, + "azure:gpt-4.1-mini": { input: 0.4, output: 1.6, cacheRead: 0.1, cacheWrite: 0 }, + "azure:gpt-4.1-nano": { input: 0.1, output: 0.4, cacheRead: 0.025, cacheWrite: 0 }, + "azure:gpt-4o": { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, + "azure:gpt-4o-2024-05-13": { input: 5, output: 15, cacheRead: 0, cacheWrite: 0 }, + "azure:gpt-4o-2024-08-06": { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, + "azure:gpt-4o-2024-11-20": { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, + "azure:gpt-4o-mini": { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, + "azure:gpt-5": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, + "azure:gpt-5-chat-latest": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, + "azure:gpt-5-mini": { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, + "azure:gpt-5-nano": { input: 0.05, output: 0.4, cacheRead: 0.005, cacheWrite: 0 }, + "azure:gpt-5-pro": { input: 15, output: 120, cacheRead: 0, cacheWrite: 0 }, + "azure:gpt-5.1": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, + "azure:gpt-5.2": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, + "azure:gpt-5.2-pro": { input: 21, output: 168, cacheRead: 0, cacheWrite: 0 }, + "azure:gpt-5.3-codex": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, + "azure:gpt-5.3-codex-spark": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, + "azure:gpt-5.4": { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, + "azure:gpt-5.4-mini": { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, + "azure:gpt-5.4-nano": { input: 0.2, output: 1.25, cacheRead: 0.02, cacheWrite: 0 }, + "azure:gpt-5.4-pro": { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, + "azure:gpt-5.5": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, + "azure:gpt-5.5-pro": { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, + "azure:gpt-5.6-luna": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, + "azure:gpt-5.6-sol": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, + "azure:gpt-5.6-terra": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, + "azure:gpt-6-astra": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, + "azure:gpt-6-luna": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, + "azure:gpt-6-sol": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, + "azure:gpt-6.1-sol": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, + "azure:gpt-daybreak-blue-latest": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, + "azure:gpt-daybreak-red-latest": { input: 12.5, output: 75, cacheRead: 1.25, cacheWrite: 15.625 }, + "azure:gpt-realtime-2.1": { input: 4, output: 24, cacheRead: 0.4, cacheWrite: 0 }, + "azure:o1": { input: 15, output: 60, cacheRead: 7.5, cacheWrite: 0 }, + "azure:o1-pro": { input: 150, output: 600, cacheRead: 0, cacheWrite: 0 }, + "azure:o3": { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, + "azure:o3-mini": { input: 1.1, output: 4.4, cacheRead: 0.55, cacheWrite: 0 }, + "azure:o3-pro": { input: 20, output: 80, cacheRead: 0, cacheWrite: 0 }, + "azure:o4-mini": { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, "baseten:deepseek-ai/DeepSeek-V4-Flash-0731": { input: 0.13, output: 0.26, cacheRead: 0.028, cacheWrite: 0 }, - "baseten:deepseek-ai/DeepSeek-V4-Pro": { input: 1.74, output: 3.48, cacheRead: 0.145, cacheWrite: 0 }, - "baseten:deepseek-ai/DeepSeek-V4-Pro-0813": { input: 1.32, output: 3.96, cacheRead: 0, cacheWrite: 0 }, - "baseten:deepseek-ai/DeepSeek-V4.1-Flash": { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0 }, - "baseten:deepseek-ai/DeepSeek-V4.1-Flash-Fast": { input: 0.6, output: 2.4, cacheRead: 0, cacheWrite: 0 }, - "baseten:moonshotai/Kimi-K2.5": { input: 0.6, output: 3, cacheRead: 0.12, cacheWrite: 0 }, - "baseten:moonshotai/Kimi-K2.6": { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, - "baseten:moonshotai/Kimi-K2.7-Code": { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, - "baseten:moonshotai/Kimi-K3": { input: 3, output: 15, cacheRead: 0, cacheWrite: 0 }, - "baseten:nvidia/Nemotron-120B-A12B": { input: 0.3, output: 0.75, cacheRead: 0.06, cacheWrite: 0 }, + "baseten:deepseek-ai/DeepSeek-V4-Pro-0813": { input: 1.32, output: 3.96, cacheRead: 0.132, cacheWrite: 0 }, + "baseten:deepseek-ai/DeepSeek-V4.1-Flash": { input: 0.3, output: 1.2, cacheRead: 0.007, cacheWrite: 0 }, + "baseten:deepseek-ai/DeepSeek-V4.1-Flash-1017": { input: 0.3, output: 1.2, cacheRead: 0.007, cacheWrite: 0 }, + "baseten:deepseek-ai/DeepSeek-V4.1-Flash-1017-Fast": { input: 0.6, output: 2.4, cacheRead: 0.014, cacheWrite: 0 }, + "baseten:deepseek-ai/DeepSeek-V4.1-Flash-Fast": { input: 0.6, output: 2.4, cacheRead: 0.014, cacheWrite: 0 }, + "baseten:moonshotai/Kimi-K3": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, "baseten:nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B": { input: 0.6, output: 2.4, cacheRead: 0.12, cacheWrite: 0 }, - "baseten:openai/gpt-oss-120b": { input: 0.1, output: 0.5, cacheRead: 0, cacheWrite: 0 }, - "baseten:thinkingmachines/inkling": { input: 1, output: 4.05, cacheRead: 0, cacheWrite: 0 }, - "baseten:thinkingmachines/inkling-small": { input: 0.5, output: 1.2, cacheRead: 0.1, cacheWrite: 0 }, - "baseten:zai-org/GLM-4.7": { input: 0.6, output: 2.2, cacheRead: 0.12, cacheWrite: 0 }, - "baseten:zai-org/GLM-5": { input: 0.95, output: 3.15, cacheRead: 0.2, cacheWrite: 0 }, - "baseten:zai-org/GLM-5.1": { input: 1.3, output: 4.3, cacheRead: 0.26, cacheWrite: 0 }, - "baseten:zai-org/GLM-5.2": { input: 1.4, output: 4.4, cacheRead: 0.3, cacheWrite: 0 }, + "baseten:openai/gpt-oss-120b": { input: 0.1, output: 0.5, cacheRead: 0.1, cacheWrite: 0 }, + "baseten:zai-org/GLM-5.2": { input: 1.4, output: 4.4, cacheRead: 0.14, cacheWrite: 0 }, "baseten:zai-org/GLM-5.2-Fast": { input: 2.1, output: 6.6, cacheRead: 0.21, cacheWrite: 0 }, "baseten:zai-org/GLM-5.3": { input: 1.4, output: 4.4, cacheRead: 0.14, cacheWrite: 0 }, - "baseten:zai-org/GLM-5.3-Fast": { input: 2.1, output: 6.6, cacheRead: 0, cacheWrite: 0 }, - "baseten:zai-org/GLM-5.3-Flash": { input: 0.15, output: 0.5, cacheRead: 0, cacheWrite: 0 }, - "cerebras:gpt-oss-120b": { input: 0.35, output: 0.75, cacheRead: 0, cacheWrite: 0 }, + "baseten:zai-org/GLM-5.3-Fast": { input: 2.1, output: 6.6, cacheRead: 0.21, cacheWrite: 0 }, + "baseten:zai-org/GLM-5.3-Flash": { input: 0.15, output: 0.5, cacheRead: 0.03, cacheWrite: 0 }, + "cerebras:gpt-oss-120b": { input: 0.35, output: 0.75, cacheRead: 0.35, cacheWrite: 0 }, "cerebras:qwen-3.8-27b": { input: 0.99, output: 1.49, cacheRead: 0.99, cacheWrite: 0 }, "cloudflare-ai-gateway:claude-fable-5": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "cloudflare-ai-gateway:claude-fable-5-1": { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 }, "cloudflare-ai-gateway:claude-haiku-4-5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, + "cloudflare-ai-gateway:claude-haiku-5-5": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "cloudflare-ai-gateway:claude-opus-4-5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "cloudflare-ai-gateway:claude-opus-4-6": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "cloudflare-ai-gateway:claude-opus-4-7": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, @@ -323,6 +326,7 @@ export const PRICES: Record = { "cloudflare-ai-gateway:claude-sonnet-4-5": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "cloudflare-ai-gateway:claude-sonnet-4-6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "cloudflare-ai-gateway:claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, + "cloudflare-ai-gateway:claude-sonnet-5-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, "cloudflare-ai-gateway:gpt-4.1": { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, "cloudflare-ai-gateway:gpt-4.1-mini": { input: 0.4, output: 1.6, cacheRead: 0.1, cacheWrite: 0 }, "cloudflare-ai-gateway:gpt-4.1-nano": { input: 0.1, output: 0.4, cacheRead: 0.025, cacheWrite: 0 }, @@ -344,11 +348,13 @@ export const PRICES: Record = { "cloudflare-ai-gateway:gpt-6-astra": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "cloudflare-ai-gateway:gpt-6-luna": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "cloudflare-ai-gateway:gpt-6-sol": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, + "cloudflare-ai-gateway:gpt-6.1-sol": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, "cloudflare-ai-gateway:o3": { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, "cloudflare-ai-gateway:o3-mini": { input: 1.1, output: 4.4, cacheRead: 0.55, cacheWrite: 0 }, "cloudflare-ai-gateway:o4-mini": { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, "cloudflare-ai-gateway:workers-ai/@cf/deepseek-ai/deepseek-v4-flash-0731": { input: 0.44, output: 1.32, cacheRead: 0.014, cacheWrite: 0 }, "cloudflare-ai-gateway:workers-ai/@cf/deepseek-ai/deepseek-v4-pro-0813": { input: 1.32, output: 3.96, cacheRead: 0.044, cacheWrite: 0 }, + "cloudflare-ai-gateway:workers-ai/@cf/deepseek-ai/deepseek-v4.1-flash-1017": { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 }, "cloudflare-ai-gateway:workers-ai/@cf/google/gemma-4-26b-a4b-it": { input: 0.1, output: 0.3, cacheRead: 0.05, cacheWrite: 0 }, "cloudflare-ai-gateway:workers-ai/@cf/ibm-granite/granite-4.0-h-micro": { input: 0.017, output: 0.112, cacheRead: 0, cacheWrite: 0 }, "cloudflare-ai-gateway:workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast": { input: 0.293, output: 2.253, cacheRead: 0, cacheWrite: 0 }, @@ -367,6 +373,7 @@ export const PRICES: Record = { "cloudflare-ai-gateway:workers-ai/@cf/zai-org/glm-5.3-flash": { input: 0.15, output: 0.5, cacheRead: 0.03, cacheWrite: 0 }, "cloudflare-workers-ai:@cf/deepseek-ai/deepseek-v4-flash-0731": { input: 0.44, output: 1.32, cacheRead: 0.014, cacheWrite: 0 }, "cloudflare-workers-ai:@cf/deepseek-ai/deepseek-v4-pro-0813": { input: 1.32, output: 3.96, cacheRead: 0.044, cacheWrite: 0 }, + "cloudflare-workers-ai:@cf/deepseek-ai/deepseek-v4.1-flash-1017": { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 }, "cloudflare-workers-ai:@cf/google/gemma-4-26b-a4b-it": { input: 0.1, output: 0.3, cacheRead: 0.05, cacheWrite: 0 }, "cloudflare-workers-ai:@cf/ibm-granite/granite-4.0-h-micro": { input: 0.017, output: 0.112, cacheRead: 0, cacheWrite: 0 }, "cloudflare-workers-ai:@cf/meta/llama-3.3-70b-instruct-fp8-fast": { input: 0.293, output: 2.253, cacheRead: 0, cacheWrite: 0 }, @@ -386,6 +393,7 @@ export const PRICES: Record = { "deepseek:deepseek-flash": { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 }, "deepseek:deepseek-v4-pro": { input: 1.32, output: 3.96, cacheRead: 0.044, cacheWrite: 0 }, "fireworks:accounts/fireworks/models/deepseek-v4p1-flash": { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 }, + "fireworks:accounts/fireworks/models/deepseek-v4p1-flash-1017": { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 }, "fireworks:accounts/fireworks/models/ember-1": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, "fireworks:accounts/fireworks/models/glm-5p3": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, "fireworks:accounts/fireworks/models/glm-5p3-flash": { input: 0.15, output: 0.5, cacheRead: 0.03, cacheWrite: 0 }, @@ -393,6 +401,7 @@ export const PRICES: Record = { "fireworks:accounts/fireworks/models/inkling": { input: 1, output: 4.05, cacheRead: 0.17, cacheWrite: 0 }, "fireworks:accounts/fireworks/models/kimi-k3": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, "fireworks:accounts/fireworks/models/minimax-m3": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, + "fireworks:accounts/fireworks/models/muse-spark-open": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, "fireworks:accounts/fireworks/models/nemotron-3-ultra-nvfp4": { input: 0.6, output: 2.4, cacheRead: 0.12, cacheWrite: 0 }, "fireworks:accounts/fireworks/models/nemotron-lightning-3p5-30b-a3b": { input: 0.05, output: 0.2, cacheRead: 0.01, cacheWrite: 0 }, "fireworks:accounts/fireworks/models/qwen3p8-2p4t-a95b": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 0 }, @@ -410,23 +419,17 @@ export const PRICES: Record = { "github-copilot:claude-fable-5": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "github-copilot:claude-fable-5.1": { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 }, "github-copilot:claude-haiku-4.5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, - "github-copilot:claude-opus-4.7": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, + "github-copilot:claude-haiku-5.5": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "github-copilot:claude-opus-4.8": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "github-copilot:claude-opus-5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "github-copilot:claude-opus-5.5": { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 5 }, "github-copilot:claude-sonnet-4.6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "github-copilot:claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, - "github-copilot:claude-sonnet-5.5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, - "github-copilot:gemini-3.5-flash": { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, - "github-copilot:gemini-3.6-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, - "github-copilot:gemini-3.7-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, + "github-copilot:claude-sonnet-5.5": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, "github-copilot:gemini-3.8-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, - "github-copilot:gpt-5-mini": { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, + "github-copilot:gemini-4-argon": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 0 }, "github-copilot:gpt-5.3-codex": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, - "github-copilot:gpt-5.4": { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, - "github-copilot:gpt-5.4-mini": { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, "github-copilot:gpt-5.4-nano": { input: 0.2, output: 1.25, cacheRead: 0.02, cacheWrite: 0 }, - "github-copilot:gpt-5.5": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, "github-copilot:gpt-5.6-luna": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, "github-copilot:gpt-5.6-sol": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, "github-copilot:gpt-5.6-terra": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, @@ -437,15 +440,14 @@ export const PRICES: Record = { "github-copilot:grok-4.5": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "github-copilot:grok-4.6": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "github-copilot:grok-4.7": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, - "github-copilot:kimi-k2.7-code": { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, "github-copilot:kimi-k3": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, - "github-copilot:mai-code-1-flash-picker": { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, "github-copilot:mai-code-1.1-flash": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0 }, "google-vertex:gemini-2.5-flash": { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, "google-vertex:gemini-2.5-flash-lite": { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, "google-vertex:gemini-2.5-pro": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, "google-vertex:gemini-3-flash-preview": { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 }, "google-vertex:gemini-3.1-flash-lite": { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, + "google-vertex:gemini-3.1-flash-lite-image": { input: 0.25, output: 30, cacheRead: 0.025, cacheWrite: 0 }, "google-vertex:gemini-3.1-pro-preview": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, "google-vertex:gemini-3.1-pro-preview-customtools": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, "google-vertex:gemini-3.5-flash": { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, @@ -453,8 +455,7 @@ export const PRICES: Record = { "google-vertex:gemini-3.6-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, "google-vertex:gemini-3.7-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, "google-vertex:gemini-3.8-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, - "google-vertex:gemini-flash-latest": { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, - "google-vertex:gemini-flash-lite-latest": { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, + "google-vertex:gemini-4-argon": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 0 }, "google:deep-research-max-preview-04-2026": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, "google:deep-research-preview-04-2026": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, "google:gemini-2.5-computer-use-preview-10-2025": { input: 1.25, output: 10, cacheRead: 0, cacheWrite: 0 }, @@ -473,15 +474,17 @@ export const PRICES: Record = { "google:gemini-3.6-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, "google:gemini-3.7-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, "google:gemini-3.8-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, + "google:gemini-4-argon": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 0 }, "google:gemini-flash-latest": { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, "google:gemini-flash-lite-latest": { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, + "google:gemini-pro-latest": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, "google:gemma-4-26b-a4b-it": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "google:gemma-4-31b-it": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "groq:llama-3.1-8b-instant": { input: 0.05, output: 0.08, cacheRead: 0, cacheWrite: 0 }, "groq:llama-3.3-70b-versatile": { input: 0.59, output: 0.79, cacheRead: 0, cacheWrite: 0 }, "groq:openai/gpt-oss-120b": { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, "groq:openai/gpt-oss-20b": { input: 0.075, output: 0.3, cacheRead: 0.0375, cacheWrite: 0 }, - "groq:openai/gpt-oss-safeguard-20b": { input: 0.075, output: 0.3, cacheRead: 0, cacheWrite: 0 }, + "groq:openai/gpt-oss-safeguard-20b": { input: 0.075, output: 0.3, cacheRead: 0.0375, cacheWrite: 0 }, "groq:qwen/qwen3.6-27b": { input: 0.6, output: 3, cacheRead: 0.3, cacheWrite: 0 }, "groq:qwen/qwen3.8-27b": { input: 0.8, output: 4, cacheRead: 0, cacheWrite: 0 }, "huggingface:deepseek-ai/DeepSeek-R1": { input: 0.7, output: 2.5, cacheRead: 0, cacheWrite: 0 }, @@ -496,6 +499,7 @@ export const PRICES: Record = { "huggingface:deepseek-ai/DeepSeek-V4-Pro": { input: 0.435, output: 0.87, cacheRead: 0.003625, cacheWrite: 0 }, "huggingface:deepseek-ai/DeepSeek-V4-Pro-0813": { input: 1.32, output: 3.96, cacheRead: 0, cacheWrite: 0 }, "huggingface:deepseek-ai/DeepSeek-V4.1-Flash": { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 }, + "huggingface:deepseek-ai/DeepSeek-V4.1-Flash-1017": { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 }, "huggingface:google/gemma-3-12b-it": { input: 0.05, output: 0.15, cacheRead: 0, cacheWrite: 0 }, "huggingface:google/gemma-3-27b-it": { input: 0.08, output: 0.16, cacheRead: 0, cacheWrite: 0 }, "huggingface:google/gemma-3-4b-it": { input: 0.05, output: 0.1, cacheRead: 0, cacheWrite: 0 }, @@ -503,6 +507,7 @@ export const PRICES: Record = { "huggingface:google/gemma-4-31B-it": { input: 0.14, output: 0.4, cacheRead: 0, cacheWrite: 0 }, "huggingface:meta-llama/Llama-3.1-8B-Instruct": { input: 0.06, output: 0.06, cacheRead: 0, cacheWrite: 0 }, "huggingface:meta-llama/Llama-3.3-70B-Instruct": { input: 0.59, output: 0.79, cacheRead: 0, cacheWrite: 0 }, + "huggingface:MiniMaxAI/MiniMax-M1-80k": { input: 0.55, output: 2.2, cacheRead: 0, cacheWrite: 0 }, "huggingface:MiniMaxAI/MiniMax-M2": { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 }, "huggingface:MiniMaxAI/MiniMax-M2.1": { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 }, "huggingface:MiniMaxAI/MiniMax-M2.5": { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0 }, @@ -523,6 +528,7 @@ export const PRICES: Record = { "huggingface:Qwen/Qwen3-235B-A22B-Thinking-2507": { input: 0.3, output: 3, cacheRead: 0, cacheWrite: 0 }, "huggingface:Qwen/Qwen3-30B-A3B": { input: 0.12, output: 0.5, cacheRead: 0, cacheWrite: 0 }, "huggingface:Qwen/Qwen3-32B": { input: 0.29, output: 0.59, cacheRead: 0, cacheWrite: 0 }, + "huggingface:Qwen/Qwen3-8B": { input: 0.07, output: 0.18, cacheRead: 0, cacheWrite: 0 }, "huggingface:Qwen/Qwen3-Coder-30B-A3B-Instruct": { input: 0.07, output: 0.26, cacheRead: 0, cacheWrite: 0 }, "huggingface:Qwen/Qwen3-Coder-480B-A35B-Instruct": { input: 2, output: 2, cacheRead: 0, cacheWrite: 0 }, "huggingface:Qwen/Qwen3-Coder-Next": { input: 0.2, output: 1.5, cacheRead: 0, cacheWrite: 0 }, @@ -530,6 +536,7 @@ export const PRICES: Record = { "huggingface:Qwen/Qwen3-Next-80B-A3B-Thinking": { input: 0.3, output: 2, cacheRead: 0, cacheWrite: 0 }, "huggingface:Qwen/Qwen3-VL-235B-A22B-Instruct": { input: 0.3, output: 1.5, cacheRead: 0, cacheWrite: 0 }, "huggingface:Qwen/Qwen3-VL-235B-A22B-Thinking": { input: 0.98, output: 3.95, cacheRead: 0, cacheWrite: 0 }, + "huggingface:Qwen/Qwen3-VL-30B-A3B-Instruct": { input: 0.2, output: 0.7, cacheRead: 0, cacheWrite: 0 }, "huggingface:Qwen/Qwen3.5-122B-A10B": { input: 0.4, output: 3.2, cacheRead: 0, cacheWrite: 0 }, "huggingface:Qwen/Qwen3.5-27B": { input: 0.3, output: 2.4, cacheRead: 0, cacheWrite: 0 }, "huggingface:Qwen/Qwen3.5-35B-A3B": { input: 0.25, output: 2, cacheRead: 0, cacheWrite: 0 }, @@ -569,12 +576,16 @@ export const PRICES: Record = { "meta:muse-spark-1.2-contributor": { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 }, "meta:muse-spark-1.3": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, "meta:muse-spark-1.3-contributor": { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 }, - "minimax-cn:MiniMax-M2.7": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0.375 }, - "minimax-cn:MiniMax-M2.7-highspeed": { input: 0.6, output: 2.4, cacheRead: 0.06, cacheWrite: 0.375 }, - "minimax-cn:MiniMax-M3": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, + "meta:muse-wonder-1.0": { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 0 }, + "minimax-cn:MiniMax-M2.7": { input: 0.3137, output: 1.2549, cacheRead: 0.0627, cacheWrite: 0.3922 }, + "minimax-cn:MiniMax-M2.7-highspeed": { input: 0.6275, output: 2.5098, cacheRead: 0.0627, cacheWrite: 0.3922 }, + "minimax-cn:MiniMax-M3": { input: 0.3137, output: 1.2549, cacheRead: 0.0627, cacheWrite: 0 }, + "minimax-cn:MiniMax-M3.1-Flash": { input: 0.1494, output: 0.5976, cacheRead: 0.0149, cacheWrite: 0 }, "minimax:MiniMax-M2.7": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0.375 }, "minimax:MiniMax-M2.7-highspeed": { input: 0.6, output: 2.4, cacheRead: 0.06, cacheWrite: 0.375 }, "minimax:MiniMax-M3": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, + "minimax:MiniMax-M3.1-Flash": { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, + "mistral:codestral-2508": { input: 0.3, output: 0.9, cacheRead: 0.03, cacheWrite: 0 }, "mistral:codestral-latest": { input: 0.3, output: 0.9, cacheRead: 0.03, cacheWrite: 0 }, "mistral:devstral-2512": { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, "mistral:devstral-latest": { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, @@ -582,12 +593,18 @@ export const PRICES: Record = { "mistral:devstral-medium-latest": { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, "mistral:devstral-small-2505": { input: 0.1, output: 0.3, cacheRead: 0.01, cacheWrite: 0 }, "mistral:devstral-small-2507": { input: 0.1, output: 0.3, cacheRead: 0.01, cacheWrite: 0 }, + "mistral:glm-5-2": { input: 1.4, output: 4.4, cacheRead: 0.14, cacheWrite: 0 }, "mistral:labs-devstral-small-2512": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "mistral:labs-leanstral-1-5-1": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "mistral:magistral-medium-latest": { input: 2, output: 5, cacheRead: 0.2, cacheWrite: 0 }, - "mistral:ministral-3b-latest": { input: 0.04, output: 0.04, cacheRead: 0.004, cacheWrite: 0 }, - "mistral:ministral-8b-latest": { input: 0.1, output: 0.1, cacheRead: 0.01, cacheWrite: 0 }, + "mistral:ministral-14b-2512": { input: 0.2, output: 0.2, cacheRead: 0.02, cacheWrite: 0 }, + "mistral:ministral-3b-2512": { input: 0.1, output: 0.1, cacheRead: 0.01, cacheWrite: 0 }, + "mistral:ministral-3b-latest": { input: 0.1, output: 0.1, cacheRead: 0.01, cacheWrite: 0 }, + "mistral:ministral-8b-2512": { input: 0.15, output: 0.15, cacheRead: 0.015, cacheWrite: 0 }, + "mistral:ministral-8b-latest": { input: 0.15, output: 0.15, cacheRead: 0.015, cacheWrite: 0 }, "mistral:mistral-large-2411": { input: 2, output: 6, cacheRead: 0.2, cacheWrite: 0 }, "mistral:mistral-large-2512": { input: 0.5, output: 1.5, cacheRead: 0.05, cacheWrite: 0 }, + "mistral:mistral-large-4": { input: 0.68, output: 2.09, cacheRead: 0.07, cacheWrite: 0 }, "mistral:mistral-large-latest": { input: 0.5, output: 1.5, cacheRead: 0.05, cacheWrite: 0 }, "mistral:mistral-medium-2505": { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, "mistral:mistral-medium-2508": { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, @@ -598,18 +615,16 @@ export const PRICES: Record = { "mistral:mistral-small-2506": { input: 0.1, output: 0.3, cacheRead: 0.01, cacheWrite: 0 }, "mistral:mistral-small-2603": { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, "mistral:mistral-small-latest": { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, - "mistral:open-mistral-7b": { input: 0.25, output: 0.25, cacheRead: 0.025, cacheWrite: 0 }, "mistral:open-mistral-nemo": { input: 0.15, output: 0.15, cacheRead: 0.015, cacheWrite: 0 }, - "mistral:open-mixtral-8x22b": { input: 2, output: 6, cacheRead: 0.2, cacheWrite: 0 }, - "mistral:open-mixtral-8x7b": { input: 0.7, output: 0.7, cacheRead: 0.07, cacheWrite: 0 }, "mistral:pixtral-12b": { input: 0.15, output: 0.15, cacheRead: 0.015, cacheWrite: 0 }, "mistral:pixtral-large-latest": { input: 2, output: 6, cacheRead: 0.2, cacheWrite: 0 }, - "mistral:voxtral-small-latest": { input: 0.1, output: 0.3, cacheRead: 0.01, cacheWrite: 0 }, + "mistral:voxtral-small-2507": { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, + "mistral:voxtral-small-latest": { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, "mistral:zai-glm-5-2": { input: 1.4, output: 4.4, cacheRead: 0.14, cacheWrite: 0 }, "mistral:zai-glm-5-3": { input: 1.4, output: 4.4, cacheRead: 0.14, cacheWrite: 0 }, - "moonshotai-cn:kimi-k2.6": { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, - "moonshotai-cn:kimi-k2.7-code": { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, - "moonshotai-cn:kimi-k2.7-code-highspeed": { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 0 }, + "moonshotai-cn:kimi-k2.6": { input: 0.9711, output: 4.0337, cacheRead: 0.1643, cacheWrite: 0 }, + "moonshotai-cn:kimi-k2.7-code": { input: 0.9711, output: 4.0337, cacheRead: 0.1942, cacheWrite: 0 }, + "moonshotai-cn:kimi-k2.7-code-highspeed": { input: 1.9421, output: 8.0673, cacheRead: 0.3884, cacheWrite: 0 }, "moonshotai-cn:kimi-k3": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, "moonshotai:kimi-k2.6": { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, "moonshotai:kimi-k2.7-code": { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, @@ -624,20 +639,18 @@ export const PRICES: Record = { "nvidia:meta/muse-glimmer-30b": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "nvidia:mistralai/mistral-7b-instruct-v0.3": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "nvidia:moonshotai/kimi-k2.6": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "nvidia:moonshotai/kimi-k3": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "nvidia:nvidia/cosmos-reason2-8b": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "nvidia:nvidia/llama-3.1-nemotron-70b-instruct": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "nvidia:nvidia/llama-3.1-nemotron-ultra-253b-v1": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "nvidia:nvidia/nemotron-3-nano-omni-30b-a3b-reasoning": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "nvidia:nvidia/nemotron-3-super-120b-a12b": { input: 0.2, output: 0.8, cacheRead: 0, cacheWrite: 0 }, - "nvidia:nvidia/nemotron-3-ultra-550b-a55b": { input: 0.5, output: 2.5, cacheRead: 0.15, cacheWrite: 0 }, + "nvidia:nvidia/nemotron-3-ultra-550b-a55b": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "nvidia:nvidia/nemotron-3.5-lightning-30b-a3b": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "nvidia:nvidia/nemotron-3.5-super-vl-120b-a12b": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "nvidia:openai/gpt-oss-20b": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "nvidia:poolside/laguna-xs-2.1": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "nvidia:stepfun-ai/step-5-preview": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "nvidia:z-ai/glm-5.3": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "nvidia:z-ai/glm-5.3-flash": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "openai-codex:gpt-5.3-codex-spark": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, - "openai-codex:gpt-5.5": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, "openai-codex:gpt-5.6-luna": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, "openai-codex:gpt-5.6-sol": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, "openai-codex:gpt-5.6-terra": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, @@ -662,9 +675,7 @@ export const PRICES: Record = { "openai:gpt-5-pro": { input: 15, output: 120, cacheRead: 0, cacheWrite: 0 }, "openai:gpt-5.1": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, "openai:gpt-5.2": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, - "openai:gpt-5.2-chat-latest": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, "openai:gpt-5.2-pro": { input: 21, output: 168, cacheRead: 0, cacheWrite: 0 }, - "openai:gpt-5.3-chat-latest": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, "openai:gpt-5.3-codex": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, "openai:gpt-5.3-codex-spark": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, "openai:gpt-5.4": { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, @@ -689,16 +700,16 @@ export const PRICES: Record = { "openai:o3-mini": { input: 1.1, output: 4.4, cacheRead: 0.55, cacheWrite: 0 }, "openai:o3-pro": { input: 20, output: 80, cacheRead: 0, cacheWrite: 0 }, "openai:o4-mini": { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, - "opencode-go:deepseek-v4-flash": { input: 0.15, output: 0.6, cacheRead: 0.003, cacheWrite: 0 }, - "opencode-go:deepseek-v4-flash-vision-exp": { input: 0.15, output: 0.6, cacheRead: 0.003, cacheWrite: 0 }, + "opencode-go:beam-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "opencode-go:claude-haiku-5-5": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "opencode-go:deepseek-v4-pro": { input: 0.66, output: 1.98, cacheRead: 0.022, cacheWrite: 0 }, "opencode-go:deepseek-v4.1-flash": { input: 0.15, output: 0.6, cacheRead: 0.003, cacheWrite: 0 }, + "opencode-go:gemini-4-argon-contributor": { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 0 }, "opencode-go:glm-5.2": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, "opencode-go:glm-5.3": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, "opencode-go:glm-5.3-flash": { input: 0.15, output: 0.5, cacheRead: 0.03, cacheWrite: 0 }, "opencode-go:gpt-5.6-luna": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, "opencode-go:gpt-6-luna": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, - "opencode-go:grok-4.6": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "opencode-go:grok-4.7": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "opencode-go:hy3": { input: 0.14, output: 0.58, cacheRead: 0.035, cacheWrite: 0 }, "opencode-go:hy4-preview": { input: 0.834, output: 2.501, cacheRead: 0.042, cacheWrite: 0 }, @@ -710,34 +721,35 @@ export const PRICES: Record = { "opencode-go:mimo-v2.5-pro": { input: 0.435, output: 0.87, cacheRead: 0.003625, cacheWrite: 0 }, "opencode-go:mimo-v2.6-flash": { input: 0.14, output: 0.28, cacheRead: 0.0028, cacheWrite: 0 }, "opencode-go:mimo-v2.6-pro": { input: 0.435, output: 0.87, cacheRead: 0.003625, cacheWrite: 0 }, - "opencode-go:minimax-m2.7": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0.375 }, "opencode-go:minimax-m3": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, + "opencode-go:minimax-m3.1-flash-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "opencode-go:muse-spark-1.2-contributor": { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 }, "opencode-go:muse-spark-1.3-contributor": { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 }, "opencode-go:qwen3.7-plus": { input: 0.4, output: 1.6, cacheRead: 0.04, cacheWrite: 0.5 }, "opencode-go:qwen3.8-flash": { input: 0.15, output: 0.47, cacheRead: 0.016, cacheWrite: 0.2 }, "opencode-go:qwen3.8-max": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 2.5 }, - "opencode-go:space-bunny-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "opencode-go:step-5-preview": { input: 1, output: 2.7, cacheRead: 0.1, cacheWrite: 0 }, + "opencode:beam-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "opencode:big-pickle": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "opencode:claude-fable-5": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "opencode:claude-fable-5-1": { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 }, "opencode:claude-haiku-4-5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, + "opencode:claude-haiku-5-5": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "opencode:claude-opus-4-5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "opencode:claude-opus-4-6": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "opencode:claude-opus-4-7": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "opencode:claude-opus-4-8": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "opencode:claude-opus-5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "opencode:claude-opus-5-5": { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 5 }, - "opencode:claude-sonnet-4": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "opencode:claude-sonnet-4-5": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "opencode:claude-sonnet-4-6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "opencode:claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, "opencode:claude-sonnet-5-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, "opencode:deepseek-v4-flash": { input: 0.14, output: 0.28, cacheRead: 0.028, cacheWrite: 0 }, - "opencode:deepseek-v4-flash-vision-exp": { input: 0.14, output: 0.28, cacheRead: 0.028, cacheWrite: 0 }, - "opencode:deepseek-v4-pro": { input: 1.74, output: 3.84, cacheRead: 0.145, cacheWrite: 0 }, + "opencode:deepseek-v4-pro": { input: 1.74, output: 3.48, cacheRead: 0.145, cacheWrite: 0 }, "opencode:deepseek-v4.1-flash": { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 }, - "opencode:fledge-alpha-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "opencode:deepseek-v4.1-flash-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "opencode:flint-40b-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "opencode:gemini-3-flash": { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 }, "opencode:gemini-3.1-pro": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, "opencode:gemini-3.5-flash": { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, @@ -745,11 +757,13 @@ export const PRICES: Record = { "opencode:gemini-3.6-flash": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, "opencode:gemini-3.7-flash": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, "opencode:gemini-3.8-flash": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, + "opencode:gemini-4-argon": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 0 }, "opencode:glm-5": { input: 1, output: 3.2, cacheRead: 0.2, cacheWrite: 0 }, "opencode:glm-5.1": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, "opencode:glm-5.2": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, "opencode:glm-5.3": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, "opencode:glm-5.3-flash": { input: 0.15, output: 0.5, cacheRead: 0.03, cacheWrite: 0 }, + "opencode:glm-5.3-flash-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "opencode:gpt-5": { input: 1.07, output: 8.5, cacheRead: 0.107, cacheWrite: 0 }, "opencode:gpt-5-codex": { input: 1.07, output: 8.5, cacheRead: 0.107, cacheWrite: 0 }, "opencode:gpt-5-nano": { input: 0.05, output: 0.4, cacheRead: 0.005, cacheWrite: 0 }, @@ -768,7 +782,7 @@ export const PRICES: Record = { "opencode:gpt-5.5-pro": { input: 30, output: 180, cacheRead: 30, cacheWrite: 0 }, "opencode:gpt-5.6-luna": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, "opencode:gpt-5.6-sol": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, - "opencode:gpt-5.6-terra": { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 3.125 }, + "opencode:gpt-5.6-terra": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, "opencode:gpt-6-astra": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "opencode:gpt-6-luna": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "opencode:gpt-6-sol": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, @@ -777,45 +791,46 @@ export const PRICES: Record = { "opencode:grok-4.6": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "opencode:grok-4.7": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "opencode:grok-build-0.1": { input: 1, output: 2, cacheRead: 0.2, cacheWrite: 0 }, - "opencode:kimi-k2.5": { input: 0.6, output: 3, cacheRead: 0.08, cacheWrite: 0 }, + "opencode:kimi-k2.5": { input: 0.6, output: 3, cacheRead: 0.1, cacheWrite: 0 }, "opencode:kimi-k2.6": { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, "opencode:kimi-k2.7-code": { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, "opencode:kimi-k3": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, - "opencode:ling-3.0-flash-fin-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "opencode:ling-3.1-flash-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "opencode:longcat-2.5-preview-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "opencode:mimo-v2.6-flash-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "opencode:minimax-m2.5": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, "opencode:minimax-m2.7": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, "opencode:minimax-m3": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, + "opencode:minimax-m3.1-flash-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "opencode:mistral-large-4": { input: 0.68, output: 2.09, cacheRead: 0.07, cacheWrite: 0 }, "opencode:muse-spark-1.2": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, "opencode:muse-spark-1.3": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, - "opencode:muse-spark-1.3-contributor-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "opencode:muse-wonder-1.0": { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 0 }, "opencode:nemotron-3-ultra-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "opencode:nemotron-3.5-lightning-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "opencode:nemotron-3.5-super-vl-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "opencode:qwen3.5-plus": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, "opencode:qwen3.6-plus": { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0.625 }, "opencode:qwen3.8-flash": { input: 0.15, output: 0.47, cacheRead: 0.016, cacheWrite: 0.2 }, "opencode:qwen3.8-max": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 2.5 }, - "opencode:space-bunny-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:~anthropic/claude-fable-latest": { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 }, - "openrouter:~anthropic/claude-haiku-latest": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, + "openrouter:~anthropic/claude-haiku-latest": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "openrouter:~anthropic/claude-opus-latest": { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 5 }, - "openrouter:~anthropic/claude-sonnet-latest": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, - "openrouter:~deepseek/deepseek-flash-latest": { input: 0.003, output: 2.4, cacheRead: 0.003, cacheWrite: 0 }, - "openrouter:~deepseek/deepseek-pro-latest": { input: 0.176, output: 4.2, cacheRead: 0.16, cacheWrite: 0 }, - "openrouter:~deepseek/deepseek-v4-flash-latest": { input: 0.0152, output: 1.28, cacheRead: 0.0137, cacheWrite: 0 }, + "openrouter:~anthropic/claude-sonnet-latest": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, + "openrouter:~deepseek/deepseek-flash-latest": { input: 0.07, output: 0.5, cacheRead: 0.008, cacheWrite: 0 }, + "openrouter:~deepseek/deepseek-pro-latest": { input: 0.1307, output: 8, cacheRead: 0.13, cacheWrite: 0 }, + "openrouter:~deepseek/deepseek-v4-flash-latest": { input: 0.0422, output: 0.1729, cacheRead: 0.0275, cacheWrite: 0 }, "openrouter:~google/gemini-flash-latest": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0.041667 }, - "openrouter:~google/gemini-pro-latest": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0.375 }, - "openrouter:~moonshotai/kimi-latest": { input: 0.3992, output: 13, cacheRead: 0.3, cacheWrite: 0 }, + "openrouter:~google/gemini-pro-latest": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 0.1875 }, + "openrouter:~moonshotai/kimi-latest": { input: 0.238, output: 16, cacheRead: 0.228, cacheWrite: 0 }, "openrouter:~openai/gpt-astra-latest": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "openrouter:~openai/gpt-luna-latest": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "openrouter:~openai/gpt-mini-latest": { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, "openrouter:~openai/gpt-sol-latest": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, "openrouter:~openai/gpt-terra-latest": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, + "openrouter:~unbiased/pareto-latest": { input: 0.8, output: 3.2, cacheRead: 0.03, cacheWrite: 0 }, "openrouter:~x-ai/grok-latest": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, - "openrouter:~z-ai/glm-flash-latest": { input: 0.024, output: 0.5, cacheRead: 0.0216, cacheWrite: 0 }, - "openrouter:~z-ai/glm-latest": { input: 0.075, output: 4.4, cacheRead: 0.065, cacheWrite: 0 }, + "openrouter:~z-ai/glm-flash-latest": { input: 0.0413, output: 0.0773, cacheRead: 0.03, cacheWrite: 0 }, + "openrouter:~z-ai/glm-latest": { input: 0.079, output: 1.4, cacheRead: 0.078, cacheWrite: 0 }, "openrouter:aion-labs/aion-2.0": { input: 0.8, output: 1.6, cacheRead: 0.2, cacheWrite: 0 }, "openrouter:aion-labs/aion-3.0": { input: 3, output: 6, cacheRead: 0.75, cacheWrite: 0 }, "openrouter:aion-labs/aion-3.0-mini": { input: 0.7, output: 1.4, cacheRead: 0.18, cacheWrite: 0 }, @@ -832,6 +847,8 @@ export const PRICES: Record = { "openrouter:anthropic/claude-fable-5.1:batch": { input: 5, output: 25, cacheRead: 0.125, cacheWrite: 6.25 }, "openrouter:anthropic/claude-haiku-4.5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, "openrouter:anthropic/claude-haiku-4.5:batch": { input: 0.5, output: 2.5, cacheRead: 0.05, cacheWrite: 0.625 }, + "openrouter:anthropic/claude-haiku-5.5": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, + "openrouter:anthropic/claude-haiku-5.5:batch": { input: 0.05, output: 0.25, cacheRead: 0.005, cacheWrite: 0.0625 }, "openrouter:anthropic/claude-opus-4.1": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }, "openrouter:anthropic/claude-opus-4.1:batch": { input: 7.5, output: 37.5, cacheRead: 0.75, cacheWrite: 9.375 }, "openrouter:anthropic/claude-opus-4.5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, @@ -846,16 +863,14 @@ export const PRICES: Record = { "openrouter:anthropic/claude-opus-5:batch": { input: 2.5, output: 12.5, cacheRead: 0.25, cacheWrite: 3.125 }, "openrouter:anthropic/claude-opus-5.5": { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 5 }, "openrouter:anthropic/claude-opus-5.5:batch": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, - "openrouter:anthropic/claude-sonnet-4": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "openrouter:anthropic/claude-sonnet-4.5": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "openrouter:anthropic/claude-sonnet-4.5:batch": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 1.875 }, "openrouter:anthropic/claude-sonnet-4.6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "openrouter:anthropic/claude-sonnet-4.6:batch": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 1.875 }, "openrouter:anthropic/claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, "openrouter:anthropic/claude-sonnet-5:batch": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, - "openrouter:anthropic/claude-sonnet-5.5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, - "openrouter:anthropic/claude-sonnet-5.5:batch": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, - "openrouter:apodex/apodex-1.1-mini:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "openrouter:anthropic/claude-sonnet-5.5": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, + "openrouter:anthropic/claude-sonnet-5.5:batch": { input: 1, output: 5, cacheRead: 0.05, cacheWrite: 1.25 }, "openrouter:arcee-ai/trinity-large-thinking": { input: 0.25, output: 0.8, cacheRead: 0.06, cacheWrite: 0 }, "openrouter:auto": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:bytedance-seed/seed-1.6": { input: 0.25, output: 2, cacheRead: 0, cacheWrite: 0 }, @@ -869,29 +884,27 @@ export const PRICES: Record = { "openrouter:cohere/command-r-plus-08-2024": { input: 2.5, output: 10, cacheRead: 0, cacheWrite: 0 }, "openrouter:cohere/north-mini-code:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:deepseek/deepseek-chat": { input: 0.2574, output: 1.0287, cacheRead: 0, cacheWrite: 0 }, - "openrouter:deepseek/deepseek-chat-v3-0324": { input: 0.25, output: 1, cacheRead: 0, cacheWrite: 0 }, + "openrouter:deepseek/deepseek-chat-v3-0324": { input: 0.29, output: 1.14, cacheRead: 0.11, cacheWrite: 0 }, "openrouter:deepseek/deepseek-chat-v3.1": { input: 0.25, output: 0.95, cacheRead: 0.13, cacheWrite: 0 }, - "openrouter:deepseek/deepseek-r1": { input: 0.7, output: 2.5, cacheRead: 0, cacheWrite: 0 }, "openrouter:deepseek/deepseek-r1-0528": { input: 0.5, output: 2.15, cacheRead: 0.35, cacheWrite: 0 }, "openrouter:deepseek/deepseek-v3.1-terminus": { input: 0.27, output: 1, cacheRead: 0, cacheWrite: 0 }, "openrouter:deepseek/deepseek-v3.2": { input: 0.28, output: 0.42, cacheRead: 0.028, cacheWrite: 0 }, "openrouter:deepseek/deepseek-v3.2-exp": { input: 0.27, output: 0.41, cacheRead: 0, cacheWrite: 0 }, - "openrouter:deepseek/deepseek-v4-flash": { input: 0.028, output: 0.056, cacheRead: 0.0056, cacheWrite: 0 }, - "openrouter:deepseek/deepseek-v4-flash-0731": { input: 0.0152, output: 1.28, cacheRead: 0.0137, cacheWrite: 0 }, + "openrouter:deepseek/deepseek-v4-flash": { input: 0.091, output: 0.182, cacheRead: 0.0182, cacheWrite: 0 }, + "openrouter:deepseek/deepseek-v4-flash-0731": { input: 0.04444, output: 0.13332, cacheRead: 0.001414, cacheWrite: 0 }, "openrouter:deepseek/deepseek-v4-flash-vision-exp": { input: 0.2156, output: 0.6468, cacheRead: 0.00686, cacheWrite: 0 }, - "openrouter:deepseek/deepseek-v4-pro": { input: 0.2088, output: 0.4176, cacheRead: 0.0174, cacheWrite: 0 }, - "openrouter:deepseek/deepseek-v4-pro-0813": { input: 0.22, output: 4.2, cacheRead: 0.17, cacheWrite: 0 }, - "openrouter:deepseek/deepseek-v4.1-flash": { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 }, - "openrouter:deepseek/deepseek-v4.1-flash:batch": { input: 0.112, output: 0.336, cacheRead: 0.00336, cacheWrite: 0 }, + "openrouter:deepseek/deepseek-v4-pro": { input: 0.388716, output: 0.777432, cacheRead: 0.032393, cacheWrite: 0 }, + "openrouter:deepseek/deepseek-v4-pro-0813": { input: 0.66, output: 1.98, cacheRead: 0.022, cacheWrite: 0 }, + "openrouter:deepseek/deepseek-v4.1-flash": { input: 0.0342, output: 0.1368, cacheRead: 0.000684, cacheWrite: 0 }, + "openrouter:deepseek/deepseek-v4.1-flash-1017": { input: 0.15, output: 0.6, cacheRead: 0.003, cacheWrite: 0 }, + "openrouter:deepseek/deepseek-v4.1-flash:batch": { input: 0.05, output: 0.15, cacheRead: 0.004, cacheWrite: 0 }, "openrouter:dots-studio/dots-3-note-preview:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "openrouter:elorian/glimpse": { input: 0.6, output: 3, cacheRead: 0.06, cacheWrite: 0 }, "openrouter:fireworks/ember-1": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, "openrouter:google/gemini-2.5-flash": { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0.083333 }, "openrouter:google/gemini-2.5-flash-lite": { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0.083333 }, - "openrouter:google/gemini-2.5-flash-lite:batch": { input: 0.05, output: 0.2, cacheRead: 0.01, cacheWrite: 0 }, - "openrouter:google/gemini-2.5-flash:batch": { input: 0.15, output: 1.25, cacheRead: 0.03, cacheWrite: 0 }, "openrouter:google/gemini-2.5-pro": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0.375 }, "openrouter:google/gemini-2.5-pro-preview": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0.375 }, - "openrouter:google/gemini-2.5-pro:batch": { input: 0.625, output: 5, cacheRead: 0.125, cacheWrite: 0 }, "openrouter:google/gemini-3-flash-preview": { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0.083333 }, "openrouter:google/gemini-3-flash-preview:batch": { input: 0.25, output: 1.5, cacheRead: 0, cacheWrite: 0 }, "openrouter:google/gemini-3-pro-image": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0.375 }, @@ -909,42 +922,47 @@ export const PRICES: Record = { "openrouter:google/gemini-3.6-flash:batch": { input: 0.375, output: 1.875, cacheRead: 0.0375, cacheWrite: 0.041667 }, "openrouter:google/gemini-3.7-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0.041667 }, "openrouter:google/gemini-3.7-flash:batch": { input: 0.375, output: 1.875, cacheRead: 0.0375, cacheWrite: 0.041667 }, - "openrouter:google/gemini-3.8-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0.041667 }, + "openrouter:google/gemini-3.8-flash": { input: 0.825, output: 4.125, cacheRead: 0.0825, cacheWrite: 0.041667 }, "openrouter:google/gemini-3.8-flash:batch": { input: 0.375, output: 1.875, cacheRead: 0.0375, cacheWrite: 0.041667 }, + "openrouter:google/gemini-4-argon": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 0.1875 }, + "openrouter:google/gemini-4-argon:batch": { input: 1, output: 5, cacheRead: 0.05, cacheWrite: 0.1875 }, + "openrouter:google/gemini-nano-banana-2.1": { input: 1.5, output: 7.5, cacheRead: 0, cacheWrite: 0 }, "openrouter:google/gemma-3-12b-it": { input: 0.05, output: 0.15, cacheRead: 0, cacheWrite: 0 }, - "openrouter:google/gemma-3-27b-it": { input: 0.08, output: 0.45, cacheRead: 0.04, cacheWrite: 0 }, - "openrouter:google/gemma-4-26b-a4b-it": { input: 0.0675, output: 0.225, cacheRead: 0.0375, cacheWrite: 0 }, + "openrouter:google/gemma-3-27b-it": { input: 0.08, output: 0.35, cacheRead: 0.04, cacheWrite: 0 }, + "openrouter:google/gemma-4-26b-a4b-it": { input: 0.0765, output: 0.255, cacheRead: 0.0425, cacheWrite: 0 }, "openrouter:google/gemma-4-26b-a4b-it:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "openrouter:google/gemma-4-31b-it": { input: 0.09, output: 0.34, cacheRead: 0.05, cacheWrite: 0 }, + "openrouter:google/gemma-4-31b-it": { input: 0.2, output: 0.4, cacheRead: 0, cacheWrite: 0 }, "openrouter:google/gemma-4-31b-it:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:ibm-granite/granite-4.2-8b": { input: 0.06, output: 0.25, cacheRead: 0.015, cacheWrite: 0 }, "openrouter:inception/mercury-2": { input: 0.25, output: 0.75, cacheRead: 0.025, cacheWrite: 0 }, "openrouter:inception/mercury-2.5": { input: 0.04, output: 0.15, cacheRead: 0.004, cacheWrite: 0 }, + "openrouter:inception/mercury-3": { input: 0.1, output: 0.35, cacheRead: 0.01, cacheWrite: 0 }, "openrouter:inclusionai/ling-3.0-flash": { input: 0.021, output: 0.063, cacheRead: 0.0042, cacheWrite: 0 }, - "openrouter:inclusionai/ling-3.0-flash-fin": { input: 0.042, output: 0.1232, cacheRead: 0.0084, cacheWrite: 0 }, - "openrouter:inclusionai/ling-3.0-flash-sante:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "openrouter:inclusionai/ling-3.0-flash-vl": { input: 0.021, output: 0.0616, cacheRead: 0.0042, cacheWrite: 0 }, - "openrouter:inclusionai/ling-3.1-flash": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "openrouter:kwaipilot/kat-coder-pro-v2.5": { input: 0.74, output: 2.96, cacheRead: 0.15, cacheWrite: 0 }, + "openrouter:inclusionai/ling-3.0-flash-vl": { input: 0.06, output: 0.18, cacheRead: 0.012, cacheWrite: 0 }, + "openrouter:inclusionai/ling-3.1-flash": { input: 0.075, output: 0.225, cacheRead: 0.015, cacheWrite: 0 }, "openrouter:liquid/lfm-2.5-2.6b:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "openrouter:liquid/lfm-2.5-24b-a2b": { input: 0.05, output: 0.7, cacheRead: 0.025, cacheWrite: 0 }, "openrouter:meituan/longcat-2.0": { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 }, "openrouter:meta-llama/llama-3.1-70b-instruct": { input: 0.4, output: 0.4, cacheRead: 0, cacheWrite: 0 }, "openrouter:meta-llama/llama-3.1-8b-instruct": { input: 0.05, output: 0.08, cacheRead: 0.025, cacheWrite: 0 }, - "openrouter:meta-llama/llama-3.3-70b-instruct": { input: 0.22, output: 0.5, cacheRead: 0.11, cacheWrite: 0 }, - "openrouter:meta-llama/llama-4-maverick": { input: 0.1875, output: 0.6525, cacheRead: 0, cacheWrite: 0 }, + "openrouter:meta-llama/llama-3.3-70b-instruct": { input: 0.1, output: 0.32, cacheRead: 0, cacheWrite: 0 }, + "openrouter:meta-llama/llama-4-maverick": { input: 0.1875, output: 0.6525, cacheRead: 0.05, cacheWrite: 0 }, "openrouter:meta-llama/llama-4-scout": { input: 0.1, output: 0.3, cacheRead: 0, cacheWrite: 0 }, - "openrouter:meta/muse-glimmer-30b": { input: 0.35, output: 1.5, cacheRead: 0.04, cacheWrite: 0 }, + "openrouter:meta/muse-glimmer-30b": { input: 0.3, output: 1.2, cacheRead: 0.04, cacheWrite: 0 }, "openrouter:meta/muse-spark-1.1": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, "openrouter:meta/muse-spark-1.2": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, "openrouter:meta/muse-spark-1.2-contributor": { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 }, "openrouter:meta/muse-spark-1.3": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, "openrouter:meta/muse-spark-1.3-contributor": { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 }, + "openrouter:meta/muse-spark-open": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, + "openrouter:meta/muse-wonder": { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 0 }, "openrouter:minimax/minimax-m1": { input: 0.55, output: 2.2, cacheRead: 0, cacheWrite: 0 }, - "openrouter:minimax/minimax-m2": { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 }, + "openrouter:minimax/minimax-m2": { input: 0.255, output: 1.02, cacheRead: 0, cacheWrite: 0 }, "openrouter:minimax/minimax-m2.1": { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0 }, - "openrouter:minimax/minimax-m2.5": { input: 0.27, output: 1.08, cacheRead: 0.027, cacheWrite: 0 }, - "openrouter:minimax/minimax-m2.7": { input: 0.21, output: 0.84, cacheRead: 0.042, cacheWrite: 0 }, + "openrouter:minimax/minimax-m2.5": { input: 0.27, output: 0.95, cacheRead: 0.03, cacheWrite: 0 }, + "openrouter:minimax/minimax-m2.7": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, "openrouter:minimax/minimax-m3": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, + "openrouter:minimax/minimax-m3.1-flash:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:mistralai/codestral-2508": { input: 0.3, output: 0.9, cacheRead: 0.03, cacheWrite: 0 }, "openrouter:mistralai/codestral-2508:batch": { input: 0.15, output: 0.45, cacheRead: 0.015, cacheWrite: 0 }, "openrouter:mistralai/devstral-2512": { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, @@ -956,12 +974,13 @@ export const PRICES: Record = { "openrouter:mistralai/mistral-large-2407": { input: 2, output: 6, cacheRead: 0.2, cacheWrite: 0 }, "openrouter:mistralai/mistral-large-2512": { input: 0.5, output: 1.5, cacheRead: 0.05, cacheWrite: 0 }, "openrouter:mistralai/mistral-large-2512:batch": { input: 0.25, output: 0.75, cacheRead: 0.025, cacheWrite: 0 }, + "openrouter:mistralai/mistral-large-4-0": { input: 1.36, output: 4.18, cacheRead: 0.14, cacheWrite: 0 }, "openrouter:mistralai/mistral-medium-3": { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, "openrouter:mistralai/mistral-medium-3-5": { input: 1.5, output: 7.5, cacheRead: 0, cacheWrite: 0 }, "openrouter:mistralai/mistral-medium-3-5:batch": { input: 0.75, output: 3.75, cacheRead: 0, cacheWrite: 0 }, "openrouter:mistralai/mistral-medium-3.1": { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, "openrouter:mistralai/mistral-medium-3.1:batch": { input: 0.2, output: 1, cacheRead: 0.02, cacheWrite: 0 }, - "openrouter:mistralai/mistral-nemo": { input: 0.019, output: 0.03, cacheRead: 0, cacheWrite: 0 }, + "openrouter:mistralai/mistral-nemo": { input: 0.029, output: 0.03, cacheRead: 0, cacheWrite: 0 }, "openrouter:mistralai/mistral-saba": { input: 0.2, output: 0.6, cacheRead: 0.02, cacheWrite: 0 }, "openrouter:mistralai/mistral-small-2603": { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, "openrouter:mistralai/mistral-small-2603:batch": { input: 0.075, output: 0.3, cacheRead: 0.0075, cacheWrite: 0 }, @@ -971,21 +990,23 @@ export const PRICES: Record = { "openrouter:mistralai/voxtral-small-24b-2507": { input: 0.1, output: 0.3, cacheRead: 0.01, cacheWrite: 0 }, "openrouter:moonshotai/kimi-k2": { input: 0.57, output: 2.3, cacheRead: 0, cacheWrite: 0 }, "openrouter:moonshotai/kimi-k2-0905": { input: 0.6, output: 2.5, cacheRead: 0, cacheWrite: 0 }, - "openrouter:moonshotai/kimi-k2-thinking": { input: 0.6, output: 2.5, cacheRead: 0, cacheWrite: 0 }, + "openrouter:moonshotai/kimi-k2-thinking": { input: 0.6, output: 2.5, cacheRead: 0.15, cacheWrite: 0 }, "openrouter:moonshotai/kimi-k2.5": { input: 0.41, output: 2.06, cacheRead: 0.07, cacheWrite: 0 }, - "openrouter:moonshotai/kimi-k2.6": { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, + "openrouter:moonshotai/kimi-k2.6": { input: 0.65, output: 3.41, cacheRead: 0.15, cacheWrite: 0 }, "openrouter:moonshotai/kimi-k2.7-code": { input: 0.6712, output: 3.35, cacheRead: 0.18, cacheWrite: 0 }, - "openrouter:moonshotai/kimi-k3": { input: 0.499, output: 13, cacheRead: 0.49, cacheWrite: 0 }, + "openrouter:moonshotai/kimi-k3": { input: 0.239, output: 11.936, cacheRead: 0.21, cacheWrite: 0 }, "openrouter:moonshotai/kimi-k3:batch": { input: 2.28, output: 11.4, cacheRead: 0.228, cacheWrite: 0 }, "openrouter:nex-agi/nex-n2.5-pro": { input: 0.075, output: 0.25, cacheRead: 0.015, cacheWrite: 0 }, - "openrouter:nvidia/nemotron-3-nano-30b-a3b": { input: 0.05, output: 0.2, cacheRead: 0.03, cacheWrite: 0 }, + "openrouter:nvidia/nemotron-3-nano-30b-a3b": { input: 0.06, output: 0.24, cacheRead: 0, cacheWrite: 0 }, "openrouter:nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "openrouter:nvidia/nemotron-3-super-120b-a12b": { input: 0.08, output: 0.45, cacheRead: 0, cacheWrite: 0 }, + "openrouter:nvidia/nemotron-3-super-120b-a12b": { input: 0.3, output: 2.4, cacheRead: 0.15, cacheWrite: 0 }, "openrouter:nvidia/nemotron-3-super-120b-a12b:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "openrouter:nvidia/nemotron-3-ultra-550b-a55b": { input: 0.5, output: 2.2, cacheRead: 0.1, cacheWrite: 0 }, + "openrouter:nvidia/nemotron-3-ultra-550b-a55b": { input: 0.6, output: 2.4, cacheRead: 0.12, cacheWrite: 0 }, "openrouter:nvidia/nemotron-3-ultra-550b-a55b:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "openrouter:nvidia/nemotron-3.5-lightning": { input: 0.0595, output: 0.17, cacheRead: 0.02975, cacheWrite: 0 }, + "openrouter:nvidia/nemotron-3.5-lightning": { input: 0.07, output: 0.2, cacheRead: 0.04, cacheWrite: 0 }, "openrouter:nvidia/nemotron-3.5-lightning:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "openrouter:nvidia/nemotron-3.5-super-vl": { input: 0.15, output: 0.5, cacheRead: 0.02, cacheWrite: 0 }, + "openrouter:nvidia/nemotron-3.5-super-vl:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:openai/gpt-3.5-turbo": { input: 0.5, output: 1.5, cacheRead: 0, cacheWrite: 0 }, "openrouter:openai/gpt-3.5-turbo-0613": { input: 1, output: 2, cacheRead: 0, cacheWrite: 0 }, "openrouter:openai/gpt-3.5-turbo-16k": { input: 3, output: 4, cacheRead: 0, cacheWrite: 0 }, @@ -1043,10 +1064,10 @@ export const PRICES: Record = { "openrouter:openai/gpt-5.6-luna-pro": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, "openrouter:openai/gpt-5.6-luna-pro:batch": { input: 0.1, output: 0.6, cacheRead: 0.01, cacheWrite: 0 }, "openrouter:openai/gpt-5.6-luna:batch": { input: 0.1, output: 0.6, cacheRead: 0.01, cacheWrite: 0 }, - "openrouter:openai/gpt-5.6-sol": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, + "openrouter:openai/gpt-5.6-sol": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, "openrouter:openai/gpt-5.6-sol-pro": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, - "openrouter:openai/gpt-5.6-sol-pro:batch": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, - "openrouter:openai/gpt-5.6-sol:batch": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, + "openrouter:openai/gpt-5.6-sol-pro:batch": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, + "openrouter:openai/gpt-5.6-sol:batch": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, "openrouter:openai/gpt-5.6-terra": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, "openrouter:openai/gpt-5.6-terra-pro": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, "openrouter:openai/gpt-5.6-terra-pro:batch": { input: 1, output: 6, cacheRead: 0.1, cacheWrite: 0 }, @@ -1065,10 +1086,12 @@ export const PRICES: Record = { "openrouter:openai/gpt-6-sol:batch": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, "openrouter:openai/gpt-6.1-sol": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, "openrouter:openai/gpt-6.1-sol-pro": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, + "openrouter:openai/gpt-6.1-sol-pro:batch": { input: 1, output: 5, cacheRead: 0.05, cacheWrite: 1.25 }, + "openrouter:openai/gpt-6.1-sol:batch": { input: 1, output: 5, cacheRead: 0.05, cacheWrite: 1.25 }, "openrouter:openai/gpt-audio": { input: 2.5, output: 10, cacheRead: 0, cacheWrite: 0 }, "openrouter:openai/gpt-audio-mini": { input: 0.6, output: 2.4, cacheRead: 0, cacheWrite: 0 }, "openrouter:openai/gpt-chat-latest": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, - "openrouter:openai/gpt-oss-120b": { input: 0.037, output: 0.17, cacheRead: 0, cacheWrite: 0 }, + "openrouter:openai/gpt-oss-120b": { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, "openrouter:openai/gpt-oss-120b:batch": { input: 0.0296, output: 0.136, cacheRead: 0, cacheWrite: 0 }, "openrouter:openai/gpt-oss-20b": { input: 0.018, output: 0.09, cacheRead: 0.009, cacheWrite: 0 }, "openrouter:openai/gpt-oss-20b:batch": { input: 0.024, output: 0.112, cacheRead: 0, cacheWrite: 0 }, @@ -1083,10 +1106,11 @@ export const PRICES: Record = { "openrouter:openai/o4-mini": { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, "openrouter:openai/o4-mini-high": { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, "openrouter:openai/o4-mini:batch": { input: 0.55, output: 2.2, cacheRead: 0.1375, cacheWrite: 0 }, - "openrouter:openrouter/auto": { input: -1000000, output: -1000000, cacheRead: 0, cacheWrite: 0 }, - "openrouter:openrouter/auto-beta": { input: -1000000, output: -1000000, cacheRead: 0, cacheWrite: 0 }, + "openrouter:openrouter/auto": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "openrouter:openrouter/auto-beta": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:openrouter/free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:openrouter/fusion": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "openrouter:openrouter/pareto-code": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:perceptron/perceptron-mk1.5": { input: 0.15, output: 1.5, cacheRead: 0, cacheWrite: 0 }, "openrouter:poolside/laguna-s-2.1": { input: 0.09, output: 0.18, cacheRead: 0.009, cacheWrite: 0 }, "openrouter:poolside/laguna-s-2.1:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, @@ -1096,78 +1120,68 @@ export const PRICES: Record = { "openrouter:qwen/qwen-2.5-72b-instruct": { input: 0.36, output: 0.4, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen-2.5-7b-instruct": { input: 0.1, output: 0.2, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen-plus": { input: 0.26, output: 0.78, cacheRead: 0.052, cacheWrite: 0.325 }, - "openrouter:qwen/qwen-plus-2025-07-28": { input: 0.26, output: 0.78, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen3-14b": { input: 0.12, output: 0.24, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3-235b-a22b": { input: 0.455, output: 1.82, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3-235b-a22b-2507": { input: 0.0875, output: 0.35, cacheRead: 0.0175, cacheWrite: 0 }, - "openrouter:qwen/qwen3-235b-a22b-thinking-2507": { input: 0.23, output: 2.3, cacheRead: 0, cacheWrite: 0 }, + "openrouter:qwen/qwen3-235b-a22b-2507": { input: 0.09, output: 0.55, cacheRead: 0, cacheWrite: 0 }, + "openrouter:qwen/qwen3-235b-a22b-thinking-2507": { input: 0.45, output: 3.5, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen3-30b-a3b": { input: 0.12, output: 0.5, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3-30b-a3b-instruct-2507": { input: 0.04815, output: 0.19305, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3-30b-a3b-thinking-2507": { input: 0.2, output: 2.4, cacheRead: 0, cacheWrite: 0 }, + "openrouter:qwen/qwen3-30b-a3b-instruct-2507": { input: 0.09, output: 0.3, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen3-32b": { input: 0.08, output: 0.28, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3-8b": { input: 0.117, output: 0.455, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen3-coder": { input: 0.3, output: 1, cacheRead: 0.1, cacheWrite: 0 }, "openrouter:qwen/qwen3-coder-30b-a3b-instruct": { input: 0.07, output: 0.28, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen3-coder-flash": { input: 0.195, output: 0.975, cacheRead: 0.039, cacheWrite: 0.24375 }, "openrouter:qwen/qwen3-coder-next": { input: 0.12, output: 0.8, cacheRead: 0.07, cacheWrite: 0 }, - "openrouter:qwen/qwen3-coder-plus": { input: 0.65, output: 3.25, cacheRead: 0.13, cacheWrite: 0.8125 }, - "openrouter:qwen/qwen3-max": { input: 0.78, output: 3.9, cacheRead: 0.156, cacheWrite: 0.975 }, - "openrouter:qwen/qwen3-max-thinking": { input: 0.78, output: 3.9, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3-next-80b-a3b-instruct": { input: 0.1, output: 1.1, cacheRead: 0.07, cacheWrite: 0 }, + "openrouter:qwen/qwen3-next-80b-a3b-instruct": { input: 0.09, output: 1.1, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen3-next-80b-a3b-thinking": { input: 0.15, output: 1.2, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen3-vl-235b-a22b-instruct": { input: 0.21, output: 1.9, cacheRead: 0.1, cacheWrite: 0 }, - "openrouter:qwen/qwen3-vl-235b-a22b-thinking": { input: 0.4, output: 4, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen3-vl-30b-a3b-instruct": { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3-vl-30b-a3b-thinking": { input: 0.2, output: 2.4, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3-vl-32b-instruct": { input: 0.104, output: 0.416, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3-vl-8b-instruct": { input: 0.117, output: 0.455, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3-vl-8b-thinking": { input: 0.18, output: 2.1, cacheRead: 0, cacheWrite: 0 }, + "openrouter:qwen/qwen3-vl-30b-a3b-thinking": { input: 0.29, output: 1, cacheRead: 0, cacheWrite: 0 }, + "openrouter:qwen/qwen3-vl-8b-instruct": { input: 0.25, output: 0.75, cacheRead: 0.12, cacheWrite: 0 }, "openrouter:qwen/qwen3.5-122b-a10b": { input: 0.26, output: 2.08, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3.5-27b": { input: 0.195, output: 1.56, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3.5-35b-a3b": { input: 0.15, output: 1, cacheRead: 0.05, cacheWrite: 0 }, - "openrouter:qwen/qwen3.5-397b-a17b": { input: 0.55, output: 3.5, cacheRead: 0.225, cacheWrite: 0 }, - "openrouter:qwen/qwen3.5-9b": { input: 0.1, output: 0.15, cacheRead: 0, cacheWrite: 0 }, + "openrouter:qwen/qwen3.5-27b": { input: 0.27, output: 2.16, cacheRead: 0.27, cacheWrite: 0 }, + "openrouter:qwen/qwen3.5-35b-a3b": { input: 0.14, output: 1, cacheRead: 0.05, cacheWrite: 0 }, + "openrouter:qwen/qwen3.5-397b-a17b": { input: 0.39, output: 2.34, cacheRead: 0, cacheWrite: 0 }, + "openrouter:qwen/qwen3.5-9b": { input: 0.08, output: 0.13, cacheRead: 0.04, cacheWrite: 0 }, "openrouter:qwen/qwen3.5-flash-02-23": { input: 0.065, output: 0.26, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen3.5-plus-02-15": { input: 0.26, output: 1.56, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen3.5-plus-20260420": { input: 0.3, output: 1.8, cacheRead: 0, cacheWrite: 0.375 }, - "openrouter:qwen/qwen3.6-27b": { input: 0.32, output: 3.2, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3.6-35b-a3b": { input: 0.15, output: 1, cacheRead: 0.05, cacheWrite: 0 }, + "openrouter:qwen/qwen3.6-27b": { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, + "openrouter:qwen/qwen3.6-35b-a3b": { input: 0.1, output: 0.95, cacheRead: 0.05, cacheWrite: 0 }, "openrouter:qwen/qwen3.6-flash": { input: 0.1875, output: 1.125, cacheRead: 0, cacheWrite: 0.234375 }, - "openrouter:qwen/qwen3.6-max-preview": { input: 1.027, output: 6.162, cacheRead: 0, cacheWrite: 1.28375 }, "openrouter:qwen/qwen3.6-plus": { input: 0.325, output: 1.95, cacheRead: 0, cacheWrite: 0.40625 }, "openrouter:qwen/qwen3.7-flash": { input: 0.03, output: 0.13, cacheRead: 0.006, cacheWrite: 0.038 }, "openrouter:qwen/qwen3.7-max": { input: 1.475, output: 4.425, cacheRead: 0.295, cacheWrite: 1.84375 }, "openrouter:qwen/qwen3.7-plus": { input: 0.32, output: 1.28, cacheRead: 0.064, cacheWrite: 0.4 }, + "openrouter:qwen/qwen3.7-plus:batch": { input: 0.23, output: 0.92, cacheRead: 0, cacheWrite: 0 }, "openrouter:qwen/qwen3.8-2.4t-a95b": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 0 }, - "openrouter:qwen/qwen3.8-27b": { input: 0.42, output: 3, cacheRead: 0.085, cacheWrite: 0 }, - "openrouter:qwen/qwen3.8-27b:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "openrouter:qwen/qwen3.8-flash": { input: 0.15, output: 0.47, cacheRead: 0.016, cacheWrite: 0.2 }, - "openrouter:qwen/qwen3.8-max-0902": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 2.5 }, + "openrouter:qwen/qwen3.8-27b": { input: 0.04, output: 1.35, cacheRead: 0.018, cacheWrite: 0 }, + "openrouter:qwen/qwen3.8-flash": { input: 0.15, output: 0.47, cacheRead: 0.016, cacheWrite: 0 }, + "openrouter:qwen/qwen3.8-max-0902": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 0 }, "openrouter:qwen/qwen3.8-max-prime": { input: 4, output: 12, cacheRead: 0.5, cacheWrite: 0 }, "openrouter:qwen/qwen3.8-omni-flash": { input: 0.15, output: 0.47, cacheRead: 0.016, cacheWrite: 0 }, + "openrouter:recursive/flint-v1.0:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "openrouter:reflection/beam-1.0-501b-a23b": { input: 0.3, output: 1, cacheRead: 0.04, cacheWrite: 0 }, "openrouter:rekaai/reka-edge": { input: 0.1, output: 0.1, cacheRead: 0, cacheWrite: 0 }, "openrouter:relace/relace-search": { input: 1, output: 3, cacheRead: 0, cacheWrite: 0 }, "openrouter:sakana/fugu-max": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 0 }, "openrouter:sakana/fugu-ultra": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, "openrouter:sakana/fugu-ultra-v2": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, "openrouter:sakana/sakana-namazu": { input: 0.95, output: 4, cacheRead: 0.15, cacheWrite: 0 }, - "openrouter:sao10k/l3.1-euryale-70b": { input: 0.85, output: 0.85, cacheRead: 0, cacheWrite: 0 }, - "openrouter:stealth/space-bunny-alpha": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:stepfun/step-3.5-flash": { input: 0.1, output: 0.3, cacheRead: 0, cacheWrite: 0 }, "openrouter:stepfun/step-3.7-flash": { input: 0.2, output: 1.15, cacheRead: 0.04, cacheWrite: 0 }, - "openrouter:tencent/hy3": { input: 0.132, output: 0.528, cacheRead: 0.033, cacheWrite: 0 }, + "openrouter:stepfun/step-5-preview": { input: 1, output: 2.7, cacheRead: 0.1, cacheWrite: 0 }, + "openrouter:tencent/hy3": { input: 0.0825, output: 0.33, cacheRead: 0.020625, cacheWrite: 0 }, "openrouter:tencent/hy3-preview": { input: 0.18, output: 0.6, cacheRead: 0.06, cacheWrite: 0 }, - "openrouter:tencent/hy4-preview": { input: 0.834, output: 2.501, cacheRead: 0.042, cacheWrite: 0 }, - "openrouter:thinkingmachines/inkling": { input: 0.95, output: 4.05, cacheRead: 0.16, cacheWrite: 0 }, + "openrouter:tencent/hy4-preview": { input: 0.7506, output: 2.2509, cacheRead: 0.0378, cacheWrite: 0 }, + "openrouter:thinkingmachines/inkling": { input: 1, output: 4.05, cacheRead: 0.17, cacheWrite: 0 }, "openrouter:thinkingmachines/inkling-small": { input: 0.45, output: 1.2, cacheRead: 0.1, cacheWrite: 0 }, "openrouter:thinkingmachines/inkling-small:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:thinkingmachines/inkling:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "openrouter:typesafe/jev-router": { input: -1000000, output: -1000000, cacheRead: 0, cacheWrite: 0 }, - "openrouter:unbiased/pareto": { input: 2.5, output: 7.5, cacheRead: 0.25, cacheWrite: 0 }, - "openrouter:unbiased/pareto-26.10-preview": { input: 0.8, output: 3.2, cacheRead: 0.03, cacheWrite: 0 }, + "openrouter:typesafe/jev-router": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "openrouter:unbiased/pareto-26.10": { input: 0.8, output: 3.2, cacheRead: 0.03, cacheWrite: 0 }, + "openrouter:unbiased/pareto-26.9": { input: 2.5, output: 7.5, cacheRead: 0.25, cacheWrite: 0 }, "openrouter:upstage/solar-mini4": { input: 0.05, output: 0.2, cacheRead: 0.005, cacheWrite: 0 }, "openrouter:upstage/solar-pro-3": { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, - "openrouter:upstage/solar-pro4": { input: 0.09, output: 0.36, cacheRead: 0.018, cacheWrite: 0 }, + "openrouter:upstage/solar-pro4": { input: 0.15, output: 0.6, cacheRead: 0.03, cacheWrite: 0 }, "openrouter:x-ai/grok-4.20": { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, "openrouter:x-ai/grok-4.3": { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, "openrouter:x-ai/grok-4.3:batch": { input: 1, output: 2, cacheRead: 0.16, cacheWrite: 0 }, @@ -1175,25 +1189,26 @@ export const PRICES: Record = { "openrouter:x-ai/grok-4.6": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "openrouter:x-ai/grok-4.7": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "openrouter:x-ai/grok-build-0.1": { input: 1, output: 2, cacheRead: 0.2, cacheWrite: 0 }, - "openrouter:xiaomi/mimo-v2.5": { input: 0.14, output: 0.28, cacheRead: 0.0028, cacheWrite: 0 }, - "openrouter:xiaomi/mimo-v2.5-pro": { input: 0.435, output: 0.87, cacheRead: 0.0036, cacheWrite: 0 }, + "openrouter:xiaomi/mimo-v2.5": { input: 0.119, output: 0.238, cacheRead: 0.00255, cacheWrite: 0 }, + "openrouter:xiaomi/mimo-v2.5-pro": { input: 0.3045, output: 0.609, cacheRead: 0.0028, cacheWrite: 0 }, "openrouter:xiaomi/mimo-v2.6-flash": { input: 0.14, output: 0.28, cacheRead: 0.0028, cacheWrite: 0 }, "openrouter:xiaomi/mimo-v2.6-pro": { input: 0.435, output: 0.87, cacheRead: 0.0036, cacheWrite: 0 }, "openrouter:xiaomi/mimo-v2.6-pro-ultraspeed": { input: 4.35, output: 8.7, cacheRead: 0.036, cacheWrite: 0 }, + "openrouter:xingchen-agi/xing4.0-29b-a4b:free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "openrouter:z-ai/glm-4.5": { input: 0.6, output: 2.2, cacheRead: 0.11, cacheWrite: 0 }, "openrouter:z-ai/glm-4.5-air": { input: 0.13, output: 0.85, cacheRead: 0.025, cacheWrite: 0 }, "openrouter:z-ai/glm-4.5v": { input: 0.6, output: 1.8, cacheRead: 0.11, cacheWrite: 0 }, - "openrouter:z-ai/glm-4.6": { input: 0.43, output: 1.75, cacheRead: 0.08, cacheWrite: 0 }, - "openrouter:z-ai/glm-4.6v": { input: 0.3, output: 0.9, cacheRead: 0.05, cacheWrite: 0 }, - "openrouter:z-ai/glm-4.7": { input: 0.6, output: 2.2, cacheRead: 0.11, cacheWrite: 0 }, + "openrouter:z-ai/glm-4.6": { input: 0.55, output: 2.2, cacheRead: 0.11, cacheWrite: 0 }, + "openrouter:z-ai/glm-4.6v": { input: 0.3, output: 0.9, cacheRead: 0.055, cacheWrite: 0 }, + "openrouter:z-ai/glm-4.7": { input: 0.54, output: 1.98, cacheRead: 0.099, cacheWrite: 0 }, "openrouter:z-ai/glm-4.7-flash": { input: 0.0605, output: 0.4, cacheRead: 0, cacheWrite: 0 }, "openrouter:z-ai/glm-5": { input: 0.6, output: 1.9, cacheRead: 0.119, cacheWrite: 0 }, "openrouter:z-ai/glm-5-turbo": { input: 1.2, output: 4, cacheRead: 0.24, cacheWrite: 0 }, "openrouter:z-ai/glm-5.1": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, - "openrouter:z-ai/glm-5.2": { input: 0.3, output: 3.49, cacheRead: 0.26, cacheWrite: 0 }, - "openrouter:z-ai/glm-5.3": { input: 1.4, output: 4.4, cacheRead: 0.14, cacheWrite: 0 }, + "openrouter:z-ai/glm-5.2": { input: 0.0341, output: 7, cacheRead: 0.033, cacheWrite: 0 }, + "openrouter:z-ai/glm-5.3": { input: 0.079, output: 1.4, cacheRead: 0.078, cacheWrite: 0 }, "openrouter:z-ai/glm-5.3-flash": { input: 0.15, output: 0.5, cacheRead: 0.03, cacheWrite: 0 }, - "openrouter:z-ai/glm-5.3-flash:batch": { input: 0.06, output: 0.2, cacheRead: 0.012, cacheWrite: 0 }, + "openrouter:z-ai/glm-5.3-flash:batch": { input: 0.05, output: 0.18, cacheRead: 0.01, cacheWrite: 0 }, "openrouter:z-ai/glm-5.3-flashx": { input: 0.37, output: 1.25, cacheRead: 0.09, cacheWrite: 0 }, "openrouter:z-ai/glm-5.3-prime": { input: 2.8, output: 8.8, cacheRead: 0.56, cacheWrite: 0 }, "openrouter:z-ai/glm-5.3:batch": { input: 0.45, output: 2, cacheRead: 0.1, cacheWrite: 0 }, @@ -1204,6 +1219,7 @@ export const PRICES: Record = { "qwen-token-plan-cn:deepseek-v4-pro": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "qwen-token-plan-cn:deepseek-v4-pro-0813": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "qwen-token-plan-cn:deepseek-v4.1-flash": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "qwen-token-plan-cn:deepseek-v4.1-flash-1017": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "qwen-token-plan-cn:glm-5": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "qwen-token-plan-cn:glm-5.1": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "qwen-token-plan-cn:glm-5.2": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, @@ -1233,6 +1249,7 @@ export const PRICES: Record = { "qwen-token-plan:deepseek-v4-pro": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "qwen-token-plan:deepseek-v4-pro-0813": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "qwen-token-plan:deepseek-v4.1-flash": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "qwen-token-plan:deepseek-v4.1-flash-1017": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "qwen-token-plan:glm-5": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "qwen-token-plan:glm-5.1": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "qwen-token-plan:glm-5.2": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, @@ -1252,6 +1269,7 @@ export const PRICES: Record = { "radius:claude-fable-5": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "radius:claude-fable-5-1": { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 }, "radius:claude-haiku-4-5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, + "radius:claude-haiku-5-5": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "radius:claude-opus-4-5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "radius:claude-opus-4-8": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "radius:claude-opus-5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, @@ -1272,22 +1290,23 @@ export const PRICES: Record = { "radius:gpt-6-astra": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "radius:gpt-6-luna": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, "radius:gpt-6-sol": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, + "radius:gpt-6.1-sol": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, "radius:grok-4.7": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "radius:kimi-k3": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, + "radius:minimax-m3.1-flash": { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, "radius:precise": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, - "together:deepseek-ai/DeepSeek-V4-Flash-0731": { input: 0.14, output: 0.28, cacheRead: 0.03, cacheWrite: 0 }, + "radius:recursive/flint": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "together:deepseek-ai/DeepSeek-V4-Pro-0813": { input: 1.32, output: 3.96, cacheRead: 0.13, cacheWrite: 0 }, "together:deepseek-ai/DeepSeek-V4.1-Flash": { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 }, - "together:meta-llama/Llama-3.3-70B-Instruct-Turbo": { input: 1.04, output: 1.04, cacheRead: 0, cacheWrite: 0 }, - "together:MiniMaxAI/MiniMax-M2.7": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, + "together:meta-models/Muse-Spark-Open-816B-A42B": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, "together:MiniMaxAI/MiniMax-M3": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, "together:moonshotai/Kimi-K3": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, - "together:nvidia/nemotron-3-ultra-550b-a55b": { input: 0.6, output: 3.6, cacheRead: 0.2, cacheWrite: 0 }, + "together:nvidia/NVIDIA-Nemotron-3.5-Super-VL": { input: 0.15, output: 0.5, cacheRead: 0.02, cacheWrite: 0 }, "together:openai/gpt-oss-120b": { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, - "together:Qwen/Qwen2.5-7B-Instruct-Turbo": { input: 0.3, output: 0.3, cacheRead: 0, cacheWrite: 0 }, "together:Qwen/Qwen3.5-9B": { input: 0.17, output: 0.25, cacheRead: 0, cacheWrite: 0 }, "together:Qwen/Qwen3.6-Plus": { input: 0.5, output: 3, cacheRead: 0, cacheWrite: 0 }, - "together:Qwen/Qwen3.7-Max": { input: 1.25, output: 3.75, cacheRead: 0.125, cacheWrite: 0 }, + "together:Qwen/Qwen3.7-Max": { input: 2.5, output: 7.5, cacheRead: 0.5, cacheWrite: 0 }, + "together:reflection/Beam-1.0-501B-A23B": { input: 0.4, output: 1.2, cacheRead: 0.04, cacheWrite: 0 }, "together:thinkingmachines/Inkling": { input: 1, output: 4.05, cacheRead: 0.17, cacheWrite: 0 }, "together:zai-org/GLM-5.2": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, "together:zai-org/GLM-5.3": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, @@ -1295,21 +1314,14 @@ export const PRICES: Record = { "vercel-ai-gateway:alibaba/qwen-3-14b": { input: 0.12, output: 0.24, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:alibaba/qwen-3-235b": { input: 0.22, output: 0.88, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:alibaba/qwen-3-30b": { input: 0.12, output: 0.5, cacheRead: 0, cacheWrite: 0 }, - "vercel-ai-gateway:alibaba/qwen-3-32b": { input: 0.16, output: 0.64, cacheRead: 0, cacheWrite: 0 }, - "vercel-ai-gateway:alibaba/qwen-3.6-max-preview": { input: 1.3, output: 7.8, cacheRead: 0.13, cacheWrite: 1.625 }, - "vercel-ai-gateway:alibaba/qwen3-235b-a22b-thinking": { input: 0.4, output: 4, cacheRead: 0, cacheWrite: 0 }, - "vercel-ai-gateway:alibaba/qwen3-coder": { input: 1.5, output: 7.5, cacheRead: 0.3, cacheWrite: 0 }, + "vercel-ai-gateway:alibaba/qwen-3-32b": { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, + "vercel-ai-gateway:alibaba/qwen3-coder": { input: 0.22, output: 1.8, cacheRead: 0.022, cacheWrite: 0 }, "vercel-ai-gateway:alibaba/qwen3-coder-30b-a3b": { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:alibaba/qwen3-coder-next": { input: 0.5, output: 1.2, cacheRead: 0, cacheWrite: 0 }, - "vercel-ai-gateway:alibaba/qwen3-coder-plus": { input: 1, output: 5, cacheRead: 0.2, cacheWrite: 0 }, - "vercel-ai-gateway:alibaba/qwen3-max": { input: 1.2, output: 6, cacheRead: 0.24, cacheWrite: 0 }, - "vercel-ai-gateway:alibaba/qwen3-max-preview": { input: 1.2, output: 6, cacheRead: 0.24, cacheWrite: 0 }, "vercel-ai-gateway:alibaba/qwen3-max-thinking": { input: 1.2, output: 6, cacheRead: 0.24, cacheWrite: 0 }, "vercel-ai-gateway:alibaba/qwen3-next-80b-a3b-instruct": { input: 0.15, output: 1.2, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:alibaba/qwen3-next-80b-a3b-thinking": { input: 0.15, output: 1.2, cacheRead: 0, cacheWrite: 0 }, - "vercel-ai-gateway:alibaba/qwen3-vl-235b-a22b-instruct": { input: 0.4, output: 1.6, cacheRead: 0, cacheWrite: 0 }, - "vercel-ai-gateway:alibaba/qwen3-vl-instruct": { input: 0.4, output: 1.6, cacheRead: 0, cacheWrite: 0 }, - "vercel-ai-gateway:alibaba/qwen3-vl-thinking": { input: 0.4, output: 4, cacheRead: 0, cacheWrite: 0 }, + "vercel-ai-gateway:alibaba/qwen3-vl-instruct": { input: 0.2, output: 0.88, cacheRead: 0.11, cacheWrite: 0 }, "vercel-ai-gateway:alibaba/qwen3.5-flash": { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0.125 }, "vercel-ai-gateway:alibaba/qwen3.5-plus": { input: 0.4, output: 2.4, cacheRead: 0.04, cacheWrite: 0.5 }, "vercel-ai-gateway:alibaba/qwen3.6-27b": { input: 0.6, output: 3.6, cacheRead: 0, cacheWrite: 0 }, @@ -1328,33 +1340,45 @@ export const PRICES: Record = { "vercel-ai-gateway:amazon/nova-lite": { input: 0.06, output: 0.24, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:amazon/nova-micro": { input: 0.035, output: 0.14, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:amazon/nova-pro": { input: 0.8, output: 3.2, cacheRead: 0, cacheWrite: 0 }, - "vercel-ai-gateway:anthropic/claude-3-haiku": { input: 0.25, output: 1.25, cacheRead: 0.03, cacheWrite: 0.3 }, "vercel-ai-gateway:anthropic/claude-fable-5": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, + "vercel-ai-gateway:anthropic/claude-fable-5-batch": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "vercel-ai-gateway:anthropic/claude-fable-5.1": { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 }, + "vercel-ai-gateway:anthropic/claude-fable-5.1-batch": { input: 5, output: 25, cacheRead: 0.125, cacheWrite: 6.25 }, "vercel-ai-gateway:anthropic/claude-haiku-4.5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, - "vercel-ai-gateway:anthropic/claude-opus-4": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }, + "vercel-ai-gateway:anthropic/claude-haiku-4.5-batch": { input: 0.5, output: 2.5, cacheRead: 0.05, cacheWrite: 0.625 }, + "vercel-ai-gateway:anthropic/claude-haiku-5.5": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, + "vercel-ai-gateway:anthropic/claude-haiku-5.5-batch": { input: 0.05, output: 0.25, cacheRead: 0.005, cacheWrite: 0.0625 }, "vercel-ai-gateway:anthropic/claude-opus-4.5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, + "vercel-ai-gateway:anthropic/claude-opus-4.5-batch": { input: 2.5, output: 12.5, cacheRead: 0.25, cacheWrite: 3.125 }, "vercel-ai-gateway:anthropic/claude-opus-4.6": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, + "vercel-ai-gateway:anthropic/claude-opus-4.6-batch": { input: 2.5, output: 12.5, cacheRead: 0.25, cacheWrite: 3.125 }, "vercel-ai-gateway:anthropic/claude-opus-4.7": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, + "vercel-ai-gateway:anthropic/claude-opus-4.7-batch": { input: 2.5, output: 12.5, cacheRead: 0.25, cacheWrite: 3.125 }, "vercel-ai-gateway:anthropic/claude-opus-4.8": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, + "vercel-ai-gateway:anthropic/claude-opus-4.8-batch": { input: 2.5, output: 12.5, cacheRead: 0.25, cacheWrite: 3.125 }, "vercel-ai-gateway:anthropic/claude-opus-4.8-fast": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "vercel-ai-gateway:anthropic/claude-opus-5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, + "vercel-ai-gateway:anthropic/claude-opus-5-batch": { input: 2.5, output: 12.5, cacheRead: 0.25, cacheWrite: 3.125 }, "vercel-ai-gateway:anthropic/claude-opus-5-fast": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, "vercel-ai-gateway:anthropic/claude-opus-5.5": { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 5 }, + "vercel-ai-gateway:anthropic/claude-opus-5.5-batch": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, "vercel-ai-gateway:anthropic/claude-opus-5.5-fast": { input: 8, output: 40, cacheRead: 0.4, cacheWrite: 10 }, - "vercel-ai-gateway:anthropic/claude-sonnet-4": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, "vercel-ai-gateway:anthropic/claude-sonnet-4.5": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, + "vercel-ai-gateway:anthropic/claude-sonnet-4.5-batch": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 1.875 }, "vercel-ai-gateway:anthropic/claude-sonnet-4.6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, + "vercel-ai-gateway:anthropic/claude-sonnet-4.6-batch": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 1.875 }, "vercel-ai-gateway:anthropic/claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, - "vercel-ai-gateway:anthropic/claude-sonnet-5.5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, - "vercel-ai-gateway:arcee-ai/trinity-large-thinking": { input: 0.25, output: 0.9, cacheRead: 0, cacheWrite: 0 }, + "vercel-ai-gateway:anthropic/claude-sonnet-5-batch": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, + "vercel-ai-gateway:anthropic/claude-sonnet-5.5": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, + "vercel-ai-gateway:anthropic/claude-sonnet-5.5-batch": { input: 1, output: 5, cacheRead: 0.05, cacheWrite: 1.25 }, + "vercel-ai-gateway:arcee-ai/trinity-large-thinking": { input: 0.25, output: 0.8, cacheRead: 0.06, cacheWrite: 0 }, "vercel-ai-gateway:bytedance/seed-1.6": { input: 0.25, output: 2, cacheRead: 0.05, cacheWrite: 0 }, "vercel-ai-gateway:bytedance/seed-1.8": { input: 0.25, output: 2, cacheRead: 0.05, cacheWrite: 0 }, "vercel-ai-gateway:bytedance/seed-2.1-turbo": { input: 0.5, output: 2.5, cacheRead: 0.1, cacheWrite: 0 }, + "vercel-ai-gateway:callstack/apex": { input: 0.5, output: 3, cacheRead: 0.2, cacheWrite: 0 }, "vercel-ai-gateway:cohere/command-a": { input: 2.5, output: 10, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:deepseek/deepseek-r1": { input: 1.35, output: 5.4, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:deepseek/deepseek-v3.1": { input: 0.25, output: 0.95, cacheRead: 0.13, cacheWrite: 0 }, - "vercel-ai-gateway:deepseek/deepseek-v3.1-terminus": { input: 0.27, output: 1, cacheRead: 0.135, cacheWrite: 0 }, "vercel-ai-gateway:deepseek/deepseek-v3.2": { input: 0.62, output: 1.85, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:deepseek/deepseek-v3.2-thinking": { input: 0.62, output: 1.85, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:deepseek/deepseek-v4-flash": { input: 0.13, output: 0.26, cacheRead: 0.028, cacheWrite: 0 }, @@ -1362,33 +1386,46 @@ export const PRICES: Record = { "vercel-ai-gateway:deepseek/deepseek-v4-flash-vision-exp": { input: 0.2156, output: 0.6468, cacheRead: 0.0068, cacheWrite: 0 }, "vercel-ai-gateway:deepseek/deepseek-v4-pro": { input: 0.66, output: 1.98, cacheRead: 0.022, cacheWrite: 0 }, "vercel-ai-gateway:deepseek/deepseek-v4-pro-0813": { input: 0.66, output: 1.98, cacheRead: 0.066, cacheWrite: 0 }, - "vercel-ai-gateway:deepseek/deepseek-v4.1-flash": { input: 0.3, output: 1.2, cacheRead: 0.007, cacheWrite: 0 }, - "vercel-ai-gateway:deepseek/deepseek-v4.1-flash-fast": { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 }, + "vercel-ai-gateway:deepseek/deepseek-v4.1-flash": { input: 0.075, output: 0.3, cacheRead: 0.0015, cacheWrite: 0 }, + "vercel-ai-gateway:deepseek/deepseek-v4.1-flash-1017": { input: 0.075, output: 0.3, cacheRead: 0.0015, cacheWrite: 0 }, + "vercel-ai-gateway:deepseek/deepseek-v4.1-flash-1017-fast": { input: 0.6, output: 2.4, cacheRead: 0.014, cacheWrite: 0 }, + "vercel-ai-gateway:deepseek/deepseek-v4.1-flash-fast": { input: 0.6, output: 2.4, cacheRead: 0.014, cacheWrite: 0 }, "vercel-ai-gateway:fireworks/ember-1": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, "vercel-ai-gateway:google/gemini-2.5-flash": { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, + "vercel-ai-gateway:google/gemini-2.5-flash-batch": { input: 0.15, output: 1.25, cacheRead: 0.03, cacheWrite: 0 }, "vercel-ai-gateway:google/gemini-2.5-flash-lite": { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, + "vercel-ai-gateway:google/gemini-2.5-flash-lite-batch": { input: 0.05, output: 0.2, cacheRead: 0.01, cacheWrite: 0 }, "vercel-ai-gateway:google/gemini-2.5-pro": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, + "vercel-ai-gateway:google/gemini-2.5-pro-batch": { input: 0.625, output: 5, cacheRead: 0.125, cacheWrite: 0 }, "vercel-ai-gateway:google/gemini-3-flash": { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 }, + "vercel-ai-gateway:google/gemini-3-flash-batch": { input: 0.25, output: 1.5, cacheRead: 0.05, cacheWrite: 0 }, "vercel-ai-gateway:google/gemini-3.1-flash-lite": { input: 0.25, output: 1.5, cacheRead: 0.03, cacheWrite: 0 }, + "vercel-ai-gateway:google/gemini-3.1-flash-lite-batch": { input: 0.125, output: 0.75, cacheRead: 0.015, cacheWrite: 0 }, "vercel-ai-gateway:google/gemini-3.1-pro-preview": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, + "vercel-ai-gateway:google/gemini-3.1-pro-preview-batch": { input: 1, output: 6, cacheRead: 0.2, cacheWrite: 0 }, "vercel-ai-gateway:google/gemini-3.5-flash": { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, + "vercel-ai-gateway:google/gemini-3.5-flash-batch": { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, "vercel-ai-gateway:google/gemini-3.5-flash-lite": { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, + "vercel-ai-gateway:google/gemini-3.5-flash-lite-batch": { input: 0.15, output: 1.25, cacheRead: 0.015, cacheWrite: 0 }, "vercel-ai-gateway:google/gemini-3.6-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, + "vercel-ai-gateway:google/gemini-3.6-flash-batch": { input: 0.375, output: 1.875, cacheRead: 0.0375, cacheWrite: 0 }, "vercel-ai-gateway:google/gemini-3.7-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, + "vercel-ai-gateway:google/gemini-3.7-flash-batch": { input: 0.375, output: 1.875, cacheRead: 0.0375, cacheWrite: 0 }, "vercel-ai-gateway:google/gemini-3.8-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, + "vercel-ai-gateway:google/gemini-4-argon": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 0 }, "vercel-ai-gateway:google/gemma-4-26b-a4b-it": { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, "vercel-ai-gateway:google/gemma-4-31b-it": { input: 0.14, output: 0.4, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:inception/mercury-2": { input: 0.25, output: 0.75, cacheRead: 0.025, cacheWrite: 0 }, "vercel-ai-gateway:inception/mercury-2.5": { input: 0.04, output: 0.15, cacheRead: 0.004, cacheWrite: 0 }, + "vercel-ai-gateway:inception/mercury-3": { input: 0.1, output: 0.35, cacheRead: 0.01, cacheWrite: 0 }, "vercel-ai-gateway:inception/mercury-coder-small": { input: 0.25, output: 1, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:inclusionai/ling-3.0-flash": { input: 0.021, output: 0.063, cacheRead: 0.0042, cacheWrite: 0 }, "vercel-ai-gateway:inclusionai/ling-3.0-flash-fin": { input: 0.075, output: 0.22, cacheRead: 0.015, cacheWrite: 0 }, - "vercel-ai-gateway:inclusionai/ling-3.0-flash-sante": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "vercel-ai-gateway:inclusionai/ling-3.0-flash-sante-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "vercel-ai-gateway:inclusionai/ling-3.0-flash-sante": { input: 0.075, output: 0.22, cacheRead: 0.015, cacheWrite: 0 }, "vercel-ai-gateway:inclusionai/ling-3.0-flash-vl": { input: 0.075, output: 0.22, cacheRead: 0.015, cacheWrite: 0 }, - "vercel-ai-gateway:inclusionai/ling-3.1-flash": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "vercel-ai-gateway:inclusionai/ling-3.1-flash-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "vercel-ai-gateway:inclusionai/ling-3.1-flash": { input: 0.3, output: 0.9, cacheRead: 0.06, cacheWrite: 0 }, "vercel-ai-gateway:interfaze/interfaze-beta": { input: 1.5, output: 3.5, cacheRead: 0, cacheWrite: 0 }, + "vercel-ai-gateway:liquid/lfm2.5-24b-a2b": { input: 0.05, output: 0.7, cacheRead: 0.025, cacheWrite: 0 }, "vercel-ai-gateway:meituan/longcat-2.5-preview": { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 }, "vercel-ai-gateway:meta/llama-3.1-70b": { input: 0.72, output: 0.72, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:meta/llama-3.1-8b": { input: 0.22, output: 0.22, cacheRead: 0, cacheWrite: 0 }, @@ -1401,6 +1438,8 @@ export const PRICES: Record = { "vercel-ai-gateway:meta/muse-spark-1.2-contributor": { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 }, "vercel-ai-gateway:meta/muse-spark-1.3": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, "vercel-ai-gateway:meta/muse-spark-1.3-contributor": { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 }, + "vercel-ai-gateway:meta/muse-spark-open": { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, + "vercel-ai-gateway:meta/muse-wonder-1.0": { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 0 }, "vercel-ai-gateway:minimax/minimax-m2": { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0.375 }, "vercel-ai-gateway:minimax/minimax-m2.1": { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0.375 }, "vercel-ai-gateway:minimax/minimax-m2.1-lightning": { input: 0.3, output: 2.4, cacheRead: 0.03, cacheWrite: 0.375 }, @@ -1409,17 +1448,18 @@ export const PRICES: Record = { "vercel-ai-gateway:minimax/minimax-m2.7": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0.375 }, "vercel-ai-gateway:minimax/minimax-m2.7-highspeed": { input: 0.6, output: 2.4, cacheRead: 0.06, cacheWrite: 0.375 }, "vercel-ai-gateway:minimax/minimax-m3": { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, + "vercel-ai-gateway:minimax/minimax-m3.1-flash": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:mistral/codestral": { input: 0.3, output: 0.9, cacheRead: 0.03, cacheWrite: 0 }, "vercel-ai-gateway:mistral/ministral-14b": { input: 0.2, output: 0.2, cacheRead: 0.02, cacheWrite: 0 }, "vercel-ai-gateway:mistral/ministral-3b": { input: 0.1, output: 0.1, cacheRead: 0.01, cacheWrite: 0 }, "vercel-ai-gateway:mistral/ministral-8b": { input: 0.15, output: 0.15, cacheRead: 0.015, cacheWrite: 0 }, "vercel-ai-gateway:mistral/mistral-large-3": { input: 0.5, output: 1.5, cacheRead: 0.05, cacheWrite: 0 }, + "vercel-ai-gateway:mistral/mistral-large-4": { input: 1.36, output: 4.18, cacheRead: 0.14, cacheWrite: 0 }, "vercel-ai-gateway:mistral/mistral-medium-3.5": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, - "vercel-ai-gateway:mistral/mistral-nemo": { input: 0.04, output: 0.17, cacheRead: 0, cacheWrite: 0 }, + "vercel-ai-gateway:mistral/mistral-nemo": { input: 0.029, output: 0.03, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:mistral/mistral-small": { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, "vercel-ai-gateway:mixedbread/toast-1": { input: 0.3, output: 0.72, cacheRead: 0.036, cacheWrite: 0 }, "vercel-ai-gateway:moonshotai/kimi-k2": { input: 0.57, output: 2.3, cacheRead: 0, cacheWrite: 0 }, - "vercel-ai-gateway:moonshotai/kimi-k2-thinking": { input: 0.47, output: 2, cacheRead: 0.141, cacheWrite: 0 }, "vercel-ai-gateway:moonshotai/kimi-k2.5": { input: 0.6, output: 3, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:moonshotai/kimi-k2.6": { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, "vercel-ai-gateway:moonshotai/kimi-k2.7-code": { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, @@ -1430,60 +1470,84 @@ export const PRICES: Record = { "vercel-ai-gateway:nvidia/nemotron-3-super-120b-a12b": { input: 0.15, output: 0.65, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:nvidia/nemotron-3-ultra-550b-a55b": { input: 0.6, output: 2.4, cacheRead: 0.12, cacheWrite: 0 }, "vercel-ai-gateway:nvidia/nemotron-3.5-lightning": { input: 0.05, output: 0.2, cacheRead: 0.01, cacheWrite: 0 }, + "vercel-ai-gateway:nvidia/nemotron-3.5-lightning-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "vercel-ai-gateway:nvidia/nemotron-3.5-super-vl": { input: 0.2, output: 0.5, cacheRead: 0.04, cacheWrite: 0 }, "vercel-ai-gateway:nvidia/nemotron-nano-12b-v2-vl": { input: 0.2, output: 0.6, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:nvidia/nemotron-nano-9b-v2": { input: 0.06, output: 0.23, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-3.5-turbo": { input: 0.5, output: 1.5, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-4-turbo": { input: 10, output: 30, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-4.1": { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-4.1-batch": { input: 1, output: 4, cacheRead: 0.25, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-4.1-fast": { input: 3.5, output: 14, cacheRead: 0.875, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-4.1-mini": { input: 0.4, output: 1.6, cacheRead: 0.1, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-4.1-mini-batch": { input: 0.2, output: 0.8, cacheRead: 0.05, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-4.1-mini-fast": { input: 0.7, output: 2.8, cacheRead: 0.175, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-4.1-nano": { input: 0.1, output: 0.4, cacheRead: 0.025, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-4.1-nano-batch": { input: 0.05, output: 0.2, cacheRead: 0.0125, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-4.1-nano-fast": { input: 0.2, output: 0.8, cacheRead: 0.05, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-4o": { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-4o-batch": { input: 1.25, output: 5, cacheRead: 0.625, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-4o-fast": { input: 4.25, output: 17, cacheRead: 2.125, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-4o-mini": { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-4o-mini-batch": { input: 0.075, output: 0.3, cacheRead: 0.0375, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-4o-mini-fast": { input: 0.25, output: 1, cacheRead: 0.125, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-5-batch": { input: 0.625, output: 5, cacheRead: 0.0625, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5-codex": { input: 1.25, output: 10, cacheRead: 0.13, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5-fast": { input: 2.5, output: 20, cacheRead: 0.25, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5-mini": { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-5-mini-batch": { input: 0.125, output: 1, cacheRead: 0.0125, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5-mini-fast": { input: 0.45, output: 3.6, cacheRead: 0.045, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5-nano": { input: 0.05, output: 0.4, cacheRead: 0.005, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-5-nano-batch": { input: 0.025, output: 0.2, cacheRead: 0.0025, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5-pro": { input: 15, output: 120, cacheRead: 0, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-5-pro-batch": { input: 7.5, output: 60, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.1-codex": { input: 1.25, output: 10, cacheRead: 0.13, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.1-codex-max": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.1-codex-mini": { input: 0.25, output: 2, cacheRead: 0.03, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.1-thinking": { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.1-thinking-fast": { input: 2.5, output: 20, cacheRead: 0.25, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.2": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-5.2-batch": { input: 0.875, output: 7, cacheRead: 0.0875, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.2-codex": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.2-fast": { input: 3.5, output: 28, cacheRead: 0.35, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.2-pro": { input: 21, output: 168, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.3-codex": { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.3-codex-fast": { input: 3.5, output: 28, cacheRead: 0.35, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.4": { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-5.4-batch": { input: 1.25, output: 7.5, cacheRead: 0.125, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.4-fast": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.4-mini": { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-5.4-mini-batch": { input: 0.375, output: 2.25, cacheRead: 0.0375, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.4-mini-fast": { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.4-nano": { input: 0.2, output: 1.25, cacheRead: 0.02, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-5.4-nano-batch": { input: 0.1, output: 0.625, cacheRead: 0.01, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.4-pro": { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.5": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-5.5-batch": { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.5-fast": { input: 12.5, output: 75, cacheRead: 1.25, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.5-pro": { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, + "vercel-ai-gateway:openai/gpt-5.5-pro-batch": { input: 15, output: 90, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-5.6-luna": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, + "vercel-ai-gateway:openai/gpt-5.6-luna-batch": { input: 0.1, output: 0.6, cacheRead: 0.01, cacheWrite: 0.125 }, "vercel-ai-gateway:openai/gpt-5.6-luna-fast": { input: 0.4, output: 2.4, cacheRead: 0.04, cacheWrite: 0.5 }, "vercel-ai-gateway:openai/gpt-5.6-sol": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, + "vercel-ai-gateway:openai/gpt-5.6-sol-batch": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, "vercel-ai-gateway:openai/gpt-5.6-sol-fast": { input: 8, output: 40, cacheRead: 0.8, cacheWrite: 10 }, "vercel-ai-gateway:openai/gpt-5.6-terra": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, + "vercel-ai-gateway:openai/gpt-5.6-terra-batch": { input: 1, output: 6, cacheRead: 0.1, cacheWrite: 1.25 }, "vercel-ai-gateway:openai/gpt-5.6-terra-fast": { input: 4, output: 24, cacheRead: 0.4, cacheWrite: 5 }, "vercel-ai-gateway:openai/gpt-6-astra": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, + "vercel-ai-gateway:openai/gpt-6-astra-batch": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, "vercel-ai-gateway:openai/gpt-6-astra-fast": { input: 20, output: 100, cacheRead: 2, cacheWrite: 25 }, "vercel-ai-gateway:openai/gpt-6-luna": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }, + "vercel-ai-gateway:openai/gpt-6-luna-batch": { input: 0.05, output: 0.25, cacheRead: 0.005, cacheWrite: 0.0625 }, "vercel-ai-gateway:openai/gpt-6-luna-fast": { input: 0.2, output: 1, cacheRead: 0.02, cacheWrite: 0.25 }, "vercel-ai-gateway:openai/gpt-6-sol": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, + "vercel-ai-gateway:openai/gpt-6-sol-batch": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, "vercel-ai-gateway:openai/gpt-6-sol-fast": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, "vercel-ai-gateway:openai/gpt-6.1-sol": { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 }, + "vercel-ai-gateway:openai/gpt-6.1-sol-batch": { input: 1, output: 5, cacheRead: 0.05, cacheWrite: 1.25 }, "vercel-ai-gateway:openai/gpt-6.1-sol-fast": { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 5 }, "vercel-ai-gateway:openai/gpt-oss-120b": { input: 0.1, output: 0.5, cacheRead: 0.1, cacheWrite: 0 }, "vercel-ai-gateway:openai/gpt-oss-20b": { input: 0.03, output: 0.14, cacheRead: 0, cacheWrite: 0 }, @@ -1496,10 +1560,12 @@ export const PRICES: Record = { "vercel-ai-gateway:openai/o3-pro": { input: 20, output: 80, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:openai/o4-mini": { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, "vercel-ai-gateway:openai/o4-mini-fast": { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, - "vercel-ai-gateway:poolside/laguna-s-2.1": { input: 0.1, output: 0.2, cacheRead: 0.01, cacheWrite: 0 }, + "vercel-ai-gateway:poolside/laguna-s-2.1": { input: 0.09, output: 0.18, cacheRead: 0.009, cacheWrite: 0 }, "vercel-ai-gateway:poolside/laguna-s-2.1-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:quiverai/arrow-2": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 }, "vercel-ai-gateway:quiverai/arrow-2-telos": { input: 6, output: 30, cacheRead: 0.6, cacheWrite: 7.5 }, + "vercel-ai-gateway:reflection/beam": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + "vercel-ai-gateway:reflection/beam-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:sakana/fugu-max": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 0 }, "vercel-ai-gateway:sakana/fugu-ultra": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, "vercel-ai-gateway:sakana/fugu-ultra-v2": { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, @@ -1507,25 +1573,30 @@ export const PRICES: Record = { "vercel-ai-gateway:spacexai/grok-4.1-fast-non-reasoning": { input: 0.2, output: 0.5, cacheRead: 0.05, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-4.1-fast-reasoning": { input: 0.2, output: 0.5, cacheRead: 0.05, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-4.20-multi-agent": { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, + "vercel-ai-gateway:spacexai/grok-4.20-multi-agent-batch": { input: 1, output: 2, cacheRead: 0.16, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-4.20-multi-agent-beta": { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-4.20-non-reasoning": { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, + "vercel-ai-gateway:spacexai/grok-4.20-non-reasoning-batch": { input: 1, output: 2, cacheRead: 0.16, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-4.20-non-reasoning-beta": { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-4.20-reasoning": { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, + "vercel-ai-gateway:spacexai/grok-4.20-reasoning-batch": { input: 1, output: 2, cacheRead: 0.16, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-4.20-reasoning-beta": { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-4.3": { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, + "vercel-ai-gateway:spacexai/grok-4.3-batch": { input: 1, output: 2, cacheRead: 0.16, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-4.5": { input: 2, output: 6, cacheRead: 0.3, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-4.6": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-4.7": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "vercel-ai-gateway:spacexai/grok-build-0.1": { input: 1, output: 2, cacheRead: 0.2, cacheWrite: 0 }, - "vercel-ai-gateway:stepfun/step-3.5-flash": { input: 0.09, output: 0.3, cacheRead: 0.02, cacheWrite: 0 }, + "vercel-ai-gateway:stealth/glyph-cluster": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "vercel-ai-gateway:stepfun/step-3.7-flash": { input: 0.2, output: 1.15, cacheRead: 0.04, cacheWrite: 0 }, + "vercel-ai-gateway:stepfun/step-5-preview": { input: 1, output: 2.7, cacheRead: 0.1, cacheWrite: 0 }, "vercel-ai-gateway:tencent/hy3": { input: 0.14, output: 0.58, cacheRead: 0.035, cacheWrite: 0 }, "vercel-ai-gateway:tencent/hy4-preview": { input: 0.834, output: 2.501, cacheRead: 0.042, cacheWrite: 0 }, "vercel-ai-gateway:thinkingmachines/inkling": { input: 1, output: 4.05, cacheRead: 0.17, cacheWrite: 0 }, "vercel-ai-gateway:thinkingmachines/inkling-small": { input: 0.45, output: 1.2, cacheRead: 0.1, cacheWrite: 0 }, - "vercel-ai-gateway:xiaomi/mimo-v2.5": { input: 0.14, output: 0.28, cacheRead: 0.0028, cacheWrite: 0 }, - "vercel-ai-gateway:xiaomi/mimo-v2.5-pro": { input: 0.435, output: 0.87, cacheRead: 0.0036, cacheWrite: 0 }, - "vercel-ai-gateway:xiaomi/mimo-v2.6-flash": { input: 0.04, output: 1.28, cacheRead: 0.04, cacheWrite: 0 }, + "vercel-ai-gateway:xiaomi/mimo-v2.5": { input: 0.119, output: 0.238, cacheRead: 0.0025, cacheWrite: 0 }, + "vercel-ai-gateway:xiaomi/mimo-v2.5-pro": { input: 0.3045, output: 0.609, cacheRead: 0.0028, cacheWrite: 0 }, + "vercel-ai-gateway:xiaomi/mimo-v2.6-flash": { input: 0.14, output: 0.28, cacheRead: 0.0028, cacheWrite: 0 }, "vercel-ai-gateway:xiaomi/mimo-v2.6-pro": { input: 0.435, output: 0.87, cacheRead: 0.0036, cacheWrite: 0 }, "vercel-ai-gateway:xiaomi/mimo-v2.6-pro-ultraspeed": { input: 4.35, output: 8.7, cacheRead: 0.036, cacheWrite: 0 }, "vercel-ai-gateway:zai/glm-4.5": { input: 0.6, output: 2.2, cacheRead: 0.11, cacheWrite: 0 }, @@ -1549,25 +1620,16 @@ export const PRICES: Record = { "xai:grok-4.5": { input: 2, output: 6, cacheRead: 0.3, cacheWrite: 0 }, "xai:grok-4.6": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, "xai:grok-4.7": { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, - "xiaomi-token-plan-ams:mimo-v2.5": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "xiaomi-token-plan-ams:mimo-v2.5-pro": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "xiaomi-token-plan-ams:mimo-v2.6-flash": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "xiaomi-token-plan-ams:mimo-v2.6-pro": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "xiaomi-token-plan-cn:mimo-v2.5": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "xiaomi-token-plan-cn:mimo-v2.5-pro": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "xiaomi-token-plan-cn:mimo-v2.6-flash": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "xiaomi-token-plan-cn:mimo-v2.6-pro": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "xiaomi-token-plan-sgp:mimo-v2.5": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "xiaomi-token-plan-sgp:mimo-v2.5-pro": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "xiaomi-token-plan-sgp:mimo-v2.6-flash": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, "xiaomi-token-plan-sgp:mimo-v2.6-pro": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - "xiaomi:mimo-v2.5": { input: 0.14, output: 0.28, cacheRead: 0.0028, cacheWrite: 0 }, - "xiaomi:mimo-v2.5-pro": { input: 0.435, output: 0.87, cacheRead: 0.0036, cacheWrite: 0 }, - "xiaomi:mimo-v2.5-pro-ultraspeed": { input: 1.305, output: 2.61, cacheRead: 0.0108, cacheWrite: 0 }, "xiaomi:mimo-v2.6-flash": { input: 0.14, output: 0.28, cacheRead: 0.0028, cacheWrite: 0 }, "xiaomi:mimo-v2.6-pro": { input: 0.435, output: 0.87, cacheRead: 0.0036, cacheWrite: 0 }, "xiaomi:mimo-v2.6-pro-ultraspeed": { input: 4.35, output: 8.7, cacheRead: 0.036, cacheWrite: 0 }, - "zai-coding-cn:glm-4.6v": { input: 0.3, output: 0.9, cacheRead: 0, cacheWrite: 0 }, + "zai-coding-cn:glm-4.6v": { input: 0.3, output: 0.9, cacheRead: 0.05, cacheWrite: 0 }, "zai-coding-cn:glm-5.3": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, "zai-coding-cn:glm-5.3-flash": { input: 0.15, output: 0.5, cacheRead: 0.03, cacheWrite: 0 }, "zai-coding-cn:glm-5.3-highspeed": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, diff --git a/tests/auth-provider-keys.test.ts b/tests/auth-provider-keys.test.ts index f4a6a39..b0a1b05 100644 --- a/tests/auth-provider-keys.test.ts +++ b/tests/auth-provider-keys.test.ts @@ -13,7 +13,7 @@ * ALL the env vars a provider reads as API keys. * * Owner-spec exclusions (asserted ABSENT): github-copilot (OAuth), - * amazon-bedrock (AWS creds), google-vertex (ADC), azure-openai-responses + * amazon-bedrock (AWS creds), google-vertex (ADC), azure * (needs base URL), the cloudflare account-scoped pair; anthropic keeps * ANTHROPIC_API_KEY only (AUTH_TOKEN/OAUTH_TOKEN stay env-only). */ @@ -32,7 +32,7 @@ const EXCLUDED_PROVIDERS = new Set([ "github-copilot", "amazon-bedrock", "google-vertex", - "azure-openai-responses", + "azure", "cloudflare-workers-ai", "cloudflare-ai-gateway", ]); diff --git a/tests/extraction.test.ts b/tests/extraction.test.ts index 37078ad..0d61caa 100644 --- a/tests/extraction.test.ts +++ b/tests/extraction.test.ts @@ -25,7 +25,7 @@ import assert from "node:assert/strict"; import { createHash } from "node:crypto"; import * as fs from "node:fs"; import { after, describe, it } from "node:test"; -import { createFauxCore, fauxAssistantMessage, fauxToolCall, type FauxResponseStep, type ToolCall } from "@earendil-works/pi-ai"; +import { createFauxCore, fauxAssistantMessage, fauxToolCall, type FauxResponseStep, type ToolCall, type Usage } from "@earendil-works/pi-ai"; import type { PiEngine } from "../src/agent/models.ts"; import type { LhMessage } from "../src/core/native-messages.ts"; import { newPlanBlockMessage } from "../src/core/native-messages.ts"; @@ -873,21 +873,30 @@ describe("the extraction pipeline (extractor → auditor → merger)", () => { const verdict: AuditVerdicts = { links: [{ id: FINDINGS.propositions[0]!.id, linkTo: existingId }], }; + const nativeUsage: Record<"extractor" | "auditor", Usage[]> = { extractor: [], auditor: [] }; + const recordUsage = (stage: "extractor" | "auditor", engine: PiEngine): PiEngine => ({ + ...engine, + streamFn: (model, context, options) => { + const stream = engine.streamFn(model, context, options); + void stream.result().then((message) => nativeUsage[stage].push(message.usage)); + return stream; + }, + }); const pipeline = createExtractionPipeline({ chatStore, graphStore: ledgers, // During the auditor's generate, the registry must already carry // the extractor's fully accumulated live usage (2 steps × 10/5). - extractor: submitModel("submit_findings", FINDINGS), - auditor: submitModel("submit_review", verdict, () => + extractor: recordUsage("extractor", submitModel("submit_findings", FINDINGS)), + auditor: recordUsage("auditor", submitModel("submit_review", verdict, () => usageSeen.push(extractionStatuses().find((r) => r.chatId === chatId)?.usage.extractor?.steps.at(-1)?.inputTokens), - ), + )), }); await pipeline.runExtraction(chatId); // Live: mid-audit the extractor's usage was fully accumulated (faux // estimates tokens from the prompt/response text — deterministic, - // positive, no cache). + // positive, with native first-conversation cache writes in 1.4). assert.equal(usageSeen.length, 1); assert.ok(typeof usageSeen[0] === "number" && usageSeen[0]! > 0, "the extractor's step billed input tokens"); @@ -903,8 +912,16 @@ describe("the extraction pipeline (extractor → auditor → merger)", () => { const step = run.stages.extractor.steps[0]!; assert.ok(step.inputTokens! > 0 && step.outputTokens! > 0, "estimated usage captured"); assert.equal(step.cacheReadTokens, 0); - assert.equal(step.cacheWriteTokens, 0); + assert.equal(nativeUsage.extractor.length, 1); + assert.ok(nativeUsage.extractor[0]!.cacheWrite > 0, "fresh native conversation writes its cached prefix"); + assert.equal(step.cacheReadTokens, nativeUsage.extractor[0]!.cacheRead); + assert.equal(step.cacheWriteTokens, nativeUsage.extractor[0]!.cacheWrite); assert.equal(step.reasoningTokens, 0); + assert.equal(nativeUsage.auditor.length, 1); + assert.equal(run.stages.auditor.steps[0]!.cacheReadTokens, 0, "auditor owns a fresh conversation too"); + assert.ok(nativeUsage.auditor[0]!.cacheWrite > 0); + assert.equal(run.stages.auditor.steps[0]!.cacheReadTokens, nativeUsage.auditor[0]!.cacheRead); + assert.equal(run.stages.auditor.steps[0]!.cacheWriteTokens, nativeUsage.auditor[0]!.cacheWrite); assert.equal(run.stages.auditor.steps.length, 1); assert.ok(!Number.isNaN(Date.parse(run.at))); }); diff --git a/tests/openrouter-free-models.test.ts b/tests/openrouter-free-models.test.ts new file mode 100644 index 0000000..8336237 --- /dev/null +++ b/tests/openrouter-free-models.test.ts @@ -0,0 +1,58 @@ +import assert from "node:assert/strict"; +import { describe, it } from "node:test"; +import { normalizeContext } from "@earendil-works/pi-ai"; +import { Type } from "typebox"; +import { piEngineForSpec, piModels } from "../src/agent/models.ts"; +import { modelCatalog, validateChatSettings, validateModelsSettings } from "../src/server/model-catalog.ts"; +import { callCost } from "../src/core/prices.ts"; + +const specimens = [ + { id: "recursive/flint-v1.0:free", input: ["text"] }, + { id: "xingchen-agi/xing4.0-29b-a4b:free", input: ["text"] }, + { id: "nvidia/nemotron-3.5-super-vl:free", input: ["text", "image"] }, + { id: "openrouter/free", input: ["text", "image"] }, +]; + +describe("native 1.4 OpenRouter free catalog (offline, no live discovery)", { concurrency: false }, () => { + for (const { id, input } of specimens) { + it(`${id}: shared listing, validation, tool-capable engine, native modality, and zero cost`, async () => { + const before = process.env; + const originalFetch = globalThis.fetch; + process.env = { NODE_ENV: "test", HOME: "/nonexistent/free-catalog", OPENROUTER_API_KEY: "dummy-free-catalog" }; + try { + const catalog = modelCatalog(); + const listed = catalog.models.find((m) => m.provider === "openrouter" && m.id === id); + assert.ok(listed); + assert.deepEqual(listed.input, input); + assert.deepEqual(listed.cost, { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }); + const model = { provider: "openrouter", id }; + assert.deepEqual(validateChatSettings({ model }), { ok: true }); + assert.deepEqual(validateModelsSettings({ strong: { model }, cheap: { model } }), { ok: true }); + assert.equal(validateModelsSettings({ vision: { model } }).ok, true, "server catalog validation stays provider/model based; vision filtering belongs to the picker"); + assert.equal(catalog.models.filter((m) => m.input.includes("image")).some((m) => m.provider === "openrouter" && m.id === id), input.includes("image")); + const engine = piEngineForSpec(model); + assert.equal(engine.model, piModels().getModel("openrouter", id)); + assert.equal(engine.model.api, "openai-completions"); + assert.deepEqual(engine.model.input, input); + assert.equal(callCost({ inputTokens: 1_000_000, outputTokens: 500_000, cacheReadTokens: 100_000, cacheWriteTokens: 50_000 }, `openrouter:${id}`), 0); + let payload: Record | undefined; + globalThis.fetch = async (input, init) => { + const request = new Request(input, init); + assert.equal(new URL(request.url).origin, "https://openrouter.ai"); + assert.equal(request.headers.get("authorization"), "Bearer dummy-free-catalog"); + payload = JSON.parse(await request.text()); + return new Response("{}", { status: 400, headers: { "content-type": "application/json" } }); + }; + await engine.streamFn(engine.model, normalizeContext({ messages: [{ role: "user", content: "offline", timestamp: 1 }], tools: [{ name: "offline_tool", description: "offline", parameters: Type.Object({}) }] }), { sessionId: "chat_free_offline" }).result(); + assert.equal(payload?.model, id); + assert.match(JSON.stringify(payload?.tools), /offline_tool/); + delete process.env.OPENROUTER_API_KEY; + assert.ok(!modelCatalog().models.some((m) => m.provider === "openrouter"), "even free models retain the provider key gate"); + } finally { process.env = before; globalThis.fetch = originalFetch; } + }); + } + it("removed/unknown native models remain unpriced and unresolvable, never aliased to a paid fallback", () => { + assert.equal(callCost({ inputTokens: 1, outputTokens: 1 }, "openrouter:removed/no-such-model"), null); + assert.throws(() => piEngineForSpec({ provider: "openrouter", id: "removed/no-such-model" }), /catalog has no model/); + }); +}); diff --git a/tests/provider-neutral-agents.test.ts b/tests/provider-neutral-agents.test.ts index 14b930b..8e4014e 100644 --- a/tests/provider-neutral-agents.test.ts +++ b/tests/provider-neutral-agents.test.ts @@ -14,7 +14,7 @@ import { type JsonObject, type TranscriptContext, type Usage, } from "@earendil-works/pi-ai"; import { builtinProviders } from "@earendil-works/pi-ai/providers/all"; -import { piEngineForSpec, type PiEngine } from "../src/agent/models.ts"; +import { APP_IDENTITY, piEngineForSpec, type PiEngine } from "../src/agent/models.ts"; import { runVisualMaker } from "../src/agent/subagents/visual-maker.ts"; import { runPdfReaderAgent } from "../src/agent/subagents/pdf-reader.ts"; import type { HeadlessApi } from "../src/agent/subagents/headless.ts"; @@ -35,6 +35,10 @@ interface Transport { origin: string; path: string; authHeader: string; } const TRANSPORTS: Transport[] = [ + { provider: "opencode-go", id: "claude-haiku-5-5", envVar: "OPENCODE_API_KEY", api: "anthropic-messages", origin: "https://opencode.ai", path: "/inference/go/v1/messages", authHeader: "x-api-key" }, + { provider: "opencode-go", id: "gemini-4-argon-contributor", envVar: "OPENCODE_API_KEY", api: "google-generative-ai", origin: "https://opencode.ai", path: "/inference/go/v1/models/gemini-4-argon-contributor:streamGenerateContent", authHeader: "x-goog-api-key" }, + { provider: "opencode-go", id: "glm-5.3", envVar: "OPENCODE_API_KEY", api: "openai-completions", origin: "https://opencode.ai", path: "/inference/go/v1/chat/completions", authHeader: "authorization" }, + { provider: "opencode-go", id: "gpt-6-luna", envVar: "OPENCODE_API_KEY", api: "openai-responses", origin: "https://opencode.ai", path: "/inference/go/v1/responses", authHeader: "authorization" }, { provider: "openrouter", id: "openai/gpt-4o-mini", envVar: "OPENROUTER_API_KEY", api: "openai-completions", origin: "https://openrouter.ai", path: "/api/v1/chat/completions", authHeader: "authorization" }, { provider: "openai", id: "gpt-4o-mini", envVar: "OPENAI_API_KEY", api: "openai-responses", origin: "https://api.openai.com", path: "/v1/responses", authHeader: "authorization" }, { provider: "anthropic", id: "claude-haiku-4-5", envVar: "ANTHROPIC_API_KEY", api: "anthropic-messages", origin: "https://api.anthropic.com", path: "/v1/messages", authHeader: "x-api-key" }, @@ -131,7 +135,7 @@ describe("provider-neutral raw agent loops", { concurrency: false }, () => { it(`${loop}: every actual stream request has NO credential override (recording faux engine)`, async () => { await isolated({ OPENROUTER_API_KEY: OR_KEY, LH_PROVIDER_EVENTS: "1" }, async () => { const faux = createFauxCore({ tokenSize: { min: 64, max: 64 } }); - faux.setResponses([0, 1, 2].map((round) => { + faux.setResponses([0, 1, 2, 0, 1, 2].map((round) => { const calls = callsFor(loop, round); return fauxAssistantMessage(calls.length ? calls.map((c, i) => fauxToolCall(c.name, c.args, { id: `call_${round}_${i}` })) @@ -149,7 +153,11 @@ describe("provider-neutral raw agent loops", { concurrency: false }, () => { const run = await runLoop(loop, engine, signal); assertSuccess(loop, run); assert.equal(requests.length, 3); + const sessionId = requests[0]!.options.sessionId; + assert.match(String(sessionId), /^[0-9a-f-]{36}$/); + assert.notEqual(sessionId, "provider-neutral-offline"); for (const { options } of requests) { + assert.equal(options.sessionId, sessionId); for (const key of ["apiKey", "getApiKey", "auth", "headers"]) { assert.ok(!Object.hasOwn(options, key), `${loop} stream must not supply ${key}`); } @@ -159,6 +167,12 @@ describe("provider-neutral raw agent loops", { concurrency: false }, () => { } assert.match(JSON.stringify(requests[2]!.context), /image\/png/); assert.match(JSON.stringify(requests[2]!.context), /toolResult/); + const second = await runLoop(loop, engine, signal); + assertSuccess(loop, second); + assert.equal(requests.length, 6); + const secondId = requests[3]!.options.sessionId; + assert.notEqual(secondId, sessionId, "a separate unsaved operation must not reuse a conversation"); + for (const request of requests.slice(3)) assert.equal(request.options.sessionId, secondId); }); }); @@ -189,6 +203,12 @@ describe("provider-neutral raw agent loops", { concurrency: false }, () => { assertSuccess(loop, run); assert.equal(requests.length, 3); for (const [round, request] of requests.entries()) { + assert.equal(request.headers.get("user-agent"), APP_IDENTITY.userAgent.custom); + if (transport.provider === "opencode-go") { + assert.match(request.headers.get("x-opencode-session") ?? "", /^[0-9a-f-]{36}$/); + assert.equal(request.headers.get("x-opencode-session"), requests[0]!.headers.get("x-opencode-session")); + assert.equal(request.headers.get("x-opencode-client"), "learnharness"); + } const url = new URL(request.url); assert.equal(url.origin, transport.origin); assert.equal(url.pathname, transport.path); @@ -263,29 +283,32 @@ function closedFetch(transport: Transport, loop: Loop, requests: RecordedRequest } function assertPayload(transport: Transport, loop: Loop, round: number, body: Record) { - if (transport.provider !== "google") assert.equal(body.model, transport.id); - const tools = JSON.stringify(body.tools); + if (transport.api !== "google-generative-ai") assert.equal(body.model, transport.id); + // Native Responses models may declare tools in additional_tools input + // items rather than top-level tools; assert the SDK's complete payload. + const tools = JSON.stringify(body); assert.match(tools, new RegExp(loop === "visual" ? "write_svg" : "pdf_extract")); assert.match(tools, new RegExp(loop === "visual" ? "render_svg" : "pdf_render")); - if (transport.provider === "google") assert.ok(Array.isArray(body.contents)); - else if (transport.provider === "openai") assert.ok(Array.isArray(body.input)); + if (transport.api === "google-generative-ai") assert.ok(Array.isArray(body.contents)); + else if (transport.api === "openai-responses") assert.ok(Array.isArray(body.input)); else assert.ok(Array.isArray(body.messages)); const json = JSON.stringify(body); assert.match(json, new RegExp(loop === "visual" ? "white square" : "Read page 1")); if (round === 2) { - assert.ok(json.includes(PNG.toString("base64")), "the actual rendered image must reach the selected provider"); - assert.match(json, new RegExp(transport.provider === "google" ? "functionResponse" : transport.provider === "openai" ? "function_call_output" : transport.provider === "anthropic" ? "tool_result" : '"role":"tool"')); + const supportsImages = piEngineForSpec({ provider: transport.provider, id: transport.id }).model.input.includes("image"); + assert.equal(json.includes(PNG.toString("base64")), supportsImages, "native modality filtering: only vision models receive rendered images"); + assert.match(json, new RegExp(transport.api === "google-generative-ai" ? "functionResponse" : transport.api === "openai-responses" ? "function_call_output" : transport.api === "anthropic-messages" ? "tool_result" : '"role":"tool"')); assert.match(json, new RegExp(loop === "visual" ? "Rendered" : "Page 1")); } } function sseResponse(transport: Transport, calls: Call[], round: number): Response { const events: Record[] = []; - if (transport.provider === "openrouter") { + if (transport.api === "openai-completions") { events.push({ id: `chatcmpl_offline_${round}`, object: "chat.completion.chunk", created: 1, model: transport.id, choices: [{ index: 0, delta: calls.length ? { role: "assistant", tool_calls: calls.map((c, i) => ({ index: i, id: `call_${round}_${i}`, type: "function", function: { name: c.name, arguments: JSON.stringify(c.args) } })) } : { role: "assistant", content: FINAL }, finish_reason: null }] }); events.push({ choices: [{ index: 0, delta: {}, finish_reason: calls.length ? "tool_calls" : "stop" }], usage: { prompt_tokens: 20, completion_tokens: 10, total_tokens: 30 } }); - } else if (transport.provider === "openai") { + } else if (transport.api === "openai-responses") { const output = calls.length ? calls.map((c, i) => ({ type: "function_call", id: `fc_${round}_${i}`, call_id: `call_${round}_${i}`, name: c.name, arguments: JSON.stringify(c.args), status: "completed" })) : [{ type: "message", id: `msg_${round}`, role: "assistant", status: "completed", content: [{ type: "output_text", text: FINAL, annotations: [] }] }]; events.push({ type: "response.created", response: { id: `resp_offline_${round}`, status: "in_progress" } }); @@ -297,7 +320,7 @@ function sseResponse(transport: Transport, calls: Call[], round: number): Respon events.push({ type: "response.output_item.done", output_index: index, item }); } events.push({ type: "response.completed", response: { id: `resp_offline_${round}`, status: "completed", output, usage: { input_tokens: 20, output_tokens: 10, total_tokens: 30 } } }); - } else if (transport.provider === "anthropic") { + } else if (transport.api === "anthropic-messages") { events.push({ type: "message_start", message: { id: `msg_offline_${round}`, type: "message", role: "assistant", model: transport.id, content: [], stop_reason: null, usage: { input_tokens: 20, output_tokens: 0 } } }); const blocks = calls.length ? calls.map((c, i) => ({ type: "tool_use", id: `call_${round}_${i}`, name: c.name, input: {} })) : [{ type: "text", text: "" }]; for (const [index, block] of blocks.entries()) { @@ -310,6 +333,6 @@ function sseResponse(transport: Transport, calls: Call[], round: number): Respon } else { events.push({ responseId: `google_offline_${round}`, candidates: [{ index: 0, content: { role: "model", parts: calls.length ? calls.map((c, i) => ({ functionCall: { id: `call_${round}_${i}`, name: c.name, args: c.args } })) : [{ text: FINAL }] }, finishReason: "STOP" }], usageMetadata: { promptTokenCount: 20, candidatesTokenCount: 10, totalTokenCount: 30 } }); } - const data = events.map((event) => `${typeof event.type === "string" ? `event: ${event.type}\n` : ""}data: ${JSON.stringify(event)}\n\n`).join("") + (transport.provider === "openrouter" ? "data: [DONE]\n\n" : ""); + const data = events.map((event) => `${typeof event.type === "string" ? `event: ${event.type}\n` : ""}data: ${JSON.stringify(event)}\n\n`).join("") + (transport.api === "openai-completions" ? "data: [DONE]\n\n" : ""); return new Response(data, { status: 200, headers: { "content-type": "text/event-stream" } }); } diff --git a/tests/session-identity.test.ts b/tests/session-identity.test.ts new file mode 100644 index 0000000..d011b5f --- /dev/null +++ b/tests/session-identity.test.ts @@ -0,0 +1,192 @@ +import assert from "node:assert/strict"; +import { describe, it } from "node:test"; +import { Type } from "typebox"; +import { createFauxCore, fauxAssistantMessage, fauxText, fauxToolCall, normalizeContext, type Model, type SimpleStreamOptions } from "@earendil-works/pi-ai"; +import { streamSimple as streamCodex } from "@earendil-works/pi-ai/api/openai-codex-responses"; +import { APP_IDENTITY, piEngineForSpec, type PiEngine } from "../src/agent/models.ts"; +import { createProberAgent, createTeacherAgent, createPracticeAgent, type AgentBuildOptions } from "../src/agent/teacher-agent.ts"; +import { runSubagent } from "../src/agent/subagents/pi-run.ts"; +import { healToolRecord } from "../src/agent/tools/heal.ts"; +import metadata from "../package.json" with { type: "json" }; + +const factories = [ + (opts: AgentBuildOptions) => createProberAgent({ chatId: opts.chatId, searchAvailable: () => false } as never, opts), + (opts: AgentBuildOptions) => createTeacherAgent(undefined, opts), + (opts: AgentBuildOptions) => createPracticeAgent({} as never, opts), +]; + +function recordingEngine() { + const faux = createFauxCore({}); + faux.setResponses([fauxAssistantMessage([fauxToolCall("again", {}, { id: "call_0" })], { stopReason: "toolUse" }), { ...fauxAssistantMessage([fauxText("done")]), durationMs: 42 }]); + const requests: SimpleStreamOptions[] = []; + const engine: PiEngine = { model: faux.getModel(), streamFn: (model, context, options) => { + requests.push(options ?? {}); + return faux.streamSimple(model, context, options); + } }; + return { engine, requests }; +} +const again = { name: "again", label: "again", description: "Continue", parameters: Type.Object({}), execute: async () => ({ content: [{ type: "text" as const, text: "ok" }], details: {} }) }; + +// Whole-process replacement isolates native auth/profile discovery; fetch never +// delegates. No real credentials, .env, OAuth accounts, or model inference. +async function closed(run: () => Promise): Promise { + const env = process.env; + const fetch = globalThis.fetch; + process.env = { NODE_ENV: "test", HOME: "/nonexistent/session-identity", OPENROUTER_API_KEY: "dummy-router", OPENCODE_API_KEY: "dummy-go", OPENAI_API_KEY: "dummy-openai" }; + globalThis.fetch = async () => { throw new Error("CLOSED: unexpected fetch"); }; + try { return await run(); } finally { process.env = env; globalThis.fetch = fetch; } +} + +describe("native app and conversation identity", { concurrency: false }, () => { + it("shares one deeply frozen metadata-derived identity, without mutable conversation state", () => { + assert.deepEqual(APP_IDENTITY, { userAgent: { custom: `learnharness/${metadata.version}` }, attribution: { name: metadata.name, url: metadata.homepage } }); + for (const value of [APP_IDENTITY, APP_IDENTITY.userAgent, APP_IDENTITY.attribution]) assert.ok(Object.isFrozen(value)); + assert.ok(!Object.hasOwn(APP_IDENTITY, "sessionId")); + }); + + it("reconstructed prober/teacher/practice Agents reuse the exact chat id across tool rounds", async () => { + for (const chatId of ["chat_exact_native_123", "chat_independent_456"]) { + for (const factory of factories) { + const { engine, requests } = recordingEngine(); + const agent = factory({ engine, chatId, tools: { again } }); + assert.equal(agent.identity, APP_IDENTITY); + assert.equal(agent.sessionId, chatId); + await agent.prompt("offline"); + assert.equal(requests.length, 2); + for (const options of requests) { + assert.equal(options.sessionId, chatId); + assert.deepEqual(options.identity, APP_IDENTITY); + assert.ok(options.signal instanceof AbortSignal); + assert.equal(options.apiKey, undefined); + } + } + } + }); + + it("separate extractor/auditor/compaction invocations own distinct stable unsaved conversations", async () => { + const ids = new Set(); + // Compaction uses the shared runner with the researcher role. + for (const role of ["extractor", "auditor", "researcher"] as const) { + const { engine, requests } = recordingEngine(); + let usage = 0; + const result = await runSubagent([again], { role, engine, chatId: "chat_shared_debug_only", systemPrompt: "offline", prompt: "offline", maxTurns: 3, onUsage: () => usage++ }); + assert.equal(requests.length, 2); + assert.equal(usage, 2); + const id = requests[0]!.sessionId; + assert.match(id ?? "", /^[0-9a-f-]{36}$/); + assert.notEqual(id, "chat_shared_debug_only"); + assert.ok(!ids.has(id)); + ids.add(id); + for (const options of requests) { assert.equal(options.sessionId, id); assert.deepEqual(options.identity, APP_IDENTITY); } + assert.ok(result.newMessages.some((m) => m.role === "toolResult" && typeof m.durationMs === "number"), "new native tool duration fields are preserved"); + assert.ok(result.newMessages.some((m) => m.role === "assistant" && typeof m.durationMs === "number"), "new native assistant duration fields are preserved"); + } + }); + + for (const [provider, id, endpoint] of [ + ["opencode-go", "claude-haiku-5-5", "/inference/go/v1/messages"], + ["opencode-go", "gemini-4-argon-contributor", "/inference/go/v1/models/gemini-4-argon-contributor:streamGenerateContent"], + ["opencode-go", "glm-5.3", "/inference/go/v1/chat/completions"], + ["opencode-go", "gpt-6-luna", "/inference/go/v1/responses"], + ["openrouter", "openrouter/free", "/api/v1/chat/completions"], + ] as const) { + it(`complete native ${provider}/${id} foreground serialization carries app identity and exact sessions`, async () => closed(async () => { + const engine = piEngineForSpec({ provider, id, thinkingLevel: "off" }); + const requests: Request[] = []; + globalThis.fetch = async (input, init) => { const request = new Request(input, init); requests.push(request); await request.text(); return new Response('{"error":{"message":"closed fixture"}}', { status: 400, headers: { "content-type": "application/json" } }); }; + for (const factory of factories) await factory({ engine, chatId: "chat_wire_exact", tools: {} }).prompt("offline"); + assert.equal(requests.length, 3); + for (const request of requests) { + assert.equal(new URL(request.url).pathname, endpoint); + assert.equal(request.headers.get("user-agent"), `learnharness/${metadata.version}`); + if (provider === "opencode-go") { + assert.equal(new URL(request.url).origin, "https://opencode.ai"); + assert.equal(request.headers.get("x-opencode-client"), metadata.name); + assert.equal(request.headers.get("x-opencode-session"), "chat_wire_exact"); + assert.ok(!JSON.stringify(Object.fromEntries(request.headers)).includes("dummy-router")); + } else { + assert.equal(new URL(request.url).origin, "https://openrouter.ai"); + assert.equal(request.headers.get("x-openrouter-title"), metadata.name); + assert.equal(request.headers.get("http-referer"), metadata.homepage); + assert.equal(request.headers.get("x-session-id"), "chat_wire_exact"); + } + } + })); + } + + it("native OpenAI cache keys clamp to 64 characters while affinity retains exact session", async () => closed(async () => { + const engine = piEngineForSpec({ provider: "openai", id: "gpt-4o-mini", thinkingLevel: "off" }); + const sessionId = "chat_" + "a".repeat(70); + let body: Record = {}; + let headers = new Headers(); + globalThis.fetch = async (input, init) => { const request = new Request(input, init); headers = request.headers; body = JSON.parse(await request.text()); return new Response("{}", { status: 400, headers: { "content-type": "application/json" } }); }; + await createTeacherAgent(undefined, { engine, chatId: sessionId, tools: {} }).prompt("offline"); + assert.equal(body.prompt_cache_key, Array.from(sessionId).slice(0, 64).join("")); + assert.equal(headers.get("session_id"), sessionId); + })); + + it("native OpenAI cache-key clamp counts Unicode code points, not UTF-16 units", async () => closed(async () => { + const engine = piEngineForSpec({ provider: "openai", id: "gpt-4o-mini", thinkingLevel: "off" }); + const sessionId = "chat_" + "😀".repeat(70); + let payload: unknown; + // HTTP affinity headers cannot encode emoji. Observe native payload + // serialization before transport, then stop deliberately (no accounts). + await engine.streamFn(engine.model, normalizeContext({ messages: [{ role: "user", content: "offline", timestamp: 1 }] }), { + sessionId, + onPayload: (value) => { payload = value; throw new Error("CLOSED: payload captured"); }, + }).result(); + assert.equal((payload as { prompt_cache_key: string }).prompt_cache_key, Array.from(sessionId).slice(0, 64).join("")); + })); + + it("native Codex serialization shares the 64-code-point clamp without an account or OAuth flow", async () => closed(async () => { + const engine = piEngineForSpec({ provider: "openai-codex", id: "gpt-6-luna", thinkingLevel: "off" }); + // Synthetic, unsigned fixture token solely satisfies native local claim + // decoding. Stop at payload capture: no account, OAuth, or fetch. + const claims = { "https://api.openai.com/auth": { chatgpt_account_id: "offline-fixture" } }; + const apiKey = `dummy.${Buffer.from(JSON.stringify(claims)).toString("base64url")}.dummy`; + for (const sessionId of ["chat_" + "a".repeat(70), "chat_" + "😀".repeat(70)]) { + let payload: unknown; + // The app intentionally has no Codex auth row: exercise the native + // serializer directly rather than adding an OAuth configuration path. + assert.equal(engine.model.api, "openai-codex-responses"); + const result = await streamCodex(engine.model as Model<"openai-codex-responses">, normalizeContext({ messages: [{ role: "user", content: "offline", timestamp: 1 }] }), { + apiKey, sessionId, identity: APP_IDENTITY, + onPayload: (value) => { payload = value; throw new Error("CLOSED: payload captured"); }, + }).result(); + assert.ok(payload, result.errorMessage); + assert.equal((payload as { prompt_cache_key: string }).prompt_cache_key, Array.from(sessionId).slice(0, 64).join("")); + } + })); + + it("SDK native header precedence and cache-off behavior remain untouched", async () => closed(async () => { + const engine = piEngineForSpec({ provider: "opencode-go", id: "gpt-6-luna", thinkingLevel: "off" }); + let headers = new Headers(); + let body: Record = {}; + globalThis.fetch = async (input, init) => { const request = new Request(input, init); headers = request.headers; body = JSON.parse(await request.text()); return new Response("{}", { status: 400, headers: { "content-type": "application/json" } }); }; + await engine.streamFn(engine.model, normalizeContext({ messages: [{ role: "user", content: "offline", timestamp: 1 }] }), { sessionId: "chat_cache_off", cacheRetention: "none", headers: { "user-agent": "explicit-sdk-override", "x-opencode-client": null } }).result(); + assert.equal(headers.get("user-agent"), "explicit-sdk-override"); + assert.equal(headers.get("x-opencode-client"), null); + // Native OpenCode routing identity remains even with cache retention off. + assert.equal(headers.get("x-opencode-session"), "chat_cache_off"); + assert.equal(body.prompt_cache_key, undefined); + })); + + it("completed malformed native JSON stays rejected despite app prepareArguments healing", async () => closed(async () => { + const engine = piEngineForSpec({ provider: "openrouter", id: "openai/gpt-4o-mini", thinkingLevel: "off" }); + const malformed = '{"value":'; + globalThis.fetch = async () => new Response(`data: ${JSON.stringify({ id: "offline", choices: [{ index: 0, delta: { tool_calls: [{ index: 0, id: "call_bad", type: "function", function: { name: "check", arguments: malformed } }] }, finish_reason: null }] })}\n\ndata: ${JSON.stringify({ choices: [{ index: 0, delta: {}, finish_reason: "tool_calls" }] })}\n\ndata: [DONE]\n\n`, { headers: { "content-type": "text/event-stream" } }); + let executed = 0; + let prepared = 0; + const tools = healToolRecord({ check: { name: "check", label: "check", description: "check", parameters: Type.Object({ value: Type.Optional(Type.String()) }), execute: async () => { executed++; return { content: [], details: {} }; } } }); + const heal = tools.check!.prepareArguments!; + tools.check!.prepareArguments = (args) => { prepared++; return heal(args); }; + const result = await runSubagent(Object.values(tools), { role: "extractor", engine, systemPrompt: "offline", prompt: "offline", maxTurns: 1 }); + const assistant = result.newMessages.find((m) => m.role === "assistant"); + assert.ok(assistant?.role === "assistant"); + const call = assistant.content.find((c) => c.type === "toolCall"); + assert.ok(call?.type === "toolCall" && call.argumentsError); + assert.equal(executed, 0); + assert.equal(prepared, 1, "SDK prepares arguments but preserves argumentsError for native validation"); + assert.ok(result.newMessages.some((m) => m.role === "toolResult" && m.isError)); + })); +}); diff --git a/tests/usage.test.ts b/tests/usage.test.ts index 91d27c5..ad23efe 100644 --- a/tests/usage.test.ts +++ b/tests/usage.test.ts @@ -51,11 +51,11 @@ test("callCost: glm-5.3-flash math — fresh input, cached read, output", () => test("callCost: cache writes bill at the cacheWrite rate", () => { const cost = callCost( call({ inputTokens: 1_000_000, outputTokens: 0, cacheWriteTokens: 500_000 }), - "openrouter:qwen/qwen3.8-max-0902", + "anthropic:claude-haiku-4-5", ); assert.ok(cost !== null); - // fresh 1M @ $2/M + cache write 500k @ $2.5/M - assert.ok(Math.abs(cost! - (2 + 1.25)) < 1e-9); + // Native 1.4 catalog: fresh 1M @ $1/M + cache write 500k @ $1.25/M. + assert.ok(Math.abs(cost! - (1 + 0.625)) < 1e-9); }); test("callCost: unknown model and absent fields are null, never zero", () => {