riffer 0.7.0 → 0.9.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.agents/architecture.md +113 -0
  3. data/.agents/code-style.md +42 -0
  4. data/.agents/providers.md +46 -0
  5. data/.agents/rdoc.md +51 -0
  6. data/.agents/testing.md +56 -0
  7. data/.release-please-manifest.json +1 -1
  8. data/AGENTS.md +21 -308
  9. data/CHANGELOG.md +17 -0
  10. data/README.md +21 -112
  11. data/Rakefile +1 -1
  12. data/docs/01_OVERVIEW.md +106 -0
  13. data/docs/02_GETTING_STARTED.md +128 -0
  14. data/docs/03_AGENTS.md +226 -0
  15. data/docs/04_TOOLS.md +342 -0
  16. data/docs/05_MESSAGES.md +173 -0
  17. data/docs/06_STREAM_EVENTS.md +191 -0
  18. data/docs/07_CONFIGURATION.md +195 -0
  19. data/docs_providers/01_PROVIDERS.md +168 -0
  20. data/docs_providers/02_AMAZON_BEDROCK.md +196 -0
  21. data/docs_providers/03_ANTHROPIC.md +211 -0
  22. data/docs_providers/04_OPENAI.md +157 -0
  23. data/docs_providers/05_TEST_PROVIDER.md +163 -0
  24. data/docs_providers/06_CUSTOM_PROVIDERS.md +304 -0
  25. data/lib/riffer/agent.rb +103 -63
  26. data/lib/riffer/config.rb +20 -12
  27. data/lib/riffer/core.rb +7 -7
  28. data/lib/riffer/helpers/class_name_converter.rb +6 -3
  29. data/lib/riffer/helpers/dependencies.rb +18 -0
  30. data/lib/riffer/helpers/validations.rb +9 -0
  31. data/lib/riffer/messages/assistant.rb +23 -1
  32. data/lib/riffer/messages/base.rb +15 -0
  33. data/lib/riffer/messages/converter.rb +15 -5
  34. data/lib/riffer/messages/system.rb +8 -1
  35. data/lib/riffer/messages/tool.rb +45 -2
  36. data/lib/riffer/messages/user.rb +8 -1
  37. data/lib/riffer/messages.rb +7 -0
  38. data/lib/riffer/providers/amazon_bedrock.rb +8 -4
  39. data/lib/riffer/providers/anthropic.rb +209 -0
  40. data/lib/riffer/providers/base.rb +17 -12
  41. data/lib/riffer/providers/open_ai.rb +7 -1
  42. data/lib/riffer/providers/repository.rb +9 -4
  43. data/lib/riffer/providers/test.rb +25 -7
  44. data/lib/riffer/providers.rb +6 -0
  45. data/lib/riffer/stream_events/base.rb +13 -1
  46. data/lib/riffer/stream_events/reasoning_delta.rb +15 -1
  47. data/lib/riffer/stream_events/reasoning_done.rb +15 -1
  48. data/lib/riffer/stream_events/text_delta.rb +14 -1
  49. data/lib/riffer/stream_events/text_done.rb +14 -1
  50. data/lib/riffer/stream_events/tool_call_delta.rb +18 -11
  51. data/lib/riffer/stream_events/tool_call_done.rb +22 -12
  52. data/lib/riffer/stream_events.rb +9 -0
  53. data/lib/riffer/tool.rb +92 -25
  54. data/lib/riffer/tools/param.rb +19 -16
  55. data/lib/riffer/tools/params.rb +28 -22
  56. data/lib/riffer/tools/response.rb +90 -0
  57. data/lib/riffer/tools.rb +6 -0
  58. data/lib/riffer/version.rb +1 -1
  59. data/lib/riffer.rb +21 -21
  60. metadata +35 -1
