phronomy 0.5.0 → 0.5.2
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 +71 -0
- data/README.md +21 -11
- data/lib/phronomy/ruby_llm_patches.rb +15 -11
- data/lib/phronomy/tool/mcp_tool.rb +28 -7
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy.rb +0 -38
- 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: f2129e4cbe20c3831530f0a8ef810abe272174195cbce5198207fec6bf255eff
|
|
4
|
+
data.tar.gz: f9a0152759518cb2d85126ee5fb7a57b96e00a0ed7b8acffd54c57de91ed0c18
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0af940bc5279c64221d000e4c545c5e2696f2f14c405326785786b94cf9afc567619e94e79aefbfc68b0656d761ebe88b7604d1cbacf75e82ae3aca6d39b9e3f
|
|
7
|
+
data.tar.gz: 71d4ef2f73a4e914d4dd85fffef0643a1725857dc6bf51dce5c39e78f34a0bfdc69d2de59be574396175f3a2ea5841e502bde75d082ddb30f15ee30a1a598037
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,77 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [0.5.2] - 2026-05-20
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- **CHANGELOG correction for v0.5.1 MCP fix** (#90): The v0.5.1 entry
|
|
15
|
+
incorrectly stated that a `Mutex` was added to `StdioTransport#rpc_call`.
|
|
16
|
+
The actual fix was per-instance transport ownership (each `McpTool` instance
|
|
17
|
+
creates its own transport in `initialize`). Corrected the description.
|
|
18
|
+
|
|
19
|
+
### Enhancements
|
|
20
|
+
|
|
21
|
+
- **Add `McpTool#close`** (#92): Tool instances now expose a `close` method
|
|
22
|
+
that shuts down the underlying stdio child process (`StdioTransport`) or
|
|
23
|
+
releases the HTTP connection (`HttpTransport`). This gives callers a
|
|
24
|
+
deterministic way to clean up resources instead of relying on GC.
|
|
25
|
+
|
|
26
|
+
### Maintenance
|
|
27
|
+
|
|
28
|
+
- **Archive stale Rails integration design doc** (#91): Added an archived
|
|
29
|
+
notice to `spec/design/17_rails_integration.md` clarifying that Rails
|
|
30
|
+
integration was removed in v0.3.0–v0.5.1 and the document is for
|
|
31
|
+
historical reference only.
|
|
32
|
+
|
|
33
|
+
- **Remove zombie `register_workflow_context` API** (#93): The
|
|
34
|
+
`Phronomy.register_workflow_context`, `workflow_context_registry`, and
|
|
35
|
+
`reset_workflow_context_registry!` methods (along with the backing
|
|
36
|
+
`@workflow_context_registry` and `@registry_mutex` module-level variables)
|
|
37
|
+
were removed from `lib/phronomy.rb`. These existed to support the
|
|
38
|
+
`StateStore` deserialization guard, which was removed in a prior release.
|
|
39
|
+
The API had no remaining callers in the codebase and was not listed in
|
|
40
|
+
the README stability table.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## [0.5.1] - 2026-05-21
|
|
45
|
+
|
|
46
|
+
### Bug Fixes
|
|
47
|
+
|
|
48
|
+
- **Remove broken Rails generator and Railtie** (#85): The generator template
|
|
49
|
+
referenced `Phronomy::ActiveRecord::ActsAs` which no longer exists, causing
|
|
50
|
+
`rails generate phronomy:install` to produce broken model files. Removed
|
|
51
|
+
`lib/generators/`, `lib/phronomy/railtie.rb`, and all references in
|
|
52
|
+
`lib/phronomy.rb`.
|
|
53
|
+
|
|
54
|
+
- **Fix MCP transport ownership** (#86): `McpTool` no longer stores a shared
|
|
55
|
+
transport at class level. `from_server` now uses a short-lived transport only
|
|
56
|
+
to fetch tool metadata and calls `close` immediately after. Each tool instance
|
|
57
|
+
creates its own `StdioTransport` or `HttpTransport` in `initialize`, so
|
|
58
|
+
concurrent callers (e.g. via `Orchestrator#dispatch_parallel`) never share
|
|
59
|
+
stdio streams. No `Mutex` is needed. Also adds missing
|
|
60
|
+
`require "securerandom"` and a no-op `HttpTransport#close` for interface
|
|
61
|
+
consistency.
|
|
62
|
+
|
|
63
|
+
### Documentation
|
|
64
|
+
|
|
65
|
+
- **README corrections** (#87): Remove stale Rails generator installation
|
|
66
|
+
instructions. Clarify that `TeamCoordinator` worker state is local to a
|
|
67
|
+
single `invoke` call (not persistent across calls). Annotate app-level
|
|
68
|
+
examples (`09_rails_chat`, `15_rails_secure_chat`, `18_rails_agent_job`,
|
|
69
|
+
`19_trust_pipeline`) as requiring external infrastructure. Add scope note
|
|
70
|
+
to `Agent::Orchestrator` section.
|
|
71
|
+
|
|
72
|
+
### Maintenance
|
|
73
|
+
|
|
74
|
+
- **Add version guard to `ruby_llm_patches.rb`** (#88): The monkey-patch for
|
|
75
|
+
the upstream `handle_error_chunk` bug (ruby_llm <= 1.15.0) is now
|
|
76
|
+
gated behind a `Gem::Version` check so upgrading ruby_llm will
|
|
77
|
+
automatically disable the override.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
10
81
|
## [0.5.0] - 2026-05-20
|
|
11
82
|
|
|
12
83
|
### 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"
|
|
@@ -394,6 +391,13 @@ search_tool = Phronomy::Tool::McpTool.from_server(
|
|
|
394
391
|
)
|
|
395
392
|
```
|
|
396
393
|
|
|
394
|
+
Call `close` when the tool is no longer needed to shut down the underlying
|
|
395
|
+
child process (stdio transport) or release the HTTP connection:
|
|
396
|
+
|
|
397
|
+
```ruby
|
|
398
|
+
search_tool.close
|
|
399
|
+
```
|
|
400
|
+
|
|
397
401
|
### Conversation History — passing prior messages
|
|
398
402
|
|
|
399
403
|
Phronomy does not manage conversation history internally. The application owns the
|
|
@@ -491,15 +495,21 @@ bundle exec ruby NN_example_name/run.rb
|
|
|
491
495
|
| 06 | `06_guardrails/` | Input/output guardrails |
|
|
492
496
|
| 07 | `07_tracing/` | Custom observability with Langfuse tracer |
|
|
493
497
|
| 08 | `08_mcp_tool/` | MCP tool integration |
|
|
494
|
-
| 09 | `09_rails_chat/` | Rails chat app with ActionCable streaming |
|
|
495
498
|
| 10 | `10_context_management/` | Token budget and context pruning |
|
|
496
499
|
| 11 | `11_agent_streaming/` | Streaming agent responses |
|
|
497
500
|
| 12 | `12_prompt_template/` | Advanced prompt templates |
|
|
498
501
|
| 13 | `13_mcp_http_tool/` | HTTP-based MCP tool server |
|
|
499
502
|
| 14 | `14_code_review/` | Automated code review agent |
|
|
500
|
-
| 15 | `15_rails_secure_chat/` | Rails chat with PII guardrails |
|
|
501
503
|
| 16 | `16_before_completion_hook/` | Global/class/instance before_completion hooks |
|
|
502
504
|
| 17 | `17_multi_agent_handoff/` | Hub-and-spoke agent routing via Runner |
|
|
505
|
+
|
|
506
|
+
The following examples are **app-level demos** (Rails apps or advanced pipelines)
|
|
507
|
+
that require additional infrastructure (a running Rails server, database, etc.):
|
|
508
|
+
|
|
509
|
+
| # | Directory | What it demonstrates |
|
|
510
|
+
|---|-----------|----------------------|
|
|
511
|
+
| 09 | `09_rails_chat/` | Rails chat app with ActionCable streaming |
|
|
512
|
+
| 15 | `15_rails_secure_chat/` | Rails chat with PII guardrails |
|
|
503
513
|
| 18 | `18_rails_agent_job/` | Rails app with AgentJob + ActionCable streaming |
|
|
504
514
|
| 19 | `19_trust_pipeline/` | Generator-Verifier pattern with citation tracking, self-review loop and confidence gate |
|
|
505
515
|
|
|
@@ -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,22 @@ 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
|
-
|
|
82
|
+
@mcp_transport.call_tool(tool_name, args)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Allow callers to deterministically shut down the underlying child
|
|
86
|
+
# process (stdio) or release the HTTP connection. For HttpTransport
|
|
87
|
+
# this is a no-op. Calling execute after close raises an error.
|
|
88
|
+
klass.define_method(:close) do
|
|
89
|
+
@mcp_transport.close
|
|
73
90
|
end
|
|
74
91
|
|
|
75
92
|
klass
|
|
@@ -108,7 +125,6 @@ module Phronomy
|
|
|
108
125
|
wait_thr = @wait_thr
|
|
109
126
|
@stderr_thread = nil
|
|
110
127
|
@wait_thr = nil
|
|
111
|
-
# Join outside the lock to avoid blocking on slow joins.
|
|
112
128
|
stderr_thread&.join(1)
|
|
113
129
|
wait_thr&.join(5)
|
|
114
130
|
end
|
|
@@ -208,6 +224,11 @@ module Phronomy
|
|
|
208
224
|
@read_timeout = read_timeout
|
|
209
225
|
end
|
|
210
226
|
|
|
227
|
+
# HTTP connections are stateless; close is a no-op, defined so that
|
|
228
|
+
# both transport classes share the same interface as StdioTransport.
|
|
229
|
+
def close
|
|
230
|
+
end
|
|
231
|
+
|
|
211
232
|
# Retrieve the tool definition from the server using MCP `tools/list`.
|
|
212
233
|
# @param tool_name [String]
|
|
213
234
|
# @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
|
|
@@ -53,42 +50,7 @@ module Phronomy
|
|
|
53
50
|
end
|
|
54
51
|
end
|
|
55
52
|
|
|
56
|
-
# Registry for WorkflowContext classes that may be serialized to external stores
|
|
57
|
-
# (Redis, DB). Call +register_workflow_context+ at application startup so that
|
|
58
|
-
# only known classes can be deserialized.
|
|
59
|
-
@workflow_context_registry = nil
|
|
60
|
-
@registry_mutex = Mutex.new
|
|
61
|
-
|
|
62
53
|
class << self
|
|
63
|
-
# Register one or more WorkflowContext classes that are allowed to be
|
|
64
|
-
# deserialized by StateStore backends. When at least one class is registered,
|
|
65
|
-
# only registered classes will be accepted by
|
|
66
|
-
# +StateStore::Base#safe_state_class+.
|
|
67
|
-
#
|
|
68
|
-
# Call this once at application startup (e.g. in a Rails initializer).
|
|
69
|
-
#
|
|
70
|
-
# @param classes [Array<Class>] classes including Phronomy::WorkflowContext
|
|
71
|
-
# @example
|
|
72
|
-
# Phronomy.register_workflow_context(ScanContext, OtherContext)
|
|
73
|
-
def register_workflow_context(*classes)
|
|
74
|
-
@registry_mutex.synchronize do
|
|
75
|
-
@workflow_context_registry ||= {}
|
|
76
|
-
classes.each do |klass|
|
|
77
|
-
raise ArgumentError, "#{klass.inspect} is not a Class" unless klass.is_a?(Class)
|
|
78
|
-
@workflow_context_registry[klass.name] = klass
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
# Returns the current registry Hash, or nil when no class has been registered.
|
|
84
|
-
# @return [Hash{String => Class}, nil]
|
|
85
|
-
attr_reader :workflow_context_registry
|
|
86
|
-
|
|
87
|
-
# Clears the registry. Primarily used in tests.
|
|
88
|
-
def reset_workflow_context_registry!
|
|
89
|
-
@registry_mutex.synchronize { @workflow_context_registry = nil }
|
|
90
|
-
end
|
|
91
|
-
|
|
92
54
|
def configuration
|
|
93
55
|
@configuration ||= Configuration.new
|
|
94
56
|
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.2
|
|
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
|