返回 oh-my-ppt
source-brief.test.ts
根目录 / tests / unit / thinking / source-brief.test.ts
1 import fs from 'fs'
2 import os from 'os'
3 import path from 'path'
4 import { afterEach, describe, expect, it } from 'vitest'
5 import { buildThinkingSourceBrief } from '../../../src/main/thinking/source-brief'
6
7 const tempDirs: string[] = []
8
9 const makeTempThinkingDir = async (): Promise<string> => {
10 const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'thinking-source-brief-'))
11 tempDirs.push(dir)
12 await fs.promises.mkdir(path.join(dir, 'sources'), { recursive: true })
13 return dir
14 }
15
16 afterEach(async () => {
17 await Promise.all(
18 tempDirs.splice(0).map((dir) => fs.promises.rm(dir, { recursive: true, force: true }))
19 )
20 })
21
22 describe('thinking source brief', () => {
23 it('returns empty when the current message has no document attachments', async () => {
24 const thinkingDir = await makeTempThinkingDir()
25
26 await expect(buildThinkingSourceBrief({ thinkingDir })).resolves.toBe('')
27 await expect(
28 buildThinkingSourceBrief({
29 thinkingDir,
30 attachments: [{ id: 'image-1', name: '截图.png', kind: 'image' }]
31 })
32 ).resolves.toBe('')
33 })
34
35 it('builds a lightweight deterministic outline card for attached sources', async () => {
36 const thinkingDir = await makeTempThinkingDir()
37 await fs.promises.writeFile(
38 path.join(thinkingDir, 'sources.json'),
39 JSON.stringify([
40 { id: 'source-1', name: '增长方案.md', kind: 'markdown', fileName: 'growth.md' },
41 { id: 'source-2', name: '未发送.md', kind: 'markdown', fileName: 'unused.md' }
42 ])
43 )
44 await fs.promises.writeFile(
45 path.join(thinkingDir, 'sources/growth.md'),
46 [
47 '# 增长方案',
48 '',
49 '## 背景',
50 '这里说明背景和目标。',
51 '',
52 '## 增长策略',
53 '- 自然流量',
54 '- 短视频转化',
55 '',
56 '### 转化指标',
57 '- GMV grew 15%',
58 '',
59 '## 执行计划',
60 '- 周期',
61 '- 责任人'
62 ].join('\n')
63 )
64 await fs.promises.writeFile(
65 path.join(thinkingDir, 'sources/unused.md'),
66 ['# 未发送', '## 不应出现'].join('\n')
67 )
68
69 const brief = await buildThinkingSourceBrief({
70 thinkingDir,
71 attachments: [{ id: 'source-1', name: '增长方案.md', kind: 'markdown' }]
72 })
73
74 expect(brief).toContain('## Source Brief')
75 expect(brief).toContain('### 增长方案.md')
76 expect(brief).toContain('- Source file: /sources/growth.md')
77 expect(brief).toContain('- Top-level title: 增长方案')
78 expect(brief).toContain('- Headings detected: 5')
79 expect(brief).toContain('Page candidates')
80 expect(brief).toContain('## 增长策略')
81 expect(brief).toContain('### 转化指标')
82 expect(brief).not.toContain('未发送')
83 expect(brief).not.toContain('这里说明背景和目标')
84 })
85
86 it('returns a bounded fallback for very large attached sources', async () => {
87 const thinkingDir = await makeTempThinkingDir()
88 await fs.promises.writeFile(
89 path.join(thinkingDir, 'sources.json'),
90 JSON.stringify([{ id: 'source-1', name: '大文档.md', kind: 'markdown', fileName: 'large.md' }])
91 )
92 await fs.promises.writeFile(
93 path.join(thinkingDir, 'sources/large.md'),
94 ['# 大文档', 'x'.repeat(1_500_001)].join('\n')
95 )
96
97 const brief = await buildThinkingSourceBrief({
98 thinkingDir,
99 attachments: [{ id: 'source-1', name: '大文档.md', kind: 'markdown' }]
100 })
101
102 expect(brief).toContain('## Source Brief')
103 expect(brief).toContain('### 大文档.md')
104 expect(brief).toContain('File is large')
105 expect(brief).toContain('Use grep/read_file')
106 expect(brief.length).toBeLessThan(700)
107 })
108
109 it('returns a source-level fallback when scanning fails', async () => {
110 const thinkingDir = await makeTempThinkingDir()
111 await fs.promises.writeFile(
112 path.join(thinkingDir, 'sources.json'),
113 JSON.stringify([{ id: 'source-1', name: '缺失.md', kind: 'markdown', fileName: 'missing.md' }])
114 )
115
116 const brief = await buildThinkingSourceBrief({
117 thinkingDir,
118 attachments: [{ id: 'source-1', name: '缺失.md', kind: 'markdown' }]
119 })
120
121 expect(brief).toContain('## Source Brief')
122 expect(brief).toContain('### 缺失.md')
123 expect(brief).toContain('Source brief scan failed')
124 expect(brief).toContain('/sources/missing.md')
125 })
126 })
127
127 lines TYPESCRIPT