raix 0.8.0 → 0.8.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 +8 -1
- data/Gemfile.lock +1 -1
- data/README.md +57 -0
- data/lib/raix/chat_completion.rb +34 -3
- data/lib/raix/function_dispatch.rb +2 -3
- data/lib/raix/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04e086a8f8f010507fef64ba8f2a1fa7c4508b34d85b39d8d045088410ba041c
|
4
|
+
data.tar.gz: b6ddc5948d4d71a967321cfe664a6fb2ad6f38833c7067e0915216ce7fc64646
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1558de827080ea2fb1c0ab0a953ae4d4cb1a9f8ad1aaae0690942f78bfde31275739857948b064721aa83b0f9b963c91c4bcb8dc5be460283e88ee2294e10e64
|
7
|
+
data.tar.gz: 001c63730739473375f0bff5c7e4edb78e4247000825799cff5cd98f9ae56bf6f2a5c436f1334b03e05de3257ef081498e2c456567a70e65417c19b70ab8918b
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,11 @@
|
|
1
|
-
## [0.8.
|
1
|
+
## [0.8.2] - 2025-04-29
|
2
|
+
- Extracts function call dispatch into a public `dispatch_tool_function` that can be overridden in subclasses
|
3
|
+
- Uses `public_send` instead of `send` for better security and explicitness
|
4
|
+
|
5
|
+
## [0.8.1] - 2025-04-24
|
6
|
+
Added ability to filter tool functions (or disable completely) when calling `chat_completion`. Thanks to @parruda for the contribution.
|
7
|
+
|
8
|
+
## [0.8.0] - 2025-04-23
|
2
9
|
### Added
|
3
10
|
* **MCP integration (Experimental)** — new `Raix::MCP` concern and `mcp` DSL for declaring remote MCP servers.
|
4
11
|
* Automatically fetches `tools/list`, registers remote tools as OpenAI‑compatible function schemas, and defines proxy methods that forward `tools/call`.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -134,6 +134,41 @@ end
|
|
134
134
|
|
135
135
|
Note that for security reasons, dispatching functions only works with functions implemented using `Raix::FunctionDispatch#function` or directly on the class.
|
136
136
|
|
137
|
+
#### Tool Filtering
|
138
|
+
|
139
|
+
You can control which tools are available to the AI on a given chat completion request using the `tools` parameter in the `chat_completion` method:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
class WeatherAndTime
|
143
|
+
include Raix::ChatCompletion
|
144
|
+
include Raix::FunctionDispatch
|
145
|
+
|
146
|
+
function :check_weather, "Check the weather for a location", location: { type: "string" } do |arguments|
|
147
|
+
"The weather in #{arguments[:location]} is sunny"
|
148
|
+
end
|
149
|
+
|
150
|
+
function :get_time, "Get the current time" do |_arguments|
|
151
|
+
"The time is 12:00 PM"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
weather = WeatherAndTime.new
|
156
|
+
|
157
|
+
# Don't pass any tools to the LLM
|
158
|
+
weather.chat_completion(tools: false)
|
159
|
+
|
160
|
+
# Only pass specific tools to the LLM
|
161
|
+
weather.chat_completion(tools: [:check_weather])
|
162
|
+
|
163
|
+
# Pass all declared tools (default behavior)
|
164
|
+
weather.chat_completion
|
165
|
+
```
|
166
|
+
|
167
|
+
The `tools` parameter accepts three types of values:
|
168
|
+
- `false`: No tools are passed to the LLM
|
169
|
+
- An array of symbols: Only the specified tools are passed (raises `Raix::UndeclaredToolError` if any tool is not declared)
|
170
|
+
- Not provided: All declared tools are passed (default behavior)
|
171
|
+
|
137
172
|
#### Multiple Tool Calls
|
138
173
|
|
139
174
|
Some AI models (like GPT-4) can make multiple tool calls in a single response. When this happens, Raix will automatically handle all the function calls sequentially.
|
@@ -171,6 +206,28 @@ example.invocations
|
|
171
206
|
# => [:first, :second]
|
172
207
|
```
|
173
208
|
|
209
|
+
#### Customizing Function Dispatch
|
210
|
+
|
211
|
+
You can customize how function calls are handled by overriding the `dispatch_tool_function` in your class. This is useful if you need to add logging, caching, error handling, or other custom behavior around function calls.
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
class CustomDispatchExample
|
215
|
+
include Raix::ChatCompletion
|
216
|
+
include Raix::FunctionDispatch
|
217
|
+
|
218
|
+
function :example_tool do |arguments|
|
219
|
+
"Result from example tool"
|
220
|
+
end
|
221
|
+
|
222
|
+
def dispatch_tool_function(function_name, arguments)
|
223
|
+
puts "Calling #{function_name} with #{arguments}"
|
224
|
+
result = super
|
225
|
+
puts "Result: #{result}"
|
226
|
+
result
|
227
|
+
end
|
228
|
+
end
|
229
|
+
```
|
230
|
+
|
174
231
|
#### Manually Stopping a Loop
|
175
232
|
|
176
233
|
To loop AI components that don't interact with end users, at least one function block should invoke `stop_looping!` whenever you're ready to stop processing.
|
data/lib/raix/chat_completion.rb
CHANGED
@@ -9,6 +9,8 @@ require "openai"
|
|
9
9
|
require_relative "message_adapters/base"
|
10
10
|
|
11
11
|
module Raix
|
12
|
+
class UndeclaredToolError < StandardError; end
|
13
|
+
|
12
14
|
# The `ChatCompletion`` module is a Rails concern that provides a way to interact
|
13
15
|
# with the OpenRouter Chat Completion API via its client. The module includes a few
|
14
16
|
# methods that allow you to build a transcript of messages and then send them to
|
@@ -44,8 +46,9 @@ module Raix
|
|
44
46
|
# @option params [Boolean] :openai (false) Whether to use OpenAI's API instead of OpenRouter's.
|
45
47
|
# @option params [Boolean] :raw (false) Whether to return the raw response or dig the text content.
|
46
48
|
# @option params [Array] :messages (nil) An array of messages to use instead of the transcript.
|
49
|
+
# @option tools [Array|false] :tools (nil) Tools to pass to the LLM. If false, no tools are passed. If an array, only declared tools in the array are passed.
|
47
50
|
# @return [String|Hash] The completed chat response.
|
48
|
-
def chat_completion(params: {}, loop: false, json: false, raw: false, openai: false, save_response: true, messages: nil)
|
51
|
+
def chat_completion(params: {}, loop: false, json: false, raw: false, openai: false, save_response: true, messages: nil, tools: nil)
|
49
52
|
# set params to default values if not provided
|
50
53
|
params[:cache_at] ||= cache_at.presence
|
51
54
|
params[:frequency_penalty] ||= frequency_penalty.presence
|
@@ -63,7 +66,13 @@ module Raix
|
|
63
66
|
params[:stop] ||= stop.presence
|
64
67
|
params[:temperature] ||= temperature.presence || Raix.configuration.temperature
|
65
68
|
params[:tool_choice] ||= tool_choice.presence
|
66
|
-
params[:tools]
|
69
|
+
params[:tools] = if tools == false
|
70
|
+
nil
|
71
|
+
elsif tools.is_a?(Array)
|
72
|
+
filtered_tools(tools)
|
73
|
+
else
|
74
|
+
self.tools.presence
|
75
|
+
end
|
67
76
|
params[:top_a] ||= top_a.presence
|
68
77
|
params[:top_k] ||= top_k.presence
|
69
78
|
params[:top_logprobs] ||= top_logprobs.presence
|
@@ -123,7 +132,7 @@ module Raix
|
|
123
132
|
function_name = tool_call["function"]["name"]
|
124
133
|
raise "Unauthorized function call: #{function_name}" unless self.class.functions.map { |f| f[:name].to_sym }.include?(function_name.to_sym)
|
125
134
|
|
126
|
-
|
135
|
+
dispatch_tool_function(function_name, arguments.with_indifferent_access)
|
127
136
|
end
|
128
137
|
end
|
129
138
|
|
@@ -180,8 +189,30 @@ module Raix
|
|
180
189
|
@transcript ||= []
|
181
190
|
end
|
182
191
|
|
192
|
+
# Dispatches a tool function call with the given function name and arguments.
|
193
|
+
# This method can be overridden in subclasses to customize how function calls are handled.
|
194
|
+
#
|
195
|
+
# @param function_name [String] The name of the function to call
|
196
|
+
# @param arguments [Hash] The arguments to pass to the function
|
197
|
+
# @return [Object] The result of the function call
|
198
|
+
def dispatch_tool_function(function_name, arguments)
|
199
|
+
public_send(function_name, arguments)
|
200
|
+
end
|
201
|
+
|
183
202
|
private
|
184
203
|
|
204
|
+
def filtered_tools(tool_names)
|
205
|
+
return nil if tool_names.blank?
|
206
|
+
|
207
|
+
requested_tools = tool_names.map(&:to_sym)
|
208
|
+
available_tool_names = tools.map { |tool| tool.dig(:function, :name).to_sym }
|
209
|
+
|
210
|
+
undeclared_tools = requested_tools - available_tool_names
|
211
|
+
raise UndeclaredToolError, "Undeclared tools: #{undeclared_tools.join(", ")}" if undeclared_tools.any?
|
212
|
+
|
213
|
+
tools.select { |tool| requested_tools.include?(tool.dig(:function, :name).to_sym) }
|
214
|
+
end
|
215
|
+
|
185
216
|
def openai_request(params:, model:, messages:)
|
186
217
|
if params[:prediction]
|
187
218
|
params.delete(:max_completion_tokens)
|
@@ -94,10 +94,7 @@ module Raix
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def chat_completion(**chat_completion_args)
|
97
|
-
raise "No functions defined" if self.class.functions.blank?
|
98
|
-
|
99
97
|
self.chat_completion_args = chat_completion_args
|
100
|
-
|
101
98
|
super
|
102
99
|
end
|
103
100
|
|
@@ -109,6 +106,8 @@ module Raix
|
|
109
106
|
end
|
110
107
|
|
111
108
|
def tools
|
109
|
+
return [] unless self.class.functions
|
110
|
+
|
112
111
|
self.class.functions.map { |function| { type: "function", function: } }
|
113
112
|
end
|
114
113
|
end
|
data/lib/raix/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: raix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Obie Fernandez
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-04-
|
10
|
+
date: 2025-04-30 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: activesupport
|