Skip to content

fix(playground): chat turns show identical token counts across turns - #5822

Open
Christian-Sidak wants to merge 2 commits into
Agenta-AI:mainfrom
Christian-Sidak:fix/issue-5789
Open

fix(playground): chat turns show identical token counts across turns#5822
Christian-Sidak wants to merge 2 commits into
Agenta-AI:mainfrom
Christian-Sidak:fix/issue-5789

Conversation

@Christian-Sidak

@Christian-Sidak Christian-Sidak commented Aug 9, 2026

Copy link
Copy Markdown

Summary

Fixes #5789. All chat turns in a session displayed the same latency, token counts, and cost because three bugs caused every turn's execution result to be stored at the same state key.

Root causes

Bug 1 -- extractLogicalRowId regex missed current message ID format (webWorkerIntegration.ts)

In comparison mode the playground builds compound row IDs:

turn-<entityId>-<logicalId>

The helper extractLogicalRowId used /^turn-([^-]+)-(lt-.+)$/ -- it only matched the legacy lt-<id> format. Current message IDs are msg-<uuid>, so the regex never matched, and the function returned the full compound string unchanged. Downstream, that compound string was looked up as the execution step key, which always missed, triggering the fallback path.

Bug 2 -- comparison-mode rowId parsing only checked "-lt-" (executionItems.ts)

handleExecutionResultAtom searched for "-lt-" to locate the logical boundary inside "turn-<entityId>-msg-<uuid>". The search always returned -1 for current message IDs, so logicalRowId became the full compound string. flatById[compoundId] is undefined (the flat message map is keyed by bare msg-<uuid>), so the deterministic path failed and the race-prone fallback fired -- it walked backward and returned the last shared user message for every turn, making all turns write their result to the same key and thus show the same traceId and token metrics.

Bug 3 -- off-by-one in runStatusByRowEntityAtom (selectors.ts)

Result keys have the form "stepId:sess:entityId". The separator ":sess:" is 6 characters, but the code sliced with sepIdx + 5, leaving a leading ":" on the extracted entityId. The mapped key became "stepId::entityId" instead of "stepId:entityId", so the resultHashes lookup in TurnMessageAdapter never matched, breaking the per-turn run-status badge.

Fix

  • Replace the lt- sentinel regex with a sentinel-string search for -msg- (current) and -lt- (legacy). Neither msg nor lt can appear in a hex UUID, so the search is unambiguous regardless of whether the entity UUID itself contains hyphens.
  • Apply the same two-sentinel search in handleExecutionResultAtom.
  • Simplify the comparison-mode fan-out in triggerExecutionAtom to reuse extractLogicalRowId instead of duplicating the parsing logic.
  • Fix sepIdx + 5 to sepIdx + 6 in runStatusByRowEntityAtom.

Demo

Before this fix, every chat turn in the playground displayed identical token counts, latency, and cost -- all turns showed the same values because they all resolved to the same internal state key. After the fix, each turn correctly shows its own individual metrics.

The screenshot below shows the chat playground view where per-turn token and cost metrics are displayed. The fix ensures each turn row shows its own distinct values rather than all rows inheriting from the last shared state.

Chat playground showing per-turn token metrics

Test plan

  • New test file tests/unit/chatTurnTokenKeys.test.ts (16 tests, all passing) covers:
    • extractLogicalRowId for plain msg-<uuid>, plain lt-<id>, compound turn-rev-msg-<uuid>, compound turn-rev-lt-<id>, and UUID entity IDs with hyphens.
    • The ":sess:" key parsing logic (sepIdx + 6) for well-formed keys, UUID entity IDs with hyphens, and missing-separator edge case.
    • The -msg- / -lt- logical row ID extraction logic mirroring the fixed handleExecutionResultAtom code.
  • Full existing test suite (215 tests across 16 files) continues to pass.

Three bugs caused all chat turns to display the same token-usage
numbers in a session:

1. extractLogicalRowId() in webWorkerIntegration used a regex that
   only matched "lt-" prefixed logical row IDs. Current message IDs
   start with "msg-", so the regex always fell through and returned
   the full compound "turn-<entityId>-msg-<uuid>" string unchanged.
   The wrong ID was used as the execution step key, making every
   turn collide on a single shared key.

2. handleExecutionResultAtom in executionItems searched for "-lt-"
   to find the boundary between the entity segment and the logical
   row ID in a comparison-mode compound rowId. Because "-lt-" was
   never found for "msg-<uuid>" IDs, logicalRowId equalled the full
   compound string. flatById[compoundId] is always undefined, so the
   fallback fired and resolved to the LAST shared user message for
   every turn -- causing all turns to store their result at the same
   key and therefore show the same traceId and token counts.

3. runStatusByRowEntityAtom in selectors parsed result keys of the
   form "stepId:sess:entityId" using key.slice(sepIdx + 5) instead
   of key.slice(sepIdx + 6). The separator ":sess:" is 6 characters,
   so +5 left a leading ":" on the entityId, producing malformed
   lookup keys that never matched the UI-side "rowId:entityId" key.

