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.
Files changed (121) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +678 -0
  4. data/Rakefile +20 -0
  5. data/app/assets/builds/raif.css +74 -0
  6. data/app/assets/builds/raif_admin.css +266 -0
  7. data/app/assets/config/raif_manifest.js +1 -0
  8. data/app/assets/javascript/raif/controllers/conversations_controller.js +11 -0
  9. data/app/assets/javascript/raif/stream_actions/raif_scroll_to_bottom.js +12 -0
  10. data/app/assets/javascript/raif.js +10 -0
  11. data/app/assets/stylesheets/raif/admin/conversation.scss +64 -0
  12. data/app/assets/stylesheets/raif/loader.scss +85 -0
  13. data/app/assets/stylesheets/raif.scss +1 -0
  14. data/app/assets/stylesheets/raif_admin.scss +299 -0
  15. data/app/controllers/raif/admin/agents_controller.rb +17 -0
  16. data/app/controllers/raif/admin/application_controller.rb +20 -0
  17. data/app/controllers/raif/admin/conversations_controller.rb +17 -0
  18. data/app/controllers/raif/admin/model_completions_controller.rb +17 -0
  19. data/app/controllers/raif/admin/model_tool_invocations_controller.rb +17 -0
  20. data/app/controllers/raif/admin/tasks_controller.rb +23 -0
  21. data/app/controllers/raif/application_controller.rb +20 -0
  22. data/app/controllers/raif/conversation_entries_controller.rb +60 -0
  23. data/app/controllers/raif/conversations_controller.rb +58 -0
  24. data/app/helpers/raif/application_helper.rb +7 -0
  25. data/app/helpers/raif/shared/conversations_helper.rb +13 -0
  26. data/app/jobs/raif/application_job.rb +8 -0
  27. data/app/jobs/raif/conversation_entry_job.rb +30 -0
  28. data/app/models/raif/agent.rb +133 -0
  29. data/app/models/raif/agents/native_tool_calling_agent.rb +127 -0
  30. data/app/models/raif/agents/re_act_agent.rb +121 -0
  31. data/app/models/raif/agents/re_act_step.rb +33 -0
  32. data/app/models/raif/application_record.rb +14 -0
  33. data/app/models/raif/concerns/boolean_timestamp.rb +69 -0
  34. data/app/models/raif/concerns/has_available_model_tools.rb +13 -0
  35. data/app/models/raif/concerns/has_llm.rb +19 -0
  36. data/app/models/raif/concerns/has_requested_language.rb +20 -0
  37. data/app/models/raif/concerns/invokes_model_tools.rb +13 -0
  38. data/app/models/raif/concerns/llm_response_parsing.rb +44 -0
  39. data/app/models/raif/conversation.rb +67 -0
  40. data/app/models/raif/conversation_entry.rb +85 -0
  41. data/app/models/raif/llm.rb +88 -0
  42. data/app/models/raif/llms/anthropic.rb +120 -0
  43. data/app/models/raif/llms/bedrock_claude.rb +134 -0
  44. data/app/models/raif/llms/open_ai.rb +259 -0
  45. data/app/models/raif/model_completion.rb +28 -0
  46. data/app/models/raif/model_tool.rb +69 -0
  47. data/app/models/raif/model_tool_invocation.rb +43 -0
  48. data/app/models/raif/model_tools/agent_final_answer.rb +46 -0
  49. data/app/models/raif/model_tools/fetch_url.rb +57 -0
  50. data/app/models/raif/model_tools/wikipedia_search.rb +78 -0
  51. data/app/models/raif/task.rb +137 -0
  52. data/app/models/raif/user_tool_invocation.rb +29 -0
  53. data/app/views/layouts/raif/admin.html.erb +98 -0
  54. data/app/views/raif/admin/agents/_agent.html.erb +18 -0
  55. data/app/views/raif/admin/agents/_conversation_message.html.erb +15 -0
  56. data/app/views/raif/admin/agents/index.html.erb +33 -0
  57. data/app/views/raif/admin/agents/show.html.erb +131 -0
  58. data/app/views/raif/admin/conversations/_conversation.html.erb +7 -0
  59. data/app/views/raif/admin/conversations/_conversation_entry.html.erb +34 -0
  60. data/app/views/raif/admin/conversations/index.html.erb +32 -0
  61. data/app/views/raif/admin/conversations/show.html.erb +56 -0
  62. data/app/views/raif/admin/model_completions/_model_completion.html.erb +9 -0
  63. data/app/views/raif/admin/model_completions/index.html.erb +34 -0
  64. data/app/views/raif/admin/model_completions/show.html.erb +117 -0
  65. data/app/views/raif/admin/model_tool_invocations/_model_tool_invocation.html.erb +16 -0
  66. data/app/views/raif/admin/model_tool_invocations/index.html.erb +33 -0
  67. data/app/views/raif/admin/model_tool_invocations/show.html.erb +66 -0
  68. data/app/views/raif/admin/tasks/_task.html.erb +19 -0
  69. data/app/views/raif/admin/tasks/index.html.erb +49 -0
  70. data/app/views/raif/admin/tasks/show.html.erb +176 -0
  71. data/app/views/raif/conversation_entries/_conversation_entry.html.erb +26 -0
  72. data/app/views/raif/conversation_entries/_form.html.erb +25 -0
  73. data/app/views/raif/conversation_entries/_form_with_available_tools.html.erb +4 -0
  74. data/app/views/raif/conversation_entries/_form_with_user_tool_invocation.html.erb +18 -0
  75. data/app/views/raif/conversation_entries/_message.html.erb +17 -0
  76. data/app/views/raif/conversation_entries/_model_response_avatar.html.erb +1 -0
  77. data/app/views/raif/conversation_entries/_user_avatar.html.erb +1 -0
  78. data/app/views/raif/conversation_entries/create.turbo_stream.erb +11 -0
  79. data/app/views/raif/conversation_entries/new.turbo_stream.erb +6 -0
  80. data/app/views/raif/conversations/_available_user_tools.html.erb +11 -0
  81. data/app/views/raif/conversations/_full_conversation.html.erb +15 -0
  82. data/app/views/raif/conversations/show.html.erb +1 -0
  83. data/config/i18n-tasks.yml +181 -0
  84. data/config/importmap.rb +6 -0
  85. data/config/initializers/pagy.rb +14 -0
  86. data/config/locales/admin.en.yml +91 -0
  87. data/config/locales/en.yml +50 -0
  88. data/config/routes.rb +22 -0
  89. data/db/migrate/20250224234252_create_raif_tables.rb +114 -0
  90. data/lib/generators/raif/agent/agent_generator.rb +22 -0
  91. data/lib/generators/raif/agent/templates/agent.rb.tt +28 -0
  92. data/lib/generators/raif/conversation/conversation_generator.rb +27 -0
  93. data/lib/generators/raif/conversation/templates/conversation.rb.tt +37 -0
  94. data/lib/generators/raif/install/install_generator.rb +31 -0
  95. data/lib/generators/raif/install/templates/initializer.rb +81 -0
  96. data/lib/generators/raif/model_tool/model_tool_generator.rb +27 -0
  97. data/lib/generators/raif/model_tool/templates/model_tool.rb.tt +74 -0
  98. data/lib/generators/raif/task/task_generator.rb +28 -0
  99. data/lib/generators/raif/task/templates/application_task.rb.tt +7 -0
  100. data/lib/generators/raif/task/templates/task.rb.tt +52 -0
  101. data/lib/generators/raif/views_generator.rb +22 -0
  102. data/lib/raif/configuration.rb +82 -0
  103. data/lib/raif/default_llms.rb +37 -0
  104. data/lib/raif/engine.rb +86 -0
  105. data/lib/raif/errors/action_not_authorized_error.rb +8 -0
  106. data/lib/raif/errors/anthropic/api_error.rb +10 -0
  107. data/lib/raif/errors/invalid_config_error.rb +8 -0
  108. data/lib/raif/errors/invalid_conversation_type_error.rb +8 -0
  109. data/lib/raif/errors/invalid_user_tool_type_error.rb +8 -0
  110. data/lib/raif/errors/open_ai/api_error.rb +10 -0
  111. data/lib/raif/errors/open_ai/json_schema_error.rb +10 -0
  112. data/lib/raif/errors.rb +9 -0
  113. data/lib/raif/languages.rb +33 -0
  114. data/lib/raif/rspec.rb +7 -0
  115. data/lib/raif/utils/html_to_markdown_converter.rb +7 -0
  116. data/lib/raif/utils/readable_content_extractor.rb +61 -0
  117. data/lib/raif/utils.rb +6 -0
  118. data/lib/raif/version.rb +5 -0
  119. data/lib/raif.rb +65 -0
  120. data/lib/tasks/raif_tasks.rake +6 -0
  121. 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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Raif
4
+ class ApplicationTask < Raif::Task
5
+ # Add any shared task behavior here
6
+ end
7
+ 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