Skip to content

Commit afe83cd

Browse files
committed
🤖 Buffer init events like stream events during replay
Init events can arrive before or after caught-up: - Before: During replay from init-status.json (historical) - After: During live workspace creation (real-time) Like stream events, init events are now explicitly buffered during replay to avoid O(N) re-renders and ensure proper ordering. Added detailed comments explaining this behavior. Generated with `cmux`
1 parent 64fde2d commit afe83cd

File tree

1 file changed

+21
-7
lines changed

1 file changed

+21
-7
lines changed

src/stores/WorkspaceStore.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import {
2222
isToolCallEnd,
2323
isReasoningDelta,
2424
isReasoningEnd,
25+
isInitStart,
26+
isInitOutput,
27+
isInitEnd,
2528
} from "@/types/ipc";
2629
import { MapStore } from "./MapStore";
2730
import { createDisplayUsage } from "@/utils/tokens/displayUsage";
@@ -780,6 +783,15 @@ export class WorkspaceStore {
780783
return this.aggregators.get(workspaceId)!;
781784
}
782785

786+
/**
787+
* Check if data is a stream event or init event that should be buffered until caught-up.
788+
*
789+
* Init events may arrive:
790+
* - BEFORE caught-up: During replay from init-status.json (historical)
791+
* - AFTER caught-up: During live workspace creation (real-time)
792+
*
793+
* Like stream events, init events are buffered during replay to avoid O(N) re-renders.
794+
*/
783795
private isStreamEvent(data: WorkspaceChatMessage): boolean {
784796
return (
785797
isStreamStart(data) ||
@@ -790,9 +802,10 @@ export class WorkspaceStore {
790802
isToolCallDelta(data) ||
791803
isToolCallEnd(data) ||
792804
isReasoningDelta(data) ||
793-
isReasoningEnd(data)
794-
// Note: Init events (type:"init-*") and regular messages (role:"user"|"assistant")
795-
// are excluded from this list and flow through the regular message path below
805+
isReasoningEnd(data) ||
806+
isInitStart(data) ||
807+
isInitOutput(data) ||
808+
isInitEnd(data)
796809
);
797810
}
798811

@@ -978,19 +991,20 @@ export class WorkspaceStore {
978991
return;
979992
}
980993

981-
// Regular messages and other events (init, etc.)
994+
// Regular messages (CmuxMessage without type field)
982995
const isCaughtUp = this.caughtUp.get(workspaceId) ?? false;
983996
if (!isCaughtUp && "role" in data && !("type" in data)) {
984-
// Buffer historical CmuxMessages only
997+
// Buffer historical CmuxMessages
985998
const historicalMsgs = this.historicalMessages.get(workspaceId) ?? [];
986999
historicalMsgs.push(data);
9871000
this.historicalMessages.set(workspaceId, historicalMsgs);
988-
} else {
989-
// Process all other events immediately (init events, live messages, etc.)
1001+
} else if (isCaughtUp) {
1002+
// Process live events immediately (after history loaded)
9901003
aggregator.handleMessage(data);
9911004
this.states.bump(workspaceId);
9921005
this.checkAndBumpRecencyIfChanged();
9931006
}
1007+
// Note: Init events and stream events are handled by isStreamEvent() buffering above
9941008
}
9951009
}
9961010

0 commit comments

Comments
 (0)