raif 1.2.0 → 1.2.1.pre

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: 93d75d28d64da2a5559de740890291cb3a125d981bb58aa56ff4c45be0169954
4
- data.tar.gz: 9f3ca2e5142f43be17c9fe27e3572cd08a4241e72d6e43893b74e6ba954169ae
3
+ metadata.gz: 1fb384de50e5d129f3cc88fd56ba12f8a45c5c25061b8dda631f3ce7593a681b
4
+ data.tar.gz: 4805d6a421cdff32a2ec857b53ced8e7244b32f918cda927bace04693d840771
5
5
  SHA512:
6
- metadata.gz: 90726f18f49a312f0e8d2ceb3913c1bb45c50ad237f0fceeefa825e28374214a8c61ae84c4a83e6d3188a27adea3dc0162001792d867babadca5e30f5f736398
7
- data.tar.gz: e053003fd9c510509cbc749d5f20d9d2596396224499fe7cc40467920a216f4da6efb3c281ed451ff7e29bced98ff17476c4779b7760a3e361c4a09285667deb
6
+ metadata.gz: fb2cb0bda00b00cbee10a08d8a634a7a06276ab555cfd7a224ea51d6ab800effc7fbaedb6ba2642687632c705bc4ee953bc0b74316431bfc2ba1e72e091aba7f
7
+ data.tar.gz: b4dc7c5b059054b5252f1d676f8dfa67253de3548da9a5c4fae813f675a77634d6bd4da477ae26129cebdd6515cb7c09de389445ec80f6bb69f89b10d620755c
data/README.md CHANGED
@@ -195,6 +195,8 @@ Currently included OpenRouter models:
195
195
  - `open_router_claude_3_7_sonnet`
196
196
  - `open_router_llama_3_3_70b_instruct`
197
197
  - `open_router_llama_3_1_8b_instruct`
198
+ - `open_router_llama_4_maverick`
199
+ - `open_router_llama_4_scout`
198
200
  - `open_router_gemini_2_0_flash`
199
201
  - `open_router_deepseek_chat_v3`
200
202
 
@@ -72,6 +72,11 @@ private
72
72
  params[:stream_options] = { include_usage: true }
73
73
  end
74
74
 
75
+ if model_completion.response_format_json?
76
+ params[:response_format] = { type: "json_object" }
77
+ model_completion.response_format_parameter = "json_object"
78
+ end
79
+
75
80
  params
76
81
  end
77
82
 
@@ -91,4 +91,6 @@ en:
91
91
  open_router_gemini_2_0_flash: Google Gemini 2.0 Flash (via OpenRouter)
92
92
  open_router_llama_3_1_8b_instruct: Meta Llama 3.1 8B Instruct (via OpenRouter)
93
93
  open_router_llama_3_3_70b_instruct: Meta Llama 3.3 70B Instruct (via OpenRouter)
94
+ open_router_llama_4_maverick: Meta Llama 4 Maverick (via OpenRouter)
95
+ open_router_llama_4_scout: Meta Llama 4 Scout (via OpenRouter)
94
96
  raif_test_llm: Raif Test LLM
@@ -297,6 +297,18 @@ module Raif
297
297
  input_token_cost: 0.02 / 1_000_000,
298
298
  output_token_cost: 0.03 / 1_000_000,
299
299
  },
