# @deepseek-ai/dsh-client-ui-openrouter-usage English | [中文](README.zh.md) OpenRouter spend surface plugin, browser half: the per-session 会话费用 readout (`CostDock`) in the `conversation.composer.dock` strip (order 5, right after the shipped stats line) plus the account 余额 badge (`BalanceBadge`) at the sidebar foot (`sidebar.footer.action`). `CostDock` reads the durable `openRouterCost` projection (seeded by the history tail page, updated by `session/projection` frames), showing `会话费用 $X.XX` only once a step actually priced — no zero-cost group. An unknown-pricing step count surfaces in a tooltip so the figure's coverage stays visible. `CostDock` therefore owns no store, refresh chain, or event listener. The figure covers the session plus its subagent subtree, walked over the session list's `parentId`/`origin` rows; a subtree share names itself in the label. Each projection value describes only its own session's work — the host fold excludes a forked child's inherited prefix — so the walk sums rather than double counts. Ordinary forks are not delegated work and stay out of it. `BalanceBadge` is account-global, so it is not a session projection: the slot inject face carries a `snapshot()` callback that polls the host `ctx.remote.openRouterUsage.snapshot()` Remote on a 60s interval and drives local state. Clicking the badge calls the `refresh()` callback instead, which makes the host fetch the account immediately; the badge marks itself `aria-busy` for the duration and ignores further clicks until it settles, and a failed refresh keeps the last-known figure. In the collapsed rail it renders only the balance marker; in the wide column a labeled pill. Unknown or absent figures render the empty placeholder. The `/client` exports are the plugin body (`apply`/`inject`), the `CostDock`/`BalanceBadge` components, and the injected face types. ## Model Experience Indirectly, none. Neither the cost readout nor the balance badge injects any model context; they are pure client-side read models over the `openRouterCost` projection and the `openRouterUsage` Remote snapshot. The agent loop and all prompts are unchanged. #### KV Cache effect None. Cost derives from existing logged usage events and balance is a fetched account figure; neither is a new model-visible input. ## Known Limitations and Deferred Work - **Priced as of the fold** — `CostDock` renders whatever the durable projection holds; figures for already-folded history reflect the pricing table at fold time (see `dsh-openrouter-usage`). - **Polled, not pushed** — `BalanceBadge` polls the host snapshot; there is no `openRouterUsage` forwarded-event channel, so an account change the user did not click for surfaces on the poll interval rather than instantly. - **A cold subagent contributes nothing** — the subtree walk reads the descendants' projection values the client holds. A subagent session never opened, and with no version-matching row in the host's cold projection cache, carries no value and is indistinguishable from a zero-cost child, so its spend is missing from the total rather than marked absent.