raif 1.1.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 +4 -4
- data/README.md +150 -4
- data/app/assets/builds/raif.css +26 -1
- data/app/assets/stylesheets/raif/loader.scss +27 -1
- data/app/models/raif/concerns/llm_response_parsing.rb +22 -16
- data/app/models/raif/concerns/llms/anthropic/tool_formatting.rb +56 -0
- data/app/models/raif/concerns/llms/{bedrock_claude → bedrock}/message_formatting.rb +4 -4
- data/app/models/raif/concerns/llms/bedrock/tool_formatting.rb +37 -0
- data/app/models/raif/concerns/llms/message_formatting.rb +7 -6
- data/app/models/raif/concerns/llms/open_ai/json_schema_validation.rb +138 -0
- data/app/models/raif/concerns/llms/{open_ai → open_ai_completions}/message_formatting.rb +1 -1
- data/app/models/raif/concerns/llms/open_ai_completions/tool_formatting.rb +26 -0
- data/app/models/raif/concerns/llms/open_ai_responses/message_formatting.rb +43 -0
- data/app/models/raif/concerns/llms/open_ai_responses/tool_formatting.rb +42 -0
- data/app/models/raif/conversation.rb +17 -4
- data/app/models/raif/conversation_entry.rb +18 -2
- data/app/models/raif/embedding_models/{bedrock_titan.rb → bedrock.rb} +2 -2
- data/app/models/raif/llm.rb +73 -7
- data/app/models/raif/llms/anthropic.rb +56 -36
- data/app/models/raif/llms/{bedrock_claude.rb → bedrock.rb} +62 -45
- data/app/models/raif/llms/open_ai_base.rb +66 -0
- data/app/models/raif/llms/open_ai_completions.rb +100 -0
- data/app/models/raif/llms/open_ai_responses.rb +144 -0
- data/app/models/raif/llms/open_router.rb +44 -44
- data/app/models/raif/model_completion.rb +2 -0
- data/app/models/raif/model_tool.rb +4 -0
- data/app/models/raif/model_tools/provider_managed/base.rb +9 -0
- data/app/models/raif/model_tools/provider_managed/code_execution.rb +5 -0
- data/app/models/raif/model_tools/provider_managed/image_generation.rb +5 -0
- data/app/models/raif/model_tools/provider_managed/web_search.rb +5 -0
- data/app/models/raif/streaming_responses/anthropic.rb +63 -0
- data/app/models/raif/streaming_responses/bedrock.rb +89 -0
- data/app/models/raif/streaming_responses/open_ai_completions.rb +76 -0
- data/app/models/raif/streaming_responses/open_ai_responses.rb +54 -0
- data/app/views/raif/admin/conversations/_conversation_entry.html.erb +48 -0
- data/app/views/raif/admin/conversations/show.html.erb +1 -1
- data/app/views/raif/admin/model_completions/_model_completion.html.erb +7 -0
- data/app/views/raif/admin/model_completions/index.html.erb +1 -0
- data/app/views/raif/admin/model_completions/show.html.erb +28 -0
- data/app/views/raif/conversation_entries/_citations.html.erb +9 -0
- data/app/views/raif/conversation_entries/_conversation_entry.html.erb +5 -1
- data/app/views/raif/conversation_entries/_message.html.erb +4 -0
- data/config/locales/admin.en.yml +2 -0
- data/config/locales/en.yml +24 -0
- data/db/migrate/20250224234252_create_raif_tables.rb +1 -1
- data/db/migrate/20250421202149_add_response_format_to_raif_conversations.rb +1 -1
- data/db/migrate/20250424200755_add_cost_columns_to_raif_model_completions.rb +1 -1
- data/db/migrate/20250424232946_add_created_at_indexes.rb +1 -1
- data/db/migrate/20250502155330_add_status_indexes_to_raif_tasks.rb +1 -1
- data/db/migrate/20250527213016_add_response_id_and_response_array_to_model_completions.rb +14 -0
- data/db/migrate/20250603140622_add_citations_to_raif_model_completions.rb +13 -0
- data/db/migrate/20250603202013_add_stream_response_to_raif_model_completions.rb +7 -0
- data/lib/generators/raif/conversation/templates/conversation.rb.tt +3 -3
- data/lib/generators/raif/install/templates/initializer.rb +14 -2
- data/lib/raif/configuration.rb +27 -5
- data/lib/raif/embedding_model_registry.rb +1 -1
- data/lib/raif/engine.rb +25 -9
- data/lib/raif/errors/streaming_error.rb +18 -0
- data/lib/raif/errors.rb +1 -0
- data/lib/raif/llm_registry.rb +169 -47
- data/lib/raif/migration_checker.rb +74 -0
- data/lib/raif/utils/html_fragment_processor.rb +170 -0
- data/lib/raif/utils.rb +1 -0
- data/lib/raif/version.rb +1 -1
- data/lib/raif.rb +2 -0
- data/spec/support/complex_test_tool.rb +65 -0
- data/spec/support/rspec_helpers.rb +66 -0
- data/spec/support/test_conversation.rb +18 -0
- data/spec/support/test_embedding_model.rb +27 -0
- data/spec/support/test_llm.rb +22 -0
- data/spec/support/test_model_tool.rb +32 -0
- data/spec/support/test_task.rb +45 -0
- metadata +52 -8
- data/app/models/raif/llms/open_ai.rb +0 -256
data/lib/raif/configuration.rb
CHANGED
@@ -4,13 +4,13 @@ module Raif
|
|
4
4
|
class Configuration
|
5
5
|
attr_accessor :agent_types,
|
6
6
|
:anthropic_api_key,
|
7
|
-
:
|
7
|
+
:bedrock_models_enabled,
|
8
8
|
:anthropic_models_enabled,
|
9
9
|
:authorize_admin_controller_action,
|
10
10
|
:authorize_controller_action,
|
11
11
|
:aws_bedrock_model_name_prefix,
|
12
12
|
:aws_bedrock_region,
|
13
|
-
:
|
13
|
+
:bedrock_embedding_models_enabled,
|
14
14
|
:conversation_entries_controller,
|
15
15
|
:conversation_system_prompt_intro,
|
16
16
|
:conversation_types,
|
@@ -29,20 +29,27 @@ module Raif
|
|
29
29
|
:open_router_models_enabled,
|
30
30
|
:open_router_app_name,
|
31
31
|
:open_router_site_url,
|
32
|
+
:streaming_update_chunk_size_threshold,
|
32
33
|
:task_system_prompt_intro,
|
33
34
|
:user_tool_types
|
34
35
|
|
36
|
+
alias_method :anthropic_bedrock_models_enabled, :bedrock_models_enabled
|
37
|
+
alias_method :anthropic_bedrock_models_enabled=, :bedrock_models_enabled=
|
38
|
+
|
39
|
+
alias_method :aws_bedrock_titan_embedding_models_enabled, :bedrock_embedding_models_enabled
|
40
|
+
alias_method :aws_bedrock_titan_embedding_models_enabled=, :bedrock_embedding_models_enabled=
|
41
|
+
|
35
42
|
def initialize
|
36
43
|
# Set default config
|
37
44
|
@agent_types = Set.new(["Raif::Agents::ReActAgent", "Raif::Agents::NativeToolCallingAgent"])
|
38
45
|
@anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
|
39
|
-
@
|
46
|
+
@bedrock_models_enabled = false
|
40
47
|
@anthropic_models_enabled = ENV["ANTHROPIC_API_KEY"].present?
|
41
48
|
@authorize_admin_controller_action = ->{ false }
|
42
49
|
@authorize_controller_action = ->{ false }
|
43
50
|
@aws_bedrock_region = "us-east-1"
|
44
51
|
@aws_bedrock_model_name_prefix = "us"
|
45
|
-
@
|
52
|
+
@bedrock_embedding_models_enabled = false
|
46
53
|
@task_system_prompt_intro = "You are a helpful assistant."
|
47
54
|
@conversation_entries_controller = "Raif::ConversationEntriesController"
|
48
55
|
@conversation_system_prompt_intro = "You are a helpful assistant who is collaborating with a teammate."
|
@@ -66,16 +73,31 @@ module Raif
|
|
66
73
|
@open_router_models_enabled = ENV["OPENROUTER_API_KEY"].present?
|
67
74
|
@open_router_app_name = nil
|
68
75
|
@open_router_site_url = nil
|
76
|
+
@streaming_update_chunk_size_threshold = 25
|
69
77
|
@user_tool_types = []
|
70
78
|
end
|
71
79
|
|
72
80
|
def validate!
|
81
|
+
if Raif.llm_registry.blank?
|
82
|
+
puts <<~EOS
|
83
|
+
|
84
|
+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
85
|
+
No LLMs are enabled in Raif. Make sure you have an API key configured for at least one LLM provider. You can do this by setting an API key in your environment variables or in config/initializers/raif.rb (e.g. ENV["OPENAI_API_KEY"], ENV["ANTHROPIC_API_KEY"], ENV["OPENROUTER_API_KEY"]).
|
86
|
+
|
87
|
+
See the README for more information: https://github.com/CultivateLabs/raif#setup
|
88
|
+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
89
|
+
|
90
|
+
EOS
|
91
|
+
|
92
|
+
return
|
93
|
+
end
|
94
|
+
|
73
95
|
unless Raif.available_llm_keys.include?(default_llm_model_key.to_sym)
|
74
96
|
raise Raif::Errors::InvalidConfigError,
|
75
97
|
"Raif.config.default_llm_model_key was set to #{default_llm_model_key}, but must be one of: #{Raif.available_llm_keys.join(", ")}"
|
76
98
|
end
|
77
99
|
|
78
|
-
|
100
|
+
if Raif.embedding_model_registry.present? && !Raif.available_embedding_model_keys.include?(default_embedding_model_key.to_sym)
|
79
101
|
raise Raif::Errors::InvalidConfigError,
|
80
102
|
"Raif.config.default_embedding_model_key was set to #{default_embedding_model_key}, but must be one of: #{Raif.available_embedding_model_keys.join(", ")}" # rubocop:disable Layout/LineLength
|
81
103
|
end
|
data/lib/raif/engine.rb
CHANGED
@@ -29,8 +29,12 @@ module Raif
|
|
29
29
|
config.after_initialize do
|
30
30
|
next unless Raif.config.open_ai_models_enabled
|
31
31
|
|
32
|
-
Raif.default_llms[Raif::Llms::
|
33
|
-
Raif.register_llm(Raif::Llms::
|
32
|
+
Raif.default_llms[Raif::Llms::OpenAiCompletions].each do |llm_config|
|
33
|
+
Raif.register_llm(Raif::Llms::OpenAiCompletions, **llm_config)
|
34
|
+
end
|
35
|
+
|
36
|
+
Raif.default_llms[Raif::Llms::OpenAiResponses].each do |llm_config|
|
37
|
+
Raif.register_llm(Raif::Llms::OpenAiResponses, **llm_config)
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
@@ -51,12 +55,12 @@ module Raif
|
|
51
55
|
end
|
52
56
|
|
53
57
|
config.after_initialize do
|
54
|
-
next unless Raif.config.
|
58
|
+
next unless Raif.config.bedrock_models_enabled
|
55
59
|
|
56
60
|
require "aws-sdk-bedrockruntime"
|
57
61
|
|
58
|
-
Raif.default_llms[Raif::Llms::
|
59
|
-
Raif.register_llm(Raif::Llms::
|
62
|
+
Raif.default_llms[Raif::Llms::Bedrock].each do |llm_config|
|
63
|
+
Raif.register_llm(Raif::Llms::Bedrock, **llm_config)
|
60
64
|
end
|
61
65
|
end
|
62
66
|
|
@@ -69,12 +73,12 @@ module Raif
|
|
69
73
|
end
|
70
74
|
|
71
75
|
config.after_initialize do
|
72
|
-
next unless Raif.config.
|
76
|
+
next unless Raif.config.bedrock_embedding_models_enabled
|
73
77
|
|
74
78
|
require "aws-sdk-bedrockruntime"
|
75
79
|
|
76
|
-
Raif.default_embedding_models[Raif::EmbeddingModels::
|
77
|
-
Raif.register_embedding_model(Raif::EmbeddingModels::
|
80
|
+
Raif.default_embedding_models[Raif::EmbeddingModels::Bedrock].each do |embedding_model_config|
|
81
|
+
Raif.register_embedding_model(Raif::EmbeddingModels::Bedrock, **embedding_model_config)
|
78
82
|
end
|
79
83
|
end
|
80
84
|
|
@@ -84,7 +88,7 @@ module Raif
|
|
84
88
|
Raif.config.conversation_types += ["Raif::TestConversation"]
|
85
89
|
|
86
90
|
require "#{Raif::Engine.root}/spec/support/test_llm"
|
87
|
-
Raif.register_llm(Raif::Llms::
|
91
|
+
Raif.register_llm(Raif::Llms::TestLlm, key: :raif_test_llm, api_name: "raif-test-llm")
|
88
92
|
|
89
93
|
require "#{Raif::Engine.root}/spec/support/test_embedding_model"
|
90
94
|
Raif.register_embedding_model(
|
@@ -99,6 +103,18 @@ module Raif
|
|
99
103
|
Raif.config.validate!
|
100
104
|
end
|
101
105
|
|
106
|
+
config.after_initialize do
|
107
|
+
# Check to see if the host app is missing any of our migrations
|
108
|
+
# and print a warning if they are
|
109
|
+
next unless Rails.env.development?
|
110
|
+
next if File.basename($PROGRAM_NAME) == "rake"
|
111
|
+
|
112
|
+
# Skip if we're running inside the engine's own dummy app
|
113
|
+
next if Rails.root.to_s.include?("raif/spec/dummy")
|
114
|
+
|
115
|
+
Raif::MigrationChecker.check_and_warn!
|
116
|
+
end
|
117
|
+
|
102
118
|
initializer "raif.assets" do
|
103
119
|
if Rails.application.config.respond_to?(:assets)
|
104
120
|
Rails.application.config.assets.precompile += [
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
module Errors
|
5
|
+
class StreamingError < StandardError
|
6
|
+
attr_reader :message, :type, :code, :event
|
7
|
+
|
8
|
+
def initialize(message:, type:, event:, code: nil)
|
9
|
+
super
|
10
|
+
|
11
|
+
@message = message
|
12
|
+
@type = type
|
13
|
+
@code = code
|
14
|
+
@event = event
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/raif/errors.rb
CHANGED
data/lib/raif/llm_registry.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Raif
|
4
|
-
|
5
|
-
|
4
|
+
def self.llm_registry
|
5
|
+
@llm_registry ||= {}
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.register_llm(llm_class, llm_config)
|
@@ -40,81 +40,170 @@ module Raif
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def self.default_llms
|
43
|
+
open_ai_models = [
|
44
|
+
{
|
45
|
+
key: :open_ai_gpt_4o_mini,
|
46
|
+
api_name: "gpt-4o-mini",
|
47
|
+
input_token_cost: 0.15 / 1_000_000,
|
48
|
+
output_token_cost: 0.6 / 1_000_000,
|
49
|
+
},
|
50
|
+
{
|
51
|
+
key: :open_ai_gpt_4o,
|
52
|
+
api_name: "gpt-4o",
|
53
|
+
input_token_cost: 2.5 / 1_000_000,
|
54
|
+
output_token_cost: 10.0 / 1_000_000,
|
55
|
+
},
|
56
|
+
{
|
57
|
+
key: :open_ai_gpt_3_5_turbo,
|
58
|
+
api_name: "gpt-3.5-turbo",
|
59
|
+
input_token_cost: 0.5 / 1_000_000,
|
60
|
+
output_token_cost: 1.5 / 1_000_000,
|
61
|
+
model_provider_settings: { supports_structured_outputs: false }
|
62
|
+
},
|
63
|
+
{
|
64
|
+
key: :open_ai_gpt_4_1,
|
65
|
+
api_name: "gpt-4.1",
|
66
|
+
input_token_cost: 2.0 / 1_000_000,
|
67
|
+
output_token_cost: 8.0 / 1_000_000,
|
68
|
+
},
|
69
|
+
{
|
70
|
+
key: :open_ai_gpt_4_1_mini,
|
71
|
+
api_name: "gpt-4.1-mini",
|
72
|
+
input_token_cost: 0.4 / 1_000_000,
|
73
|
+
output_token_cost: 1.6 / 1_000_000,
|
74
|
+
},
|
75
|
+
{
|
76
|
+
key: :open_ai_gpt_4_1_nano,
|
77
|
+
api_name: "gpt-4.1-nano",
|
78
|
+
input_token_cost: 0.1 / 1_000_000,
|
79
|
+
output_token_cost: 0.4 / 1_000_000,
|
80
|
+
},
|
81
|
+
{
|
82
|
+
key: :open_ai_o1,
|
83
|
+
api_name: "o1",
|
84
|
+
input_token_cost: 15.0 / 1_000_000,
|
85
|
+
output_token_cost: 60.0 / 1_000_000,
|
86
|
+
model_provider_settings: { supports_temperature: false },
|
87
|
+
},
|
88
|
+
{
|
89
|
+
key: :open_ai_o1_mini,
|
90
|
+
api_name: "o1-mini",
|
91
|
+
input_token_cost: 1.5 / 1_000_000,
|
92
|
+
output_token_cost: 6.0 / 1_000_000,
|
93
|
+
model_provider_settings: { supports_temperature: false },
|
94
|
+
},
|
95
|
+
{
|
96
|
+
key: :open_ai_o3,
|
97
|
+
api_name: "o3",
|
98
|
+
input_token_cost: 2.0 / 1_000_000,
|
99
|
+
output_token_cost: 8.0 / 1_000_000,
|
100
|
+
model_provider_settings: { supports_temperature: false },
|
101
|
+
},
|
102
|
+
{
|
103
|
+
key: :open_ai_o3_mini,
|
104
|
+
api_name: "o3-mini",
|
105
|
+
input_token_cost: 1.1 / 1_000_000,
|
106
|
+
output_token_cost: 4.4 / 1_000_000,
|
107
|
+
model_provider_settings: { supports_temperature: false },
|
108
|
+
},
|
109
|
+
{
|
110
|
+
key: :open_ai_o4_mini,
|
111
|
+
api_name: "o4-mini",
|
112
|
+
input_token_cost: 1.1 / 1_000_000,
|
113
|
+
output_token_cost: 4.4 / 1_000_000,
|
114
|
+
model_provider_settings: { supports_temperature: false },
|
115
|
+
},
|
116
|
+
]
|
117
|
+
|
118
|
+
open_ai_responses_models = open_ai_models.dup.map.with_index do |model, _index|
|
119
|
+
model.merge(
|
120
|
+
key: model[:key].to_s.gsub("open_ai_", "open_ai_responses_").to_sym,
|
121
|
+
supported_provider_managed_tools: [
|
122
|
+
Raif::ModelTools::ProviderManaged::WebSearch,
|
123
|
+
Raif::ModelTools::ProviderManaged::CodeExecution,
|
124
|
+
Raif::ModelTools::ProviderManaged::ImageGeneration
|
125
|
+
]
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
# o1-mini is not supported by the OpenAI Responses API.
|
130
|
+
open_ai_responses_models.delete_if{|model| model[:key] == :open_ai_o1_mini }
|
131
|
+
|
132
|
+
# o1-pro and o3-pro are not supported by the OpenAI Completions API, but it is supported by the OpenAI Responses API.
|
133
|
+
open_ai_responses_models << {
|
134
|
+
key: :open_ai_responses_o1_pro,
|
135
|
+
api_name: "o1-pro",
|
136
|
+
input_token_cost: 150.0 / 1_000_000,
|
137
|
+
output_token_cost: 600.0 / 1_000_000,
|
138
|
+
model_provider_settings: { supports_temperature: false },
|
139
|
+
}
|
140
|
+
|
141
|
+
open_ai_responses_models << {
|
142
|
+
key: :open_ai_responses_o3_pro,
|
143
|
+
api_name: "o3-pro",
|
144
|
+
input_token_cost: 20.0 / 1_000_000,
|
145
|
+
output_token_cost: 80.0 / 1_000_000,
|
146
|
+
model_provider_settings: { supports_temperature: false },
|
147
|
+
}
|
148
|
+
|
43
149
|
{
|
44
|
-
Raif::Llms::
|
45
|
-
|
46
|
-
key: :open_ai_gpt_4o_mini,
|
47
|
-
api_name: "gpt-4o-mini",
|
48
|
-
input_token_cost: 0.15 / 1_000_000,
|
49
|
-
output_token_cost: 0.6 / 1_000_000,
|
50
|
-
},
|
51
|
-
{
|
52
|
-
key: :open_ai_gpt_4o,
|
53
|
-
api_name: "gpt-4o",
|
54
|
-
input_token_cost: 2.5 / 1_000_000,
|
55
|
-
output_token_cost: 10.0 / 1_000_000,
|
56
|
-
},
|
57
|
-
{
|
58
|
-
key: :open_ai_gpt_3_5_turbo,
|
59
|
-
api_name: "gpt-3.5-turbo",
|
60
|
-
input_token_cost: 0.5 / 1_000_000,
|
61
|
-
output_token_cost: 1.5 / 1_000_000,
|
62
|
-
model_provider_settings: { supports_structured_outputs: false }
|
63
|
-
},
|
64
|
-
{
|
65
|
-
key: :open_ai_gpt_4_1,
|
66
|
-
api_name: "gpt-4.1",
|
67
|
-
input_token_cost: 2.0 / 1_000_000,
|
68
|
-
output_token_cost: 8.0 / 1_000_000,
|
69
|
-
},
|
70
|
-
{
|
71
|
-
key: :open_ai_gpt_4_1_mini,
|
72
|
-
api_name: "gpt-4.1-mini",
|
73
|
-
input_token_cost: 0.4 / 1_000_000,
|
74
|
-
output_token_cost: 1.6 / 1_000_000,
|
75
|
-
},
|
76
|
-
{
|
77
|
-
key: :open_ai_gpt_4_1_nano,
|
78
|
-
api_name: "gpt-4.1-nano",
|
79
|
-
input_token_cost: 0.1 / 1_000_000,
|
80
|
-
output_token_cost: 0.4 / 1_000_000,
|
81
|
-
},
|
82
|
-
],
|
150
|
+
Raif::Llms::OpenAiCompletions => open_ai_models,
|
151
|
+
Raif::Llms::OpenAiResponses => open_ai_responses_models,
|
83
152
|
Raif::Llms::Anthropic => [
|
84
153
|
{
|
85
154
|
key: :anthropic_claude_4_sonnet,
|
86
155
|
api_name: "claude-sonnet-4-20250514",
|
87
156
|
input_token_cost: 3.0 / 1_000_000,
|
88
157
|
output_token_cost: 15.0 / 1_000_000,
|
89
|
-
max_completion_tokens: 8192
|
158
|
+
max_completion_tokens: 8192,
|
159
|
+
supported_provider_managed_tools: [
|
160
|
+
Raif::ModelTools::ProviderManaged::WebSearch,
|
161
|
+
Raif::ModelTools::ProviderManaged::CodeExecution
|
162
|
+
]
|
90
163
|
},
|
91
164
|
{
|
92
165
|
key: :anthropic_claude_4_opus,
|
93
166
|
api_name: "claude-opus-4-20250514",
|
94
167
|
input_token_cost: 15.0 / 1_000_000,
|
95
168
|
output_token_cost: 75.0 / 1_000_000,
|
96
|
-
max_completion_tokens: 8192
|
169
|
+
max_completion_tokens: 8192,
|
170
|
+
supported_provider_managed_tools: [
|
171
|
+
Raif::ModelTools::ProviderManaged::WebSearch,
|
172
|
+
Raif::ModelTools::ProviderManaged::CodeExecution
|
173
|
+
]
|
97
174
|
},
|
98
175
|
{
|
99
176
|
key: :anthropic_claude_3_7_sonnet,
|
100
177
|
api_name: "claude-3-7-sonnet-latest",
|
101
178
|
input_token_cost: 3.0 / 1_000_000,
|
102
179
|
output_token_cost: 15.0 / 1_000_000,
|
103
|
-
max_completion_tokens: 8192
|
180
|
+
max_completion_tokens: 8192,
|
181
|
+
supported_provider_managed_tools: [
|
182
|
+
Raif::ModelTools::ProviderManaged::WebSearch,
|
183
|
+
Raif::ModelTools::ProviderManaged::CodeExecution
|
184
|
+
]
|
104
185
|
},
|
105
186
|
{
|
106
187
|
key: :anthropic_claude_3_5_sonnet,
|
107
188
|
api_name: "claude-3-5-sonnet-latest",
|
108
189
|
input_token_cost: 3.0 / 1_000_000,
|
109
190
|
output_token_cost: 15.0 / 1_000_000,
|
110
|
-
max_completion_tokens: 8192
|
191
|
+
max_completion_tokens: 8192,
|
192
|
+
supported_provider_managed_tools: [
|
193
|
+
Raif::ModelTools::ProviderManaged::WebSearch,
|
194
|
+
Raif::ModelTools::ProviderManaged::CodeExecution
|
195
|
+
]
|
111
196
|
},
|
112
197
|
{
|
113
198
|
key: :anthropic_claude_3_5_haiku,
|
114
199
|
api_name: "claude-3-5-haiku-latest",
|
115
200
|
input_token_cost: 0.8 / 1_000_000,
|
116
201
|
output_token_cost: 4.0 / 1_000_000,
|
117
|
-
max_completion_tokens: 8192
|
202
|
+
max_completion_tokens: 8192,
|
203
|
+
supported_provider_managed_tools: [
|
204
|
+
Raif::ModelTools::ProviderManaged::WebSearch,
|
205
|
+
Raif::ModelTools::ProviderManaged::CodeExecution
|
206
|
+
]
|
118
207
|
},
|
119
208
|
{
|
120
209
|
key: :anthropic_claude_3_opus,
|
@@ -124,7 +213,7 @@ module Raif
|
|
124
213
|
max_completion_tokens: 4096
|
125
214
|
},
|
126
215
|
],
|
127
|
-
Raif::Llms::
|
216
|
+
Raif::Llms::Bedrock => [
|
128
217
|
{
|
129
218
|
key: :bedrock_claude_4_sonnet,
|
130
219
|
api_name: "anthropic.claude-sonnet-4-20250514-v1:0",
|
@@ -167,6 +256,27 @@ module Raif
|
|
167
256
|
output_token_cost: 0.075 / 1000,
|
168
257
|
max_completion_tokens: 4096
|
169
258
|
},
|
259
|
+
{
|
260
|
+
key: :bedrock_amazon_nova_micro,
|
261
|
+
api_name: "amazon.nova-micro-v1:0",
|
262
|
+
input_token_cost: 0.0000115 / 1000,
|
263
|
+
output_token_cost: 0.000184 / 1000,
|
264
|
+
max_completion_tokens: 4096
|
265
|
+
},
|
266
|
+
{
|
267
|
+
key: :bedrock_amazon_nova_lite,
|
268
|
+
api_name: "amazon.nova-lite-v1:0",
|
269
|
+
input_token_cost: 0.0000195 / 1000,
|
270
|
+
output_token_cost: 0.000312 / 1000,
|
271
|
+
max_completion_tokens: 4096
|
272
|
+
},
|
273
|
+
{
|
274
|
+
key: :bedrock_amazon_nova_pro,
|
275
|
+
api_name: "amazon.nova-pro-v1:0",
|
276
|
+
input_token_cost: 0.0002625 / 1000,
|
277
|
+
output_token_cost: 0.0042 / 1000,
|
278
|
+
max_completion_tokens: 4096
|
279
|
+
}
|
170
280
|
],
|
171
281
|
Raif::Llms::OpenRouter => [
|
172
282
|
{
|
@@ -187,6 +297,18 @@ module Raif
|
|
187
297
|
input_token_cost: 0.02 / 1_000_000,
|
188
298
|
output_token_cost: 0.03 / 1_000_000,
|
189
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
|
+
},
|
190
312
|
{
|
191
313
|
key: :open_router_gemini_2_0_flash,
|
192
314
|
api_name: "google/gemini-2.0-flash-001",
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
module MigrationChecker
|
5
|
+
class << self
|
6
|
+
def uninstalled_migrations
|
7
|
+
engine_migration_names = engine_migration_names_from_context
|
8
|
+
ran_migration_names = ran_migration_names_from_host
|
9
|
+
|
10
|
+
engine_migration_names - ran_migration_names
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_and_warn!
|
14
|
+
return unless defined?(Rails) && Rails.application
|
15
|
+
|
16
|
+
uninstalled = uninstalled_migrations
|
17
|
+
return if uninstalled.empty?
|
18
|
+
|
19
|
+
warning_message = build_warning_message(uninstalled)
|
20
|
+
|
21
|
+
# Output to both logger and STDOUT to ensure visibility
|
22
|
+
Rails.logger&.warn(warning_message)
|
23
|
+
warn warning_message
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def engine_migration_names_from_context
|
29
|
+
engine_paths = Raif::Engine.paths["db/migrate"].existent
|
30
|
+
return [] if engine_paths.empty?
|
31
|
+
|
32
|
+
ActiveRecord::MigrationContext.new(engine_paths).migrations.map(&:name)
|
33
|
+
rescue => e
|
34
|
+
Rails.logger&.debug("Raif: Could not load engine migrations: #{e.message}")
|
35
|
+
[]
|
36
|
+
end
|
37
|
+
|
38
|
+
def ran_migration_names_from_host
|
39
|
+
return [] unless defined?(Rails) && Rails.application
|
40
|
+
|
41
|
+
app_paths = Rails.application.paths["db/migrate"].expanded
|
42
|
+
return [] if app_paths.empty?
|
43
|
+
|
44
|
+
ctx = ActiveRecord::MigrationContext.new(app_paths)
|
45
|
+
ran_versions = ctx.get_all_versions
|
46
|
+
ctx.migrations.select{|m| ran_versions.include?(m.version) }.map(&:name)
|
47
|
+
rescue ActiveRecord::NoDatabaseError
|
48
|
+
# Database doesn't exist yet, so no migrations have been run
|
49
|
+
[]
|
50
|
+
rescue => e
|
51
|
+
Rails.logger&.debug("Raif: Could not load migration status: #{e.message}")
|
52
|
+
[]
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_warning_message(uninstalled_migration_names)
|
56
|
+
<<~WARNING
|
57
|
+
\e[33m
|
58
|
+
⚠️ RAIF MIGRATION WARNING ⚠️
|
59
|
+
|
60
|
+
The following Raif migrations have not been run in your application:
|
61
|
+
|
62
|
+
#{uninstalled_migration_names.map { |name| " • #{name}" }.join("\n")}
|
63
|
+
|
64
|
+
To install and run these migrations:
|
65
|
+
|
66
|
+
rails raif:install:migrations
|
67
|
+
rails db:migrate
|
68
|
+
|
69
|
+
\e[0m
|
70
|
+
WARNING
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|