import { STATUS_LABEL, type ChatMessage, type Task, type TaskStatus } from './types'; interface ProgressBlock { ts: string; title: string; status: string; detail: string; } let counter = 0; export function nextMessageId(prefix = 'm'): string { counter += 1; return `${prefix}-${Date.now()}-${counter}`; } /** 解析 progress.md 的事件块:### 图标 [时间] 标题 / - **状态**:x / - **详情**:y */ export function parseProgressBlocks(content: string): ProgressBlock[] { const blocks: ProgressBlock[] = []; let current: ProgressBlock | null = null; for (const line of content.split('\n')) { const heading = line.match(/^### (\S+) \[(.+?)\] (.+)$/); if (heading) { current = { ts: heading[2], title: heading[3].trim(), status: '', detail: '' }; blocks.push(current); continue; } if (line.startsWith('## ') || line.startsWith('---')) { current = null; continue; } if (!current) continue; const status = line.match(/^- \*\*状态\*\*:(.*)$/); const detail = line.match(/^- \*\*详情\*\*:(.*)$/); if (status) current.status = status[1].trim(); else if (detail) current.detail = detail[1].trim(); else if (current.detail && line.trim() && !line.startsWith('#')) current.detail += `\n${line}`; } return blocks; } function labelOf(status: string): string { return (STATUS_LABEL as Record)[status] ?? status; } /** 用进度文档把一个历史任务回放成对话。 */ export function buildTranscript(task: Task, content: string | null): ChatMessage[] { const messages: ChatMessage[] = []; const push = (role: ChatMessage['role'], text: string): void => { if (text.trim()) messages.push({ id: nextMessageId('t'), role, text }); }; if (task.inputs.goal) push('user', task.inputs.goal); if (!content) return messages; for (const block of parseProgressBlocks(content)) { if (/^步骤 \d+/.test(block.title)) continue; if (block.title.startsWith('跟踪回查')) { if (/^(状态|审批)/.test(block.detail)) push('system', `${block.title}:${block.detail}`); continue; } if (block.title === '提交后跟踪' || block.title === '切换前置事项' || block.title === '用户接管' || block.title === '接管结束') { push('system', block.detail); continue; } if (block.title === '识别业务') push('system', `识别业务:${block.detail}`); else if (block.title === '角色准入') push('assistant', block.detail); else if (block.title === '收集资料') push('assistant', `请补充:${block.detail.replace(/^缺少:/, '')}`); else if (block.title === '用户补充资料' || block.title === '用户回答') push('user', block.detail.replace(/(抽取:.*)$/, '')); else if (block.title === '等待用户' || block.title === '前置阻断') { if (block.status === 'paused') push('assistant', block.detail); else if (block.status === 'blocked') push('system', block.detail); } else if (block.status === 'completed' || block.status === 'submitted') push('assistant', `${labelOf(block.status)}\n\n${block.detail}`); else if (block.status === 'failed') push('system', `办理未完成:${block.detail}`); else if (block.status === 'rejected') push('assistant', block.detail); else if (block.title === '沉淀草稿') push('system', `沉淀:${block.detail.split('(')[0]}`); } return messages; } export function isTerminal(status: TaskStatus): boolean { return ['submitted', 'completed', 'failed', 'blocked', 'rejected'].includes(status); }