返回 oh-my-ppt
style-fidelity.test.ts
根目录 / tests / unit / prompt / style-fidelity.test.ts
1 import { describe, expect, it } from 'vitest'
2 import fs from 'fs'
3 import path from 'path'
4 import {
5 buildDeckAgentSystemPrompt,
6 buildEditAgentSystemPrompt
7 } from '../../../src/main/agent-runtime/prompt'
8 import { resolveSlideSize } from '../../../src/shared/slide-size'
9
10 const readSource = (relativePath: string): string =>
11 fs.readFileSync(path.join(process.cwd(), relativePath), 'utf-8')
12
13 describe('style fidelity prompt placement', () => {
14 it('keeps style fidelity as a shared system-level rule', () => {
15 const shared = readSource('src/main/agent-runtime/prompt/composers/shared.ts')
16
17 expect(shared).toContain('export const STYLE_FIDELITY_RULES')
18 expect(shared).toContain('尺寸布局与风格合成闸门')
19 expect(shared).toContain('当前画布尺寸与已注入的 layout skill/catalog 是页面结构的唯一来源')
20 expect(shared).toContain('视觉语言的唯一来源')
21 expect(shared).toContain('先依据 layout skill/catalog 选择适合当前尺寸的页面结构')
22 expect(shared).toContain('不能直接作为页面骨架')
23 expect(shared).toContain('size-aware layoutMotif')
24 expect(shared).toContain('单页生成也必须像整套 deck 一样遵守当前 style')
25 expect(shared).toContain('Size-adapted composition motif')
26 })
27
28 it('prescribes content-overload priority in shared content rules', () => {
29 const shared = readSource('src/main/agent-runtime/prompt/composers/shared.ts')
30
31 // When content oversupply exceeds a canvas's capacity, the model must
32 // compress/merge/drop first; it must NOT resolve overload by shrinking
33 // fonts below floors or by overflowing the canvas.
34 expect(shared).toContain('内容超载时按这个优先级解决')
35 expect(shared).toContain('绝不靠缩字号到下限以下')
36 expect(shared).toContain('竖版/小红书/方图本来就是低密度载体')
37 })
38
39 it('moves the deck-generation style preset to the end of the system prompt', () => {
40 const deckSystem = readSource('src/main/agent-runtime/prompt/composers/deck-system.ts')
41 const prompt = buildDeckAgentSystemPrompt('test-style', {
42 sessionId: 'session-1',
43 projectDir: '/tmp/project',
44 indexPath: '/tmp/project/index.html',
45 pageFileMap: { 'page-1': '/tmp/project/page-1.html' },
46 topic: 'Quarterly report',
47 deckTitle: 'Quarterly report',
48 styleId: 'test-style',
49 styleSkillPrompt: 'Use a clean business style.',
50 userMessage: 'Create a quarterly report.',
51 outlineTitles: ['Overview'],
52 outlineItems: [{ title: 'Overview', contentOutline: 'Summarize the quarter.' }],
53 slideSize: resolveSlideSize({ id: 'wide-16-9' }),
54 appLocale: 'en'
55 })
56
57 const currentTaskIndex = prompt.indexOf('## Current Task')
58 const finalStyleIndex = prompt.indexOf('## 最终风格校准(写入前)')
59 const finalReminderIndex = prompt.indexOf('⛔ FINAL REMINDER')
60
61 expect(deckSystem.slice(0, deckSystem.indexOf("} from './shared'"))).toContain(
62 'STYLE_FIDELITY_RULES'
63 )
64 expect(finalStyleIndex).toBeGreaterThan(currentTaskIndex)
65 expect(finalStyleIndex).toBeLessThan(finalReminderIndex)
66 expect(prompt.slice(currentTaskIndex)).toContain('风格预设:test-style (test-style)')
67 expect(prompt.slice(currentTaskIndex)).toContain('尺寸布局与风格合成闸门')
68 })
69
70 it('does not duplicate style fidelity into the single-page user prompt', () => {
71 const generationUser = readSource('src/main/agent-runtime/prompt/composers/generation-user.ts')
72
73 expect(generationUser).not.toContain('STYLE_FIDELITY_RULES')
74 expect(generationUser).not.toContain('风格预设:')
75 expect(generationUser).not.toContain('## 最终风格校准(写入前)')
76 })
77
78 it('applies the final style gate only to rewrite-capable edit system prompts', () => {
79 const baseContext = {
80 sessionId: 'session-1',
81 projectDir: '/tmp/project',
82 indexPath: '/tmp/project/index.html',
83 pageFileMap: { 'page-1': '/tmp/project/page-1.html' },
84 topic: 'Quarterly report',
85 deckTitle: 'Quarterly report',
86 styleId: 'test-style',
87 styleSkillPrompt: 'Use a clean business style.',
88 userMessage: 'Create a quarterly report.',
89 outlineTitles: ['Overview'],
90 outlineItems: [{ title: 'Overview', contentOutline: 'Summarize the quarter.' }],
91 slideSize: resolveSlideSize({ id: 'wide-16-9' }),
92 appLocale: 'en' as const,
93 mode: 'edit' as const,
94 selectedPageId: 'page-1',
95 selectedPageNumber: 1
96 }
97 const singlePageEdit = buildEditAgentSystemPrompt('test-style', {
98 ...baseContext,
99 editScope: 'page'
100 })
101 const deckEdit = buildEditAgentSystemPrompt('test-style', {
102 ...baseContext,
103 editScope: 'deck'
104 })
105 const selectorEdit = buildEditAgentSystemPrompt('test-style', {
106 ...baseContext,
107 editScope: 'page',
108 selectedSelector: '.metric'
109 })
110 const containerEdit = buildEditAgentSystemPrompt('test-style', {
111 ...baseContext,
112 editScope: 'presentation-container'
113 })
114
115 for (const prompt of [singlePageEdit, deckEdit]) {
116 expect(prompt).toContain('## 最终风格校准(写入前)')
117 expect(prompt.indexOf('## 最终风格校准(写入前)')).toBeGreaterThan(
118 prompt.indexOf('## Current Task')
119 )
120 expect(prompt).toContain('尺寸布局与风格合成闸门')
121 }
122
123 expect(selectorEdit).not.toContain('尺寸布局与风格合成闸门')
124 expect(containerEdit).not.toContain('尺寸布局与风格合成闸门')
125 })
126 })
127
127 lines TYPESCRIPT