Compare commits

...
Author SHA1 Message Date
Time Attakc 95d623c748 Merge branch 'master' into build/embedding-price-refresh 2026-08-01 03:27:30 +08:00
Garry TanandClaude Opus 5 73b443cf05 fix(pricing): correct voyage-4-large rate and add the missing voyage-4 family entries
voyage-4-large was priced at $0.18/Mtok — the voyage-3-large rate. The
actual published rate is $0.12, so every Voyage budget estimate and spend
guard over-charged by 50%. voyage-4 and voyage-4-lite were absent entirely,
so they fell through to "estimate unavailable" despite being first-class
models in the Voyage recipe.

All entries re-verified against their official pricing pages on 2026-07-28;
each now carries its source URL plus the date it was last read. Only Voyage
had drifted — OpenAI, Mistral, Perplexity and ZeroEntropy all matched.

voyage-4-nano stays deliberately unpriced: it's the open-weight variant with
no published hosted rate, and a fabricated 0 would under-charge anyone
running it through Voyage's hosted API. No entry means callers print
"estimate unavailable" instead of a wrong number.

Embedding prices stay confined to embedding-pricing.ts; the chat/completion
table in model-pricing.ts is untouched (different unit).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 00:22:31 -07:00
4 changed files with 41 additions and 17 deletions
File diff suppressed because one or more lines are too long
+4 -2
View File
@@ -37,8 +37,10 @@ export const voyage: Recipe = {
'voyage-multimodal-3',
],
default_dims: 1024,
cost_per_1m_tokens_usd: 0.18,
price_last_verified: '2026-04-20',
// Display hint for `gbrain providers` only (billing math goes through
// src/core/embedding-pricing.ts). Rate for the default voyage-4-large.
cost_per_1m_tokens_usd: 0.12,
price_last_verified: '2026-07-28',
// Voyage enforces 120K tokens per batch. Voyage's tokenizer runs
// ~3-4× denser than OpenAI tiktoken on mixed content (code/JSON/CJK),
// so the per-recipe pre-split uses 1 char ≈ 1 token at 0.5 utilization
+22 -11
View File
@@ -5,12 +5,15 @@
* cost-estimate prompt so users with large brains see a dollar figure
* before the chunker-version sweep re-embeds.
*
* Prices in USD per 1M tokens. Numbers as of 2026-05-11. Verify alongside
* the Anthropic-pricing refresh cycle; drift here produces estimates
* that mislead operators.
* Prices in USD per 1M tokens. Every entry carries the official page it came
* from plus the date it was last read against that page — re-verify alongside
* the Anthropic-pricing refresh cycle; drift here produces estimates that
* mislead operators. This table is for EMBEDDINGS only; chat/completion
* pricing lives in `model-pricing.ts` (different unit) and must never be
* mixed in here.
*
* Codex outside-voice C3 fold: non-OpenAI embedding providers (Voyage,
* Hunyuan, Dashscope, etc.) return UNKNOWN_PROVIDER from `lookupPrice`
* Codex outside-voice C3 fold: embedding providers with no entry below
* (Hunyuan, Dashscope, etc.) return UNKNOWN_PROVIDER from `lookupPrice`
* so the cost-estimate prompt can fall back to a "estimate unavailable
* for <provider>; press Ctrl-C in 10s to abort" message rather than
* fabricate numbers.
@@ -26,25 +29,33 @@ export interface EmbeddingPricing {
* gateway model strings (e.g. 'openai:text-embedding-3-large').
*/
export const EMBEDDING_PRICING: Record<string, EmbeddingPricing> = {
// OpenAI (https://openai.com/api/pricing/, verified 2026-05-11)
// OpenAI (https://developers.openai.com/api/docs/pricing, verified 2026-07-28)
'openai:text-embedding-3-large': { pricePerMTok: 0.13 },
'openai:text-embedding-3-small': { pricePerMTok: 0.02 },
// Legacy OpenAI ada (still common in older brains)
'openai:text-embedding-ada-002': { pricePerMTok: 0.10 },
// Voyage (https://www.voyageai.com/pricing)
// Voyage (https://docs.voyageai.com/docs/pricing, verified 2026-07-28)
'voyage:voyage-4-large': { pricePerMTok: 0.12 },
'voyage:voyage-4': { pricePerMTok: 0.06 },
'voyage:voyage-4-lite': { pricePerMTok: 0.02 },
// voyage-4-nano is deliberately absent: it's the open-weight variant (see
// src/core/ai/recipes/voyage.ts) and Voyage's pricing page lists no hosted
// rate for it. A 0 entry would under-estimate anyone paying for it via the
// hosted API; no entry means lookupEmbeddingPrice returns `unknown` and the
// caller prints "estimate unavailable" instead of a wrong number.
// Legacy Voyage models (same page, "older models" section — no free tokens):
'voyage:voyage-3-large': { pricePerMTok: 0.18 },
'voyage:voyage-3': { pricePerMTok: 0.06 },
'voyage:voyage-4-large': { pricePerMTok: 0.18 },
// ZeroEntropy (https://zeroentropy.dev/pricing — zembed-1)
// ZeroEntropy (https://www.zeroentropy.dev/pricing, verified 2026-07-28)
'zeroentropyai:zembed-1': { pricePerMTok: 0.05 },
// ZeroEntropy reranker (docs/ai-providers/zeroentropy.md — $0.025/1M tokens).
// Reused here (not a separate rerank table) because budget-tracker.ts's
// rerank-kind lookup falls back to this same table for paid providers.
'zeroentropyai:zerank-2': { pricePerMTok: 0.025 },
// Mistral (https://mistral.ai/pricing/api/, verified 2026-07-19)
// Mistral (https://mistral.ai/pricing/api/, verified 2026-07-28)
'mistral:mistral-embed': { pricePerMTok: 0.10 },
'mistral:mistral-embed-2312': { pricePerMTok: 0.10 },
// Perplexity (https://docs.perplexity.ai/getting-started/pricing, verified 2026-07-21)
// Perplexity (https://docs.perplexity.ai/getting-started/pricing, verified 2026-07-28)
'perplexity:pplx-embed-v1-0.6b': { pricePerMTok: 0.004 },
'perplexity:pplx-embed-v1-4b': { pricePerMTok: 0.03 },
};
+14 -3
View File
@@ -26,10 +26,21 @@ describe('lookupEmbeddingPrice — first-class providers', () => {
if (r.kind === 'known') expect(r.pricePerMTok).toBe(0.18);
});
test('Voyage voyage-4-large at $0.18/MTok (v0.35.1.0+)', () => {
const r = lookupEmbeddingPrice('voyage:voyage-4-large');
// Voyage v4 family, verified against docs.voyageai.com/docs/pricing 2026-07-28.
test.each([
['voyage:voyage-4-large', 0.12],
['voyage:voyage-4', 0.06],
['voyage:voyage-4-lite', 0.02],
])('Voyage %s at $%d/MTok', (model, expected) => {
const r = lookupEmbeddingPrice(model);
expect(r.kind).toBe('known');
if (r.kind === 'known') expect(r.pricePerMTok).toBe(0.18);
if (r.kind === 'known') expect(r.pricePerMTok).toBe(expected);
});
// voyage-4-nano is the open-weight variant with no hosted rate published;
// it must stay unpriced so callers say "estimate unavailable" (see table comment).
test('voyage-4-nano is deliberately unpriced', () => {
expect(lookupEmbeddingPrice('voyage:voyage-4-nano').kind).toBe('unknown');
});
test('ZeroEntropy zembed-1 at $0.05/MTok (v0.35.1.0+)', () => {