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
JavaScript
/**
* 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