rails_orchestrator 0.1.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad0ec91cbefd4c8e690a05ebf1dc856b8a150b327ef2831ac97ff48353be8306
4
- data.tar.gz: 616f18aa8047af98fe2c7ce928cdf7cba36d813afdb4110c36e73ff017362782
3
+ metadata.gz: 0d2f38594952e49f0d659722dcb48401a6d5f2427d48781ac2048433bd84557b
4
+ data.tar.gz: 4841db7dd3ff00b4befc942d7706ea13474a94a6efb1405070ef20472c10335f
5
5
  SHA512:
6
- metadata.gz: 3953ffb04fcd799ee99ee9209158feec39781b68236db0548627ac55932c62a39e16b67e3904dbb8e71f53413a3d80fdcf7092bf8301c140e496b05603a363ca
7
- data.tar.gz: 9b86fb351556db3be676bcb13752cf54bd103768d46ecc47611fa209a5f59843b36e6647e055cfc1b46f25070df7c05103bc28c8c261f0b6e5c9cee7633409ed
6
+ metadata.gz: 53eaa449566c589561b0a091be660075ec3a91c97a5f8559878c11e9477fdb22f4f748b9ca56917fa471c030a7277f913614d5e3898baf8a994eb52f25581b45
7
+ data.tar.gz: 14d45a700a36801ce88878ee3ba9624637943245177fbdf4c2aee7b8f6ca44ec98d13b593c7e12c884a1f4380e100df55280303cf05e5bf6ac474bf9aa1bbd4b
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require spec_helper
2
+ --format documentation
data/.rubocop.yml ADDED
@@ -0,0 +1,35 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+
6
+ Style/StringLiterals:
7
+ EnforcedStyle: double_quotes
8
+
9
+ Style/StringLiteralsInInterpolation:
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
14
+
15
+ Metrics/BlockLength:
16
+ Exclude:
17
+ - "spec/**/*"
18
+ - "*.gemspec"
19
+
20
+ Metrics/AbcSize:
21
+ Exclude:
22
+ - "spec/**/*"
23
+
24
+ Metrics/MethodLength:
25
+ Exclude:
26
+ - "spec/**/*"
27
+
28
+ Style/Documentation:
29
+ Enabled: false
30
+
31
+ Gemspec/DevelopmentDependencies:
32
+ Enabled: false
33
+
34
+ Gemspec/RequireMFA:
35
+ Enabled: false
data/README.md CHANGED
@@ -1,31 +1,72 @@
1
1
  # RailsOrchestrator
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
4
-
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rails_orchestrator`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ A framework to build AI agents in Rails applications. Send conversations to a local LLM (Ollama, etc.) and get responses.
6
4
 
7
5
  ## Installation
8
6
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
7
+ Add to your Gemfile:
10
8
 
11
- Install the gem and add to the application's Gemfile by executing:
9
+ ```ruby
10
+ gem "rails_orchestrator"
11
+ ```
12
12
 
13
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
13
+ Then run `bundle install`.
14
14
 
15
- If bundler is not being used to manage dependencies, install the gem by executing:
15
+ ## Usage
16
16
 
17
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
17
+ ### Configuration
18
18
 
19
- ## Usage
19
+ ```ruby
20
+ RailsOrchestrator.configure do |config|
21
+ config.base_url = "http://localhost:11434" # default
22
+ config.model = "llama3" # default
23
+ config.request_timeout = 120 # default, in seconds
24
+ end
25
+ ```
20
26
 
21
- TODO: Write usage instructions here
27
+ ### Sending a conversation
22
28
 
23
- ## Development
29
+ ```ruby
30
+ conversation = RailsOrchestrator::Conversation.new
31
+ conversation.system("You are a helpful assistant.")
32
+ conversation.user("Hello!")
33
+
34
+ client = RailsOrchestrator::Client.new
35
+ response = client.chat(conversation)
36
+ response.content # => "Hi there!"
37
+ ```
38
+
39
+ You can also pass plain arrays:
24
40
 
25
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake none` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
41
+ ```ruby
42
+ response = client.chat([{ role: "user", content: "Hello" }])
43
+ ```
26
44
 
