deepwiki-rs 1.2.7

deepwiki-rs(also known as Litho) is a high-performance automatic generation engine for C4 architecture documentation, developed using Rust. It can intelligently analyze project structures, identify core components, parse dependency relationships, and leverage large language models (LLMs) to automatically generate professional architecture documentation.
use crate::generator::compose::memory::MemoryScope;
use crate::generator::compose::types::AgentType;
use crate::generator::context::GeneratorContext;
use crate::generator::research::memory::MemoryRetriever;
use crate::generator::research::types::{
    APIBoundary, AgentType as ResearchAgentType, BoundaryAnalysisReport, CLIBoundary,
    IntegrationSuggestion, RouterBoundary,
};
use crate::generator::step_forward_agent::{
    AgentDataConfig, DataSource, PromptTemplate, StepForwardAgent,
};
use anyhow::Result;
use async_trait::async_trait;

/// Boundary Interface Documentation Editor - Orchestrates boundary analysis results into standardized documentation
#[derive(Default)]
pub struct BoundaryEditor;

#[async_trait]
impl StepForwardAgent for BoundaryEditor {
    type Output = String;

    fn agent_type(&self) -> String {
        AgentType::Boundary.to_string()
    }

    fn memory_scope_key(&self) -> String {
        MemoryScope::DOCUMENTATION.to_string()
    }

    fn should_include_timestamp(&self) -> bool {
        true
    }

    fn data_config(&self) -> AgentDataConfig {
        AgentDataConfig {
            required_sources: vec![],
            optional_sources: vec![
                DataSource::ResearchResult(ResearchAgentType::BoundaryAnalyzer.to_string()),
                DataSource::PROJECT_STRUCTURE,
                DataSource::CODE_INSIGHTS,
                DataSource::README_CONTENT,
            ],
        }
    }

    fn prompt_template(&self) -> PromptTemplate {
        PromptTemplate {
            system_prompt: r#"You are a professional software interface documentation expert, focused on generating clear, detailed boundary interface documentation. Your task is to write an interface documentation with the title `Boundary Interfaces` based on the provided research report.

## Documentation Requirements
1. **Complete Interfaces**: Describe all external interfaces in detail
2. **Clear Parameters**: Each parameter must have a clear explanation
3. **Rich Examples**: Provide practical usage examples
4. **Easy to Understand**: Provide valuable references for developers

## Output Format
- Use Markdown format
- Include appropriate heading levels
- Use code blocks to show examples
- Ensure logical and readable content"#.to_string(),

            opening_instruction: "Based on the following boundary analysis results, generate system boundary interface documentation:".to_string(),

            closing_instruction: r#"
## Documentation Requirements:
- Use standard Markdown format
- Create separate sections for each boundary type
- Include detailed parameter descriptions and usage examples
- Highlight security considerations and best practices
- Ensure clear document structure and complete content"#
                .to_string(),

            llm_call_mode: crate::generator::step_forward_agent::LLMCallMode::Prompt,
            formatter_config: crate::generator::step_forward_agent::FormatterConfig::default(),
        }
    }

    /// Custom execute implementation that generates documentation directly without using LLM
    async fn execute(&self, context: &GeneratorContext) -> Result<Self::Output> {
        // Get boundary analysis results from memory
        let boundary_analysis = context
            .get_research(&ResearchAgentType::BoundaryAnalyzer.to_string())
            .await
            .ok_or_else(|| anyhow::anyhow!("BoundaryAnalyzer result not found"))?;

        // Parse as BoundaryAnalysisReport
        let report: BoundaryAnalysisReport = serde_json::from_value(boundary_analysis)?;

        // Generate documentation content
        let content = self.generate_boundary_documentation(&report);

        // Store to memory
        let value = serde_json::to_value(&content)?;
        context
            .store_to_memory(&self.memory_scope_key(), &self.agent_type(), value)
            .await?;

        Ok(content)
    }
}

impl BoundaryEditor {
    /// Generate boundary interface documentation
    fn generate_boundary_documentation(&self, report: &BoundaryAnalysisReport) -> String {
        let mut content = String::new();
        content.push_str("# System Boundary Interface Documentation\n\n");
        content.push_str(
            "This document describes the system's external invocation interfaces, including CLI commands, API endpoints, configuration parameters, and other boundary mechanisms.\n\n",
        );

        // Generate CLI interface documentation
        if !report.cli_boundaries.is_empty() {
            content.push_str(&self.generate_cli_documentation(&report.cli_boundaries));
        }

        // Generate API interface documentation
        if !report.api_boundaries.is_empty() {
            content.push_str(&self.generate_api_documentation(&report.api_boundaries));
        }

        // Generate Router route documentation
        if !report.router_boundaries.is_empty() {
            content.push_str(&self.generate_router_documentation(&report.router_boundaries));
        }

        // Generate integration suggestions
        if !report.integration_suggestions.is_empty() {
            content.push_str(
                &self.generate_integration_documentation(&report.integration_suggestions),
            );
        }

        // Add analysis confidence score
        content.push_str(&format!(
            "\n---\n\n**Analysis Confidence**: {:.1}/10\n",
            report.confidence_score
        ));

        content
    }

