docs: add 0.2.0 changelog entry and pricing section to README
Document the incremental reasoning-delta streaming, live display pricing, and dynamic model fetch in CHANGELOG.md. Add a Pricing section to README.md explaining the MODEL_COSTS overlay and how to update prices.
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
# Changelog
|
# 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
|
## 0.1.1 - 2026-05-26
|
||||||
|
|
||||||
- Align Command Code generate requests with CLI `0.27.2` headers and payload shape.
|
- Align Command Code generate requests with CLI `0.27.2` headers and payload shape.
|
||||||
|
|||||||
@@ -115,6 +115,15 @@ https://api.commandcode.ai/provider/v1/models
|
|||||||
|
|
||||||
For tests or local mocks, override it with `COMMANDCODE_MODELS_URL`.
|
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
|
## Contributing
|
||||||
|
|
||||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, PR expectations, and commit message rules.
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, PR expectations, and commit message rules.
|
||||||
|
|||||||
+1
-1
@@ -263,7 +263,7 @@ export function createStreamCommandCode(deps: CoreDependencies) {
|
|||||||
} else {
|
} else {
|
||||||
const tc = output.content[thinkingIdx]
|
const tc = output.content[thinkingIdx]
|
||||||
if (tc && tc.type === "thinking") {
|
if (tc && tc.type === "thinking") {
|
||||||
(tc as { thinking: string }).thinking += delta
|
;(tc as { thinking: string }).thinking += delta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stream.push({
|
stream.push({
|
||||||
|
|||||||
+6
-12
@@ -31,9 +31,7 @@ const entries: Record<string, { input: number; output: number }> = {}
|
|||||||
for (const line of costBlock.split("\n")) {
|
for (const line of costBlock.split("\n")) {
|
||||||
const trimmed = line.trim()
|
const trimmed = line.trim()
|
||||||
if (!trimmed || trimmed.startsWith("//")) continue
|
if (!trimmed || trimmed.startsWith("//")) continue
|
||||||
const entryMatch = trimmed.match(
|
const entryMatch = trimmed.match(/^"([^"]+)":\s*\{\s*input:\s*([\d.]+),\s*output:\s*([\d.]+)/)
|
||||||
/^"([^"]+)":\s*\{\s*input:\s*([\d.]+),\s*output:\s*([\d.]+)/,
|
|
||||||
)
|
|
||||||
if (entryMatch) {
|
if (entryMatch) {
|
||||||
entries[entryMatch[1]] = {
|
entries[entryMatch[1]] = {
|
||||||
input: Number(entryMatch[2]),
|
input: Number(entryMatch[2]),
|
||||||
@@ -80,17 +78,13 @@ describe("MODEL_COSTS pricing overlay", () => {
|
|||||||
const claudeModels = ["claude-sonnet-4-6", "claude-opus-4-7"]
|
const claudeModels = ["claude-sonnet-4-6", "claude-opus-4-7"]
|
||||||
for (const id of claudeModels) {
|
for (const id of claudeModels) {
|
||||||
const fullEntryMatch = costBlock.match(
|
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(fullEntryMatch, `"${id}" should have cacheRead and cacheWrite fields`)
|
||||||
assert.ok(
|
assert.ok(Number(fullEntryMatch[1]) > 0, `"${id}" cacheRead should be > 0`)
|
||||||
Number(fullEntryMatch[1]) > 0,
|
assert.ok(Number(fullEntryMatch[2]) > 0, `"${id}" cacheWrite should be > 0`)
|
||||||
`"${id}" cacheRead should be > 0`,
|
|
||||||
)
|
|
||||||
assert.ok(
|
|
||||||
Number(fullEntryMatch[2]) > 0,
|
|
||||||
`"${id}" cacheWrite should be > 0`,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user