upulse-engine/src/workflows/roles/meta-coder-cursor.ts

88 lines
2.6 KiB
TypeScript

/**
* Meta Coder role — uses Cursor Agent to implement workflow code.
* Uses createAgentExecutorRole with LLM₂ meta parsing.
*
* 小橘 🍊 (NEKO Team)
*/
import type { LlmClient } from '@uncaged/pulse';
import type { MetaCoderMeta } from '../meta.js';
import type { Role } from '@uncaged/pulse';
import { type AgentRunner, createAgentExecutorRole } from '@uncaged/pulse';
const PARSE_META_TOOL = {
type: 'function' as const,
function: {
name: 'extract_coder_meta',
description: 'Extract coder execution metadata',
parameters: {
type: 'object',
properties: {
filesChanged: {
type: 'array',
items: { type: 'string' },
description: 'Files created or modified',
},
testsPassed: {
type: 'boolean',
description: 'Whether all tests passed',
},
},
required: ['filesChanged', 'testsPassed'],
},
},
};
export function createMetaCoderRole(
runner: AgentRunner,
llm: LlmClient,
repoDir: string,
): Role<MetaCoderMeta> {
return createAgentExecutorRole<MetaCoderMeta>(runner, llm, {
prepPrompt: (chain, _topicId) => {
const startMsg = chain.find((m) => m.role === '__start__');
const taskDescription = startMsg?.content ?? '';
// 如果有 tester 失败反馈,附加
const testerMsg = [...chain].reverse().find((m) => m.role === 'tester');
const testerFeedback = testerMsg ? `\n\n## 上次验证失败\n${testerMsg.content}` : '';
const prompt = `# 任务
${taskDescription}
${testerFeedback}
## 参考
- 先阅读项目结构了解上下文
- 参考已有代码风格
- **必读模板**:\`templates/workflow.ts.tmpl\`\`templates/workflow.test.ts.tmpl\`,严格按模板结构写 workflow + test
## 步骤
1. 理解任务需求
2. 写代码实现
3. 运行 \`bun run build\` 确认编译通过
4. 运行测试确认通过
5. 不要 commit,让 workflow 处理
## 约束
- commit author: 小橘 <xiaoju@shazhou.work>
- 只修改 $HOME/.upulse/engine/src/workflows/ 下的代码
- 不修改 workflow-rule-adapter.ts 和 workflow-type.ts`;
return { prompt, cwd: repoDir };
},
parseMeta: {
system: '从 Cursor Agent 的输出中提取 coder 执行结果。',
tool: PARSE_META_TOOL,
parse: (args: string) => {
const parsed = JSON.parse(args);
return {
filesChanged: parsed.filesChanged ?? [],
testsPassed: parsed.testsPassed ?? false,
} as MetaCoderMeta;
},
defaultMeta: (_output: string) =>
({ filesChanged: [], testsPassed: false }) as MetaCoderMeta,
},
});
}