    fn generate_cli_documentation(&self, cli_boundaries: &[CLIBoundary]) -> String {
        if cli_boundaries.len() == 0 {
            return String::new();
        }

        let mut content = String::new();
        content.push_str("## Command Line Interface (CLI)\n\n");

        for cli in cli_boundaries {
            content.push_str(&format!("### {}\n\n", cli.command));
            content.push_str(&format!("**Description**: {}\n\n", cli.description));
            content.push_str(&format!("**Source File**: `{}`\n\n", cli.source_location));

            if !cli.arguments.is_empty() {
                content.push_str("**Arguments**:\n\n");
                for arg in &cli.arguments {
                    let required_text = if arg.required { "required" } else { "optional" };
                    let default_text = arg
                        .default_value
                        .as_ref()
                        .map(|v| format!(" (default: `{}`)", v))
                        .unwrap_or_default();
                    content.push_str(&format!(
                        "- `{}` ({}): {} - {}{}\n",
                        arg.name, arg.value_type, required_text, arg.description, default_text
                    ));
                }
                content.push_str("\n");
            }

            if !cli.options.is_empty() {
                content.push_str("**Options**:\n\n");
                for option in &cli.options {
                    let short_text = option
                        .short_name
                        .as_ref()
                        .map(|s| format!(", {}", s))
                        .unwrap_or_default();
                    let required_text = if option.required { "required" } else { "optional" };
                    let default_text = option
                        .default_value
                        .as_ref()
                        .map(|v| format!(" (default: `{}`)", v))
                        .unwrap_or_default();
                    content.push_str(&format!(
                        "- `{}{}`({}): {} - {}{}\n",
                        option.name,
                        short_text,
                        option.value_type,
                        required_text,
                        option.description,
                        default_text
                    ));
                }
                content.push_str("\n");
            }

            if !cli.examples.is_empty() {
                content.push_str("**Usage Examples**:\n\n");
                for example in &cli.examples {
                    content.push_str(&format!("```bash\n{}\n```\n\n", example));
                }
            }
        }

        content
    }

    fn generate_api_documentation(&self, api_boundaries: &[APIBoundary]) -> String {
        if api_boundaries.len() == 0 {
            return String::new();
        }

        let mut content = String::new();
        content.push_str("## API Interfaces\n\n");

        for api in api_boundaries {
            content.push_str(&format!("### {} {}\n\n", api.method, api.endpoint));
            content.push_str(&format!("**Description**: {}\n\n", api.description));
            content.push_str(&format!("**Source File**: `{}`\n\n", api.source_location));

            if let Some(request_format) = &api.request_format {
                content.push_str(&format!("**Request Format**: {}\n\n", request_format));
            }

            if let Some(response_format) = &api.response_format {
                content.push_str(&format!("**Response Format**: {}\n\n", response_format));
            }

            if let Some(auth) = &api.authentication {
                content.push_str(&format!("**Authentication**: {}\n\n", auth));
            }
        }

        content
    }

    fn generate_router_documentation(&self, router_boundaries: &[RouterBoundary]) -> String {
        if router_boundaries.len() == 0 {
            return String::new();
        }

        let mut content = String::new();
        content.push_str("## Router Routes\n\n");

        for router in router_boundaries {
            content.push_str(&format!("### {}\n\n", router.path));
            content.push_str(&format!("**Description**: {}\n\n", router.description));
            content.push_str(&format!("**Source File**: `{}`\n\n", router.source_location));

            if !router.params.is_empty() {
                content.push_str("**Parameters**:\n\n");
                for param in &router.params {
                    content.push_str(&format!(
                        "- `{}` ({}): {}\n",
                        param.key, param.value_type, param.description
                    ));
                }
            }
        }

        content
    }

    fn generate_integration_documentation(
        &self,
        integration_suggestions: &[IntegrationSuggestion],
    ) -> String {
        if integration_suggestions.len() == 0 {
            return String::new();
        }

        let mut content = String::new();
        content.push_str("## Integration Suggestions\n\n");

        for suggestion in integration_suggestions {
            content.push_str(&format!("### {}\n\n", suggestion.integration_type));
            content.push_str(&format!("{}\n\n", suggestion.description));

            if !suggestion.example_code.is_empty() {
                content.push_str("**Example Code**:\n\n");
                content.push_str(&format!("```\n{}\n```\n\n", suggestion.example_code));
            }

            if !suggestion.best_practices.is_empty() {
                content.push_str("**Best Practices**:\n\n");
                for practice in &suggestion.best_practices {
                    content.push_str(&format!("- {}\n", practice));
                }
                content.push_str("\n");
            }
        }

        content
    }
}