fix(ui): skip session.message reloads during active chat#67037
fix(ui): skip session.message reloads during active chat#67037hansolo949 wants to merge 6 commits intoopenclaw:mainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9ecf377af0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
|
||
| function isActiveChatFlow(host: GatewayHost & Partial<ChatState>): boolean { | ||
| return ( | ||
| host.chatLoading === true || |
There was a problem hiding this comment.
Remove chatLoading from the session.message suppression gate
Including host.chatLoading in isActiveChatFlow suppresses session.message reloads during any in-flight history fetch, not just during active send/stream. Because loadChatHistory sets chatLoading = true immediately and handleSessionMessageGatewayEvent just returns (without scheduling a retry), a message that arrives after the current chat.history snapshot can be dropped until some unrelated future reload occurs, leaving the active session temporarily stale.
Useful? React with 👍 / 👎.
Greptile SummaryAdds an Confidence Score: 5/5Safe to merge — the guard is narrow and correct, and terminal-event reload paths remain intact. No P0/P1 findings. The sole remaining comment is P2 test coverage: three of the four active-flow conditions go untested. Logic, type safety, and the main regression scenario are all sound. ui/src/ui/app-gateway.sessions.node.test.ts — missing test cases for chatLoading, chatSending, and chatStream branches of isActiveChatFlow. Prompt To Fix All With AIThis is a comment left during a code review.
Path: ui/src/ui/app-gateway.sessions.node.test.ts
Line: 145-159
Comment:
**Test only covers one of four active-flow conditions**
The new test validates the `chatRunId` branch of `isActiveChatFlow`, but the other three conditions — `chatLoading`, `chatSending`, and `chatStream` — each have distinct lifecycle meanings and are not independently exercised. A chat that has started streaming (`chatStream = ""`) but has no `chatRunId` yet, or a reload already in flight (`chatLoading = true`), would also be suppressed. Extending coverage to the other conditions would lock in the full guard boundary.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(ui): skip session.message reloads du..." | Re-trigger Greptile |
| it("does not reload chat history during active chat flow", () => { | ||
| loadChatHistoryMock.mockReset(); | ||
| const host = createHost(); | ||
| host.sessionKey = "agent:qa:main"; | ||
| host.chatRunId = "run-123"; | ||
|
|
||
| handleGatewayEvent(host, { | ||
| type: "event", | ||
| event: "session.message", | ||
| payload: { sessionKey: "agent:qa:main" }, | ||
| seq: 1, | ||
| }); | ||
|
|
||
| expect(loadChatHistoryMock).not.toHaveBeenCalled(); | ||
| }); |
There was a problem hiding this comment.
Test only covers one of four active-flow conditions
The new test validates the chatRunId branch of isActiveChatFlow, but the other three conditions — chatLoading, chatSending, and chatStream — each have distinct lifecycle meanings and are not independently exercised. A chat that has started streaming (chatStream = "") but has no chatRunId yet, or a reload already in flight (chatLoading = true), would also be suppressed. Extending coverage to the other conditions would lock in the full guard boundary.
Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/ui/app-gateway.sessions.node.test.ts
Line: 145-159
Comment:
**Test only covers one of four active-flow conditions**
The new test validates the `chatRunId` branch of `isActiveChatFlow`, but the other three conditions — `chatLoading`, `chatSending`, and `chatStream` — each have distinct lifecycle meanings and are not independently exercised. A chat that has started streaming (`chatStream = ""`) but has no `chatRunId` yet, or a reload already in flight (`chatLoading = true`), would also be suppressed. Extending coverage to the other conditions would lock in the full guard boundary.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 23e29f3e3d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (isActiveChatFlow(host as GatewayHost & Partial<ChatState>)) { | ||
| return; |
There was a problem hiding this comment.
Queue a deferred reload when session.message is suppressed
Returning early for active chat flow drops same-session session.message events without any retry path. Because tracked-run chat finals now skip loadChatHistory when shouldReloadHistoryForFinalEvent(..., { trackedRunId }) is false, a message that lands during chatSending/chatRunId/chatLoading/streaming can be missed indefinitely until an unrelated reload occurs. This makes the active transcript stale in real scenarios like concurrent writers (another client/channel) or transcript updates that race with the in-flight run.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 373c94d193
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| suppressionHost.suppressNextSessionMessageReloadForSessionKey = | ||
| payload?.sessionKey?.trim() || host.sessionKey; |
There was a problem hiding this comment.
Expire one-shot suppression when matching event is not received
Setting suppressNextSessionMessageReloadForSessionKey here assumes the corresponding session.message will always arrive next, but that flag is only cleared when a matching event is handled. Because transcript events are sent with dropIfSlow and connections can reconnect between events, the matching session.message can be missed; in that case this stale flag suppresses the next unrelated session.message for the same session, leaving chat history stale until a later reload trigger happens.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b284ff913d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| clearDeferredSessionMessageReload(host, payload?.sessionKey); | ||
| void loadChatHistory(host as unknown as ChatState); | ||
| } else { | ||
| suppressNextSessionMessageReload(host, payload?.sessionKey?.trim() || host.sessionKey); |
There was a problem hiding this comment.
Limit one-shot suppression to a confirmed matching update
handleChatGatewayEvent always arms suppressNextSessionMessageReload for tracked finals, but this suppresses the next same-session session.message even when no matching follow-up exists. Fresh evidence: gateway finals can be emitted without a message payload (state: "final" with optional message), and transcript events are sent with dropIfSlow, so the expected paired session.message is not guaranteed; in that case this line drops an unrelated real update and the chat can remain stale until another reload path runs.
Useful? React with 👍 / 👎.
|
Closing this as implemented after Codex automated review. Current main already implements the useful part of PR #67037: same-session Best possible solution: Close PR #67037 as implemented on current main. Keep the shipped current-main approach: defer same-session reloads only while an actual chat run is active, replay the deferred reload after terminal events, and preserve optimistic transcript entries during stale or empty history refreshes. Use #66875 or a new narrow issue for any remaining flicker path that still reproduces on current main. What I checked:
So I’m closing this as already implemented rather than keeping a duplicate issue open. Codex Review notes: model gpt-5.5, reasoning high; reviewed against d54d2d6b9b8a; fix evidence: release v2026.4.24, commit d54d2d6b9b8a. |
Summary
chat.historyonsession.messagewhile the current chat is still sending, loading, or streaming.ui/src/ui/app-gateway.tsso same-sessionsession.messageevents do not reload history during an active chat, and added a regression test for that behavior.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause (if applicable)
session.messageevents could triggerloadChatHistory(...)for the active session even while the same chat was still in an active local send/load/stream state.session.message.Regression Test Plan (if applicable)
ui/src/ui/app-gateway.sessions.node.test.tssession.messageevent arrives for the active session during an active chat flow, the UI does not reload chat historysession.messageevent handler and can be locked down directly without a broader end-to-end harnesssession.messagenormally reloads historyUser-visible / Behavior Changes
session.messagearrives for the current session.Diagram (if applicable)
Security Impact (required)
Yes, explain risk + mitigation:Repro + Verification
Environment
Steps
session.messageto fire for the same session.Expected
session.messageduring active flowActual
session.messagecould trigger history reload during active chat flow and contribute to flicker/collapse/duplicate behaviorEvidence
Attach at least one:
Human Verification (required)
chatRunIdsessions.changedpathsReview Conversations
Compatibility / Migration
Risks and Mitigations