From 28857413b38196bbaf2f5fb50d91cc225ff1ad52 Mon Sep 17 00:00:00 2001 From: murashit Date: Tue, 23 Jun 2026 19:32:51 +0900 Subject: [PATCH] Extract chat session graph responsibilities --- .../threads/start-new-thread-actions.ts | 28 +++++++++++++++++++ src/features/chat/host/session-graph.ts | 19 +++++++------ 2 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 src/features/chat/application/threads/start-new-thread-actions.ts diff --git a/src/features/chat/application/threads/start-new-thread-actions.ts b/src/features/chat/application/threads/start-new-thread-actions.ts new file mode 100644 index 00000000..3c409d81 --- /dev/null +++ b/src/features/chat/application/threads/start-new-thread-actions.ts @@ -0,0 +1,28 @@ +import type { ActiveThreadIdentitySync } from "./active-thread-identity-sync"; +import { chatTurnBusy } from "../state/root-reducer"; +import type { ChatStateStore } from "../state/store"; + +export interface StartNewThreadActions { + startNewThread(): Promise; +} + +interface StartNewThreadActionsHost { + stateStore: ChatStateStore; + identity: ActiveThreadIdentitySync; + focusComposer: () => void; +} + +export function createStartNewThreadActions(host: StartNewThreadActionsHost): StartNewThreadActions { + return { + startNewThread: () => startNewThread(host), + }; +} + +async function startNewThread(host: StartNewThreadActionsHost): Promise { + if (chatTurnBusy(host.stateStore.getState())) return; + + host.identity.clearActiveThreadIdentity(); + host.stateStore.dispatch({ type: "ui/panel-set", panel: null }); + host.stateStore.dispatch({ type: "connection/status-set", statusText: "New chat." }); + host.focusComposer(); +} diff --git a/src/features/chat/host/session-graph.ts b/src/features/chat/host/session-graph.ts index f1d3c5a8..4097293e 100644 --- a/src/features/chat/host/session-graph.ts +++ b/src/features/chat/host/session-graph.ts @@ -18,7 +18,7 @@ import type { ComposerSubmitActions } from "../application/conversation/composer import { reconnectPanel, type ChatReconnectActionsHost } from "../application/connection/reconnect-actions"; import { runtimeSnapshotForChatState } from "../application/runtime/snapshot"; import { createChatRuntimeSettingsActions } from "../application/runtime/settings-actions"; -import { chatTurnBusy, type ChatAction, type ChatConnectionPhase } from "../application/state/root-reducer"; +import type { ChatAction, ChatConnectionPhase } from "../application/state/root-reducer"; import { messageStreamItems } from "../application/state/message-stream"; import type { ChatStateStore } from "../application/state/store"; import type { ChatResumeWorkTracker, ChatViewDeferredTasks } from "../application/lifecycle"; @@ -35,6 +35,7 @@ import { import type { RestorationController } from "../application/threads/restoration-controller"; import type { ResumeActions } from "../application/threads/resume-actions"; import { createSelectionActions } from "../application/threads/selection-actions"; +import { createStartNewThreadActions } from "../application/threads/start-new-thread-actions"; import { createThreadManagementActions, type ThreadManagementActionsHost } from "../application/threads/thread-management-actions"; import type { ChatServerDiagnosticsActions } from "../app-server/actions/diagnostics"; import type { ChatServerMetadataActions } from "../app-server/actions/metadata"; @@ -278,14 +279,14 @@ export function createChatPanelSessionGraph(host: ChatPanelSessionGraphHost): Ch const composerSurface = createSessionComposerSurface(threadLifecycle, runtimeSettings); const composerController = createSessionComposerController(host, composerSurface, runtimeSettings); - const startNewThread = async (): Promise => { - if (chatTurnBusy(stateStore.getState())) return; - - identity.clearActiveThreadIdentity(); - stateStore.dispatch({ type: "ui/panel-set", panel: null }); - stateStore.dispatch({ type: "connection/status-set", statusText: "New chat." }); - composerController.focus(); - }; + const newThreadActions = createStartNewThreadActions({ + stateStore, + identity, + focusComposer: () => { + composerController.focus(); + }, + }); + const startNewThread = () => newThreadActions.startNewThread(); const threadActionParts = createThreadActionParts(host, { operations: threadOperations, connectedClient,