Skip to content

Conversation

@IdrisGit
Copy link
Contributor

@IdrisGit IdrisGit commented Jan 11, 2026

What does this PR do?

This PR adds a persistent cost field to sessions to fix incorrect cost reporting in the sidebar when sessions exceed 100 messages. Previously, cost was calculated from the last 100 messages only, causing under-reporting for long sessions.

Key changes:

  • Added cost field to Session schema
  • Sessions now accumulate cost incrementally when assistant messages complete
  • Sidebar reads cost directly from session metadata instead of summing messages
  • Forked sessions inherit parent's accumulated cost
  • Added startup migration to backfill existing sessions

How did you verify your code works?

Verified with before/after testing on the same long session:

  • v1.1.12: Sidebar showed $0.12 (incorrect - last 100 messages only)
  • Local build: Sidebar shows $1.61 (correct - accumulated total cost)
  • Used local build to work on an issue in the same session, cost is being accumulated correctly.
OpenCode v1.1.12
image
OpenCode local
image

Fixes #7767 #6989

@github-actions
Copy link
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions
Copy link
Contributor

The following comment was made by an LLM, it may be inaccurate:

No duplicate PRs found


const cost = createMemo(() => {
const total = messages().reduce((sum, x) => sum + (x.role === "assistant" ? x.cost : 0), 0)
const total = session().cost ?? 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you would want to fallback to the messages cost right cause otherwise opening old sessions would show 0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be handled by the migration script for old sessions as well, but yeah it makes more sense to fallback to the old method instead of defaulting to zero. updated.


export const getCost = fn(Identifier.schema("session"), async (id) => {
const read = await Storage.read<Info>(["session", Instance.project.id, id])
return read.cost ?? 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer leaving as undefined so we can properly do checks in frontend right

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, updated

this informs the caller function that cost can be undefined so it can
properly handle it, instead of just defaulting to 0.
@IdrisGit IdrisGit requested a review from rekram1-node January 15, 2026 01:57
Comment on lines +141 to +149
async (dir) => {
log.info("migrating session costs")
const startTime = Date.now()
let migratedCount = 0

for await (const sessionPath of new Bun.Glob("session/*/*.json").scan({
cwd: dir,
absolute: true,
})) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have to do a migration?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine if only new things are updated, some people have a LOT of sessions

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be awesome to have a way to run the migration manually if its not automatic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rekram1-node with the fallback to deriving cost from messages present in the memory (from commit affc11a), migration is not strictly required in a sense that it will break the functionality but for older sessions the cost reporting will still be bugged.

from my local testing the migration was fine but again I don't know the extent of how many sessions people have, it could be a concern.

as @maharshi365 mentioned I can also add lazy migration, that only runs when a session is loaded, checks if the session has cost field, and run the migration if needed. I am currently not aware if users can manually run migrations in OC or not, also if it's fine from maintainers perspective to only updated new sessions I am fine with that as well, let me know @rekram1-node .

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think one time migration is probably way more important than whatever slowness there is in startup. Its not just stale data, but incorrect cost data that is being shown.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

session-cost/spent-value under reported for sessions with 100+ messages

3 participants