diff --git a/CHANGELOG.md b/CHANGELOG.md index 13474c9..6cb2835 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.2.0 - 2026-05-27 + +- Stream `reasoning-delta` events incrementally instead of buffering the full thinking block until `reasoning-end`. Emits `thinking_start`, `thinking_delta`, and `thinking_end` events as they arrive so the UI can show reasoning in real time. +- Close open text blocks on `reasoning-start` and `reasoning-delta` so thinking and text never overlap in the output. +- Add live display pricing (`MODEL_COSTS`) for known Command Code models. Cost falls back to zero for models not yet in the price table until the Provider API exposes pricing directly. +- Fetch models from the Command Code Provider API at startup (inherited from upstream 0.1.1) and overlay the static cost table. + ## 0.1.1 - 2026-05-26 - Align Command Code generate requests with CLI `0.27.2` headers and payload shape. diff --git a/README.md b/README.md index 474a73a..9454cf8 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,15 @@ https://api.commandcode.ai/provider/v1/models For tests or local mocks, override it with `COMMANDCODE_MODELS_URL`. +## Pricing + +Command Code does not yet expose model pricing through its Provider API. The provider ships a static cost table (`MODEL_COSTS` in `index.ts`) for known models so that pi can display per-model pricing. + +- Models present in `MODEL_COSTS` show their real per-million-token rates (including promotional deals like the DeepSeek V4 Pro 4× discount and Qwen 3.7 Max 2× discount). +- Models **not** in the table fall back to zero cost. When the Provider API adds a `cost` field, the static table can be removed. + +To add or update a price, edit the `MODEL_COSTS` record in `index.ts` and update the corresponding test in `tests/test-models.ts`. + ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, PR expectations, and commit message rules. diff --git a/src/core.ts b/src/core.ts index 5119a8b..f01198f 100644 --- a/src/core.ts +++ b/src/core.ts @@ -263,7 +263,7 @@ export function createStreamCommandCode(deps: CoreDependencies) { } else { const tc = output.content[thinkingIdx] if (tc && tc.type === "thinking") { - (tc as { thinking: string }).thinking += delta + ;(tc as { thinking: string }).thinking += delta } } stream.push({ diff --git a/tests/test-pricing.ts b/tests/test-pricing.ts index 702c966..3d4e995 100644 --- a/tests/test-pricing.ts +++ b/tests/test-pricing.ts @@ -31,9 +31,7 @@ const entries: Record = {} for (const line of costBlock.split("\n")) { const trimmed = line.trim() if (!trimmed || trimmed.startsWith("//")) continue - const entryMatch = trimmed.match( - /^"([^"]+)":\s*\{\s*input:\s*([\d.]+),\s*output:\s*([\d.]+)/, - ) + const entryMatch = trimmed.match(/^"([^"]+)":\s*\{\s*input:\s*([\d.]+),\s*output:\s*([\d.]+)/) if (entryMatch) { entries[entryMatch[1]] = { input: Number(entryMatch[2]), @@ -80,17 +78,13 @@ describe("MODEL_COSTS pricing overlay", () => { const claudeModels = ["claude-sonnet-4-6", "claude-opus-4-7"] for (const id of claudeModels) { const fullEntryMatch = costBlock.match( - new RegExp(`"${id.replace(/\//g, "\\\\")}":\\s*\\{[^}]+cacheRead:\\s*([\\d.]+)[^}]+cacheWrite:\\s*([\\d.]+)`), + new RegExp( + `"${id.replace(/\//g, "\\\\")}":\\s*\\{[^}]+cacheRead:\\s*([\\d.]+)[^}]+cacheWrite:\\s*([\\d.]+)`, + ), ) assert.ok(fullEntryMatch, `"${id}" should have cacheRead and cacheWrite fields`) - assert.ok( - Number(fullEntryMatch[1]) > 0, - `"${id}" cacheRead should be > 0`, - ) - assert.ok( - Number(fullEntryMatch[2]) > 0, - `"${id}" cacheWrite should be > 0`, - ) + assert.ok(Number(fullEntryMatch[1]) > 0, `"${id}" cacheRead should be > 0`) + assert.ok(Number(fullEntryMatch[2]) > 0, `"${id}" cacheWrite should be > 0`) } }) -}) \ No newline at end of file +})