@@ -0,0 +1,304 @@
1
+ # Creating Custom Providers
2
+
3
+ You can create custom providers to connect Riffer to other LLM services.
4
+
5
+ ## Basic Structure
6
+
7
+ Extend `Riffer::Providers::Base` and implement the required methods:
8
+
9
+ ```ruby
10
+ class Riffer::Providers::MyProvider < Riffer::Providers::Base
11
+ def initialize(**options)
12
+ # Initialize your client
13
+ @api_key = options[:api_key] || ENV['MY_PROVIDER_API_KEY']
14
+ @client = MyProviderClient.new(api_key: @api_key)
15
+ end
16
+
17
+ private
18
+
19
+ def perform_generate_text(messages, model:, **options)
20
+ # Convert messages to provider format
21
+ formatted = convert_messages(messages)
22
+
23
+ # Call your provider's API
24
+ response = @client.generate(
25
+ model: model,
26
+ messages: formatted,
27
+ **options
28
+ )
29
+
30
+ # Return a Riffer::Messages::Assistant
31
+ Riffer::Messages::Assistant.new(
32
+ response.text,
33
+ tool_calls: extract_tool_calls(response)
34
+ )
35
+ end
36
+
37
+ def perform_stream_text(messages, model:, **options)
38
+ Enumerator.new do |yielder|
39
+ formatted = convert_messages(messages)
40
+
41
+ @client.stream(model: model, messages: formatted, **options) do |chunk|
42
+ # Yield appropriate stream events
43
+ case chunk.type
44
+ when :text
45
+ yielder << Riffer::StreamEvents::TextDelta.new(chunk.content)
46
+ when :text_done
47
+ yielder << Riffer::StreamEvents::TextDone.new(chunk.content)
48
+ when :tool_call
49
+ yielder << Riffer::StreamEvents::ToolCallDone.new(
50
+ item_id: chunk.id,
51
+ call_id: chunk.id,
52
+ name: chunk.name,
53
+ arguments: chunk.arguments
54
+ )
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def convert_messages(messages)
61
+ messages.map do |msg|
62
+ case msg
63
+ when Riffer::Messages::System
64
+ {role: "system", content: msg.content}
65
+ when Riffer::Messages::User
66
+ {role: "user", content: msg.content}
67
+ when Riffer::Messages::Assistant
68
+ convert_assistant(msg)
69
+ when Riffer::Messages::Tool
70
+ {role: "tool", tool_call_id: msg.tool_call_id, content: msg.content}
71
+ end
72
+ end
73
+ end
74
+
75
+ def convert_assistant(msg)
76
+ # Handle tool calls if present
77
+ {role: "assistant", content: msg.content, tool_calls: msg.tool_calls}
78
+ end
79
+
80
+ def extract_tool_calls(response)
81
+ return [] unless response.tool_calls
82
+
83
+ response.tool_calls.map do |tc|
84
+ {
85
+ id: tc.id,
86
+ call_id: tc.id,
87
+ name: tc.name,
88
+ arguments: tc.arguments
89
+ }
90
+ end
91
+ end
92
+ end
93
+ ```
94
+
95
+ ## Using depends_on
96
+
97
+ For lazy loading of external gems:
98
+
99
+ ```ruby
100
+ class Riffer::Providers::MyProvider < Riffer::Providers::Base
101
+ def initialize(**options)
102
+ depends_on "my_provider_gem" # Only loaded when provider is used
103
+
104
+ @client = ::MyProviderGem::Client.new(**options)
105
+ end
106
+ end
107
+ ```
108
+
109
+ ## Registering Your Provider
110
+
111
+ Add your provider to the repository:
112
+
113
+ ```ruby
114
+ # In lib/riffer/providers/repository.rb or your own code
115
+
116
+ Riffer::Providers::Repository::REPO[:my_provider] = -> { Riffer::Providers::MyProvider }
117
+ ```
118
+
119
+ Or create a custom repository:
120
+
121
+ ```ruby
122
+ module MyApp
123
+ module Providers
124
+ def self.find(identifier)
125
+ case identifier.to_sym
126
+ when :my_provider
127
+ Riffer::Providers::MyProvider
128
+ else
129
+ Riffer::Providers::Repository.find(identifier)
130
+ end
131
+ end
132
+ end
133
+ end
134
+ ```
135
+
136
+ ## Using Your Provider
137
+
138
+ ```ruby
139
+ class MyAgent < Riffer::Agent
140
+ model 'my_provider/model-name'
141
+ end
142
+ ```
143
+
144
+ ## Tool Support
145
+
146
+ Convert tools to your provider's format:
147
+
148
+ ```ruby
149
+ def perform_generate_text(messages, model:, tools: nil, **options)
150
+ params = {
151
+ model: model,
152
+ messages: convert_messages(messages)
153
+ }
154
+
155
+ if tools && !tools.empty?
156
+ params[:tools] = tools.map { |t| convert_tool(t) }
157
+ end
158
+
159
+ response = @client.generate(**params)
160
+ # ...
161
+ end
162
+
163
+ def convert_tool(tool)
164
+ {
165
+ name: tool.name,
166
+ description: tool.description,
167
+ parameters: tool.parameters_schema
168
+ }
169
+ end
170
+ ```
171
+
172
+ ## Stream Events
173
+
174
+ Use the appropriate stream event classes:
175
+
176
+ ```ruby
177
+ # Text streaming
178
+ Riffer::StreamEvents::TextDelta.new("chunk of text")
179
+ Riffer::StreamEvents::TextDone.new("complete text")
180
+
181
+ # Tool calls
182
+ Riffer::StreamEvents::ToolCallDelta.new(
183
+ item_id: "id",
184
+ name: "tool_name",
185
+ arguments_delta: '{"partial":'
186
+ )
187
+ Riffer::StreamEvents::ToolCallDone.new(
188
+ item_id: "id",
189
+ call_id: "call_id",
190
+ name: "tool_name",
191
+ arguments: '{"complete":"args"}'
192
+ )
193
+
194
+ # Reasoning (if supported)
195
+ Riffer::StreamEvents::ReasoningDelta.new("thinking...")
196
+ Riffer::StreamEvents::ReasoningDone.new("complete reasoning")
197
+ ```
198
+
199
+ ## Error Handling
200
+
201
+ Raise appropriate Riffer errors:
202
+
203
+ ```ruby
204
+ def perform_generate_text(messages, model:, **options)
205
+ response = @client.generate(...)
206
+
207
+ if response.error?
208
+ raise Riffer::Error, "Provider error: #{response.error_message}"
209
+ end
210
+
211
+ # ...
212
+ rescue MyProviderGem::AuthError => e
213
+ raise Riffer::ArgumentError, "Authentication failed: #{e.message}"
214
+ end
215
+ ```
216
+
217
+ ## Complete Example
218
+
219
+ ```ruby
220
+ # lib/riffer/providers/anthropic.rb
221
+
222
+ class Riffer::Providers::Anthropic < Riffer::Providers::Base
223
+ def initialize(**options)
224
+ depends_on "anthropic"
225
+
226
+ api_key = options[:api_key] || ENV['ANTHROPIC_API_KEY']
227
+ @client = ::Anthropic::Client.new(api_key: api_key)
228
+ end
229
+
230
+ private
231
+
232
+ def perform_generate_text(messages, model:, tools: nil, **options)
233
+ system_message = extract_system(messages)
234
+ conversation = messages.reject { |m| m.is_a?(Riffer::Messages::System) }
235
+
236
+ params = {
237
+ model: model,
238
+ messages: convert_messages(conversation),
239
+ system: system_message,
240
+ max_tokens: options[:max_tokens] || 4096
241
+ }
242
+
243
+ if tools && !tools.empty?
244
+ params[:tools] = tools.map { |t| convert_tool(t) }
245
+ end
246
+
247
+ response = @client.messages.create(**params)
248
+ extract_assistant_message(response)
249
+ end
250
+
251
+ def perform_stream_text(messages, model:, tools: nil, **options)
252
+ Enumerator.new do |yielder|
253
+ # Similar implementation with streaming
254
+ end
255
+ end
256
+
257
+ def extract_system(messages)
258
+ system_msg = messages.find { |m| m.is_a?(Riffer::Messages::System) }
259
+ system_msg&.content
260
+ end
261
+
262
+ def convert_messages(messages)
263
+ messages.map do |msg|
264
+ case msg
265
+ when Riffer::Messages::User
266
+ {role: "user", content: msg.content}
267
+ when Riffer::Messages::Assistant
268
+ {role: "assistant", content: msg.content}
269
+ when Riffer::Messages::Tool
270
+ {role: "user", content: [{type: "tool_result", tool_use_id: msg.tool_call_id, content: msg.content}]}
271
+ end
272
+ end
273
+ end
274
+
275
+ def convert_tool(tool)
276
+ {
277
+ name: tool.name,
278
+ description: tool.description,
279
+ input_schema: tool.parameters_schema
280
+ }
281
+ end
282
+
283
+ def extract_assistant_message(response)
284
+ text = ""
285
+ tool_calls = []
286
+
287
+ response.content.each do |block|
288
+ case block.type
289
+ when "text"
290
+ text = block.text
291
+ when "tool_use"
292
+ tool_calls << {
293
+ id: block.id,
294
+ call_id: block.id,
295
+ name: block.name,
296
+ arguments: block.input.to_json
297
+ }
298
+ end
299
+ end
300
+
301
+ Riffer::Messages::Assistant.new(text, tool_calls: tool_calls)
302
+ end
303
+ end
304
+ ```
data/lib/riffer/agent.rb CHANGED
@@ -5,10 +5,18 @@ require "json"
5
5
  # Riffer::Agent is the base class for all agents in the Riffer framework.
