You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Turn the existing Settings → Usage → Pricing tab into an editable, Runtime Host-backed price-override editor. It should show the prices Maka will use for newly activated model work, distinguish bundled prices from user overrides, and preserve the Host as the only pricing authority.
This keeps Pricing next to the cost data it explains without adding another top-level Settings destination. When the Pricing tab is active, the Usage range/summary controls should not imply that prices are time-scoped; show Pricing-specific copy and refresh controls instead.
Current code facts
The current Pricing tab is disconnected, not merely read-only. It renders UsageStats.pricing, while readUsageStats() currently returns pricing: [] unconditionally.
The Runtime Host authority implementation owns persisted overrides and one root-scoped revision shared by all pricing keys in runtime.sqlite. pricing.query returns revision-pinned override pages; pricing.mutate performs CAS upsert/delete and returns committed, unchanged, or revision_conflict. This is not yet the active Desktop production path before M5.
Runtime cost settlement uses override ?? builtin. The bundled table lives in Runtime. When pricing resolves, a completed ModelCallAttempt freezes the resolved costUsd and pricingRates; otherwise its cost basis remains unpriced.
Execution snapshots effective pricing when an AiSdkBackend is activated. A mutation refreshes idle backends, but an active Run keeps its existing snapshot until it settles; this issue does not introduce mid-Run repricing.
Open PR refactor(desktop): remove unused Usage preload bridge #2038 proposes to remove the unused speculative maka.usage preload bridge while retaining the temporary Main handlers. This feature must not restore that bridge or treat those handlers as its long-term contract.
Product behavior
The first version lists this exact key set:
bundled pricing keys ∪ persisted override keys
It does not join the Provider model catalog yet. Users can add an exact model key manually.
Example:
Pricing [Refresh] [Add price]
USD per 1M tokens. Applies to newly activated model work; an active run keeps its starting prices.
Historical costs are not recalculated. Provider billing is authoritative.
Model key Source Input Output Cache read Cache write Action
openai:gpt-4o Built-in $2.50 $10.00 $1.25 Not set Customize
anthropic:claude-sonnet-4-5 Custom · has fallback $2.00 $12.00 $0.30 $3.75 Edit · Reset
acme:coder-v2 Custom-only $0.80 $2.40 Not set Not set Edit · Delete
Editing a Built-in row creates a complete override and changes its source to Custom.
Editing a Custom row updates that override.
Resetting a Custom row with a bundled fallback deletes the override and restores Built-in pricing.
Deleting a Custom-only row removes the override; newly activated model work becomes unpriced for that key, not $0, while work already active keeps the snapshot it started with.
Provenance comes from override presence, not value equality. An override numerically equal to the bundled value is still Custom.
The row and confirmation copy must make the destructive outcome explicit: reset restores a bundled value, while deleting a Custom-only row leaves newly activated model work unpriced; work already active keeps its starting snapshot.
An omitted cache rate and an explicit 0 must remain distinct in the form. The current cost calculator treats an omitted cache rate as no cache charge, so show copy such as Not set (no cache charge in Maka estimates) instead of an ambiguous dash.
Display formatting must not become stored input. Editing must round-trip the canonical value without losing precision, and a positive rate must never be rendered as $0. The form may use a friendlier display format only while preserving the exact underlying value.
The manual model-key field explains that this is the exact Runtime lookup key and shows existing examples. For a Custom-only model, users must be able to copy the exact key from an unpriced Host-backed Usage or Inspector call fact; use the canonical providerId and modelId, never the connection slug. A shared projection/helper should own key construction so the renderer does not guess the lookup rule. A direct prefilled deep link is a later convenience, not a prerequisite for obtaining the key.
Host read model
Prefer evolving the currently unused pricing.query response instead of adding parallel raw-override and catalog operations.
The Host-owned projection should contain one revision-consistent page of effective entries. Conceptually:
The Host combines the same bundled table used by execution with persisted overrides and keeps canonical model-key ordering and existing page bounds.
An override is a complete PricingConfig; fields do not partially inherit from the bundled row.
Pagination remains pinned to the override revision. If a later page reports revision_changed, the adapter discards the whole partial snapshot and restarts from page one with a bounded retry count.
A snapshot and its save revision are valid only for the current Host connection/epoch. Reconnect or Host replacement preserves any user draft but discards partial pages and the mutation base, then requires a fresh authoritative load and review before another save. This handles bundled-table changes across Host builds without inventing a second catalog revision.
Once the renderer uses this projection, remove the dead UsageStats.pricing field rather than retaining a second pricing read model.
Desktop adapter boundary
Coordinate the concrete Electron/preload shape with #2010; this issue specifies only two semantic capabilities:
load one complete Pricing Settings snapshot
apply one upsert/delete against an expected revision
The Desktop adapter owns Host transport, page assembly, bounded restart, and typed error mapping. The renderer owns only presentation, an in-memory editor draft, and user feedback. It must not:
open a Pricing Store or TelemetryRepo;
import/copy the bundled pricing table;
maintain a persistent canonical mirror;
receive Host pagination cursors;
call the retained legacy Main handlers as a fallback;
restore window.maka.usage.
Before or as M5 atomically activates the M4-built adapter, remove or statically fence usage:pricing:list, usage:pricing:put, and usage:pricing:reset so the legacy direct Store routes cannot coexist with the active Host path. This does not remove the separate settings:usageStats read path.
No live pricing subscription is required for V1. Load on entering the tab, manual refresh, and authoritative reload after every mutation/conflict/uncertain outcome are sufficient; CAS prevents silent overwrites.
M4 may land the Host projection, production-shaped Desktop adapter, and isolated UI coverage independently. User-visible activation must still obey #853's M5 atomic ownership cutover and must not introduce a second production Runtime owner.
Input rules
Reuse canonical modelKey validation. Its current boundary trims, rejects empty input, and requires JavaScript string.length <= 128; do not lowercase or Unicode-normalize it. Matching is exact and existing keys are case-sensitive.
Input/output rates are required.
Cache-read/cache-write rates are optional; blank means omitted and 0 is a valid explicit value.
Every present rate must be finite and non-negative. Do not add a UI-only upper limit.
Editing an existing row keeps its model key fixed. Renaming is delete + add, not an atomic mutation invented by the client.
Concurrency and uncertain outcomes
Every save carries the revision from the loaded snapshot.
For committed and unchanged, reload the authoritative snapshot before presenting the final state. If that read fails, the mutation outcome is still known: say that the save completed but the latest prices could not be loaded, keep the draft, show no speculative final list, and disable further writes until a fresh snapshot is available. Do not reclassify it as an uncertain commit.
For revision_conflict:
never replay the mutation automatically;
keep the user's draft;
reload the latest authoritative snapshot;
compare the intended state, including whether an override is present, with fresh authority;
if it already matches, report that the current authoritative state is synchronized without issuing another write;
otherwise show the latest value beside the draft and require an explicit review and second Save against the new revision.
Treat commit_outcome_unknown, a response-losing disconnect, and a timeout after dispatch as uncertain rather than ordinary failure:
do not retry automatically or claim success/failure;
keep the draft and block another write;
reload authority when the Host is available;
compare the complete target state: override presence/absence plus every canonical field. Reset matches only when the override is absent and the row resolves to Built-in; Custom-only delete matches only when that key is absent; an upsert equal to a bundled price matches only when provenance still proves an override exists;
if the complete target matches, report that current authority matches the draft without claiming which command committed it;
otherwise require the user to review before an explicit retry.
Delivery slices
Host projection — replace the unused override-only pricing.query projection with effective pricing + provenance, including bounded pages and two-client/CAS tests.
[Tracking] Runtime Host M4 Desktop-first client adapters #2010 Pricing adapter — aggregate pages, invalidate state across Host epochs, map conflict/uncertain outcomes, and replace/fence the three legacy Pricing Main handlers without reaching Stores or activating another production owner.
Desktop Pricing UI + exact-key source — evolve the existing Usage/Pricing tab after rebasing over fix(ui): clarify the Usage page hierarchy #2024, and expose a copyable exact Pricing key from an unpriced Host-backed Usage/Inspector fact. Activate the Host-backed editor only at the M5 ownership switch.
Optional follow-up — link that unpriced call directly to a prefilled Add-price editor. This shortens the journey but is not required to discover/copy the canonical key.
Acceptance
The page reads one Host-backed effective snapshot and distinguishes Built-in, overridden Built-in, and Custom-only rows.
The Pricing tab is visibly not time-scoped; the Usage date range cannot be mistaken for a Pricing scope.
Add/edit/reset/delete cover input, output, cache-read, and cache-write rates, including blank optionals and explicit zero.
Reset restores the bundled value when one exists; deleting a Custom-only override makes the key unpriced.
Effective provenance is based on override presence, including an override equal to the bundled values.
A user can obtain a copyable exact key for an observed unpriced model without guessing or substituting a connection slug.
Multi-page reads never mix revisions, fail clearly after bounded restart under continuous churn, and discard both snapshot and save base after a Host epoch change while preserving the draft.
committed/unchanged (including post-commit reload failure), revision_conflict, commit_outcome_unknown, and response loss follow the behavior above; no mutation is blindly replayed.
Newly activated model work uses the new effective rates; work already active keeps the pricing snapshot it started with until that Run settles, and historical costUsd/pricingRates remain unchanged.
Loading, read-error/retry, mutation-pending, and refresh states are explicit; destructive reset/delete copy states whether the result is Built-in or unpriced.
Field errors are associated with their controls, validation/conflict/pending status is announced to assistive technology, and closing the editor restores focus to its trigger.
Static adapter gates prove the renderer path cannot open Host-owned Stores or an embedded Runtime owner, and the active Host path cannot coexist with the three legacy Pricing handlers/direct Store routes.
English
Goal
Turn the existing
Settings → Usage → Pricingtab into an editable, Runtime Host-backed price-override editor. It should show the prices Maka will use for newly activated model work, distinguish bundled prices from user overrides, and preserve the Host as the only pricing authority.This keeps Pricing next to the cost data it explains without adding another top-level Settings destination. When the Pricing tab is active, the Usage range/summary controls should not imply that prices are time-scoped; show Pricing-specific copy and refresh controls instead.
Current code facts
UsageStats.pricing, whilereadUsageStats()currently returnspricing: []unconditionally.runtime.sqlite.pricing.queryreturns revision-pinned override pages;pricing.mutateperforms CAS upsert/delete and returnscommitted,unchanged, orrevision_conflict. This is not yet the active Desktop production path before M5.override ?? builtin. The bundled table lives in Runtime. When pricing resolves, a completedModelCallAttemptfreezes the resolvedcostUsdandpricingRates; otherwise its cost basis remains unpriced.AiSdkBackendis activated. A mutation refreshes idle backends, but an active Run keeps its existing snapshot until it settles; this issue does not introduce mid-Run repricing.pricing.querycurrently has no production client. The Desktop adapter tracked by [Tracking] Runtime Host M4 Desktop-first client adapters #2010 is still planned, and Desktop production still has an embedded Runtime owner until the atomic M5 cutover governed by feat(runtime): RFC - one Runtime Host for every interactive Maka surface #853.maka.usagepreload bridge while retaining the temporary Main handlers. This feature must not restore that bridge or treat those handlers as its long-term contract.Product behavior
The first version lists this exact key set:
It does not join the Provider model catalog yet. Users can add an exact model key manually.
Example:
$0, while work already active keeps the snapshot it started with.0must remain distinct in the form. The current cost calculator treats an omitted cache rate as no cache charge, so show copy such asNot set (no cache charge in Maka estimates)instead of an ambiguous dash.$0. The form may use a friendlier display format only while preserving the exact underlying value.providerIdandmodelId, never the connection slug. A shared projection/helper should own key construction so the renderer does not guess the lookup rule. A direct prefilled deep link is a later convenience, not a prerequisite for obtaining the key.Host read model
Prefer evolving the currently unused
pricing.queryresponse instead of adding parallel raw-override and catalog operations.The Host-owned projection should contain one revision-consistent page of effective entries. Conceptually:
PricingConfig; fields do not partially inherit from the bundled row.revision_changed, the adapter discards the whole partial snapshot and restarts from page one with a bounded retry count.UsageStats.pricingfield rather than retaining a second pricing read model.Desktop adapter boundary
Coordinate the concrete Electron/preload shape with #2010; this issue specifies only two semantic capabilities:
The Desktop adapter owns Host transport, page assembly, bounded restart, and typed error mapping. The renderer owns only presentation, an in-memory editor draft, and user feedback. It must not:
window.maka.usage.Before or as M5 atomically activates the M4-built adapter, remove or statically fence
usage:pricing:list,usage:pricing:put, andusage:pricing:resetso the legacy direct Store routes cannot coexist with the active Host path. This does not remove the separatesettings:usageStatsread path.No live pricing subscription is required for V1. Load on entering the tab, manual refresh, and authoritative reload after every mutation/conflict/uncertain outcome are sufficient; CAS prevents silent overwrites.
M4 may land the Host projection, production-shaped Desktop adapter, and isolated UI coverage independently. User-visible activation must still obey #853's M5 atomic ownership cutover and must not introduce a second production Runtime owner.
Input rules
modelKeyvalidation. Its current boundary trims, rejects empty input, and requires JavaScriptstring.length <= 128; do not lowercase or Unicode-normalize it. Matching is exact and existing keys are case-sensitive.0is a valid explicit value.Concurrency and uncertain outcomes
Every save carries the revision from the loaded snapshot.
For
committedandunchanged, reload the authoritative snapshot before presenting the final state. If that read fails, the mutation outcome is still known: say that the save completed but the latest prices could not be loaded, keep the draft, show no speculative final list, and disable further writes until a fresh snapshot is available. Do not reclassify it as an uncertain commit.For
revision_conflict:Treat
commit_outcome_unknown, a response-losing disconnect, and a timeout after dispatch as uncertain rather than ordinary failure:Delivery slices
pricing.queryprojection with effective pricing + provenance, including bounded pages and two-client/CAS tests.Acceptance
committed/unchanged(including post-commit reload failure),revision_conflict,commit_outcome_unknown, and response loss follow the behavior above; no mutation is blindly replayed.costUsd/pricingRatesremain unchanged.Dependencies
Non-goals
简体中文
目标
把现有
设置 → 使用统计 → 定价配置标签页改造成可编辑、由 Runtime Host 支撑的价格覆盖编辑器。页面应展示 Maka 将用于新激活模型工作的真实生效价格,区分内置价格与用户 override,并保持 Host 是唯一 Pricing authority。Pricing 与它所解释的费用数据继续放在一起,不新增顶层 Settings 导航项。打开 Pricing 标签时,Usage 的时间范围/汇总控件不应让用户误以为价格受时间范围约束;此时改为展示 Pricing 专属说明和刷新操作。
当前代码事实
UsageStats.pricing,但readUsageStats()目前始终写死返回pricing: []。runtime.sqlite中拥有持久化 override,以及由当前 storage root 全部 pricing key 共享的一份 revision。pricing.query返回绑定 revision 的 override 分页;pricing.mutate通过 CAS 执行 upsert/delete,并返回committed、unchanged或revision_conflict。在 M5 前,它还不是 Desktop production 的 active path。override ?? builtin,内置价格表位于 Runtime。能够解析价格时,完成的ModelCallAttempt会冻结当时解析出的costUsd与pricingRates;否则其费用依据保持未定价。AiSdkBackend激活时取得一份 effective pricing snapshot。Mutation 会刷新 idle backend,但 active Run 在结束前继续使用原 snapshot;本 Issue 不引入运行途中的动态重定价。pricing.query当前没有生产 Client。[Tracking] Runtime Host M4 Desktop-first client adapters #2010 追踪的 Desktop adapter 仍为 Planned;在 feat(runtime): RFC - one Runtime Host for every interactive Maka surface #853 规定的 M5 原子切换前,Desktop production 仍拥有 embedded Runtime。maka.usagepreload bridge,同时暂时保留 Main handlers。本功能不得恢复该 bridge,也不得把这些 handler 当成长期产品契约。产品行为
V1 的列表严格定义为:
首版不与 Provider model catalog 做 join;用户可以手动添加精确 model key。
页面示例:
$0,已经运行中的工作继续使用其启动时的 snapshot。$0。页面可以使用更友好的显示格式,但必须保留底层精确值。providerId与modelId,绝不能拿 connection slug 代替。key 的构造由共享 projection/helper 持有,Renderer 不猜测 lookup rule。直接跳转并预填表单只是后续便利功能,不是获取 key 的前置条件。Host read model
优先演进当前无人使用的
pricing.queryresponse,而不是并行增加 raw override 与 catalog 两套相似 operation。Host-owned projection 应以同一 revision 输出生效价格。概念结构如下:
PricingConfig,字段不会从内置行做部分继承。revision_changed时,adapter 必须丢弃全部部分结果,并以有界次数从第一页重读。UsageStats.pricing,而不是保留第二套 Pricing read model。Desktop adapter 边界
Electron/preload 的具体形状继续与 #2010 协调;本 Issue 只规定两个语义能力:
Desktop adapter 拥有 Host transport、分页组装、有界重读与 typed error mapping。Renderer 只拥有展示、内存中的编辑草稿和用户反馈。它不得:
window.maka.usage。在 M5 原子激活由 M4 构建的 adapter 之前或切换当下,必须删除或用静态门禁封死
usage:pricing:list、usage:pricing:put、usage:pricing:reset,防止旧的 Store 直达路径与 active Host path 共存。这不影响独立的settings:usageStats读取路径。V1 不需要 live pricing subscription。进入标签页、手动刷新、每次 mutation/冲突/不确定结果后重新读取已经足够;CAS 可以阻止静默覆盖。
M4 可以分别落地 Host projection、production-shaped Desktop adapter 与隔离的 UI 覆盖。用户可见的正式启用仍须服从 #853 的 M5 原子 ownership 切换,不能引入第二个 production Runtime owner。
输入规则
modelKeyvalidation。当前边界会 trim、拒绝空值,并要求 JavaScriptstring.length <= 128;不得 lowercase 或 Unicode normalize。匹配是精确的,现有 key 也区分大小写。0是合法的显式值。并发与不确定结果
每次保存都携带已加载 snapshot 的 revision。
收到
committed或unchanged后,先重新读取 authority,再展示最终状态。如果读取失败,mutation outcome 仍然是已知的:提示“保存已完成,但无法加载最新价格”,保留 draft,不展示推测出的最终列表,并在拿到 fresh snapshot 前禁止后续写入;不能把它重新归类成 commit outcome uncertain。收到
revision_conflict时:commit_outcome_unknown、发送后丢失 response 的断线,以及无法证明 command 未到达 Host 的 timeout,都属于“不确定结果”,不能当作普通失败:交付 slices
pricing.query替换为 effective pricing + provenance,并覆盖有界分页与双 Client/CAS 测试。验收条件
committed/unchanged(包括提交后 reload 失败)、revision_conflict、commit_outcome_unknown与 response loss 均遵循上述行为,任何 mutation 都不会被盲目重放。costUsd/pricingRates也保持不变。依赖
非目标