From dd270544f7bf2aa357f84eeed8b4f0bff501eb7c Mon Sep 17 00:00:00 2001
From: LukeParkerDev <10430890+Hona@users.noreply.github.com>
Date: Thu, 9 Jul 2026 13:54:29 +1000
Subject: [PATCH] fix(app): align context tokens with usage
---
.../src/components/session-context-usage.tsx | 5 ++---
.../session/session-context-metrics.test.ts | 19 +++++--------------
.../session/session-context-metrics.ts | 9 +++------
.../session/session-context-tab.tsx | 14 +++++++-------
4 files changed, 17 insertions(+), 30 deletions(-)
diff --git a/packages/app/src/components/session-context-usage.tsx b/packages/app/src/components/session-context-usage.tsx
index fd2d1dd1a3..c1e0ccde05 100644
--- a/packages/app/src/components/session-context-usage.tsx
+++ b/packages/app/src/components/session-context-usage.tsx
@@ -12,7 +12,7 @@ import { useSync } from "@/context/sync"
import { useLanguage } from "@/context/language"
import { useProviders } from "@/hooks/use-providers"
import { useSDK } from "@/context/sdk"
-import { getSessionContext, getSessionTokenTotal } from "@/components/session/session-context-metrics"
+import { getSessionContext } from "@/components/session/session-context-metrics"
import { useSessionLayout } from "@/pages/session/session-layout"
import { createSessionTabs } from "@/pages/session/helpers"
import { useSettings } from "@/context/settings"
@@ -74,7 +74,6 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
)
const context = createMemo(() => getSessionContext(messages(), [...providers.all().values()]))
- const tokens = createMemo(() => info()?.tokens)
const cost = createMemo(() => {
return usd().format(info()?.cost ?? 0)
})
@@ -132,7 +131,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
)
diff --git a/packages/app/src/components/session/session-context-metrics.test.ts b/packages/app/src/components/session/session-context-metrics.test.ts
index 5b11bf1433..37cc0d5b5d 100644
--- a/packages/app/src/components/session/session-context-metrics.test.ts
+++ b/packages/app/src/components/session/session-context-metrics.test.ts
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"
import type { Message } from "@opencode-ai/sdk/v2/client"
-import { getSessionContext, getSessionTokenTotal } from "./session-context-metrics"
+import { getSessionContext } from "./session-context-metrics"
const assistant = (
id: string,
@@ -38,10 +38,10 @@ const user = (id: string) => {
}
describe("getSessionContext", () => {
- test("computes usage from latest assistant with tokens", () => {
+ test("computes token totals and usage from latest assistant with tokens", () => {
const messages = [
user("u1"),
- assistant("a1", { input: 0, output: 0, reasoning: 0, read: 0, write: 0 }, 0.5),
+ assistant("a1", { input: 600, output: 200, reasoning: 100, read: 50, write: 50 }, 0.5),
assistant("a2", { input: 300, output: 100, reasoning: 50, read: 25, write: 25 }, 1.25),
]
const providers = [
@@ -60,6 +60,8 @@ describe("getSessionContext", () => {
const ctx = getSessionContext(messages, providers)
expect(ctx?.message.id).toBe("a2")
+ expect(ctx?.total).toBe(500)
+ expect(ctx?.input).toBe(300)
expect(ctx?.usage).toBe(50)
expect(ctx?.providerLabel).toBe("OpenAI")
expect(ctx?.modelLabel).toBe("GPT-4.1")
@@ -94,15 +96,4 @@ describe("getSessionContext", () => {
expect(ctx).toBeUndefined()
})
-
- test("computes stored session token totals", () => {
- expect(
- getSessionTokenTotal({
- input: 10,
- output: 20,
- reasoning: 30,
- cache: { read: 40, write: 50 },
- }),
- ).toBe(150)
- })
})
diff --git a/packages/app/src/components/session/session-context-metrics.ts b/packages/app/src/components/session/session-context-metrics.ts
index 84cc984abf..30dc9e958b 100644
--- a/packages/app/src/components/session/session-context-metrics.ts
+++ b/packages/app/src/components/session/session-context-metrics.ts
@@ -1,4 +1,4 @@
-import type { AssistantMessage, Message, Session } from "@opencode-ai/sdk/v2/client"
+import type { AssistantMessage, Message } from "@opencode-ai/sdk/v2/client"
type Provider = {
id: string
@@ -21,6 +21,7 @@ type Context = {
modelLabel: string
limit: number | undefined
input: number
+ total: number
usage: number | null
}
@@ -54,6 +55,7 @@ const build = (messages: Message[] = [], providers: Provider[] = []): Context |
modelLabel: model?.name ?? message.modelID,
limit,
input: message.tokens.input,
+ total,
usage: limit ? Math.round((total / limit) * 100) : null,
}
}
@@ -61,8 +63,3 @@ const build = (messages: Message[] = [], providers: Provider[] = []): Context |
export function getSessionContext(messages: Message[] = [], providers: Provider[] = []) {
return build(messages, providers)
}
-
-export function getSessionTokenTotal(tokens: Session["tokens"] | undefined) {
- if (!tokens) return undefined
- return tokens.input + tokens.output + tokens.reasoning + tokens.cache.read + tokens.cache.write
-}
diff --git a/packages/app/src/components/session/session-context-tab.tsx b/packages/app/src/components/session/session-context-tab.tsx
index 8757c69367..25ad5ab230 100644
--- a/packages/app/src/components/session/session-context-tab.tsx
+++ b/packages/app/src/components/session/session-context-tab.tsx
@@ -15,7 +15,7 @@ import { useLanguage } from "@/context/language"
import { useProviders } from "@/hooks/use-providers"
import { useSDK } from "@/context/sdk"
import { useSessionLayout } from "@/pages/session/session-layout"
-import { getSessionContext, getSessionTokenTotal } from "./session-context-metrics"
+import { getSessionContext } from "./session-context-metrics"
import { estimateSessionContextBreakdown, type SessionContextBreakdownKey } from "./session-context-breakdown"
import { createSessionContextFormatter } from "./session-context-format"
@@ -135,7 +135,6 @@ export function SessionContextTab() {
)
const ctx = createMemo(() => getSessionContext(messages(), [...providers.all().values()]))
- const tokens = createMemo(() => info()?.tokens)
const formatter = createMemo(() => createSessionContextFormatter(language.intl()))
const cost = createMemo(() => {
@@ -204,14 +203,15 @@ export function SessionContextTab() {
{ label: "context.stats.provider", value: providerLabel },
{ label: "context.stats.model", value: modelLabel },
{ label: "context.stats.limit", value: () => formatter().number(ctx()?.limit) },
- { label: "context.stats.totalTokens", value: () => formatter().number(getSessionTokenTotal(tokens())) },
+ { label: "context.stats.totalTokens", value: () => formatter().number(ctx()?.total) },
{ label: "context.stats.usage", value: () => formatter().percent(ctx()?.usage) },
- { label: "context.stats.inputTokens", value: () => formatter().number(tokens()?.input) },
- { label: "context.stats.outputTokens", value: () => formatter().number(tokens()?.output) },
- { label: "context.stats.reasoningTokens", value: () => formatter().number(tokens()?.reasoning) },
+ { label: "context.stats.inputTokens", value: () => formatter().number(ctx()?.input) },
+ { label: "context.stats.outputTokens", value: () => formatter().number(ctx()?.message.tokens.output) },
+ { label: "context.stats.reasoningTokens", value: () => formatter().number(ctx()?.message.tokens.reasoning) },
{
label: "context.stats.cacheTokens",
- value: () => `${formatter().number(tokens()?.cache.read)} / ${formatter().number(tokens()?.cache.write)}`,
+ value: () =>
+ `${formatter().number(ctx()?.message.tokens.cache.read)} / ${formatter().number(ctx()?.message.tokens.cache.write)}`,
},
{ label: "context.stats.userMessages", value: () => counts().user.toLocaleString(language.intl()) },
{ label: "context.stats.assistantMessages", value: () => counts().assistant.toLocaleString(language.intl()) },