mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-26 20:33:35 +00:00
fix(tui): total root session family cost
This commit is contained in:
parent
6b3c4f5839
commit
0eaa75ec0f
5 changed files with 35 additions and 7 deletions
|
|
@ -290,7 +290,7 @@ export function Prompt(props: PromptProps) {
|
|||
.list(session.location)
|
||||
?.find((model) => model.providerID === last.model.providerID && model.id === last.model.id)
|
||||
const pct = model?.limit.context ? `${Math.round((tokens / model.limit.context) * 100)}%` : undefined
|
||||
const cost = session.cost
|
||||
const cost = data.session.cost(props.sessionID)
|
||||
return {
|
||||
context: pct ? `${Locale.number(tokens)} (${pct})` : Locale.number(tokens),
|
||||
cost: cost > 0 ? money.format(cost) : undefined,
|
||||
|
|
|
|||
|
|
@ -805,6 +805,15 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
family(sessionID: string) {
|
||||
return store.session.family[resolveRoot(sessionID)] ?? []
|
||||
},
|
||||
cost(sessionID: string) {
|
||||
const session = store.session.info[sessionID]
|
||||
if (!session) return 0
|
||||
if (session.parentID) return session.cost
|
||||
return (store.session.family[sessionID] ?? [sessionID]).reduce(
|
||||
(total, id) => total + (store.session.info[id]?.cost ?? 0),
|
||||
0,
|
||||
)
|
||||
},
|
||||
status(sessionID: string) {
|
||||
return store.session.status[sessionID] ?? "idle"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ function View(props: { api: TuiPluginApi; session_id: string }) {
|
|||
const theme = () => props.api.theme.current
|
||||
const msg = createMemo(() => data.session.message.list(props.session_id))
|
||||
const session = createMemo(() => data.session.get(props.session_id))
|
||||
const cost = createMemo(() => session()?.cost ?? 0)
|
||||
const cost = createMemo(() => data.session.cost(props.session_id))
|
||||
|
||||
const state = createMemo(() => {
|
||||
const last = lastAssistantWithUsage(msg(), session()?.revert?.messageID)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export function SubagentFooter() {
|
|||
.model.list(current.location)
|
||||
?.find((model) => model.providerID === last.model.providerID && model.id === last.model.id)
|
||||
const pct = model?.limit.context ? `${Math.round((tokens / model.limit.context) * 100)}%` : undefined
|
||||
const cost = current.cost
|
||||
const cost = data.session.cost(route.sessionID)
|
||||
|
||||
const money = new Intl.NumberFormat("en-US", {
|
||||
style: "currency",
|
||||
|
|
|
|||
|
|
@ -2148,12 +2148,12 @@ test("projects live instruction updates with their message ID", async () => {
|
|||
}
|
||||
})
|
||||
|
||||
function sessionInfo(id: string, parentID: string | undefined) {
|
||||
function sessionInfo(id: string, parentID: string | undefined, cost = 0) {
|
||||
return {
|
||||
id,
|
||||
parentID,
|
||||
projectID: "proj_test",
|
||||
cost: 0,
|
||||
cost,
|
||||
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
||||
time: { created: 0, updated: 0 },
|
||||
title: id,
|
||||
|
|
@ -2164,10 +2164,11 @@ function sessionInfo(id: string, parentID: string | undefined) {
|
|||
// Mounts a DataProvider whose `/api/session/:id` responses are driven by the
|
||||
// given parent map (sessionID -> parentID). Roots omit the entry. Reused across
|
||||
// the family-index tests below.
|
||||
async function mountData(parents: Record<string, string>) {
|
||||
async function mountData(parents: Record<string, string>, costs: Record<string, number> = {}) {
|
||||
const calls = createFetch((url) => {
|
||||
const match = url.pathname.match(/^\/api\/session\/([^/]+)$/)
|
||||
if (match && match[1] !== "active") return json({ data: sessionInfo(match[1], parents[match[1]]) })
|
||||
if (match && match[1] !== "active")
|
||||
return json({ data: sessionInfo(match[1], parents[match[1]], costs[match[1]]) })
|
||||
})
|
||||
let data!: ReturnType<typeof useData>
|
||||
let ready!: () => void
|
||||
|
|
@ -2235,6 +2236,24 @@ test("indexes arbitrarily deep nesting under a single root", async () => {
|
|||
}
|
||||
})
|
||||
|
||||
test("totals family cost for roots and keeps subagent cost scoped", async () => {
|
||||
const { data, app } = await mountData(
|
||||
{ grandchild: "child", child: "root" },
|
||||
{ root: 1, child: 2, grandchild: 3 },
|
||||
)
|
||||
try {
|
||||
await data.session.refresh("grandchild")
|
||||
await data.session.refresh("child")
|
||||
await data.session.refresh("root")
|
||||
|
||||
expect(data.session.cost("root")).toBe(6)
|
||||
expect(data.session.cost("child")).toBe(2)
|
||||
expect(data.session.cost("grandchild")).toBe(3)
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("re-registering an existing session is idempotent", async () => {
|
||||
const { data, app } = await mountData({ grandchild: "child", child: "root" })
|
||||
try {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue