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,50 @@
|
|
1
|
+
---
|
2
|
+
en:
|
3
|
+
raif:
|
4
|
+
agents:
|
5
|
+
errors:
|
6
|
+
available_model_tools:
|
7
|
+
too_short: must have at least 1 tool
|
8
|
+
common:
|
9
|
+
send: Send
|
10
|
+
there_was_an_error_generating_this_response: There was an error generating this response
|
11
|
+
tools: Tools
|
12
|
+
type_your_message: Type your message...
|
13
|
+
conversation:
|
14
|
+
initial_chat_message: Hello, how can I help you today?
|
15
|
+
languages:
|
16
|
+
ar: Arabic
|
17
|
+
da: Danish
|
18
|
+
de: German
|
19
|
+
en: English
|
20
|
+
es: Spanish
|
21
|
+
fi: Finnish
|
22
|
+
fr: French
|
23
|
+
he: Hebrew
|
24
|
+
hi: Hindi
|
25
|
+
it: Italian
|
26
|
+
ja: Japanese
|
27
|
+
ko: Korean
|
28
|
+
nl: Dutch
|
29
|
+
pl: Polish
|
30
|
+
pt: Portuguese
|
31
|
+
ru: Russian
|
32
|
+
sv: Swedish
|
33
|
+
th: Thai
|
34
|
+
tr: Turkish
|
35
|
+
uk: Ukrainian
|
36
|
+
vi: Vietnamese
|
37
|
+
zh: Chinese
|
38
|
+
model_names:
|
39
|
+
anthropic_claude_3_5_haiku: Anthropic Claude 3.5 Haiku
|
40
|
+
anthropic_claude_3_5_sonnet: Anthropic Claude 3.5 Sonnet
|
41
|
+
anthropic_claude_3_7_sonnet: Anthropic Claude 3.7 Sonnet
|
42
|
+
anthropic_claude_3_opus: Anthropic Claude 3 Opus
|
43
|
+
bedrock_claude_3_5_haiku: Anthropic Claude 3.5 Haiku (via AWS Bedrock)
|
44
|
+
bedrock_claude_3_5_sonnet: Anthropic Claude 3.5 Sonnet (via AWS Bedrock)
|
45
|
+
bedrock_claude_3_7_sonnet: Anthropic Claude 3.7 Sonnet (via AWS Bedrock)
|
46
|
+
bedrock_claude_3_opus: Anthropic Claude 3 Opus (via AWS Bedrock)
|
47
|
+
open_ai_gpt_3_5_turbo: OpenAI GPT-3.5 Turbo
|
48
|
+
open_ai_gpt_4o: OpenAI GPT-4o
|
49
|
+
open_ai_gpt_4o_mini: OpenAI GPT-4o Mini
|
50
|
+
raif_test_llm: Raif Test LLM
|
data/config/routes.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Raif::Engine.routes.draw do
|
4
|
+
resources :conversations,
|
5
|
+
only: [:index, :show],
|
6
|
+
controller: "/#{Raif.config.conversations_controller.constantize.controller_path}" do
|
7
|
+
resources :conversation_entries,
|
8
|
+
only: [:new, :create],
|
9
|
+
as: :entries,
|
10
|
+
path: "entries",
|
11
|
+
controller: "/#{Raif.config.conversation_entries_controller.constantize.controller_path}"
|
12
|
+
end
|
13
|
+
|
14
|
+
namespace :admin do
|
15
|
+
root to: redirect("admin/model_completions")
|
16
|
+
resources :tasks, only: [:index, :show]
|
17
|
+
resources :conversations, only: [:index, :show]
|
18
|
+
resources :model_completions, only: [:index, :show]
|
19
|
+
resources :agents, only: [:index, :show]
|
20
|
+
resources :model_tool_invocations, only: [:index, :show]
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateRaifTables < ActiveRecord::Migration[8.0]
|
4
|
+
def change
|
5
|
+
json_column_type = if connection.adapter_name.downcase.include?("postgresql")
|
6
|
+
:jsonb
|
7
|
+
else
|
8
|
+
:json
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table :raif_tasks do |t|
|
12
|
+
t.string :type, null: false, index: true
|
13
|
+
t.text :prompt
|
14
|
+
t.text :raw_response
|
15
|
+
t.references :creator, polymorphic: true, null: false, index: true
|
16
|
+
t.text :system_prompt
|
17
|
+
t.string :requested_language_key
|
18
|
+
t.integer :response_format, default: 0, null: false
|
19
|
+
t.datetime :started_at
|
20
|
+
t.datetime :completed_at
|
21
|
+
t.datetime :failed_at
|
22
|
+
t.send json_column_type, :available_model_tools, null: false
|
23
|
+
t.string :llm_model_key, null: false
|
24
|
+
|
25
|
+
t.timestamps
|
26
|
+
end
|
27
|
+
|
28
|
+
create_table :raif_conversations do |t|
|
29
|
+
t.string :llm_model_key, null: false
|
30
|
+
t.references :creator, polymorphic: true, null: false, index: true
|
31
|
+
t.string :requested_language_key
|
32
|
+
t.string :type, null: false
|
33
|
+
t.text :system_prompt
|
34
|
+
t.send json_column_type, :available_model_tools, null: false
|
35
|
+
t.send json_column_type, :available_user_tools, null: false
|
36
|
+
t.integer :conversation_entries_count, default: 0, null: false
|
37
|
+
|
38
|
+
t.timestamps
|
39
|
+
end
|
40
|
+
|
41
|
+
create_table :raif_conversation_entries do |t|
|
42
|
+
t.references :raif_conversation, null: false, foreign_key: true
|
43
|
+
t.references :creator, polymorphic: true, null: false, index: true
|
44
|
+
t.datetime :started_at
|
45
|
+
t.datetime :completed_at
|
46
|
+
t.datetime :failed_at
|
47
|
+
t.text :user_message
|
48
|
+
t.text :raw_response
|
49
|
+
t.text :model_response_message
|
50
|
+
|
51
|
+
t.timestamps
|
52
|
+
end
|
53
|
+
|
54
|
+
create_table :raif_model_tool_invocations do |t|
|
55
|
+
t.references :source, polymorphic: true, null: false, index: true
|
56
|
+
t.string :tool_type, null: false
|
57
|
+
t.send json_column_type, :tool_arguments, null: false
|
58
|
+
t.send json_column_type, :result, null: false
|
59
|
+
t.datetime :completed_at
|
60
|
+
t.datetime :failed_at
|
61
|
+
|
62
|
+
t.timestamps
|
63
|
+
end
|
64
|
+
|
65
|
+
create_table :raif_user_tool_invocations do |t|
|
66
|
+
t.references :raif_conversation_entry, null: false, foreign_key: true
|
67
|
+
t.string :type, null: false
|
68
|
+
t.send json_column_type, :tool_settings, null: false
|
69
|
+
|
70
|
+
t.timestamps
|
71
|
+
end
|
72
|
+
|
73
|
+
create_table :raif_agents do |t|
|
74
|
+
t.string :type, null: false
|
75
|
+
t.string :llm_model_key, null: false
|
76
|
+
t.text :task
|
77
|
+
t.text :system_prompt
|
78
|
+
t.text :final_answer
|
79
|
+
t.integer :max_iterations, default: 10, null: false
|
80
|
+
t.integer :iteration_count, default: 0, null: false
|
81
|
+
t.send json_column_type, :available_model_tools, null: false
|
82
|
+
t.references :creator, polymorphic: true, null: false, index: true
|
83
|
+
t.string :requested_language_key
|
84
|
+
t.datetime :started_at
|
85
|
+
t.datetime :completed_at
|
86
|
+
t.datetime :failed_at
|
87
|
+
t.text :failure_reason
|
88
|
+
t.send json_column_type, :conversation_history, null: false
|
89
|
+
|
90
|
+
t.timestamps
|
91
|
+
end
|
92
|
+
|
93
|
+
create_table :raif_model_completions do |t|
|
94
|
+
t.references :source, polymorphic: true, index: true
|
95
|
+
t.string :llm_model_key, null: false
|
96
|
+
t.string :model_api_name, null: false
|
97
|
+
t.send json_column_type, :available_model_tools, null: false
|
98
|
+
t.send json_column_type, :messages, null: false
|
99
|
+
t.text :system_prompt
|
100
|
+
t.integer :response_format, default: 0, null: false
|
101
|
+
t.string :response_format_parameter
|
102
|
+
t.decimal :temperature, precision: 5, scale: 3
|
103
|
+
t.integer :max_completion_tokens
|
104
|
+
t.integer :completion_tokens
|
105
|
+
t.integer :prompt_tokens
|
106
|
+
t.text :raw_response
|
107
|
+
t.send json_column_type, :response_tool_calls
|
108
|
+
t.integer :total_tokens
|
109
|
+
|
110
|
+
t.timestamps
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
class AgentGenerator < Rails::Generators::NamedBase
|
5
|
+
source_root File.expand_path("templates", __dir__)
|
6
|
+
desc "Creates a new Raif::Agent subclass in app/models/raif/agents"
|
7
|
+
|
8
|
+
def create_agent
|
9
|
+
template "agent.rb.tt", "app/models/raif/agents/#{file_name}.rb"
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def class_name
|
15
|
+
name.classify
|
16
|
+
end
|
17
|
+
|
18
|
+
def file_name
|
19
|
+
name.underscore
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
module Agents
|
5
|
+
class <%= class_name %> < Raif::Agent
|
6
|
+
# If you want to always include a certain set of model tools with this agent type,
|
7
|
+
# uncomment this callback to populate the available_model_tools attribute with your desired model tools.
|
8
|
+
# before_create -> {
|
9
|
+
# self.available_model_tools ||= [
|
10
|
+
# Raif::ModelTools::WikipediaSearchTool,
|
11
|
+
# Raif::ModelTools::FetchUrlTool
|
12
|
+
# ]
|
13
|
+
# }
|
14
|
+
|
15
|
+
# Enter your agent's system prompt here. Alternatively, you can change your agent's superclass
|
16
|
+
# to an existing agent types (like Raif::Agents::ReActAgent) to utilize an existing system prompt.
|
17
|
+
def build_system_prompt
|
18
|
+
# TODO: Implement your system prompt here
|
19
|
+
end
|
20
|
+
|
21
|
+
# Each iteration of the agent loop will generate a new Raif::ModelCompletion record and
|
22
|
+
# then call this method with it as an argument.
|
23
|
+
def process_iteration_model_completion(model_completion)
|
24
|
+
# TODO: Implement your iteration processing here
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
module Generators
|
5
|
+
class ConversationGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
7
|
+
|
8
|
+
desc "Creates a new conversation type in the app/models/raif/conversations directory"
|
9
|
+
|
10
|
+
def create_conversation_file
|
11
|
+
template "conversation.rb.tt", File.join("app/models/raif/conversations", "#{file_name}.rb")
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_directory
|
15
|
+
empty_directory "app/models/raif/conversations" unless File.directory?("app/models/raif/conversations")
|
16
|
+
end
|
17
|
+
|
18
|
+
def success_message
|
19
|
+
say_status :success, "Conversation type created successfully", :green
|
20
|
+
say "\nYou can now implement your conversation type in:"
|
21
|
+
say " app/models/raif/conversations/#{file_name}.rb\n\n"
|
22
|
+
say "\nDon't forget to add it to the config.conversation_types in your Raif configuration"
|
23
|
+
say "For example: config.conversation_types += ['Raif::Conversations::#{class_name}']\n\n"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
module Conversations
|
5
|
+
class <%= class_name %> < Raif::Conversation
|
6
|
+
# If you want to always include a certain set of model tools with this conversation type,
|
7
|
+
# uncomment this callback to populate the available_model_tools attribute with your desired model tools.
|
8
|
+
# before_create -> { self.available_model_tools = ["Raif::ModelTools::Example"] }
|
9
|
+
|
10
|
+
# Override the methods below to customize the system prompt for this conversation type.
|
11
|
+
# Raif::Conversation expects a JSON response with a message key from the model, so make sure your system prompt instructs the model to respond accordingly.
|
12
|
+
# def system_prompt_intro
|
13
|
+
# Raif.config.conversation_system_prompt_intro
|
14
|
+
# end
|
15
|
+
|
16
|
+
# def build_system_prompt
|
17
|
+
# <<~PROMPT
|
18
|
+
# #{system_prompt_intro}
|
19
|
+
#
|
20
|
+
# # Your Responses
|
21
|
+
# Your responses should always be in JSON format with a "message" field containing your response to your collaborator. For example:
|
22
|
+
# {
|
23
|
+
# "message": "Your response message"
|
24
|
+
# }
|
25
|
+
# #{tool_usage_system_prompt}
|
26
|
+
# #{system_prompt_reminders}
|
27
|
+
# #{system_prompt_language_preference}
|
28
|
+
# PROMPT
|
29
|
+
# end
|
30
|
+
|
31
|
+
# Override this method to set the initial message shown to the user.
|
32
|
+
# def initial_chat_message
|
33
|
+
# I18n.t("#{self.class.name.underscore.gsub("/", ".")}.initial_chat_message")
|
34
|
+
# end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
require "rails/generators/migration"
|
5
|
+
|
6
|
+
module Raif
|
7
|
+
module Generators
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
9
|
+
include Rails::Generators::Migration
|
10
|
+
|
11
|
+
source_root File.expand_path("templates", __dir__)
|
12
|
+
|
13
|
+
def self.next_migration_number(path)
|
14
|
+
next_migration_number = current_migration_number(path) + 1
|
15
|
+
ActiveRecord::Migration.next_migration_number(next_migration_number)
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy_initializer
|
19
|
+
template "initializer.rb", "config/initializers/raif.rb"
|
20
|
+
end
|
21
|
+
|
22
|
+
def install_migrations
|
23
|
+
rake "raif:install:migrations"
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_engine_route
|
27
|
+
route 'mount Raif::Engine => "/raif"'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Raif.configure do |config|
|
4
|
+
# Your OpenAI API key. Defaults to ENV["OPENAI_API_KEY"]
|
5
|
+
# config.open_ai_api_key = ENV["OPENAI_API_KEY"]
|
6
|
+
|
7
|
+
# Whether OpenAI models are enabled. Defaults to true
|
8
|
+
# config.open_ai_models_enabled = true
|
9
|
+
|
10
|
+
# Your Anthropic API key. Defaults to ENV["ANTHROPIC_API_KEY"]
|
11
|
+
# config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
|
12
|
+
|
13
|
+
# Whether Anthropic models are enabled. Defaults to true
|
14
|
+
# config.anthropic_models_enabled = true
|
15
|
+
|
16
|
+
# Whether Anthropic models via AWS Bedrock are enabled. Defaults to true
|
17
|
+
# config.anthropic_bedrock_models_enabled = true
|
18
|
+
|
19
|
+
# The AWS Bedrock region to use. Defaults to "us-east-1"
|
20
|
+
# config.aws_bedrock_region = "us-east-1"
|
21
|
+
|
22
|
+
# The default LLM model to use. Defaults to "open_ai_gpt_4o"
|
23
|
+
# Available keys:
|
24
|
+
# open_ai_gpt_4o_mini
|
25
|
+
# open_ai_gpt_4o
|
26
|
+
# open_ai_gpt_3_5_turbo
|
27
|
+
# anthropic_claude_3_7_sonnet
|
28
|
+
# anthropic_claude_3_5_sonnet
|
29
|
+
# anthropic_claude_3_5_haiku
|
30
|
+
# anthropic_claude_3_opus
|
31
|
+
# bedrock_claude_3_5_sonnet
|
32
|
+
# bedrock_claude_3_7_sonnet
|
33
|
+
# bedrock_claude_3_5_haiku
|
34
|
+
# bedrock_claude_3_opus
|
35
|
+
# config.default_llm_model_key = "open_ai_gpt_4o"
|
36
|
+
|
37
|
+
# A lambda that returns true if the current user is authorized to access admin controllers.
|
38
|
+
# By default it returns false, so you must implement this in your application to use the admin controllers.
|
39
|
+
# If your application's user model has an admin? method, you could use something like this:
|
40
|
+
# config.authorize_admin_controller_action = ->{ current_user&.admin? }
|
41
|
+
|
42
|
+
# A lambda that returns true if the current user is authorized to access non-admin controllers.
|
43
|
+
# By default it returns false, so you must implement this in your application to use the non-admin controllers.
|
44
|
+
# If you wanted to allow access to all logged in users, you could use something like this:
|
45
|
+
# config.authorize_controller_action = ->{ current_user.present? }
|
46
|
+
|
47
|
+
# The system prompt intro for Raif::Task instances. Defaults to "You are a helpful assistant."
|
48
|
+
# config.task_system_prompt_intro = "You are a helpful assistant."
|
49
|
+
|
50
|
+
# The system prompt intro for Raif::Conversation instances. Defaults to "You are a helpful assistant who is collaborating with a teammate."
|
51
|
+
# config.conversation_system_prompt_intro = "You are a helpful assistant who is collaborating with a teammate."
|
52
|
+
|
53
|
+
# The conversation types that are available. Defaults to ["Raif::Conversation"]
|
54
|
+
# If you want to use custom conversation types that inherits from Raif::Conversation, you can add them here.
|
55
|
+
# config.conversation_types += ["Raif::MyConversation"]
|
56
|
+
|
57
|
+
# The controller class for conversations. Defaults to "Raif::ConversationsController"
|
58
|
+
# If you want to use a custom controller that inherits from Raif::ConversationsController, you can set it here.
|
59
|
+
# config.conversations_controller = "Raif::ConversationsController"
|
60
|
+
|
61
|
+
# The controller class for conversation entries. Defaults to "Raif::ConversationEntriesController"
|
62
|
+
# If you want to use a custom controller that inherits from Raif::ConversationEntriesController, you can set it here.
|
63
|
+
# config.conversation_entries_controller = "Raif::ConversationEntriesController"
|
64
|
+
|
65
|
+
# The method to call to get the current user. Defaults to :current_user
|
66
|
+
# config.current_user_method = :current_user
|
67
|
+
|
68
|
+
# The agent types that are available. Defaults to Set.new(["Raif::Agents::ReActAgent", "Raif::Agents::NativeToolCallingAgent"])
|
69
|
+
# If you want to use custom agent types that inherits from Raif::Agent, you can add them here.
|
70
|
+
# config.agent_types += ["MyAgent"]
|
71
|
+
|
72
|
+
# The superclass for Raif models. Defaults to "ApplicationRecord"
|
73
|
+
# config.model_superclass = "ApplicationRecord"
|
74
|
+
|
75
|
+
# The user tool types that are available. Defaults to []
|
76
|
+
# config.user_tool_types = []
|
77
|
+
|
78
|
+
# Whether LLM API requests are enabled. Defaults to true.
|
79
|
+
# Use this to globally disable requests to LLM APIs.
|
80
|
+
# config.llm_api_requests_enabled = true
|
81
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
module Generators
|
5
|
+
class ModelToolGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
7
|
+
|
8
|
+
desc "Creates a new model tool for the LLM to invoke in app/models/raif/model_tools"
|
9
|
+
|
10
|
+
def create_model_tool_file
|
11
|
+
template "model_tool.rb.tt", File.join("app/models/raif/model_tools", "#{file_name}.rb")
|
12
|
+
end
|
13
|
+
|
14
|
+
def success_message
|
15
|
+
say_status :success, "Model tool created successfully", :green
|
16
|
+
say "\nYou can now implement your model tool in:"
|
17
|
+
say " app/models/raif/model_tools/#{file_name}.rb"
|
18
|
+
say "\nImportant methods to implement:"
|
19
|
+
say " - example_model_invocation: An example of how to invoke the tool, to be provided to the LLM"
|
20
|
+
say " - tool_arguments_schema: JSON schema for validating arguments when the tool is invoked"
|
21
|
+
say " - tool_description: A brief description of what the tool does, to be provided to the LLM"
|
22
|
+
say " - process_invocation: The main method that executes the tool's functionality"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Raif::ModelTools::<%= class_name %> < Raif::ModelTool
|
4
|
+
# For example tool implementations, see:
|
5
|
+
# Wikipedia Search Tool: https://github.com/CultivateLabs/raif/blob/main/app/models/raif/model_tools/wikipedia_search_tool.rb
|
6
|
+
# Fetch URL Tool: https://github.com/CultivateLabs/raif/blob/main/app/models/raif/model_tools/fetch_url_tool.rb
|
7
|
+
|
8
|
+
# An example of how the LLM should invoke your tool. This should return a hash with name and arguments keys.
|
9
|
+
# `to_json` will be called on it and provided to the LLM as an example of how to invoke your tool.
|
10
|
+
def self.example_model_invocation
|
11
|
+
{
|
12
|
+
"name": tool_name,
|
13
|
+
"arguments": { }
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
# Define your tool's argument schema here. It should be a valid JSON schema.
|
18
|
+
# When the model invokes your tool, the arguments it provides will be validated
|
19
|
+
# against this schema using JSON::Validator from the json-schema gem.
|
20
|
+
def self.tool_arguments_schema
|
21
|
+
# For example:
|
22
|
+
# {
|
23
|
+
# type: "object",
|
24
|
+
# additionalProperties: false,
|
25
|
+
# required: ["query"],
|
26
|
+
# properties: {
|
27
|
+
# query: {
|
28
|
+
# type: "string",
|
29
|
+
# description: "The query to search for"
|
30
|
+
# }
|
31
|
+
# }
|
32
|
+
# }
|
33
|
+
# Would expect the model to invoke your tool with an arguments JSON object like:
|
34
|
+
# { "query" : "some query here" }
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.tool_description
|
38
|
+
"Description of your tool that will be provided to the LLM so it knows when to invoke it"
|
39
|
+
end
|
40
|
+
|
41
|
+
# When your tool is invoked by the LLM in a Raif::Agent loop,
|
42
|
+
# the results of the tool invocation are provided back to the LLM as an observation.
|
43
|
+
# This method should return whatever you want provided to the LLM.
|
44
|
+
# For example, if you were implementing a GoogleSearch tool, this might return a JSON
|
45
|
+
# object containing search results for the query.
|
46
|
+
def self.observation_for_invocation(tool_invocation)
|
47
|
+
return "No results found" unless tool_invocation.result.present?
|
48
|
+
|
49
|
+
JSON.pretty_generate(tool_invocation.result)
|
50
|
+
end
|
51
|
+
|
52
|
+
# When the LLM invokes your tool, this method will be called with a `Raif::ModelToolInvocation` record as an argument.
|
53
|
+
# It should handle the actual execution of the tool.
|
54
|
+
# For example, if you are implementing a GoogleSearch tool, this method should run the actual search
|
55
|
+
# and store the results in the tool_invocation's result JSON column.
|
56
|
+
def self.process_invocation(tool_invocation)
|
57
|
+
# Extract arguments from tool_invocation.tool_arguments
|
58
|
+
# query = tool_invocation.tool_arguments["query"]
|
59
|
+
#
|
60
|
+
# Process the invocation and perform the desired action
|
61
|
+
# ...
|
62
|
+
#
|
63
|
+
# Store the results in the tool_invocation
|
64
|
+
# tool_invocation.update!(
|
65
|
+
# result: {
|
66
|
+
# # Your result data structure
|
67
|
+
# }
|
68
|
+
# )
|
69
|
+
#
|
70
|
+
# Return the result
|
71
|
+
# tool_invocation.result
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
module Generators
|
5
|
+
class TaskGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
7
|
+
|
8
|
+
class_option :response_format,
|
9
|
+
type: :string,
|
10
|
+
default: "text",
|
11
|
+
desc: "Response format for the task (text, html, or json)"
|
12
|
+
|
13
|
+
def create_application_task
|
14
|
+
template "application_task.rb.tt", "app/models/raif/application_task.rb" unless File.exist?("app/models/raif/application_task.rb")
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_task_file
|
18
|
+
template "task.rb.tt", File.join("app/models/raif/tasks", class_path, "#{file_name}.rb")
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def task_class_name
|
24
|
+
class_name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
module Tasks
|
5
|
+
class <%= task_class_name %> < Raif::ApplicationTask
|
6
|
+
# Set the response format for the task. Options are :html, :text, or :json.
|
7
|
+
llm_response_format :<%= options[:response_format] %>
|
8
|
+
|
9
|
+
# Define any attributes that are needed for the task.
|
10
|
+
# You can then pass them when running the task and they will be available in build_prompt:
|
11
|
+
# Raif::Tasks::<%= task_class_name %>.run(your_attribute: "some value")
|
12
|
+
# attr_accessor :your_attribute
|
13
|
+
|
14
|
+
<%- if options[:response_format] == "json" -%>
|
15
|
+
# Define a JSON schema that the response should adhere to
|
16
|
+
# def self.json_response_schema
|
17
|
+
# {
|
18
|
+
# type: "object",
|
19
|
+
# additionalProperties: false,
|
20
|
+
# required: ["your_key_here"],
|
21
|
+
# properties: {
|
22
|
+
# your_key_here: {
|
23
|
+
# type: "array",
|
24
|
+
# items: {
|
25
|
+
# type: "object",
|
26
|
+
# additionalProperties: false,
|
27
|
+
# required: ["query", "rationale"],
|
28
|
+
# properties: {
|
29
|
+
# query: { type: "string" },
|
30
|
+
# rationale: { type: "string" }
|
31
|
+
# }
|
32
|
+
# }
|
33
|
+
# }
|
34
|
+
# }
|
35
|
+
# }
|
36
|
+
# end
|
37
|
+
<%- end -%>
|
38
|
+
|
39
|
+
def build_prompt
|
40
|
+
# Implement the LLM prompt for this task.
|
41
|
+
raise NotImplementedError, "Implement #build_prompt in #{self.class}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Optional: Override build_system_prompt if you need custom system instructions.
|
45
|
+
# The default implementation, which you'll get if you call super, will use Raif.config.task_system_prompt_intro
|
46
|
+
# and append the system_prompt_language_preference if the task's requested_language_key is set.
|
47
|
+
# def build_system_prompt
|
48
|
+
# super + "\nAdditional system instructions..."
|
49
|
+
# end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Raif
|
4
|
+
class ViewsGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path("../../../app/views/raif", __dir__)
|
6
|
+
|
7
|
+
desc "Copies Raif conversation views to your application for customization"
|
8
|
+
|
9
|
+
def copy_views
|
10
|
+
directory "conversations", "app/views/raif/conversations"
|
11
|
+
directory "conversation_entries", "app/views/raif/conversation_entries"
|
12
|
+
end
|
13
|
+
|
14
|
+
def success_message
|
15
|
+
say_status :success, "Raif conversation views have been copied to your application", :green
|
16
|
+
say "\nYou can now customize these views in:"
|
17
|
+
say " app/views/raif/conversations/"
|
18
|
+
say " app/views/raif/conversation_entries/"
|
19
|
+
say "\nNote: These views will now override the default Raif engine views."
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|