active_agent_ai 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: 3f8e59ee6101735d458933d0da5e9eb6e8f3bd39df7071398d7249e6f890cea6
4
+ data.tar.gz: e99fc40d871ccedc862e0bea72527189bdc172ae3b69f7c7fec41e5a3ddf2776
5
+ SHA512:
6
+ metadata.gz: 95549528b0c33c08f926796aa726e8a961da50e13659813e7594c061078dabf932e1ba32e65a90a19679b43df1ebdd985dee5d307a67c3e0c6f7d550dee6d31d
7
+ data.tar.gz: 4a6cd7a3ff52d930d796e70886e50deec8903a05468cf59df4a6d8c886490bfe1bde3b1db63dc73005131cf39618029aa140623cdafcd7dde71ed9444d4bb794
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aditya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction: including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDINGRem, BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # active_agent 🤖
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/active_agent_ai.svg)](https://badge.fury.io/rb/active_agent_ai)
4
+ [![GEM Downloads](https://img.shields.io/gem/dt/active_agent_ai.svg)](https://rubygems.org/gems/active_agent_ai)
5
+ [![CI Status](https://github.com/aditya-8108/active_agent/actions/workflows/ci.yml/badge.svg)](https://github.com/aditya-8108/active_agent/actions/workflows/ci.yml)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ **The Native Multi-Agent AI Framework for Ruby & Rails.**
9
+
10
+ Inspired by Python's [CrewAI](https://github.com/crewAIInc/crewAI) and [Microsoft AutoGen](https://github.com/microsoft/autogen), [`active_agent`](https://github.com/aditya-8108/active_agent) provides a clean, idiomatic Ruby DSL to orchestrate teams of autonomous AI agents with roles, backstories, tools, tasks, and multi-provider LLMs.
11
+
12
+ ---
13
+
14
+ ## Key Features 🚀
15
+
16
+ - 👥 **Autonomous Agent Teams**: Define specialized personas (`Agent`) with goals, backstories, and assigned capabilities.
17
+ - 🛠️ **Custom Executable Tools**: Agents dynamically select and execute custom Ruby tools (`ActiveAgent::Tool`) to perform real-world tasks (Web Search, Database Queries, API calls).
18
+ - 📋 **Task Orchestration**: Assign discrete objectives (`Task`) with expected outputs and context passing across workflow steps.
19
+ - 🌐 **Multi-Provider LLM Adapters**: Built-in support for **OpenAI** (`gpt-4o`), **Anthropic Claude** (`claude-3-5-sonnet`), **Google Gemini** (`gemini-1.5-flash`), and **Ollama (Local AI)**.
20
+ - ⚡ **Sequential & Parallel Processes**: Run agent teams in sequential pipelines where outputs pass from step to step.
21
+
22
+ ---
23
+
24
+ ## Installation
25
+
26
+ Add this line to your application's Gemfile:
27
+
28
+ ```ruby
29
+ gem 'active_agent_ai'
30
+ ```
31
+
32
+ And then execute:
33
+ ```bash
34
+ bundle install
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Quickstart Example
40
+
41
+ Define tools, agents, tasks, and kick off your agent team in 100% native Ruby:
42
+
43
+ ```ruby
44
+ require 'active_agent'
45
+
46
+ # 1. Define a Custom Executable Tool
47
+ class WebSearchTool < ActiveAgent::Tool
48
+ description "Searches the web for latest software benchmarks and language features"
49
+ param :query, type: :string, desc: "Search query", required: true
50
+
51
+ def perform(query:)
52
+ # Execute actual search or API call here
53
+ "Ruby 3.4 introduces Prism parser by default and 20% YJIT performance gains."
54
+ end
55
+ end
56
+
57
+ # 2. Define Specialized AI Agents
58
+ researcher = ActiveAgent::Agent.new(
59
+ role: "Senior Tech Researcher",
60
+ goal: "Find cutting-edge developments in Ruby & Rails",
61
+ backstory: "An expert language analyst with 10 years of compiler and AST experience.",
62
+ tools: [WebSearchTool],
63
+ provider: :openai # or :claude, :gemini, :ollama
64
+ )
65
+
66
+ writer = ActiveAgent::Agent.new(
67
+ role: "Technical Journalist",
68
+ goal: "Draft engaging tech articles from technical research reports",
69
+ backstory: "A skilled writer capable of explaining complex software benchmarks simply.",
70
+ provider: :openai
71
+ )
72
+
73
+ # 3. Define Tasks
74
+ research_task = ActiveAgent::Task.new(
75
+ description: "Research Ruby 3.4 JIT benchmarks and Prism parser updates",
76
+ expected_output: "Detailed technical report with benchmarks",
77
+ agent: researcher
78
+ )
79
+
80
+ write_task = ActiveAgent::Task.new(
81
+ description: "Write a high-converting blog post based on the research findings",
82
+ expected_output: "Formatted Markdown article ready for publication",
83
+ agent: writer
84
+ )
85
+
86
+ # 4. Assemble and Kickoff Team
87
+ team = ActiveAgent::Team.new(
88
+ agents: [researcher, writer],
89
+ tasks: [research_task, write_task],
90
+ process: :sequential
91
+ )
92
+
93
+ result = team.kickoff
94
+ puts result
95
+ ```
96
+
97
+ ---
98
+
99
+ ## Multi-Provider Support
100
+
101
+ `active_agent` seamlessly works with all top LLM providers:
102
+
103
+ ```ruby
104
+ # OpenAI
105
+ agent = ActiveAgent::Agent.new(role: "Coder", goal: "Refactor", provider: :openai, model: "gpt-4o")
106
+
107
+ # Anthropic Claude
108
+ agent = ActiveAgent::Agent.new(role: "Analyst", goal: "Audit", provider: :claude, model: "claude-3-5-sonnet-20241022")
109
+
110
+ # Google Gemini
111
+ agent = ActiveAgent::Agent.new(role: "Data Engine", goal: "Parse", provider: :gemini, model: "gemini-1.5-flash")
112
+
113
+ # Ollama (100% Local AI - No API keys needed)
114
+ agent = ActiveAgent::Agent.new(role: "Local Assistant", goal: "Summarize", provider: :ollama, model: "llama3")
115
+ ```
116
+
117
+ ---
118
+
119
+ ## License
120
+
121
+ MIT License.
data/bin/active_agent ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require_relative '../lib/active_agent'
6
+
7
+ ActiveAgent::CLI.start(ARGV)
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require_relative '../lib/active_agent'
6
+
7
+ ActiveAgent::CLI.start(ARGV)
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'providers/openai'
4
+ require_relative 'providers/anthropic'
5
+ require_relative 'providers/gemini'
6
+ require_relative 'providers/ollama'
7
+
8
+ module ActiveAgent
9
+ # Defines an autonomous AI Agent with persona, tools, and execution capabilities.
10
+ class Agent
11
+ attr_reader :role, :goal, :backstory, :tools, :provider
12
+
13
+ def initialize(role:, goal:, backstory: '', tools: [], provider: :openai, model: nil, api_key: nil, api_url: nil)
14
+ @role = role
15
+ @goal = goal
16
+ @backstory = backstory
17
+ @tools = tools.map { |t| t.is_a?(Class) ? t.new : t }
18
+ @provider = build_provider(provider, model: model, api_key: api_key, api_url: api_url)
19
+ end
20
+
21
+ def execute_task(task_description, expected_output: nil, context: nil)
22
+ system_prompt = build_system_prompt
23
+ user_prompt = build_user_prompt(task_description, expected_output: expected_output, context: context)
24
+
25
+ messages = [
26
+ { role: 'system', content: system_prompt },
27
+ { role: 'user', content: user_prompt }
28
+ ]
29
+
30
+ max_tool_loops = 5
31
+ loop_count = 0
32
+
33
+ while loop_count < max_tool_loops
34
+ response = @provider.chat(messages: messages, tools: @tools)
35
+ content = response[:content]
36
+ tool_calls = response[:tool_calls]
37
+
38
+ return content unless tool_calls && !tool_calls.empty?
39
+
40
+ messages << { role: 'assistant', content: content, tool_calls: tool_calls }
41
+
42
+ tool_calls.each do |tool_call|
43
+ func_name = tool_call.dig('function', 'name')
44
+ raw_args = tool_call.dig('function', 'arguments')
45
+ args = raw_args.is_a?(String) ? JSON.parse(raw_args, symbolize_names: true) : raw_args
46
+
47
+ matching_tool = @tools.find { |t| t.class.name.split('::').last.downcase == func_name.to_s.downcase }
48
+ tool_result = if matching_tool
49
+ matching_tool.perform(**args)
50
+ else
51
+ "Tool #{func_name} not found."
52
+ end
53
+
54
+ messages << { role: 'tool', tool_call_id: tool_call['id'], content: tool_result.to_s }
55
+ end
56
+ loop_count += 1
57
+ end
58
+
59
+ messages.last[:content] || 'Execution completed.'
60
+ end
61
+
62
+ private
63
+
64
+ def build_system_prompt
65
+ prompt = "You are #{@role}.\n"
66
+ prompt += "Your Goal: #{@goal}\n"
67
+ prompt += "Your Backstory: #{@backstory}\n" if @backstory && !@backstory.empty?
68
+ prompt += "\nRespond precisely and execute assigned tasks professionally."
69
+ prompt
70
+ end
71
+
72
+ def build_user_prompt(task_description, expected_output:, context:)
73
+ prompt = "Task: #{task_description}\n"
74
+ prompt += "Expected Output: #{expected_output}\n" if expected_output
75
+ prompt += "\nContext from Previous Steps:\n#{context}\n" if context && !context.to_s.strip.empty?
76
+ prompt
77
+ end
78
+
79
+ def build_provider(provider, model:, api_key:, api_url:)
80
+ return provider if provider.is_a?(Providers::Base)
81
+
82
+ case provider.to_s.downcase.to_sym
83
+ when :anthropic, :claude
84
+ Providers::Anthropic.new(model: model || 'claude-3-5-sonnet-20241022', api_key: api_key, api_url: api_url)
85
+ when :gemini
86
+ Providers::Gemini.new(model: model || 'gemini-1.5-flash', api_key: api_key, api_url: api_url)
87
+ when :ollama
88
+ Providers::Ollama.new(model: model || 'llama3', api_key: api_key, api_url: api_url)
89
+ else
90
+ Providers::OpenAI.new(model: model || 'gpt-4o-mini', api_key: api_key, api_url: api_url)
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ module ActiveAgent
6
+ class CLI < Thor
7
+ desc 'kickoff FILE', 'Run a multi-agent team workflow defined in a Ruby file'
8
+ def kickoff(file_path)
9
+ unless File.exist?(file_path)
10
+ say_error "File not found: #{file_path}", :red
11
+ exit(1)
12
+ end
13
+
14
+ say "🚀 Launching ActiveAgent team from #{file_path}...", :green
15
+ load file_path
16
+ end
17
+
18
+ desc 'version', 'Show ActiveAgent version'
19
+ def version
20
+ say "ActiveAgent v#{ActiveAgent::VERSION}", :blue
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module ActiveAgent
6
+ module Providers
7
+ class Anthropic < Base
8
+ DEFAULT_URL = 'https://api.anthropic.com/v1/messages'
9
+
10
+ def initialize(model: 'claude-3-5-sonnet-20241022', api_key: ENV.fetch('ANTHROPIC_API_KEY', nil), api_url: nil)
11
+ url = api_url || DEFAULT_URL
12
+ super(model: model, api_key: api_key, api_url: url)
13
+
14
+ raise Error, 'ANTHROPIC_API_KEY is required for Anthropic provider' unless @api_key || ENV['MOCK_AGENT_RESPONSE']
15
+ end
16
+
17
+ def chat(messages:, tools: [])
18
+ headers = {
19
+ 'Content-Type' => 'application/json',
20
+ 'x-api-key' => @api_key,
21
+ 'anthropic-version' => '2023-06-01'
22
+ }
23
+
24
+ system_message = messages.find { |m| m[:role] == 'system' }&.fetch(:content, '')
25
+ user_messages = messages.reject { |m| m[:role] == 'system' }
26
+
27
+ payload = {
28
+ model: @model,
29
+ max_tokens: 4096,
30
+ system: system_message,
31
+ messages: user_messages,
32
+ temperature: 0.2
33
+ }
34
+
35
+ data = http_post(@api_url, headers, payload)
36
+ content = data.dig('content', 0, 'text')
37
+
38
+ { content: content, tool_calls: nil }
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'uri'
6
+
7
+ module ActiveAgent
8
+ module Providers
9
+ class Base
10
+ attr_reader :model, :api_key, :api_url
11
+
12
+ def initialize(model:, api_key: nil, api_url: nil)
13
+ @model = model
14
+ @api_key = api_key
15
+ @api_url = api_url
16
+ end
17
+
18
+ def chat(messages:, tools: [])
19
+ raise NotImplementedError, "#{self.class.name}#chat must be implemented"
20
+ end
21
+
22
+ private
23
+
24
+ def http_post(url, headers, body)
25
+ return mock_response if ENV['MOCK_AGENT_RESPONSE']
26
+
27
+ uri = URI(url)
28
+ request = Net::HTTP::Post.new(uri)
29
+ headers.each { |k, v| request[k] = v }
30
+ request.body = body.is_a?(String) ? body : body.to_json
31
+
32
+ use_ssl = uri.scheme == 'https'
33
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: use_ssl) do |http|
34
+ http.request(request)
35
+ end
36
+
37
+ raise ActiveAgent::Error, "API Error (#{uri.host}): #{response.code} - #{response.body}" unless response.is_a?(Net::HTTPSuccess)
38
+
39
+ JSON.parse(response.body)
40
+ end
41
+
42
+ def mock_response
43
+ {
44
+ 'choices' => [
45
+ {
46
+ 'message' => {
47
+ 'content' => ENV.fetch('MOCK_AGENT_RESPONSE', nil)
48
+ }
49
+ }
50
+ ]
51
+ }
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module ActiveAgent
6
+ module Providers
7
+ class Gemini < Base
8
+ DEFAULT_URL = 'https://generativelanguage.googleapis.com/v1beta/openai/chat/completions'
9
+
10
+ def initialize(model: 'gemini-1.5-flash', api_key: nil, api_url: nil)
11
+ key = api_key || ENV.fetch('GEMINI_API_KEY', nil) || ENV.fetch('GOOGLE_API_KEY', nil)
12
+ url = api_url || DEFAULT_URL
13
+ super(model: model, api_key: key, api_url: url)
14
+
15
+ raise Error, 'GEMINI_API_KEY or GOOGLE_API_KEY is required for Gemini provider' unless @api_key || ENV['MOCK_AGENT_RESPONSE']
16
+ end
17
+
18
+ def chat(messages:, tools: [])
19
+ headers = {
20
+ 'Content-Type' => 'application/json',
21
+ 'Authorization' => "Bearer #{@api_key}"
22
+ }
23
+
24
+ payload = {
25
+ model: @model,
26
+ messages: messages,
27
+ temperature: 0.2
28
+ }
29
+
30
+ data = http_post(@api_url, headers, payload)
31
+ message = data.dig('choices', 0, 'message') || {}
32
+
33
+ { content: message['content'], tool_calls: nil }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module ActiveAgent
6
+ module Providers
7
+ class Ollama < Base
8
+ DEFAULT_URL = 'http://localhost:11434/v1/chat/completions'
9
+
10
+ def initialize(model: 'llama3', api_key: nil, api_url: nil)
11
+ url = api_url || DEFAULT_URL
12
+ super(model: model, api_key: api_key, api_url: url)
13
+ end
14
+
15
+ def chat(messages:, tools: [])
16
+ headers = { 'Content-Type' => 'application/json' }
17
+ payload = {
18
+ model: @model,
19
+ messages: messages,
20
+ temperature: 0.2
21
+ }
22
+
23
+ data = http_post(@api_url, headers, payload)
24
+ message = data.dig('choices', 0, 'message') || {}
25
+
26
+ { content: message['content'], tool_calls: nil }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module ActiveAgent
6
+ module Providers
7
+ class OpenAI < Base
8
+ DEFAULT_URL = 'https://api.openai.com/v1/chat/completions'
9
+
10
+ def initialize(model: 'gpt-4o-mini', api_key: ENV.fetch('OPENAI_API_KEY', nil), api_url: nil)
11
+ url = api_url || DEFAULT_URL
12
+ super(model: model, api_key: api_key, api_url: url)
13
+
14
+ raise Error, 'OPENAI_API_KEY is required for OpenAI provider' unless @api_key || ENV['MOCK_AGENT_RESPONSE']
15
+ end
16
+
17
+ def chat(messages:, tools: [])
18
+ headers = {
19
+ 'Content-Type' => 'application/json',
20
+ 'Authorization' => "Bearer #{@api_key}"
21
+ }
22
+
23
+ payload = {
24
+ model: @model,
25
+ messages: messages,
26
+ temperature: 0.2
27
+ }
28
+
29
+ payload[:tools] = tools.map { |t| { type: 'function', function: t.to_openai_function } } if tools && !tools.empty?
30
+
31
+ data = http_post(@api_url, headers, payload)
32
+ message = data.dig('choices', 0, 'message') || {}
33
+
34
+ {
35
+ content: message['content'],
36
+ tool_calls: message['tool_calls']
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ # Defines a discrete task to be executed by an assigned Agent.
5
+ class Task
6
+ attr_reader :description, :expected_output, :agent
7
+ attr_accessor :output
8
+
9
+ def initialize(description:, agent:, expected_output: nil)
10
+ @description = description
11
+ @agent = agent
12
+ @expected_output = expected_output
13
+ @output = nil
14
+ end
15
+
16
+ def execute(context: nil)
17
+ @output = @agent.execute_task(
18
+ @description,
19
+ expected_output: @expected_output,
20
+ context: context
21
+ )
22
+ @output
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ # Orchestrates multiple agents and tasks in sequential or hierarchical processes.
5
+ class Team
6
+ attr_reader :agents, :tasks, :process
7
+
8
+ def initialize(agents:, tasks:, process: :sequential)
9
+ @agents = agents
10
+ @tasks = tasks
11
+ @process = process
12
+ end
13
+
14
+ def kickoff
15
+ accumulated_context = []
16
+
17
+ @tasks.each_with_index do |task, index|
18
+ context_str = accumulated_context.last
19
+ say_verbose "🤖 Task #{index + 1}/#{@tasks.size} [#{task.agent.role}]: #{task.description[0..80]}..."
20
+
21
+ result = task.execute(context: context_str)
22
+ accumulated_context << result
23
+ end
24
+
25
+ accumulated_context.last
26
+ end
27
+
28
+ private
29
+
30
+ def say_verbose(msg)
31
+ puts msg if ENV['VERBOSE'] || $stdout.tty?
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ # Abstract base class for tools that Agents can execute.
5
+ class Tool
6
+ class << self
7
+ def description(desc = nil)
8
+ if desc
9
+ @description = desc
10
+ else
11
+ @description || "Tool: #{name}"
12
+ end
13
+ end
14
+
15
+ def param(name, type: :string, desc: '', required: true)
16
+ params_schema[name] = { type: type, description: desc, required: required }
17
+ end
18
+
19
+ def params_schema
20
+ @params_schema ||= {}
21
+ end
22
+
23
+ def to_openai_function
24
+ properties = {}
25
+ required_fields = []
26
+
27
+ params_schema.each do |param_name, options|
28
+ properties[param_name] = {
29
+ type: options[:type].to_s,
30
+ description: options[:description]
31
+ }
32
+ required_fields << param_name.to_s if options[:required]
33
+ end
34
+
35
+ {
36
+ name: name.split('::').last.downcase,
37
+ description: description,
38
+ parameters: {
39
+ type: 'object',
40
+ properties: properties,
41
+ required: required_fields
42
+ }
43
+ }
44
+ end
45
+ end
46
+
47
+ def to_openai_function
48
+ self.class.to_openai_function
49
+ end
50
+
51
+ def perform(**_args)
52
+ raise NotImplementedError, "#{self.class.name}#perform must be implemented"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'active_agent/version'
4
+ require_relative 'active_agent/tool'
5
+ require_relative 'active_agent/providers/base'
6
+ require_relative 'active_agent/providers/openai'
7
+ require_relative 'active_agent/providers/anthropic'
8
+ require_relative 'active_agent/providers/gemini'
9
+ require_relative 'active_agent/providers/ollama'
10
+ require_relative 'active_agent/agent'
11
+ require_relative 'active_agent/task'
12
+ require_relative 'active_agent/team'
13
+ require_relative 'active_agent/cli'
14
+
15
+ module ActiveAgent
16
+ class Error < StandardError; end
17
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'active_agent'
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_agent_ai
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Aditya
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-08-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.50'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.50'
83
+ description: Orchestrate autonomous AI agent teams with roles, tools, tasks, and multi-provider
84
+ LLMs in 100% native Ruby.
85
+ email:
86
+ executables:
87
+ - active_agent_ai
88
+ - active_agent
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - LICENSE
93
+ - README.md
94
+ - bin/active_agent
95
+ - bin/active_agent_ai
96
+ - lib/active_agent.rb
97
+ - lib/active_agent/agent.rb
98
+ - lib/active_agent/cli.rb
99
+ - lib/active_agent/providers/anthropic.rb
100
+ - lib/active_agent/providers/base.rb
101
+ - lib/active_agent/providers/gemini.rb
102
+ - lib/active_agent/providers/ollama.rb
103
+ - lib/active_agent/providers/openai.rb
104
+ - lib/active_agent/task.rb
105
+ - lib/active_agent/team.rb
106
+ - lib/active_agent/tool.rb
107
+ - lib/active_agent/version.rb
108
+ - lib/active_agent_ai.rb
109
+ homepage: https://github.com/aditya-8108/active_agent
110
+ licenses:
111
+ - MIT
112
+ metadata:
113
+ homepage_uri: https://github.com/aditya-8108/active_agent
114
+ source_code_uri: https://github.com/aditya-8108/active_agent
115
+ rubygems_mfa_required: 'true'
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 3.0.0
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubygems_version: 3.3.5
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Native Multi-Agent AI Framework for Ruby & Rails
135
+ test_files: []