Fixes: Agenta-AI#5789
Signed-off-by: Christian-Sidak <61099993+Christian-Sidak@users.noreply.github.com>
@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Aug 9, 2026
@vercel

vercel Bot commented Aug 9, 2026

Copy link
Copy Markdown

@Christian-Sidak is attempting to deploy a commit to the agenta projects Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant

CLAassistant commented Aug 9, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ bekossy
❌ Christian-Sidak
You have signed the CLA already but the status is still pending? Let us recheck it.

@dosubot dosubot Bot added bug report Something isn't working frontend tests labels Aug 9, 2026
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

✅ Thanks @Christian-Sidak! This PR now meets the contribution requirements and has been reopened. A maintainer will review it soon.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved chat execution handling for current and legacy message identifiers.
    • Fixed execution result lookups when entity IDs contain hyphens.
    • Corrected token counts and result matching across multiple chat turns.
    • Fixed parsing of execution results to ensure entity identifiers are mapped correctly.
  • Tests

    • Added regression coverage for message ID parsing, entity identifier extraction, and execution-result lookups.

Walkthrough

Execution result handling now supports current msg- and legacy lt- logical row IDs, including hyphenated entity IDs. Session result parsing correctly extracts entityId. Regression tests cover both parsing paths and fallback behavior.

Changes

Execution token key handling

Layer / File(s) Summary
Logical row ID parsing
web/packages/agenta-playground/src/state/execution/webWorkerIntegration.ts, web/packages/agenta-playground/src/state/execution/executionItems.ts, web/packages/agenta-playground/tests/unit/chatTurnTokenKeys.test.ts
Logical row ID extraction now supports -msg- and -lt- separators. Parent-message handling uses the first recognized separator. Tests cover compound, hyphenated, ambiguous, and invalid IDs.
Execution fan-out and result mapping
web/packages/agenta-playground/src/state/execution/webWorkerIntegration.ts, web/packages/agenta-playground/src/state/execution/selectors.ts, web/packages/agenta-playground/tests/unit/chatTurnTokenKeys.test.ts
Multi-entity fan-out uses extractLogicalRowId. Entity extraction skips the full :sess: delimiter. Tests verify execution-result IDs, entity IDs, UI-compatible lookup keys, malformed keys, and fallback behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the chat-turn token count fix, which is the main change in the pull request.
Description check ✅ Passed The description explains the token, latency, and cost reporting bug, its causes, the fixes, and the test coverage.
Linked Issues check ✅ Passed The changes address issue #5789 by separating per-turn execution keys and correcting row ID and session key parsing.
Out of Scope Changes check ✅ Passed All code changes and tests support the linked issue and the stated objective of correcting per-turn usage reporting.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Warning

⚠️ This pull request shows signs of AI-generated slop (redundant_comments, trivial_assertion). It has been flagged by CodeRabbit slop detection and should be reviewed carefully.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8486921b-872d-42d9-974a-885aa4eac25a

📥 Commits

Reviewing files that changed from the base of the PR and between adec2aa and b23939f.

📒 Files selected for processing (4)
  • web/packages/agenta-playground/src/state/execution/executionItems.ts
  • web/packages/agenta-playground/src/state/execution/selectors.ts
  • web/packages/agenta-playground/src/state/execution/webWorkerIntegration.ts
  • web/packages/agenta-playground/tests/unit/chatTurnTokenKeys.test.ts

Comment on lines +819 to +822
const msgIdx = rowId.indexOf("-msg-")
if (msgIdx >= 0) return rowId.slice(msgIdx + 1)
const ltIdx = rowId.indexOf("-lt-")
if (ltIdx >= 0) return rowId.slice(ltIdx + 1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the earliest logical-ID delimiter.

The code selects -msg- whenever it exists. This conflicts with the first-separator contract. For turn-rev1-lt-old-msg-fragment, it extracts msg-fragment instead of lt-old-msg-fragment. This can map a result to the wrong chat turn.

  • web/packages/agenta-playground/src/state/execution/webWorkerIntegration.ts#L819-L822: select the lowest non-negative index of -msg- and -lt-.
  • web/packages/agenta-playground/src/state/execution/executionItems.ts#L1473-L1476: apply the same earliest-index selection.
  • web/packages/agenta-playground/tests/unit/chatTurnTokenKeys.test.ts#L56-L59: add a case where -lt- occurs before -msg- and expect the legacy logical ID.
📍 Affects 3 files
  • web/packages/agenta-playground/src/state/execution/webWorkerIntegration.ts#L819-L822 (this comment)
  • web/packages/agenta-playground/src/state/execution/executionItems.ts#L1473-L1476
  • web/packages/agenta-playground/tests/unit/chatTurnTokenKeys.test.ts#L56-L59

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

Labels

bug report Something isn't working frontend size:M This PR changes 30-99 lines, ignoring generated files. slop tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

(bug) Token-usage numbers are identical across every turn of a session

3 participants