6
6
  #
7
7
  # Provides orchestration for LLM calls, tool use, and message management.
8
+ # Subclass this to create your own agents.
9
+ #
10
+ # See Riffer::Messages and Riffer::Providers.
11
+ #
12
+ # class MyAgent < Riffer::Agent
13
+ # model 'openai/gpt-4o'
14
+ # instructions 'You are a helpful assistant.'
15
+ # end
16
+ #
17
+ # agent = MyAgent.new
18
+ # agent.generate('Hello!')
8
19
  #
9
- # @abstract
10
- # @see Riffer::Messages
11
- # @see Riffer::Providers
12
20
  class Riffer::Agent
13
21
  include Riffer::Messages::Converter
14
22
 
@@ -16,79 +24,97 @@ class Riffer::Agent
16
24
  include Riffer::Helpers::ClassNameConverter
17
25
  include Riffer::Helpers::Validations
18
26
 
19
- # Gets or sets the agent identifier
20
- # @param value [String, nil] the identifier to set, or nil to get
21
- # @return [String] the agent identifier
27
+ # Gets or sets the agent identifier.
28
+ #
29
+ # value:: String or nil - the identifier to set, or nil to get
30
+ #
31
+ # Returns String - the agent identifier.
22
32
  def identifier(value = nil)
