mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 17:30:31 +00:00
Inline chat panel effects
This commit is contained in:
parent
3ece50abd3
commit
5265ebd3a6
6 changed files with 308 additions and 404 deletions
|
|
@ -6,9 +6,14 @@ import type { RuntimeSnapshot } from "../../../runtime/state";
|
|||
import type { ChatState, ChatStateStore } from "../chat-state";
|
||||
import type { CodexChatHost } from "../chat-host";
|
||||
import type { ChatMessageScrollIntentController } from "../controllers/view/message-scroll-intent-controller";
|
||||
import type { DisplayDetailSection } from "../display/types";
|
||||
import type { ChatViewEffects } from "./effects";
|
||||
import type { ChatConnectionWorkTracker, ChatResumeWorkTracker, ChatViewDeferredTasks } from "./lifecycle";
|
||||
import type { DisplayDetailSection, DisplayItem } from "../display/types";
|
||||
import type {
|
||||
ChatConnectionWorkTracker,
|
||||
ChatResumeWorkTracker,
|
||||
ChatViewDeferredTasks,
|
||||
ChatViewRenderScheduleOptions,
|
||||
RestoredThreadState,
|
||||
} from "./lifecycle";
|
||||
import type { ComposerMetaViewModel } from "./model";
|
||||
|
||||
export interface ChatPanelContext {
|
||||
|
|
@ -20,7 +25,10 @@ export interface ChatPanelContext {
|
|||
render: ChatPanelRenderContext;
|
||||
runtime: ChatPanelRuntimeContext;
|
||||
thread: ChatPanelThreadContext;
|
||||
effects: ChatViewEffects;
|
||||
liveState: ChatPanelLiveStateContext;
|
||||
scroll: ChatPanelScrollContext;
|
||||
status: ChatPanelStatusContext;
|
||||
composer: ChatPanelComposerContext;
|
||||
}
|
||||
|
||||
interface ChatPanelObsidianContext {
|
||||
|
|
@ -37,11 +45,14 @@ interface ChatPanelObsidianContext {
|
|||
interface ChatPanelStateContext {
|
||||
stateStore: ChatStateStore;
|
||||
getState: () => ChatState;
|
||||
systemItem: (text: string) => DisplayItem;
|
||||
}
|
||||
|
||||
interface ChatPanelClientContext {
|
||||
getClient: () => AppServerClient | null;
|
||||
setClient: (client: AppServerClient | null) => void;
|
||||
clear: () => void;
|
||||
ensureConnected: () => Promise<void>;
|
||||
}
|
||||
|
||||
interface ChatPanelLifecycleContext {
|
||||
|
|
@ -53,6 +64,13 @@ interface ChatPanelLifecycleContext {
|
|||
setOpened: (opened: boolean) => void;
|
||||
getClosing: () => boolean;
|
||||
setClosing: (closing: boolean) => void;
|
||||
invalidateConnectionWork: () => void;
|
||||
invalidateResumeWork: () => void;
|
||||
scheduleDeferredDiagnostics: () => void;
|
||||
clearDeferredDiagnostics: () => void;
|
||||
scheduleDeferredRestoredThreadHydration: () => void;
|
||||
clearDeferredRestoredThreadHydration: () => void;
|
||||
scheduleDeferredAppServerWarmup: () => void;
|
||||
}
|
||||
|
||||
interface ChatPanelRenderContext {
|
||||
|
|
@ -66,6 +84,9 @@ interface ChatPanelRenderContext {
|
|||
composerPlaceholder: () => string;
|
||||
composerMetaViewModel: () => ComposerMetaViewModel;
|
||||
closeToolbarPanelOnOutsidePointer: (event: PointerEvent) => void;
|
||||
now: () => void;
|
||||
shellSlots: () => void;
|
||||
schedule: (options?: ChatViewRenderScheduleOptions) => void;
|
||||
}
|
||||
|
||||
interface ChatPanelRuntimeContext {
|
||||
|
|
@ -87,4 +108,31 @@ interface ChatPanelThreadContext {
|
|||
refreshSkills: (forceReload?: boolean) => Promise<void>;
|
||||
publishAppServerMetadataSnapshot: () => void;
|
||||
loadSharedThreadList: () => Promise<void>;
|
||||
notifyIdentityChanged: () => void;
|
||||
resetTurnPresence: (hadTurns: boolean) => void;
|
||||
restorePlaceholder: (restoredThread: RestoredThreadState) => void;
|
||||
clearRestoredLifecycle: () => void;
|
||||
refreshTabHeader: () => void;
|
||||
}
|
||||
|
||||
interface ChatPanelLiveStateContext {
|
||||
refresh: () => void;
|
||||
deferRefresh: () => void;
|
||||
}
|
||||
|
||||
interface ChatPanelScrollContext {
|
||||
forceBottom: () => void;
|
||||
correctAfterLayoutChange: () => void;
|
||||
preservePosition: () => void;
|
||||
bottomOnFocus: () => void;
|
||||
}
|
||||
|
||||
interface ChatPanelStatusContext {
|
||||
set: (status: string) => void;
|
||||
addSystemMessage: (text: string) => void;
|
||||
addStructuredSystemMessage: (text: string, details: DisplayDetailSection[]) => void;
|
||||
}
|
||||
|
||||
interface ChatPanelComposerContext {
|
||||
setText: (text: string) => void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,17 +132,17 @@ export function createChatViewControllers(ports: ChatPanelContext): ChatViewCont
|
|||
connection.setHandlers({
|
||||
onNotification: (notification) => {
|
||||
controller.handleNotification(notification);
|
||||
context.effects.liveState.refresh();
|
||||
context.effects.render.schedule();
|
||||
context.liveState.refresh();
|
||||
context.render.schedule();
|
||||
},
|
||||
onServerRequest: (request) => {
|
||||
controller.handleServerRequest(request);
|
||||
context.effects.liveState.refresh();
|
||||
context.effects.render.now();
|
||||
context.liveState.refresh();
|
||||
context.render.now();
|
||||
},
|
||||
onLog: (message) => {
|
||||
controller.handleAppServerLog(message);
|
||||
context.effects.render.now();
|
||||
context.render.now();
|
||||
},
|
||||
onExit: () => {
|
||||
connectionController.handleExit();
|
||||
|
|
@ -215,7 +215,7 @@ export function createChatViewControllers(ports: ChatPanelContext): ChatViewCont
|
|||
}
|
||||
|
||||
function createControllerContext(ports: ChatPanelContext) {
|
||||
const { obsidian, plugin, state, client, lifecycle, render, runtime, thread, effects } = ports;
|
||||
const { obsidian, plugin, state, client, lifecycle, render, runtime, thread, liveState, scroll, status, composer } = ports;
|
||||
const { app, owner, viewId } = obsidian;
|
||||
const { stateStore } = state;
|
||||
|
||||
|
|
@ -229,7 +229,10 @@ function createControllerContext(ports: ChatPanelContext) {
|
|||
render,
|
||||
runtime,
|
||||
thread,
|
||||
effects,
|
||||
liveState,
|
||||
scroll,
|
||||
status,
|
||||
composer,
|
||||
app,
|
||||
owner,
|
||||
viewId,
|
||||
|
|
@ -284,8 +287,24 @@ function createSubmissionControllerGroup(
|
|||
history: ThreadHistoryController;
|
||||
},
|
||||
) {
|
||||
const { app, owner, plugin, state, stateStore, viewId, render, runtime, thread, effects, lifecycle, currentClient, submissionState } =
|
||||
context;
|
||||
const {
|
||||
app,
|
||||
owner,
|
||||
plugin,
|
||||
state,
|
||||
stateStore,
|
||||
viewId,
|
||||
render,
|
||||
runtime,
|
||||
thread,
|
||||
liveState,
|
||||
scroll,
|
||||
status,
|
||||
lifecycle,
|
||||
currentClient,
|
||||
submissionState,
|
||||
client,
|
||||
} = context;
|
||||
const { messageScrollIntent } = lifecycle;
|
||||
|
||||
const composerController = new ChatComposerController({
|
||||
|
|
@ -302,18 +321,18 @@ function createSubmissionControllerGroup(
|
|||
togglePlan: () => void refs.runtimeSettings.toggleCollaborationMode(),
|
||||
toggleAutoReview: () => void refs.runtimeSettings.toggleAutoReview(),
|
||||
toggleFast: () => void refs.runtimeSettings.toggleFastMode(),
|
||||
renderIfDetached: effects.render.now,
|
||||
onDraftChange: effects.liveState.refresh,
|
||||
renderIfDetached: render.now,
|
||||
onDraftChange: liveState.refresh,
|
||||
onComposerResize: () => {
|
||||
effects.scroll.correctAfterLayoutChange();
|
||||
scroll.correctAfterLayoutChange();
|
||||
},
|
||||
});
|
||||
const pendingRequests = new PendingRequestController({
|
||||
state: createPendingRequestStatePort(stateStore),
|
||||
controller: refs.controller,
|
||||
composerHasFocus: () => composerController.hasFocus(),
|
||||
refreshLiveState: effects.liveState.refresh,
|
||||
render: effects.render.now,
|
||||
refreshLiveState: liveState.refresh,
|
||||
render: render.now,
|
||||
});
|
||||
|
||||
const turnSubmission = new TurnSubmissionController({
|
||||
|
|
@ -327,8 +346,8 @@ function createSubmissionControllerGroup(
|
|||
},
|
||||
thread: {
|
||||
startThread: (preview) => refs.appServerThreads.startThread(preview),
|
||||
notifyActiveThreadIdentityChanged: effects.thread.notifyIdentityChanged,
|
||||
resetThreadTurnPresence: effects.thread.resetTurnPresence,
|
||||
notifyActiveThreadIdentityChanged: thread.notifyIdentityChanged,
|
||||
resetThreadTurnPresence: thread.resetTurnPresence,
|
||||
},
|
||||
runtime: {
|
||||
applyPendingThreadSettings: () => refs.runtimeSettings.applyPendingThreadSettings(),
|
||||
|
|
@ -340,13 +359,13 @@ function createSubmissionControllerGroup(
|
|||
},
|
||||
},
|
||||
view: {
|
||||
forceMessagesToBottom: effects.scroll.forceBottom,
|
||||
render: effects.render.now,
|
||||
scheduleRender: effects.render.schedule,
|
||||
forceMessagesToBottom: scroll.forceBottom,
|
||||
render: render.now,
|
||||
scheduleRender: render.schedule,
|
||||
},
|
||||
status: {
|
||||
setStatus: effects.status.set,
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
setStatus: status.set,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
},
|
||||
});
|
||||
const slashCommands = new SlashCommandController({
|
||||
|
|
@ -381,9 +400,9 @@ function createSubmissionControllerGroup(
|
|||
clear: (threadId) => refs.goals.clear(threadId),
|
||||
},
|
||||
status: {
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
addStructuredSystemMessage: effects.status.addStructuredSystemMessage,
|
||||
setStatus: effects.status.set,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
addStructuredSystemMessage: status.addStructuredSystemMessage,
|
||||
setStatus: status.set,
|
||||
statusSummaryLines: runtime.statusSummaryLines,
|
||||
connectionDiagnosticDetails: runtime.connectionDiagnosticDetails,
|
||||
mcpStatusLines: runtime.mcpStatusLines,
|
||||
|
|
@ -395,7 +414,7 @@ function createSubmissionControllerGroup(
|
|||
state: submissionState,
|
||||
connection: {
|
||||
currentClient,
|
||||
ensureConnected: effects.client.ensureConnected,
|
||||
ensureConnected: client.ensureConnected,
|
||||
},
|
||||
submission: {
|
||||
sendTurnText: (text) => turnSubmission.sendTurnText(text),
|
||||
|
|
@ -437,11 +456,11 @@ function createSubmissionControllerGroup(
|
|||
turnSubmission,
|
||||
connection: {
|
||||
currentClient,
|
||||
ensureConnected: effects.client.ensureConnected,
|
||||
ensureConnected: client.ensureConnected,
|
||||
},
|
||||
status: {
|
||||
setStatus: effects.status.set,
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
setStatus: status.set,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
},
|
||||
});
|
||||
composerController.setActionHandlers({
|
||||
|
|
@ -469,7 +488,7 @@ function createConnectionLifecycleControllerGroup(
|
|||
appServerMetadata: ChatAppServerMetadataController;
|
||||
},
|
||||
) {
|
||||
const { ports, obsidian, lifecycle, render, effects } = context;
|
||||
const { ports, obsidian, lifecycle, render, liveState, scroll, client } = context;
|
||||
const { deferredTasks } = lifecycle;
|
||||
|
||||
return {
|
||||
|
|
@ -478,7 +497,7 @@ function createConnectionLifecycleControllerGroup(
|
|||
opened: lifecycle.getOpened,
|
||||
closing: lifecycle.getClosing,
|
||||
connected: () => refs.connection.isConnected(),
|
||||
ensureConnected: effects.client.ensureConnected,
|
||||
ensureConnected: client.ensureConnected,
|
||||
}),
|
||||
openCloseController: new ChatViewOpenCloseController({
|
||||
setOpened: lifecycle.setOpened,
|
||||
|
|
@ -490,16 +509,16 @@ function createConnectionLifecycleControllerGroup(
|
|||
registerPointerDown: obsidian.registerPointerDown,
|
||||
registerActiveLeafChange: obsidian.registerActiveLeafChange,
|
||||
isOwnLeaf: obsidian.isOwnLeaf,
|
||||
scrollMessagesToBottomOnFocus: effects.scroll.bottomOnFocus,
|
||||
scrollMessagesToBottomOnFocus: scroll.bottomOnFocus,
|
||||
applyCachedSharedAppServerState: () => {
|
||||
applyCachedSharedAppServerState(ports, refs.appServerThreads, refs.appServerMetadata);
|
||||
},
|
||||
render: effects.render.now,
|
||||
scheduleDeferredAppServerWarmup: effects.lifecycle.scheduleDeferredAppServerWarmup,
|
||||
scheduleDeferredRestoredThreadHydration: effects.lifecycle.scheduleDeferredRestoredThreadHydration,
|
||||
render: render.now,
|
||||
scheduleDeferredAppServerWarmup: lifecycle.scheduleDeferredAppServerWarmup,
|
||||
scheduleDeferredRestoredThreadHydration: lifecycle.scheduleDeferredRestoredThreadHydration,
|
||||
closeToolbarPanelOnOutsidePointer: render.closeToolbarPanelOnOutsidePointer,
|
||||
invalidateConnectionWork: effects.lifecycle.invalidateConnectionWork,
|
||||
invalidateResumeWork: effects.lifecycle.invalidateResumeWork,
|
||||
invalidateConnectionWork: lifecycle.invalidateConnectionWork,
|
||||
invalidateResumeWork: lifecycle.invalidateResumeWork,
|
||||
clearDeferredTasks: () => {
|
||||
deferredTasks.clearAll();
|
||||
},
|
||||
|
|
@ -513,9 +532,9 @@ function createConnectionLifecycleControllerGroup(
|
|||
disconnect: () => {
|
||||
refs.connection.disconnect();
|
||||
},
|
||||
clearClient: effects.client.clear,
|
||||
refreshLiveState: effects.liveState.refresh,
|
||||
deferRefreshLiveState: effects.liveState.deferRefresh,
|
||||
clearClient: client.clear,
|
||||
refreshLiveState: liveState.refresh,
|
||||
deferRefreshLiveState: liveState.deferRefresh,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
|
@ -527,7 +546,7 @@ function createAppServerControllerGroup(
|
|||
goals: ChatThreadGoalController;
|
||||
},
|
||||
) {
|
||||
const { plugin, runtime, effects, stateStore } = context;
|
||||
const { plugin, runtime, scroll, stateStore } = context;
|
||||
const appServerBaseHost = {
|
||||
stateStore,
|
||||
vaultPath: plugin.vaultPath,
|
||||
|
|
@ -549,7 +568,7 @@ function createAppServerControllerGroup(
|
|||
const appServerThreads = new ChatAppServerThreadController({
|
||||
...appServerBaseHost,
|
||||
runtimeSnapshot: runtime.runtimeSnapshot,
|
||||
forceMessagesToBottom: effects.scroll.forceBottom,
|
||||
forceMessagesToBottom: scroll.forceBottom,
|
||||
publishThreadList: (threads) => {
|
||||
plugin.applyThreadListSnapshot(threads);
|
||||
},
|
||||
|
|
@ -570,7 +589,7 @@ function createInboundController(
|
|||
serverRequestResponder: ServerRequestResponder;
|
||||
},
|
||||
) {
|
||||
const { plugin, thread, effects, stateStore } = context;
|
||||
const { plugin, thread, render, stateStore } = context;
|
||||
|
||||
return new ChatInboundController(stateStore, {
|
||||
refreshThreads: () => {
|
||||
|
|
@ -588,7 +607,7 @@ function createInboundController(
|
|||
notifyThreadRenamed: plugin.notifyThreadRenamed.bind(plugin),
|
||||
recordMcpStartupStatus: (name, status, message) => {
|
||||
refs.appServerDiagnostics.recordMcpStartupStatus(name, status, message);
|
||||
effects.render.schedule();
|
||||
render.schedule();
|
||||
},
|
||||
respondToServerRequest: (requestId, result) => refs.serverRequestResponder.respond(requestId, result),
|
||||
rejectServerRequest: (requestId, code, message) => refs.serverRequestResponder.reject(requestId, code, message),
|
||||
|
|
@ -603,7 +622,7 @@ function createConnectionControllerGroup(
|
|||
appServerDiagnostics: ChatAppServerDiagnosticsController;
|
||||
},
|
||||
) {
|
||||
const { plugin, client, thread, effects, lifecycle, connectionState } = context;
|
||||
const { plugin, client, thread, status, liveState, render, lifecycle, connectionState } = context;
|
||||
const { connectionWork } = lifecycle;
|
||||
|
||||
return {
|
||||
|
|
@ -619,18 +638,18 @@ function createConnectionControllerGroup(
|
|||
refreshPublishedCapabilityDiagnostics: () => refs.appServerDiagnostics.refreshPublishedCapabilityDiagnostics(),
|
||||
},
|
||||
setClient: client.setClient,
|
||||
invalidateResumeWork: effects.lifecycle.invalidateResumeWork,
|
||||
invalidateResumeWork: lifecycle.invalidateResumeWork,
|
||||
loadSharedThreadList: thread.loadSharedThreadList,
|
||||
scheduleDeferredDiagnostics: effects.lifecycle.scheduleDeferredDiagnostics,
|
||||
clearDeferredDiagnostics: effects.lifecycle.clearDeferredDiagnostics,
|
||||
refreshTabHeader: effects.thread.refreshTabHeader,
|
||||
resetThreadTurnPresence: effects.thread.resetTurnPresence,
|
||||
setStatus: effects.status.set,
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
scheduleDeferredDiagnostics: lifecycle.scheduleDeferredDiagnostics,
|
||||
clearDeferredDiagnostics: lifecycle.clearDeferredDiagnostics,
|
||||
refreshTabHeader: thread.refreshTabHeader,
|
||||
resetThreadTurnPresence: thread.resetTurnPresence,
|
||||
setStatus: status.set,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
configuredCommand: () => plugin.settings.codexPath,
|
||||
refreshLiveState: effects.liveState.refresh,
|
||||
render: effects.render.now,
|
||||
scheduleRender: effects.render.schedule,
|
||||
refreshLiveState: liveState.refresh,
|
||||
render: render.now,
|
||||
scheduleRender: render.schedule,
|
||||
notifyConnectionFailed: () => {
|
||||
new Notice("Codex app-server connection failed.");
|
||||
},
|
||||
|
|
@ -644,37 +663,54 @@ function createThreadToolbarControllerGroup(
|
|||
connection: ConnectionManager;
|
||||
},
|
||||
) {
|
||||
const { obsidian, plugin, runtime, thread, effects, lifecycle, stateStore, currentClient, connectionState, panelState, threadState } =
|
||||
context;
|
||||
const {
|
||||
obsidian,
|
||||
plugin,
|
||||
state,
|
||||
runtime,
|
||||
thread,
|
||||
status,
|
||||
liveState,
|
||||
scroll,
|
||||
render,
|
||||
client,
|
||||
composer,
|
||||
lifecycle,
|
||||
stateStore,
|
||||
currentClient,
|
||||
connectionState,
|
||||
panelState,
|
||||
threadState,
|
||||
} = context;
|
||||
const { deferredTasks, resumeWork } = lifecycle;
|
||||
|
||||
const history = new ThreadHistoryController({
|
||||
stateStore,
|
||||
currentClient,
|
||||
render: effects.render.now,
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
forceMessagesToBottom: effects.scroll.forceBottom,
|
||||
keepCurrentScrollPosition: effects.scroll.preservePosition,
|
||||
setThreadTurnPresence: effects.thread.resetTurnPresence,
|
||||
render: render.now,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
forceMessagesToBottom: scroll.forceBottom,
|
||||
keepCurrentScrollPosition: scroll.preservePosition,
|
||||
setThreadTurnPresence: thread.resetTurnPresence,
|
||||
});
|
||||
const threadActions = new ChatThreadActionController({
|
||||
stateStore,
|
||||
vaultPath: plugin.vaultPath,
|
||||
settings: () => plugin.settings,
|
||||
archiveAdapter: obsidian.archiveAdapter,
|
||||
ensureConnected: effects.client.ensureConnected,
|
||||
ensureConnected: client.ensureConnected,
|
||||
currentClient,
|
||||
history,
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
setStatus: effects.status.set,
|
||||
setComposerText: effects.composer.setText,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
setStatus: status.set,
|
||||
setComposerText: composer.setText,
|
||||
openThreadInNewView: (threadId) => plugin.openThreadInNewView(threadId),
|
||||
openThreadInCurrentPanel: thread.selectThread,
|
||||
notifyThreadArchived: plugin.notifyThreadArchived.bind(plugin),
|
||||
notifyThreadRenamed: (threadId, name) => {
|
||||
plugin.notifyThreadRenamed(threadId, name);
|
||||
},
|
||||
notifyActiveThreadIdentityChanged: effects.thread.notifyIdentityChanged,
|
||||
notifyActiveThreadIdentityChanged: thread.notifyIdentityChanged,
|
||||
refreshThreads: thread.refreshThreads,
|
||||
refreshSharedThreadListFromOpenSurface: () => {
|
||||
plugin.refreshSharedThreadListFromOpenSurface();
|
||||
|
|
@ -683,7 +719,7 @@ function createThreadToolbarControllerGroup(
|
|||
const toolbarPanels = new ToolbarPanelController({
|
||||
stateStore,
|
||||
threadActions,
|
||||
scheduleRender: effects.render.schedule,
|
||||
scheduleRender: render.schedule,
|
||||
});
|
||||
const threadSelection = new ThreadSelectionController({
|
||||
panelState,
|
||||
|
|
@ -693,59 +729,59 @@ function createThreadToolbarControllerGroup(
|
|||
},
|
||||
focusThreadInOpenView: (threadId) => plugin.focusThreadInOpenView(threadId),
|
||||
resumeThread: thread.resumeThread,
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
});
|
||||
const reconnectActions = new ChatReconnectController({
|
||||
connectionState,
|
||||
panelState,
|
||||
threadState,
|
||||
invalidateConnectionWork: effects.lifecycle.invalidateConnectionWork,
|
||||
invalidateResumeWork: effects.lifecycle.invalidateResumeWork,
|
||||
clearDeferredDiagnostics: effects.lifecycle.clearDeferredDiagnostics,
|
||||
invalidateConnectionWork: lifecycle.invalidateConnectionWork,
|
||||
invalidateResumeWork: lifecycle.invalidateResumeWork,
|
||||
clearDeferredDiagnostics: lifecycle.clearDeferredDiagnostics,
|
||||
reconnect: () => {
|
||||
refs.connection.reconnect();
|
||||
},
|
||||
clearClient: effects.client.clear,
|
||||
setStatus: effects.status.set,
|
||||
render: effects.render.now,
|
||||
ensureConnected: effects.client.ensureConnected,
|
||||
clearClient: client.clear,
|
||||
setStatus: status.set,
|
||||
render: render.now,
|
||||
ensureConnected: client.ensureConnected,
|
||||
resumeThread: thread.resumeThread,
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
});
|
||||
const runtimeSettings = new ChatRuntimeSettingsController({
|
||||
stateStore,
|
||||
currentClient,
|
||||
runtimeSnapshot: runtime.runtimeSnapshot,
|
||||
collaborationModeLabel: runtime.collaborationModeLabel,
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
});
|
||||
const goals = new ChatThreadGoalController({
|
||||
stateStore,
|
||||
currentClient,
|
||||
ensureConnected: effects.client.ensureConnected,
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
ensureConnected: client.ensureConnected,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
addGoalEvent: (item) => {
|
||||
stateStore.dispatch({ type: "transcript/item-upserted", item });
|
||||
},
|
||||
render: effects.render.now,
|
||||
refreshLiveState: effects.liveState.refresh,
|
||||
render: render.now,
|
||||
refreshLiveState: liveState.refresh,
|
||||
});
|
||||
const restoredThread = new RestoredThreadController({
|
||||
deferredTasks,
|
||||
opened: lifecycle.getOpened,
|
||||
resumeThread: thread.resumeThread,
|
||||
invalidateResumeWork: effects.lifecycle.invalidateResumeWork,
|
||||
invalidateResumeWork: lifecycle.invalidateResumeWork,
|
||||
state: threadState,
|
||||
systemItem: effects.state.systemItem,
|
||||
setStatus: effects.status.set,
|
||||
refreshTabHeader: effects.thread.refreshTabHeader,
|
||||
systemItem: state.systemItem,
|
||||
setStatus: status.set,
|
||||
refreshTabHeader: thread.refreshTabHeader,
|
||||
});
|
||||
const viewStateController = new ChatViewStateController({
|
||||
invalidateResumeWork: effects.lifecycle.invalidateResumeWork,
|
||||
clearRestoredThreadLifecycle: effects.thread.clearRestoredLifecycle,
|
||||
clearDeferredRestoredThreadHydration: effects.lifecycle.clearDeferredRestoredThreadHydration,
|
||||
scheduleDeferredAppServerWarmup: effects.lifecycle.scheduleDeferredAppServerWarmup,
|
||||
restoreThreadPlaceholder: effects.thread.restorePlaceholder,
|
||||
invalidateResumeWork: lifecycle.invalidateResumeWork,
|
||||
clearRestoredThreadLifecycle: thread.clearRestoredLifecycle,
|
||||
clearDeferredRestoredThreadHydration: lifecycle.clearDeferredRestoredThreadHydration,
|
||||
scheduleDeferredAppServerWarmup: lifecycle.scheduleDeferredAppServerWarmup,
|
||||
restoreThreadPlaceholder: thread.restorePlaceholder,
|
||||
});
|
||||
const threadResume = new ThreadResumeController({
|
||||
state: threadState,
|
||||
|
|
@ -754,16 +790,16 @@ function createThreadToolbarControllerGroup(
|
|||
history,
|
||||
restoredThread,
|
||||
currentClient,
|
||||
ensureConnected: effects.client.ensureConnected,
|
||||
ensureConnected: client.ensureConnected,
|
||||
closing: lifecycle.getClosing,
|
||||
systemItem: effects.state.systemItem,
|
||||
resetThreadTurnPresence: effects.thread.resetTurnPresence,
|
||||
clearDeferredRestoredThreadHydration: effects.lifecycle.clearDeferredRestoredThreadHydration,
|
||||
notifyActiveThreadIdentityChanged: effects.thread.notifyIdentityChanged,
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
forceMessagesToBottom: effects.scroll.forceBottom,
|
||||
render: effects.render.now,
|
||||
refreshLiveState: effects.liveState.refresh,
|
||||
systemItem: state.systemItem,
|
||||
resetThreadTurnPresence: thread.resetTurnPresence,
|
||||
clearDeferredRestoredThreadHydration: lifecycle.clearDeferredRestoredThreadHydration,
|
||||
notifyActiveThreadIdentityChanged: thread.notifyIdentityChanged,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
forceMessagesToBottom: scroll.forceBottom,
|
||||
render: render.now,
|
||||
refreshLiveState: liveState.refresh,
|
||||
syncThreadGoal: (threadId) => goals.syncThreadGoal(threadId),
|
||||
recoverTokenUsageFromRollout: (path) =>
|
||||
recoverRolloutTokenUsage(path, async (filePath, options) => {
|
||||
|
|
@ -774,23 +810,23 @@ function createThreadToolbarControllerGroup(
|
|||
const threadIdentity = new ThreadIdentityController({
|
||||
state: threadState,
|
||||
restoredThread,
|
||||
invalidateResumeWork: effects.lifecycle.invalidateResumeWork,
|
||||
clearDeferredRestoredThreadHydration: effects.lifecycle.clearDeferredRestoredThreadHydration,
|
||||
resetThreadTurnPresence: effects.thread.resetTurnPresence,
|
||||
notifyActiveThreadIdentityChanged: effects.thread.notifyIdentityChanged,
|
||||
refreshTabHeader: effects.thread.refreshTabHeader,
|
||||
refreshLiveState: effects.liveState.refresh,
|
||||
render: effects.render.now,
|
||||
invalidateResumeWork: lifecycle.invalidateResumeWork,
|
||||
clearDeferredRestoredThreadHydration: lifecycle.clearDeferredRestoredThreadHydration,
|
||||
resetThreadTurnPresence: thread.resetTurnPresence,
|
||||
notifyActiveThreadIdentityChanged: thread.notifyIdentityChanged,
|
||||
refreshTabHeader: thread.refreshTabHeader,
|
||||
refreshLiveState: liveState.refresh,
|
||||
render: render.now,
|
||||
});
|
||||
const threadRename = new ThreadRenameController({
|
||||
stateStore,
|
||||
vaultPath: plugin.vaultPath,
|
||||
settings: () => plugin.settings,
|
||||
ensureConnected: effects.client.ensureConnected,
|
||||
ensureConnected: client.ensureConnected,
|
||||
currentClient: () => refs.connection.currentClient(),
|
||||
refreshThreads: thread.refreshThreads,
|
||||
render: effects.render.shellSlots,
|
||||
addSystemMessage: effects.status.addSystemMessage,
|
||||
render: render.shellSlots,
|
||||
addSystemMessage: status.addSystemMessage,
|
||||
notifyThreadRenamed: plugin.notifyThreadRenamed.bind(plugin),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,139 +0,0 @@
|
|||
import type { ChatMessageScrollIntentController } from "../controllers/view/message-scroll-intent-controller";
|
||||
import type { ChatAction } from "../chat-state";
|
||||
import type { CodexChatHost } from "../chat-host";
|
||||
import type { DisplayDetailSection, DisplayItem } from "../display/types";
|
||||
import { createSystemItem } from "../display/system";
|
||||
import type { ChatViewEffects } from "./effects";
|
||||
import type { ChatViewRenderScheduleOptions, RestoredThreadState } from "./lifecycle";
|
||||
|
||||
export interface ChatViewEffectHandlersOptions {
|
||||
plugin: CodexChatHost;
|
||||
viewWindow: () => Window;
|
||||
renderCommands: {
|
||||
render: (options?: ChatViewRenderScheduleOptions) => void;
|
||||
renderShellSlots: () => void;
|
||||
forceMessagesToBottom: () => void;
|
||||
correctMessagesAfterLayoutChange: () => void;
|
||||
};
|
||||
statusCommands: {
|
||||
addSystemMessage: (text: string) => void;
|
||||
addStructuredSystemMessage: (text: string, details: DisplayDetailSection[]) => void;
|
||||
};
|
||||
threadCommands: {
|
||||
resetThreadTurnPresence: (hadTurns: boolean) => void;
|
||||
restorePlaceholder: (restoredThread: RestoredThreadState) => void;
|
||||
clearRestoredLifecycle: () => void;
|
||||
};
|
||||
connectionCommands: {
|
||||
invalidate: () => void;
|
||||
ensureConnected: () => Promise<void>;
|
||||
};
|
||||
composerCommands: {
|
||||
setText: (text: string) => void;
|
||||
};
|
||||
messageScrollIntent: ChatMessageScrollIntentController;
|
||||
scheduleRender: (options?: ChatViewRenderScheduleOptions) => void;
|
||||
notifyActiveThreadIdentityChanged: () => void;
|
||||
refreshTabHeader: () => void;
|
||||
invalidateResumeWork: () => void;
|
||||
scheduleDeferredDiagnostics: () => void;
|
||||
clearDeferredDiagnostics: () => void;
|
||||
scheduleDeferredRestoredThreadHydration: () => void;
|
||||
clearDeferredRestoredThreadHydration: () => void;
|
||||
scheduleDeferredAppServerWarmup: () => void;
|
||||
dispatch: (action: ChatAction) => void;
|
||||
clearClient: () => void;
|
||||
}
|
||||
|
||||
export function createChatViewEffectHandlers(options: ChatViewEffectHandlersOptions): ChatViewEffects {
|
||||
return {
|
||||
render: {
|
||||
now: () => {
|
||||
options.renderCommands.render();
|
||||
},
|
||||
shellSlots: () => {
|
||||
options.renderCommands.renderShellSlots();
|
||||
},
|
||||
schedule: (renderOptions) => {
|
||||
options.scheduleRender(renderOptions);
|
||||
},
|
||||
},
|
||||
liveState: {
|
||||
refresh: () => {
|
||||
options.plugin.refreshThreadsViewLiveState();
|
||||
},
|
||||
deferRefresh: () => {
|
||||
options.viewWindow().setTimeout(() => {
|
||||
options.plugin.refreshThreadsViewLiveState();
|
||||
}, 0);
|
||||
},
|
||||
},
|
||||
scroll: {
|
||||
forceBottom: () => {
|
||||
options.messageScrollIntent.forceBottom();
|
||||
options.renderCommands.forceMessagesToBottom();
|
||||
},
|
||||
correctAfterLayoutChange: () => {
|
||||
options.renderCommands.correctMessagesAfterLayoutChange();
|
||||
},
|
||||
preservePosition: () => {
|
||||
options.messageScrollIntent.preservePosition();
|
||||
},
|
||||
bottomOnFocus: () => {
|
||||
options.messageScrollIntent.scrollToBottomOnFocus();
|
||||
},
|
||||
},
|
||||
status: {
|
||||
set: (status) => {
|
||||
options.dispatch({ type: "connection/status-set", status });
|
||||
},
|
||||
addSystemMessage: (text) => {
|
||||
options.statusCommands.addSystemMessage(text);
|
||||
},
|
||||
addStructuredSystemMessage: (text, details) => {
|
||||
options.statusCommands.addStructuredSystemMessage(text, details);
|
||||
},
|
||||
},
|
||||
thread: {
|
||||
notifyIdentityChanged: options.notifyActiveThreadIdentityChanged,
|
||||
resetTurnPresence: (hadTurns) => {
|
||||
options.threadCommands.resetThreadTurnPresence(hadTurns);
|
||||
},
|
||||
restorePlaceholder: (restoredThread) => {
|
||||
options.threadCommands.restorePlaceholder(restoredThread);
|
||||
},
|
||||
clearRestoredLifecycle: () => {
|
||||
options.threadCommands.clearRestoredLifecycle();
|
||||
},
|
||||
refreshTabHeader: options.refreshTabHeader,
|
||||
},
|
||||
lifecycle: {
|
||||
invalidateConnectionWork: () => {
|
||||
options.connectionCommands.invalidate();
|
||||
},
|
||||
invalidateResumeWork: options.invalidateResumeWork,
|
||||
scheduleDeferredDiagnostics: options.scheduleDeferredDiagnostics,
|
||||
clearDeferredDiagnostics: options.clearDeferredDiagnostics,
|
||||
scheduleDeferredRestoredThreadHydration: options.scheduleDeferredRestoredThreadHydration,
|
||||
clearDeferredRestoredThreadHydration: options.clearDeferredRestoredThreadHydration,
|
||||
scheduleDeferredAppServerWarmup: options.scheduleDeferredAppServerWarmup,
|
||||
},
|
||||
state: {
|
||||
dispatch: options.dispatch,
|
||||
systemItem,
|
||||
},
|
||||
client: {
|
||||
clear: options.clearClient,
|
||||
ensureConnected: options.connectionCommands.ensureConnected,
|
||||
},
|
||||
composer: {
|
||||
setText: (text) => {
|
||||
options.composerCommands.setText(text);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function systemItem(text: string): DisplayItem {
|
||||
return createSystemItem(`system-${String(Date.now())}-${Math.random().toString(36).slice(2)}`, text);
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
import type { ChatAction } from "../chat-state";
|
||||
import type { DisplayDetailSection, DisplayItem } from "../display/types";
|
||||
import type { ChatViewRenderScheduleOptions, RestoredThreadState } from "./lifecycle";
|
||||
|
||||
export interface ChatViewEffects {
|
||||
render: {
|
||||
now: () => void;
|
||||
shellSlots: () => void;
|
||||
schedule: (options?: ChatViewRenderScheduleOptions) => void;
|
||||
};
|
||||
liveState: {
|
||||
refresh: () => void;
|
||||
deferRefresh: () => void;
|
||||
};
|
||||
scroll: {
|
||||
forceBottom: () => void;
|
||||
correctAfterLayoutChange: () => void;
|
||||
preservePosition: () => void;
|
||||
bottomOnFocus: () => void;
|
||||
};
|
||||
status: {
|
||||
set: (status: string) => void;
|
||||
addSystemMessage: (text: string) => void;
|
||||
addStructuredSystemMessage: (text: string, details: DisplayDetailSection[]) => void;
|
||||
};
|
||||
thread: {
|
||||
notifyIdentityChanged: () => void;
|
||||
resetTurnPresence: (hadTurns: boolean) => void;
|
||||
restorePlaceholder: (restoredThread: RestoredThreadState) => void;
|
||||
clearRestoredLifecycle: () => void;
|
||||
refreshTabHeader: () => void;
|
||||
};
|
||||
lifecycle: {
|
||||
invalidateConnectionWork: () => void;
|
||||
invalidateResumeWork: () => void;
|
||||
scheduleDeferredDiagnostics: () => void;
|
||||
clearDeferredDiagnostics: () => void;
|
||||
scheduleDeferredRestoredThreadHydration: () => void;
|
||||
clearDeferredRestoredThreadHydration: () => void;
|
||||
scheduleDeferredAppServerWarmup: () => void;
|
||||
};
|
||||
state: {
|
||||
dispatch: (action: ChatAction) => void;
|
||||
systemItem: (text: string) => DisplayItem;
|
||||
};
|
||||
client: {
|
||||
clear: () => void;
|
||||
ensureConnected: () => Promise<void>;
|
||||
};
|
||||
composer: {
|
||||
setText: (text: string) => void;
|
||||
};
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ import type { RuntimeSnapshot } from "../../../../runtime/state";
|
|||
import type { CodexChatHost } from "../../chat-host";
|
||||
import type { ChatAction, ChatState } from "../../chat-state";
|
||||
import type { ToolbarThreadRow } from "../../toolbar-model";
|
||||
import type { ChatViewEffects } from "../effects";
|
||||
import type { ChatViewRenderScheduleOptions } from "../lifecycle";
|
||||
import type { RestoredThreadTitleSnapshot } from "../model";
|
||||
import type { ChatViewSlotRendererPorts } from "./types";
|
||||
|
|
@ -64,7 +63,9 @@ export interface ChatViewSlotRendererPortsOptions {
|
|||
goalCommands: ChatSlotGoalCommands;
|
||||
appServerCommands: ChatSlotAppServerCommands;
|
||||
renderCommands: ChatSlotRenderCommands;
|
||||
effects: ChatViewEffects;
|
||||
status: {
|
||||
addSystemMessage: (text: string) => void;
|
||||
};
|
||||
dispatch: (action: ChatAction) => void;
|
||||
startNewThread: () => Promise<void>;
|
||||
setRequestedModelFromUi: (model: string | null) => Promise<void>;
|
||||
|
|
@ -156,7 +157,7 @@ export function createChatViewSlotRendererPorts(options: ChatViewSlotRendererPor
|
|||
async function compactConversation(options: ChatViewSlotRendererPortsOptions): Promise<void> {
|
||||
const threadId = options.state().activeThread.id;
|
||||
if (!threadId) {
|
||||
options.effects.status.addSystemMessage("No active thread to compact.");
|
||||
options.status.addSystemMessage("No active thread to compact.");
|
||||
return;
|
||||
}
|
||||
await options.threadCommands.compactThread(threadId);
|
||||
|
|
@ -180,7 +181,7 @@ async function saveGoalObjective(options: ChatViewSlotRendererPortsOptions, obje
|
|||
const response = await options.appServerCommands.startThread(objective, { syncGoal: false });
|
||||
threadId = response?.thread.id ?? null;
|
||||
} catch (error) {
|
||||
options.effects.status.addSystemMessage(error instanceof Error ? error.message : String(error));
|
||||
options.status.addSystemMessage(error instanceof Error ? error.message : String(error));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { ItemView, type ViewStateResult, type WorkspaceLeaf } from "obsidian";
|
|||
|
||||
import type { AppServerClient } from "../../app-server/client";
|
||||
import { VIEW_TYPE_CODEX_PANEL } from "../../constants";
|
||||
import type { DisplayDetailSection } from "./display/types";
|
||||
import type { DisplayDetailSection, DisplayItem } from "./display/types";
|
||||
import type { ReasoningEffort } from "../../generated/app-server/ReasoningEffort";
|
||||
import type { Model } from "../../generated/app-server/v2/Model";
|
||||
import type { Thread } from "../../generated/app-server/v2/Thread";
|
||||
|
|
@ -12,6 +12,7 @@ import { chatTurnBusy, createChatStateStore, type ChatState, type ChatAction } f
|
|||
import type { OpenCodexPanelSnapshot } from "../../runtime/open-panel-snapshot";
|
||||
import type { SharedAppServerMetadata } from "../../runtime/shared-app-server-state";
|
||||
import type { CodexChatHost } from "./chat-host";
|
||||
import { createSystemItem } from "./display/system";
|
||||
import {
|
||||
activeThreadTitle as buildActiveThreadTitle,
|
||||
chatViewDisplayTitle,
|
||||
|
|
@ -29,11 +30,9 @@ import {
|
|||
type ChatViewRenderScheduleOptions,
|
||||
} from "./panel/lifecycle";
|
||||
import { ChatMessageScrollIntentController } from "./controllers/view/message-scroll-intent-controller";
|
||||
import type { ChatViewEffects } from "./panel/effects";
|
||||
import type { ChatPanelContext } from "./panel/context";
|
||||
import { createChatViewControllers, type ChatViewControllers } from "./panel/controllers";
|
||||
import { createPanelUiStatePort } from "./controllers/state-ports";
|
||||
import { createChatViewEffectHandlers } from "./panel/effect-handlers";
|
||||
import { createChatViewSlotRendererPorts } from "./panel/slots/ports";
|
||||
import { ChatViewSlotRenderers } from "./panel/slots/renderers";
|
||||
|
||||
|
|
@ -45,7 +44,6 @@ export class CodexChatView extends ItemView {
|
|||
private readonly chatState = createChatStateStore();
|
||||
private readonly viewId = `codex-panel-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
||||
private readonly deferredTasks: ChatViewDeferredTasks;
|
||||
private readonly effects: ChatViewEffects;
|
||||
private readonly messageScrollIntent: ChatMessageScrollIntentController;
|
||||
private readonly slotRenderers: ChatViewSlotRenderers;
|
||||
private readonly connectionWork = new ChatConnectionWorkTracker();
|
||||
|
|
@ -68,7 +66,6 @@ export class CodexChatView extends ItemView {
|
|||
this.controllers.render.controller.render();
|
||||
},
|
||||
});
|
||||
this.effects = this.createEffectHandlers();
|
||||
this.controllers = createChatViewControllers(this.createControllerPorts());
|
||||
this.slotRenderers = new ChatViewSlotRenderers(this.createSlotRendererPorts());
|
||||
}
|
||||
|
|
@ -95,12 +92,17 @@ export class CodexChatView extends ItemView {
|
|||
state: {
|
||||
stateStore: this.chatState,
|
||||
getState: () => this.state,
|
||||
systemItem: (text) => this.systemItem(text),
|
||||
},
|
||||
client: {
|
||||
getClient: () => this.client,
|
||||
setClient: (client) => {
|
||||
this.client = client;
|
||||
},
|
||||
clear: () => {
|
||||
this.client = null;
|
||||
},
|
||||
ensureConnected: () => this.controllers.connection.controller.ensureConnected(),
|
||||
},
|
||||
lifecycle: {
|
||||
deferredTasks: this.deferredTasks,
|
||||
|
|
@ -115,6 +117,27 @@ export class CodexChatView extends ItemView {
|
|||
setClosing: (closing) => {
|
||||
this.closing = closing;
|
||||
},
|
||||
invalidateConnectionWork: () => {
|
||||
this.controllers.connection.controller.invalidate();
|
||||
},
|
||||
invalidateResumeWork: () => {
|
||||
this.invalidateResumeWork();
|
||||
},
|
||||
scheduleDeferredDiagnostics: () => {
|
||||
this.scheduleDeferredDiagnostics();
|
||||
},
|
||||
clearDeferredDiagnostics: () => {
|
||||
this.clearDeferredDiagnostics();
|
||||
},
|
||||
scheduleDeferredRestoredThreadHydration: () => {
|
||||
this.scheduleDeferredRestoredThreadHydration();
|
||||
},
|
||||
clearDeferredRestoredThreadHydration: () => {
|
||||
this.clearDeferredRestoredThreadHydration();
|
||||
},
|
||||
scheduleDeferredAppServerWarmup: () => {
|
||||
this.scheduleDeferredAppServerWarmup();
|
||||
},
|
||||
},
|
||||
render: {
|
||||
panelRoot: () => this.panelRoot(),
|
||||
|
|
@ -137,6 +160,15 @@ export class CodexChatView extends ItemView {
|
|||
closeToolbarPanelOnOutsidePointer: (event) => {
|
||||
this.closeToolbarPanelOnOutsidePointer(event);
|
||||
},
|
||||
now: () => {
|
||||
this.controllers.render.controller.render();
|
||||
},
|
||||
shellSlots: () => {
|
||||
this.controllers.render.controller.renderShellSlots();
|
||||
},
|
||||
schedule: (options) => {
|
||||
this.scheduleRender(options);
|
||||
},
|
||||
},
|
||||
runtime: {
|
||||
runtimeSnapshot: () => this.runtimeSnapshot(),
|
||||
|
|
@ -158,8 +190,65 @@ export class CodexChatView extends ItemView {
|
|||
this.controllers.appServer.metadata.publishAppServerMetadataSnapshot();
|
||||
},
|
||||
loadSharedThreadList: () => this.loadSharedThreadList(),
|
||||
notifyIdentityChanged: () => {
|
||||
this.notifyActiveThreadIdentityChanged();
|
||||
},
|
||||
resetTurnPresence: (hadTurns) => {
|
||||
this.controllers.thread.rename.resetThreadTurnPresence(hadTurns);
|
||||
},
|
||||
restorePlaceholder: (restoredThread) => {
|
||||
this.controllers.thread.restored.restore(restoredThread);
|
||||
},
|
||||
clearRestoredLifecycle: () => {
|
||||
this.controllers.thread.restored.clear();
|
||||
},
|
||||
refreshTabHeader: () => {
|
||||
this.refreshTabHeader();
|
||||
},
|
||||
},
|
||||
liveState: {
|
||||
refresh: () => {
|
||||
this.plugin.refreshThreadsViewLiveState();
|
||||
},
|
||||
deferRefresh: () => {
|
||||
this.containerEl.win.setTimeout(() => {
|
||||
this.plugin.refreshThreadsViewLiveState();
|
||||
}, 0);
|
||||
},
|
||||
},
|
||||
scroll: {
|
||||
forceBottom: () => {
|
||||
this.messageScrollIntent.forceBottom();
|
||||
this.controllers.render.messages.forceMessagesToBottom();
|
||||
},
|
||||
correctAfterLayoutChange: () => {
|
||||
this.controllers.render.messages.correctMessagesAfterLayoutChange();
|
||||
},
|
||||
preservePosition: () => {
|
||||
this.messageScrollIntent.preservePosition();
|
||||
},
|
||||
bottomOnFocus: () => {
|
||||
this.messageScrollIntent.scrollToBottomOnFocus();
|
||||
},
|
||||
},
|
||||
status: {
|
||||
set: (status) => {
|
||||
this.dispatch({ type: "connection/status-set", status });
|
||||
},
|
||||
addSystemMessage: (text) => {
|
||||
this.controllers.inbound.controller.addSystemMessage(text);
|
||||
this.controllers.render.controller.render();
|
||||
},
|
||||
addStructuredSystemMessage: (text, details) => {
|
||||
this.controllers.inbound.controller.addStructuredSystemMessage(text, details);
|
||||
this.controllers.render.controller.render();
|
||||
},
|
||||
},
|
||||
composer: {
|
||||
setText: (text) => {
|
||||
this.controllers.composer.controller.setDraft(text, { focus: true, renderIfDetached: true });
|
||||
},
|
||||
},
|
||||
effects: this.effects,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -230,7 +319,12 @@ export class CodexChatView extends ItemView {
|
|||
this.controllers.composer.controller.render(parent);
|
||||
},
|
||||
},
|
||||
effects: this.effects,
|
||||
status: {
|
||||
addSystemMessage: (text) => {
|
||||
this.controllers.inbound.controller.addSystemMessage(text);
|
||||
this.controllers.render.controller.render();
|
||||
},
|
||||
},
|
||||
dispatch: (action) => {
|
||||
this.dispatch(action);
|
||||
},
|
||||
|
|
@ -240,93 +334,6 @@ export class CodexChatView extends ItemView {
|
|||
});
|
||||
}
|
||||
|
||||
private createEffectHandlers(): ChatViewEffects {
|
||||
return createChatViewEffectHandlers({
|
||||
plugin: this.plugin,
|
||||
viewWindow: () => this.containerEl.win,
|
||||
renderCommands: {
|
||||
render: (options) => {
|
||||
this.controllers.render.controller.render(options);
|
||||
},
|
||||
renderShellSlots: () => {
|
||||
this.controllers.render.controller.renderShellSlots();
|
||||
},
|
||||
forceMessagesToBottom: () => {
|
||||
this.controllers.render.messages.forceMessagesToBottom();
|
||||
},
|
||||
correctMessagesAfterLayoutChange: () => {
|
||||
this.controllers.render.messages.correctMessagesAfterLayoutChange();
|
||||
},
|
||||
},
|
||||
statusCommands: {
|
||||
addSystemMessage: (text) => {
|
||||
this.controllers.inbound.controller.addSystemMessage(text);
|
||||
this.controllers.render.controller.render();
|
||||
},
|
||||
addStructuredSystemMessage: (text, details) => {
|
||||
this.controllers.inbound.controller.addStructuredSystemMessage(text, details);
|
||||
this.controllers.render.controller.render();
|
||||
},
|
||||
},
|
||||
threadCommands: {
|
||||
resetThreadTurnPresence: (hadTurns) => {
|
||||
this.controllers.thread.rename.resetThreadTurnPresence(hadTurns);
|
||||
},
|
||||
restorePlaceholder: (restoredThread) => {
|
||||
this.controllers.thread.restored.restore(restoredThread);
|
||||
},
|
||||
clearRestoredLifecycle: () => {
|
||||
this.controllers.thread.restored.clear();
|
||||
},
|
||||
},
|
||||
connectionCommands: {
|
||||
invalidate: () => {
|
||||
this.controllers.connection.controller.invalidate();
|
||||
},
|
||||
ensureConnected: () => this.controllers.connection.controller.ensureConnected(),
|
||||
},
|
||||
composerCommands: {
|
||||
setText: (text) => {
|
||||
this.controllers.composer.controller.setDraft(text, { focus: true, renderIfDetached: true });
|
||||
},
|
||||
},
|
||||
messageScrollIntent: this.messageScrollIntent,
|
||||
scheduleRender: (options) => {
|
||||
this.scheduleRender(options);
|
||||
},
|
||||
notifyActiveThreadIdentityChanged: () => {
|
||||
this.notifyActiveThreadIdentityChanged();
|
||||
},
|
||||
refreshTabHeader: () => {
|
||||
this.refreshTabHeader();
|
||||
},
|
||||
invalidateResumeWork: () => {
|
||||
this.invalidateResumeWork();
|
||||
},
|
||||
scheduleDeferredDiagnostics: () => {
|
||||
this.scheduleDeferredDiagnostics();
|
||||
},
|
||||
clearDeferredDiagnostics: () => {
|
||||
this.clearDeferredDiagnostics();
|
||||
},
|
||||
scheduleDeferredRestoredThreadHydration: () => {
|
||||
this.scheduleDeferredRestoredThreadHydration();
|
||||
},
|
||||
clearDeferredRestoredThreadHydration: () => {
|
||||
this.clearDeferredRestoredThreadHydration();
|
||||
},
|
||||
scheduleDeferredAppServerWarmup: () => {
|
||||
this.scheduleDeferredAppServerWarmup();
|
||||
},
|
||||
dispatch: (action) => {
|
||||
this.dispatch(action);
|
||||
},
|
||||
clearClient: () => {
|
||||
this.client = null;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private get state(): ChatState {
|
||||
return this.chatState.getState();
|
||||
}
|
||||
|
|
@ -339,6 +346,10 @@ export class CodexChatView extends ItemView {
|
|||
this.chatState.dispatch(action);
|
||||
}
|
||||
|
||||
private systemItem(text: string): DisplayItem {
|
||||
return createSystemItem(`system-${String(Date.now())}-${Math.random().toString(36).slice(2)}`, text);
|
||||
}
|
||||
|
||||
override getViewType(): string {
|
||||
return VIEW_TYPE_CODEX_PANEL;
|
||||
}
|
||||
|
|
@ -451,7 +462,7 @@ export class CodexChatView extends ItemView {
|
|||
|
||||
this.controllers.thread.identity.clearActiveThreadContext();
|
||||
this.chatState.dispatch({ type: "ui/panel-set", panel: null });
|
||||
this.effects.status.set("New chat.");
|
||||
this.dispatch({ type: "connection/status-set", status: "New chat." });
|
||||
this.messageScrollIntent.forceBottom();
|
||||
this.controllers.render.controller.render();
|
||||
this.focusComposer();
|
||||
|
|
|
|||
Loading…
Reference in a new issue