Token state not showing on load, or after message is finished.#5606
Token state not showing on load, or after message is finished.#5606
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR adds token state tracking to the Finish event in the message stream, ensuring that final token counts are properly communicated to the frontend when a conversation completes.
- Added
token_statefield to theFinishevent in both backend and frontend type definitions - Extracted token state retrieval logic into a reusable
get_token_statehelper function - Updated frontend to use the token state from Finish events and changed nullish coalescing operators to logical OR operators
- Removed a debug console.log statement
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| crates/goose-server/src/routes/reply.rs | Added token_state to Finish event, extracted token state retrieval into get_token_state helper function |
| ui/desktop/src/hooks/useMessageStream.ts | Updated Finish event type to include token_state and added call to setTokenState in Finish event handler |
| ui/desktop/src/hooks/useChatEngine.ts | Removed debug console.log statement |
| ui/desktop/src/components/BaseChat.tsx | Changed nullish coalescing operators (??) to logical OR operators (||) for token count fallbacks |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| initialValue={input || ''} | ||
| setView={setView} | ||
| totalTokens={tokenState?.totalTokens ?? sessionTokenCount} | ||
| totalTokens={tokenState?.totalTokens || sessionTokenCount} |
There was a problem hiding this comment.
Using logical OR (||) instead of nullish coalescing (??) means that a valid token count of 0 will be incorrectly treated as falsy and fall back to sessionTokenCount. Use ?? to only fallback on null/undefined values.
| totalTokens={tokenState?.totalTokens || sessionTokenCount} | |
| totalTokens={tokenState?.totalTokens ?? sessionTokenCount} |
| totalTokens={tokenState?.totalTokens || sessionTokenCount} | ||
| accumulatedInputTokens={ | ||
| tokenState?.accumulatedInputTokens ?? sessionInputTokens ?? localInputTokens | ||
| tokenState?.accumulatedInputTokens || sessionInputTokens || localInputTokens |
There was a problem hiding this comment.
Using logical OR (||) instead of nullish coalescing (??) means that a valid token count of 0 will be incorrectly treated as falsy and fall through to the next fallback. Use ?? to only fallback on null/undefined values.
| } | ||
| accumulatedOutputTokens={ | ||
| tokenState?.accumulatedOutputTokens ?? sessionOutputTokens ?? localOutputTokens | ||
| tokenState?.accumulatedOutputTokens || sessionOutputTokens || localOutputTokens |
There was a problem hiding this comment.
Using logical OR (||) instead of nullish coalescing (??) means that a valid token count of 0 will be incorrectly treated as falsy and fall through to the next fallback. Use ?? to only fallback on null/undefined values.
| accumulated_input_tokens: 0, | ||
| accumulated_output_tokens: 0, | ||
| accumulated_total_tokens: 0, | ||
| } |
There was a problem hiding this comment.
TokenState could derive Default (if it doesn't already) and this could be TokenState::default()
then this could alaso be get_session(session_id).await.map( .. ).unwrap_or_default()
| } | ||
| accumulatedOutputTokens={ | ||
| tokenState?.accumulatedOutputTokens ?? sessionOutputTokens ?? localOutputTokens | ||
| tokenState?.accumulatedOutputTokens || sessionOutputTokens || localOutputTokens |
There was a problem hiding this comment.
What are these three sources of token counts and do we need them all? tokenState, sessionOutputTokens, localOutputTokens
There was a problem hiding this comment.
fwiw this is all gone in basecamp2
There was a problem hiding this comment.
Im not convinced sessionOutputTokens is working right; I think that's the reason we were seeing this issue. The stream seems like a reasonable place to do this (although I suspect that might be used for session load because the stream code path is not hit there).
Also really don't know why we have token estimates in the client.
Will take a deeper pass and try to clean shop here.
There was a problem hiding this comment.
fwiw this is all gone in basecamp2
👍
There was a problem hiding this comment.
If it's all going away soon, I wouldn't bother tracking it all down if this gets it working
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| totalTokens={tokenState?.totalTokens || sessionTokenCount} | ||
| accumulatedInputTokens={ | ||
| tokenState?.accumulatedInputTokens ?? sessionInputTokens ?? localInputTokens | ||
| tokenState?.accumulatedInputTokens || sessionInputTokens || localInputTokens | ||
| } | ||
| accumulatedOutputTokens={ | ||
| tokenState?.accumulatedOutputTokens ?? sessionOutputTokens ?? localOutputTokens | ||
| tokenState?.accumulatedOutputTokens || sessionOutputTokens || localOutputTokens | ||
| } |
There was a problem hiding this comment.
Changing from nullish coalescing (??) to logical OR (||) alters the behavior for falsy values. The nullish coalescing operator only falls back for null or undefined, while || also falls back for 0, empty string, false, etc. Since these are token counts that could legitimately be 0, using || means a value of 0 would incorrectly fall through to the next fallback. The original ?? operator should be retained to preserve correct behavior when token counts are zero.
|
does this work in basecamp2? |
If I set ALPHA=true, I still see the issue with and without this PR |
* main: (60 commits) fix: add standard context menu items to prevent empty right-click menu (#5616) Bump openapi in prepare-release (#5611) docs: add access control section to Developer tutorial (#5615) Token state not showing on load, or after message is finished. (#5606) Change the other location too (#5608) feat(ui): bring back quick launcher (#5144) Support platform tools through CLI (#5570) Avoid web double write (#5601) fix: gemini flash -> pro for mcp smoke tests (#5574) Manual compaction test and fix (#5568) fix: tidy up claude cli handling (#5594) Remove jetbrains (#5602) feat(githubcopilot): add support for newer Copilot AI Models (#5603) fix: customised recipe to yaml string to avoid minininjia parsing error (#5494) Add pending extension indicator to extension panel (#5493) Add environment subsition for auth blocks (#5439) acp: ToolCallLocations and working cancellation (#5588) feat(providers): add Mistral AI provider (#5009) Listen for ctrl-c during provider request (#5585) Also accept null as description, not just missing (#5589) ...
* main: (31 commits) Standardize CLI argument flags and update documentation (#5516) Release 1.13.0 fix: move goosehints/AGENTS.md handling to goose, and out of developer extension (#5575) fix: add standard context menu items to prevent empty right-click menu (#5616) Bump openapi in prepare-release (#5611) docs: add access control section to Developer tutorial (#5615) Token state not showing on load, or after message is finished. (#5606) Change the other location too (#5608) feat(ui): bring back quick launcher (#5144) Support platform tools through CLI (#5570) Avoid web double write (#5601) fix: gemini flash -> pro for mcp smoke tests (#5574) Manual compaction test and fix (#5568) fix: tidy up claude cli handling (#5594) Remove jetbrains (#5602) feat(githubcopilot): add support for newer Copilot AI Models (#5603) fix: customised recipe to yaml string to avoid minininjia parsing error (#5494) Add pending extension indicator to extension panel (#5493) Add environment subsition for auth blocks (#5439) acp: ToolCallLocations and working cancellation (#5588) ...
* main: (21 commits) differentiate debug/release in cache key (#5613) Unify subrecipe and subagent execution through shared recipe pipeline (#5082) Standardize CLI argument flags and update documentation (#5516) Release 1.13.0 fix: move goosehints/AGENTS.md handling to goose, and out of developer extension (#5575) fix: add standard context menu items to prevent empty right-click menu (#5616) Bump openapi in prepare-release (#5611) docs: add access control section to Developer tutorial (#5615) Token state not showing on load, or after message is finished. (#5606) Change the other location too (#5608) feat(ui): bring back quick launcher (#5144) Support platform tools through CLI (#5570) Avoid web double write (#5601) fix: gemini flash -> pro for mcp smoke tests (#5574) Manual compaction test and fix (#5568) fix: tidy up claude cli handling (#5594) Remove jetbrains (#5602) feat(githubcopilot): add support for newer Copilot AI Models (#5603) fix: customised recipe to yaml string to avoid minininjia parsing error (#5494) Add pending extension indicator to extension panel (#5493) ...
…#5606) Signed-off-by: fbalicchia <fbalicchia@gmail.com>
* origin/main: (34 commits) Remove some logging (#5631) Use session IDs as task IDs for subagents instead of UUIDs (#5398) Fix the naming (#5628) fix: default tetrate model is broken, replace with haiku-4.5 (#5535) (#5587) Fetch less and use the right SHA (#5621) feat(ui): add custom macOS dock menu with New Window option (#5099) feat: remove hints from recipe prompts (#5622) docs: October 2025 Community All-Stars spotlight, Hacktoberfest edition (#5625) differentiate debug/release in cache key (#5613) Unify subrecipe and subagent execution through shared recipe pipeline (#5082) Standardize CLI argument flags and update documentation (#5516) Release 1.13.0 fix: move goosehints/AGENTS.md handling to goose, and out of developer extension (#5575) fix: add standard context menu items to prevent empty right-click menu (#5616) Bump openapi in prepare-release (#5611) docs: add access control section to Developer tutorial (#5615) Token state not showing on load, or after message is finished. (#5606) Change the other location too (#5608) feat(ui): bring back quick launcher (#5144) Support platform tools through CLI (#5570) ...
…#5606) Signed-off-by: Blair Allan <Blairallan@icloud.com>
Two fixes:
On client side use || an issue with truthyness of 0.
On server add token_state to Finish. This ensures the last turn is always included; update_session_metrics doesn't run until after the last Message.
fixes #5604