mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-14 03:56:55 +03:00
feat(app): show Go allowance when a session costs nothing (#58566)
This commit is contained in:
@@ -4,6 +4,8 @@ export default {
|
||||
"usage.tokens": "Tokens",
|
||||
"usage.usage": "Context",
|
||||
"usage.cost": "Cost",
|
||||
"usage.allowance": "Allowance",
|
||||
"usage.allowanceAmount": "{{amount}} allowance",
|
||||
"usage.view": "View context usage",
|
||||
"usage.toggle": "Toggle session context",
|
||||
"systemPrompt.title": "System Prompt",
|
||||
@@ -23,6 +25,7 @@ export default {
|
||||
"stats.userMessages": "User Messages",
|
||||
"stats.assistantMessages": "Assistant Messages",
|
||||
"stats.totalCost": "Total Cost",
|
||||
"stats.allowance": "Allowance Used",
|
||||
"stats.sessionCreated": "Session Created",
|
||||
"stats.lastActivity": "Last Activity",
|
||||
"export.success.title": "Session exported",
|
||||
|
||||
@@ -75,9 +75,18 @@ export function SessionContextUsage(props: {
|
||||
|
||||
const cost = createMemo(() => usd().format(spent()))
|
||||
|
||||
// A subscription such as OpenCode Go covers its requests from an allowance, so they cost nothing.
|
||||
const allowance = createMemo(() =>
|
||||
props.session.id ? props.session.server.data.session.allowance(props.session.id) : 0,
|
||||
)
|
||||
|
||||
// Spend anywhere in the family keeps the cost visible, even when this session's model is free.
|
||||
const showCost = createMemo(() => {
|
||||
if (spent() > 0) return true
|
||||
|
||||
// The allowance shows instead of $0.00.
|
||||
if (allowance() > 0) return false
|
||||
|
||||
const ref = info()?.model ?? messages().findLast((item) => item.type === "assistant")?.model
|
||||
const model = ref ? catalogModel(props.session, ref)?.model : undefined
|
||||
|
||||
@@ -118,6 +127,9 @@ export function SessionContextUsage(props: {
|
||||
<Show when={showCost()}>
|
||||
<ContextTooltipRow name={ctx.t("usage.cost")} value={cost()} />
|
||||
</Show>
|
||||
<Show when={allowance() > 0}>
|
||||
<ContextTooltipRow name={ctx.t("usage.allowance")} value={usd().format(allowance())} />
|
||||
</Show>
|
||||
<ContextTooltipRow name={ctx.t("usage.usage")} value={`${context()?.usage ?? 0}%`} />
|
||||
<ContextTooltipRow name={ctx.t("usage.tokens")} value={context()?.total.toLocaleString(i18n.locale()) ?? "0"} />
|
||||
</div>
|
||||
@@ -150,6 +162,12 @@ export function SessionContextUsage(props: {
|
||||
</span>
|
||||
<span>{cost()}</span>
|
||||
</Show>
|
||||
<Show when={allowance() > 0}>
|
||||
<span aria-hidden="true" class="flex w-1.5 shrink-0 items-center justify-center">
|
||||
·
|
||||
</span>
|
||||
<span>{ctx.t("usage.allowanceAmount", { amount: usd().format(allowance()) })}</span>
|
||||
</Show>
|
||||
</span>
|
||||
</Button>
|
||||
}
|
||||
|
||||
@@ -139,6 +139,8 @@ export default function SessionContextTab(props: { session: MountedSession }) {
|
||||
|
||||
// A root session's cost includes its subagent sessions, as in the TUI.
|
||||
const cost = createMemo(() => usd().format(props.session.id ? data().session.cost(props.session.id) : 0))
|
||||
// Spent from a subscription allowance such as OpenCode Go's instead of money; shown only when there is some.
|
||||
const allowance = createMemo(() => (props.session.id ? data().session.allowance(props.session.id) : 0))
|
||||
|
||||
const counts = createMemo(() => {
|
||||
const all = messages()
|
||||
@@ -179,7 +181,7 @@ export default function SessionContextTab(props: { session: MountedSession }) {
|
||||
return c.modelLabel
|
||||
})
|
||||
|
||||
const stats = [
|
||||
const stats: { label: string; value: () => JSX.Element; shown?: () => boolean }[] = [
|
||||
{ label: "stats.session", value: () => info()?.title ?? (props.session.id || "—") },
|
||||
{ label: "stats.messages", value: () => counts().all.toLocaleString(i18n.locale()) },
|
||||
{ label: "stats.provider", value: providerLabel },
|
||||
@@ -198,9 +200,10 @@ export default function SessionContextTab(props: { session: MountedSession }) {
|
||||
{ label: "stats.userMessages", value: () => counts().user.toLocaleString(i18n.locale()) },
|
||||
{ label: "stats.assistantMessages", value: () => counts().assistant.toLocaleString(i18n.locale()) },
|
||||
{ label: "stats.totalCost", value: cost },
|
||||
{ label: "stats.allowance", value: () => usd().format(allowance()), shown: () => allowance() > 0 },
|
||||
{ label: "stats.sessionCreated", value: () => formatter().time(info()?.time.created) },
|
||||
{ label: "stats.lastActivity", value: () => formatter().time(context()?.message.time.created) },
|
||||
] satisfies { label: string; value: () => JSX.Element }[]
|
||||
]
|
||||
|
||||
const exportSession = async () => {
|
||||
const sessionID = props.session.id
|
||||
@@ -292,7 +295,9 @@ export default function SessionContextTab(props: { session: MountedSession }) {
|
||||
>
|
||||
<div data-slot="session-usage-content" class="px-4 pt-4 pb-6 flex flex-col gap-6 md:px-6 md:pb-10 md:gap-10">
|
||||
<div class="grid grid-cols-1 @[32rem]:grid-cols-2 gap-4">
|
||||
<For each={stats}>{(stat) => <Stat label={ctx.t(stat.label)} value={stat.value()} />}</For>
|
||||
<For each={stats.filter((stat) => stat.shown?.() ?? true)}>
|
||||
{(stat) => <Stat label={ctx.t(stat.label)} value={stat.value()} />}
|
||||
</For>
|
||||
</div>
|
||||
|
||||
<Show when={systemPrompt()}>
|
||||
|
||||
Reference in New Issue
Block a user