(task: Task, chunks: Chunk[])
| 313 | } |
| 314 | |
| 315 | private async handleNewSkill(task: Task, chunks: Chunk[]): Promise<void> { |
| 316 | const minConfidence = this.ctx.config.skillEvolution?.minConfidence ?? DEFAULTS.skillMinConfidence; |
| 317 | const evalResult = await this.evaluator.evaluateCreate(task); |
| 318 | |
| 319 | if (evalResult.shouldGenerate && evalResult.confidence >= minConfidence) { |
| 320 | const existingByName = this.store.getSkillByName(evalResult.suggestedName); |
| 321 | if (existingByName && (existingByName.status === "active" || existingByName.status === "draft")) { |
| 322 | this.ctx.log.info(`SkillEvolver: skill "${evalResult.suggestedName}" already exists, redirecting to upgrade instead of create`); |
| 323 | await this.handleExistingSkill(task, chunks, existingByName); |
| 324 | return; |
| 325 | } |
| 326 | |
| 327 | this.ctx.log.info(`SkillEvolver: generating new skill "${evalResult.suggestedName}" — ${evalResult.reason}`); |
| 328 | this.store.setTaskSkillMeta(task.id, { skillStatus: "generating", skillReason: evalResult.reason }); |
| 329 | |
| 330 | const skill = await this.generator.generate(task, chunks, evalResult); |
| 331 | this.markChunksWithSkill(chunks, skill.id); |
| 332 | this.store.linkTaskSkill(task.id, skill.id, "generated_from", 1); |
| 333 | this.store.setTaskSkillMeta(task.id, { skillStatus: "generated", skillReason: evalResult.reason }); |
| 334 | this.onSkillEvolved?.(skill.name, "created"); |
| 335 | |
| 336 | this.autoInstallIfNeeded(skill); |
| 337 | } else { |
| 338 | const reason = evalResult.reason || `confidence不足 (${evalResult.confidence} < ${minConfidence})`; |
| 339 | this.ctx.log.debug(`SkillEvolver: task "${task.title}" not worth generating skill — ${reason}`); |
| 340 | this.store.setTaskSkillMeta(task.id, { skillStatus: "not_generated", skillReason: reason }); |
| 341 | } |
| 342 | } |
| 343 | |
| 344 | private markChunksWithSkill(chunks: Chunk[], skillId: string): void { |
| 345 | for (const chunk of chunks) { |
no test coverage detected