fix(app): align context tokens with usage (#36015)
This commit is contained in:
parent
9c6bb4ff72
commit
b94e55c7c0
4 changed files with 17 additions and 30 deletions
|
|
@ -12,7 +12,7 @@ import { useSync } from "@/context/sync"
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { useProviders } from "@/hooks/use-providers"
|
import { useProviders } from "@/hooks/use-providers"
|
||||||
import { useSDK } from "@/context/sdk"
|
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 { useSessionLayout } from "@/pages/session/session-layout"
|
||||||
import { createSessionTabs } from "@/pages/session/helpers"
|
import { createSessionTabs } from "@/pages/session/helpers"
|
||||||
import { useSettings } from "@/context/settings"
|
import { useSettings } from "@/context/settings"
|
||||||
|
|
@ -74,7 +74,6 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
|
||||||
)
|
)
|
||||||
|
|
||||||
const context = createMemo(() => getSessionContext(messages(), [...providers.all().values()]))
|
const context = createMemo(() => getSessionContext(messages(), [...providers.all().values()]))
|
||||||
const tokens = createMemo(() => info()?.tokens)
|
|
||||||
const cost = createMemo(() => {
|
const cost = createMemo(() => {
|
||||||
return usd().format(info()?.cost ?? 0)
|
return usd().format(info()?.cost ?? 0)
|
||||||
})
|
})
|
||||||
|
|
@ -132,7 +131,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
|
||||||
<ContextTooltipRow name={language.t("context.usage.usage")} value={`${context()?.usage ?? 0}%`} />
|
<ContextTooltipRow name={language.t("context.usage.usage")} value={`${context()?.usage ?? 0}%`} />
|
||||||
<ContextTooltipRow
|
<ContextTooltipRow
|
||||||
name={language.t("context.usage.tokens")}
|
name={language.t("context.usage.tokens")}
|
||||||
value={getSessionTokenTotal(tokens())?.toLocaleString(language.intl()) ?? "0"}
|
value={context()?.total.toLocaleString(language.intl()) ?? "0"}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import type { Message } from "@opencode-ai/sdk/v2/client"
|
import type { Message } from "@opencode-ai/sdk/v2/client"
|
||||||
import { getSessionContext, getSessionTokenTotal } from "./session-context-metrics"
|
import { getSessionContext } from "./session-context-metrics"
|
||||||
|
|
||||||
const assistant = (
|
const assistant = (
|
||||||
id: string,
|
id: string,
|
||||||
|
|
@ -38,10 +38,10 @@ const user = (id: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("getSessionContext", () => {
|
describe("getSessionContext", () => {
|
||||||
test("computes usage from latest assistant with tokens", () => {
|
test("computes token totals and usage from latest assistant with tokens", () => {
|
||||||
const messages = [
|
const messages = [
|
||||||
user("u1"),
|
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),
|
assistant("a2", { input: 300, output: 100, reasoning: 50, read: 25, write: 25 }, 1.25),
|
||||||
]
|
]
|
||||||
const providers = [
|
const providers = [
|
||||||
|
|
@ -60,6 +60,8 @@ describe("getSessionContext", () => {
|
||||||
const ctx = getSessionContext(messages, providers)
|
const ctx = getSessionContext(messages, providers)
|
||||||
|
|
||||||
expect(ctx?.message.id).toBe("a2")
|
expect(ctx?.message.id).toBe("a2")
|
||||||
|
expect(ctx?.total).toBe(500)
|
||||||
|
expect(ctx?.input).toBe(300)
|
||||||
expect(ctx?.usage).toBe(50)
|
expect(ctx?.usage).toBe(50)
|
||||||
expect(ctx?.providerLabel).toBe("OpenAI")
|
expect(ctx?.providerLabel).toBe("OpenAI")
|
||||||
expect(ctx?.modelLabel).toBe("GPT-4.1")
|
expect(ctx?.modelLabel).toBe("GPT-4.1")
|
||||||
|
|
@ -94,15 +96,4 @@ describe("getSessionContext", () => {
|
||||||
|
|
||||||
expect(ctx).toBeUndefined()
|
expect(ctx).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
test("computes stored session token totals", () => {
|
|
||||||
expect(
|
|
||||||
getSessionTokenTotal({
|
|
||||||
input: 10,
|
|
||||||
output: 20,
|
|
||||||
reasoning: 30,
|
|
||||||
cache: { read: 40, write: 50 },
|
|
||||||
}),
|
|
||||||
).toBe(150)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -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 = {
|
type Provider = {
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -21,6 +21,7 @@ type Context = {
|
||||||
modelLabel: string
|
modelLabel: string
|
||||||
limit: number | undefined
|
limit: number | undefined
|
||||||
input: number
|
input: number
|
||||||
|
total: number
|
||||||
usage: number | null
|
usage: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,6 +55,7 @@ const build = (messages: Message[] = [], providers: Provider[] = []): Context |
|
||||||
modelLabel: model?.name ?? message.modelID,
|
modelLabel: model?.name ?? message.modelID,
|
||||||
limit,
|
limit,
|
||||||
input: message.tokens.input,
|
input: message.tokens.input,
|
||||||
|
total,
|
||||||
usage: limit ? Math.round((total / limit) * 100) : null,
|
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[] = []) {
|
export function getSessionContext(messages: Message[] = [], providers: Provider[] = []) {
|
||||||
return build(messages, providers)
|
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
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import { useLanguage } from "@/context/language"
|
||||||
import { useProviders } from "@/hooks/use-providers"
|
import { useProviders } from "@/hooks/use-providers"
|
||||||
import { useSDK } from "@/context/sdk"
|
import { useSDK } from "@/context/sdk"
|
||||||
import { useSessionLayout } from "@/pages/session/session-layout"
|
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 { estimateSessionContextBreakdown, type SessionContextBreakdownKey } from "./session-context-breakdown"
|
||||||
import { createSessionContextFormatter } from "./session-context-format"
|
import { createSessionContextFormatter } from "./session-context-format"
|
||||||
|
|
||||||
|
|
@ -135,7 +135,6 @@ export function SessionContextTab() {
|
||||||
)
|
)
|
||||||
|
|
||||||
const ctx = createMemo(() => getSessionContext(messages(), [...providers.all().values()]))
|
const ctx = createMemo(() => getSessionContext(messages(), [...providers.all().values()]))
|
||||||
const tokens = createMemo(() => info()?.tokens)
|
|
||||||
const formatter = createMemo(() => createSessionContextFormatter(language.intl()))
|
const formatter = createMemo(() => createSessionContextFormatter(language.intl()))
|
||||||
|
|
||||||
const cost = createMemo(() => {
|
const cost = createMemo(() => {
|
||||||
|
|
@ -204,14 +203,15 @@ export function SessionContextTab() {
|
||||||
{ label: "context.stats.provider", value: providerLabel },
|
{ label: "context.stats.provider", value: providerLabel },
|
||||||
{ label: "context.stats.model", value: modelLabel },
|
{ label: "context.stats.model", value: modelLabel },
|
||||||
{ label: "context.stats.limit", value: () => formatter().number(ctx()?.limit) },
|
{ 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.usage", value: () => formatter().percent(ctx()?.usage) },
|
||||||
{ label: "context.stats.inputTokens", value: () => formatter().number(tokens()?.input) },
|
{ label: "context.stats.inputTokens", value: () => formatter().number(ctx()?.input) },
|
||||||
{ label: "context.stats.outputTokens", value: () => formatter().number(tokens()?.output) },
|
{ label: "context.stats.outputTokens", value: () => formatter().number(ctx()?.message.tokens.output) },
|
||||||
{ label: "context.stats.reasoningTokens", value: () => formatter().number(tokens()?.reasoning) },
|
{ label: "context.stats.reasoningTokens", value: () => formatter().number(ctx()?.message.tokens.reasoning) },
|
||||||
{
|
{
|
||||||
label: "context.stats.cacheTokens",
|
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.userMessages", value: () => counts().user.toLocaleString(language.intl()) },
|
||||||
{ label: "context.stats.assistantMessages", value: () => counts().assistant.toLocaleString(language.intl()) },
|
{ label: "context.stats.assistantMessages", value: () => counts().assistant.toLocaleString(language.intl()) },
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue