mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 17:30:31 +00:00
Clarify chat reducer state scopes
This commit is contained in:
parent
ca4db5f0cc
commit
e8d2a637ab
5 changed files with 100 additions and 137 deletions
|
|
@ -17,6 +17,17 @@ export type RequestAction =
|
|||
| { type: "request/user-input-queued"; input: PendingUserInput }
|
||||
| { type: "request/user-input-draft-set"; key: string; value: string };
|
||||
|
||||
export function isRequestAction(action: { type: string }): action is RequestAction {
|
||||
switch (action.type) {
|
||||
case "request/approval-queued":
|
||||
case "request/user-input-queued":
|
||||
case "request/user-input-draft-set":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function initialChatRequestState(): ChatRequestState {
|
||||
return {
|
||||
approvals: [],
|
||||
|
|
|
|||
|
|
@ -88,12 +88,6 @@ export interface DisclosureSetAction {
|
|||
open: boolean;
|
||||
}
|
||||
|
||||
export interface UserInputDraftSetAction {
|
||||
type: "request/user-input-draft-set";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface TurnOptimisticStartedAction {
|
||||
type: "turn/optimistic-started";
|
||||
item: MessageStreamItem;
|
||||
|
|
@ -111,11 +105,6 @@ export interface TurnStartFailedAction {
|
|||
items: readonly MessageStreamItem[];
|
||||
}
|
||||
|
||||
export interface MessageStreamItemAddedAction {
|
||||
type: "message-stream/item-added";
|
||||
item: MessageStreamItem;
|
||||
}
|
||||
|
||||
export function activeThreadSettingsAppliedAction(settings: ActiveThreadSettingsAppliedActionSettings): ActiveThreadSettingsAppliedAction {
|
||||
return {
|
||||
type: "active-thread/settings-applied",
|
||||
|
|
|
|||
|
|
@ -70,6 +70,27 @@ export type MessageStreamAction =
|
|||
}
|
||||
| { type: "message-stream/turn-diff-updated"; turnId: string; diff: string };
|
||||
|
||||
export function isMessageStreamAction(action: { type: string }): action is MessageStreamAction {
|
||||
switch (action.type) {
|
||||
case "message-stream/item-added":
|
||||
case "message-stream/system-item-added":
|
||||
case "message-stream/deduped-log-added":
|
||||
case "message-stream/history-loading-set":
|
||||
case "message-stream/items-replaced":
|
||||
case "message-stream/item-upserted":
|
||||
case "message-stream/reasoning-completed":
|
||||
case "message-stream/assistant-delta-appended":
|
||||
case "message-stream/plan-delta-appended":
|
||||
case "message-stream/item-text-appended":
|
||||
case "message-stream/tool-output-appended":
|
||||
case "message-stream/item-output-appended":
|
||||
case "message-stream/turn-diff-updated":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function initialChatMessageStreamState(items: readonly MessageStreamItem[] = []): ChatMessageStreamState {
|
||||
return {
|
||||
stableItems: items,
|
||||
|
|
|
|||
|
|
@ -38,14 +38,13 @@ import type {
|
|||
ClearLocalTurnAction,
|
||||
ConnectionInitializedAction,
|
||||
ThreadListAppliedAction,
|
||||
MessageStreamItemAddedAction,
|
||||
TurnOptimisticStartedAction,
|
||||
TurnStartAcknowledgedAction,
|
||||
TurnStartFailedAction,
|
||||
UserInputDraftSetAction,
|
||||
} from "./actions";
|
||||
import {
|
||||
initialChatMessageStreamState,
|
||||
isMessageStreamAction,
|
||||
messageStreamItems,
|
||||
messageStreamStartActiveSegment,
|
||||
messageStreamWithActiveTurnItems,
|
||||
|
|
@ -57,6 +56,7 @@ import {
|
|||
} from "./message-stream";
|
||||
import {
|
||||
initialChatRequestState,
|
||||
isRequestAction,
|
||||
reduceRequestSlice,
|
||||
resolveChatRequest,
|
||||
type ChatRequestState,
|
||||
|
|
@ -246,9 +246,7 @@ type ChatSliceAction =
|
|||
| ActiveThreadAction
|
||||
| RuntimeAction
|
||||
| RequestAction
|
||||
| UserInputDraftSetAction
|
||||
| MessageStreamAction
|
||||
| MessageStreamItemAddedAction
|
||||
| ComposerAction
|
||||
| UiAction;
|
||||
|
||||
|
|
@ -291,9 +289,9 @@ export function chatReducer(state: ChatState, action: ChatAction): ChatState {
|
|||
function reduceChatTransition(state: ChatState, action: ChatTransitionAction): ChatState {
|
||||
switch (action.type) {
|
||||
case "connection/scoped-cleared":
|
||||
return reduceDisconnectedConnectionStateClearedTransition(state);
|
||||
return clearConnectionScopedState(state);
|
||||
case "active-thread/cleared":
|
||||
return reduceActiveThreadClearedTransition(state);
|
||||
return clearThreadScopedState(state);
|
||||
case "active-thread/resumed":
|
||||
return reduceActiveThreadResumedTransition(state, action);
|
||||
case "active-thread/settings-applied":
|
||||
|
|
@ -307,7 +305,7 @@ function reduceChatTransition(state: ChatState, action: ChatTransitionAction): C
|
|||
case "turn/completed":
|
||||
return reduceTurnCompletedTransition(state, action);
|
||||
case "turn/scoped-cleared":
|
||||
return reduceTurnScopedClearedTransition(state);
|
||||
return clearTurnScopedState(state);
|
||||
case "turn/optimistic-started":
|
||||
return reduceTurnOptimisticStartedTransition(state, action);
|
||||
case "turn/start-acknowledged":
|
||||
|
|
@ -321,17 +319,10 @@ function reduceChatTransition(state: ChatState, action: ChatTransitionAction): C
|
|||
}
|
||||
}
|
||||
|
||||
function reduceDisconnectedConnectionStateClearedTransition(state: ChatState): ChatState {
|
||||
return clearDisconnectedConnectionState(state);
|
||||
}
|
||||
|
||||
function reduceActiveThreadClearedTransition(state: ChatState): ChatState {
|
||||
return clearActiveThreadState(state);
|
||||
}
|
||||
|
||||
function reduceActiveThreadResumedTransition(state: ChatState, action: ActiveThreadResumedAction): ChatState {
|
||||
const runtimeBase = action.preserveRequestedRuntimeSettings ? state.runtime : initialChatRuntimeState();
|
||||
return patchChatState(clearActiveTurnState(state), {
|
||||
const turnScopedState = clearTurnScopedState(state);
|
||||
return patchChatState(turnScopedState, {
|
||||
connection: {
|
||||
...state.connection,
|
||||
statusText: action.status ?? state.connection.statusText,
|
||||
|
|
@ -385,7 +376,7 @@ function reduceActiveThreadSettingsAppliedTransition(state: ChatState, action: A
|
|||
}
|
||||
|
||||
function reduceActiveThreadRestoredPlaceholderTransition(state: ChatState, action: ActiveThreadRestoredPlaceholderAction): ChatState {
|
||||
return clearActiveTurnState(
|
||||
return clearTurnScopedState(
|
||||
patchChatState(state, {
|
||||
activeThread: {
|
||||
id: action.threadId,
|
||||
|
|
@ -432,10 +423,6 @@ function reduceTurnCompletedTransition(state: ChatState, action: TurnCompletedAc
|
|||
});
|
||||
}
|
||||
|
||||
function reduceTurnScopedClearedTransition(state: ChatState): ChatState {
|
||||
return clearActiveTurnState(state);
|
||||
}
|
||||
|
||||
function reduceTurnOptimisticStartedTransition(state: ChatState, action: TurnOptimisticStartedAction): ChatState {
|
||||
const lifecycle = transitionChatTurnLifecycleState(state.turn.lifecycle, {
|
||||
type: "optimistic-started",
|
||||
|
|
@ -492,6 +479,44 @@ function reduceRequestResolvedTransition(state: ChatState, action: RequestResolv
|
|||
});
|
||||
}
|
||||
|
||||
function clearTurnScopedState(state: ChatState): ChatState {
|
||||
return patchChatState(state, {
|
||||
turn: {
|
||||
lifecycle: transitionChatTurnLifecycleState(state.turn.lifecycle, { type: "cleared" }),
|
||||
},
|
||||
messageStream: messageStreamWithItems(state.messageStream, messageStreamItems(state.messageStream)),
|
||||
requests: initialRequestState(),
|
||||
ui: clearAllRequestDisclosures(state.ui),
|
||||
});
|
||||
}
|
||||
|
||||
function clearThreadScopedState(state: ChatState): ChatState {
|
||||
return clearTurnScopedState(
|
||||
patchChatState(state, {
|
||||
activeThread: initialActiveThreadState(),
|
||||
runtime: initialChatRuntimeState(),
|
||||
messageStream: initialMessageStreamState(),
|
||||
composer: initialComposerState(),
|
||||
ui: initialUiState(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function clearConnectionScopedState(state: ChatState): ChatState {
|
||||
return patchChatState(clearTurnScopedState(state), {
|
||||
activeThread: initialActiveThreadState(),
|
||||
runtime: initialChatRuntimeState(),
|
||||
connection: {
|
||||
...state.connection,
|
||||
serverDiagnostics: createServerDiagnostics(),
|
||||
rateLimit: null,
|
||||
availableModels: [],
|
||||
availableSkills: [],
|
||||
},
|
||||
threadList: initialThreadListState(),
|
||||
});
|
||||
}
|
||||
|
||||
function reduceChatSlices(state: ChatState, action: ChatSliceAction): ChatState {
|
||||
return patchChatState(state, {
|
||||
connection: reduceConnectionSlice(state.connection, action),
|
||||
|
|
@ -601,44 +626,6 @@ function reduceComposerSlice(state: ChatComposerState, action: ChatSliceAction):
|
|||
}
|
||||
}
|
||||
|
||||
function clearActiveTurnState(state: ChatState): ChatState {
|
||||
return patchChatState(state, {
|
||||
turn: {
|
||||
lifecycle: transitionChatTurnLifecycleState(state.turn.lifecycle, { type: "cleared" }),
|
||||
},
|
||||
messageStream: messageStreamWithItems(state.messageStream, messageStreamItems(state.messageStream)),
|
||||
requests: initialRequestState(),
|
||||
ui: clearAllRequestDisclosures(state.ui),
|
||||
});
|
||||
}
|
||||
|
||||
function clearActiveThreadState(state: ChatState): ChatState {
|
||||
return clearActiveTurnState(
|
||||
patchChatState(state, {
|
||||
activeThread: initialActiveThreadState(),
|
||||
runtime: initialChatRuntimeState(),
|
||||
messageStream: initialMessageStreamState(),
|
||||
composer: initialComposerState(),
|
||||
ui: initialUiState(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function clearDisconnectedConnectionState(state: ChatState): ChatState {
|
||||
return patchChatState(clearActiveTurnState(state), {
|
||||
activeThread: initialActiveThreadState(),
|
||||
runtime: initialChatRuntimeState(),
|
||||
connection: {
|
||||
...state.connection,
|
||||
serverDiagnostics: createServerDiagnostics(),
|
||||
rateLimit: null,
|
||||
availableModels: [],
|
||||
availableSkills: [],
|
||||
},
|
||||
threadList: initialThreadListState(),
|
||||
});
|
||||
}
|
||||
|
||||
function initialConnectionState(): ChatConnectionState {
|
||||
return {
|
||||
phase: { kind: "idle" },
|
||||
|
|
@ -749,38 +736,6 @@ function cloneActiveSegment(segment: ChatMessageStreamActiveSegment | null): Cha
|
|||
};
|
||||
}
|
||||
|
||||
function isMessageStreamAction(action: ChatSliceAction): action is MessageStreamAction {
|
||||
switch (action.type) {
|
||||
case "message-stream/item-added":
|
||||
case "message-stream/system-item-added":
|
||||
case "message-stream/deduped-log-added":
|
||||
case "message-stream/history-loading-set":
|
||||
case "message-stream/items-replaced":
|
||||
case "message-stream/item-upserted":
|
||||
case "message-stream/reasoning-completed":
|
||||
case "message-stream/assistant-delta-appended":
|
||||
case "message-stream/plan-delta-appended":
|
||||
case "message-stream/item-text-appended":
|
||||
case "message-stream/tool-output-appended":
|
||||
case "message-stream/item-output-appended":
|
||||
case "message-stream/turn-diff-updated":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isRequestAction(action: ChatSliceAction): action is RequestAction {
|
||||
switch (action.type) {
|
||||
case "request/approval-queued":
|
||||
case "request/user-input-queued":
|
||||
case "request/user-input-draft-set":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function setComposerSuggestionsSlice(
|
||||
state: ChatComposerState,
|
||||
suggestions: readonly ComposerSuggestion[],
|
||||
|
|
|
|||
|
|
@ -28,24 +28,19 @@ interface ChatMessageActionsUiState {
|
|||
readonly forkActionsItemId: string | null;
|
||||
}
|
||||
|
||||
export type ChatDisclosureBucket =
|
||||
| "toolResults"
|
||||
| "activityGroups"
|
||||
| "agentDetails"
|
||||
| "textDetails"
|
||||
| "userMessageExpanded"
|
||||
| "goalObjectiveExpanded"
|
||||
| "approvalDetails";
|
||||
const CHAT_DISCLOSURE_BUCKETS = [
|
||||
"toolResults",
|
||||
"activityGroups",
|
||||
"agentDetails",
|
||||
"textDetails",
|
||||
"userMessageExpanded",
|
||||
"goalObjectiveExpanded",
|
||||
"approvalDetails",
|
||||
] as const;
|
||||
|
||||
export interface ChatDisclosureUiState {
|
||||
readonly toolResults: ReadonlySet<string>;
|
||||
readonly activityGroups: ReadonlySet<string>;
|
||||
readonly agentDetails: ReadonlySet<string>;
|
||||
readonly textDetails: ReadonlySet<string>;
|
||||
readonly userMessageExpanded: ReadonlySet<string>;
|
||||
readonly goalObjectiveExpanded: ReadonlySet<string>;
|
||||
readonly approvalDetails: ReadonlySet<string>;
|
||||
}
|
||||
export type ChatDisclosureBucket = (typeof CHAT_DISCLOSURE_BUCKETS)[number];
|
||||
|
||||
export type ChatDisclosureUiState = Readonly<Record<ChatDisclosureBucket, ReadonlySet<string>>>;
|
||||
|
||||
export interface ChatUiState {
|
||||
readonly toolbarPanel: "history" | "chat-actions" | "status-panel" | null;
|
||||
|
|
@ -152,15 +147,7 @@ export function reduceUiSlice(state: ChatUiState, action: UiAction): ChatUiState
|
|||
}
|
||||
|
||||
export function cloneDisclosureUiState(state: ChatDisclosureUiState): ChatDisclosureUiState {
|
||||
return {
|
||||
toolResults: new Set(state.toolResults),
|
||||
activityGroups: new Set(state.activityGroups),
|
||||
agentDetails: new Set(state.agentDetails),
|
||||
textDetails: new Set(state.textDetails),
|
||||
userMessageExpanded: new Set(state.userMessageExpanded),
|
||||
goalObjectiveExpanded: new Set(state.goalObjectiveExpanded),
|
||||
approvalDetails: new Set(state.approvalDetails),
|
||||
};
|
||||
return disclosureUiStateFrom((bucket) => new Set(state[bucket]));
|
||||
}
|
||||
|
||||
export function maybeClearGoalObjectiveExpansion(
|
||||
|
|
@ -247,15 +234,15 @@ function initialMessageActionsUiState(): ChatMessageActionsUiState {
|
|||
}
|
||||
|
||||
function initialDisclosureUiState(): ChatDisclosureUiState {
|
||||
return {
|
||||
toolResults: new Set(),
|
||||
activityGroups: new Set(),
|
||||
agentDetails: new Set(),
|
||||
textDetails: new Set(),
|
||||
userMessageExpanded: new Set(),
|
||||
goalObjectiveExpanded: new Set(),
|
||||
approvalDetails: new Set(),
|
||||
};
|
||||
return disclosureUiStateFrom(() => new Set());
|
||||
}
|
||||
|
||||
function disclosureUiStateFrom(factory: (bucket: ChatDisclosureBucket) => ReadonlySet<string>): ChatDisclosureUiState {
|
||||
const disclosures = {} as Record<ChatDisclosureBucket, ReadonlySet<string>>;
|
||||
for (const bucket of CHAT_DISCLOSURE_BUCKETS) {
|
||||
disclosures[bucket] = factory(bucket);
|
||||
}
|
||||
return disclosures;
|
||||
}
|
||||
|
||||
function goalObjectiveResetKey(goal: ThreadGoal | null): string {
|
||||
|
|
|
|||
Loading…
Reference in a new issue