x_aeon_agents 1.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/AGENTS.md +136 -0
- data/CHANGELOG.md +398 -0
- data/README.md +579 -0
- data/TODO.md +48 -0
- data/bin/xaa +5 -0
- data/lib/x_aeon_agents/agent_defaults.rb +60 -0
- data/lib/x_aeon_agents/agent_options.rb +58 -0
- data/lib/x_aeon_agents/agents/coder_agent.rb +82 -0
- data/lib/x_aeon_agents/agents/committer_agent.rb +71 -0
- data/lib/x_aeon_agents/agents/developer_agent.rb +235 -0
- data/lib/x_aeon_agents/agents/diff_interpreter_agent.rb +80 -0
- data/lib/x_aeon_agents/agents/documenter_agent.rb +44 -0
- data/lib/x_aeon_agents/agents/executor_agent.rb +9 -0
- data/lib/x_aeon_agents/agents/feedback_analyst_agent.rb +62 -0
- data/lib/x_aeon_agents/agents/gh_comments.gql +64 -0
- data/lib/x_aeon_agents/agents/git_diff_interpreter_agent.rb +57 -0
- data/lib/x_aeon_agents/agents/issue_implementer_agent.rb +88 -0
- data/lib/x_aeon_agents/agents/one_line_code_diff_summarizer_agent.rb +57 -0
- data/lib/x_aeon_agents/agents/plan_generator_agent.rb +51 -0
- data/lib/x_aeon_agents/agents/planner_agent.rb +89 -0
- data/lib/x_aeon_agents/agents/pull_request_creator_agent.rb +144 -0
- data/lib/x_aeon_agents/agents/readme/about_analyzer_agent.rb +55 -0
- data/lib/x_aeon_agents/agents/readme/contributing_agent.rb +47 -0
- data/lib/x_aeon_agents/agents/readme/development_agent.rb +54 -0
- data/lib/x_aeon_agents/agents/readme/documentation_agent.rb +43 -0
- data/lib/x_aeon_agents/agents/readme/features_agent.rb +45 -0
- data/lib/x_aeon_agents/agents/readme/how_it_works_agent.rb +47 -0
- data/lib/x_aeon_agents/agents/readme/license_agent.rb +43 -0
- data/lib/x_aeon_agents/agents/readme/public_api_agent.rb +44 -0
- data/lib/x_aeon_agents/agents/readme/quick_start_agent.rb +50 -0
- data/lib/x_aeon_agents/agents/readme/requirements_agent.rb +43 -0
- data/lib/x_aeon_agents/agents/readme_generator_agent.rb +438 -0
- data/lib/x_aeon_agents/agents/review_resolver_agent.rb +236 -0
- data/lib/x_aeon_agents/agents/review_responder_agent.rb +64 -0
- data/lib/x_aeon_agents/agents/skill_generator_agent.rb +95 -0
- data/lib/x_aeon_agents/agents/skill_installer_agent.rb +103 -0
- data/lib/x_aeon_agents/agents/task_starter_agent.rb +66 -0
- data/lib/x_aeon_agents/agents/tester_agent.rb +44 -0
- data/lib/x_aeon_agents/cli.rb +384 -0
- data/lib/x_aeon_agents/config.rb +110 -0
- data/lib/x_aeon_agents/gen_helpers.rb +270 -0
- data/lib/x_aeon_agents/helpers.rb +211 -0
- data/lib/x_aeon_agents/logger.rb +21 -0
- data/lib/x_aeon_agents/providers/cline.rb +78 -0
- data/lib/x_aeon_agents/version.rb +6 -0
- data/lib/x_aeon_agents.rb +38 -0
- metadata +296 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module XAeonAgents
|
|
2
|
+
# Mixin setting up default settings for agents.
|
|
3
|
+
# This mixin is meant to be the last prepended mixin in all Agent classes.
|
|
4
|
+
module AgentDefaults
|
|
5
|
+
class << self
|
|
6
|
+
# Get the singleton session ID.
|
|
7
|
+
# If it is the first time it is invoked, use a default session ID.
|
|
8
|
+
def singleton_session_id
|
|
9
|
+
@singleton_session_id ||= Time.now.utc.strftime('%Y-%m-%d-%H-%M-%S-%N')
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Instantiate a new agent.
|
|
14
|
+
# Transfer the same session to the new agent.
|
|
15
|
+
#
|
|
16
|
+
# @param agent_class [Class] The agent class to be instantiated
|
|
17
|
+
# @param args [Array] Constructor parameters
|
|
18
|
+
# @param kwargs [Hash] Constructor kwargs
|
|
19
|
+
# @return [ComposableAgents::Agent] The new agent
|
|
20
|
+
def new_agent(agent_class, *args, **kwargs)
|
|
21
|
+
agent_class.new(*args, session_id: @session_id, **kwargs)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Hook called when this mixin is prepended in a class
|
|
25
|
+
#
|
|
26
|
+
# @param base [Class] The base class prepending this mixin
|
|
27
|
+
def self.prepended(base)
|
|
28
|
+
base.prepend ComposableAgents::Mixins::ArtifactContract unless base.ancestors.include?(ComposableAgents::Mixins::ArtifactContract)
|
|
29
|
+
base.prepend ComposableAgents::Mixins::Resumable unless base.ancestors.include?(ComposableAgents::Mixins::Resumable)
|
|
30
|
+
# Make sure we always prepend at the top our initializer that sets all defaults
|
|
31
|
+
base.prepend(
|
|
32
|
+
Module.new do
|
|
33
|
+
# Constructor
|
|
34
|
+
#
|
|
35
|
+
# @param args [Array] Agent's constructor arguments
|
|
36
|
+
# @param session_id [String, nil] Specific X-Aeon session id to be used, or nil if none
|
|
37
|
+
# @param kwargs [Array] Agent's constructor kwargs
|
|
38
|
+
def initialize(*args, session_id: nil, **kwargs)
|
|
39
|
+
# If we inherit from some frameworks initialize them now.
|
|
40
|
+
Config.setup_composable_agents
|
|
41
|
+
case self
|
|
42
|
+
when ComposableAgents::AiAgents::Agent
|
|
43
|
+
Config.setup_ai_agents
|
|
44
|
+
when ComposableAgents::Cline::Agent
|
|
45
|
+
Config.setup_cline
|
|
46
|
+
end
|
|
47
|
+
@session_id = session_id || AgentDefaults.singleton_session_id
|
|
48
|
+
@session_dir = "#{Config.data_dir}/sessions/#{@session_id}"
|
|
49
|
+
super(
|
|
50
|
+
*args,
|
|
51
|
+
composable_agents_dir: "#{@session_dir}/composable_agents",
|
|
52
|
+
run_id: "#{@session_id}-#{kwargs[:name] || self.class.name.split('::').last}",
|
|
53
|
+
**kwargs
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module XAeonAgents
|
|
2
|
+
# Provide agent options for different agent categories
|
|
3
|
+
class AgentOptions
|
|
4
|
+
# @!group Public API
|
|
5
|
+
|
|
6
|
+
# Get an agent's option for a given agent category.
|
|
7
|
+
# Those options can be given directly to the agent's constructor to tune it for the desired category.
|
|
8
|
+
#
|
|
9
|
+
# @param agent_category [String] The agent category for which we want the agent's options
|
|
10
|
+
# @return [Hash{Symbol => Object}, nil] The corresponding agent's options, or nil if none
|
|
11
|
+
def [](agent_category)
|
|
12
|
+
# Lazy-evaluate it if needed
|
|
13
|
+
options[agent_category] = options[agent_category].call if options[agent_category].is_a?(Proc)
|
|
14
|
+
options[agent_category]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Set an agent's option for a given agent category.
|
|
18
|
+
#
|
|
19
|
+
# @param agent_category [String] The agent category for which we want the agent's options
|
|
20
|
+
# @param agent_options [Hash{Symbol => Object}, #call -> Hash] The corresponding agent's options (can be lazily evaluated)
|
|
21
|
+
def []=(agent_category, agent_options)
|
|
22
|
+
options[agent_category] = agent_options
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# @return [Hash{String => Hash{Symbol => Object}, #call -> Hash}] The memoized options (can be lazily evaluated), per agent category.
|
|
28
|
+
def options
|
|
29
|
+
@options ||= {
|
|
30
|
+
'free_simple' => {
|
|
31
|
+
model: 'openrouter/free',
|
|
32
|
+
strategy: ComposableAgents::PromptRenderingStrategy::Markdown
|
|
33
|
+
},
|
|
34
|
+
'free_complex' => proc do
|
|
35
|
+
{
|
|
36
|
+
model: 'tencent/hy3:free',
|
|
37
|
+
api_key: Config.cline_api_key,
|
|
38
|
+
cli_options: Config.default_cline_cli_args
|
|
39
|
+
}
|
|
40
|
+
end,
|
|
41
|
+
'free_complex_planning' => proc do
|
|
42
|
+
{
|
|
43
|
+
model: 'tencent/hy3:free',
|
|
44
|
+
api_key: Config.cline_api_key,
|
|
45
|
+
cli_options: Config.default_cline_cli_args.merge(
|
|
46
|
+
{
|
|
47
|
+
plan: true
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
configure_global: proc do |global_settings|
|
|
51
|
+
global_settings.disabled_tools = %w[editor run_commands]
|
|
52
|
+
end
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module XAeonAgents
|
|
2
|
+
# Collection of agents that can be used
|
|
3
|
+
module Agents
|
|
4
|
+
# Agent responsible for implementing tasks following an implementation plan
|
|
5
|
+
class CoderAgent < ComposableAgents::Cline::Agent
|
|
6
|
+
prepend AgentDefaults
|
|
7
|
+
|
|
8
|
+
# Define input artifacts contracts
|
|
9
|
+
#
|
|
10
|
+
# @return [Hash{Symbol => Object}] Set of input artifacts description, per artifact name
|
|
11
|
+
def input_artifacts_contracts
|
|
12
|
+
super.merge(plan: 'The implementation plan that you must follow')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Constructor
|
|
16
|
+
#
|
|
17
|
+
# @param agent_params [Hash{Symbol => Object}] Extra agent parameters
|
|
18
|
+
def initialize(**agent_params)
|
|
19
|
+
super(
|
|
20
|
+
name: 'Coder',
|
|
21
|
+
role: 'You are a Coder agent',
|
|
22
|
+
objective: <<~EO_OBJECTIVE,
|
|
23
|
+
Your primary goal is to assist users with various coding tasks by leveraging your knowledge and the tools at your disposal.
|
|
24
|
+
Given the user's prompt, you should use the tools available to you to answer user's question.
|
|
25
|
+
EO_OBJECTIVE
|
|
26
|
+
system_instructions: <<~EO_INSTRUCTIONS,
|
|
27
|
+
Always gather all the necessary context before starting to work on a task.
|
|
28
|
+
For example, if you are generating a unit test or new code, make sure you understand the requirement, the naming conventions, frameworks and libraries used and aligned in the current codebase, and the environment and commands used to run and test the code etc.
|
|
29
|
+
Always validate the new unit test at the end including running the code if possible for live feedback.
|
|
30
|
+
|
|
31
|
+
Begin by analyzing the user's input and gathering any necessary additional context.
|
|
32
|
+
Then, present your plan at the start of your response along with tool calls before proceeding with the task.
|
|
33
|
+
It's OK for this section to be quite long.
|
|
34
|
+
|
|
35
|
+
Review each question carefully and answer it with detailed, accurate information.
|
|
36
|
+
|
|
37
|
+
If you need more information, use one of the available tools or ask for clarification instead of making assumptions or lies.
|
|
38
|
+
|
|
39
|
+
When you have completed the task, please provide a summary of what you did and any relevant information that the user should know.
|
|
40
|
+
This will help ensure that the user understands the changes made and can easily follow up if they have any questions or need further assistance.
|
|
41
|
+
EO_INSTRUCTIONS
|
|
42
|
+
constraints: <<~EO_CONSTRAINTS,
|
|
43
|
+
Remember:
|
|
44
|
+
- Always adhere to existing code conventions and patterns.
|
|
45
|
+
- Use only libraries and frameworks that are confirmed to be in use in the current codebase.
|
|
46
|
+
- Provide complete and functional code without omissions or placeholders.
|
|
47
|
+
- Be explicit about any assumptions or limitations in your solution.
|
|
48
|
+
- Always show your planning process before executing any task.
|
|
49
|
+
This will help ensure that you have a clear understanding of the requirements and that your approach aligns with the user's needs.
|
|
50
|
+
- Always use absolute paths when referring to files.
|
|
51
|
+
- You can call multiple tools in a single response.
|
|
52
|
+
Before using tools, identify every independent read, search, command, or edit needed for the next step and emit all of those tool calls now, either as multiple tool calls or as one batched input for tools that accept arrays.
|
|
53
|
+
Do not wait for one independent result before requesting another.
|
|
54
|
+
Do not split independent reads, searches, checks, or edits across separate turns.
|
|
55
|
+
- Good parallelism examples: read all known relevant files in one read_files call;
|
|
56
|
+
run independent inspection commands in one run_commands call;
|
|
57
|
+
emit independent read_files, search_codebase, and run_commands calls together in one response;
|
|
58
|
+
emit multiple editor calls together when editing different files or non-overlapping regions.
|
|
59
|
+
- Always verify the files you have edited or created at the end of the task to ensure they are completed and working as expected.
|
|
60
|
+
|
|
61
|
+
REMEMBER, be helpful and proactive!
|
|
62
|
+
Don't ask for permission to do something when you can do it!
|
|
63
|
+
Do not indicates you will be using a tool unless you are actually going to use it.
|
|
64
|
+
|
|
65
|
+
IMPORTANT: Always includes tool calls in your response until the task is completed.
|
|
66
|
+
Response without tool calls will be considered as completed with the final answer.
|
|
67
|
+
|
|
68
|
+
Do not indicate that you will perform an action without actually doing it.
|
|
69
|
+
Always provide the final result in your response.
|
|
70
|
+
Always validate your answer with checking the code and running it if possible.
|
|
71
|
+
EO_CONSTRAINTS
|
|
72
|
+
skills: %w[
|
|
73
|
+
applying-ruby-conventions
|
|
74
|
+
applying-test-conventions
|
|
75
|
+
enforcing-project-rules
|
|
76
|
+
],
|
|
77
|
+
**agent_params
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module XAeonAgents
|
|
2
|
+
module Agents
|
|
3
|
+
# Agent responsible for git committing locally staged or modified files
|
|
4
|
+
class CommitterAgent < ComposableAgents::Agent
|
|
5
|
+
prepend AgentDefaults
|
|
6
|
+
|
|
7
|
+
# Constructor
|
|
8
|
+
#
|
|
9
|
+
# @param user_review [Boolean] Should the agent ask for user's git comment review?
|
|
10
|
+
# @param stage [Symbol] Apply different staging strategies:
|
|
11
|
+
# - `all`: Always stage all files
|
|
12
|
+
# - `if_empty`: Stage all files only if the staging aread is empty
|
|
13
|
+
# - `none`: Don't stage anything
|
|
14
|
+
# @param authors [Array<Agent>] List of agents that should be credited as authors of this commit
|
|
15
|
+
# @param agent_params [Hash{Symbol => Object}] Extra agent parameters
|
|
16
|
+
def initialize(user_review: true, stage: :if_empty, authors: [], **agent_params)
|
|
17
|
+
super(name: 'Committer', **agent_params)
|
|
18
|
+
@user_review = user_review
|
|
19
|
+
@stage = stage
|
|
20
|
+
@authors = authors
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Execute the agent to generate some output artifacts based on some input artifacts.
|
|
24
|
+
#
|
|
25
|
+
# @return [Hash{Symbol => Object}] Output artifacts content
|
|
26
|
+
def run
|
|
27
|
+
case @stage
|
|
28
|
+
when :all
|
|
29
|
+
Helpers.git.add(all: true)
|
|
30
|
+
when :if_empty
|
|
31
|
+
Helpers.git.add(all: true) if Helpers.git_diff_cached.empty?
|
|
32
|
+
when :none
|
|
33
|
+
# Do nothing
|
|
34
|
+
else
|
|
35
|
+
raise "Unknown staging strategy: #{@stage}"
|
|
36
|
+
end
|
|
37
|
+
if Helpers.git_diff_cached.empty?
|
|
38
|
+
log_debug 'Nothing to commit'
|
|
39
|
+
else
|
|
40
|
+
git_diff_interpreter_agent = GitDiffInterpreterAgent.new
|
|
41
|
+
git_diff_interpreter_agent_output = git_diff_interpreter_agent.run(git_ref_base: 'cached')
|
|
42
|
+
content = <<~EO_COMMIT
|
|
43
|
+
#{git_diff_interpreter_agent_output[:one_line_summary].strip}
|
|
44
|
+
|
|
45
|
+
#{git_diff_interpreter_agent_output[:change_intent].strip}
|
|
46
|
+
|
|
47
|
+
Co-authored by X-Aeon AI Agents:
|
|
48
|
+
#{
|
|
49
|
+
(@authors + [git_diff_interpreter_agent.diff_interpreter_agent]).map do |agent|
|
|
50
|
+
"* #{agent.full_name}"
|
|
51
|
+
end.join("\n")
|
|
52
|
+
}
|
|
53
|
+
EO_COMMIT
|
|
54
|
+
if @user_review
|
|
55
|
+
content, _user_prompt = Helpers.review_content(
|
|
56
|
+
name: 'commit.md',
|
|
57
|
+
description: 'Git commit comment',
|
|
58
|
+
editable: true,
|
|
59
|
+
content:
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
Helpers.git.commit(content)
|
|
63
|
+
|
|
64
|
+
puts
|
|
65
|
+
puts 'Commit created successfully.'
|
|
66
|
+
end
|
|
67
|
+
{}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
require 'diffy'
|
|
2
|
+
|
|
3
|
+
module XAeonAgents
|
|
4
|
+
module Agents
|
|
5
|
+
# Agent responsible for developing some requirements
|
|
6
|
+
class DeveloperAgent < ComposableAgents::Agent
|
|
7
|
+
prepend AgentDefaults
|
|
8
|
+
|
|
9
|
+
# Define input artifacts contracts
|
|
10
|
+
#
|
|
11
|
+
# @return [Hash{Symbol => Object}] Set of input artifacts description, per artifact name
|
|
12
|
+
def input_artifacts_contracts
|
|
13
|
+
{ requirements: 'The initial requirements that need to be implemented' }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Constructor
|
|
17
|
+
#
|
|
18
|
+
# @param commit [Boolean] Should we commit files at every step?
|
|
19
|
+
# @param pull_request [Boolean] Should we create a Github Pull Request with this implementation?
|
|
20
|
+
# @param agent_params [Hash{Symbol => Object}] Extra agent parameters
|
|
21
|
+
def initialize(commit: false, pull_request: false, **agent_params)
|
|
22
|
+
super(name: 'Developer', **agent_params)
|
|
23
|
+
@commit = commit
|
|
24
|
+
@pull_request = pull_request
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Execute the agent to generate some output artifacts based on some input artifacts.
|
|
28
|
+
#
|
|
29
|
+
# @param requirements [String] Requirements to be implemented
|
|
30
|
+
# @return [Hash{Symbol => Object}] Output artifacts content
|
|
31
|
+
def run(requirements:)
|
|
32
|
+
# Initial artifacts
|
|
33
|
+
step(:setup_requirements) do
|
|
34
|
+
@artifacts.merge!(
|
|
35
|
+
requirements:,
|
|
36
|
+
base_sha: Helpers.git.gcommit('HEAD').sha
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
planner_agent = new_agent(PlannerAgent)
|
|
41
|
+
step_agent(planner_agent)
|
|
42
|
+
|
|
43
|
+
coder_agent = new_agent(CoderAgent, **Config.agent_options['free_complex'])
|
|
44
|
+
|
|
45
|
+
step_agent(
|
|
46
|
+
coder_agent,
|
|
47
|
+
user_instructions: "Follow all the steps of the implementation plan described in the artifact named `#{coder_agent.artifact_ref(:plan)}`."
|
|
48
|
+
)
|
|
49
|
+
puts "===== Coder changes: #{Helpers.git.status.changed.keys.join(', ')}"
|
|
50
|
+
|
|
51
|
+
step_agent(new_agent(CommitterAgent, user_review: false, stage: :all, authors: [coder_agent])) if @commit
|
|
52
|
+
|
|
53
|
+
tester_agent = new_agent(TesterAgent, **Config.agent_options['free_complex'])
|
|
54
|
+
|
|
55
|
+
step(:test) do
|
|
56
|
+
tests_cmd = 'bundle exec rspec --format documentation'
|
|
57
|
+
@artifacts[:tests_cmd] = tests_cmd
|
|
58
|
+
idx_test = 0
|
|
59
|
+
loop do
|
|
60
|
+
puts
|
|
61
|
+
puts "===== Run tests ##{idx_test}..."
|
|
62
|
+
test_result = Helpers.run_cmd(tests_cmd, expected_exit_status: nil)
|
|
63
|
+
puts "Tests ##{idx_test} exit status: #{test_result[:exit_status]}"
|
|
64
|
+
@artifacts[:tests_output] = <<~EO_ARTIFACT
|
|
65
|
+
```
|
|
66
|
+
#{test_result[:stdout]}
|
|
67
|
+
```
|
|
68
|
+
EO_ARTIFACT
|
|
69
|
+
break if test_result[:exit_status].zero?
|
|
70
|
+
|
|
71
|
+
@artifacts[:files_diffs] = Helpers.artifact_files_diffs(@artifacts[:base_sha])
|
|
72
|
+
step_agent(
|
|
73
|
+
tester_agent,
|
|
74
|
+
user_instructions: {
|
|
75
|
+
ordered_list: [
|
|
76
|
+
<<~EO_STEP,
|
|
77
|
+
Understand the initial requirements from the artifact named `#{tester_agent.artifact_ref(:requirements)}`
|
|
78
|
+
|
|
79
|
+
- Understand those requirements and their intent.
|
|
80
|
+
EO_STEP
|
|
81
|
+
<<~EO_STEP,
|
|
82
|
+
Understand the implementation plan from the artifact named `#{tester_agent.artifact_ref(:plan)}`
|
|
83
|
+
|
|
84
|
+
- Understand all the steps of the implementation plan.
|
|
85
|
+
EO_STEP
|
|
86
|
+
<<~EO_STEP,
|
|
87
|
+
Understand the file changes from the artifact named `#{tester_agent.artifact_ref(:files_diffs)}`
|
|
88
|
+
|
|
89
|
+
- Understand what was the intent of the developer implementing the requirements.
|
|
90
|
+
EO_STEP
|
|
91
|
+
<<~EO_STEP,
|
|
92
|
+
Analyze the full output of unit tests run from the artifact named `#{tester_agent.artifact_ref(:tests_output)}`
|
|
93
|
+
|
|
94
|
+
- Check every error reported in the output.
|
|
95
|
+
EO_STEP
|
|
96
|
+
'Fix any issue that unit tests are surfacing, while keeping the original intent of the requirements',
|
|
97
|
+
'Remember any inconsistency and modification you need to make to the implementation plan ' \
|
|
98
|
+
'so that your fixes are in-line with a better implementation plan',
|
|
99
|
+
<<~EO_STEP
|
|
100
|
+
Make sure all tests are running without issue after your fixes
|
|
101
|
+
|
|
102
|
+
- You can run tests again using the provided tests command from the artifact named `#{tester_agent.artifact_ref(:tests_cmd)}` to test your own fixes.
|
|
103
|
+
EO_STEP
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
puts "===== Tester changes: #{Helpers.git.status.changed.keys.join(', ')}"
|
|
108
|
+
# Integrate potential implementation plan modifications
|
|
109
|
+
unless @artifacts[:plan_modifications].strip.empty?
|
|
110
|
+
plan_modifications = @artifacts.delete(:plan_modifications)
|
|
111
|
+
@artifacts[:plan] = <<~EO_PLAN
|
|
112
|
+
#{@artifacts[:plan].strip}
|
|
113
|
+
|
|
114
|
+
# Revision ##{idx_test} to the implementation plan
|
|
115
|
+
|
|
116
|
+
#{ComposableAgents::Utils::Markdown.align_markdown_headers(plan_modifications, level: 2)}
|
|
117
|
+
|
|
118
|
+
EO_PLAN
|
|
119
|
+
end
|
|
120
|
+
step_agent(new_agent(CommitterAgent, user_review: false, stage: :all, authors: [tester_agent])) if @commit
|
|
121
|
+
idx_test += 1
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
step_agent(new_agent(CommitterAgent, user_review: false, stage: :all, authors: [tester_agent])) if @commit
|
|
126
|
+
|
|
127
|
+
documenter_agent = new_agent(DocumenterAgent, **Config.agent_options['free_complex'])
|
|
128
|
+
@artifacts[:files_diffs] = Helpers.artifact_files_diffs(@artifacts[:base_sha])
|
|
129
|
+
|
|
130
|
+
step_agent(
|
|
131
|
+
documenter_agent,
|
|
132
|
+
user_instructions: {
|
|
133
|
+
ordered_list: [
|
|
134
|
+
<<~EO_STEP,
|
|
135
|
+
Analyze the initial requirements from the artifact named `#{documenter_agent.artifact_ref(:requirements)}`
|
|
136
|
+
|
|
137
|
+
- Those give you information about the requirements you should be documenting.
|
|
138
|
+
EO_STEP
|
|
139
|
+
<<~EO_STEP,
|
|
140
|
+
Analyze all the steps of the implementation plan from the artifact named `#{documenter_agent.artifact_ref(:plan)}`
|
|
141
|
+
|
|
142
|
+
- Those give you every step that should have been followed for this new development.
|
|
143
|
+
EO_STEP
|
|
144
|
+
<<~EO_STEP,
|
|
145
|
+
Analyze the concrete changes from the artifact named `#{documenter_agent.artifact_ref(:files_diffs)}`
|
|
146
|
+
|
|
147
|
+
- Understand what was the intent of the developer implementing those requirements.
|
|
148
|
+
EO_STEP
|
|
149
|
+
<<~EO_STEP,
|
|
150
|
+
Decide if documentation is needed
|
|
151
|
+
|
|
152
|
+
Before making any change, classify the development:
|
|
153
|
+
|
|
154
|
+
- If the change affects:
|
|
155
|
+
- Features
|
|
156
|
+
- Usage
|
|
157
|
+
- APIs
|
|
158
|
+
- Behavior visible to users
|
|
159
|
+
→ Documentation update MAY be required
|
|
160
|
+
|
|
161
|
+
- If the change is:
|
|
162
|
+
- Internal refactor
|
|
163
|
+
- Cleanup (removal of useless content)
|
|
164
|
+
- Formatting
|
|
165
|
+
- Documentation-only removal of irrelevant info
|
|
166
|
+
→ NO documentation update is required
|
|
167
|
+
|
|
168
|
+
If no documentation is required:
|
|
169
|
+
→ STOP and do nothing
|
|
170
|
+
EO_STEP
|
|
171
|
+
<<~EO_STEP,
|
|
172
|
+
Explore the filesystem to locate documentation files
|
|
173
|
+
|
|
174
|
+
Guidelines:
|
|
175
|
+
- Start with README.md and docs/**/*.md if they exist.
|
|
176
|
+
- Look for files mentioning related features or APIs.
|
|
177
|
+
- Find documentation files that are referenced recursively from other documentation files.
|
|
178
|
+
- Understand the documentation structure and content.
|
|
179
|
+
- If no relevant documentation is found, proceed by assuming documentation needs to be created or extended.
|
|
180
|
+
- If you are unsure which documentation file to update: default to updating README.md.
|
|
181
|
+
|
|
182
|
+
This step is best-effort and should not block progress.
|
|
183
|
+
EO_STEP
|
|
184
|
+
<<~EO_STEP
|
|
185
|
+
Update the relevant documentation files
|
|
186
|
+
|
|
187
|
+
- Only perform this step if you think documentation is required.
|
|
188
|
+
- Use artifacts as the source of truth for understanding the changes to be documented.
|
|
189
|
+
- Use the filesystem to locate where documentation should be updated.
|
|
190
|
+
- After exploring the filesystem, if relevant documentation files are found: update them.
|
|
191
|
+
|
|
192
|
+
When updating documentation:
|
|
193
|
+
- Modify existing sections if they already describe related functionality.
|
|
194
|
+
- Add new sections if the feature is not documented.
|
|
195
|
+
- Keep consistency with existing documentation style.
|
|
196
|
+
- Prefer minimal, precise updates over large rewrites.
|
|
197
|
+
EO_STEP
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
puts "===== Documenter changes: #{Helpers.git.status.changed.keys.join(', ')}"
|
|
202
|
+
|
|
203
|
+
if @commit || @pull_request
|
|
204
|
+
step_agent(
|
|
205
|
+
new_agent(
|
|
206
|
+
CommitterAgent,
|
|
207
|
+
user_review: false,
|
|
208
|
+
stage: :all,
|
|
209
|
+
authors: (@commit ? [] : [coder_agent, tester_agent]) + [documenter_agent]
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
if @pull_request
|
|
215
|
+
step_agent(
|
|
216
|
+
new_agent(
|
|
217
|
+
PullRequestCreatorAgent,
|
|
218
|
+
authors: [
|
|
219
|
+
planner_agent.plan_generator_agent,
|
|
220
|
+
coder_agent,
|
|
221
|
+
tester_agent,
|
|
222
|
+
documenter_agent
|
|
223
|
+
]
|
|
224
|
+
)
|
|
225
|
+
)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
puts
|
|
229
|
+
puts 'Requirements implemented successfully'
|
|
230
|
+
|
|
231
|
+
@artifacts
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module XAeonAgents
|
|
2
|
+
module Agents
|
|
3
|
+
# Agent responsible for analyzing files differences in a repository
|
|
4
|
+
class DiffInterpreterAgent < ComposableAgents::AiAgents::Agent
|
|
5
|
+
prepend AgentDefaults
|
|
6
|
+
|
|
7
|
+
# Define input artifacts contracts
|
|
8
|
+
#
|
|
9
|
+
# @return [Hash{Symbol => Object}] Set of input artifacts description, per artifact name
|
|
10
|
+
def input_artifacts_contracts
|
|
11
|
+
super.merge(files_diff: 'The full list of files changes and differences that have been done')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Define output artifacts contracts
|
|
15
|
+
#
|
|
16
|
+
# @return [Hash{Symbol => Object}] Set of output artifacts description, per artifact name
|
|
17
|
+
def output_artifacts_contracts
|
|
18
|
+
super.merge(
|
|
19
|
+
change_intent: {
|
|
20
|
+
description: 'The full explanation of the changes, as in a git commit description',
|
|
21
|
+
type: :text
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Constructor
|
|
27
|
+
#
|
|
28
|
+
# @param agent_params [Hash{Symbol => Object}] Extra agent parameters
|
|
29
|
+
def initialize(**agent_params)
|
|
30
|
+
super(
|
|
31
|
+
name: 'Diff interpreter',
|
|
32
|
+
role: 'You are a files diff interpreter agent',
|
|
33
|
+
objective: <<~EO_OBJECTIVE,
|
|
34
|
+
Interpret files modifications and explain the changes properly with its meaning and intent.
|
|
35
|
+
|
|
36
|
+
The goals are:
|
|
37
|
+
- Get a general explanation of those changes.
|
|
38
|
+
- Identify the kind of changes involved (new features, feature change, bug fix, documentation...).
|
|
39
|
+
- Identify the components that are impacted by those changes (a specific plugin, CLI, UI...).
|
|
40
|
+
EO_OBJECTIVE
|
|
41
|
+
**agent_params
|
|
42
|
+
)
|
|
43
|
+
self.system_instructions = {
|
|
44
|
+
ordered_list: [
|
|
45
|
+
<<~EO_INSTRUCTIONS,
|
|
46
|
+
Read and analyze ALL file changes from the artifact named `#{artifact_ref(:files_diff)}`
|
|
47
|
+
|
|
48
|
+
- Those changes are the ones you must explain.
|
|
49
|
+
EO_INSTRUCTIONS
|
|
50
|
+
<<~EO_INSTRUCTIONS,
|
|
51
|
+
Analyze the project files
|
|
52
|
+
|
|
53
|
+
- Those files give you context to understand the changes.
|
|
54
|
+
- Changes made on those files should NOT be explained unless they are part of the artifact named `#{artifact_ref(:files_diff)}`.
|
|
55
|
+
EO_INSTRUCTIONS
|
|
56
|
+
<<~EO_INSTRUCTIONS
|
|
57
|
+
Create an artifact named `#{artifact_ref(:change_intent)}` to explain properly the changes reported by the artifact named `#{artifact_ref(:files_diff)}`
|
|
58
|
+
|
|
59
|
+
- You MUST create an artifact named `change_intent` that contains:
|
|
60
|
+
1. A general explanation of the changes, their meaning and intent in the context of this project.
|
|
61
|
+
2. The types of changes (feature, bug fix, documentation, etc.).
|
|
62
|
+
3. The impacted architectural components (backend, login screen, CLI, etc.).
|
|
63
|
+
- Describe those changes in a way similar to a git commit comment or a pull request description.
|
|
64
|
+
- ONLY cover changes from the artifact named `#{artifact_ref(:files_diff)}`.
|
|
65
|
+
- Do NOT explain changes for other files.
|
|
66
|
+
EO_INSTRUCTIONS
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
self.constraints = <<~EO_CONSTRAINTS
|
|
70
|
+
- You are in read-only mode.
|
|
71
|
+
- Do NOT modify or write any file.
|
|
72
|
+
- You must ONLY explain the changes of the artifact named `#{artifact_ref(:files_diff)}`, NOT other changes.
|
|
73
|
+
- You already have ALL the information required.
|
|
74
|
+
- The user's intent is fully specified.
|
|
75
|
+
- The conversation log is provided for context only. You MUST NOT ask follow-up questions.
|
|
76
|
+
EO_CONSTRAINTS
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module XAeonAgents
|
|
2
|
+
module Agents
|
|
3
|
+
# Agent responsible for updating documentation after a new development
|
|
4
|
+
class DocumenterAgent < ComposableAgents::Cline::Agent
|
|
5
|
+
prepend AgentDefaults
|
|
6
|
+
|
|
7
|
+
# Define input artifacts contracts
|
|
8
|
+
#
|
|
9
|
+
# @return [Hash{Symbol => Object}] Set of input artifacts description, per artifact name
|
|
10
|
+
def input_artifacts_contracts
|
|
11
|
+
super.merge(
|
|
12
|
+
requirements: 'The initial requirements',
|
|
13
|
+
plan: 'Implementation plan that introduced features and fixes to be documented',
|
|
14
|
+
files_diffs: 'Full list of files changes and differences that have been done to implement the initial requirements following the implementation plan'
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Constructor
|
|
19
|
+
#
|
|
20
|
+
# @param agent_params [Hash{Symbol => Object}] Extra agent parameters
|
|
21
|
+
def initialize(**agent_params)
|
|
22
|
+
super(
|
|
23
|
+
name: 'Documenter',
|
|
24
|
+
objective: 'Ensure documentation reflects the current product behavior and usage after a new development.',
|
|
25
|
+
constraints: <<~EO_CONSTRAINTS,
|
|
26
|
+
- Only update documentation files.
|
|
27
|
+
- Do NOT change any code or test.
|
|
28
|
+
- NEVER document the fact that a change happened.
|
|
29
|
+
- NEVER explain that something was removed, renamed, or fixed.
|
|
30
|
+
- Documentation describes the CURRENT STATE only.
|
|
31
|
+
- Documentation is NOT a changelog.
|
|
32
|
+
EO_CONSTRAINTS
|
|
33
|
+
skills: %w[
|
|
34
|
+
applying-ruby-conventions
|
|
35
|
+
applying-test-conventions
|
|
36
|
+
updating-doc
|
|
37
|
+
enforcing-project-rules
|
|
38
|
+
],
|
|
39
|
+
**agent_params
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|