aa2c7dfed3
Add semi-automatic knowledge suggestions and user-confirmed injection across chat, interactive, auto, and wizard modes; fix writing flows to persist full systemPrompt in contextJson. Co-authored-by: Cursor <cursoragent@cursor.com>
96 lines
3.5 KiB
TypeScript
96 lines
3.5 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { DatabaseSync } from 'node:sqlite'
|
|
import { migrate } from '../../src/main/db/migrate'
|
|
import { AiSessionRepository } from '../../src/main/db/repositories/ai-session.repo'
|
|
import { InteractiveRepository } from '../../src/main/db/repositories/interactive.repo'
|
|
import { WizardWritingService } from '../../src/main/services/wizard-writing.service'
|
|
import { AutoWritingService } from '../../src/main/services/auto-writing.service'
|
|
import { AiClientService } from '../../src/main/services/ai-client.service'
|
|
import { DEFAULT_AI_CONFIG, type AutoWritingConfig, type InteractiveFlow } from '../../src/shared/types'
|
|
|
|
const AI_TEST_CONFIG = { ...DEFAULT_AI_CONFIG, timeoutMs: 300_000, maxTokens: 4096 }
|
|
const CONTEXT = '林远站在演武场中央,众人目光汇聚,等待入门考核开始。'
|
|
|
|
describe('WizardWritingService.startGenerate', () => {
|
|
const wizard = (db: DatabaseSync) =>
|
|
new WizardWritingService(db, new AiClientService(() => AI_TEST_CONFIG))
|
|
const auto = (db: DatabaseSync) =>
|
|
new AutoWritingService(db, new AiClientService(() => AI_TEST_CONFIG))
|
|
|
|
async function setupWizardFlow(svc: WizardWritingService, sessionId: string): Promise<string> {
|
|
let flow = svc.start(sessionId)
|
|
flow = svc.setGoal(flow.id, {
|
|
chapterGoal: '林远通过入门考核,展现天赋',
|
|
wordMin: 600,
|
|
wordMax: 1200
|
|
})
|
|
flow = svc.setRhythm(flow.id, 'tense')
|
|
flow = svc.setPov(flow.id)
|
|
flow = svc.confirmContext(flow.id, {
|
|
binding: {
|
|
chapterIds: [],
|
|
outlineIds: [],
|
|
settingIds: [],
|
|
inspirationIds: [],
|
|
knowledgeIds: []
|
|
},
|
|
systemPrompt: CONTEXT,
|
|
contextSummary: '0章·0纲·0设·0感·0知'
|
|
})
|
|
return flow.id
|
|
}
|
|
|
|
async function continueAfterPartialGenerate(
|
|
wizSvc: WizardWritingService,
|
|
autoSvc: AutoWritingService,
|
|
repo: InteractiveRepository,
|
|
flowId: string,
|
|
initial: InteractiveFlow
|
|
): Promise<InteractiveFlow> {
|
|
let flow = initial
|
|
for (let guard = 0; guard < 8 && flow.flowMode !== 'interactive'; guard++) {
|
|
if (flow.step === 'naming_pause' && flow.namingPending) {
|
|
flow = await autoSvc.resolveNaming(
|
|
flowId,
|
|
flow.namingPending.options[0]!,
|
|
CONTEXT,
|
|
() => {}
|
|
)
|
|
continue
|
|
}
|
|
const config = repo.getModeConfig<AutoWritingConfig>(flowId)
|
|
const planLen = config.scenePlan?.length ?? 0
|
|
const idx = config.currentPlanIndex ?? 0
|
|
if (idx < planLen) {
|
|
flow = await autoSvc.generateNext(flowId, CONTEXT, () => {})
|
|
continue
|
|
}
|
|
if (flow.scenes.length > 0) {
|
|
return wizSvc.handoffToInteractive(flowId)
|
|
}
|
|
break
|
|
}
|
|
return flow
|
|
}
|
|
|
|
it('IT-WIZ-02: startGenerate handoffs to interactive with scenes', async () => {
|
|
const db = new DatabaseSync(':memory:')
|
|
migrate(db)
|
|
const repo = new InteractiveRepository(db)
|
|
const session = new AiSessionRepository(db).create('t', DEFAULT_AI_CONFIG.model)
|
|
const wizSvc = wizard(db)
|
|
const autoSvc = auto(db)
|
|
const flowId = await setupWizardFlow(wizSvc, session.id)
|
|
|
|
const initial = await wizSvc.startGenerate(flowId, CONTEXT, () => {})
|
|
const flow =
|
|
initial.flowMode === 'interactive'
|
|
? initial
|
|
: await continueAfterPartialGenerate(wizSvc, autoSvc, repo, flowId, initial)
|
|
|
|
expect(flow.flowMode).toBe('interactive')
|
|
expect(flow.scenes.length).toBeGreaterThanOrEqual(1)
|
|
db.close()
|
|
}, 600_000)
|
|
})
|