mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Classify chat state command selectors
This commit is contained in:
parent
24b38f8163
commit
d38bdaf32c
14 changed files with 74 additions and 75 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { activeThreadId } from "../state/selectors";
|
||||
import type { ChatConnectionPhase } from "../state/root-reducer";
|
||||
import type { ChatStateStore } from "../state/store";
|
||||
import { activeThreadId } from "../threads/state-selectors";
|
||||
|
||||
const STATUS_RECONNECTING = "Reconnecting...";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { AppServerClient } from "../../../../app-server/connection/client";
|
||||
import type { CodexInput } from "../../../../domain/chat/input";
|
||||
import { submissionStateSnapshot } from "../state/selectors";
|
||||
import { submissionStateSnapshot } from "./submission-state";
|
||||
import type { ChatStateStore } from "../state/store";
|
||||
import { parseSlashCommand } from "../composer/suggestions";
|
||||
import type { SlashCommandExecutionResult } from "./slash-command-execution";
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ import type { CodexInput } from "../../../../domain/chat/input";
|
|||
import type { MessageStreamNoticeSection } from "../../domain/message-stream/items";
|
||||
import type { LocalIdSource } from "../../../../shared/id/local-id";
|
||||
import type { ChatRuntimeSettingsActions } from "../runtime/settings-actions";
|
||||
import { activeThreadId, canImplementPlanItemId } from "../state/selectors";
|
||||
import type { ChatStateStore } from "../state/store";
|
||||
import type { ThreadManagementActions } from "../threads/thread-management-actions";
|
||||
import type { GoalActions } from "../threads/goal-actions";
|
||||
import { activeThreadId } from "../threads/state-selectors";
|
||||
import { submitComposer, type ComposerSubmitActions, type ComposerSubmitActionsHost } from "./composer-submit-actions";
|
||||
import { canImplementPlanItemId } from "./plan-implementation-target";
|
||||
import { executeSlashCommandWithState, type SlashCommandExecutorHost } from "./slash-command-executor";
|
||||
import { createTurnSubmissionActions } from "./turn-submission-actions";
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
import type { ChatActiveThreadState, ChatMessageStreamState, ChatRuntimeState, ChatState, ChatTurnState } from "../state/root-reducer";
|
||||
import { chatTurnBusy } from "../state/root-reducer";
|
||||
import { messageStreamItems } from "../state/message-stream";
|
||||
import { latestImplementablePlanTargetFromItems, type PlanImplementationTarget } from "../../domain/message-stream/selectors";
|
||||
|
||||
export function canImplementPlanItemId(state: ChatState, itemId: string): boolean {
|
||||
return itemId === implementPlanTargetFromState(state)?.itemId;
|
||||
}
|
||||
|
||||
export function implementPlanTargetFromState(state: {
|
||||
activeThread: Pick<ChatActiveThreadState, "id">;
|
||||
turn: ChatTurnState;
|
||||
runtime: Pick<ChatRuntimeState, "selectedCollaborationMode">;
|
||||
messageStream: Pick<ChatMessageStreamState, "stableItems" | "activeSegment">;
|
||||
}): PlanImplementationTarget | null {
|
||||
if (!state.activeThread.id || chatTurnBusy(state) || state.runtime.selectedCollaborationMode !== "plan") {
|
||||
return null;
|
||||
}
|
||||
return latestImplementablePlanTargetFromItems(messageStreamItems(state.messageStream));
|
||||
}
|
||||
|
|
@ -13,10 +13,10 @@ import {
|
|||
import type { SlashCommandName } from "../composer/slash-commands";
|
||||
import type { ReasoningEffort } from "../../../../domain/catalog/metadata";
|
||||
import { findModelMetadataByIdOrName, supportedEffortsForModelMetadata } from "../../../../domain/catalog/metadata";
|
||||
import { submissionStateSnapshot } from "../state/selectors";
|
||||
import type { ChatStateStore } from "../state/store";
|
||||
import { currentModel, runtimeConfigOrDefault } from "../../domain/runtime/effective";
|
||||
import { runtimeSnapshotForChatState } from "../runtime/snapshot";
|
||||
import { submissionStateSnapshot } from "./submission-state";
|
||||
|
||||
export interface SlashCommandExecutorHost extends SlashCommandExecutionPorts {
|
||||
stateStore: ChatStateStore;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import type { Thread } from "../../../../domain/threads/model";
|
||||
import type { MessageStreamItem } from "../../domain/message-stream/items";
|
||||
import { activeTurnId, chatTurnBusy, pendingTurnStart, type ChatState, type PendingTurnStart } from "../state/root-reducer";
|
||||
import { messageStreamItems } from "../state/message-stream";
|
||||
|
||||
export interface SubmissionStateSnapshot {
|
||||
activeThreadId: string | null;
|
||||
activeTurnId: string | null;
|
||||
busy: boolean;
|
||||
listedThreads: readonly Thread[];
|
||||
items: readonly MessageStreamItem[];
|
||||
pendingTurnStart: PendingTurnStart | null;
|
||||
}
|
||||
|
||||
export function submissionStateSnapshot(state: ChatState): SubmissionStateSnapshot {
|
||||
return {
|
||||
activeThreadId: state.activeThread.id,
|
||||
activeTurnId: activeTurnId(state),
|
||||
busy: chatTurnBusy(state),
|
||||
listedThreads: state.threadList.listedThreads,
|
||||
items: messageStreamItems(state.messageStream),
|
||||
pendingTurnStart: pendingTurnStart(state),
|
||||
};
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ import type { AppServerClient } from "../../../../app-server/connection/client";
|
|||
import type { CodexInput } from "../../../../domain/chat/input";
|
||||
import type { ReferencedThreadMetadata } from "../../../../domain/threads/reference";
|
||||
import type { LocalIdSource } from "../../../../shared/id/local-id";
|
||||
import { submissionStateSnapshot } from "../state/selectors";
|
||||
import { STATUS_TURN_RUNNING } from "../state/status-text";
|
||||
import type { ChatStateStore } from "../state/store";
|
||||
import {
|
||||
|
|
@ -12,6 +11,7 @@ import {
|
|||
optimisticTurnStart,
|
||||
shouldAcknowledgeTurnStart,
|
||||
} from "./optimistic-turn-start";
|
||||
import { submissionStateSnapshot } from "./submission-state";
|
||||
|
||||
const STATUS_STEERED_CURRENT_TURN = "Steered current turn.";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
import { activeTurnId as selectActiveTurnId, chatTurnBusy, pendingTurnStart } from "./root-reducer";
|
||||
import type {
|
||||
ChatActiveThreadState,
|
||||
ChatRuntimeState,
|
||||
ChatState,
|
||||
ChatMessageStreamState,
|
||||
ChatTurnState,
|
||||
PendingTurnStart,
|
||||
} from "./root-reducer";
|
||||
import type { Thread } from "../../../../domain/threads/model";
|
||||
import type { MessageStreamItem } from "../../domain/message-stream/items";
|
||||
import { latestImplementablePlanTargetFromItems, type PlanImplementationTarget } from "../../domain/message-stream/selectors";
|
||||
import { messageStreamItems, messageStreamIsEmpty } from "./message-stream";
|
||||
|
||||
export interface SubmissionStateSnapshot {
|
||||
activeThreadId: string | null;
|
||||
activeTurnId: string | null;
|
||||
busy: boolean;
|
||||
listedThreads: readonly Thread[];
|
||||
items: readonly MessageStreamItem[];
|
||||
pendingTurnStart: PendingTurnStart | null;
|
||||
}
|
||||
|
||||
export function activeThreadId(state: ChatState): string | null {
|
||||
return state.activeThread.id;
|
||||
}
|
||||
|
||||
export function canSwitchToThread(state: ChatState, threadId: string): boolean {
|
||||
return !chatTurnBusy(state) || threadId === state.activeThread.id;
|
||||
}
|
||||
|
||||
export function listedThreads(state: ChatState): readonly Thread[] {
|
||||
return state.threadList.listedThreads;
|
||||
}
|
||||
|
||||
export function messageStreamItemsEmpty(state: ChatState): boolean {
|
||||
return messageStreamIsEmpty(state.messageStream);
|
||||
}
|
||||
|
||||
export function submissionStateSnapshot(state: ChatState): SubmissionStateSnapshot {
|
||||
return {
|
||||
activeThreadId: state.activeThread.id,
|
||||
activeTurnId: selectActiveTurnId(state),
|
||||
busy: chatTurnBusy(state),
|
||||
listedThreads: state.threadList.listedThreads,
|
||||
items: messageStreamItems(state.messageStream),
|
||||
pendingTurnStart: pendingTurnStart(state),
|
||||
};
|
||||
}
|
||||
|
||||
export function canImplementPlanItemId(state: ChatState, itemId: string): boolean {
|
||||
return itemId === implementPlanTargetFromState(state)?.itemId;
|
||||
}
|
||||
|
||||
export function implementPlanTargetFromState(state: {
|
||||
activeThread: Pick<ChatActiveThreadState, "id">;
|
||||
turn: ChatTurnState;
|
||||
runtime: Pick<ChatRuntimeState, "selectedCollaborationMode">;
|
||||
messageStream: Pick<ChatMessageStreamState, "stableItems" | "activeSegment">;
|
||||
}): PlanImplementationTarget | null {
|
||||
if (!state.activeThread.id || chatTurnBusy(state) || state.runtime.selectedCollaborationMode !== "plan") {
|
||||
return null;
|
||||
}
|
||||
return latestImplementablePlanTargetFromItems(messageStreamItems(state.messageStream));
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import type { RestorationController } from "./restoration-controller";
|
||||
import { activeThreadId } from "../state/selectors";
|
||||
import type { ChatStateStore } from "../state/store";
|
||||
import { activeThreadId } from "./state-selectors";
|
||||
|
||||
export interface ActiveThreadIdentitySyncHost {
|
||||
stateStore: ChatStateStore;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import type { AppServerClient } from "../../../../app-server/connection/client";
|
|||
import type { ThreadTokenUsage } from "../../../../domain/runtime/metrics";
|
||||
import { resumeChatThread, type ChatThreadResumeSnapshot } from "../../app-server/threads/resume";
|
||||
import { resumedThreadAction } from "../state/actions";
|
||||
import { activeThreadId, canSwitchToThread, listedThreads, messageStreamItemsEmpty } from "../state/selectors";
|
||||
import type { ChatStateStore } from "../state/store";
|
||||
import type { RestorationController } from "./restoration-controller";
|
||||
import type { HistoryController } from "./history-controller";
|
||||
import type { ChatResumeWorkTracker, ActiveChatResume } from "../lifecycle";
|
||||
import { activeThreadId, canSwitchToThread, listedThreads, messageStreamItemsEmpty } from "./state-selectors";
|
||||
|
||||
export interface ResumeActionsHost {
|
||||
stateStore: ChatStateStore;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { canSwitchToThread } from "../state/selectors";
|
||||
import type { ChatStateStore } from "../state/store";
|
||||
import { canSwitchToThread } from "./state-selectors";
|
||||
|
||||
export interface SelectionActionsHost {
|
||||
stateStore: ChatStateStore;
|
||||
|
|
|
|||
19
src/features/chat/application/threads/state-selectors.ts
Normal file
19
src/features/chat/application/threads/state-selectors.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import type { Thread } from "../../../../domain/threads/model";
|
||||
import { chatTurnBusy, type ChatState } from "../state/root-reducer";
|
||||
import { messageStreamIsEmpty } from "../state/message-stream";
|
||||
|
||||
export function activeThreadId(state: ChatState): string | null {
|
||||
return state.activeThread.id;
|
||||
}
|
||||
|
||||
export function canSwitchToThread(state: ChatState, threadId: string): boolean {
|
||||
return !chatTurnBusy(state) || threadId === state.activeThread.id;
|
||||
}
|
||||
|
||||
export function listedThreads(state: ChatState): readonly Thread[] {
|
||||
return state.threadList.listedThreads;
|
||||
}
|
||||
|
||||
export function messageStreamItemsEmpty(state: ChatState): boolean {
|
||||
return messageStreamIsEmpty(state.messageStream);
|
||||
}
|
||||
|
|
@ -3,8 +3,8 @@ import { describe, expect, it, vi } from "vitest";
|
|||
import type { AppServerClient } from "../../../../../src/app-server/connection/client";
|
||||
import { createChatState } from "../../../../../src/features/chat/application/state/root-reducer";
|
||||
import { createChatStateStore, type ChatStateStore } from "../../../../../src/features/chat/application/state/store";
|
||||
import { implementPlanTargetFromState } from "../../../../../src/features/chat/application/state/selectors";
|
||||
import { implementPlan, type PlanImplementationHost } from "../../../../../src/features/chat/application/conversation/composition";
|
||||
import { implementPlanTargetFromState } from "../../../../../src/features/chat/application/conversation/plan-implementation-target";
|
||||
import type { MessageStreamItem } from "../../../../../src/features/chat/domain/message-stream/items";
|
||||
|
||||
const planItem = (id: string): MessageStreamItem => ({
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { act } from "preact/test-utils";
|
|||
import { MarkdownRenderer } from "obsidian";
|
||||
|
||||
import type { MessageStreamItem } from "../../../../../src/features/chat/domain/message-stream/items";
|
||||
import { implementPlanTargetFromState } from "../../../../../src/features/chat/application/state/selectors";
|
||||
import { implementPlanTargetFromState } from "../../../../../src/features/chat/application/conversation/plan-implementation-target";
|
||||
import { MESSAGE_CONTENT_RENDERED_EVENT } from "../../../../../src/features/chat/ui/message-stream/content-events";
|
||||
import { MarkdownMessageRenderer } from "../../../../../src/features/chat/ui/message-stream/markdown-renderer";
|
||||
import { deferred } from "../../../../support/async";
|
||||
|
|
|
|||
Loading…
Reference in a new issue