300
+ {
301
+ key: :open_router_llama_4_maverick,
302
+ api_name: "meta-llama/llama-4-maverick",
303
+ input_token_cost: 0.15 / 1_000_000,
304
+ output_token_cost: 0.60 / 1_000_000,
305
+ },
306
+ {
307
+ key: :open_router_llama_4_scout,
308
+ api_name: "meta-llama/llama-4-scout",
309
+ input_token_cost: 0.08 / 1_000_000,
310
+ output_token_cost: 0.30 / 1_000_000,
311
+ },
300
312
  {
301
313
  key: :open_router_gemini_2_0_flash,
302
314
  api_name: "google/gemini-2.0-flash-001",
@@ -137,6 +137,7 @@ class Raif::Utils::HtmlFragmentProcessor
137
137
  # strip_tracking_parameters("/path?utm_source=test&param=keep")
138
138
  # # => "/path?param=keep"
139
139
  def strip_tracking_parameters(url)
140
+ return url if url.blank?
140
141
  return url unless url.include?("?")
141
142
 
142
143
  begin
data/lib/raif/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Raif
4
- VERSION = "1.2.0"
4
+ VERSION = "1.2.1.pre"
5
5
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Raif::ModelTools::ComplexTestTool < Raif::ModelTool
4
+ tool_arguments_schema do
5
+ string :title, description: "The title of the operation", minLength: 3
6
+
7
+ object :settings, description: "Configuration settings" do
8
+ boolean :enabled, description: "Whether the tool is enabled"
9
+ integer :priority, description: "Priority level (1-10)", minimum: 1, maximum: 10
10
+ array :tags, description: "Associated tags" do
11
+ items type: "string"
12
+ end
13
+ end
14
+
15
+ array :products, description: "List of products" do
16
+ object do
17
+ integer :id, description: "Product identifier"
18
+ string :name, description: "Product name"
19
+ number :price, description: "Product price", minimum: 0
20
+ end
21
+ end
22
+ end
23
+
24
+ example_model_invocation do
25
+ {
26
+ "name" => tool_name,
27
+ "arguments" => {
28
+ "title" => "Daily Inventory Update",
29
+ "settings" => {
30
+ "enabled" => true,
31
+ "priority" => 5,
32
+ "tags" => ["inventory", "daily-update", "retail"]
33
+ },
34
+ "items" => [
35
+ { "id" => 101, "name" => "Wireless Mouse", "price" => 25.99 },
36
+ { "id" => 102, "name" => "Keyboard", "price" => 45.0 },
37
+ { "id" => 103, "name" => "USB-C Cable", "price" => 9.99 }
38
+ ]
39
+ }
40
+ }
41
+ end
42
+
43
+ tool_description do
44
+ "An example tool demonstrating complex schema capabilities"
45
+ end
46
+
47
+ def self.process_invocation(tool_invocation)
48
+ # This would be the actual implementation
49
+ # For demonstration purposes, just echo back the arguments
50
+ tool_invocation.update!(
51
+ result: {
52
+ message: "Received complex example request",
53
+ arguments: tool_invocation.tool_arguments
54
+ }
55
+ )
56
+
57
+ tool_invocation.result
58
+ end
59
+
60
+ def self.observation_for_invocation(tool_invocation)
61
+ return "No results" unless tool_invocation.result.present?
62
+
63
+ "Successfully processed request for: #{tool_invocation.tool_arguments["title"]}"
64
+ end
65
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Raif
4
+ module RspecHelpers
5
+
6
+ def stubbed_llm(llm_model_key, &block)
7
+ test_llm = Raif.llm(llm_model_key.to_sym)
8
+
9
+ allow(test_llm).to receive(:perform_model_completion!) do |model_completion|
10
+ result = block.call(model_completion.messages, model_completion)
11
+ model_completion.raw_response = result if result.is_a?(String)
12
+ model_completion.completion_tokens = rand(100..2000)
13
+ model_completion.prompt_tokens = rand(100..2000)
14
+ model_completion.total_tokens = model_completion.completion_tokens + model_completion.prompt_tokens
15
+ model_completion.save!
16
+
17
+ model_completion
18
+ end
19
+
20
+ test_llm
21
+ end
22
+
23
+ def stub_raif_task(task, &block)
24
+ allow(Raif.config).to receive(:llm_api_requests_enabled){ true }
25
+
26
+ if task.is_a?(Raif::Task)
27
+ allow(task).to receive(:llm){ stubbed_llm(task.llm_model_key, &block) }
28
+ else
29
+ allow_any_instance_of(task).to receive(:llm) do |task_instance|
30
+ stubbed_llm(task_instance.llm_model_key, &block)
31
+ end
32
+ end
33
+ end
34
+
35
+ def stub_raif_conversation(conversation, &block)
36
+ allow(Raif.config).to receive(:llm_api_requests_enabled){ true }
37
+
38
+ if conversation.is_a?(Raif::Conversation)
39
+ allow(conversation).to receive(:llm){ stubbed_llm(conversation.llm_model_key, &block) }
40
+ else
41
+ allow_any_instance_of(conversation).to receive(:llm) do |conversation_instance|
42
+ stubbed_llm(conversation_instance.llm_model_key, &block)
43
+ end
44
+ end
45
+ end
46
+
47
+ def stub_raif_agent(agent, &block)
48
+ allow(Raif.config).to receive(:llm_api_requests_enabled){ true }
49
+
50
+ if agent.is_a?(Raif::Agent)
51
+ allow(agent).to receive(:llm){ stubbed_llm(agent.llm_model_key, &block) }
52
+ else
53
+ allow_any_instance_of(agent).to receive(:llm) do |agent_instance|
54
+ stubbed_llm(agent_instance.llm_model_key, &block)
55
+ end
56
+ end
57
+ end
58
+
59
+ def stub_raif_llm(llm, &block)
60
+ llm.chat_handler = block
61
+ allow(Raif.config).to receive(:llm_api_requests_enabled){ true }
62
+ llm
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Raif::TestConversation < Raif::Conversation
4
+
5
+ before_create :populate_available_model_tools
6
+
7
+ def populate_available_model_tools
8
+ self.available_model_tools = [
9
+ "Raif::TestModelTool",
10
+ "Raif::ModelTools::WikipediaSearch",
11
+ ]
12
+ end
13
+
14
+ def process_model_response_message(message:, entry:)
15
+ message.gsub("jerk", "[REDACTED]")
16
+ end
17
+
18
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Raif
4
+ module EmbeddingModels
5
+ class Test < Raif::EmbeddingModel
6
+ attr_accessor :embedding_handler
7
+
8
+ def generate_embedding!(input, dimensions: nil)
9
+ if input.is_a?(Array)
10
+ input.map { |text| generate_test_embedding!(text, dimensions:) }
11
+ else
12
+ generate_test_embedding!(input, dimensions:)
13
+ end
14
+ end
15
+
16
+ def generate_test_embedding!(input, dimensions: nil)
17
+ if embedding_handler.present?
18
+ embedding_handler.call(input, dimensions)
19
+ else
20
+ dimensions ||= default_output_vector_size
21
+ Array.new(dimensions) { rand(-1.0..1.0) }
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Raif
4
+ module Llms
5
+ class TestLlm < Raif::Llm
6
+ include Raif::Concerns::Llms::OpenAiCompletions::MessageFormatting
7
+
8
+ attr_accessor :chat_handler
9
+
10
+ def perform_model_completion!(model_completion)
11
+ result = chat_handler.call(model_completion.messages, model_completion)
12
+ model_completion.raw_response = result if result.is_a?(String)
13
+ model_completion.completion_tokens = rand(100..2000)
14
+ model_completion.prompt_tokens = rand(100..2000)
15
+ model_completion.total_tokens = model_completion.completion_tokens + model_completion.prompt_tokens
16
+ model_completion.save!
17
+
18
+ model_completion
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Raif::TestModelTool < Raif::ModelTool
4
+ tool_arguments_schema do
5
+ array :items do
6
+ object do
7
+ string :title, description: "The title of the item"
8
+ string :description
9
+ end
10
+ end
11
+ end
12
+
13
+ example_model_invocation do
14
+ {
15
+ "name": tool_name,
16
+ "arguments": { "items": [{ "title": "foo", "description": "bar" }] }
17
+ }
18
+ end
19
+
20
+ def self.process_invocation(tool_arguments)
21
+ end
22
+
23
+ tool_description do
24
+ "Mock Tool Description"
25
+ end
26
+
27
+ def self.observation_for_invocation(tool_invocation)
28
+ return if tool_invocation.result.blank?
29
+
30
+ "Mock Observation for #{tool_invocation.id}. Result was: #{tool_invocation.result["status"]}"
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Raif::TestTask < Raif::Task
4
+ llm_temperature 0.5
5
+
6
+ def build_prompt
7
+ "Tell me a joke"
8
+ end
9
+
10
+ def build_system_prompt
11
+ super + "\nYou are also good at telling jokes."
12
+ end
13
+ end
14
+
15
+ class Raif::TestJsonTask < Raif::Task
16
+ llm_response_format :json
17
+ llm_temperature 0.75
18
+
19
+ json_response_schema do
20
+ string :joke
21
+ string :answer
22
+ end
23
+
24
+ def build_prompt
25
+ "Tell me a joke"
26
+ end
27
+
28
+ def build_system_prompt
29
+ super + "\nYou are also good at telling jokes. Your response should be a JSON object with the following keys: joke, answer."
30
+ end
31
+ end
32
+
33
+ class Raif::TestHtmlTask < Raif::Task
34
+ llm_response_format :html
35
+ llm_response_allowed_tags %w[p b i u s a]
36
+ llm_response_allowed_attributes %w[style href]
37
+
38
+ def build_prompt
39
+ "Tell me a joke"
40
+ end
41
+
42
+ def build_system_prompt
43
+ super + "\nYou are also good at telling jokes. Your response should be an HTML snippet that is formatted with basic HTML tags."
44
+ end
45
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: raif
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.1.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Roesch
@@ -315,6 +315,13 @@ files:
315
315
  - lib/raif/utils/readable_content_extractor.rb
316
316
  - lib/raif/version.rb
317
317
  - lib/tasks/raif_tasks.rake
318
+ - spec/support/complex_test_tool.rb
319
+ - spec/support/rspec_helpers.rb
320
+ - spec/support/test_conversation.rb
321
+ - spec/support/test_embedding_model.rb
322
+ - spec/support/test_llm.rb
323
+ - spec/support/test_model_tool.rb
324
+ - spec/support/test_task.rb
318
325
  homepage: https://github.com/cultivatelabs/raif
319
326
  licenses:
320
327
  - MIT