27
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
45
+ ### Error handling
46
+
47
+ ```ruby
48
+ begin
49
+ response = client.chat(conversation)
50
+ rescue RailsOrchestrator::ConnectionError => e
51
+ # Network failure (connection refused, timeout, etc.)
52
+ rescue RailsOrchestrator::ApiError => e
53
+ e.status # HTTP status code
54
+ e.body # Raw response body
55
+ end
56
+ ```
57
+
58
+ ## Development
59
+
60
+ ```sh
61
+ bundle install
62
+ bundle exec rspec
63
+ bundle exec rubocop
64
+ ```
28
65
 
29
66
  ## Contributing
30
67
 
31
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rails_orchestrator.
68
+ Bug reports and pull requests are welcome on GitHub at https://github.com/jpmsantana/rails_orchestrator.
69
+
70
+ ## License
71
+
72
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,4 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
- task default: %i[]
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+ require "uri"
6
+
7
+ module RailsOrchestrator
8
+ class Client
9
+ def initialize(config: nil)
10
+ @config = config || RailsOrchestrator.configuration
11
+ end
12
+
13
+ def chat(messages)
14
+ messages = messages.to_a if messages.is_a?(Conversation)
15
+ messages = normalize_messages(messages)
16
+
17
+ body = { model: @config.model, messages: messages, stream: false }
18
+ Response.new(post("/api/chat", body))
19
+ end
20
+
21
+ private
22
+
23
+ def normalize_messages(messages)
24
+ messages.map do |msg|
25
+ if msg.is_a?(Hash)
26
+ { role: msg[:role] || msg["role"], content: msg[:content] || msg["content"] }
27
+ else
28
+ msg.to_h
29
+ end
30
+ end
31
+ end
32
+
33
+ def post(path, body)
34
+ uri = URI.join(@config.base_url, path)
35
+ response = execute_request(uri, body)
36
+ handle_response(response)
37
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Net::OpenTimeout, Net::ReadTimeout, SocketError => e
38
+ raise ConnectionError, "Failed to connect to #{@config.base_url}: #{e.message}"
39
+ end
40
+
41
+ def execute_request(uri, body)
42
+ request = Net::HTTP::Post.new(uri)
43
+ request["Content-Type"] = "application/json"
44
+ request.body = JSON.generate(body)
45
+
46
+ http = Net::HTTP.new(uri.host, uri.port)
47
+ http.read_timeout = @config.request_timeout
48
+ http.open_timeout = @config.request_timeout
49
+ http.request(request)
50
+ end
51
+
52
+ def handle_response(response)
53
+ unless response.is_a?(Net::HTTPSuccess)
54
+ raise ApiError.new(
55
+ "API request failed with status #{response.code}",
56
+ status: response.code.to_i, body: response.body
57
+ )
58
+ end
59
+
60
+ JSON.parse(response.body)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsOrchestrator
4
+ class Configuration
5
+ attr_accessor :base_url, :model, :request_timeout
6
+
7
+ def initialize
8
+ @base_url = "http://localhost:11434"
9
+ @model = "llama3"
10
+ @request_timeout = 120
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsOrchestrator
4
+ class Conversation
5
+ include Enumerable
6
+
7
+ def initialize
8
+ @messages = []
9
+ end
10
+
11
+ def system(content)
12
+ @messages << Message.new(role: "system", content: content)
13
+ self
14
+ end
15
+
16
+ def user(content)
17
+ @messages << Message.new(role: "user", content: content)
18
+ self
19
+ end
20
+
21
+ def assistant(content)
22
+ @messages << Message.new(role: "assistant", content: content)
23
+ self
24
+ end
25
+
26
+ def each(&block)
27
+ @messages.each(&block)
28
+ end
29
+
30
+ def to_a
31
+ @messages.map(&:to_h)
32
+ end
33
+
34
+ def size
35
+ @messages.size
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsOrchestrator
4
+ class Error < StandardError; end
5
+ class ConnectionError < Error; end
6
+
7
+ class ApiError < Error
8
+ attr_reader :status, :body
9
+
10
+ def initialize(message, status:, body:)
11
+ @status = status
12
+ @body = body
13
+ super(message)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsOrchestrator
4
+ class Message
5
+ attr_reader :role, :content
6
+
7
+ def initialize(role:, content:)
8
+ @role = role.to_s
9
+ @content = content
10
+ end
11
+
12
+ def to_h
13
+ { role: @role, content: @content }
14
+ end
15
+
16
+ def ==(other)
17
+ other.is_a?(Message) && role == other.role && content == other.content
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsOrchestrator
4
+ class Response
5
+ attr_reader :raw
6
+
7
+ def initialize(raw)
8
+ @raw = raw
9
+ end
10
+
11
+ def content
12
+ # Ollama format
13
+ if raw.key?("message")
14
+ raw.dig("message", "content")
15
+ # OpenAI-compatible format
16
+ elsif raw.key?("choices")
17
+ raw.dig("choices", 0, "message", "content")
18
+ end
19
+ end
20
+
21
+ def model
22
+ raw["model"]
23
+ end
24
+
25
+ def done?
26
+ raw["done"] == true
27
+ end
28
+ end
29
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsOrchestrator
4
- VERSION = "0.1.0"
4
+ VERSION = "1.0.0"
5
5
  end
