mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Clarify chat state reset and placeholders
This commit is contained in:
parent
0b379ecc93
commit
cd43d0c96a
2 changed files with 136 additions and 70 deletions
|
|
@ -210,41 +210,22 @@ export function createChatState(): ChatState {
|
|||
activeThreadId: null,
|
||||
activeThreadCwd: null,
|
||||
turnLifecycle: { kind: "idle" },
|
||||
activeModel: null,
|
||||
activeReasoningEffort: null,
|
||||
activeCollaborationMode: "default",
|
||||
activeServiceTier: null,
|
||||
activeApprovalPolicy: null,
|
||||
activeApprovalsReviewer: null,
|
||||
activePermissionProfile: null,
|
||||
...initialActiveRuntimeState(),
|
||||
activeThreadCreationCliVersion: null,
|
||||
appServerDiagnostics: createAppServerDiagnostics(),
|
||||
requestedModel: unchangedRuntimeSetting(),
|
||||
requestedReasoningEffort: unchangedRuntimeSetting(),
|
||||
requestedApprovalsReviewer: unchangedRuntimeSetting(),
|
||||
selectedCollaborationMode: "default",
|
||||
requestedServiceTier: unchangedRuntimeSetting(),
|
||||
...initialRequestedRuntimeState(),
|
||||
tokenUsage: null,
|
||||
rateLimit: null,
|
||||
displayItems: [],
|
||||
turnDiffs: new Map(),
|
||||
approvals: [],
|
||||
pendingUserInputs: [],
|
||||
userInputDrafts: new Map(),
|
||||
...initialDisplayState(),
|
||||
...initialPendingRequestState(),
|
||||
listedThreads: [],
|
||||
threadsLoaded: false,
|
||||
historyCursor: null,
|
||||
loadingHistory: false,
|
||||
composerDraft: "",
|
||||
runtimePicker: null,
|
||||
...initialHistoryState(),
|
||||
...initialComposerState(),
|
||||
...initialPanelUiState(),
|
||||
availableModels: [],
|
||||
availableSkills: [],
|
||||
reportedLogs: new Set(),
|
||||
composerSuggestSelected: 0,
|
||||
composerSuggestions: [],
|
||||
composerSuggestionsDismissedSignature: null,
|
||||
messagesPinnedToBottom: true,
|
||||
openDetails: new Set(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -340,16 +321,10 @@ function reduceThreadState(state: ChatState, action: ThreadAction): ChatState {
|
|||
activePermissionProfile: action.activePermissionProfile,
|
||||
activeThreadCreationCliVersion: action.thread.cliVersion,
|
||||
tokenUsage: null,
|
||||
historyCursor: null,
|
||||
loadingHistory: false,
|
||||
...initialHistoryState(),
|
||||
...initialPendingRequestState(),
|
||||
...initialComposerState(),
|
||||
turnDiffs: new Map(),
|
||||
approvals: [],
|
||||
pendingUserInputs: [],
|
||||
userInputDrafts: new Map(),
|
||||
composerDraft: "",
|
||||
composerSuggestSelected: 0,
|
||||
composerSuggestions: [],
|
||||
composerSuggestionsDismissedSignature: null,
|
||||
displayItems: action.displayItems ?? [],
|
||||
listedThreads: action.listedThreads ?? state.listedThreads,
|
||||
messagesPinnedToBottom: action.forceMessagesToBottom ?? true,
|
||||
|
|
@ -386,17 +361,10 @@ function reduceThreadState(state: ChatState, action: ThreadAction): ChatState {
|
|||
patchChatState(state, {
|
||||
activeThreadId: action.threadId,
|
||||
activeThreadCwd: null,
|
||||
activeModel: null,
|
||||
activeReasoningEffort: null,
|
||||
activeCollaborationMode: "default",
|
||||
activeServiceTier: null,
|
||||
activeApprovalPolicy: null,
|
||||
activeApprovalsReviewer: null,
|
||||
activePermissionProfile: null,
|
||||
...initialActiveRuntimeState(),
|
||||
activeThreadCreationCliVersion: null,
|
||||
tokenUsage: null,
|
||||
historyCursor: null,
|
||||
loadingHistory: false,
|
||||
...initialHistoryState(),
|
||||
displayItems: [action.item],
|
||||
turnDiffs: new Map(),
|
||||
messagesPinnedToBottom: true,
|
||||
|
|
@ -565,9 +533,7 @@ function reduceRuntimeState(state: ChatState, action: RuntimeAction): ChatState
|
|||
export function clearActiveTurnState(state: ChatState): ChatState {
|
||||
return patchChatState(state, {
|
||||
turnLifecycle: transitionChatTurnLifecycleState(state.turnLifecycle, { type: "cleared" }),
|
||||
approvals: [],
|
||||
pendingUserInputs: [],
|
||||
userInputDrafts: new Map(),
|
||||
...initialPendingRequestState(),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -576,37 +542,19 @@ export function clearActiveThreadState(state: ChatState): ChatState {
|
|||
patchChatState(state, {
|
||||
activeThreadId: null,
|
||||
activeThreadCwd: null,
|
||||
activeModel: null,
|
||||
activeReasoningEffort: null,
|
||||
activeCollaborationMode: "default",
|
||||
activeServiceTier: null,
|
||||
activeApprovalPolicy: null,
|
||||
activeApprovalsReviewer: null,
|
||||
activePermissionProfile: null,
|
||||
...initialActiveRuntimeState(),
|
||||
activeThreadCreationCliVersion: null,
|
||||
tokenUsage: null,
|
||||
historyCursor: null,
|
||||
loadingHistory: false,
|
||||
displayItems: [],
|
||||
turnDiffs: new Map(),
|
||||
composerDraft: "",
|
||||
composerSuggestSelected: 0,
|
||||
composerSuggestions: [],
|
||||
composerSuggestionsDismissedSignature: null,
|
||||
messagesPinnedToBottom: true,
|
||||
...initialHistoryState(),
|
||||
...initialDisplayState(),
|
||||
...initialComposerState(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function clearConnectionScopedState(state: ChatState): ChatState {
|
||||
return patchChatState(clearActiveTurnState(state), {
|
||||
activeModel: null,
|
||||
activeReasoningEffort: null,
|
||||
activeCollaborationMode: "default",
|
||||
activeServiceTier: null,
|
||||
activeApprovalPolicy: null,
|
||||
activeApprovalsReviewer: null,
|
||||
activePermissionProfile: null,
|
||||
...initialActiveRuntimeState(),
|
||||
activeThreadCreationCliVersion: null,
|
||||
rateLimit: null,
|
||||
listedThreads: [],
|
||||
|
|
@ -618,6 +566,82 @@ export function clearConnectionScopedState(state: ChatState): ChatState {
|
|||
});
|
||||
}
|
||||
|
||||
function initialActiveRuntimeState(): Pick<
|
||||
ChatState,
|
||||
| "activeModel"
|
||||
| "activeReasoningEffort"
|
||||
| "activeCollaborationMode"
|
||||
| "activeServiceTier"
|
||||
| "activeApprovalPolicy"
|
||||
| "activeApprovalsReviewer"
|
||||
| "activePermissionProfile"
|
||||
> {
|
||||
return {
|
||||
activeModel: null,
|
||||
activeReasoningEffort: null,
|
||||
activeCollaborationMode: "default",
|
||||
activeServiceTier: null,
|
||||
activeApprovalPolicy: null,
|
||||
activeApprovalsReviewer: null,
|
||||
activePermissionProfile: null,
|
||||
};
|
||||
}
|
||||
|
||||
function initialRequestedRuntimeState(): Pick<
|
||||
ChatState,
|
||||
"requestedModel" | "requestedReasoningEffort" | "requestedApprovalsReviewer" | "selectedCollaborationMode" | "requestedServiceTier"
|
||||
> {
|
||||
return {
|
||||
requestedModel: unchangedRuntimeSetting(),
|
||||
requestedReasoningEffort: unchangedRuntimeSetting(),
|
||||
requestedApprovalsReviewer: unchangedRuntimeSetting(),
|
||||
selectedCollaborationMode: "default",
|
||||
requestedServiceTier: unchangedRuntimeSetting(),
|
||||
};
|
||||
}
|
||||
|
||||
function initialDisplayState(): Pick<ChatState, "displayItems" | "turnDiffs" | "messagesPinnedToBottom"> {
|
||||
return {
|
||||
displayItems: [],
|
||||
turnDiffs: new Map(),
|
||||
messagesPinnedToBottom: true,
|
||||
};
|
||||
}
|
||||
|
||||
function initialPendingRequestState(): Pick<ChatState, "approvals" | "pendingUserInputs" | "userInputDrafts"> {
|
||||
return {
|
||||
approvals: [],
|
||||
pendingUserInputs: [],
|
||||
userInputDrafts: new Map(),
|
||||
};
|
||||
}
|
||||
|
||||
function initialHistoryState(): Pick<ChatState, "historyCursor" | "loadingHistory"> {
|
||||
return {
|
||||
historyCursor: null,
|
||||
loadingHistory: false,
|
||||
};
|
||||
}
|
||||
|
||||
function initialComposerState(): Pick<
|
||||
ChatState,
|
||||
"composerDraft" | "composerSuggestSelected" | "composerSuggestions" | "composerSuggestionsDismissedSignature"
|
||||
> {
|
||||
return {
|
||||
composerDraft: "",
|
||||
composerSuggestSelected: 0,
|
||||
composerSuggestions: [],
|
||||
composerSuggestionsDismissedSignature: null,
|
||||
};
|
||||
}
|
||||
|
||||
function initialPanelUiState(): Pick<ChatState, "runtimePicker" | "openDetails"> {
|
||||
return {
|
||||
runtimePicker: null,
|
||||
openDetails: new Set(),
|
||||
};
|
||||
}
|
||||
|
||||
export function cloneChatState(state: ChatState): ChatState {
|
||||
return {
|
||||
...state,
|
||||
|
|
|
|||
|
|
@ -115,6 +115,48 @@ describe("chatReducer", () => {
|
|||
expect(next.displayItems).toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps composer state when restoring a thread placeholder", () => {
|
||||
const state = createChatState();
|
||||
state.activeThreadId = "previous-thread";
|
||||
state.turnLifecycle = { kind: "running", turnId: "previous-turn" };
|
||||
state.activeModel = "gpt-5.1";
|
||||
state.historyCursor = "cursor";
|
||||
state.loadingHistory = true;
|
||||
state.composerDraft = "draft in this panel";
|
||||
state.composerSuggestSelected = 1;
|
||||
state.composerSuggestions = [suggestion("/resume")];
|
||||
state.composerSuggestionsDismissedSignature = "dismissed";
|
||||
state.displayItems = [message("previous-message")];
|
||||
state.turnDiffs = new Map([["previous-turn", "@@"]]);
|
||||
state.approvals = [approval(1)];
|
||||
state.pendingUserInputs = [userInput(2)];
|
||||
state.userInputDrafts = new Map([["2:note", "answer"]]);
|
||||
state.messagesPinnedToBottom = false;
|
||||
const placeholder = message("placeholder");
|
||||
|
||||
const next = chatReducer(state, {
|
||||
type: "thread/restored-placeholder",
|
||||
threadId: "restored-thread",
|
||||
item: placeholder,
|
||||
});
|
||||
|
||||
expect(next.activeThreadId).toBe("restored-thread");
|
||||
expect(activeTurnId(next)).toBeNull();
|
||||
expect(next.activeModel).toBeNull();
|
||||
expect(next.historyCursor).toBeNull();
|
||||
expect(next.loadingHistory).toBe(false);
|
||||
expect(next.displayItems).toEqual([placeholder]);
|
||||
expect(next.turnDiffs.size).toBe(0);
|
||||
expect(next.approvals).toEqual([]);
|
||||
expect(next.pendingUserInputs).toEqual([]);
|
||||
expect(next.userInputDrafts.size).toBe(0);
|
||||
expect(next.messagesPinnedToBottom).toBe(true);
|
||||
expect(next.composerDraft).toBe("draft in this panel");
|
||||
expect(next.composerSuggestSelected).toBe(1);
|
||||
expect(next.composerSuggestions).toEqual([suggestion("/resume")]);
|
||||
expect(next.composerSuggestionsDismissedSignature).toBe("dismissed");
|
||||
});
|
||||
|
||||
it("clones map and set backed state when updating turn diffs and open panels", () => {
|
||||
const state = createChatState();
|
||||
state.turnDiffs = new Map([["turn", "old"]]);
|
||||
|
|
|
|||
Loading…
Reference in a new issue