Fold chat state cloning into store

This commit is contained in:
murashit 2026-06-23 10:34:14 +09:00
parent 128e777d9e
commit f5c02b8340
2 changed files with 60 additions and 62 deletions

View file

@ -1,61 +0,0 @@
import type { ChatState } from "./root-reducer";
import { cloneDisclosureUiState } from "./ui-state";
import type { ChatMessageStreamActiveSegment, ChatMessageStreamState } from "./message-stream";
export function cloneChatState(state: ChatState): ChatState {
return {
connection: {
...state.connection,
availableModels: [...state.connection.availableModels],
availableSkills: [...state.connection.availableSkills],
},
threadList: {
listedThreads: [...state.threadList.listedThreads],
threadsLoaded: state.threadList.threadsLoaded,
},
activeThread: { ...state.activeThread },
runtime: { ...state.runtime },
turn: { lifecycle: state.turn.lifecycle },
messageStream: cloneMessageStreamState(state.messageStream),
requests: {
approvals: [...state.requests.approvals],
pendingUserInputs: [...state.requests.pendingUserInputs],
pendingMcpElicitations: [...state.requests.pendingMcpElicitations],
userInputDrafts: new Map(state.requests.userInputDrafts),
mcpElicitationDrafts: new Map(state.requests.mcpElicitationDrafts),
},
composer: {
...state.composer,
suggestions: [...state.composer.suggestions],
},
ui: {
toolbarPanel: state.ui.toolbarPanel,
archiveConfirmThreadId: state.ui.archiveConfirmThreadId,
rename: { ...state.ui.rename },
goalEditor: { ...state.ui.goalEditor },
messageActionMenu: { ...state.ui.messageActionMenu },
disclosures: cloneDisclosureUiState(state.ui.disclosures),
},
};
}
function cloneMessageStreamState(state: ChatMessageStreamState): ChatMessageStreamState {
return {
stableItems: [...state.stableItems],
activeSegment: cloneActiveSegment(state.activeSegment),
turnDiffs: new Map(state.turnDiffs),
historyCursor: state.historyCursor,
loadingHistory: state.loadingHistory,
reportedLogs: new Set(state.reportedLogs),
};
}
function cloneActiveSegment(segment: ChatMessageStreamActiveSegment | null): ChatMessageStreamActiveSegment | null {
if (!segment) return null;
return {
turnId: segment.turnId,
items: [...segment.items],
indexById: new Map(segment.indexById),
indexBySourceItemId: new Map(segment.indexBySourceItemId),
};
}

View file

@ -1,4 +1,5 @@
import { cloneChatState } from "./clone";
import { cloneDisclosureUiState } from "./ui-state";
import type { ChatMessageStreamActiveSegment, ChatMessageStreamState } from "./message-stream";
import { chatReducer, createChatState, type ChatAction, type ChatState } from "./root-reducer";
export interface ChatStateStore {
@ -27,3 +28,61 @@ export function createChatStateStore(initialState: ChatState = createChatState()
},
};
}
function cloneChatState(state: ChatState): ChatState {
return {
connection: {
...state.connection,
availableModels: [...state.connection.availableModels],
availableSkills: [...state.connection.availableSkills],
},
threadList: {
listedThreads: [...state.threadList.listedThreads],
threadsLoaded: state.threadList.threadsLoaded,
},
activeThread: { ...state.activeThread },
runtime: { ...state.runtime },
turn: { lifecycle: state.turn.lifecycle },
messageStream: cloneMessageStreamState(state.messageStream),
requests: {
approvals: [...state.requests.approvals],
pendingUserInputs: [...state.requests.pendingUserInputs],
pendingMcpElicitations: [...state.requests.pendingMcpElicitations],
userInputDrafts: new Map(state.requests.userInputDrafts),
mcpElicitationDrafts: new Map(state.requests.mcpElicitationDrafts),
},
composer: {
...state.composer,
suggestions: [...state.composer.suggestions],
},
ui: {
toolbarPanel: state.ui.toolbarPanel,
archiveConfirmThreadId: state.ui.archiveConfirmThreadId,
rename: { ...state.ui.rename },
goalEditor: { ...state.ui.goalEditor },
messageActionMenu: { ...state.ui.messageActionMenu },
disclosures: cloneDisclosureUiState(state.ui.disclosures),
},
};
}
function cloneMessageStreamState(state: ChatMessageStreamState): ChatMessageStreamState {
return {
stableItems: [...state.stableItems],
activeSegment: cloneActiveSegment(state.activeSegment),
turnDiffs: new Map(state.turnDiffs),
historyCursor: state.historyCursor,
loadingHistory: state.loadingHistory,
reportedLogs: new Set(state.reportedLogs),
};
}
function cloneActiveSegment(segment: ChatMessageStreamActiveSegment | null): ChatMessageStreamActiveSegment | null {
if (!segment) return null;
return {
turnId: segment.turnId,
items: [...segment.items],
indexById: new Map(segment.indexById),
indexBySourceItemId: new Map(segment.indexBySourceItemId),
};
}