[6778][6776] fix(frontend): Show working dots and the new session as soon as a message is sent - #6783
[6778][6776] fix(frontend): Show working dots and the new session as soon as a message is sent#6783ardaerzin wants to merge 1 commit into
Conversation
…sage is sent On /m the working dots trailed a sent message by 0.4-2.6 s, and a new session reached the sidebar 0.6-2.9 s after its first message. Both wait on the runner admitting the turn: the send goes through `useServerSessionInputs`, which does its own fetch and shows the message as a local echo, so `useChat`'s status never leaves "ready" and the only "a run is happening" signal was the liveness poll. The server lists a new session only once that same admission happens. The echo state machine already knows a send is on its way. It now exposes `inFlight`, the queue returns it as `sendInFlight`, and `useAgentConversation` folds it into the published run status and returns it; the /m conversation counts it as activity, so the dots render with the message. `@agenta/entities/session` gains `localSessionsAtom`, a reactive registry of sessions this client created and sent into. The /m conversation registers a fresh session on its first send, and a mobile binding derives sidebar rows from it into the navigation package's existing `localSessionRefsAtom` seam (which the desktop feeds from its tab cache and /m never fed), retiring a row once the server lists that id via the new `sidebarServerSessionIdsAtomFamily`. Measured after the change on /m: dots at 73 ms in an existing session; in a new session the sidebar row at 86 ms and the dots at 102 ms, both before the invoke request returns. The desktop playground does not show the dots delay, so it is untouched. Fixes #6778 Fixes #6776
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 SummarySummary by CodeRabbit
WalkthroughThe change registers fresh mobile sessions locally, synchronizes them with the mobile sidebar, and removes them after server discovery. It also exposes in-flight send state through chat hooks and uses that state for immediate mobile activity feedback. ChangesLocal session visibility
Send activity feedback
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~25 minutes Severity of issue fixed: Medium Sequence Diagram(s)sequenceDiagram
participant MobileComposer
participant LiveConversation
participant LocalSessionRegistry
participant AgentConversation
participant ChatQueue
MobileComposer->>LiveConversation: submit message
LiveConversation->>LocalSessionRegistry: register fresh session
LiveConversation->>AgentConversation: send message
AgentConversation->>ChatQueue: admit send
ChatQueue-->>AgentConversation: sendInFlight
AgentConversation-->>LiveConversation: activity state
Possibly related PRs
Merge Risk: 🟡 Moderate · up to Navigating away during a send can clear the chat's pending activity and reset the session to idle before the runner accepts it. Resolve the lifecycle mismatch before merge. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
web/mobile/src/features/nav/localSessionRefs.ts (1)
46-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a hook-level reconciliation test.
withLocalSessionsexcludes local refs already present in server rows, so a stale ref does not create an immediate duplicate. It can reappear when the server row leaves the loaded window. The current tests never mountuseSyncLocalSessionRefsor seedsidebarServerSessionIdsAtomFamily(scopeId). Register a session, expose its ID through the scoped server list, mount the hook, and assert thatlocalSessionRefsAtomandlocalSessionsAtomno longer contain it.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Advanced
Run ID: b66c2199-cecb-42cd-82e7-b659747a0820
📒 Files selected for processing (14)
web/mobile/src/features/chat/LiveConversation.tsxweb/mobile/src/features/nav/localSessionRefs.tsweb/mobile/src/features/nav/useMobileNavItems.tsxweb/mobile/tests/unit/localSessionRefs.test.tsweb/packages/agenta-chat/src/assets/pendingSendEchoes.tsweb/packages/agenta-chat/src/hooks/useAgentChatQueue.tsweb/packages/agenta-chat/src/hooks/useAgentConversation.tsweb/packages/agenta-chat/src/hooks/usePendingSendEchoes.tsweb/packages/agenta-chat/tests/unit/pendingSendsInFlight.test.tsweb/packages/agenta-entities/src/session/core/localSessions.tsweb/packages/agenta-entities/src/session/index.tsweb/packages/agenta-entities/tests/unit/session-local-sessions.test.tsweb/packages/agenta-navigation/src/dynamic/sessionsSource.tsweb/packages/agenta-navigation/src/index.ts
Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.
| error: !!errorBoundary.runError, | ||
| hitlPending, | ||
| busy: busy || acceptedRunPending || ownsContinuation, | ||
| busy: busy || acceptedRunPending || ownsContinuation || sendInFlight, |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Include sendInFlight in busyRef.current.
useAgentChatQueue marks the durable send in flight before server.submit, but line 537 updates busyRef.current before that hook runs and omits sendInFlight. Line 975 can therefore publish running while useSessionChat reads false during cleanup. releaseSessionChat then drops the chat, and the unmount cleanup sets the session to idle.
Move the assignment after sendInFlight is available:
Proposed fix
- busyRef.current = busy || acceptedRunPending
+ busyRef.current = busy || acceptedRunPending
...
const {
// ...
sendInFlight,
} = useAgentChatQueue({
// ...
})
+ busyRef.current = busy || acceptedRunPending || sendInFlight📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| busy: busy || acceptedRunPending || ownsContinuation || sendInFlight, | |
| busyRef.current = busy || acceptedRunPending | |
| const { | |
| // ... | |
| sendInFlight, | |
| } = useAgentChatQueue({ | |
| // ... | |
| }) | |
| busyRef.current = busy || acceptedRunPending || sendInFlight |
Railway Preview Environment
|
Fixes #6778
Fixes #6776
Linear: AGE-4334, AGE-4332.
Context
Two delays Mahmoud reported together, and they do share a cause. Both reproduce on
/m; the desktop playground was checked too and does not show the dots delay, so it is untouched.When you send a chat message in
/m, the message shows at once but the working dots arrive later, and when the message is the first one of a new session, the session shows up in the sidebar later still. Measured on the local EE stack with a scripted send (times from Enter):The send does not go through the AI SDK's
sendMessage. The queue hands it touseServerSessionInputs, which does its ownfetchto the invoke URL and shows the message as a local "echo" row. SouseChat'sstatusstaysreadyfor the whole turn, and the only "a run is happening" signal the screen had was the session liveness poll. That poll can only see the run once the runner has admitted it, and it runs on its own cadence. The sidebar has the same dependency: the server lists a new session only once its first turn is admitted (absent at 86 ms, present at 269 ms warm, seconds on a cold runner), and the list refetches after that.Changes
Both surfaces now read what the client already knows at submit time.
Working dots (#6778). The echo state machine in
usePendingSendEchoesalready tracks each send from "left the composer" through "runner named the turn" to "row persisted". It now exposesinFlight(an echo that is neither refused nor parked),useAgentChatQueuereturns it assendInFlight, anduseAgentConversationfolds it into the published run status and returns it. The/mconversation treats it as activity, next to the SDK status and the liveness-derived remote turn. The session's status dot goes live at the same moment.Sidebar (#6776).
@agenta/entities/sessiongains a small reactive registry of sessions this client created and sent into (localSessionsAtom, with the agent and the first message as the name). The/mconversation registers the session on the first send of a fresh session. The navigation package already had a host seam for exactly this (localSessionRefsAtom, fed on the desktop from its playground tab cache);/mnever fed it. A mobile binding now derives rows from the registry, mirrors them into the seam, and retires a local row once the server lists that id, using a newsidebarServerSessionIdsAtomFamilyexport. The existing merge lets the server row win the moment it exists, so the row the agent later renames is the same row.Tests
pendingSendsInFlight), the registry atoms (register, idempotent rename, forget), and the mobile row derivation following the session's run status. All pass;eslint,prettier --check, andtsc --noEmitpass in entities, chat, navigation, and mobile./m, same scripted send after the change: working dots at 73 ms in an existing session; in a new session the sidebar row appears at 86 ms and the dots at 102 ms, both before the invoke request has even returned. After the run settles there is exactly one row for the session, carrying the server's name.sendInFlightis available fromuseAgentChatQueueif a desktop surface ever needs it.What to QA
/m: open an existing session, send a message. The three dots appear under your message in the same instant it does, and stay until the reply starts./m: press + for a new session, send a first message. Your message text is the top row in the sidebar's Sessions list immediately, with the running spinner. When the agent renames the session, the row's label updates in place and there is only one row for it./m: send from Home's composer instead of a session page. Same two checks.