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,384 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
|
|
3
|
+
module XAeonAgents
|
|
4
|
+
# Main X-Aeon Agents CLI
|
|
5
|
+
class Cli < Thor
|
|
6
|
+
# Global options
|
|
7
|
+
class_option :session_id, type: :string, desc: 'Session ID for persistence'
|
|
8
|
+
class_option :debug, type: :boolean, default: false, desc: 'Enable debug mode'
|
|
9
|
+
|
|
10
|
+
# --------------------------------------------------------------------------- #
|
|
11
|
+
# review-comments: Address Pull Request review comments
|
|
12
|
+
# --------------------------------------------------------------------------- #
|
|
13
|
+
|
|
14
|
+
desc 'review-comments [PULL_REQUEST_NUMBER]', 'Address review comments on a GitHub Pull Request'
|
|
15
|
+
long_desc <<~LONGDESC
|
|
16
|
+
Reads Pull Request comments addressed to the agent, improves or fixes
|
|
17
|
+
the code based on those comments, and replies to each one. The Pull
|
|
18
|
+
Request is identified by its number in the current GitHub repository,
|
|
19
|
+
or auto-detected from the current git branch when no number is given.
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
|
|
23
|
+
$ xaa review-comments 42
|
|
24
|
+
|
|
25
|
+
$ xaa review-comments
|
|
26
|
+
|
|
27
|
+
$ xaa review-comments 42 --session-id my-session
|
|
28
|
+
LONGDESC
|
|
29
|
+
# Addresses review comments on a GitHub Pull Request.
|
|
30
|
+
#
|
|
31
|
+
# @param pull_request_number [Integer, nil] The GitHub Pull Request number to process, or nil to auto-detect
|
|
32
|
+
def review_comments(pull_request_number = nil)
|
|
33
|
+
Agents::ReviewResolverAgent.new(session_id: options[:session_id]).run(
|
|
34
|
+
pull_request_number: pull_request_number ? Integer(pull_request_number) : nil
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# --------------------------------------------------------------------------- #
|
|
39
|
+
# commit: Commit staged changes with an AI-generated message
|
|
40
|
+
# --------------------------------------------------------------------------- #
|
|
41
|
+
|
|
42
|
+
desc 'commit', 'Commit staged changes with an AI-generated commit message'
|
|
43
|
+
long_desc <<~LONGDESC
|
|
44
|
+
Analyzes the currently staged changes and generates a meaningful commit
|
|
45
|
+
message before committing.
|
|
46
|
+
|
|
47
|
+
The --stage option controls how files are staged before committing:
|
|
48
|
+
|
|
49
|
+
--stage all Always stage all changes (tracked and untracked)
|
|
50
|
+
--stage if_empty Stage all changes only if the staging area is empty (default)
|
|
51
|
+
--stage none Do not stage anything; only commit already staged changes
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
|
|
55
|
+
$ xaa commit
|
|
56
|
+
|
|
57
|
+
$ xaa commit --stage all
|
|
58
|
+
|
|
59
|
+
$ xaa commit --stage none
|
|
60
|
+
LONGDESC
|
|
61
|
+
option(
|
|
62
|
+
:stage,
|
|
63
|
+
type: :string,
|
|
64
|
+
default: 'if_empty',
|
|
65
|
+
desc: 'Staging strategy: all, if_empty, or none'
|
|
66
|
+
)
|
|
67
|
+
# Commits staged changes with an AI-generated commit message.
|
|
68
|
+
def commit
|
|
69
|
+
Agents::CommitterAgent.new(
|
|
70
|
+
session_id: options[:session_id],
|
|
71
|
+
stage: options[:stage].to_sym
|
|
72
|
+
).run
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# --------------------------------------------------------------------------- #
|
|
76
|
+
# create-pr: Push on Github and create a Pull Request if not already existing
|
|
77
|
+
# --------------------------------------------------------------------------- #
|
|
78
|
+
|
|
79
|
+
desc 'create-pr', 'Push on Github and create a Pull Request if not already existing'
|
|
80
|
+
long_desc <<~LONGDESC
|
|
81
|
+
Analyzes the current changes between the existing branch and its base,
|
|
82
|
+
pushes the branch on Github and generates a meaningful Pull Request on it.
|
|
83
|
+
|
|
84
|
+
The --base option gives the base ref of the Pull Request (defaults to main).
|
|
85
|
+
|
|
86
|
+
The --requirements option gives an optional description of requirements behind this Pull Request.
|
|
87
|
+
|
|
88
|
+
Examples:
|
|
89
|
+
|
|
90
|
+
$ xaa create-pr
|
|
91
|
+
|
|
92
|
+
$ xaa create-pr --base master
|
|
93
|
+
|
|
94
|
+
$ xaa create-pr --requirements "Add a new Home button on main screen"
|
|
95
|
+
LONGDESC
|
|
96
|
+
option :base, type: :string, default: 'main', desc: 'Base git ref to compare the existing base with for the Pull Request'
|
|
97
|
+
option :requirements, type: :string, default: nil, desc: 'Optional requirements that describe this Pull Request purpose'
|
|
98
|
+
# Push changes on Github and create a Pull Request.
|
|
99
|
+
def create_pr
|
|
100
|
+
agent_kwargs = {
|
|
101
|
+
base_sha: options[:base]
|
|
102
|
+
}
|
|
103
|
+
agent_kwargs[:requirements] = options[:requirements] if options[:requirements]
|
|
104
|
+
Agents::PullRequestCreatorAgent.new(session_id: options[:session_id]).run(**agent_kwargs)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# --------------------------------------------------------------------------- #
|
|
108
|
+
# generate-readme: Generate or update the project README
|
|
109
|
+
# --------------------------------------------------------------------------- #
|
|
110
|
+
|
|
111
|
+
desc 'generate-readme', 'Generate a comprehensive README from the codebase'
|
|
112
|
+
long_desc <<~LONGDESC
|
|
113
|
+
Uses AI to analyze the project and generate a README file with the
|
|
114
|
+
following sections (all enabled by default):
|
|
115
|
+
|
|
116
|
+
--about
|
|
117
|
+
--quick-start
|
|
118
|
+
--requirements
|
|
119
|
+
--features
|
|
120
|
+
--public-api
|
|
121
|
+
--documentation
|
|
122
|
+
--how-it-works
|
|
123
|
+
--development
|
|
124
|
+
--contributing
|
|
125
|
+
--license
|
|
126
|
+
|
|
127
|
+
Disable individual sections with --no-<section>.
|
|
128
|
+
|
|
129
|
+
Examples:
|
|
130
|
+
|
|
131
|
+
$ xaa generate-readme
|
|
132
|
+
|
|
133
|
+
$ xaa generate-readme --no-features --no-license --session-id my-session
|
|
134
|
+
|
|
135
|
+
$ xaa generate-readme --readme-file-path /path/to/custom/README.md
|
|
136
|
+
LONGDESC
|
|
137
|
+
option :about, type: :boolean, default: true, desc: 'Generate the About section'
|
|
138
|
+
option :quick_start, type: :boolean, default: true, desc: 'Generate the Quick Start section'
|
|
139
|
+
option :requirements, type: :boolean, default: true, desc: 'Generate the Requirements section'
|
|
140
|
+
option :features, type: :boolean, default: true, desc: 'Generate the Features section'
|
|
141
|
+
option :public_api, type: :boolean, default: true, desc: 'Generate the Public API section'
|
|
142
|
+
option :documentation, type: :boolean, default: true, desc: 'Generate the Documentation section'
|
|
143
|
+
option :how_it_works, type: :boolean, default: true, desc: 'Generate the How It Works section'
|
|
144
|
+
option :development, type: :boolean, default: true, desc: 'Generate the Development section'
|
|
145
|
+
option :contributing, type: :boolean, default: true, desc: 'Generate the Contributing section'
|
|
146
|
+
option :license, type: :boolean, default: true, desc: 'Generate the License section'
|
|
147
|
+
option :readme_file_path, type: :string, default: nil, desc: 'Path to the README file to generate or update'
|
|
148
|
+
# Generates or updates the project README file.
|
|
149
|
+
def generate_readme
|
|
150
|
+
agent_kwargs = {
|
|
151
|
+
gen_about: options[:about],
|
|
152
|
+
gen_quick_start: options[:quick_start],
|
|
153
|
+
gen_requirements: options[:requirements],
|
|
154
|
+
gen_features: options[:features],
|
|
155
|
+
gen_public_api: options[:public_api],
|
|
156
|
+
gen_documentation: options[:documentation],
|
|
157
|
+
gen_how_it_works: options[:how_it_works],
|
|
158
|
+
gen_development: options[:development],
|
|
159
|
+
gen_contributing: options[:contributing],
|
|
160
|
+
gen_license: options[:license]
|
|
161
|
+
}
|
|
162
|
+
agent_kwargs[:readme_file_path] = options[:readme_file_path] if options[:readme_file_path]
|
|
163
|
+
Agents::ReadmeGeneratorAgent.new(session_id: options[:session_id]).run(**agent_kwargs)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# --------------------------------------------------------------------------- #
|
|
167
|
+
# generate-skills: Generate skill files from ERB templates
|
|
168
|
+
# --------------------------------------------------------------------------- #
|
|
169
|
+
|
|
170
|
+
desc 'generate-skills', 'Generate skill files from ERB templates in skills.src/'
|
|
171
|
+
long_desc <<~LONGDESC
|
|
172
|
+
Processes the skills.src/ directory and writes generated skill files to
|
|
173
|
+
the output directory (default: skills/). ERB templates (.erb) are
|
|
174
|
+
evaluated; all other files are copied as-is.
|
|
175
|
+
|
|
176
|
+
Examples:
|
|
177
|
+
|
|
178
|
+
$ xaa generate-skills
|
|
179
|
+
|
|
180
|
+
$ xaa generate-skills --output-dir custom_skills
|
|
181
|
+
LONGDESC
|
|
182
|
+
option :output_dir, type: :string, default: 'skills', desc: 'Output directory for generated skills'
|
|
183
|
+
option(
|
|
184
|
+
:skill,
|
|
185
|
+
type: :string,
|
|
186
|
+
repeatable: true,
|
|
187
|
+
desc: 'Skill name(s) to generate. Can be repeated: --skill name1 --skill name2 or comma-separated: --skill name1,name2. Omit to generate all skills.'
|
|
188
|
+
)
|
|
189
|
+
# Generates skill files from ERB templates in skills.src/.
|
|
190
|
+
#
|
|
191
|
+
# @note Exits with status 1 if skill generation fails
|
|
192
|
+
def generate_skills
|
|
193
|
+
result = Agents::SkillGeneratorAgent.new(session_id: options[:session_id]).run(
|
|
194
|
+
output_dir: options[:output_dir],
|
|
195
|
+
skill_names: options[:skill]
|
|
196
|
+
)
|
|
197
|
+
exit 1 unless result[:success]
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# --------------------------------------------------------------------------- #
|
|
201
|
+
# implement-issue: Implement a GitHub issue
|
|
202
|
+
# --------------------------------------------------------------------------- #
|
|
203
|
+
|
|
204
|
+
desc 'implement-issue ISSUE_NUMBER', 'Implement a GitHub issue using AI'
|
|
205
|
+
long_desc <<~LONGDESC
|
|
206
|
+
Reads the content (and comments) of a GitHub issue and delegates the
|
|
207
|
+
implementation to the Developer agent. The agent commits changes and
|
|
208
|
+
opens a Pull Request automatically.
|
|
209
|
+
|
|
210
|
+
Examples:
|
|
211
|
+
|
|
212
|
+
$ xaa implement-issue 15
|
|
213
|
+
|
|
214
|
+
$ xaa implement-issue 15 --session-id my-session
|
|
215
|
+
LONGDESC
|
|
216
|
+
# Implements a GitHub issue using AI.
|
|
217
|
+
#
|
|
218
|
+
# @param github_issue_number [Integer] The GitHub issue number to implement
|
|
219
|
+
def implement_issue(github_issue_number)
|
|
220
|
+
Agents::IssueImplementerAgent.new(
|
|
221
|
+
commit: true,
|
|
222
|
+
pull_request: true,
|
|
223
|
+
session_id: options[:session_id]
|
|
224
|
+
).run(github_issue_number: Integer(github_issue_number))
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# --------------------------------------------------------------------------- #
|
|
228
|
+
# implement: Implement arbitrary requirements
|
|
229
|
+
# --------------------------------------------------------------------------- #
|
|
230
|
+
|
|
231
|
+
desc 'implement REQUIREMENTS', 'Implement given requirements with AI'
|
|
232
|
+
long_desc <<~LONGDESC
|
|
233
|
+
Pass free-form requirements to the Developer agent, which will analyze
|
|
234
|
+
the codebase and produce the requested changes.
|
|
235
|
+
|
|
236
|
+
Examples:
|
|
237
|
+
|
|
238
|
+
$ xaa implement "Add authentication middleware"
|
|
239
|
+
|
|
240
|
+
$ xaa implement "Refactor the database layer" --commit --pr --session-id my-session
|
|
241
|
+
LONGDESC
|
|
242
|
+
option :commit, type: :boolean, default: false, desc: 'Commit files at every step'
|
|
243
|
+
option :pr, type: :boolean, default: false, desc: 'Create a GitHub Pull Request for the changes'
|
|
244
|
+
# Implements arbitrary requirements using AI.
|
|
245
|
+
#
|
|
246
|
+
# @param requirements [String] Free-form requirements describing the desired changes
|
|
247
|
+
def implement(requirements)
|
|
248
|
+
Agents::DeveloperAgent.new(
|
|
249
|
+
commit: options[:commit],
|
|
250
|
+
pull_request: options[:pr],
|
|
251
|
+
session_id: options[:session_id]
|
|
252
|
+
).run(requirements:)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# --------------------------------------------------------------------------- #
|
|
256
|
+
# interpret-diffs: Summarize current git diffs
|
|
257
|
+
# --------------------------------------------------------------------------- #
|
|
258
|
+
|
|
259
|
+
desc 'interpret-diffs [BASE]', 'Summarize git diffs relative to a base ref'
|
|
260
|
+
long_desc <<~LONGDESC
|
|
261
|
+
Produces a one-line summary and a description of the intent behind the
|
|
262
|
+
changes in the working tree relative to BASE (default: HEAD).
|
|
263
|
+
|
|
264
|
+
Examples:
|
|
265
|
+
|
|
266
|
+
$ xaa interpret-diffs
|
|
267
|
+
|
|
268
|
+
$ xaa interpret-diffs main
|
|
269
|
+
|
|
270
|
+
$ xaa interpret-diffs HEAD~3
|
|
271
|
+
LONGDESC
|
|
272
|
+
# Summarizes current git diffs relative to a base ref.
|
|
273
|
+
#
|
|
274
|
+
# @param base [String] Git reference to diff against
|
|
275
|
+
def interpret_diffs(base = 'HEAD')
|
|
276
|
+
output = Agents::GitDiffInterpreterAgent.new(session_id: options[:session_id]).run(git_ref_base: base)
|
|
277
|
+
puts <<~EO_OUTPUT
|
|
278
|
+
===== Code diffs interpretation:
|
|
279
|
+
|
|
280
|
+
#{output[:one_line_summary].strip}
|
|
281
|
+
|
|
282
|
+
#{output[:change_intent].strip}
|
|
283
|
+
EO_OUTPUT
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# --------------------------------------------------------------------------- #
|
|
287
|
+
# prompt: Send a one-shot prompt to the AI agent
|
|
288
|
+
# --------------------------------------------------------------------------- #
|
|
289
|
+
|
|
290
|
+
desc 'prompt PROMPT', 'Send a one-shot prompt to the AI agent and print the response'
|
|
291
|
+
long_desc <<~LONGDESC
|
|
292
|
+
Executes a single prompt against the free simple AI model and prints
|
|
293
|
+
the last message of the conversation.
|
|
294
|
+
|
|
295
|
+
Examples:
|
|
296
|
+
|
|
297
|
+
$ xaa prompt "What is the capital of France?"
|
|
298
|
+
|
|
299
|
+
$ xaa prompt "Explain this code: puts 'hello'"
|
|
300
|
+
LONGDESC
|
|
301
|
+
# Sends a one-shot prompt to the AI agent and prints the response.
|
|
302
|
+
#
|
|
303
|
+
# @param user_prompt [String] The prompt text to send to the AI agent
|
|
304
|
+
def prompt(user_prompt)
|
|
305
|
+
agent = Agents::ExecutorAgent.new(session_id: options[:session_id], **Config.agent_options['free_simple'])
|
|
306
|
+
agent.run(user_instructions: user_prompt)
|
|
307
|
+
puts agent.conversation.last[:message]
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# --------------------------------------------------------------------------- #
|
|
311
|
+
# install-skills: Install skills from the .skills manifest
|
|
312
|
+
# --------------------------------------------------------------------------- #
|
|
313
|
+
|
|
314
|
+
desc 'install-skills', 'Install skills and their dependencies from the .skills manifest'
|
|
315
|
+
long_desc <<~LONGDESC
|
|
316
|
+
Reads the .skills manifest file and installs every listed skill,
|
|
317
|
+
together with their recursively-resolved dependencies.
|
|
318
|
+
|
|
319
|
+
Example:
|
|
320
|
+
|
|
321
|
+
$ xaa install-skills
|
|
322
|
+
|
|
323
|
+
$ xaa install-skills --agent cline
|
|
324
|
+
LONGDESC
|
|
325
|
+
option :agent, type: :string, default: 'cline', desc: 'Agent name to be used to install skills'
|
|
326
|
+
# Installs skills and their dependencies from the .skills manifest.
|
|
327
|
+
def install_skills
|
|
328
|
+
Agents::SkillInstallerAgent.new(session_id: options[:session_id]).run(
|
|
329
|
+
agent: options[:agent].to_sym
|
|
330
|
+
)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# --------------------------------------------------------------------------- #
|
|
334
|
+
# start-task: Open a new git worktree for a task
|
|
335
|
+
# --------------------------------------------------------------------------- #
|
|
336
|
+
|
|
337
|
+
desc 'start-task', 'Open a new git worktree for a feature branch'
|
|
338
|
+
long_desc <<~LONGDESC
|
|
339
|
+
Interactive command that prompts for a branch name, creates the branch
|
|
340
|
+
(if it does not exist), sets up a git worktree in .worktrees/, pushes
|
|
341
|
+
the branch upstream, and opens it in VSCodium.
|
|
342
|
+
|
|
343
|
+
The --branch option gives the branch name directly, so the command is
|
|
344
|
+
not interactive anymore (no prompt to STDIN).
|
|
345
|
+
|
|
346
|
+
Example:
|
|
347
|
+
|
|
348
|
+
$ xaa start-task
|
|
349
|
+
|
|
350
|
+
$ xaa start-task --branch feature/my-task
|
|
351
|
+
LONGDESC
|
|
352
|
+
option :branch, type: :string, default: nil, desc: 'Branch name to create a worktree for. If omitted, the branch name is read interactively from STDIN.'
|
|
353
|
+
# Opens a new git worktree for a feature branch.
|
|
354
|
+
def start_task
|
|
355
|
+
branch = options[:branch] || begin
|
|
356
|
+
puts 'Branch name:'
|
|
357
|
+
$stdin.gets.strip
|
|
358
|
+
end
|
|
359
|
+
Agents::TaskStarterAgent.new(session_id: options[:session_id]).run(branch_name: branch)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
# --------------------------------------------------------------------------- #
|
|
363
|
+
# Exit on failure for consistent scripting
|
|
364
|
+
# --------------------------------------------------------------------------- #
|
|
365
|
+
|
|
366
|
+
# Returns whether to exit on command failure.
|
|
367
|
+
#
|
|
368
|
+
# @return [Boolean] Always returns true so Thor exits with a non-zero status on command failure
|
|
369
|
+
def self.exit_on_failure?
|
|
370
|
+
true
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
no_commands do
|
|
374
|
+
# Initializes the CLI and applies global configuration from options.
|
|
375
|
+
#
|
|
376
|
+
# @param args [Array<Object>] Arguments forwarded to Thor's constructor
|
|
377
|
+
def initialize(*)
|
|
378
|
+
super
|
|
379
|
+
# Handle all the global setup from options
|
|
380
|
+
Config.debug = options[:debug]
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'agents'
|
|
2
|
+
require 'ruby_llm'
|
|
3
|
+
require 'secret_string'
|
|
4
|
+
|
|
5
|
+
module XAeonAgents
|
|
6
|
+
# Singleton module to get all configuration of X-Aeon Agents
|
|
7
|
+
module Config
|
|
8
|
+
# TODO: Add test cases for this module
|
|
9
|
+
class << self
|
|
10
|
+
include Logger
|
|
11
|
+
|
|
12
|
+
# @!group Public API
|
|
13
|
+
|
|
14
|
+
# Automatically generate accessors for secrets taken from the ENV or the Launcher
|
|
15
|
+
%i[
|
|
16
|
+
cline_api_key
|
|
17
|
+
openrouter_api_key
|
|
18
|
+
github_token
|
|
19
|
+
].each do |secret_name|
|
|
20
|
+
# Set the secret from a string
|
|
21
|
+
#
|
|
22
|
+
# @param secret [String] The secret value
|
|
23
|
+
define_method(:"#{secret_name}=") do |secret|
|
|
24
|
+
@secrets ||= {}
|
|
25
|
+
@secrets[secret_name] = SecretString.new(secret)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Get the unprotected secret as a string.
|
|
29
|
+
# Use defaults if the secret was never set.
|
|
30
|
+
#
|
|
31
|
+
# @return [String, nil] The secret value, or nil if none
|
|
32
|
+
define_method(secret_name) do
|
|
33
|
+
@secrets ||= {}
|
|
34
|
+
@secrets[secret_name] ||= begin
|
|
35
|
+
env_secret = ENV.fetch(secret_name.to_s.upcase, nil)
|
|
36
|
+
env_secret ? SecretString.new(env_secret.dup) : Helpers.keys_from_launcher[secret_name]
|
|
37
|
+
end
|
|
38
|
+
@secrets[secret_name]&.to_unprotected
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [String] X-Aeon Agents data directory
|
|
43
|
+
attr_writer :data_dir
|
|
44
|
+
|
|
45
|
+
# @return [String] X-Aeon Agents data directory
|
|
46
|
+
def data_dir
|
|
47
|
+
@data_dir ||= '.x_aeon_agents'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @return [Hash{Symbol => Object}] Default Cline CLI arguments
|
|
51
|
+
attr_writer :default_cline_cli_args
|
|
52
|
+
|
|
53
|
+
# @return [Hash{Symbol => Object}] Default Cline CLI arguments
|
|
54
|
+
def default_cline_cli_args
|
|
55
|
+
@default_cline_cli_args ||= { thinking: 'xhigh' }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @return [Boolean] The debug mode
|
|
59
|
+
def debug=(value)
|
|
60
|
+
@debug = value
|
|
61
|
+
Logger.debug = debug
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @return [Boolean] The debug mode
|
|
65
|
+
def debug
|
|
66
|
+
@debug ||= ENV['X_AEON_AGENTS_DEBUG'] == '1'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [AgentOptions] The available agent options.
|
|
70
|
+
def agent_options
|
|
71
|
+
@agent_options ||= AgentOptions.new
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Configure X-Aeon Agents
|
|
75
|
+
#
|
|
76
|
+
# @param kwargs [Hash] Any configuration property that can be set
|
|
77
|
+
def configure(**kwargs)
|
|
78
|
+
kwargs.each do |property, value|
|
|
79
|
+
send(:"#{property}=", value)
|
|
80
|
+
end
|
|
81
|
+
Logger.debug = debug
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @!group Internal
|
|
85
|
+
|
|
86
|
+
# Setup composable_agents in a lazy and memoized way
|
|
87
|
+
def setup_composable_agents
|
|
88
|
+
ENV['COMPOSABLE_AGENTS_DEBUG'] = '1' if debug
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Setup ai-agents in a lazy and memoized way
|
|
92
|
+
def setup_ai_agents
|
|
93
|
+
ENV['RUBYLLM_DEBUG'] = '1' if debug
|
|
94
|
+
::Agents.configure do |ai_agents_config|
|
|
95
|
+
ai_agents_config.debug = debug
|
|
96
|
+
end
|
|
97
|
+
RubyLLM.configure do |ruby_llm_config|
|
|
98
|
+
ruby_llm_config.openrouter_api_key = openrouter_api_key
|
|
99
|
+
end
|
|
100
|
+
# Discover all the models
|
|
101
|
+
RubyLLM::Models.refresh!
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Setup Cline in a lazy and memoized way
|
|
105
|
+
def setup_cline
|
|
106
|
+
# Nothing to do
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|