Skip to content

fix(frontend): render a session that is parked on a tool approval - #6202

Merged
mmabrouk merged 1 commit into
release/v0.113.0from
fix/s1-approval-session-empty
Aug 22, 2026
Merged

mmabrouk merged 1 commit into
release/v0.113.0from
fix/s1-approval-session-empty

Conversation

@mmabrouk

@mmabrouk mmabrouk commented Aug 22, 2026 •

Copy link
Copy Markdown
Member

Context

Opening a session that is waiting on a tool approval showed an empty pane. You got the agent card, the Templates grid and the composer, but none of the session's turns and no Approve/Deny controls. This happened from the sessions list and from Home's "Waiting on you" entry. QA reproduced it 3/3 on staging; the five sessions on the same account without a pending approval rendered normally in the same pane.

The backend was never the problem. POST /api/sessions/interactions/query returned the turns and the pending user_approval row the whole time. The transcript was mapped correctly and then thrown away.

#5942 added an awaitingUser input to shouldAdoptServerTranscript. Its job is to stop a background poll from adopting the durable log over a card the user is still filling in, which would discard whatever they typed into its form. That intent is right. The problem is that the guard ran on every path, including a cold open, where localMessageCount is 0. There is no card on screen to protect there, so refusing the server transcript protects nothing and leaves the pane blank. Nothing else calls setMessages on that path. hydratedEmpty also stays false, because the transcript was not empty, so the user does not even get the "history unavailable" notice. The Templates grid only renders when messages.length === 0, which is exactly the reported symptom.

That is also why the split QA saw is 1 versus 5. All six sessions took the same cold-hydration path. The five without a pending interaction had awaitingUser: false and were adopted. The one parked on an approval was refused.

Changes

shouldAdoptServerTranscript now pairs the guard with localMessageCount, so it only fires when there is a rendered transcript to preserve.

Before:

if (awaitingUser) return false

After:

if (awaitingUser && localMessageCount > 0) return false

Every background and revalidation path runs with a rendered transcript, so #5942 keeps its protection. The only case that changes is the one that was broken: a first paint with nothing on screen.

Regression or pre-existing

This is a regression in v0.113.0. v0.112.3 has no awaitingUser input at all:

git show v0.112.3:web/packages/agenta-entities/src/session/core/transcriptAdoption.ts

It arrived in commit c08a8248bc ("rebuild #5942's adoption guard in the lane's idiom"), merged in PR #6065. The v0.112.3 release solved #5942 with different machinery in the app hook. The rebuild moved the rule into the shared predicate and lost the "only when we render something" precondition.

Blast radius is the desktop OSS and EE chat slice only. The @agenta/chat copy of the hook (useAgentConversation.ts) never passed awaitingUser, so mobile was never affected.

Tests

Four cases added to transcriptAdoptionAwaiting.test.ts. They drive a real pending user_approval row through hasWaitingInteraction into the guard, so the wiring is covered, not just the predicate.

  • The cold-open case fails without this change (expected false to be true) and passes with it.
  • The [fix] Waiting cards refuse transcript adoption without proof they ended #5942 case (same session, transcript now on screen) stays green in both directions.
  • One case checks that localMessageCount: 0 did not turn the guard into a blanket "always adopt": busy, an empty server transcript, and a watermark that has not moved all still refuse.

Verified: @agenta/entities 1334 unit tests pass, @agenta/chat 378 pass, types:check clean for both @agenta/oss and @agenta/ee, prettier 3.7.4 clean, and one production build via pnpm build-oss (10/10 tasks).

Not verified live. Reproducing a pending approval needs a stack, and every local stack is in use by another release task. The click path below is the handoff.

Why it can look intermittent

It is not intermittent. It is deterministic for the first open of a session on a device, and it disappears the moment anything caches that session locally.

QA hit the empty pane 3/3 on cold opens. They then opened the same session on /m and went back to the desktop, where it rendered 7/7. That is the fix working by accident, not the bug going away. The mobile app drives the same session through useAgentConversation (mobile/src/features/chat/LiveConversation.tsx:71), and that hook never passes awaitingUser into the guard. So /m adopted the transcript and persisted it. Both apps read and write the same store, agenta:agent-chat:messages:v2, declared once in packages/agenta-chat/src/state/sessionMessages.ts:52. /m is a basePath on the same deployment, not a separate host, so it is the same origin and the same localStorage partition. After that write, every desktop open of that session takes the warm path: initialMessages is non-empty, the pane paints from cache, and the guard is never the thing standing between the user and their turns.

One detail if you try to reproduce the sequence. tabLocalStorage deletes jotai's subscribe, so a desktop tab that was already open when /m wrote does not pick the value up live. The warm path needs a fresh page load after the /m visit.

