(doc, transcript)
| 214 | } |
| 215 | |
| 216 | async function updateMagicDoc(doc, transcript) { |
| 217 | const now = Date.now() |
| 218 | const lastAt = magicDocLastUpdated.get(doc.path) || 0 |
| 219 | if (now - lastAt < MAGIC_DOC_COOLDOWN_MS) return |
| 220 | magicDocLastUpdated.set(doc.path, now) |
| 221 | |
| 222 | const currentContent = await readFile(doc.path, 'utf8').catch(() => null) |
| 223 | if (!currentContent) return |
| 224 | |
| 225 | const recentChat = transcript.slice(-6).map(e => `${e.role}: ${e.content?.slice(0, 500) || ''}`).join('\n') |
| 226 | if (!recentChat.trim()) return |
| 227 | |
| 228 | const systemPrompt = `你是一个文档维护助手。根据最近的对话内容,更新 Magic Doc 文件。 |
| 229 | 规则: |
| 230 | - 保留文件头 "# MAGIC DOC: ${doc.title}" 不变 |
| 231 | - 只更新有实质新信息的部分 |
| 232 | - 删除过时内容 |
| 233 | - 保持简洁,高信号密度 |
| 234 | - 如果没有需要更新的内容,原样返回文档 |
| 235 | ${doc.instructions ? `- 自定义指令: ${doc.instructions}` : ''}` |
| 236 | |
| 237 | const userPrompt = `当前文档内容: |
| 238 | <doc> |
| 239 | ${currentContent} |
| 240 | </doc> |
| 241 | |
| 242 | 最近对话: |
| 243 | <conversation> |
| 244 | ${recentChat} |
| 245 | </conversation> |
| 246 | |
| 247 | 请返回更新后的完整文档内容(不要用代码块包裹)。如果无需更新,原样返回。` |
| 248 | |
| 249 | const result = await callGatewayLLM(systemPrompt, userPrompt) |
| 250 | if (!result || result.length < 10) return |
| 251 | if (!result.match(/^#\s*MAGIC\s+DOC:/im)) return |
| 252 | |
| 253 | await writeFile(doc.path, result, 'utf8') |
| 254 | pushLog('ui', `已更新 Magic Doc: ${doc.title}`, 'info') |
| 255 | broadcast({ type: 'timeline_upsert', entry: { id: `magic-${Date.now()}`, kind: 'status', status: 'success', title: `已更新文档: ${doc.title}`, content: '', timestamp: new Date().toISOString() } }) |
| 256 | } |
| 257 | |
| 258 | async function runMagicDocsHook() { |
| 259 | try { |
no test coverage detected