23
33
  return @identifier || class_name_to_path(name) if value.nil?
24
34
  @identifier = value.to_s
25
35
  end
26
36
 
27
- # Gets or sets the model string (e.g., "openai/gpt-4")
28
- # @param model_string [String, nil] the model string to set, or nil to get
29
- # @return [String] the model string
37
+ # Gets or sets the model string (e.g., "openai/gpt-4o").
38
+ #
39
+ # model_string:: String or nil - the model string to set, or nil to get
40
+ #
41
+ # Returns String - the model string.
30
42
  def model(model_string = nil)
31
43
  return @model if model_string.nil?
32
44
  validate_is_string!(model_string, "model")
33
45
  @model = model_string
34
46
  end
35
47
 
36
- # Gets or sets the agent instructions
37
- # @param instructions_text [String, nil] the instructions to set, or nil to get
38
- # @return [String] the agent instructions
48
+ # Gets or sets the agent instructions.
49
+ #
50
+ # instructions_text:: String or nil - the instructions to set, or nil to get
51
+ #
52
+ # Returns String - the agent instructions.
39
53
  def instructions(instructions_text = nil)
40
54
  return @instructions if instructions_text.nil?
41
55
  validate_is_string!(instructions_text, "instructions")
42
56
  @instructions = instructions_text
43
57
  end
44
58
 