The practical consequence for review: test COLD. Use a fresh browser profile, or clear agenta:agent-chat:messages:v2 before opening the session. A warm open exercises a path that was never broken and will pass either way.

What to QA

  • Start a session and get the agent to request a tool that needs approval, for example a Terminal command under an "ask" policy. Leave the approval pending.
  • Open that session in a browser profile that never ran it, or clear localStorage first. The key is agenta:agent-chat:messages:v2. This is what makes it a cold open, and it is the only shape that was broken.
  • Open it from the sessions list. The turns render and the Approve/Deny card is there and clickable. Before this change the pane showed the Templates grid instead.
  • Open it from Home's "Waiting on you" entry. Same result.
  • Regression to watch for, this is what [fix] Waiting cards refuse transcript adoption without proof they ended #5942 protects: with the session already open and a card parked on you, type into that card's form and leave it for a minute while a background refresh ticks. Your typing must survive. The transcript must not jump back to an older state.
  • Regression: the five-sessions-without-approvals case. Sessions with no pending interaction must still open normally from a cold browser.

Opening a session that waits on an approval showed an empty pane: the agent
card, the Templates grid and the composer, but none of the session's turns and
no Approve/Deny controls. The backend returned the turns and the pending
user_approval row the whole time. A user was told something waited on them and
had no way to act on it.

The transcript was mapped correctly and then discarded. #5942 added an
`awaitingUser` input to `shouldAdoptServerTranscript` so a background poll
cannot adopt the durable log over a card the user is still filling in. The
guard was applied unconditionally, including on a COLD open, where
`localMessageCount` is 0. There is no local card to protect there, so refusing
the server transcript protects nothing and leaves the pane blank. Nothing else
calls `setMessages` on that path, and `hydratedEmpty` stays false because the
transcript was not empty, so the user does not even get the history-unavailable
notice.

Pair the guard with `localMessageCount` so it only fires when there is a
rendered transcript to preserve. Every background and revalidation path runs
with one, so #5942 keeps its protection.

Regression in v0.113.0. v0.112.3 has no `awaitingUser` input at all; it came in
with c08a824, merged in PR #6065. The @agenta/chat copy of the hook never
passed `awaitingUser`, so mobile is unaffected.

Tests: 4 cases in transcriptAdoptionAwaiting.test.ts driving a pending
user_approval row through hasWaitingInteraction into the guard. The cold-open
case fails without this change and the #5942 case stays green in both
directions.
@vercel

vercel Bot commented Aug 22, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview Aug 22, 2026 9:35am

Request Review

@coderabbitai

coderabbitai Bot commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 8e3de705-2802-49d9-ae00-ecee19e7d662

📥 Commits

Reviewing files that changed from the base of the PR and between cce6501 and c7bd77f.

📒 Files selected for processing (2)
  • web/packages/agenta-entities/src/session/core/transcriptAdoption.ts
  • web/packages/agenta-entities/tests/unit/transcriptAdoptionAwaiting.test.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Cold-opening a session awaiting approval now correctly loads the durable server transcript when no local messages have been rendered.
    • Existing safeguards remain in place after transcript content is displayed and during busy, empty-server, or watermark conditions.
  • Tests

    • Added coverage for transcript adoption behavior in sessions awaiting approval.

Walkthrough

The transcript adoption guard now allows empty clients to load durable server transcripts when a pending approval exists. Clients with rendered transcript content still refuse adoption. Unit tests cover both cases and related safeguards.

Changes

Transcript adoption

Layer / File(s) Summary
Update adoption guard and coverage
web/packages/agenta-entities/src/session/core/transcriptAdoption.ts, web/packages/agenta-entities/tests/unit/transcriptAdoptionAwaiting.test.ts
The awaiting-user guard now blocks adoption only when local rendered messages exist. Tests add a pending approval fixture and cover cold-open adoption, refusal after hydration, and existing busy, empty-server, and watermark guards.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to c7bd7

This restores cold-open rendering for sessions waiting on tool approval while preserving protection for approvals already visible on screen; no actionable merge-blocking risk remains after normal checks and review.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the frontend fix for sessions parked on tool approval, which matches the main change.
Description check ✅ Passed The description directly explains the regression, implementation change, tests, verification, and QA steps.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/s1-approval-session-empty

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.

@mmabrouk
mmabrouk marked this pull request as ready for review August 22, 2026 09:38
@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. bug frontend tests labels Aug 22, 2026
@mmabrouk
mmabrouk merged commit f679f4a into release/v0.113.0 Aug 22, 2026
41 of 42 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-pr-6202.up.railway.app/w
Project agenta-oss-clone-spike
Image tag pr-6202-2163e76
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-08-22T09:51:05.998Z

This branch was successfully deployed

1 active deployment
Preview — c7bd77f9 Deployed Aug 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug frontend size:S This PR changes 10-29 lines, ignoring generated files. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant