Class: XAeonAgents::Agents::ReadmeGeneratorAgent
- Inherits:
-
ComposableAgents::Agent
- Object
- ComposableAgents::Agent
- XAeonAgents::Agents::ReadmeGeneratorAgent
- Includes:
- XAeonAgents::AgentDefaults
- Defined in:
- lib/x_aeon_agents/agents/readme_generator_agent.rb
Overview
Agent responsible for writing the README.md file of a project.
Instance Method Summary collapse
-
#input_artifacts_contracts ⇒ Hash{Symbol => Object}
Define input artifacts contracts.
-
#run(readme_file_path: File.expand_path('README.md'), gen_about: true, gen_quick_start: true, gen_requirements: true, gen_features: true, gen_public_api: true, gen_documentation: true, gen_how_it_works: true, gen_development: true, gen_contributing: true, gen_license: true) ⇒ Hash{Symbol => Object}
Execute the agent to generate some output artifacts based on some input artifacts.
Methods included from XAeonAgents::AgentDefaults
#new_agent, prepended, singleton_session_id
Instance Method Details
#input_artifacts_contracts ⇒ Hash{Symbol => Object}
Define input artifacts contracts
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/x_aeon_agents/agents/readme_generator_agent.rb', line 13 def input_artifacts_contracts { readme_file_path: { description: 'The full path to the README file', optional: true }, gen_about: 'The option to generate the about/header section (name, description, badges, TOC)', gen_quick_start: 'The option to generate the "Quick start" section', gen_requirements: 'The option to generate the "Requirements" section', gen_features: 'The option to generate the "Features" section', gen_public_api: 'The option to generate the "Public API" section', gen_documentation: 'The option to generate the "Documentation" section', gen_how_it_works: 'The option to generate the "How it works" section', gen_development: 'The option to generate the "Development" section', gen_contributing: 'The option to generate the "Contributing" section', gen_license: 'The option to generate the "License" section' } end |
#run(readme_file_path: File.expand_path('README.md'), gen_about: true, gen_quick_start: true, gen_requirements: true, gen_features: true, gen_public_api: true, gen_documentation: true, gen_how_it_works: true, gen_development: true, gen_contributing: true, gen_license: true) ⇒ Hash{Symbol => Object}
Execute the agent to generate some output artifacts based on some input artifacts.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/x_aeon_agents/agents/readme_generator_agent.rb', line 48 def run( readme_file_path: File.('README.md'), gen_about: true, gen_quick_start: true, gen_requirements: true, gen_features: true, gen_public_api: true, gen_documentation: true, gen_how_it_works: true, gen_development: true, gen_contributing: true, gen_license: true ) # Each section of the README has a dedicated agent who generates its content in an artifact. if gen_about about_analyzer_agent = new_agent(Readme::AboutAnalyzerAgent, **Config.['free_complex_planning']) step_agent( about_analyzer_agent, user_instructions: <<~EO_INSTRUCTIONS Analyze this project's code, features and layout. Devise the goal of this project, what problem it solves, and using which interface (CLI, library, web app...). Create an artifact named `#{about_analyzer_agent.artifact_ref(:name)}` with the name of this project. Create an artifact named `#{about_analyzer_agent.artifact_ref(:description)}` with a 1-line high-level description of this project using Markdown format, compatible with Github flavor. Create an artifact named `#{about_analyzer_agent.artifact_ref(:about)}` with an engaging high-level description/overview of this project using Markdown format, compatible with Github flavor. The description should be concise, in 1 small section and will serve as a the first paragraph of a README file. The description is intended to be for end-users and should be simple and easy to understand. Use emphasis, bullet points and small emojis to illustrate in a readable way the description. EO_INSTRUCTIONS ) end if gen_quick_start quick_start_agent = new_agent(Readme::QuickStartAgent, **Config.['free_complex_planning']) step_agent( quick_start_agent, user_instructions: <<~EO_INSTRUCTIONS Analyze this project's installation and usage patterns. Create an artifact named `#{quick_start_agent.artifact_ref(:quick_start)}` with quick installation and usage instructions using Markdown format, compatible with Github flavor. These instructions should cover the installation and basic usage of this project, with simple examples. EO_INSTRUCTIONS ) end if gen_requirements requirements_agent = new_agent(Readme::RequirementsAgent, **Config.['free_complex_planning']) step_agent( requirements_agent, user_instructions: <<~EO_INSTRUCTIONS Analyze this project's dependencies, runtime environment, and prerequisites. Create an artifact named `#{requirements_agent.artifact_ref(:requirements)}` listing all prerequisites needed to use or run the project using Markdown format, compatible with Github flavor. Those prerequisites should be given as a short list of technical points (for example OS, languages and versions, needed libraries...). Only list prerequisites that are needed by the users of the project, and not provided by the installation steps. EO_INSTRUCTIONS ) end if gen_features features_agent = new_agent(Readme::FeaturesAgent, **Config.['free_complex_planning']) step_agent( features_agent, user_instructions: <<~EO_INSTRUCTIONS Analyze this project's codebase and capabilities to identify all key features. Create an artifact named `#{features_agent.artifact_ref(:features)}` listing the main features of the project using Markdown format, compatible with Github flavor. Those features should be summarized in a simple paragraph. EO_INSTRUCTIONS ) end if gen_public_api public_api_agent = new_agent(Readme::PublicApiAgent, **Config.['free_complex_planning']) step_agent( public_api_agent, user_instructions: <<~EO_INSTRUCTIONS Analyze this project's codebase to identify all public APIs, classes, methods, and interfaces exposed to users. Create an artifact named `#{public_api_agent.artifact_ref(:public_api)}` documenting the public API surface using Markdown format, compatible with Github flavor. The public API description should only contain public entry points of the project. Those entry points can be: - Executables from the `bin` directory, if any. - Any public method (part of yard's group `Public API` only). Try to document 1 simple usecase with an example for each public API you find, without getting into details. Provide links to more complete documentation next to the usecase example so that users can refer to more details about this specific public API. Links can be (by order of preference): - Links to the RubyDoc.info documentation for a Ruby public method (for example `https://www.rubydoc.info/gems/x-aeon_agents/XAeonAgents/Agents#config-class_method`). - Links to the Github pages (for example `https://github.com/Muriel-Salvan/x_aeon_agents/blob/main/bin/xaa`). EO_INSTRUCTIONS ) end if gen_documentation documentation_agent = new_agent(Readme::DocumentationAgent, **Config.['free_complex_planning']) step_agent( documentation_agent, user_instructions: <<~EO_INSTRUCTIONS Explore this project's documentation files and resources to identify all available documentation. Create an artifact named `#{documentation_agent.artifact_ref(:documentation)}` providing links to documentation resources using Markdown format, compatible with Github flavor. Links can be: - Link to the RubyDoc.info documentation for a Ruby public method (for example `https://www.rubydoc.info/gems/x_aeon_agents`). - Link to the main Github page (for example `https://github.com/Muriel-Salvan/x_aeon_agents`). EO_INSTRUCTIONS ) end if gen_how_it_works how_it_works_agent = new_agent(Readme::HowItWorksAgent, **Config.['free_complex_planning']) step_agent( how_it_works_agent, user_instructions: <<~EO_INSTRUCTIONS Analyze this project's architecture, design patterns, and internal workings. Create an artifact named `#{how_it_works_agent.artifact_ref(:how_it_works)}` explaining the internal architecture and working principles using Markdown format, compatible with Github flavor. This should be summarized as a small section, not an architecture document. EO_INSTRUCTIONS ) end if gen_development development_agent = new_agent(Readme::DevelopmentAgent, **Config.['free_complex_planning']) step_agent( development_agent, user_instructions: <<~EO_INSTRUCTIONS Analyze this project's development setup, build system, testing framework, and development workflows. Create an artifact named `#{development_agent.artifact_ref(:development)}` explaining how to set up a development environment to code for this project using Markdown format, compatible with Github flavor. EO_INSTRUCTIONS ) end if gen_contributing contributing_agent = new_agent(Readme::ContributingAgent, **Config.['free_complex_planning']) step_agent( contributing_agent, user_instructions: <<~EO_INSTRUCTIONS Analyze this project's CONTRIBUTING guidelines, issue templates, pull request templates, and any community guidelines. Create an artifact named `#{contributing_agent.artifact_ref(:contributing)}` explaining how users can contribute to the project using Markdown format, compatible with Github flavor. This should be done in 1 paragraph showing how to install or setup test dependencies and how to run tests, as a whole or individually. Use simple examples to illustrate it. EO_INSTRUCTIONS ) end if gen_license license_agent = new_agent(Readme::LicenseAgent, **Config.['free_complex_planning']) step_agent( license_agent, user_instructions: <<~EO_INSTRUCTIONS Analyze this project's LICENSE file to identify the license type and terms. Create an artifact named `#{license_agent.artifact_ref(:license)}` describing the project license using Markdown format, compatible with Github flavor. If there is already a LICENSE file in this project, just provide a link to this license file. EO_INSTRUCTIONS ) end # Assemble README.md from all section artifacts step(:assemble_readme) do sections = File.exist?(readme_file_path) ? parse_sections(File.read(readme_file_path)) : [] header_content = nil # We expect the first 2 sections to be of level 0 or 1, and they both correspond to the about top section. # Treat them as a header if that's the case. 2.times do if !sections.empty? && sections.first[:level] < 2 section = sections.shift header_content = ([header_content] + [section[:body]]).compact.join("\n\n") end end # Remove the eventual Table of contents section as we will always regenerate it. sections.delete_if { |section| section[:title] == 'Table of contents' } # Replace or insert sections in the order they are expected if gen_about header_content = <<~EO_HEADER.strip <div align="center"> # #{@artifacts[:name]} #{@artifacts[:description]} #{build_badges.join("\n")} </div> #{ComposableAgents::Utils::Markdown.align_markdown_headers(@artifacts[:about], level: 3).strip} EO_HEADER end ordered_sections = [ ['Quick start', :quick_start], ['Requirements', :requirements], ['Features', :features], ['Public API', :public_api], ['Documentation', :documentation], ['How it works', :how_it_works], ['Development', :development], ['Contributing', :contributing], ['License', :license] ] ordered_sections.each.with_index do |(section_title, art_name), idx_section| next unless @artifacts[art_name] content = <<~EO_CONTENT.strip ## #{section_title} #{ComposableAgents::Utils::Markdown.align_markdown_headers(strip_grouping_header(@artifacts[art_name]), level: 3).strip} EO_CONTENT # Find the section of this title if any existing_idx = sections.index { |section| section[:title] == section_title } if existing_idx sections[existing_idx][:body] = content else # Look for the first previous section. # The we insert our section just after. found_previous_section_index = nil previous_section_index = idx_section - 1 while found_previous_section_index.nil? if previous_section_index == -1 # We didn't find any previous section. # Insert it at the top. found_previous_section_index = -1 else previous_section_title = ordered_sections[previous_section_index][0] found_previous_section_index = sections.index { |section| section[:title] == previous_section_title } end previous_section_index -= 1 end # Insert just after found_previous_section_index sections.insert( found_previous_section_index + 1, { level: 2, title: section_title, body: content } ) end end sections_content = sections.map { |section| section[:body] }.join("\n\n").strip File.write( readme_file_path, <<~EO_README #{header_content} ## Table of contents #{generate_table_of_contents(sections_content).strip} #{sections_content} EO_README ) end puts "#{readme_file_path} has been generated successfully." @artifacts end |