use anyhow::Result;
use tracing::{debug, info, warn};
use crate::providers::OpenAIProvider;
use crate::utils::templates::TemplateManager;
pub mod architect;
pub mod conceptualizer;
pub mod pipeline;
pub use architect::{Architect, ArchitectStage};
pub use conceptualizer::{ConceptualizationStage, Conceptualizer};
pub use pipeline::{run_pipeline, CrateContext, GenerationPipeline};
#[derive(Clone)]
pub struct StageOrchestrator {
openai_provider: OpenAIProvider,
conceptualizer: Conceptualizer,
architect: Architect,
}
impl StageOrchestrator {
#[must_use]
pub fn new(openai_provider: OpenAIProvider) -> Self {
Self {
conceptualizer: Conceptualizer::new(openai_provider.clone()),
architect: Architect::new(openai_provider.clone()),
openai_provider,
}
}
#[must_use]
pub fn openai(&self) -> &OpenAIProvider {
&self.openai_provider
}
pub async fn conceptualize(
&self,
mut context: CrateContext,
enhanced_context: &str,
) -> Result<CrateContext> {
info!("Stage 1: Conceptualizing crate");
let start_time = std::time::Instant::now();
context = self
.conceptualizer
.execute(context, enhanced_context)
.await?;
let duration = start_time.elapsed();
debug!("Conceptualization completed in {:?}", duration);
context.set_stage_output(
"conceptualization_metrics",
serde_json::json!({
"duration_ms": duration.as_millis(),
"enhanced_context_length": enhanced_context.len()
}),
);
Ok(context)
}
pub async fn architect(&self, mut context: CrateContext) -> Result<CrateContext> {
info!("Stage 2: Architecting crate structure");
let start_time = std::time::Instant::now();
context = self.architect.execute(context).await?;
let duration = start_time.elapsed();
debug!("Architecture completed in {:?}", duration);
context.set_stage_output(
"architecture_metrics",
serde_json::json!({
"duration_ms": duration.as_millis(),
"modules_designed": context.get_file_paths().len()
}),
);
Ok(context)
}
pub async fn execute_full_pipeline(
&self,
context: CrateContext,
enhanced_context: &str,
) -> Result<CrateContext> {
info!("Executing full crate generation pipeline");
let pipeline_start = std::time::Instant::now();
let context = self.conceptualize(context, enhanced_context).await?;
let context = self.architect(context).await?;
let context = self.package(context, None).await?;
let context = self.test(context).await?;
let context = self.document(context).await?;
let context = self.deploy(context).await?;
let context = self.refine(context).await?;
let total_duration = pipeline_start.elapsed();
info!("Pipeline completed successfully in {:?}", total_duration);
Ok(context)
}
pub async fn package(
&self,
mut context: CrateContext,
template: Option<&str>,
) -> Result<CrateContext> {
info!("Stage 3: Packaging crate files");
let start_time = std::time::Instant::now();
let template_manager = TemplateManager::new().await?;
let generated_files = template_manager
.render_crate(&context, &context.output_path)
.await?;
for (path, content) in &generated_files {
context.add_file(path, content.clone());
}
let duration = start_time.elapsed();
debug!("Packaging completed in {:?}", duration);
context.set_stage_output(
"packaging_metrics",
serde_json::json!({
"duration_ms": duration.as_millis(),
"files_generated": generated_files.len(),
"template_used": template.unwrap_or("default")
}),
);
Ok(context)
}
pub async fn test(&self, mut context: CrateContext) -> Result<CrateContext> {
info!("Stage 4: Generating tests and validation");
let start_time = std::time::Instant::now();
let unit_tests = self.generate_unit_tests(&context).await?;
context.add_file("src/tests.rs", unit_tests);
let integration_tests = self.generate_integration_tests(&context).await?;
context.add_file("tests/integration.rs", integration_tests);
let benchmarks = self.generate_benchmarks(&context).await?;
context.add_file("benches/benchmarks.rs", benchmarks);
let duration = start_time.elapsed();
debug!("Testing stage completed in {:?}", duration);
context.set_stage_output(
"testing_metrics",
serde_json::json!({
"duration_ms": duration.as_millis(),
"unit_tests_generated": true,
"integration_tests_generated": true,
"benchmarks_generated": true
}),
);
Ok(context)
}
pub async fn document(&self, mut context: CrateContext) -> Result<CrateContext> {
info!("Stage 5: Generating documentation");
let start_time = std::time::Instant::now();
let api_docs = self.generate_api_docs(&context).await?;
context.add_file("docs/api.md", api_docs);
let examples = self.generate_examples(&context).await?;
context.add_file("examples/basic_usage.rs", examples);
let user_guide = self.generate_user_guide(&context).await?;
context.add_file("docs/user_guide.md", user_guide);
let duration = start_time.elapsed();
debug!("Documentation stage completed in {:?}", duration);
context.set_stage_output(
"documentation_metrics",
serde_json::json!({
"duration_ms": duration.as_millis(),
"api_docs_generated": true,
"examples_generated": true,
"user_guide_generated": true
}),
);
Ok(context)
}
pub async fn deploy(&self, mut context: CrateContext) -> Result<CrateContext> {
info!("Stage 6: Preparing deployment configuration");
let start_time = std::time::Instant::now();
let github_actions = self.generate_github_actions(&context).await?;
context.add_file(".github/workflows/ci.yml", github_actions);
let dockerfile = self.generate_dockerfile(&context).await?;
context.add_file("Dockerfile", dockerfile);
let release_config = self.get_release_config()?;
context.add_file("release.toml", release_config);
let duration = start_time.elapsed();
debug!("Deployment stage completed in {:?}", duration);
context.set_stage_output(
"deployment_metrics",
serde_json::json!({
"duration_ms": duration.as_millis(),
"ci_cd_generated": true,
"docker_generated": true,
"release_config_generated": true
}),
);
Ok(context)
}
pub async fn refine(&self, mut context: CrateContext) -> Result<CrateContext> {
info!("Stage 7: Final refinement and optimization");
let start_time = std::time::Instant::now();
context = self.optimize_code(context).await?;
context = self.format_code(context).await?;
let validation_results = self.validate_final_output(&context).await?;
let duration = start_time.elapsed();
debug!("Refinement stage completed in {:?}", duration);
context.set_stage_output(
"refinement_metrics",
serde_json::json!({
"duration_ms": duration.as_millis(),
"code_optimized": true,
"code_formatted": true,
"validation_passed": validation_results.is_empty()
}),
);
if !validation_results.is_empty() {
warn!("Validation issues found: {:?}", validation_results);
}
Ok(context)
}
async fn generate_unit_tests(&self, context: &CrateContext) -> Result<String> {
let prompt = format!(
"Generate comprehensive unit tests for a Rust crate named '{}' with description: '{}'",
context.crate_name, context.description
);
let response = self.openai_provider.chat("gpt-4", &prompt).await?;
Ok(response)
}
async fn generate_integration_tests(&self, context: &CrateContext) -> Result<String> {
let prompt = format!(
"Generate integration tests for a Rust crate named '{}' that tests end-to-end functionality",
context.crate_name
);
let response = self.openai_provider.chat("gpt-4", &prompt).await?;
Ok(response)
}
async fn generate_benchmarks(&self, context: &CrateContext) -> Result<String> {
let prompt = format!(
"Generate performance benchmarks using criterion for a Rust crate named '{}'",
context.crate_name
);
let response = self.openai_provider.chat("gpt-4", &prompt).await?;
Ok(response)
}
async fn generate_api_docs(&self, context: &CrateContext) -> Result<String> {
let prompt = format!(
"Generate comprehensive API documentation for a Rust crate named '{}' with description: '{}'",
context.crate_name, context.description
);
let response = self.openai_provider.chat("gpt-4", &prompt).await?;
Ok(response)
}
async fn generate_examples(&self, context: &CrateContext) -> Result<String> {
let prompt = format!(
"Generate practical usage examples for a Rust crate named '{}' that demonstrate core functionality",
context.crate_name
);
let response = self.openai_provider.chat("gpt-4", &prompt).await?;
Ok(response)
}
async fn generate_user_guide(&self, context: &CrateContext) -> Result<String> {
let prompt = format!(
"Generate a comprehensive user guide for a Rust crate named '{}' including installation, configuration, and usage",
context.crate_name
);
let response = self.openai_provider.chat("gpt-4", &prompt).await?;
Ok(response)
}
async fn generate_github_actions(&self, _context: &CrateContext) -> Result<String> {
let ci_config = r"name: CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
CARGO_TERM_COLOR: always
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
components: rustfmt, clippy
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.cargo
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Check formatting
run: cargo fmt --all -- --check
- name: Run clippy
run: cargo clippy -- -D warnings
- name: Run tests
run: cargo test --verbose
- name: Run benchmarks
run: cargo bench
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Build
run: cargo build --release --verbose
publish:
runs-on: ubuntu-latest
needs: [test, build]
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish --dry-run
"
.to_string();
Ok(ci_config)
}
async fn generate_dockerfile(&self, context: &CrateContext) -> Result<String> {
let dockerfile = format!(
r#"FROM rust:1.70 as builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/{} /usr/local/bin/{}
EXPOSE 8080
CMD ["{}"]
"#,
context.crate_name, context.crate_name, context.crate_name
);
Ok(dockerfile)
}
fn get_release_config(&self) -> Result<String> {
let release_config = r#"[package]
sign-commit = false
sign-tag = false
pre-release-commit-message = "Release version {{version}}"
tag-message = "Release {{version}}"
[build]
pre-release-hook = ["cargo", "check"]
"#;
Ok(release_config.to_string())
}
async fn optimize_code(&self, mut context: CrateContext) -> Result<CrateContext> {
debug!("Optimizing generated code");
context.set_metadata("optimized".to_string(), "true".to_string());
Ok(context)
}
async fn format_code(&self, mut context: CrateContext) -> Result<CrateContext> {
debug!("Formatting generated code");
context.set_metadata("formatted".to_string(), "true".to_string());
Ok(context)
}
async fn validate_final_output(&self, context: &CrateContext) -> Result<Vec<String>> {
debug!("Validating final output");
let mut issues = Vec::new();
let required_files = ["Cargo.toml", "src/lib.rs", "README.md"];
for file in required_files {
if !context.generated_files.contains_key(file) {
issues.push(format!("Missing required file: {file}"));
}
}
if let Some(cargo_content) = context.get_file_content("Cargo.toml") {
if !cargo_content.contains(&context.crate_name) {
issues.push("Cargo.toml does not contain crate name".to_string());
}
}
Ok(issues)
}
}