45
- # Gets or sets provider options passed to the provider client
46
- # @param options [Hash, nil] the options to set, or nil to get
47
- # @return [Hash] the provider options
59
+ # Gets or sets provider options passed to the provider client.
60
+ #
61
+ # options:: Hash or nil - the options to set, or nil to get
62
+ #
63
+ # Returns Hash - the provider options.
48
64
  def provider_options(options = nil)
49
65
  return @provider_options || {} if options.nil?
50
66
  @provider_options = options
51
67
  end
52
68
 
53
- # Gets or sets model options passed to generate_text/stream_text
54
- # @param options [Hash, nil] the options to set, or nil to get
55
- # @return [Hash] the model options
69
+ # Gets or sets model options passed to generate_text/stream_text.
70
+ #
71
+ # options:: Hash or nil - the options to set, or nil to get
72
+ #
73
+ # Returns Hash - the model options.
56
74
  def model_options(options = nil)
57
75
  return @model_options || {} if options.nil?
58
76
  @model_options = options
59
77
  end
60
78
 
61
- # Gets or sets the tools used by this agent
62
- # @param tools_or_lambda [Array<Class>, Proc, nil] tools array or lambda returning tools
63
- # @return [Array<Class>, Proc, nil] the tools configuration
79
+ # Gets or sets the tools used by this agent.
80
+ #
81
+ # tools_or_lambda:: Array of Tool classes, Proc, or nil - tools array or lambda returning tools
82
+ #
83
+ # Returns Array, Proc, or nil - the tools configuration.
64
84
  def uses_tools(tools_or_lambda = nil)
65
85
  return @tools_config if tools_or_lambda.nil?
66
86
  @tools_config = tools_or_lambda
67
87
  end
68
88
 
69
- # Finds an agent class by identifier
70
- # @param identifier [String] the identifier to search for
71
- # @return [Class, nil] the agent class, or nil if not found
89
+ # Finds an agent class by identifier.
90
+ #
91
+ # identifier:: String - the identifier to search for
92
+ #
93
+ # Returns Class or nil - the agent class, or nil if not found.
72
94
  def find(identifier)
73
95
  subclasses.find { |agent_class| agent_class.identifier == identifier.to_s }
74
96
  end
75
97
 
76
- # Returns all agent subclasses
77
- # @return [Array<Class>] all agent subclasses
98
+ # Returns all agent subclasses.
99
+ #
100
+ # Returns Array of Class - all agent subclasses.
78
101
  def all
79
102
  subclasses
80
103
  end
81
104
  end
82
105
 
83
- # The message history for the agent
84
- # @return [Array<Riffer::Messages::Base>]
106
+ # The message history for the agent.
107
+ #
108
+ # Returns Array of Riffer::Messages::Base.
85
109
  attr_reader :messages
86
110
 
87
- # Initializes a new agent
88
- # @raise [Riffer::ArgumentError] if the configured model string is invalid (must be "provider/model")
89
- # @return [void]
111
+ # Initializes a new agent.
112
+ #
113
+ # Raises Riffer::ArgumentError if the configured model string is invalid
114
+ # (must be "provider/model" format).
90
115
  def initialize
91
116
  @messages = []
117
+ @message_callbacks = []
92
118
  @model_string = self.class.model
93
119
  @instructions_text = self.class.instructions
94
120
 
@@ -100,10 +126,12 @@ class Riffer::Agent
100
126
  @model_name = model_name
101
127
  end
102
128
 
103
- # Generates a response from the agent
104
- # @param prompt_or_messages [String, Array<Hash, Riffer::Messages::Base>]
105
- # @param tool_context [Object, nil] optional context object passed to all tool calls
106
- # @return [String]
129
+ # Generates a response from the agent.
130
+ #
131
+ # prompt_or_messages:: String or Array - a string prompt or array of message hashes/objects
132
+ # tool_context:: Object or nil - optional context object passed to all tool calls
133
+ #
134
+ # Returns String - the final response content.
107
135
  def generate(prompt_or_messages, tool_context: nil)
108
136
  @tool_context = tool_context
109
137
  @resolved_tools = nil
@@ -111,7 +139,7 @@ class Riffer::Agent
111
139
 
