phronomy 0.5.0 → 0.5.1
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 +4 -4
- data/CHANGELOG.md +33 -0
- data/README.md +14 -11
- data/lib/phronomy/ruby_llm_patches.rb +15 -11
- data/lib/phronomy/tool/mcp_tool.rb +21 -7
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy.rb +0 -3
- metadata +2 -7
- data/lib/generators/phronomy/install/install_generator.rb +0 -41
- data/lib/generators/phronomy/install/templates/create_phronomy_messages.rb.tt +0 -15
- data/lib/generators/phronomy/install/templates/initializer.rb.tt +0 -18
- data/lib/generators/phronomy/install/templates/message_model.rb.tt +0 -8
- data/lib/phronomy/railtie.rb +0 -39
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8ca63f10e2d505005a6011a8755135e0dea1c3d8e8013ae3b2ea1d3b5ecf13d3
|
|
4
|
+
data.tar.gz: 420ec691725b6450a0430cdce90372c13da4e73d7013a630b2aa33a7b72e496d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 300b155e482fe0b0015bba5d3985c8d37f2599828d9d87763cc5d9925c3bf399cbee46a658d48a79e152d9b410505609e35a89d3b02db632d51b85280938dc8c
|
|
7
|
+
data.tar.gz: 88184d595d04eb1ed1be8c6ec145476a5e1f7e6e02e52658f9d80ad3893a29fbcfc377c736b7c0de10deb14e6105bd9594d6b950bd2fb3afda800e770a2219c4
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [0.5.1] - 2026-05-21
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- **Remove broken Rails generator and Railtie** (#85): The generator template
|
|
15
|
+
referenced `Phronomy::ActiveRecord::ActsAs` which no longer exists, causing
|
|
16
|
+
`rails generate phronomy:install` to produce broken model files. Removed
|
|
17
|
+
`lib/generators/`, `lib/phronomy/railtie.rb`, and all references in
|
|
18
|
+
`lib/phronomy.rb`.
|
|
19
|
+
|
|
20
|
+
- **Fix thread-safety of `StdioTransport#rpc_call`** (#86): Concurrent calls
|
|
21
|
+
to the same `McpTool` instance could interleave JSON-RPC writes and reads,
|
|
22
|
+
corrupting request/response pairing. A `Mutex` is now held around each
|
|
23
|
+
write+read cycle. Also adds the missing `require "securerandom"`.
|
|
24
|
+
|
|
25
|
+
### Documentation
|
|
26
|
+
|
|
27
|
+
- **README corrections** (#87): Remove stale Rails generator installation
|
|
28
|
+
instructions. Clarify that `TeamCoordinator` worker state is local to a
|
|
29
|
+
single `invoke` call (not persistent across calls). Annotate app-level
|
|
30
|
+
examples (`09_rails_chat`, `15_rails_secure_chat`, `18_rails_agent_job`,
|
|
31
|
+
`19_trust_pipeline`) as requiring external infrastructure. Add scope note
|
|
32
|
+
to `Agent::Orchestrator` section.
|
|
33
|
+
|
|
34
|
+
### Maintenance
|
|
35
|
+
|
|
36
|
+
- **Add version guard to `ruby_llm_patches.rb`** (#88): The monkey-patch for
|
|
37
|
+
the upstream `handle_error_chunk` bug (ruby_llm <= 1.15.0) is now
|
|
38
|
+
gated behind a `Gem::Version` check so upgrading ruby_llm will
|
|
39
|
+
automatically disable the override.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
10
43
|
## [0.5.0] - 2026-05-20
|
|
11
44
|
|
|
12
45
|
### Breaking Changes
|
data/README.md
CHANGED
|
@@ -20,7 +20,7 @@ It provides composable building blocks — Workflows, Agents, Tools, Guardrails,
|
|
|
20
20
|
| **Multi-agent** — Agent-as-Tool pattern and hub-and-spoke handoff routing | Beta |
|
|
21
21
|
| **GeneratorVerifier** — Generator-Verifier loop with injectable prompt builders/parsers | Beta |
|
|
22
22
|
| **Agent::Orchestrator** — Parallel subagent dispatch, fan-out, and `subagent` DSL | Beta |
|
|
23
|
-
| **Agent::TeamCoordinator** — Agent teams pattern: LLM coordinator +
|
|
23
|
+
| **Agent::TeamCoordinator** — Agent teams pattern: LLM coordinator + stateful worker pool with task queue (worker-local message history per run) | Beta |
|
|
24
24
|
| **Agent::SharedState** — Shared state pattern: peer agents collaborate via a shared KnowledgeStore; `member` DSL with per-agent instructions and `coordination` team protocol | Experimental |
|
|
25
25
|
| **Guardrails** — Input/output validation; built-in PII and prompt-injection detectors | Beta |
|
|
26
26
|
| **Output Parser** — JSON and Struct-mapped parsers for structured LLM responses | Stable |
|
|
@@ -42,14 +42,6 @@ Then run:
|
|
|
42
42
|
bundle install
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
For Rails apps, run the install generator after bundling:
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
rails generate phronomy:install
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
This creates a configuration initializer.
|
|
52
|
-
|
|
53
45
|
## Quick Start
|
|
54
46
|
|
|
55
47
|
### Agent — ReAct tool-calling agent
|
|
@@ -279,6 +271,11 @@ end
|
|
|
279
271
|
|
|
280
272
|
### Agent::Orchestrator — Parallel subagent dispatch
|
|
281
273
|
|
|
274
|
+
> **Note:** `dispatch_parallel` and `fan_out` use plain Ruby threads and are
|
|
275
|
+
> intended for small-scale fan-out (a handful of subagents). For large-scale
|
|
276
|
+
> parallel dispatch, manage concurrency (thread pools, rate limiting) at the
|
|
277
|
+
> application level.
|
|
278
|
+
|
|
282
279
|
```ruby
|
|
283
280
|
class ResearchOrchestrator < Phronomy::Agent::Orchestrator
|
|
284
281
|
model "gpt-4o"
|
|
@@ -491,15 +488,21 @@ bundle exec ruby NN_example_name/run.rb
|
|
|
491
488
|
| 06 | `06_guardrails/` | Input/output guardrails |
|
|
492
489
|
| 07 | `07_tracing/` | Custom observability with Langfuse tracer |
|
|
493
490
|
| 08 | `08_mcp_tool/` | MCP tool integration |
|
|
494
|
-
| 09 | `09_rails_chat/` | Rails chat app with ActionCable streaming |
|
|
495
491
|
| 10 | `10_context_management/` | Token budget and context pruning |
|
|
496
492
|
| 11 | `11_agent_streaming/` | Streaming agent responses |
|
|
497
493
|
| 12 | `12_prompt_template/` | Advanced prompt templates |
|
|
498
494
|
| 13 | `13_mcp_http_tool/` | HTTP-based MCP tool server |
|
|
499
495
|
| 14 | `14_code_review/` | Automated code review agent |
|
|
500
|
-
| 15 | `15_rails_secure_chat/` | Rails chat with PII guardrails |
|
|
501
496
|
| 16 | `16_before_completion_hook/` | Global/class/instance before_completion hooks |
|
|
502
497
|
| 17 | `17_multi_agent_handoff/` | Hub-and-spoke agent routing via Runner |
|
|
498
|
+
|
|
499
|
+
The following examples are **app-level demos** (Rails apps or advanced pipelines)
|
|
500
|
+
that require additional infrastructure (a running Rails server, database, etc.):
|
|
501
|
+
|
|
502
|
+
| # | Directory | What it demonstrates |
|
|
503
|
+
|---|-----------|----------------------|
|
|
504
|
+
| 09 | `09_rails_chat/` | Rails chat app with ActionCable streaming |
|
|
505
|
+
| 15 | `15_rails_secure_chat/` | Rails chat with PII guardrails |
|
|
503
506
|
| 18 | `18_rails_agent_job/` | Rails app with AgentJob + ActionCable streaming |
|
|
504
507
|
| 19 | `19_trust_pipeline/` | Generator-Verifier pattern with citation tracking, self-review loop and confidence gate |
|
|
505
508
|
|
|
@@ -3,18 +3,22 @@
|
|
|
3
3
|
# Patches for upstream ruby_llm bugs that have not yet been released.
|
|
4
4
|
# Remove each patch once the fix is available in a published gem version.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
# Guard: apply monkey-patches only to affected ruby_llm versions so that
|
|
7
|
+
# upgrading the gem does not silently keep dead overrides in place.
|
|
8
|
+
if Gem::Version.new(RubyLLM::VERSION) <= Gem::Version.new("1.15.0")
|
|
9
|
+
module RubyLLM
|
|
10
|
+
module Streaming
|
|
11
|
+
private
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
# Upstream ruby_llm <= 1.15.0 assumes the SSE error chunk always has two
|
|
14
|
+
# lines ("event: error\ndata: {...}") and uses a fixed index [1], which
|
|
15
|
+
# raises NoMethodError when some providers (e.g. Qwen) return a single-line
|
|
16
|
+
# chunk ("data: {...}"). This patch finds the data line by content instead.
|
|
17
|
+
def handle_error_chunk(chunk, env)
|
|
18
|
+
data_line = chunk.split("\n").find { |l| l.start_with?("data: ") } || chunk.split("\n")[0]
|
|
19
|
+
error_data = data_line.delete_prefix("data: ")
|
|
20
|
+
parse_error_from_json(error_data, env, "Failed to parse error chunk")
|
|
21
|
+
end
|
|
18
22
|
end
|
|
19
23
|
end
|
|
20
24
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
require "net/http"
|
|
5
5
|
require "open3"
|
|
6
|
+
require "securerandom"
|
|
6
7
|
require "shellwords"
|
|
7
8
|
require "uri"
|
|
8
9
|
|
|
@@ -36,9 +37,13 @@ module Phronomy
|
|
|
36
37
|
# @param tool_name [String] the tool name as registered in the MCP server
|
|
37
38
|
# @return [McpTool] a configured subclass instance ready for use with an Agent
|
|
38
39
|
def from_server(server_uri, tool_name:)
|
|
40
|
+
# Use a short-lived transport only to query the tool definition,
|
|
41
|
+
# then close it. Each McpTool instance creates its own transport
|
|
42
|
+
# so that concurrent callers never share IO streams.
|
|
39
43
|
transport = build_transport(server_uri)
|
|
40
44
|
tool_def = transport.fetch_tool(tool_name)
|
|
41
|
-
|
|
45
|
+
transport.close
|
|
46
|
+
build_tool_class(tool_name, server_uri, tool_def).new
|
|
42
47
|
end
|
|
43
48
|
|
|
44
49
|
private
|
|
@@ -55,10 +60,10 @@ module Phronomy
|
|
|
55
60
|
end
|
|
56
61
|
end
|
|
57
62
|
|
|
58
|
-
def build_tool_class(tool_name,
|
|
63
|
+
def build_tool_class(tool_name, server_uri, tool_def)
|
|
59
64
|
klass = Class.new(McpTool)
|
|
60
65
|
klass.instance_variable_set(:@mcp_tool_name, tool_name)
|
|
61
|
-
klass.instance_variable_set(:@
|
|
66
|
+
klass.instance_variable_set(:@mcp_server_uri, server_uri)
|
|
62
67
|
|
|
63
68
|
# Register description and params from the MCP tool definition.
|
|
64
69
|
klass.description(tool_def[:description] || tool_name)
|
|
@@ -66,10 +71,15 @@ module Phronomy
|
|
|
66
71
|
klass.param(p[:name].to_sym, type: p[:type]&.to_sym || :string, desc: p[:description].to_s)
|
|
67
72
|
end
|
|
68
73
|
|
|
69
|
-
#
|
|
74
|
+
# Each instance creates its own transport so concurrent agent threads
|
|
75
|
+
# never share IO streams, eliminating the need for synchronisation.
|
|
76
|
+
klass.define_method(:initialize) do
|
|
77
|
+
uri = self.class.instance_variable_get(:@mcp_server_uri)
|
|
78
|
+
@mcp_transport = self.class.send(:build_transport, uri)
|
|
79
|
+
end
|
|
80
|
+
|
|
70
81
|
klass.define_method(:execute) do |**args|
|
|
71
|
-
|
|
72
|
-
.call_tool(tool_name, args)
|
|
82
|
+
@mcp_transport.call_tool(tool_name, args)
|
|
73
83
|
end
|
|
74
84
|
|
|
75
85
|
klass
|
|
@@ -108,7 +118,6 @@ module Phronomy
|
|
|
108
118
|
wait_thr = @wait_thr
|
|
109
119
|
@stderr_thread = nil
|
|
110
120
|
@wait_thr = nil
|
|
111
|
-
# Join outside the lock to avoid blocking on slow joins.
|
|
112
121
|
stderr_thread&.join(1)
|
|
113
122
|
wait_thr&.join(5)
|
|
114
123
|
end
|
|
@@ -208,6 +217,11 @@ module Phronomy
|
|
|
208
217
|
@read_timeout = read_timeout
|
|
209
218
|
end
|
|
210
219
|
|
|
220
|
+
# HTTP connections are stateless; close is a no-op, defined so that
|
|
221
|
+
# both transport classes share the same interface as StdioTransport.
|
|
222
|
+
def close
|
|
223
|
+
end
|
|
224
|
+
|
|
211
225
|
# Retrieve the tool definition from the server using MCP `tools/list`.
|
|
212
226
|
# @param tool_name [String]
|
|
213
227
|
# @return [Hash] { description:, parameters: }
|
data/lib/phronomy/version.rb
CHANGED
data/lib/phronomy.rb
CHANGED
|
@@ -5,7 +5,6 @@ require "ruby_llm"
|
|
|
5
5
|
require_relative "phronomy/ruby_llm_patches"
|
|
6
6
|
|
|
7
7
|
loader = Zeitwerk::Loader.for_gem
|
|
8
|
-
loader.ignore(File.expand_path("generators", __dir__))
|
|
9
8
|
# Teach Zeitwerk that "llm" maps to "LLM" so that file names such as
|
|
10
9
|
# ruby_llm_embeddings.rb resolve to RubyLLMEmbeddings (not RubyLlmEmbeddings).
|
|
11
10
|
loader.inflector.inflect("ruby_llm_embeddings" => "RubyLLMEmbeddings")
|
|
@@ -14,8 +13,6 @@ loader.setup
|
|
|
14
13
|
require_relative "phronomy/version"
|
|
15
14
|
require_relative "phronomy/token_usage"
|
|
16
15
|
|
|
17
|
-
require "phronomy/railtie" if defined?(Rails::Railtie)
|
|
18
|
-
|
|
19
16
|
module Phronomy
|
|
20
17
|
# Exception hierarchy
|
|
21
18
|
class Error < StandardError; end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: phronomy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Raizo T.C.S
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ruby_llm
|
|
@@ -64,10 +64,6 @@ files:
|
|
|
64
64
|
- CHANGELOG.md
|
|
65
65
|
- README.md
|
|
66
66
|
- Rakefile
|
|
67
|
-
- lib/generators/phronomy/install/install_generator.rb
|
|
68
|
-
- lib/generators/phronomy/install/templates/create_phronomy_messages.rb.tt
|
|
69
|
-
- lib/generators/phronomy/install/templates/initializer.rb.tt
|
|
70
|
-
- lib/generators/phronomy/install/templates/message_model.rb.tt
|
|
71
67
|
- lib/phronomy.rb
|
|
72
68
|
- lib/phronomy/agent.rb
|
|
73
69
|
- lib/phronomy/agent/base.rb
|
|
@@ -132,7 +128,6 @@ files:
|
|
|
132
128
|
- lib/phronomy/output_parser/json_parser.rb
|
|
133
129
|
- lib/phronomy/output_parser/structured_parser.rb
|
|
134
130
|
- lib/phronomy/prompt_template.rb
|
|
135
|
-
- lib/phronomy/railtie.rb
|
|
136
131
|
- lib/phronomy/ruby_llm_patches.rb
|
|
137
132
|
- lib/phronomy/runnable.rb
|
|
138
133
|
- lib/phronomy/splitter.rb
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "rails/generators"
|
|
4
|
-
require "rails/generators/active_record"
|
|
5
|
-
|
|
6
|
-
module Phronomy
|
|
7
|
-
module Generators
|
|
8
|
-
# Rails generator that installs Phronomy into a Rails app.
|
|
9
|
-
# Creates an initializer and database migrations:
|
|
10
|
-
# - phronomy_messages (conversation history persistence)
|
|
11
|
-
#
|
|
12
|
-
# Usage:
|
|
13
|
-
# rails generate phronomy:install
|
|
14
|
-
class InstallGenerator < ::Rails::Generators::Base
|
|
15
|
-
include ::Rails::Generators::Migration
|
|
16
|
-
|
|
17
|
-
source_root File.expand_path("templates", __dir__)
|
|
18
|
-
|
|
19
|
-
desc "Creates a Phronomy initializer and database migrations."
|
|
20
|
-
|
|
21
|
-
def self.next_migration_number(dirname)
|
|
22
|
-
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def copy_initializer
|
|
26
|
-
template "initializer.rb.tt", "config/initializers/phronomy.rb"
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def create_messages_migration
|
|
30
|
-
migration_template(
|
|
31
|
-
"create_phronomy_messages.rb.tt",
|
|
32
|
-
"db/migrate/create_phronomy_messages.rb"
|
|
33
|
-
)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def create_message_model
|
|
37
|
-
template "message_model.rb.tt", "app/models/phronomy_message.rb"
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
class CreatePhronomyMessages < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
2
|
-
def change
|
|
3
|
-
create_table :phronomy_messages do |t|
|
|
4
|
-
t.string :thread_id, null: false
|
|
5
|
-
t.string :role, null: false
|
|
6
|
-
t.text :content
|
|
7
|
-
t.text :tool_calls_json
|
|
8
|
-
t.string :model_id
|
|
9
|
-
t.timestamps
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
add_index :phronomy_messages, :thread_id
|
|
13
|
-
add_index :phronomy_messages, [:thread_id, :created_at]
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Phronomy configuration initializer.
|
|
4
|
-
# Customize LLM settings and agent defaults here.
|
|
5
|
-
Phronomy.configure do |config|
|
|
6
|
-
# Default LLM model used when no model is specified on an agent or chain.
|
|
7
|
-
# config.default_model = "gpt-4o-mini"
|
|
8
|
-
|
|
9
|
-
# Maximum graph recursion depth (node steps per invoke).
|
|
10
|
-
# config.recursion_limit = 25
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# RubyLLM provider credentials.
|
|
14
|
-
# Prefer Rails credentials (config/credentials.yml.enc) over ENV vars.
|
|
15
|
-
RubyLLM.configure do |c|
|
|
16
|
-
c.openai_api_key = Rails.application.credentials.dig(:openai, :api_key) || ENV["OPENAI_API_KEY"]
|
|
17
|
-
c.anthropic_api_key = Rails.application.credentials.dig(:anthropic, :api_key) || ENV["ANTHROPIC_API_KEY"]
|
|
18
|
-
end
|
data/lib/phronomy/railtie.rb
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
# Railtie providing Rails integration for Phronomy.
|
|
5
|
-
# Loaded only when Rails is present.
|
|
6
|
-
class Railtie < ::Rails::Railtie
|
|
7
|
-
# Registers generator paths (rails generate phronomy:install).
|
|
8
|
-
generators do
|
|
9
|
-
require "generators/phronomy/install/install_generator"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# Fills in defaults not already set by a phronomy.rb initializer.
|
|
13
|
-
initializer "phronomy.configure_defaults" do
|
|
14
|
-
# Passes LLM API keys from Rails credentials to RubyLLM (only when present).
|
|
15
|
-
# Use ::Rails to avoid resolving to Phronomy::Rails by accident.
|
|
16
|
-
if ::Rails.application.credentials.respond_to?(:openai_api_key) &&
|
|
17
|
-
::Rails.application.credentials.openai_api_key
|
|
18
|
-
RubyLLM.configure do |c|
|
|
19
|
-
c.openai_api_key = ::Rails.application.credentials.openai_api_key
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
if ::Rails.application.credentials.respond_to?(:anthropic_api_key) &&
|
|
24
|
-
::Rails.application.credentials.anthropic_api_key
|
|
25
|
-
RubyLLM.configure do |c|
|
|
26
|
-
c.anthropic_api_key = ::Rails.application.credentials.anthropic_api_key
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Loads Phronomy::Rails::AgentJob when both ActionCable and ActiveJob are present.
|
|
32
|
-
initializer "phronomy.agent_job" do
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Loads Phronomy ActiveRecord extensions when ActiveRecord is available.
|
|
36
|
-
initializer "phronomy.active_record", after: "active_record.initialize_database" do
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|