test: complete P4.1 LM Studio coverage and fix auto/wizard handoff

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 21:45:18 +08:00
parent 6a949b54ba
commit 5d3e264cf3
11 changed files with 415 additions and 6 deletions
+1 -1
View File
@@ -176,7 +176,7 @@ export function AutoPanel({ bookId, sessionId, disabled }: AutoPanelProps): Reac
type="button"
className="btn"
data-testid="auto-pause"
disabled={disabled || streaming}
disabled={disabled}
onClick={() => void pause(bookId)}
>
{t('auto.pause')}
@@ -2,6 +2,8 @@ import { useTranslation } from 'react-i18next'
import { useAppStore } from '@renderer/stores/useAppStore'
import { useBookStore } from '@renderer/stores/useBookStore'
import { useInteractiveStore } from '@renderer/stores/useInteractiveStore'
import { useAutoStore } from '@renderer/stores/useAutoStore'
import { useWizardStore } from '@renderer/stores/useWizardStore'
import { WordFreqPanel } from '@renderer/components/wordfreq/WordFreqPanel'
import { AiPanel } from '@renderer/components/ai/AiPanel'
import { KnowledgePanel } from '@renderer/components/knowledge/KnowledgePanel'
@@ -29,7 +31,11 @@ export function RightPanel(): React.JSX.Element {
onClick={() => {
if (tab.id === 'ai') {
const bookId = useBookStore.getState().currentBookId
if (bookId) void useInteractiveStore.getState().checkGate(bookId)
if (bookId) {
void useInteractiveStore.getState().checkGate(bookId)
void useAutoStore.getState().checkGate(bookId)
void useWizardStore.getState().checkGate(bookId)
}
}
setRightPanel(tab.id)
}}
+9 -2
View File
@@ -5,6 +5,7 @@ import { useBookStore } from '@renderer/stores/useBookStore'
import { useAppStore } from '@renderer/stores/useAppStore'
import { useEditStore } from '@renderer/stores/useEditStore'
import { useAiStore } from '@renderer/stores/useAiStore'
import { useInteractiveStore } from '@renderer/stores/useInteractiveStore'
import i18n from '@renderer/i18n'
interface AutoState {
@@ -126,11 +127,17 @@ export const useAutoStore = create<AutoState>((set, get) => ({
handoffInteractive: async (bookId) => {
const flowId = get().flow?.id
if (!flowId) return
const sessionId = useAiStore.getState().activeSessionId
if (!flowId || !sessionId) return
const flow = await ipcCall(() => window.electronAPI.auto.handoffInteractive(bookId, flowId))
set({ flow })
set({ flow, streaming: false, streamBuffer: '' })
useAiStore.getState().setWritingMode('interactive')
useAppStore.getState().showToast(i18n.t('wizard.handoffToast'))
await useInteractiveStore.getState().loadFlow(bookId, sessionId)
const interactiveFlow = useInteractiveStore.getState().flow
if (interactiveFlow?.step === 'plot_suggest') {
await useInteractiveStore.getState().suggestPlots(bookId)
}
},
finishChapter: async (bookId, title) => {
+8 -1
View File
@@ -8,6 +8,7 @@ import type {
} from '@shared/types'
import { ipcCall } from '@renderer/lib/ipc-client'
import { useAiStore } from '@renderer/stores/useAiStore'
import { useInteractiveStore } from '@renderer/stores/useInteractiveStore'
import { useAppStore } from '@renderer/stores/useAppStore'
import i18n from '@renderer/i18n'
@@ -108,13 +109,19 @@ export const useWizardStore = create<WizardState>((set, get) => ({
startGenerate: async (bookId) => {
const flowId = get().flow?.id
if (!flowId) return
const sessionId = useAiStore.getState().activeSessionId
if (!flowId || !sessionId) return
set({ streaming: true, streamBuffer: '' })
try {
const flow = await ipcCall(() => window.electronAPI.wizard.startGenerate(bookId, flowId))
set({ flow })
useAiStore.getState().setWritingMode('interactive')
useAppStore.getState().showToast(i18n.t('wizard.handoffToast'))
await useInteractiveStore.getState().loadFlow(bookId, sessionId)
const interactiveFlow = useInteractiveStore.getState().flow
if (interactiveFlow?.step === 'plot_suggest') {
await useInteractiveStore.getState().suggestPlots(bookId)
}
} finally {
set({ streaming: false, streamBuffer: '' })
}