112
140
  loop do
113
141
  response = call_llm
114
- @messages << response
142
+ add_message(response)
115
143
 
116
144
  break unless has_tool_calls?(response)
117
145
 
@@ -121,10 +149,12 @@ class Riffer::Agent
121
149
  extract_final_response
122
150
  end
123
151
 
124
- # Streams a response from the agent
125
- # @param prompt_or_messages [String, Array<Hash, Riffer::Messages::Base>]
126
- # @param tool_context [Object, nil] optional context object passed to all tool calls
127
- # @return [Enumerator] an enumerator yielding stream events
152
+ # Streams a response from the agent.
153
+ #
154
+ # prompt_or_messages:: String or Array - a string prompt or array of message hashes/objects
155
+ # tool_context:: Object or nil - optional context object passed to all tool calls
156
+ #
157
+ # Returns Enumerator - an enumerator yielding stream events.
128
158
  def stream(prompt_or_messages, tool_context: nil)
129
159
  @tool_context = tool_context
130
160
  @resolved_tools = nil
@@ -160,7 +190,7 @@ class Riffer::Agent
160
190
  end
161
191
 
162
192
  response = Riffer::Messages::Assistant.new(accumulated_content, tool_calls: accumulated_tool_calls)
163
- @messages << response
193
+ add_message(response)
164
194
 
165
195
  break unless has_tool_calls?(response)
166
196
 
@@ -169,8 +199,26 @@ class Riffer::Agent
169
199
  end
170
200
  end
171
201
 
202
+ # Registers a callback to be invoked when messages are added during generation.
203
+ #
204
+ # block:: Block - callback receiving a Riffer::Messages::Base subclass
205
+ #
206
+ # Raises Riffer::ArgumentError if no block is given.
207
+ #
208
+ # Returns self for method chaining.
209
+ def on_message(&block)
210
+ raise Riffer::ArgumentError, "on_message requires a block" unless block_given?
211
+ @message_callbacks << block
212
+ self
213
+ end
214
+
172
215
  private
173
216
 
217
+ def add_message(message)
218
+ @messages << message
219
+ @message_callbacks.each { |callback| callback.call(message) }
220
+ end
221
+
174
222
  def initialize_messages(prompt_or_messages)
175
223
  @messages = []
176
224
  @messages << Riffer::Messages::System.new(@instructions_text) if @instructions_text
@@ -217,13 +265,13 @@ class Riffer::Agent
217
265
  def execute_tool_calls(response)
218
266
  response.tool_calls.each do |tool_call|
219
267
  result = execute_tool_call(tool_call)
220
- @messages << Riffer::Messages::Tool.new(
221
- result[:content],
268
+ add_message(Riffer::Messages::Tool.new(
269
+ result.content,
222
270
  tool_call_id: tool_call[:id],
223
271
  name: tool_call[:name],
224
- error: result[:error],
225
- error_type: result[:error_type]
226
- )
272
+ error: result.error_message,
273
+ error_type: result.error_type
274
+ ))
227
275
  end
228
276
  end
229
277
 
@@ -231,31 +279,23 @@ class Riffer::Agent
231
279
  tool_class = find_tool_class(tool_call[:name])
232
280
 
233
281
  if tool_class.nil?
234
- return {
235
- content: "Error: Unknown tool '#{tool_call[:name]}'",
236
- error: "Unknown tool '#{tool_call[:name]}'",
237
- error_type: :unknown_tool
238
- }
282
+ return Riffer::Tools::Response.error(
283
+ "Unknown tool '#{tool_call[:name]}'",
284
+ type: :unknown_tool
285
+ )
239
286
  end
240
287
 
241
288
  tool_instance = tool_class.new
242
289
  arguments = parse_tool_arguments(tool_call[:arguments])
243
290
 
244
291
  begin
245
- result = tool_instance.call_with_validation(context: @tool_context, **arguments)
246
- {content: result.to_s, error: nil, error_type: nil}
292
+ tool_instance.call_with_validation(context: @tool_context, **arguments)
293
+ rescue Riffer::TimeoutError => e
294
+ Riffer::Tools::Response.error(e.message, type: :timeout_error)
247
295
  rescue Riffer::ValidationError => e
