UNPKG

miyabi-agent-sdk

Version:

Miyabi Autonomous Agent SDK - 7 Agents based on Shikigaku Theory with 100% cost reduction mode

319 lines (304 loc) 9.87 kB
/** * CodeGenAgent - コード生成Agent * * 識学理論適用: * - 責任: タスクに対してコードを生成 * - 権限: ファイル作成・変更・削除、テストコード生成、品質スコア自己評価 * - 階層: Specialist Layer * * Phase 8-2: Real API Integration */ import { AnthropicClient } from "../clients/AnthropicClient.js"; import { ClaudeCodeClient } from "../clients/ClaudeCodeClient.js"; import { GitHubClient } from "../clients/GitHubClient.js"; /** * CodeGenAgent実装 * * 既存コード読み込み → Claude生成 → テスト生成 → 品質自己評価 */ export class CodeGenAgent { anthropicClient; claudeCodeClient; githubClient; constructor(config) { if (config) { if (config.useClaudeCode) { this.claudeCodeClient = new ClaudeCodeClient(); } else if (config.anthropicApiKey) { this.anthropicClient = new AnthropicClient(config.anthropicApiKey); } if (config.githubToken) { this.githubClient = new GitHubClient(config.githubToken); } } } /** * メイン実行ロジック */ async generate(input) { try { const githubClient = input.githubClient || this.githubClient; const anthropicClient = input.anthropicClient || this.anthropicClient; const claudeCodeClient = input.claudeCodeClient || this.claudeCodeClient; const useRealAPI = input.useRealAPI !== false && !!(githubClient || anthropicClient || claudeCodeClient); // 1. 既存コード読み込み(GitHub API - Phase 8で実API統合) const context = await this.loadContext(input.context, githubClient); // 2. コード生成(Claude Sonnet 4 / Claude Code - Phase 9統合) const result = await this.generateCode(input.requirements, context, input.language || "typescript", anthropicClient, claudeCodeClient, useRealAPI); // 3. テストコード生成(Claude already included in result) const tests = result.tests || await this.generateTests(result.files, context); // 4. 品質スコア自己評価 const qualityScore = result.qualityScore || await this.evaluateQuality(result.files, tests); return { success: true, data: { files: result.files, tests, qualityScore, tokensUsed: result.tokensUsed, cost: result.cost, }, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Unknown error occurred", }; } } /** * 既存コンテキスト読み込み * * Phase 8: Real GitHub API integration */ async loadContext(context, githubClient) { if (githubClient && context.relatedFiles.length > 0) { // Real API implementation const files = await Promise.all(context.relatedFiles.map(async (path) => { const file = await githubClient.getFileContent(context.owner, context.repository, path, context.baseBranch); return file ? { path: file.path, content: file.content } : null; })); return { files: files.filter((f) => f !== null), }; } else { // Mock implementation (fallback) return { files: context.relatedFiles.map((path) => ({ path, content: `// Mock content for ${path}`, })), }; } } /** * コード生成(Claude Sonnet 4使用) * * Phase 8: Real Claude API integration */ async generateCode(requirements, context, language, anthropicClient, claudeCodeClient, useRealAPI) { if (useRealAPI && claudeCodeClient) { // Phase 9: Claude Code implementation const contextStr = context.files .map((f) => `File: ${f.path}\n\`\`\`\n${f.content}\n\`\`\``) .join("\n\n"); const result = await claudeCodeClient.generateCode({ taskId: "code-gen", requirements, context: contextStr, language, }); return { files: result.files, tests: result.tests, qualityScore: result.qualityScore, tokensUsed: { input: 0, output: 0 }, cost: 0, // Free! }; } else if (useRealAPI && anthropicClient) { // Phase 8: Real Anthropic API implementation const contextStr = context.files .map((f) => `File: ${f.path}\n\`\`\`\n${f.content}\n\`\`\``) .join("\n\n"); const result = await anthropicClient.generateCode(requirements, contextStr, language); // Calculate cost const cost = anthropicClient.calculateCost(result.tokensUsed); return { files: result.files, tests: result.tests, qualityScore: result.qualityScore, tokensUsed: result.tokensUsed, cost, }; } else { // Mock implementation (fallback) const files = [ { path: `src/generated/${this.sanitizeFilename(requirements)}.${this.getExtension(language)}`, content: this.generateMockCode(requirements, language), action: "create", }, ]; return { files, tokensUsed: undefined, cost: undefined, }; } } /** * Claude用プロンプト生成 * * TODO: Claude統合時に使用 */ // @ts-ignore - Claude統合時に使用する予定 buildCodeGenPrompt(requirements, context, language) { return ` あなたは${language}のエキスパートエンジニアです。以下の要件に基づいてコードを生成してください。 ## 要件 ${requirements} ## 既存コンテキスト ${context.files.map((f) => `### ${f.path}\n\`\`\`${language}\n${f.content}\n\`\`\``).join("\n\n")} ## 出力形式(JSON) { "files": [ { "path": "src/example.ts", "content": "// コード内容", "action": "create" | "modify" | "delete" } ] } ## 品質要件 - TypeScript: strict mode準拠 - Rust: clippy警告0件 - ESLint/Clippy警告0件 - 適切なエラーハンドリング - ドキュメントコメント必須 `.trim(); } /** * テストコード生成 */ async generateTests(files, _context) { // Mock implementation return files.map((file) => ({ path: file.path.replace(/\.(ts|rs|py|go)$/, ".test.$1"), content: this.generateMockTest(file), action: "create", })); } /** * Mock test生成 */ generateMockTest(file) { return ` // Test for ${file.path} import { describe, it, expect } from "vitest"; describe("${file.path}", () => { it("should work correctly", () => { expect(true).toBe(true); }); }); `.trim(); } /** * 品質スコア自己評価 */ async evaluateQuality(files, tests) { let score = 100; // ファイル数チェック if (files.length === 0) score -= 50; // テストカバレッジチェック if (tests.length === 0) score -= 30; else if (tests.length < files.length) score -= 10; // TODO: 実際のLint/TypeCheckを実行 // - ESLint実行: エラー1件につき-5点 // - TypeScript型チェック: エラー1件につき-10点 // - テストカバレッジ: 80%未満の場合-20点 return Math.max(0, score); } /** * Mock code生成 */ generateMockCode(requirements, language) { const template = { typescript: ` /** * Generated code for: ${requirements} */ export class GeneratedClass { constructor() { // TODO: Implement } public execute(): void { console.log("Generated code executed"); } } `.trim(), rust: ` // Generated code for: ${requirements} pub struct GeneratedStruct; impl GeneratedStruct { pub fn new() -> Self { Self } pub fn execute(&self) { println!("Generated code executed"); } } `.trim(), python: ` # Generated code for: ${requirements} class GeneratedClass: def __init__(self): pass def execute(self): print("Generated code executed") `.trim(), go: ` // Generated code for: ${requirements} package generated type GeneratedStruct struct{} func New() *GeneratedStruct { return &GeneratedStruct{} } func (g *GeneratedStruct) Execute() { println("Generated code executed") } `.trim(), }; return template[language] || template.typescript; } /** * ファイル名サニタイズ */ sanitizeFilename(text) { return text .toLowerCase() .replace(/[^a-z0-9]+/g, "-") .replace(/^-+|-+$/g, "") .substring(0, 50); } /** * 言語別拡張子取得 */ getExtension(language) { const extensions = { typescript: "ts", rust: "rs", python: "py", go: "go", }; return extensions[language] || "txt"; } } //# sourceMappingURL=CodeGenAgent.js.map