diff --git a/CHANGELOG.md b/CHANGELOG.md index ebe24d15e..2d239a185 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [1.91.100.0] - 2026-10-13 + +**A gbrain LongMemEval call plan now prices in full.** gbrain's `eval longmemeval --call-plan` (gbrain#6638) writes a `GSTACK_EVAL_CALLS` file for every lane of the run. `gstack-eval-plan price-gate` verified its binding but stopped at `EVAL_PRICE_MISSING` with the total unknown: it had no row for the judge (`gpt-4o`) or the reranker (`rerank-2.5`), and it did not recognize the dated Claude id gbrain resolves (`claude-haiku-4-5-20251001`). On the gbrain fixture plan (`--mode tokenmax --judge`) all seven lanes now price, for a total of $0.447. + +### What this means for you + +- **Dated Claude snapshots bill at their alias's price.** `claude--YYYYMMDD`, with or without a provider prefix, resolves to the `claude-` row. Dated OpenAI snapshots are not folded, because some (`gpt-4o-2024-05-13`) have their own price. +- **New rows, sourced and dated in `lib/pricing.ts`:** `gpt-4o` ($2.50 in, $10 out, $1.25 cached per million tokens) and the Voyage rerankers `rerank-2.5` ($0.05) and `rerank-2.5-lite` ($0.02 per million processed tokens: query tokens × documents, plus document tokens). + +### For contributors + +- `test/pricing-eval-plan.test.ts` checks every model a gbrain call plan names. It failed before the change. + ## [1.91.99.0] - 2026-10-13 **A Bun pin mismatch on Capy now names the one command that fixes it, and the skill says to run it.** After gbrain pinned Bun 1.4.3 in CI, a session-start check on a gbrain checkout ended `gstack: fail pins` with a fix line that offered two choices and no command, and the skill's repair step only covered `revision` and `runtime`, so an agent following the skill left the machine failing. The same bootstrapper run without `--check` already installs the pinned Bun (a verified 1.4.3 in about 4 s) and ends `gstack: ok`. diff --git a/VERSION b/VERSION index c2ce38c56..eb0c32a12 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.99.0 +1.91.100.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index 1d59dbb9e..4d99220ae 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.99.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.100.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/lib/pricing.ts b/lib/pricing.ts index c3d547399..3fd3a3421 100644 --- a/lib/pricing.ts +++ b/lib/pricing.ts @@ -21,7 +21,7 @@ * - Anthropic: https://www.anthropic.com/pricing#api * - OpenAI: https://openai.com/api/pricing/ * - Google AI: https://ai.google.dev/gemini-api/docs/pricing - * - Voyage AI (embeddings): https://docs.voyageai.com/docs/pricing + * - Voyage AI (embeddings, rerankers): https://docs.voyageai.com/docs/pricing */ export interface ModelPricing { @@ -59,6 +59,9 @@ export const PRICING: Record = { // https://developers.openai.com/api/docs/models/gpt-6.1-sol (standard tier, up to 272K input) 'gpt-6.1-sol': { input_per_mtok: 2.00, output_per_mtok: 10.00, cached_input_per_mtok: 0.10, as_of: '2026-10' }, 'gpt-5.4': { input_per_mtok: 2.50, output_per_mtok: 10.00, as_of: '2026-04' }, + // https://developers.openai.com/api/docs/models/gpt-4o (fetched 2026-10-13; gbrain's LongMemEval judge, the official scorer's model; + // the alias only: the gpt-4o-2024-05-13 snapshot has its own price) + 'gpt-4o': { input_per_mtok: 2.50, output_per_mtok: 10.00, cached_input_per_mtok: 1.25, as_of: '2026-10' }, 'gpt-5.4-mini': { input_per_mtok: 0.60, output_per_mtok: 2.40, as_of: '2026-04' }, 'o3': { input_per_mtok: 15.00, output_per_mtok: 60.00, as_of: '2026-04' }, 'o4-mini': { input_per_mtok: 1.10, output_per_mtok: 4.40, as_of: '2026-04' }, @@ -89,6 +92,9 @@ export const EMBEDDING_PRICING: Record = { 'voyage-code-3': { input_per_mtok: 0.18, output_per_mtok: 0, as_of: '2026-10' }, 'voyage-3-large': { input_per_mtok: 0.18, output_per_mtok: 0, as_of: '2026-10' }, 'voyage-multimodal-3': { input_per_mtok: 0.12, output_per_mtok: 0, as_of: '2026-10' }, // text tokens; pixels excluded + // https://docs.voyageai.com/docs/pricing (fetched 2026-10-13; rerankers bill query tokens x documents plus document tokens) + 'rerank-2.5': { input_per_mtok: 0.05, output_per_mtok: 0, as_of: '2026-10' }, + 'rerank-2.5-lite': { input_per_mtok: 0.02, output_per_mtok: 0, as_of: '2026-10' }, // https://developers.openai.com/api/docs/pricing (fetched 2026-10-12) 'text-embedding-3-large': { input_per_mtok: 0.13, output_per_mtok: 0, as_of: '2026-10' }, 'text-embedding-3-small': { input_per_mtok: 0.02, output_per_mtok: 0, as_of: '2026-10' }, @@ -98,12 +104,16 @@ export const EMBEDDING_PRICING: Record = { /** * A provider-prefixed id (`openai/gpt-6-astra`, `anthropic/claude-fable-5-1`, - * or gbrain's `voyage:voyage-4`) resolves to its table row. + * or gbrain's `voyage:voyage-4`) resolves to its table row, and so does a + * dated Claude snapshot (`claude-haiku-4-5-20251001`, Anthropic's `-YYYYMMDD` + * form), which bills at its alias's price. Dated OpenAI snapshots are not + * folded: some are priced differently from their alias. */ export function pricingRow(model: string | undefined): ModelPricing | undefined { if (!model) return undefined; const bare = model.replace(/^[a-z-]+[/:]/, ''); - return PRICING[model] ?? PRICING[bare] ?? EMBEDDING_PRICING[model] ?? EMBEDDING_PRICING[bare]; + const undated = /^claude-/.test(bare) ? bare.replace(/-\d{8}$/, '') : bare; + return PRICING[model] ?? PRICING[bare] ?? PRICING[undated] ?? EMBEDDING_PRICING[model] ?? EMBEDDING_PRICING[bare]; } export function hasPricing(model: string | undefined): boolean { diff --git a/package.json b/package.json index bd7e4804c..394b73648 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.99", + "version": "1.91.100", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/test/pricing-eval-plan.test.ts b/test/pricing-eval-plan.test.ts index bba955cc5..661ed5742 100644 --- a/test/pricing-eval-plan.test.ts +++ b/test/pricing-eval-plan.test.ts @@ -448,4 +448,13 @@ describe('pricing rows with fetched sources (2026-10-12)', () => { expect(estimateCostUsd({ input: 1_000_000, output: 0 }, 'voyage:voyage-4')).toBe(0.06); expect(hasPricing('voyage-4-nano')).toBe(false); }); + + test('every model in a gbrain `eval longmemeval --call-plan` file is priced: dated Claude snapshots, the judge and the reranker', () => { + expect(pricingRow('anthropic:claude-haiku-4-5-20251001')).toBe(PRICING['claude-haiku-4-5']); + expect(estimateCostUsd({ input: 1_000_000, output: 1_000_000 }, 'openai:gpt-4o')).toBe(12.5); + expect(hasPricing('gpt-4o-2024-05-13')).toBe(false); + expect(estimateCostUsd({ input: 1_000_000, output: 0 }, 'voyage:rerank-2.5')).toBe(0.05); + expect(estimateCostUsd({ input: 1_000_000, output: 0 }, 'rerank-2.5-lite')).toBe(0.02); + expect(hasPricing('claude-haiku-4-5-2025100')).toBe(false); + }); });