📄 generator.ts • 7809 bytes
/**
* 执行计划 - 计划生成器
* Phase 2: LLM生成 + 智能拆解
*/
import { type ExecutionPlan, type PlanStep, type Risk评估 } from './types'
/** 生成唯一ID */
function generateId(): string {
return 'plan_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 6)
}
/** 分析任务复杂度 */
function analyzeComplexity(task: string): 'simple' | 'medium' | 'complex' {
const simpleIndicators = ['读', '查看', '显示', '输出', '列出']
const complexIndicators = ['创建', '实现', '开发', '系统', '完整', '全面']
let score = 0
for (const ind of simpleIndicators) {
if (task.includes(ind)) score -= 1
}
for (const ind of complexIndicators) {
if (task.includes(ind)) score += 2
}
if (score <= -1) return 'simple'
if (score >= 2) return 'complex'
return 'medium'
}
/** 识别文件路径 */
function extractFilePaths(task: string): string[] {
const regex = /[\w\-\./]+\.[a-zA-Z]+/g
return task.match(regex) || []
}
/** 识别编程语言 */
function extractLanguage(task: string): string | null {
const langMap: Record<string, RegExp> = {
'TypeScript': /typescript|ts\b/i,
'JavaScript': /javascript|js\b/i,
'Python': /python|py\b/i,
'Rust': /rust\b/i,
'Go': /\bgo\b/i,
'HTML': /html\b/i,
'CSS': /css\b/i,
'SQL': /sql\b/i,
}
for (const [lang, regex] of Object.entries(langMap)) {
if (regex.test(task)) return lang
}
return null
}
/** 为简单任务生成快速计划 */
function generateSimplePlan(task: string): ExecutionPlan {
const filePaths = extractFilePaths(task)
const lang = extractLanguage(task)
const steps: PlanStep[] = []
let stepId = 1
// 根据任务关键词生成步骤
if (task.includes('读') || task.includes('查看') || task.includes('显示')) {
for (const file of filePaths) {
steps.push({
id: stepId++,
action: `读取文件 ${file}`,
tool: 'file_read',
params: { path: file },
expected: '文件内容',
status: 'pending',
retryCount: 0,
})
}
if (steps.length === 0) {
steps.push({
id: stepId++,
action: '搜索相关信息',
tool: 'grep_search',
params: { pattern: task.replace(/[读查看显示]/g, '').trim() },
expected: '搜索结果',
status: 'pending',
retryCount: 0,
})
}
} else if (task.includes('写') || task.includes('创建') || task.includes('新建')) {
const file = filePaths[0] || 'new_file.txt'
steps.push({
id: stepId++,
action: `创建文件 ${file}`,
tool: 'file_write',
params: { path: file, content: `// ${lang || 'TODO'}: ${task}` },
expected: '文件创建成功',
status: 'pending',
retryCount: 0,
})
}
return {
id: generateId(),
title: task.slice(0, 50),
description: task,
steps,
estimatedSteps: steps.length,
risks: [{ level: 'low', description: '简单文件操作' }],
createdAt: new Date().toISOString(),
status: 'pending',
currentStep: 0,
}
}
/** 为中等任务生成计划 */
function generateMediumPlan(task: string): ExecutionPlan {
const filePaths = extractFilePaths(task)
const lang = extractLanguage(task)
const steps: PlanStep[] = []
let stepId = 1
// 1. 分析现有代码
if (filePaths.length > 0) {
steps.push({
id: stepId++,
action: `分析文件 ${filePaths[0]}`,
tool: 'file_read',
params: { path: filePaths[0] },
expected: '代码结构分析',
status: 'pending',
retryCount: 0,
})
}
// 2. 编写代码
const targetFile = filePaths[1] || filePaths[0] || 'output.ts'
steps.push({
id: stepId++,
action: `编写 ${lang || '代码'} 代码`,
tool: 'file_write',
params: { path: targetFile, content: '// generated code' },
expected: '代码编写完成',
status: 'pending',
retryCount: 0,
})
// 3. 验证语法
if (lang === 'TypeScript') {
steps.push({
id: stepId++,
action: '检查 TypeScript 语法',
tool: 'bash_run',
params: { command: `npx tsc --noEmit ${targetFile}` },
expected: '无语法错误',
status: 'pending',
retryCount: 1,
})
}
return {
id: generateId(),
title: task.slice(0, 50),
description: task,
steps,
estimatedSteps: steps.length,
estimatedTime: steps.length * 5,
risks: [{ level: 'medium', description: '涉及代码修改' }],
createdAt: new Date().toISOString(),
status: 'pending',
currentStep: 0,
}
}
/** 为复杂任务生成计划 */
function generateComplexPlan(task: string): ExecutionPlan {
const filePaths = extractFilePaths(task)
const lang = extractLanguage(task)
const steps: PlanStep[] = []
let stepId = 1
// 1. 调研阶段
steps.push({
id: stepId++,
action: '分析任务需求',
tool: 'list_dir',
params: { path: '.' },
expected: '了解项目结构',
status: 'pending',
retryCount: 0,
})
// 2. 读取现有代码
for (const file of filePaths.slice(0, 3)) {
steps.push({
id: stepId++,
action: `分析 ${file}`,
tool: 'file_read',
params: { path: file },
expected: '理解现有实现',
status: 'pending',
retryCount: 0,
})
}
// 3. 实现阶段
steps.push({
id: stepId++,
action: `实现 ${lang || '代码'} 功能`,
tool: 'file_write',
params: { path: 'src/main.ts', content: '// implementation' },
expected: '功能实现完成',
status: 'pending',
retryCount: 2,
})
// 4. 测试阶段
steps.push({
id: stepId++,
action: '运行测试验证',
tool: 'bash_run',
params: { command: 'npm test' },
expected: '测试通过',
status: 'pending',
retryCount: 1,
})
return {
id: generateId(),
title: task.slice(0, 50),
description: task,
steps,
estimatedSteps: steps.length,
estimatedTime: steps.length * 10,
risks: [
{ level: 'medium', description: '涉及多文件修改', mitigation: '分步执行验证' },
{ level: 'medium', description: '可能影响现有功能', mitigation: '执行测试确认' },
],
createdAt: new Date().toISOString(),
status: 'pending',
currentStep: 0,
}
}
/**
* 生成执行计划
* @param task 用户任务描述
* @returns 执行计划
*/
export function generatePlan(task: string): ExecutionPlan {
const complexity = analyzeComplexity(task)
switch (complexity) {
case 'simple':
return generateSimplePlan(task)
case 'medium':
return generateMediumPlan(task)
case 'complex':
return generateComplexPlan(task)
}
}
/**
* 格式化计划为用户可读文本
*/
export function formatPlan(plan: ExecutionPlan): string {
let output = `\n📋 **执行计划**: ${plan.title}\n\n`
output += `⏱️ 预估步骤: ${plan.estimatedSteps}`
if (plan.estimatedTime) {
output += ` | 预估时间: ~${plan.estimatedTime}秒`
}
output += '\n\n'
for (const step of plan.steps) {
output += `${step.id}. [${step.status}] ${step.action}\n`
output += ` 🔧 ${step.tool}\n`
output += ` 📤 预期: ${step.expected}\n\n`
}
if (plan.risks.length > 0) {
output += '\n⚠️ **风险提示**:\n'
for (const risk of plan.risks) {
output += `- ${risk.level.toUpperCase()}: ${risk.description}`
if (risk.mitigation) {
output += ` (${risk.mitigation})`
}
output += '\n'
}
}
output += '\n---\n'
output += '请选择操作:\n'
output += '1️⃣ 确认执行\n'
output += '2️⃣ 修改计划\n'
output += '3️⃣ 部分执行\n'
output += '4️⃣ 取消\n'
return output
}