(event: ReturnType<typeof toAppEvent>, sessionId: string, seq: number)
| 686 | |
| 687 | // Helper: mutate rawState by applying a reducer on a snapshot then re-assigning fields |
| 688 | function applyEvent(event: ReturnType<typeof toAppEvent>, sessionId: string, seq: number): void { |
| 689 | const snapshot: KimiClientState = { |
| 690 | sessions: rawState.sessions, |
| 691 | activeSessionId: rawState.activeSessionId, |
| 692 | messagesBySession: rawState.messagesBySession, |
| 693 | approvalsBySession: rawState.approvalsBySession, |
| 694 | planReviewByToolCallId: rawState.planReviewByToolCallId, |
| 695 | questionsBySession: rawState.questionsBySession, |
| 696 | tasksBySession: rawState.tasksBySession, |
| 697 | goalBySession: rawState.goalBySession, |
| 698 | lastSeqBySession: rawState.lastSeqBySession, |
| 699 | compactionBySession: rawState.compactionBySession, |
| 700 | config: rawState.config, |
| 701 | warnings: rawState.warnings, |
| 702 | }; |
| 703 | const next = reduceAppEvent(snapshot, event, { sessionId, seq }); |
| 704 | // Assign back to the reactive proxy |
| 705 | setSessions(next.sessions); |
| 706 | setActiveSessionId(next.activeSessionId); |
| 707 | setMessagesBySession(next.messagesBySession); |
| 708 | rawState.approvalsBySession = next.approvalsBySession; |
| 709 | rawState.planReviewByToolCallId = next.planReviewByToolCallId; |
| 710 | rawState.questionsBySession = next.questionsBySession; |
| 711 | rawState.tasksBySession = next.tasksBySession; |
| 712 | rawState.goalBySession = next.goalBySession; |
| 713 | rawState.lastSeqBySession = next.lastSeqBySession; |
| 714 | rawState.compactionBySession = next.compactionBySession; |
| 715 | rawState.config = next.config ?? null; |
| 716 | rawState.warnings = next.warnings; |
| 717 | |
| 718 | if (event.type === 'configChanged') { |
| 719 | rawState.defaultModel = event.config.defaultModel ?? null; |
| 720 | } |
| 721 | |
| 722 | if (event.type === 'modelCatalogChanged') { |
| 723 | void modelProvider.loadModels(); |
| 724 | void modelProvider.loadProviders(); |
| 725 | } |
| 726 | |
| 727 | // Reflect the agent's live plan/swarm state per session (e.g. it auto-entered |
| 728 | // plan mode). Applied to the event's own session — not gated on the active |
| 729 | // session — so a background session keeps its own independent toggle state. |
| 730 | if (event.type === 'sessionUsageUpdated') { |
| 731 | if (event.swarmMode !== undefined) { |
| 732 | rawState.swarmModeBySession = { ...rawState.swarmModeBySession, [event.sessionId]: event.swarmMode }; |
| 733 | } |
| 734 | if (event.planMode !== undefined) { |
| 735 | rawState.planModeBySession = { ...rawState.planModeBySession, [event.sessionId]: event.planMode }; |
| 736 | } |
| 737 | } |
| 738 | } |
| 739 | |
| 740 | // --------------------------------------------------------------------------- |
| 741 | // Streaming event batching |
no test coverage detected