aigency 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c413cf37072efae1aa6df896884d291ee9bac175a1154e579d85833692f55959
4
+ data.tar.gz: feaacbce278ae242f36bd8f2b3024d014bb200dad97679f6fb023986def493ec
5
+ SHA512:
6
+ metadata.gz: '09ba427def6dcce5abcb433c76d44276c58af597ad15f703e1cfb3503e8a527f2944951314c6a2a53e3b91cc54005d54c996e659288d4726e71d0565a33e7cef'
7
+ data.tar.gz: e4ef1fea768cd49fad82edf2ea4086b792118c545c7d12ea8772e0ba7c694793fa45c3024552ca35b9677d15a744a133a6f94bcf5f98a952008a6e5fefd9834b
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # Aigency
2
+
3
+ A framework for creating AI agents with RubyLLM.
4
+
5
+ ## Installation
6
+
7
+ Install the gem from the command line:
8
+
9
+ ```bash
10
+ gem install aigency
11
+ ```
12
+
13
+ Or add it to your Gemfile:
14
+
15
+ ```ruby
16
+ gem 'aigency'
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ### Creating a New Aigent
22
+
23
+ The recommended way to create an aigent is to give it a dedicated system user.
24
+
25
+ ```bash
26
+ useradd aigent_user
27
+ sudo su - aigent_user
28
+ ```
29
+
30
+ Once you're logged in as the aigent user, create the aigent directory:
31
+
32
+ ```bash
33
+ aigency enlist
34
+ cd aigent
35
+ bundle install
36
+ rake setup
37
+ ```
38
+
39
+ The bare minimum configuration you need to do is setting `openai_api_base` and `openai_api_key` in `config/aigent.yml`.
40
+
41
+ Test the aigent with with the `rake say` task.
42
+
43
+ ```bash
44
+ rake say["How many fibers are intertwined in a shredded wheat biscuit?"]
45
+ ```
46
+
47
+ See the aigent's README (scaffold/README.md in this codebase) for more information.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/exe/aigency ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # turn off warning diagnostics from Ruby
5
+ $VERBOSE=nil
6
+
7
+ require 'aigency'
8
+
9
+ Aigency::Shell.start(ARGV)
@@ -0,0 +1,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'yaml'
5
+
6
+ module Aigency
7
+ class Aigent
8
+ # @return [IO]
9
+ attr_reader :log
10
+
11
+ def initialize(directory)
12
+ @base_directory = File.absolute_path(directory)
13
+ @log = $stdout
14
+ load_requires
15
+ end
16
+
17
+ # @return [String]
18
+ def name
19
+ @name ||= config('aigent')['name'] || "an Aigent"
20
+ end
21
+
22
+ # Get the aigent directory with optional additional paths.
23
+ #
24
+ # @param paths [Array<String>] Additional paths
25
+ # @return [String] The complete path
26
+ def directory(*paths)
27
+ File.join(@base_directory, *paths)
28
+ end
29
+
30
+ # Get the aigent data directory with optional additional paths.
31
+ #
32
+ # @param paths [Array<String>] Additional paths
33
+ # @return [String] The complete path
34
+ def data(*paths)
35
+ directory('data', *paths)
36
+ end
37
+
38
+ # Initialize a RubyLLM::Chat.
39
+ #
40
+ # @param extra [Array<String>] Additional instructions
41
+ # @return [RubyLLM::Chat]
42
+ def brief(*extra)
43
+ chat = rubyllm_context.chat(provider: :openai)
44
+ Tools.registry.each { |klass| chat.with_tool(klass.new(self)) }
45
+ chat.with_instructions(build_instructions(extra), append: true)
46
+ # @todo This should be configurable
47
+ chat.with_params(max_tokens: max_tokens)
48
+ end
49
+
50
+ def load filename, *extra, out: $stdout
51
+ stream File.read(filename), *extra, out: out
52
+ end
53
+
54
+ def stream text, *extra, with: [], out: $stdout
55
+ original_log = @log
56
+ @log = out
57
+ brief(*extra).ask text, with: with do |chunk|
58
+ @log.print chunk.thinking&.text
59
+ @log.print chunk.content
60
+ end.tap { @log = original_log }
61
+ end
62
+
63
+ # @param name [String]
64
+ # @return [Hash]
65
+ def config(name)
66
+ configs[name] ||= read_config(name)
67
+ end
68
+
69
+ # Initialize the aigent's tool configurations.
70
+ #
71
+ # @param only [Array<String>] Limit the tools being configured
72
+ # @param overwrite [Boolean] Replace existing configs if true
73
+ def setup(only: [], overwrite: false)
74
+ only = [only].flatten.compact
75
+ config_count = 0
76
+ Tools.config_map.each do |name, text|
77
+ next unless only.empty? || only.include?(name)
78
+
79
+ dir = directory('config')
80
+ FileUtils.mkdir_p dir
81
+ path = File.join(dir, "#{name}.yml")
82
+ if overwrite || !File.file?(path)
83
+ doing = File.file?(path) ? 'Overwriting' : 'Writing new'
84
+ log.puts "#{doing} config for #{name}"
85
+ File.write path, text
86
+ config_count += 1
87
+ else
88
+ log.puts "Config for #{name} exists, skipping"
89
+ end
90
+ end
91
+ dir_count = 0
92
+ Tools.directories.each do |path|
93
+ absolute = directory(path)
94
+ next if File.directory?(absolute)
95
+
96
+ FileUtils.mkdir_p absolute
97
+ dir_count += 1
98
+ end
99
+ log.puts "#{config_count} config files initialized."
100
+ log.puts "#{dir_count} directories created."
101
+ end
102
+
103
+ # Run code in an exclusive lock
104
+ #
105
+ def lock(&block)
106
+ File.open(data('lock'), 'w') do |file|
107
+ file.flock(File::LOCK_EX)
108
+ file.write(Process.pid)
109
+ file.flush
110
+ block&.call
111
+ end
112
+ end
113
+
114
+ # Run code if an exclusive lock is available or skip if a lock exists
115
+ #
116
+ def try_with_lock(&block)
117
+ File.open(data('lock'), 'w') do |file|
118
+ acquired = file.flock(File::LOCK_EX|File::LOCK_NB)
119
+ return unless acquired
120
+ file.write(Process.pid)
121
+ file.flush
122
+ block&.call
123
+ end
124
+ end
125
+ alias nonblock try_with_lock
126
+
127
+ # True if an exclusive lock exists
128
+ #
129
+ def locked?
130
+ File.open(data('lock'), File::RDWR|File::CREAT) do |file|
131
+ result = file.flock(File::LOCK_EX|File::LOCK_NB)
132
+ return !result
133
+ end
134
+ end
135
+ alias busy? locked?
136
+
137
+ def instructions
138
+ @instructions ||= build_instructions([])
139
+ end
140
+
141
+ private
142
+
143
+ def configs
144
+ @configs ||= {}
145
+ end
146
+
147
+ def read_config(name)
148
+ base = directory('config')
149
+ filename = if name =~ /(\.yaml|\.yml)$/
150
+ name
151
+ else
152
+ "#{name}.yml"
153
+ end
154
+ full_path = File.join(directory, 'config', filename)
155
+ if File.file?(full_path)
156
+ YAML.load_file(full_path)
157
+ else
158
+ warn "Config name #{name} not found at #{full_path}"
159
+ {}
160
+ end
161
+ end
162
+
163
+ def identity_file
164
+ @identity_file ||= File.join(directory, 'IDENTITY.md')
165
+ end
166
+
167
+ def identity_file?
168
+ File.file?(identity_file)
169
+ end
170
+
171
+ def base_instructions
172
+ @base_instructions ||= identity_file? ? File.read(identity_file) : "You are a helpful AI assistant."
173
+ end
174
+
175
+ def build_instructions(extra)
176
+ [base_instructions].concat tool_prompts
177
+ .push "Today's date is #{DateTime.now.strftime('%B %e, %Y')}."
178
+ .concat extra
179
+ .join("\n\n")
180
+ end
181
+
182
+ def tool_prompts
183
+ Tools.config_map
184
+ .keys
185
+ .map { |name| config(name)['prompt'] }
186
+ .compact
187
+ end
188
+
189
+ def load_requires
190
+ read_requires.each { |name| require name }
191
+ end
192
+
193
+ def read_requires
194
+ config('aigent')['require'] || []
195
+ end
196
+
197
+ def max_tokens
198
+ @max_tokens ||= (config('aigent')['max_tokens'] || -1).to_i
199
+ end
200
+
201
+ def rubyllm_context
202
+ RubyLLM.context do |config|
203
+ config.openai_api_base = config('aigent')['openai_api_base']
204
+ config.openai_api_key = config('aigent')['openai_api_key']
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'thor'
5
+
6
+ module Aigency
7
+ class Shell < Thor
8
+ map %i[new] => :enlist
9
+ desc "enlist [DIRECTORY]", "Enable the current user as an aigent"
10
+ option :directory, type: :string, desc: 'Aigent directory', default: File.join(Dir.home, 'aigent')
11
+ def enlist
12
+ directory = options[:directory]
13
+ puts "Installing aigent at #{directory}"
14
+ if File.exist?(directory)
15
+ if !File.directory?(directory)
16
+ raise "#{directory} is not a directory."
17
+ end
18
+ if !Dir.empty?(directory)
19
+ raise "#{directory} is not empty."
20
+ end
21
+ end
22
+ FileUtils.mkdir(directory) unless File.directory?(directory)
23
+ FileUtils.copy_entry(File.join(GEM_PATH, 'scaffold'), directory)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aigency
4
+ # A subclass of RubyLLM::Tool with aigent integration.
5
+ #
6
+ class Tool < RubyLLM::Tool
7
+ include Usability
8
+ end
9
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aigency
4
+ module Tools
5
+ # @return [Array<Class<Tool>>]
6
+ def self.registry
7
+ @registry ||= []
8
+ end
9
+
10
+ # @return [Hash{String => String}]
11
+ def self.config_map
12
+ @configs ||= {}
13
+ end
14
+
15
+ # @return [Array<String>]
16
+ def self.directories
17
+ @directories ||= []
18
+ end
19
+
20
+ # Register a tool.
21
+ #
22
+ # @param klass [Class<Tool>]
23
+ # @return [void]
24
+ def self.register klass
25
+ registry.push klass
26
+ end
27
+
28
+ # Define a default configuration.
29
+ #
30
+ # @param name [String] The name of the config section
31
+ # @param text [String] YAML-formatted config data
32
+ # @return [void]
33
+ def self.configure name, text
34
+ config_map[name] = text
35
+ end
36
+
37
+ # Define directories to be created relative to an aigent's root.
38
+ #
39
+ def self.mkdir_p *paths
40
+ directories.concat paths
41
+ end
42
+ end
43
+
44
+ Tools.configure 'aigent', <<~EOF
45
+ name: an Aigent
46
+ openai_api_base: https://api.openai.com/v1
47
+ openai_api_key: CHANGE_ME
48
+ require:
49
+ - aigency/email
50
+ - aigency/wikipedia
51
+ - aigency/workspace
52
+ EOF
53
+
54
+ Tools.mkdir_p 'data/chats', 'data/log'
55
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aigency
4
+ module Usability
5
+ attr_reader :aigent
6
+
7
+ def initialize(aigent)
8
+ @aigent = aigent
9
+ post_initialize
10
+ end
11
+
12
+ def post_initialize
13
+ end
14
+
15
+ # Subclasses need to implement functionality here.
16
+ #
17
+ # @abstract
18
+ def execute(**opts)
19
+ raise 'Not implemented'
20
+ end
21
+
22
+ def self.included other
23
+ other.extend ClassMethods
24
+ end
25
+
26
+ module ClassMethods
27
+ def execute(aigent, **opts)
28
+ new(aigent).execute(**opts)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aigency
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aigency
4
+ module Workspace
5
+ class DirectoryDeleter < Tool
6
+ desc "Deletes a directory from your private workspace"
7
+
8
+ def execute(dirname:)
9
+ puts "Deleting directory #{dirname}"
10
+
11
+ resolved = File.absolute_path(dirname, aigent.data('workspace'))
12
+ return { dirname: dirname, success: false, error: "Permission denied" } unless resolved.start_with?(aigent.data('workspace'))
13
+ return { dirname: dirname, success: false, error: "Permission denied" } if resolved.include?('/.git/') || resolved.end_with?('/.git')
14
+ return { dirname: dirname, success: false, error: "Not a directory" } if File.file?(resolved)
15
+ return { dirname: dirname, sucess: false, error: "Directory not found" } unless File.directory?(resolved)
16
+
17
+ FileUtils.rm_rf(resolved)
18
+ { dirname: dirname, success: true }
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ Aigency::Tools.register Aigency::Workspace::DirectoryDeleter
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aigency
4
+ module Workspace
5
+ class DirectoryReader < Tool
6
+ desc "Gets the contents of a directory from your private workspace"
7
+
8
+ def execute(directory_name:)
9
+ aigent.log.puts "[Workspace::DirectoryReader] Reading #{directory_name}"
10
+ directory = aigent.data('workspace')
11
+ resolved = File.absolute_path(directory_name, directory)
12
+ return { directory: directory_name,
13
+ success: false,
14
+ error: "Permission denied. Path must be local to #{directory}" } unless resolved.start_with?(directory)
15
+
16
+ if File.directory?(resolved)
17
+ {
18
+ directory: directory_name,
19
+ success: true,
20
+ entries: Dir[File.join(resolved, '*')].map { |dir| dir[resolved.length+1..]}
21
+ }
22
+ else
23
+ {
24
+ directory: directory_name,
25
+ success: false,
26
+ error: "Not a directory"
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ Aigency::Tools.register Aigency::Workspace::DirectoryReader
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aigency
4
+ module Workspace
5
+ class FileDeleter < Tool
6
+ desc "Deletes a file from your private workspace"
7
+
8
+ def execute(filename:)
9
+ aigent.log.puts "[Workspace::FileDeleter] Deleting file #{filename}"
10
+
11
+ directory = aigent.data('directory')
12
+ resolved = File.absolute_path(filename, directory)
13
+ return { filename: filename, error: "Permission denied" } unless resolved.start_with?(directory)
14
+ return { filename: filename, error: "Permission denied" } if resolved.include?('/.git/')
15
+ return { filename: filename, error: "File does not exist" } unless File.file?(resolved)
16
+
17
+ File.delete resolved
18
+ { filename: filename, success: true }
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ Aigency::Tools.register Aigency::Workspace::FileDeleter
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aigency
4
+ module Workspace
5
+ class FileReader < Tool
6
+ desc "Reads a file from your private workspace"
7
+
8
+ def execute(filename:)
9
+ aigent.log.puts "[Workspace::FileReader] Reading #{filename}"
10
+
11
+ directory = aigent.data('workspace')
12
+ resolved = File.absolute_path(filename, directory)
13
+ return { filename: filename, success: false, error: "Permission denied" } unless resolved.start_with?(directory)
14
+
15
+ if File.file?(resolved)
16
+ {
17
+ filename: filename,
18
+ success: true,
19
+ content: File.read(resolved)
20
+ }
21
+ else
22
+ {
23
+ filename: filename,
24
+ success: false,
25
+ error: "File not found"
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ Aigency::Tools.register Aigency::Workspace::FileReader
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+
5
+ module Aigency
6
+ module Workspace
7
+ class FileWriter < Tool
8
+ desc "Writes a file to your private workspace"
9
+
10
+ def execute(filename:, content:)
11
+ aigent.log.puts "[Workspace::FileWriter] Writing #{filename}"
12
+
13
+ directory = aigent.data('workspace')
14
+ resolved = File.absolute_path(filename, directory)
15
+ return { filename: filename, success: false, error: "Permission denied" } unless resolved.start_with?(directory)
16
+
17
+ FileUtils.mkdir_p File.dirname(resolved)
18
+ File.write resolved, content
19
+ return { filename: filename, success: true }
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ Aigency::Tools.register Aigency::Workspace::FileWriter
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aigency
4
+ module Workspace
5
+ require 'aigency/workspace/directory_reader'
6
+ require 'aigency/workspace/file_reader'
7
+ require 'aigency/workspace/file_writer'
8
+ end
9
+
10
+ Tools.mkdir_p 'data/workspace'
11
+ end
data/lib/aigency.rb ADDED
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ruby_llm'
4
+
5
+ # Core
6
+ require 'aigency/version'
7
+ require 'aigency/usability'
8
+ require 'aigency/tool'
9
+ require 'aigency/tools'
10
+ require 'aigency/aigent'
11
+ require 'aigency/shell'
12
+
13
+ # Extensions
14
+ require 'aigency/workspace'
15
+
16
+ module Aigency
17
+ GEM_PATH = File.absolute_path(File.join(__dir__, '..'))
18
+
19
+ class Error < StandardError; end
20
+ # Your code goes here...
21
+ end
@@ -0,0 +1 @@
1
+ data
data/scaffold/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "dotenv"
6
+ gem "rake", "~> 13.0"
7
+ gem "whenever", "~> 1.1"
8
+
9
+ gem "ruby_llm"
10
+ gem "aigency", path: "../aigency"
@@ -0,0 +1 @@
1
+ You are a helpful AI assistant.
@@ -0,0 +1,74 @@
1
+ # Your Aigent
2
+
3
+ An aigent (AI agent) is an intelligent assistant powered by language models through OpenAI-compatible APIs. It can read and write files in its private workspace and perform scheduled tasks on your behalf.
4
+
5
+ ## Configuration
6
+
7
+ ### Install dependencies
8
+
9
+ ```bash
10
+ bundle install
11
+ ```
12
+
13
+ ### Initial setup
14
+
15
+ ```bash
16
+ rake setup
17
+ ```
18
+
19
+ ### 1. Configure the Aigent
20
+
21
+ Configure the aigent's settings in `config/aigent.yml`.
22
+
23
+ #### OpenAI-Compatible Providers
24
+
25
+ If you're using a local AI server or any other provider that is compatible with OpenAI, you can set the OPENAI_API_BASE config option to point there instead (e.g., `http://localhost:8080/v1`).
26
+
27
+ ### 2. Define the Aigent's Personality
28
+
29
+ Edit `IDENTITY.md` to define how your aigent should behave:
30
+
31
+ ```markdown
32
+ You are a professional assistant named Alex. You respond in a friendly but concise manner.
33
+ ```
34
+
35
+ This file sets the foundation for all the aigent's responses.
36
+
37
+ ## Usage
38
+
39
+ ### Interactive Mode
40
+
41
+ Talk to your aigent using the Rake task:
42
+
43
+ ```bash
44
+ rake say["Tell me about project progress"]
45
+ ```
46
+
47
+ ### The Workspace
48
+
49
+ Your aigent has read/write access to everything in the `data/workspace` directory.
50
+
51
+ ### Scheduling Tasks
52
+
53
+ The project includes the `whenever` gem for scheduling. Example of a scheduled task:
54
+
55
+ ```ruby
56
+ # config/schedule.rb
57
+
58
+ # Every day at 9am, the aigent will run the prompt in the DAILY_TASKS.md file
59
+ every 1.day, at: '9am' do
60
+ rake 'load[DAILY_TASKS.md]'
61
+ end
62
+ ```
63
+
64
+ Add the scheduled tasks to your crontab:
65
+
66
+ ```bash
67
+ bundle exec whenever --update-crontab
68
+ ```
69
+
70
+ (Note: the `whenever` gem does not work on Windows.)
71
+
72
+ ## Aigent Tools
73
+
74
+ You can give your aigent more functionality by installing additional tools. It ships with the `Workspace` tool, which gives it full read/write access to the `data/workspace` directory.
data/scaffold/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ require "bundler/setup"
2
+ require 'yaml'
3
+ require 'dotenv/load'
4
+ require 'aigency'
5
+
6
+ desc "Run a prompt from a file"
7
+ task :load, [:filename] do |_, args|
8
+ aigent = Aigency::Aigent.new('.')
9
+ aigent.nonblock do
10
+ filename = File.join('data', 'chats', "#{Time.now.strftime("%Y-%m-%d_%H%M%S")}_load_#{args[:filename].gsub('/', '_')}.txt")
11
+ File.open(filename, 'w') do |file|
12
+ aigent.load args[:filename], out: file
13
+ rescue StandardError => e
14
+ file.puts "[#{e.class}]: #{e.message}"
15
+ file.puts e.backtrace
16
+ end
17
+ end
18
+ end
19
+
20
+ desc "Talk to the aigent"
21
+ task :say, [:text] do |_, args|
22
+ aigent = Aigency::Aigent.new('.')
23
+ aigent.stream args[:text]
24
+ end
25
+
26
+ desc "Set up aigent configurations"
27
+ task :setup do
28
+ aigent = Aigency::Aigent.new('.')
29
+ aigent.setup
30
+ end
@@ -0,0 +1,6 @@
1
+ name: an Aigent
2
+ openai_api_base: https://api.openai.com/v1
3
+ openai_api_key: CHANGE_ME
4
+ # max_tokens: 65536
5
+ # require:
6
+ # - aigency-example
@@ -0,0 +1,24 @@
1
+ # Use this file to easily define all of your cron jobs.
2
+ #
3
+ # It's helpful, but not entirely necessary to understand cron before proceeding.
4
+ # http://en.wikipedia.org/wiki/Cron
5
+
6
+ # Example:
7
+ #
8
+ # set :output, "/path/to/my/cron_log.log"
9
+ #
10
+ # every 2.hours do
11
+ # command "/usr/bin/some_great_command"
12
+ # runner "MyModel.some_method"
13
+ # rake "some:great:rake:task"
14
+ # end
15
+ #
16
+ # every 4.days do
17
+ # runner "AnotherModel.prune_old_records"
18
+ # end
19
+
20
+ # Learn more: http://github.com/javan/whenever
21
+
22
+ # every 1.day do
23
+ # rake "load[DAILY.md]"
24
+ # end
data/sig/aigency.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Aigency
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aigency
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Fred Snyder
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: fileutils
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.8'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.8'
26
+ - !ruby/object:Gem::Dependency
27
+ name: ruby_llm
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.15'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.15'
40
+ - !ruby/object:Gem::Dependency
41
+ name: thor
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.5'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.5'
54
+ email:
55
+ - fsnyder@castwide.com
56
+ executables:
57
+ - aigency
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - README.md
62
+ - Rakefile
63
+ - exe/aigency
64
+ - lib/aigency.rb
65
+ - lib/aigency/aigent.rb
66
+ - lib/aigency/shell.rb
67
+ - lib/aigency/tool.rb
68
+ - lib/aigency/tools.rb
69
+ - lib/aigency/usability.rb
70
+ - lib/aigency/version.rb
71
+ - lib/aigency/workspace.rb
72
+ - lib/aigency/workspace/directory_deleter.rb
73
+ - lib/aigency/workspace/directory_reader.rb
74
+ - lib/aigency/workspace/file_deleter.rb
75
+ - lib/aigency/workspace/file_reader.rb
76
+ - lib/aigency/workspace/file_writer.rb
77
+ - scaffold/.gitignore
78
+ - scaffold/Gemfile
79
+ - scaffold/IDENTITY.md
80
+ - scaffold/README.md
81
+ - scaffold/Rakefile
82
+ - scaffold/config/aigent.yml
83
+ - scaffold/config/schedule.rb
84
+ - sig/aigency.rbs
85
+ licenses: []
86
+ metadata: {}
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 3.2.0
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 4.0.11
102
+ specification_version: 4
103
+ summary: A framework for building agentic AI workers.
104
+ test_files: []