raix 0.8.1 → 0.8.3

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: 2de11b289a7c245c49e865735e1abc67ff671f02a9f23fb89d262d3ff83e6157
4
- data.tar.gz: f8cd493f6f018ddd6b981f944786635b6800ca9beac4480e0a4c3c08bb7b8392
3
+ metadata.gz: 29fc354187c6971947ca178f55eae07ec23af8f2f3435dec89e58a9231de5a94
4
+ data.tar.gz: 70c5289b69f81f741b3e41fd1bb69d081f22e78aa65de34e8cb11c6190e700c3
5
5
  SHA512:
6
- metadata.gz: 4d26f6ffad99abb7eaf6c8ef072393d75625e4762206d0d1f94c811e9d44747fa2e9048d5a8951484ded2861ecd5ebac69ea39bf6163432a411e2f9e427b0533
7
- data.tar.gz: 893d062ab1f23b6c6a47dc715a7c98a3886dbe092645642e74bdb97ad80b2b4f637305b95acc6e6a8984cfe6defcdf020410233f5f818cba16bbbd0c5f49b5ed
6
+ metadata.gz: 4fbeb53566e02702163055d966e4ed14e8bc4a76a2ebb76191bcfea6175e250943c55817e1cbe4325c42a890c261365231f984bf1ce3855af6929a640457ca15
7
+ data.tar.gz: 942185162e40960170e64c5c4d93edc58ba37429efb0b19ded2f997fa60d70d2aaafad1788694d964ba5173e0ef0dfbab781b6e61c17f6e996f7dad083984197
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [0.8.3] - 2025-04-30
2
+ - Adds optional ActiveSupport Cache parameter to `dispatch_tool_function` for caching tool calls
3
+
4
+ ## [0.8.2] - 2025-04-29
5
+ - Extracts function call dispatch into a public `dispatch_tool_function` that can be overridden in subclasses
6
+ - Uses `public_send` instead of `send` for better security and explicitness
7
+
1
8
  ## [0.8.1] - 2025-04-24
2
9
  Added ability to filter tool functions (or disable completely) when calling `chat_completion`. Thanks to @parruda for the contribution.
3
10
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- raix (0.8.1)
4
+ raix (0.8.3)
5
5
  activesupport (>= 6.0)
6
6
  faraday-retry (~> 2.0)
7
7
  open_router (~> 0.2)
data/README.md CHANGED
@@ -206,6 +206,59 @@ example.invocations
206
206
  # => [:first, :second]
207
207
  ```
208
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
+ #### Function Call Caching
231
+
232
+ You can use ActiveSupport's Cache to cache function call results, which can be particularly useful for expensive operations or external API calls that don't need to be repeated frequently.
233
+
234
+ ```ruby
235
+ class CachedFunctionExample
236
+ include Raix::ChatCompletion
237
+ include Raix::FunctionDispatch
238
+
239
+ function :expensive_operation do |arguments|
240
+ "Result of expensive operation with #{arguments}"
241
+ end
242
+
243
+ # Override dispatch_tool_function to enable caching for all functions
244
+ def dispatch_tool_function(function_name, arguments)
245
+ # Pass the cache to the superclass implementation
246
+ super(function_name, arguments, cache: Rails.cache)
247
+ end
248
+ end
249
+ ```
250
+
251
+ The caching mechanism works by:
252
+ 1. Passing the cache object through `dispatch_tool_function` to the function implementation
253
+ 2. Using the function name and arguments as cache keys
254
+ 3. Automatically fetching from cache when available or executing the function when not cached
255
+
256
+ This is particularly useful for:
257
+ - Expensive database operations
258
+ - External API calls
259
+ - Resource-intensive computations
260
+ - Functions with deterministic outputs for the same inputs
261
+
209
262
  #### Manually Stopping a Loop
210
263
 
211
264
  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.
@@ -132,7 +132,7 @@ module Raix
132
132
  function_name = tool_call["function"]["name"]
133
133
  raise "Unauthorized function call: #{function_name}" unless self.class.functions.map { |f| f[:name].to_sym }.include?(function_name.to_sym)
134
134
 
135
- send(function_name, arguments.with_indifferent_access)
135
+ dispatch_tool_function(function_name, arguments.with_indifferent_access)
136
136
  end
137
137
  end
138
138
 
@@ -189,6 +189,17 @@ module Raix
189
189
  @transcript ||= []
190
190
  end
191
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
+ # @param cache [ActiveSupport::Cache] Optional cache object
198
+ # @return [Object] The result of the function call
199
+ def dispatch_tool_function(function_name, arguments, cache: nil)
200
+ public_send(function_name, arguments, cache)
201
+ end
202
+
192
203
  private
193
204
 
194
205
  def filtered_tools(tool_names)
@@ -54,35 +54,41 @@ module Raix
54
54
  end
55
55
  end
56
56
 
57
- define_method(name) do |arguments|
57
+ define_method(name) do |arguments, cache|
58
58
  id = SecureRandom.uuid[0, 23]
59
- instance_exec(arguments, &block).tap do |content|
60
- # add in one operation to prevent race condition and potential wrong
61
- # interleaving of tool calls in multi-threaded environments
62
- transcript << [
63
- {
64
- role: "assistant",
65
- content: nil,
66
- tool_calls: [
67
- {
68
- id:,
69
- type: "function",
70
- function: {
71
- name:,
72
- arguments: arguments.to_json
73
- }
59
+
60
+ content = if cache.present?
61
+ cache.fetch([name, arguments]) do
62
+ instance_exec(arguments, &block)
63
+ end
64
+ else
65
+ instance_exec(arguments, &block)
66
+ end
67
+
68
+ # add in one operation to prevent race condition and potential wrong
69
+ # interleaving of tool calls in multi-threaded environments
70
+ transcript << [
71
+ {
72
+ role: "assistant",
73
+ content: nil,
74
+ tool_calls: [
75
+ {
76
+ id:,
77
+ type: "function",
78
+ function: {
79
+ name:,
80
+ arguments: arguments.to_json
74
81
  }
75
- ]
76
- },
77
- {
78
- role: "tool",
79
- tool_call_id: id,
80
- name:,
81
- content: content.to_s
82
- }
83
- ]
84
- # TODO: add on_error handler as optional parameter to function
85
- end
82
+ }
83
+ ]
84
+ },
85
+ {
86
+ role: "tool",
87
+ tool_call_id: id,
88
+ name:,
89
+ content: content.to_s
90
+ }
91
+ ]
86
92
 
87
93
  chat_completion(**chat_completion_args) if loop
88
94
  end
data/lib/raix/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Raix
4
- VERSION = "0.8.1"
4
+ VERSION = "0.8.3"
5
5
  end
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.1
4
+ version: 0.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Obie Fernandez
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-25 00:00:00.000000000 Z
10
+ date: 2025-05-01 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activesupport