raif 1.0.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +678 -0
- data/Rakefile +20 -0
- data/app/assets/builds/raif.css +74 -0
- data/app/assets/builds/raif_admin.css +266 -0
- data/app/assets/config/raif_manifest.js +1 -0
- data/app/assets/javascript/raif/controllers/conversations_controller.js +11 -0
- data/app/assets/javascript/raif/stream_actions/raif_scroll_to_bottom.js +12 -0
- data/app/assets/javascript/raif.js +10 -0
- data/app/assets/stylesheets/raif/admin/conversation.scss +64 -0
- data/app/assets/stylesheets/raif/loader.scss +85 -0
- data/app/assets/stylesheets/raif.scss +1 -0
- data/app/assets/stylesheets/raif_admin.scss +299 -0
- data/app/controllers/raif/admin/agents_controller.rb +17 -0
- data/app/controllers/raif/admin/application_controller.rb +20 -0
- data/app/controllers/raif/admin/conversations_controller.rb +17 -0
- data/app/controllers/raif/admin/model_completions_controller.rb +17 -0
- data/app/controllers/raif/admin/model_tool_invocations_controller.rb +17 -0
- data/app/controllers/raif/admin/tasks_controller.rb +23 -0
- data/app/controllers/raif/application_controller.rb +20 -0
- data/app/controllers/raif/conversation_entries_controller.rb +60 -0
- data/app/controllers/raif/conversations_controller.rb +58 -0
- data/app/helpers/raif/application_helper.rb +7 -0
- data/app/helpers/raif/shared/conversations_helper.rb +13 -0
- data/app/jobs/raif/application_job.rb +8 -0
- data/app/jobs/raif/conversation_entry_job.rb +30 -0
- data/app/models/raif/agent.rb +133 -0
- data/app/models/raif/agents/native_tool_calling_agent.rb +127 -0
- data/app/models/raif/agents/re_act_agent.rb +121 -0
- data/app/models/raif/agents/re_act_step.rb +33 -0
- data/app/models/raif/application_record.rb +14 -0
- data/app/models/raif/concerns/boolean_timestamp.rb +69 -0
- data/app/models/raif/concerns/has_available_model_tools.rb +13 -0
- data/app/models/raif/concerns/has_llm.rb +19 -0
- data/app/models/raif/concerns/has_requested_language.rb +20 -0
- data/app/models/raif/concerns/invokes_model_tools.rb +13 -0
- data/app/models/raif/concerns/llm_response_parsing.rb +44 -0
- data/app/models/raif/conversation.rb +67 -0
- data/app/models/raif/conversation_entry.rb +85 -0
- data/app/models/raif/llm.rb +88 -0
- data/app/models/raif/llms/anthropic.rb +120 -0
- data/app/models/raif/llms/bedrock_claude.rb +134 -0
- data/app/models/raif/llms/open_ai.rb +259 -0
- data/app/models/raif/model_completion.rb +28 -0
- data/app/models/raif/model_tool.rb +69 -0
- data/app/models/raif/model_tool_invocation.rb +43 -0
- data/app/models/raif/model_tools/agent_final_answer.rb +46 -0
- data/app/models/raif/model_tools/fetch_url.rb +57 -0
- data/app/models/raif/model_tools/wikipedia_search.rb +78 -0
- data/app/models/raif/task.rb +137 -0
- data/app/models/raif/user_tool_invocation.rb +29 -0
- data/app/views/layouts/raif/admin.html.erb +98 -0
- data/app/views/raif/admin/agents/_agent.html.erb +18 -0
- data/app/views/raif/admin/agents/_conversation_message.html.erb +15 -0
- data/app/views/raif/admin/agents/index.html.erb +33 -0
- data/app/views/raif/admin/agents/show.html.erb +131 -0
- data/app/views/raif/admin/conversations/_conversation.html.erb +7 -0
- data/app/views/raif/admin/conversations/_conversation_entry.html.erb +34 -0
- data/app/views/raif/admin/conversations/index.html.erb +32 -0
- data/app/views/raif/admin/conversations/show.html.erb +56 -0
- data/app/views/raif/admin/model_completions/_model_completion.html.erb +9 -0
- data/app/views/raif/admin/model_completions/index.html.erb +34 -0
- data/app/views/raif/admin/model_completions/show.html.erb +117 -0
- data/app/views/raif/admin/model_tool_invocations/_model_tool_invocation.html.erb +16 -0
- data/app/views/raif/admin/model_tool_invocations/index.html.erb +33 -0
- data/app/views/raif/admin/model_tool_invocations/show.html.erb +66 -0
- data/app/views/raif/admin/tasks/_task.html.erb +19 -0
- data/app/views/raif/admin/tasks/index.html.erb +49 -0
- data/app/views/raif/admin/tasks/show.html.erb +176 -0
- data/app/views/raif/conversation_entries/_conversation_entry.html.erb +26 -0
- data/app/views/raif/conversation_entries/_form.html.erb +25 -0
- data/app/views/raif/conversation_entries/_form_with_available_tools.html.erb +4 -0
- data/app/views/raif/conversation_entries/_form_with_user_tool_invocation.html.erb +18 -0
- data/app/views/raif/conversation_entries/_message.html.erb +17 -0
- data/app/views/raif/conversation_entries/_model_response_avatar.html.erb +1 -0
- data/app/views/raif/conversation_entries/_user_avatar.html.erb +1 -0
- data/app/views/raif/conversation_entries/create.turbo_stream.erb +11 -0
- data/app/views/raif/conversation_entries/new.turbo_stream.erb +6 -0
- data/app/views/raif/conversations/_available_user_tools.html.erb +11 -0
- data/app/views/raif/conversations/_full_conversation.html.erb +15 -0
- data/app/views/raif/conversations/show.html.erb +1 -0
- data/config/i18n-tasks.yml +181 -0
- data/config/importmap.rb +6 -0
- data/config/initializers/pagy.rb +14 -0
- data/config/locales/admin.en.yml +91 -0
- data/config/locales/en.yml +50 -0
- data/config/routes.rb +22 -0
- data/db/migrate/20250224234252_create_raif_tables.rb +114 -0
- data/lib/generators/raif/agent/agent_generator.rb +22 -0
- data/lib/generators/raif/agent/templates/agent.rb.tt +28 -0
- data/lib/generators/raif/conversation/conversation_generator.rb +27 -0
- data/lib/generators/raif/conversation/templates/conversation.rb.tt +37 -0
- data/lib/generators/raif/install/install_generator.rb +31 -0
- data/lib/generators/raif/install/templates/initializer.rb +81 -0
- data/lib/generators/raif/model_tool/model_tool_generator.rb +27 -0
- data/lib/generators/raif/model_tool/templates/model_tool.rb.tt +74 -0
- data/lib/generators/raif/task/task_generator.rb +28 -0
- data/lib/generators/raif/task/templates/application_task.rb.tt +7 -0
- data/lib/generators/raif/task/templates/task.rb.tt +52 -0
- data/lib/generators/raif/views_generator.rb +22 -0
- data/lib/raif/configuration.rb +82 -0
- data/lib/raif/default_llms.rb +37 -0
- data/lib/raif/engine.rb +86 -0
- data/lib/raif/errors/action_not_authorized_error.rb +8 -0
- data/lib/raif/errors/anthropic/api_error.rb +10 -0
- data/lib/raif/errors/invalid_config_error.rb +8 -0
- data/lib/raif/errors/invalid_conversation_type_error.rb +8 -0
- data/lib/raif/errors/invalid_user_tool_type_error.rb +8 -0
- data/lib/raif/errors/open_ai/api_error.rb +10 -0
- data/lib/raif/errors/open_ai/json_schema_error.rb +10 -0
- data/lib/raif/errors.rb +9 -0
- data/lib/raif/languages.rb +33 -0
- data/lib/raif/rspec.rb +7 -0
- data/lib/raif/utils/html_to_markdown_converter.rb +7 -0
- data/lib/raif/utils/readable_content_extractor.rb +61 -0
- data/lib/raif/utils.rb +6 -0
- data/lib/raif/version.rb +5 -0
- data/lib/raif.rb +65 -0
- data/lib/tasks/raif_tasks.rake +6 -0
- metadata +294 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :agent_types,
|
6
|
+
:anthropic_api_key,
|
7
|
+
:anthropic_bedrock_models_enabled,
|
8
|
+
:anthropic_models_enabled,
|
9
|
+
:authorize_admin_controller_action,
|
10
|
+
:authorize_controller_action,
|
11
|
+
:aws_bedrock_model_name_prefix,
|
12
|
+
:aws_bedrock_region,
|
13
|
+
:conversation_entries_controller,
|
14
|
+
:conversation_system_prompt_intro,
|
15
|
+
:conversation_types,
|
16
|
+
:conversations_controller,
|
17
|
+
:current_user_method,
|
18
|
+
:default_llm_model_key,
|
19
|
+
:llm_api_requests_enabled,
|
20
|
+
:model_superclass,
|
21
|
+
:open_ai_api_key,
|
22
|
+
:open_ai_models_enabled,
|
23
|
+
:task_system_prompt_intro,
|
24
|
+
:user_tool_types
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
# Set default config
|
28
|
+
@agent_types = Set.new(["Raif::Agents::ReActAgent", "Raif::Agents::NativeToolCallingAgent"])
|
29
|
+
@anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
|
30
|
+
@anthropic_bedrock_models_enabled = true
|
31
|
+
@anthropic_models_enabled = true
|
32
|
+
@authorize_admin_controller_action = ->{ false }
|
33
|
+
@authorize_controller_action = ->{ false }
|
34
|
+
@aws_bedrock_region = "us-east-1"
|
35
|
+
@aws_bedrock_model_name_prefix = "us"
|
36
|
+
@task_system_prompt_intro = "You are a helpful assistant."
|
37
|
+
@conversation_entries_controller = "Raif::ConversationEntriesController"
|
38
|
+
@conversation_system_prompt_intro = "You are a helpful assistant who is collaborating with a teammate."
|
39
|
+
@conversation_types = Set.new(["Raif::Conversation"])
|
40
|
+
@conversations_controller = "Raif::ConversationsController"
|
41
|
+
@current_user_method = :current_user
|
42
|
+
@default_llm_model_key = "open_ai_gpt_4o"
|
43
|
+
@llm_api_requests_enabled = true
|
44
|
+
@model_superclass = "ApplicationRecord"
|
45
|
+
@open_ai_api_key = ENV["OPENAI_API_KEY"]
|
46
|
+
@open_ai_models_enabled = true
|
47
|
+
@user_tool_types = []
|
48
|
+
end
|
49
|
+
|
50
|
+
def validate!
|
51
|
+
unless Raif.available_llm_keys.include?(default_llm_model_key.to_sym)
|
52
|
+
raise Raif::Errors::InvalidConfigError,
|
53
|
+
"Raif.config.default_llm_model_key was set to #{default_llm_model_key}, but must be one of: #{Raif.available_llm_keys.join(", ")}"
|
54
|
+
end
|
55
|
+
|
56
|
+
if authorize_controller_action.respond_to?(:call)
|
57
|
+
authorize_controller_action.freeze
|
58
|
+
else
|
59
|
+
raise Raif::Errors::InvalidConfigError,
|
60
|
+
"Raif.config.authorize_controller_action must respond to :call and return a boolean"
|
61
|
+
end
|
62
|
+
|
63
|
+
if authorize_admin_controller_action.respond_to?(:call)
|
64
|
+
authorize_admin_controller_action.freeze
|
65
|
+
else
|
66
|
+
raise Raif::Errors::InvalidConfigError,
|
67
|
+
"Raif.config.authorize_admin_controller_action must respond to :call and return a boolean"
|
68
|
+
end
|
69
|
+
|
70
|
+
if open_ai_models_enabled && open_ai_api_key.blank?
|
71
|
+
raise Raif::Errors::InvalidConfigError,
|
72
|
+
"Raif.config.open_ai_api_key is required when Raif.config.open_ai_models_enabled is true. Set it via Raif.config.open_ai_api_key or ENV[\"OPENAI_API_KEY\"]" # rubocop:disable Layout/LineLength
|
73
|
+
end
|
74
|
+
|
75
|
+
if anthropic_models_enabled && anthropic_api_key.blank?
|
76
|
+
raise Raif::Errors::InvalidConfigError,
|
77
|
+
"Raif.config.anthropic_api_key is required when Raif.config.anthropic_models_enabled is true. Set it via Raif.config.anthropic_api_key or ENV['ANTHROPIC_API_KEY']" # rubocop:disable Layout/LineLength
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
def self.default_llms
|
5
|
+
{
|
6
|
+
Raif::Llms::OpenAi => [
|
7
|
+
{
|
8
|
+
key: :open_ai_gpt_4o_mini,
|
9
|
+
api_name: "gpt-4o-mini",
|
10
|
+
model_provider_settings: { supports_structured_outputs: true }
|
11
|
+
},
|
12
|
+
{
|
13
|
+
key: :open_ai_gpt_4o,
|
14
|
+
api_name: "gpt-4o",
|
15
|
+
model_provider_settings: { supports_structured_outputs: true }
|
16
|
+
},
|
17
|
+
{
|
18
|
+
key: :open_ai_gpt_3_5_turbo,
|
19
|
+
api_name: "gpt-3.5-turbo",
|
20
|
+
model_provider_settings: { supports_structured_outputs: false }
|
21
|
+
},
|
22
|
+
],
|
23
|
+
Raif::Llms::Anthropic => [
|
24
|
+
{ key: :anthropic_claude_3_7_sonnet, api_name: "claude-3-7-sonnet-latest", max_completion_tokens: 8192 },
|
25
|
+
{ key: :anthropic_claude_3_5_sonnet, api_name: "claude-3-5-sonnet-latest", max_completion_tokens: 8192 },
|
26
|
+
{ key: :anthropic_claude_3_5_haiku, api_name: "claude-3-5-haiku-latest", max_completion_tokens: 8192 },
|
27
|
+
{ key: :anthropic_claude_3_opus, api_name: "claude-3-opus-latest", max_completion_tokens: 4096 },
|
28
|
+
],
|
29
|
+
Raif::Llms::BedrockClaude => [
|
30
|
+
{ key: :bedrock_claude_3_5_sonnet, api_name: "anthropic.claude-3-5-sonnet-20241022-v2:0", max_completion_tokens: 8192 },
|
31
|
+
{ key: :bedrock_claude_3_7_sonnet, api_name: "anthropic.claude-3-7-sonnet-20250219-v1:0", max_completion_tokens: 8192 },
|
32
|
+
{ key: :bedrock_claude_3_5_haiku, api_name: "anthropic.claude-3-5-haiku-20241022-v1:0", max_completion_tokens: 8192 },
|
33
|
+
{ key: :bedrock_claude_3_opus, api_name: "anthropic.claude-3-opus-20240229-v1:0", max_completion_tokens: 4096 },
|
34
|
+
]
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
data/lib/raif/engine.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "factory_bot_rails"
|
5
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
6
|
+
end
|
7
|
+
|
8
|
+
module Raif
|
9
|
+
class Engine < ::Rails::Engine
|
10
|
+
isolate_namespace Raif
|
11
|
+
|
12
|
+
# If the host app is using FactoryBot, add the factories to the host app so they can be used in host apptests
|
13
|
+
if defined?(FactoryBotRails)
|
14
|
+
config.factory_bot.definition_file_paths += [File.expand_path("../../../spec/factories/shared", __FILE__)]
|
15
|
+
end
|
16
|
+
|
17
|
+
config.generators do |g|
|
18
|
+
g.test_framework :rspec
|
19
|
+
g.fixture_replacement :factory_bot
|
20
|
+
g.factory_bot dir: "spec/factories"
|
21
|
+
end
|
22
|
+
|
23
|
+
config.after_initialize do
|
24
|
+
ActiveSupport.on_load(:action_view) do
|
25
|
+
include Raif::Shared::ConversationsHelper
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
config.after_initialize do
|
30
|
+
next unless Raif.config.open_ai_models_enabled
|
31
|
+
|
32
|
+
Raif.default_llms[Raif::Llms::OpenAi].each do |llm_config|
|
33
|
+
Raif.register_llm(Raif::Llms::OpenAi, **llm_config)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
config.after_initialize do
|
38
|
+
next unless Raif.config.anthropic_models_enabled
|
39
|
+
|
40
|
+
Raif.default_llms[Raif::Llms::Anthropic].each do |llm_config|
|
41
|
+
Raif.register_llm(Raif::Llms::Anthropic, **llm_config)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
config.after_initialize do
|
46
|
+
next unless Raif.config.anthropic_bedrock_models_enabled
|
47
|
+
|
48
|
+
require "aws-sdk-bedrock"
|
49
|
+
require "aws-sdk-bedrockruntime"
|
50
|
+
|
51
|
+
Raif.default_llms[Raif::Llms::BedrockClaude].each do |llm_config|
|
52
|
+
Raif.register_llm(Raif::Llms::BedrockClaude, **llm_config)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
config.after_initialize do
|
57
|
+
next unless Rails.env.test?
|
58
|
+
|
59
|
+
Raif.config.conversation_types += ["Raif::TestConversation"]
|
60
|
+
|
61
|
+
require "#{Raif::Engine.root}/spec/support/test_llm"
|
62
|
+
Raif.register_llm(Raif::Llms::Test, key: :raif_test_llm, api_name: "raif-test-llm")
|
63
|
+
end
|
64
|
+
|
65
|
+
config.after_initialize do
|
66
|
+
Raif.config.validate!
|
67
|
+
end
|
68
|
+
|
69
|
+
initializer "raif.assets" do
|
70
|
+
if Rails.application.config.respond_to?(:assets)
|
71
|
+
Rails.application.config.assets.precompile += [
|
72
|
+
"raif.js",
|
73
|
+
"raif.css",
|
74
|
+
"raif_admin.css"
|
75
|
+
]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
initializer "raif.importmap", before: "importmap" do |app|
|
80
|
+
if Rails.application.respond_to?(:importmap)
|
81
|
+
app.config.importmap.paths << Raif::Engine.root.join("config/importmap.rb")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
data/lib/raif/errors.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "raif/errors/invalid_config_error"
|
4
|
+
require "raif/errors/action_not_authorized_error"
|
5
|
+
require "raif/errors/invalid_user_tool_type_error"
|
6
|
+
require "raif/errors/invalid_conversation_type_error"
|
7
|
+
require "raif/errors/open_ai/json_schema_error"
|
8
|
+
require "raif/errors/open_ai/api_error"
|
9
|
+
require "raif/errors/anthropic/api_error"
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
SUPPORTED_LANGUAGES = [
|
5
|
+
"ar",
|
6
|
+
"da",
|
7
|
+
"de",
|
8
|
+
"en",
|
9
|
+
"es",
|
10
|
+
"fi",
|
11
|
+
"fr",
|
12
|
+
"he",
|
13
|
+
"hi",
|
14
|
+
"it",
|
15
|
+
"ja",
|
16
|
+
"ko",
|
17
|
+
"nl",
|
18
|
+
"no",
|
19
|
+
"pl",
|
20
|
+
"pt",
|
21
|
+
"ru",
|
22
|
+
"sv",
|
23
|
+
"th",
|
24
|
+
"tr",
|
25
|
+
"uk",
|
26
|
+
"vi",
|
27
|
+
"zh",
|
28
|
+
].freeze
|
29
|
+
|
30
|
+
def self.supported_languages
|
31
|
+
SUPPORTED_LANGUAGES
|
32
|
+
end
|
33
|
+
end
|
data/lib/raif/rspec.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../spec/support/rspec_helpers"
|
4
|
+
require_relative "../../spec/support/test_model_tool"
|
5
|
+
require_relative "../../spec/support/test_conversation"
|
6
|
+
require_relative "../../spec/support/test_task"
|
7
|
+
require_relative "../../spec/support/test_llm"
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Raif::Utils::ReadableContentExtractor
|
4
|
+
attr_reader :raw_html
|
5
|
+
|
6
|
+
def initialize(raw_html)
|
7
|
+
@raw_html = raw_html
|
8
|
+
end
|
9
|
+
|
10
|
+
TAG_REMOVE_LIST = [
|
11
|
+
"a",
|
12
|
+
"button",
|
13
|
+
"form",
|
14
|
+
"iframe",
|
15
|
+
"img",
|
16
|
+
"input",
|
17
|
+
"label",
|
18
|
+
"nav",
|
19
|
+
"noscript",
|
20
|
+
"script",
|
21
|
+
"style",
|
22
|
+
"svg",
|
23
|
+
"footer"
|
24
|
+
]
|
25
|
+
|
26
|
+
# This will first remove all tags in TAG_REMOVE_LIST and their children.
|
27
|
+
# Things in TAG_REMOVE_LIST are things that we do not consider likely to contain readable content.
|
28
|
+
# We also call scrub!(:strip) to remove anything unsafe, but leave the text content.
|
29
|
+
def extract_readable_content
|
30
|
+
body_content = Loofah.html5_document(raw_html).at("body")
|
31
|
+
return raw_html unless body_content
|
32
|
+
|
33
|
+
scrubbed_html = body_content
|
34
|
+
.scrub!(readable_content_scrubber)
|
35
|
+
.scrub!(empty_node_scrubber)
|
36
|
+
.scrub!(:strip)
|
37
|
+
|
38
|
+
scrubbed_html.inner_html
|
39
|
+
end
|
40
|
+
|
41
|
+
def readable_content_scrubber
|
42
|
+
@readable_content_scrubber ||= Loofah::Scrubber.new do |node|
|
43
|
+
# if the node is something we don't consider readable content, remove it entirely
|
44
|
+
node.remove if TAG_REMOVE_LIST.include?(node.name)
|
45
|
+
|
46
|
+
# strip all attributes from the tags
|
47
|
+
node.attributes.each { |attr| node.remove_attribute(attr.first) }
|
48
|
+
|
49
|
+
# remove html comments
|
50
|
+
node.remove if node.comment?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def empty_node_scrubber
|
55
|
+
# remove empty nodes from the bottom up so any parents that have only empty children also get removed
|
56
|
+
@empty_node_scrubber ||= Loofah::Scrubber.new(direction: :bottom_up) do |node|
|
57
|
+
node.remove if node.children.empty? && node.text.strip.empty?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/lib/raif/utils.rb
ADDED
data/lib/raif/version.rb
ADDED
data/lib/raif.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "raif/version"
|
4
|
+
require "raif/languages"
|
5
|
+
require "raif/engine"
|
6
|
+
require "raif/configuration"
|
7
|
+
require "raif/errors"
|
8
|
+
require "raif/utils"
|
9
|
+
require "raif/default_llms"
|
10
|
+
require "faraday"
|
11
|
+
require "loofah"
|
12
|
+
require "pagy"
|
13
|
+
require "reverse_markdown"
|
14
|
+
require "turbo-rails"
|
15
|
+
|
16
|
+
module Raif
|
17
|
+
class << self
|
18
|
+
attr_accessor :configuration
|
19
|
+
attr_accessor :llm_registry
|
20
|
+
|
21
|
+
attr_writer :logger
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.config
|
25
|
+
@configuration ||= Raif::Configuration.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.configure
|
29
|
+
yield(config)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.logger
|
33
|
+
@logger ||= Rails.logger
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.register_llm(llm_class, llm_config)
|
37
|
+
llm = llm_class.new(**llm_config)
|
38
|
+
|
39
|
+
unless llm.valid?
|
40
|
+
raise ArgumentError, "The LLM you tried to register is invalid: #{llm.errors.full_messages.join(", ")}"
|
41
|
+
end
|
42
|
+
|
43
|
+
@llm_registry ||= {}
|
44
|
+
@llm_registry[llm.key] = llm_config.merge(llm_class: llm_class)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.llm(model_key)
|
48
|
+
llm_config = llm_registry[model_key]
|
49
|
+
|
50
|
+
if llm_config.nil?
|
51
|
+
raise ArgumentError, "No LLM found for model key: #{model_key}. Available models: #{available_llm_keys.join(", ")}"
|
52
|
+
end
|
53
|
+
|
54
|
+
llm_class = llm_config[:llm_class]
|
55
|
+
llm_class.new(**llm_config.except(:llm_class))
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.available_llms
|
59
|
+
llm_registry.values
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.available_llm_keys
|
63
|
+
llm_registry.keys
|
64
|
+
end
|
65
|
+
end
|