@@ -1,7 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "rails_orchestrator/version"
4
+ require_relative "rails_orchestrator/errors"
5
+ require_relative "rails_orchestrator/configuration"
6
+ require_relative "rails_orchestrator/message"
7
+ require_relative "rails_orchestrator/conversation"
8
+ require_relative "rails_orchestrator/response"
9
+ require_relative "rails_orchestrator/client"
4
10
 
5
11
  module RailsOrchestrator
6
- class Error < StandardError; end
12
+ class << self
13
+ def configuration
14
+ @configuration ||= Configuration.new
15
+ end
16
+
17
+ def configure
18
+ yield(configuration)
19
+ end
20
+
21
+ def reset_configuration!
22
+ @configuration = Configuration.new
23
+ end
24
+ end
7
25
  end
@@ -9,7 +9,9 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ["jpmsantana14@gmail.com"]
10
10
 
11
11
  spec.summary = "A framework to build AI agents in Rails applications with tool support, memory and orchestration."
12
- spec.description = "RailsOrchestrator provides a structured framework for building AI agents in Ruby on Rails applications. It includes tool support, memory management, and orchestration capabilities for composing complex agent workflows."
12
+ spec.description = "RailsOrchestrator provides a structured framework for building AI agents " \
13
+ "in Ruby on Rails applications. It includes tool support, memory management, " \
14
+ "and orchestration capabilities for composing complex agent workflows."
13
15
  spec.homepage = "https://github.com/jpmsantana/rails_orchestrator"
14
16
  spec.license = "MIT"
15
17
  spec.required_ruby_version = ">= 3.0.0"
@@ -32,9 +34,6 @@ Gem::Specification.new do |spec|
32
34
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
33
35
  spec.require_paths = ["lib"]
34
36
 
35
- # Uncomment to register a new dependency of your gem
36
- # spec.add_dependency "example-gem", "~> 1.0"
37
-
38
- # For more information and examples about making a new gem, check out our
39
- # guide at: https://bundler.io/guides/creating_gem.html
37
+ spec.add_development_dependency "rspec", "~> 3.0"
38
+ spec.add_development_dependency "rubocop", "~> 1.21"
40
39
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_orchestrator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - João Paulo Moreira Sant'ana
@@ -9,7 +9,35 @@ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
11
  date: 2026-02-02 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.21'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.21'
13
41
  description: RailsOrchestrator provides a structured framework for building AI agents
14
42
  in Ruby on Rails applications. It includes tool support, memory management, and
15
43
  orchestration capabilities for composing complex agent workflows.
@@ -19,10 +47,18 @@ executables: []
19
47
  extensions: []
20
48
  extra_rdoc_files: []
21
49
  files:
50
+ - ".rspec"
51
+ - ".rubocop.yml"
22
52
  - LICENSE.txt
23
53
  - README.md
24
54
  - Rakefile
25
55
  - lib/rails_orchestrator.rb
56
+ - lib/rails_orchestrator/client.rb
57
+ - lib/rails_orchestrator/configuration.rb
58
+ - lib/rails_orchestrator/conversation.rb
59
+ - lib/rails_orchestrator/errors.rb
60
+ - lib/rails_orchestrator/message.rb
61
+ - lib/rails_orchestrator/response.rb
26
62
  - lib/rails_orchestrator/version.rb
27
63
  - rails_orchestrator.gemspec
28
64
  - sig/rails_orchestrator.rbs