248
- {
249
- content: "Validation error: #{e.message}",
250
- error: e.message,
251
- error_type: :validation_error
252
- }
296
+ Riffer::Tools::Response.error(e.message, type: :validation_error)
253
297
  rescue => e
254
- {
255
- content: "Error executing tool: #{e.message}",
256
- error: e.message,
257
- error_type: :execution_error
258
- }
298
+ Riffer::Tools::Response.error("Error executing tool: #{e.message}", type: :execution_error)
259
299
  end
260
300
  end
261
301
 
data/lib/riffer/config.rb CHANGED
@@ -1,28 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Configuration for the Riffer framework
3
+ # Configuration for the Riffer framework.
4
4
  #
5
5
  # Provides configuration options for AI providers and other settings.
6
6
  #
7
- # @example Setting the OpenAI API key
8
7
  # Riffer.config.openai.api_key = "sk-..."
9
8
  #
10
- # @example Setting Amazon Bedrock configuration
11
9
  # Riffer.config.amazon_bedrock.region = "us-east-1"
12
10
  # Riffer.config.amazon_bedrock.api_token = "..."
11
+ #
12
+ # Riffer.config.anthropic.api_key = "sk-ant-..."
13
+ #
13
14
  class Riffer::Config
14
- # OpenAI configuration
15
- # @return [Struct]
16
- attr_reader :openai
17
-
18
- # Amazon Bedrock configuration
19
- # @return [Struct]
15
+ # Amazon Bedrock configuration (Struct with +api_token+ and +region+).
16
+ #
17
+ # Returns Struct.
20
18
  attr_reader :amazon_bedrock
21
19
 
22
- # Initializes the configuration
23
- # @return [void]
20
+ # Anthropic configuration (Struct with +api_key+).
21
+ #
22
+ # Returns Struct.
23
+ attr_reader :anthropic
24
+
25
+ # OpenAI configuration (Struct with +api_key+).
26
+ #
27
+ # Returns Struct.
28
+ attr_reader :openai
29
+
30
+ # Initializes the configuration.
24
31
  def initialize
25
- @openai = Struct.new(:api_key).new
26
32
  @amazon_bedrock = Struct.new(:api_token, :region).new
33
+ @anthropic = Struct.new(:api_key).new
34
+ @openai = Struct.new(:api_key).new
27
35
  end
28
36
  end
data/lib/riffer/core.rb CHANGED
@@ -6,21 +6,21 @@ require "logger"
6
6
  #
7
7
  # Handles logging and configuration for the framework.
8
8
  class Riffer::Core
9
- # The logger instance for Riffer
10
- # @return [Logger]
9
+ # The logger instance for Riffer.
10
+ #
11
+ # Returns Logger.
11
12
  attr_reader :logger
12
13
 
13
- # Initializes the core object and logger
14
- # @return [void]
14
+ # Initializes the core object and logger.
15
15
  def initialize
16
16
  @logger = Logger.new($stdout)
17
17
  @logger.level = Logger::INFO
18
18
  @storage_registry = {}
19
19
  end
20
20
 
21
- # Yields self for configuration
22
- # @yieldparam core [Riffer::Core] the core object
23
- # @return [void]
21
+ # Yields self for configuration.
22
+ #
23
+ # Yields core (Riffer::Core) to the block.
24
24
  def configure
25
25
  yield self if block_given?
26
26
  end
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Helper module for converting class names.
3
4
  module Riffer::Helpers::ClassNameConverter
4
- # Converts a class name to snake_case path format
5
- # @param class_name [String] the class name (e.g., "Riffer::Agent")
6
- # @return [String] the snake_case path (e.g., "riffer/agent")
5
+ # Converts a class name to snake_case path format.
6
+ #
7
+ # class_name:: String - the class name (e.g., "Riffer::Agent")
8
+ #
9
+ # Returns String - the snake_case path (e.g., "riffer/agent").
7
10
  def class_name_to_path(class_name)
8
11
  class_name
9
12
  .to_s