raif 1.2.2 → 1.4.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 +4 -4
- data/README.md +6 -5
- data/app/assets/builds/raif.css +4 -1
- data/app/assets/builds/raif_admin.css +13 -1
- data/app/assets/javascript/raif/controllers/conversations_controller.js +1 -1
- data/app/assets/stylesheets/raif/admin/conversation.scss +16 -0
- data/app/assets/stylesheets/raif/conversations.scss +3 -0
- data/app/assets/stylesheets/raif.scss +2 -1
- data/app/controllers/raif/admin/application_controller.rb +16 -0
- data/app/controllers/raif/admin/configs_controller.rb +94 -0
- data/app/controllers/raif/admin/model_completions_controller.rb +18 -1
- data/app/controllers/raif/admin/model_tool_invocations_controller.rb +7 -1
- data/app/controllers/raif/admin/stats/model_tool_invocations_controller.rb +21 -0
- data/app/controllers/raif/admin/stats/tasks_controller.rb +15 -6
- data/app/controllers/raif/admin/stats_controller.rb +32 -3
- data/app/controllers/raif/conversation_entries_controller.rb +1 -0
- data/app/controllers/raif/conversations_controller.rb +10 -2
- data/app/jobs/raif/conversation_entry_job.rb +8 -6
- data/app/models/raif/admin/task_stat.rb +7 -0
- data/app/models/raif/agent.rb +63 -2
- data/app/models/raif/agents/native_tool_calling_agent.rb +101 -56
- data/app/models/raif/application_record.rb +18 -0
- data/app/models/raif/concerns/agent_inference_stats.rb +35 -0
- data/app/models/raif/concerns/has_llm.rb +1 -1
- data/app/models/raif/concerns/json_schema_definition.rb +40 -5
- data/app/models/raif/concerns/llms/anthropic/message_formatting.rb +28 -0
- data/app/models/raif/concerns/llms/anthropic/response_tool_calls.rb +24 -0
- data/app/models/raif/concerns/llms/anthropic/tool_formatting.rb +4 -0
- data/app/models/raif/concerns/llms/bedrock/message_formatting.rb +36 -0
- data/app/models/raif/concerns/llms/bedrock/response_tool_calls.rb +26 -0
- data/app/models/raif/concerns/llms/bedrock/tool_formatting.rb +4 -0
- data/app/models/raif/concerns/llms/google/message_formatting.rb +109 -0
- data/app/models/raif/concerns/llms/google/response_tool_calls.rb +32 -0
- data/app/models/raif/concerns/llms/google/tool_formatting.rb +72 -0
- data/app/models/raif/concerns/llms/message_formatting.rb +11 -5
- data/app/models/raif/concerns/llms/open_ai/json_schema_validation.rb +3 -3
- data/app/models/raif/concerns/llms/open_ai_completions/message_formatting.rb +22 -0
- data/app/models/raif/concerns/llms/open_ai_completions/response_tool_calls.rb +22 -0
- data/app/models/raif/concerns/llms/open_ai_completions/tool_formatting.rb +4 -0
- data/app/models/raif/concerns/llms/open_ai_responses/message_formatting.rb +17 -0
- data/app/models/raif/concerns/llms/open_ai_responses/response_tool_calls.rb +26 -0
- data/app/models/raif/concerns/llms/open_ai_responses/tool_formatting.rb +4 -0
- data/app/models/raif/concerns/run_with.rb +127 -0
- data/app/models/raif/conversation.rb +96 -9
- data/app/models/raif/conversation_entry.rb +37 -8
- data/app/models/raif/embedding_model.rb +2 -1
- data/app/models/raif/embedding_models/open_ai.rb +1 -1
- data/app/models/raif/llm.rb +28 -3
- data/app/models/raif/llms/anthropic.rb +7 -19
- data/app/models/raif/llms/bedrock.rb +6 -20
- data/app/models/raif/llms/google.rb +140 -0
- data/app/models/raif/llms/open_ai_base.rb +19 -5
- data/app/models/raif/llms/open_ai_completions.rb +6 -11
- data/app/models/raif/llms/open_ai_responses.rb +6 -16
- data/app/models/raif/llms/open_router.rb +10 -14
- data/app/models/raif/model_completion.rb +61 -0
- data/app/models/raif/model_tool.rb +10 -2
- data/app/models/raif/model_tool_invocation.rb +38 -6
- data/app/models/raif/model_tools/agent_final_answer.rb +2 -7
- data/app/models/raif/model_tools/provider_managed/code_execution.rb +4 -0
- data/app/models/raif/model_tools/provider_managed/image_generation.rb +4 -0
- data/app/models/raif/model_tools/provider_managed/web_search.rb +4 -0
- data/app/models/raif/streaming_responses/google.rb +71 -0
- data/app/models/raif/task.rb +74 -18
- data/app/models/raif/user_tool_invocation.rb +19 -0
- data/app/views/layouts/raif/admin.html.erb +12 -1
- data/app/views/raif/admin/agents/_agent.html.erb +8 -0
- data/app/views/raif/admin/agents/_conversation_message.html.erb +28 -6
- data/app/views/raif/admin/agents/index.html.erb +2 -0
- data/app/views/raif/admin/agents/show.html.erb +46 -1
- data/app/views/raif/admin/configs/show.html.erb +117 -0
- data/app/views/raif/admin/conversations/_conversation_entry.html.erb +29 -34
- data/app/views/raif/admin/conversations/show.html.erb +2 -0
- data/app/views/raif/admin/model_completions/_model_completion.html.erb +9 -0
- data/app/views/raif/admin/model_completions/index.html.erb +26 -0
- data/app/views/raif/admin/model_completions/show.html.erb +124 -61
- data/app/views/raif/admin/model_tool_invocations/index.html.erb +22 -1
- data/app/views/raif/admin/model_tools/_list.html.erb +16 -0
- data/app/views/raif/admin/model_tools/_model_tool.html.erb +36 -0
- data/app/views/raif/admin/stats/_stats_tile.html.erb +34 -0
- data/app/views/raif/admin/stats/index.html.erb +71 -88
- data/app/views/raif/admin/stats/model_tool_invocations/index.html.erb +43 -0
- data/app/views/raif/admin/stats/tasks/index.html.erb +20 -6
- data/app/views/raif/admin/tasks/index.html.erb +6 -1
- data/app/views/raif/admin/tasks/show.html.erb +36 -3
- data/app/views/raif/conversation_entries/_form.html.erb +4 -1
- data/app/views/raif/conversations/_conversation.html.erb +10 -0
- data/app/views/raif/conversations/_entry_processed.turbo_stream.erb +12 -0
- data/app/views/raif/conversations/_full_conversation.html.erb +3 -6
- data/app/views/raif/conversations/_initial_chat_message.html.erb +5 -0
- data/app/views/raif/conversations/index.html.erb +23 -0
- data/config/locales/admin.en.yml +33 -1
- data/config/locales/en.yml +41 -4
- data/config/routes.rb +2 -0
- data/db/migrate/20250804013843_add_task_run_args_to_raif_tasks.rb +13 -0
- data/db/migrate/20250811171150_make_raif_task_creator_optional.rb +8 -0
- data/db/migrate/20250904194456_add_generating_entry_response_to_raif_conversations.rb +7 -0
- data/db/migrate/20250911125234_add_source_to_raif_tasks.rb +7 -0
- data/db/migrate/20251020005853_add_source_to_raif_agents.rb +7 -0
- data/db/migrate/20251020011346_rename_task_run_args_to_run_with.rb +7 -0
- data/db/migrate/20251020011405_add_run_with_to_raif_agents.rb +13 -0
- data/db/migrate/20251024160119_add_llm_messages_max_length_to_raif_conversations.rb +14 -0
- data/db/migrate/20251124185033_add_provider_tool_call_id_to_raif_model_tool_invocations.rb +7 -0
- data/db/migrate/20251128202941_add_tool_choice_to_raif_model_completions.rb +7 -0
- data/db/migrate/20260118144846_add_source_to_raif_conversations.rb +7 -0
- data/db/migrate/20260119000000_add_failure_tracking_to_raif_model_completions.rb +10 -0
- data/db/migrate/20260119000001_add_completed_at_to_raif_model_completions.rb +8 -0
- data/db/migrate/20260119000002_add_started_at_to_raif_model_completions.rb +8 -0
- data/exe/raif +7 -0
- data/lib/generators/raif/agent/agent_generator.rb +22 -7
- data/lib/generators/raif/agent/templates/agent.rb.tt +20 -24
- data/lib/generators/raif/agent/templates/agent_eval_set.rb.tt +48 -0
- data/lib/generators/raif/agent/templates/application_agent.rb.tt +1 -3
- data/lib/generators/raif/base_generator.rb +19 -0
- data/lib/generators/raif/conversation/conversation_generator.rb +21 -2
- data/lib/generators/raif/conversation/templates/application_conversation.rb.tt +0 -2
- data/lib/generators/raif/conversation/templates/conversation.rb.tt +34 -32
- data/lib/generators/raif/conversation/templates/conversation_eval_set.rb.tt +70 -0
- data/lib/generators/raif/eval_set/eval_set_generator.rb +28 -0
- data/lib/generators/raif/eval_set/templates/eval_set.rb.tt +21 -0
- data/lib/generators/raif/evals/setup/setup_generator.rb +47 -0
- data/lib/generators/raif/install/install_generator.rb +15 -0
- data/lib/generators/raif/install/templates/initializer.rb +89 -10
- data/lib/generators/raif/model_tool/model_tool_generator.rb +5 -5
- data/lib/generators/raif/model_tool/templates/model_tool.rb.tt +78 -78
- data/lib/generators/raif/model_tool/templates/model_tool_invocation_partial.html.erb.tt +1 -1
- data/lib/generators/raif/task/task_generator.rb +22 -3
- data/lib/generators/raif/task/templates/application_task.rb.tt +0 -2
- data/lib/generators/raif/task/templates/task.rb.tt +55 -59
- data/lib/generators/raif/task/templates/task_eval_set.rb.tt +54 -0
- data/lib/raif/cli/base.rb +39 -0
- data/lib/raif/cli/evals.rb +47 -0
- data/lib/raif/cli/evals_setup.rb +27 -0
- data/lib/raif/cli.rb +67 -0
- data/lib/raif/configuration.rb +57 -8
- data/lib/raif/engine.rb +8 -0
- data/lib/raif/errors/instance_dependent_schema_error.rb +8 -0
- data/lib/raif/errors/streaming_error.rb +6 -3
- data/lib/raif/errors.rb +1 -0
- data/lib/raif/evals/eval.rb +30 -0
- data/lib/raif/evals/eval_set.rb +111 -0
- data/lib/raif/evals/eval_sets/expectations.rb +53 -0
- data/lib/raif/evals/eval_sets/llm_judge_expectations.rb +255 -0
- data/lib/raif/evals/expectation_result.rb +39 -0
- data/lib/raif/evals/llm_judge.rb +32 -0
- data/lib/raif/evals/llm_judges/binary.rb +94 -0
- data/lib/raif/evals/llm_judges/comparative.rb +89 -0
- data/lib/raif/evals/llm_judges/scored.rb +63 -0
- data/lib/raif/evals/llm_judges/summarization.rb +166 -0
- data/lib/raif/evals/run.rb +202 -0
- data/lib/raif/evals/scoring_rubric.rb +174 -0
- data/lib/raif/evals.rb +26 -0
- data/lib/raif/json_schema_builder.rb +14 -0
- data/lib/raif/llm_registry.rb +218 -15
- data/lib/raif/messages.rb +180 -0
- data/lib/raif/migration_checker.rb +3 -3
- data/lib/raif/utils/colors.rb +23 -0
- data/lib/raif/utils.rb +1 -0
- data/lib/raif/version.rb +1 -1
- data/lib/raif.rb +13 -0
- data/lib/tasks/annotate_rb.rake +10 -0
- data/spec/support/current_temperature_test_tool.rb +34 -0
- data/spec/support/rspec_helpers.rb +8 -8
- data/spec/support/test_conversation.rb +1 -1
- metadata +77 -10
- data/app/models/raif/agents/re_act_agent.rb +0 -127
- data/app/models/raif/agents/re_act_step.rb +0 -33
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../base_generator"
|
|
4
|
+
|
|
5
|
+
module Raif
|
|
6
|
+
module Generators
|
|
7
|
+
class EvalSetGenerator < BaseGenerator
|
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
|
9
|
+
|
|
10
|
+
def create_eval_set_file
|
|
11
|
+
template "eval_set.rb.tt", eval_set_file_path
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def show_instructions
|
|
15
|
+
say "\nEval set created!"
|
|
16
|
+
say "To run this eval set: bundle exec raif evals ./#{eval_set_file_path}"
|
|
17
|
+
say "To run all eval sets: bundle exec raif evals"
|
|
18
|
+
say ""
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def eval_set_file_path
|
|
24
|
+
File.join("raif_evals", "eval_sets", class_path, "#{file_name}_eval_set.rb")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<% raif_module_namespacing(["Evals"]) do -%>
|
|
2
|
+
class <%= class_name.demodulize %>EvalSet < Raif::Evals::EvalSet
|
|
3
|
+
# Run this eval set with:
|
|
4
|
+
# bundle exec raif evals ./<%= eval_set_file_path %>
|
|
5
|
+
|
|
6
|
+
# Setup method runs before each eval
|
|
7
|
+
setup do
|
|
8
|
+
# Common setup code
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Teardown runs after each eval
|
|
12
|
+
teardown do
|
|
13
|
+
# Cleanup code
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
eval "description of your eval" do
|
|
17
|
+
# Your eval code here
|
|
18
|
+
# expect_tool_invocation, expect_no_tool_invocation, expect, etc.
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
<% end -%>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module Raif
|
|
6
|
+
module Generators
|
|
7
|
+
module Evals
|
|
8
|
+
class SetupGenerator < Rails::Generators::Base
|
|
9
|
+
source_root File.expand_path("templates", __dir__)
|
|
10
|
+
|
|
11
|
+
def create_directories
|
|
12
|
+
empty_directory "raif_evals"
|
|
13
|
+
empty_directory "raif_evals/eval_sets"
|
|
14
|
+
empty_directory "raif_evals/files"
|
|
15
|
+
empty_directory "raif_evals/results"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create_setup_file
|
|
19
|
+
create_file "raif_evals/setup.rb", <<~EOS
|
|
20
|
+
#
|
|
21
|
+
# This file is loaded at the start of a run of your evals.
|
|
22
|
+
#
|
|
23
|
+
# Add any setup code that should run before your evals.
|
|
24
|
+
#
|
|
25
|
+
EOS
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def create_gitignore
|
|
29
|
+
create_file "raif_evals/results/.gitignore", <<~EOS
|
|
30
|
+
*
|
|
31
|
+
!.gitignore
|
|
32
|
+
EOS
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def show_instructions
|
|
36
|
+
say "\nRaif evals setup complete!", :green
|
|
37
|
+
say "You can create evals with: rails g raif:eval_set ExampleName"
|
|
38
|
+
say ""
|
|
39
|
+
say "Run evals with:"
|
|
40
|
+
say " bundle exec raif evals # Run all evals"
|
|
41
|
+
say " bundle exec raif evals ./raif_evals/eval_sets/my_eval_set.rb # Run specific eval set"
|
|
42
|
+
say ""
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -24,8 +24,23 @@ module Raif
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def add_engine_route
|
|
27
|
+
routes_file = "config/routes.rb"
|
|
28
|
+
|
|
29
|
+
if File.exist?(routes_file)
|
|
30
|
+
routes_content = File.read(routes_file)
|
|
31
|
+
if routes_content.include?("mount Raif::Engine")
|
|
32
|
+
say "Raif is already mounted in #{routes_file}, skipping route", :yellow
|
|
33
|
+
return
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
27
37
|
route 'mount Raif::Engine => "/raif"'
|
|
28
38
|
end
|
|
39
|
+
|
|
40
|
+
def setup_evals
|
|
41
|
+
say "\nSetting up Raif evals...", :green
|
|
42
|
+
generate "raif:evals:setup"
|
|
43
|
+
end
|
|
29
44
|
end
|
|
30
45
|
end
|
|
31
46
|
end
|
|
@@ -10,6 +10,22 @@ Raif.configure do |config|
|
|
|
10
10
|
# Whether OpenAI embedding models are enabled.
|
|
11
11
|
# config.open_ai_embedding_models_enabled = ENV["OPENAI_API_KEY"].present?
|
|
12
12
|
|
|
13
|
+
# The base URL for OpenAI API requests.
|
|
14
|
+
# Set this if you want to use the OpenAI adapter with a different provider (e.g. for using Azure instead of OpenAI)
|
|
15
|
+
# config.open_ai_base_url = "https://api.openai.com/v1"
|
|
16
|
+
|
|
17
|
+
# The base URL for OpenAI embedding API requests.
|
|
18
|
+
# Set this if you want to use a different provider for embeddings (e.g. Ollama, vLLM, or other OpenAI-compatible APIs)
|
|
19
|
+
# config.open_ai_embedding_base_url = "https://api.openai.com/v1"
|
|
20
|
+
|
|
21
|
+
# When set, this will be included as an api-version parameter in any OpenAI API requests (e.g. for using Azure instead of OpenAI)
|
|
22
|
+
# config.open_ai_api_version = nil
|
|
23
|
+
|
|
24
|
+
# The authentication header style for OpenAI API requests. Defaults to :bearer
|
|
25
|
+
# Use :bearer for standard OpenAI API (Authorization: Bearer <token>)
|
|
26
|
+
# Use :api_key for Azure OpenAI API (api-key: <token>)
|
|
27
|
+
# config.open_ai_auth_header_style = :bearer
|
|
28
|
+
|
|
13
29
|
# Your Anthropic API key. Defaults to ENV["ANTHROPIC_API_KEY"]
|
|
14
30
|
# config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
|
|
15
31
|
|
|
@@ -40,24 +56,56 @@ Raif.configure do |config|
|
|
|
40
56
|
# The site URL to include in OpenRouter API requests headers. Optional.
|
|
41
57
|
# config.open_router_site_url = "https://myapp.com"
|
|
42
58
|
|
|
59
|
+
# Your Google AI API key. Defaults to ENV["GOOGLE_AI_API_KEY"].presence || ENV["GOOGLE_API_KEY"]
|
|
60
|
+
# config.google_api_key = ENV["GOOGLE_AI_API_KEY"].presence || ENV["GOOGLE_API_KEY"]
|
|
61
|
+
|
|
62
|
+
# Whether Google models are enabled.
|
|
63
|
+
# config.google_models_enabled = ENV["GOOGLE_API_KEY"].present?
|
|
64
|
+
|
|
43
65
|
# The default LLM model to use. Defaults to "open_ai_gpt_4o"
|
|
44
66
|
# Available keys:
|
|
45
|
-
# open_ai_gpt_4_1
|
|
46
|
-
# open_ai_gpt_4_1_mini
|
|
47
|
-
# open_ai_gpt_4_1_nano
|
|
48
67
|
# open_ai_gpt_4o_mini
|
|
49
68
|
# open_ai_gpt_4o
|
|
50
69
|
# open_ai_gpt_3_5_turbo
|
|
70
|
+
# open_ai_gpt_4_1
|
|
71
|
+
# open_ai_gpt_4_1_mini
|
|
72
|
+
# open_ai_gpt_4_1_nano
|
|
73
|
+
# open_ai_o1
|
|
74
|
+
# open_ai_o1_mini
|
|
75
|
+
# open_ai_o3
|
|
76
|
+
# open_ai_o3_mini
|
|
77
|
+
# open_ai_o4_mini
|
|
78
|
+
# open_ai_gpt_5
|
|
79
|
+
# open_ai_gpt_5_mini
|
|
80
|
+
# open_ai_gpt_5_nano
|
|
81
|
+
# open_ai_responses_gpt_4o_mini
|
|
82
|
+
# open_ai_responses_gpt_4o
|
|
83
|
+
# open_ai_responses_gpt_3_5_turbo
|
|
51
84
|
# open_ai_responses_gpt_4_1
|
|
52
85
|
# open_ai_responses_gpt_4_1_mini
|
|
53
86
|
# open_ai_responses_gpt_4_1_nano
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
87
|
+
# open_ai_responses_o1
|
|
88
|
+
# open_ai_responses_o1_mini
|
|
89
|
+
# open_ai_responses_o3
|
|
90
|
+
# open_ai_responses_o3_mini
|
|
91
|
+
# open_ai_responses_o4_mini
|
|
92
|
+
# open_ai_responses_gpt_5
|
|
93
|
+
# open_ai_responses_gpt_5_mini
|
|
94
|
+
# open_ai_responses_gpt_5_nano
|
|
95
|
+
# open_ai_responses_o1_pro
|
|
96
|
+
# open_ai_responses_o3_pro
|
|
97
|
+
# anthropic_claude_4_sonnet
|
|
98
|
+
# anthropic_claude_4_5_sonnet
|
|
99
|
+
# anthropic_claude_4_opus
|
|
100
|
+
# anthropic_claude_4_1_opus
|
|
57
101
|
# anthropic_claude_3_7_sonnet
|
|
58
102
|
# anthropic_claude_3_5_sonnet
|
|
59
103
|
# anthropic_claude_3_5_haiku
|
|
60
104
|
# anthropic_claude_3_opus
|
|
105
|
+
# bedrock_claude_4_sonnet
|
|
106
|
+
# bedrock_claude_4_5_sonnet
|
|
107
|
+
# bedrock_claude_4_opus
|
|
108
|
+
# bedrock_claude_4_1_opus
|
|
61
109
|
# bedrock_claude_3_5_sonnet
|
|
62
110
|
# bedrock_claude_3_7_sonnet
|
|
63
111
|
# bedrock_claude_3_5_haiku
|
|
@@ -66,10 +114,21 @@ Raif.configure do |config|
|
|
|
66
114
|
# bedrock_amazon_nova_lite
|
|
67
115
|
# bedrock_amazon_nova_pro
|
|
68
116
|
# open_router_claude_3_7_sonnet
|
|
69
|
-
# open_router_llama_3_3_70b_instruct
|
|
70
|
-
# open_router_llama_3_1_8b_instruct
|
|
71
|
-
# open_router_gemini_2_0_flash
|
|
72
117
|
# open_router_deepseek_chat_v3
|
|
118
|
+
# open_router_deepseek_v3_1
|
|
119
|
+
# open_router_gemini_2_0_flash
|
|
120
|
+
# open_router_gemini_2_5_pro
|
|
121
|
+
# open_router_grok_4
|
|
122
|
+
# open_router_llama_3_1_8b_instruct
|
|
123
|
+
# open_router_llama_3_3_70b_instruct
|
|
124
|
+
# open_router_llama_4_maverick
|
|
125
|
+
# open_router_llama_4_scout
|
|
126
|
+
# open_router_open_ai_gpt_oss_120b
|
|
127
|
+
# open_router_open_ai_gpt_oss_20b
|
|
128
|
+
# google_gemini_2_5_pro
|
|
129
|
+
# google_gemini_2_5_flash
|
|
130
|
+
# google_gemini_3_0_pro
|
|
131
|
+
# google_gemini_3_0_flash
|
|
73
132
|
#
|
|
74
133
|
# config.default_llm_model_key = "open_ai_gpt_4o"
|
|
75
134
|
|
|
@@ -98,6 +157,9 @@ Raif.configure do |config|
|
|
|
98
157
|
# Or you can use a lambda to return a dynamic system prompt intro:
|
|
99
158
|
# config.task_system_prompt_intro = ->(task){ "You are a helpful assistant. Today's date is #{Date.today.strftime('%B %d, %Y')}." }
|
|
100
159
|
|
|
160
|
+
# Whether the creator association is optional for Raif::Task. Defaults to true.
|
|
161
|
+
# config.task_creator_optional = true
|
|
162
|
+
|
|
101
163
|
# The system prompt intro for Raif::Conversation instances. Defaults to "You are a helpful assistant who is collaborating with a teammate."
|
|
102
164
|
# config.conversation_system_prompt_intro = "You are a helpful assistant who is collaborating with a teammate."
|
|
103
165
|
# Or you can use a lambda to return a dynamic system prompt intro:
|
|
@@ -115,10 +177,14 @@ Raif.configure do |config|
|
|
|
115
177
|
# If you want to use a custom controller that inherits from Raif::ConversationEntriesController, you can set it here.
|
|
116
178
|
# config.conversation_entries_controller = "Raif::ConversationEntriesController"
|
|
117
179
|
|
|
180
|
+
# The default maximum number of conversation entries to include in LLM messages. Defaults to 50.
|
|
181
|
+
# Set to nil to include all entries. Each conversation can override this with its own llm_messages_max_length attribute.
|
|
182
|
+
# config.conversation_llm_messages_max_length_default = 50
|
|
183
|
+
|
|
118
184
|
# The method to call to get the current user. Defaults to :current_user
|
|
119
185
|
# config.current_user_method = :current_user
|
|
120
186
|
|
|
121
|
-
# The agent types that are available. Defaults to Set.new(["Raif::Agents::
|
|
187
|
+
# The agent types that are available. Defaults to Set.new(["Raif::Agents::NativeToolCallingAgent"])
|
|
122
188
|
# If you want to use custom agent types that inherits from Raif::Agent, you can add them here.
|
|
123
189
|
# config.agent_types += ["MyAgent"]
|
|
124
190
|
|
|
@@ -134,4 +200,17 @@ Raif.configure do |config|
|
|
|
134
200
|
# Whether LLM API requests are enabled. Defaults to true.
|
|
135
201
|
# Use this to globally disable requests to LLM APIs.
|
|
136
202
|
# config.llm_api_requests_enabled = true
|
|
203
|
+
|
|
204
|
+
# Timeout settings for LLM API requests (in seconds). All default to nil (use Faraday defaults).
|
|
205
|
+
# config.request_open_timeout = nil # Time to wait for a connection to be opened
|
|
206
|
+
# config.request_read_timeout = nil # Time to wait for data to be read
|
|
207
|
+
# config.request_write_timeout = nil # Time to wait for data to be written
|
|
208
|
+
|
|
209
|
+
# The default LLM model to use for LLM-as-judge evaluations.
|
|
210
|
+
# If not set, falls back to the default_llm_model_key.
|
|
211
|
+
# config.evals_default_llm_judge_model_key = ENV["RAIF_EVALS_DEFAULT_LLM_JUDGE_MODEL_KEY"].presence
|
|
212
|
+
|
|
213
|
+
# Whether to output verbose information during evaluation runs. Defaults to false.
|
|
214
|
+
# When true, provides more detailed output including individual test results.
|
|
215
|
+
# config.evals_verbose_output = false
|
|
137
216
|
end
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../base_generator"
|
|
4
|
+
|
|
3
5
|
module Raif
|
|
4
6
|
module Generators
|
|
5
|
-
class ModelToolGenerator <
|
|
7
|
+
class ModelToolGenerator < BaseGenerator
|
|
6
8
|
source_root File.expand_path("templates", __dir__)
|
|
7
9
|
|
|
8
10
|
desc "Creates a new model tool for the LLM to invoke in app/models/raif/model_tools"
|
|
9
11
|
|
|
10
12
|
def create_model_tool_file
|
|
11
|
-
template "model_tool.rb.tt", File.join("app/models/raif/model_tools", "#{file_name}.rb")
|
|
12
|
-
|
|
13
|
-
# Generate the view partial for the tool invocation
|
|
14
|
-
template "model_tool_invocation_partial.html.erb.tt", File.join("app/views/raif/model_tool_invocations", "_#{file_name}.html.erb")
|
|
13
|
+
template "model_tool.rb.tt", File.join("app/models/raif/model_tools", class_path, "#{file_name}.rb")
|
|
14
|
+
template "model_tool_invocation_partial.html.erb.tt", File.join("app/views/raif/model_tool_invocations", class_path, "_#{file_name}.html.erb")
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def success_message
|
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
|
|
1
|
+
<% raif_module_namespacing(["ModelTools"]) do -%>
|
|
2
|
+
class <%= class_name.demodulize %> < Raif::ModelTool
|
|
3
|
+
# For example tool implementations, see:
|
|
4
|
+
# Wikipedia Search Tool: https://github.com/CultivateLabs/raif/blob/main/app/models/raif/model_tools/wikipedia_search.rb
|
|
5
|
+
# Fetch URL Tool: https://github.com/CultivateLabs/raif/blob/main/app/models/raif/model_tools/fetch_url.rb
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
# Fetch URL Tool: https://github.com/CultivateLabs/raif/blob/main/app/models/raif/model_tools/fetch_url.rb
|
|
7
|
-
|
|
8
|
-
tool_description do
|
|
9
|
-
"Description of your tool that will be provided to the LLM so it knows when to invoke it"
|
|
10
|
-
end
|
|
7
|
+
tool_description do
|
|
8
|
+
"Description of your tool that will be provided to the LLM so it knows when to invoke it"
|
|
9
|
+
end
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
#
|
|
16
|
-
# All attributes will be required and additionalProperties will be set to false.
|
|
17
|
-
#
|
|
18
|
-
# See https://docs.raif.ai/learn_more/json_schemas for more information about defining JSON schemas.
|
|
19
|
-
tool_arguments_schema do
|
|
20
|
-
# string :title, description: "The title of the operation", minLength: 3
|
|
11
|
+
# Define the schema for the arguments that the LLM should use when invoking your tool.
|
|
12
|
+
# It should be a valid JSON schema. When the model invokes your tool,
|
|
13
|
+
# the arguments it provides will be validated against this schema using JSON::Validator from the json-schema gem.
|
|
21
14
|
#
|
|
22
|
-
#
|
|
23
|
-
# boolean :is_red, description: "Whether the widget is red"
|
|
24
|
-
# integer :rating, description: "A rating of the widget from 1 to 10", minimum: 1, maximum: 10
|
|
25
|
-
# array :tags, description: "Associated tags" do
|
|
26
|
-
# items type: "string"
|
|
27
|
-
# end
|
|
28
|
-
# end
|
|
15
|
+
# All attributes will be required and additionalProperties will be set to false.
|
|
29
16
|
#
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
17
|
+
# See https://docs.raif.ai/learn_more/json_schemas for more information about defining JSON schemas.
|
|
18
|
+
tool_arguments_schema do
|
|
19
|
+
# string :title, description: "The title of the operation", minLength: 3
|
|
20
|
+
#
|
|
21
|
+
# object :widget, description: "A widget's description" do
|
|
22
|
+
# boolean :is_red, description: "Whether the widget is red"
|
|
23
|
+
# integer :rating, description: "A rating of the widget from 1 to 10", minimum: 1, maximum: 10
|
|
24
|
+
# array :tags, description: "Associated tags" do
|
|
25
|
+
# items type: "string"
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# array :products, description: "List of products" do
|
|
30
|
+
# object do
|
|
31
|
+
# integer :id, description: "Product identifier"
|
|
32
|
+
# string :name, description: "Product name"
|
|
33
|
+
# number :price, description: "Product price", minimum: 0
|
|
34
|
+
# end
|
|
35
|
+
# end
|
|
36
|
+
end
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
# An example of how the LLM should invoke your tool. This should return a hash with name and arguments keys.
|
|
39
|
+
# `to_json` will be called on it and provided to the LLM as an example of how to invoke your tool.
|
|
40
|
+
example_model_invocation do
|
|
41
|
+
{
|
|
42
|
+
"name": tool_name,
|
|
43
|
+
"arguments": {}
|
|
44
|
+
}
|
|
45
|
+
end
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
class << self
|
|
48
|
+
# When your tool is invoked by the LLM in a Raif::Agent loop,
|
|
49
|
+
# the results of the tool invocation are provided back to the LLM as an observation.
|
|
50
|
+
# This method should return whatever you want provided to the LLM.
|
|
51
|
+
# For example, if you were implementing a GoogleSearch tool, this might return a JSON
|
|
52
|
+
# object containing search results for the query.
|
|
53
|
+
def observation_for_invocation(tool_invocation)
|
|
54
|
+
return "No results found" unless tool_invocation.result.present?
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
JSON.pretty_generate(tool_invocation.result)
|
|
57
|
+
end
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
# When your tool is invoked in a Raif::Conversation, should the result be automatically provided back to the model?
|
|
60
|
+
# When true, observation_for_invocation will be used to produce the observation provided to the model
|
|
61
|
+
def triggers_observation_to_model?
|
|
62
|
+
false
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# When the LLM invokes your tool, this method will be called with a `Raif::ModelToolInvocation` record as an argument.
|
|
66
|
+
# It should handle the actual execution of the tool.
|
|
67
|
+
# For example, if you are implementing a GoogleSearch tool, this method should run the actual search
|
|
68
|
+
# and store the results in the tool_invocation's result JSON column.
|
|
69
|
+
def process_invocation(tool_invocation)
|
|
70
|
+
# Extract arguments from tool_invocation.tool_arguments
|
|
71
|
+
# query = tool_invocation.tool_arguments["query"]
|
|
72
|
+
#
|
|
73
|
+
# Process the invocation and perform the desired action
|
|
74
|
+
# ...
|
|
75
|
+
#
|
|
76
|
+
# Store the results in the tool_invocation
|
|
77
|
+
# tool_invocation.update!(
|
|
78
|
+
# result: {
|
|
79
|
+
# # Your result data structure
|
|
80
|
+
# }
|
|
81
|
+
# )
|
|
82
|
+
#
|
|
83
|
+
# Return the result
|
|
84
|
+
# tool_invocation.result
|
|
85
|
+
end
|
|
65
86
|
|
|
66
|
-
# When the LLM invokes your tool, this method will be called with a `Raif::ModelToolInvocation` record as an argument.
|
|
67
|
-
# It should handle the actual execution of the tool.
|
|
68
|
-
# For example, if you are implementing a GoogleSearch tool, this method should run the actual search
|
|
69
|
-
# and store the results in the tool_invocation's result JSON column.
|
|
70
|
-
def process_invocation(tool_invocation)
|
|
71
|
-
# Extract arguments from tool_invocation.tool_arguments
|
|
72
|
-
# query = tool_invocation.tool_arguments["query"]
|
|
73
|
-
#
|
|
74
|
-
# Process the invocation and perform the desired action
|
|
75
|
-
# ...
|
|
76
|
-
#
|
|
77
|
-
# Store the results in the tool_invocation
|
|
78
|
-
# tool_invocation.update!(
|
|
79
|
-
# result: {
|
|
80
|
-
# # Your result data structure
|
|
81
|
-
# }
|
|
82
|
-
# )
|
|
83
|
-
#
|
|
84
|
-
# Return the result
|
|
85
|
-
# tool_invocation.result
|
|
86
87
|
end
|
|
87
88
|
end
|
|
88
|
-
|
|
89
|
-
end
|
|
89
|
+
<% end -%>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../base_generator"
|
|
4
|
+
|
|
3
5
|
module Raif
|
|
4
6
|
module Generators
|
|
5
|
-
class TaskGenerator <
|
|
7
|
+
class TaskGenerator < BaseGenerator
|
|
6
8
|
source_root File.expand_path("templates", __dir__)
|
|
7
9
|
|
|
8
10
|
class_option :response_format,
|
|
@@ -10,6 +12,11 @@ module Raif
|
|
|
10
12
|
default: "text",
|
|
11
13
|
desc: "Response format for the task (text, html, or json)"
|
|
12
14
|
|
|
15
|
+
class_option :skip_eval_set,
|
|
16
|
+
type: :boolean,
|
|
17
|
+
default: false,
|
|
18
|
+
desc: "Skip generating the corresponding eval set"
|
|
19
|
+
|
|
13
20
|
def create_application_task
|
|
14
21
|
template "application_task.rb.tt", "app/models/raif/application_task.rb" unless File.exist?("app/models/raif/application_task.rb")
|
|
15
22
|
end
|
|
@@ -18,11 +25,23 @@ module Raif
|
|
|
18
25
|
template "task.rb.tt", File.join("app/models/raif/tasks", class_path, "#{file_name}.rb")
|
|
19
26
|
end
|
|
20
27
|
|
|
28
|
+
def create_eval_set
|
|
29
|
+
return if options[:skip_eval_set]
|
|
30
|
+
|
|
31
|
+
template "task_eval_set.rb.tt", eval_set_file_path
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def show_instructions
|
|
35
|
+
say "\nTask created!"
|
|
36
|
+
say ""
|
|
37
|
+
end
|
|
38
|
+
|
|
21
39
|
private
|
|
22
40
|
|
|
23
|
-
def
|
|
24
|
-
|
|
41
|
+
def eval_set_file_path
|
|
42
|
+
File.join("raif_evals", "eval_sets", "tasks", class_path, "#{file_name}_eval_set.rb")
|
|
25
43
|
end
|
|
44
|
+
|
|
26
45
|
end
|
|
27
46
|
end
|
|
28
47
|
end
|
|
@@ -1,63 +1,59 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
<% raif_module_namespacing(["Tasks"]) do -%>
|
|
2
|
+
class <%= class_name.demodulize %> < Raif::ApplicationTask
|
|
3
|
+
# Set the response format for the task. Options are :html, :text, or :json.
|
|
4
|
+
llm_response_format :<%= options[:response_format] %>
|
|
5
|
+
|
|
6
|
+
# Set the temperature for the task
|
|
7
|
+
# llm_temperature 0.7
|
|
8
|
+
|
|
9
|
+
# Optional: Set the allowed tags for the task. Only relevant if response_format is :html.
|
|
10
|
+
# Defaults to Rails::HTML5::SafeListSanitizer.allowed_tags
|
|
11
|
+
# llm_response_allowed_tags %w[p b i div strong]
|
|
12
|
+
|
|
13
|
+
# Optional: Set the allowed attributes for the task. Only relevant if response_format is :html.
|
|
14
|
+
# Defaults to Rails::HTML5::SafeListSanitizer.allowed_attributes
|
|
15
|
+
# llm_response_allowed_attributes %w[style]
|
|
16
|
+
|
|
17
|
+
# Define any attributes that are needed for the task.
|
|
18
|
+
# You can then pass them when running the task and they will be available in build_prompt:
|
|
19
|
+
# Raif::Tasks::<%= class_name %>.run(your_attribute: "some value")
|
|
20
|
+
# run_with :your_attribute
|
|
21
|
+
<%- if options[:response_format] == "json" -%>
|
|
22
|
+
|
|
23
|
+
# Define a JSON schema that the model's response should adhere to
|
|
24
|
+
#
|
|
25
|
+
# All attributes will be required and additionalProperties will be set to false.
|
|
26
|
+
json_response_schema do
|
|
27
|
+
# string :title, description: "The title of the operation", minLength: 3
|
|
27
28
|
#
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# integer :id, description: "Product identifier"
|
|
43
|
-
# string :name, description: "Product name"
|
|
44
|
-
# number :price, description: "Product price", minimum: 0
|
|
45
|
-
# end
|
|
46
|
-
# end
|
|
47
|
-
end
|
|
48
|
-
<%- end -%>
|
|
49
|
-
|
|
50
|
-
def build_prompt
|
|
51
|
-
# Implement the LLM prompt for this task.
|
|
52
|
-
raise NotImplementedError, "Implement #build_prompt in #{self.class.name}"
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Optional: Override build_system_prompt if you need custom system instructions.
|
|
56
|
-
# The default implementation, which you'll get if you call super, will use Raif.config.task_system_prompt_intro
|
|
57
|
-
# and append the system_prompt_language_preference if the task's requested_language_key is set.
|
|
58
|
-
# def build_system_prompt
|
|
59
|
-
# super + "\nAdditional system instructions..."
|
|
29
|
+
# object :widget, description: "A widget's description" do
|
|
30
|
+
# boolean :is_red, description: "Whether the widget is red"
|
|
31
|
+
# integer :rating, description: "A rating of the widget from 1 to 10", minimum: 1, maximum: 10
|
|
32
|
+
# array :tags, description: "Associated tags" do
|
|
33
|
+
# items type: "string"
|
|
34
|
+
# end
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
# array :products, description: "List of products" do
|
|
38
|
+
# object do
|
|
39
|
+
# integer :id, description: "Product identifier"
|
|
40
|
+
# string :name, description: "Product name"
|
|
41
|
+
# number :price, description: "Product price", minimum: 0
|
|
42
|
+
# end
|
|
60
43
|
# end
|
|
61
44
|
end
|
|
45
|
+
<%- end -%>
|
|
46
|
+
|
|
47
|
+
def build_prompt
|
|
48
|
+
# Implement the LLM prompt for this task.
|
|
49
|
+
raise NotImplementedError, "Implement #build_prompt in #{self.class.name}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Optional: Override build_system_prompt if you need custom system instructions.
|
|
53
|
+
# The default implementation, which you'll get if you call super, will use Raif.config.task_system_prompt_intro
|
|
54
|
+
# and append the system_prompt_language_preference if the task's requested_language_key is set.
|
|
55
|
+
# def build_system_prompt
|
|
56
|
+
# super + "\nAdditional system instructions..."
|
|
57
|
+
# end
|
|
62
58
|
end
|
|
63
|
-
end
|
|
59
|
+
<% end -%>
|