raif 1.0.0 → 1.1.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 +200 -41
- data/app/assets/stylesheets/raif/admin/stats.scss +12 -0
- data/app/controllers/raif/admin/application_controller.rb +14 -0
- data/app/controllers/raif/admin/stats/tasks_controller.rb +25 -0
- data/app/controllers/raif/admin/stats_controller.rb +19 -0
- data/app/controllers/raif/admin/tasks_controller.rb +18 -2
- data/app/controllers/raif/conversations_controller.rb +5 -1
- data/app/models/raif/agent.rb +11 -9
- data/app/models/raif/agents/native_tool_calling_agent.rb +11 -1
- data/app/models/raif/agents/re_act_agent.rb +6 -0
- data/app/models/raif/concerns/has_available_model_tools.rb +1 -1
- data/app/models/raif/concerns/json_schema_definition.rb +28 -0
- data/app/models/raif/concerns/llm_response_parsing.rb +23 -1
- data/app/models/raif/concerns/llm_temperature.rb +17 -0
- data/app/models/raif/concerns/llms/anthropic/message_formatting.rb +51 -0
- data/app/models/raif/concerns/llms/bedrock_claude/message_formatting.rb +70 -0
- data/app/models/raif/concerns/llms/message_formatting.rb +41 -0
- data/app/models/raif/concerns/llms/open_ai/message_formatting.rb +41 -0
- data/app/models/raif/conversation.rb +11 -3
- data/app/models/raif/conversation_entry.rb +22 -6
- data/app/models/raif/embedding_model.rb +22 -0
- data/app/models/raif/embedding_models/bedrock_titan.rb +34 -0
- data/app/models/raif/embedding_models/open_ai.rb +40 -0
- data/app/models/raif/llm.rb +39 -6
- data/app/models/raif/llms/anthropic.rb +23 -28
- data/app/models/raif/llms/bedrock_claude.rb +33 -19
- data/app/models/raif/llms/open_ai.rb +14 -17
- data/app/models/raif/llms/open_router.rb +93 -0
- data/app/models/raif/model_completion.rb +21 -2
- data/app/models/raif/model_file_input.rb +113 -0
- data/app/models/raif/model_image_input.rb +4 -0
- data/app/models/raif/model_tool.rb +77 -51
- data/app/models/raif/model_tool_invocation.rb +8 -6
- data/app/models/raif/model_tools/agent_final_answer.rb +18 -27
- data/app/models/raif/model_tools/fetch_url.rb +27 -36
- data/app/models/raif/model_tools/wikipedia_search.rb +46 -55
- data/app/models/raif/task.rb +71 -16
- data/app/views/layouts/raif/admin.html.erb +10 -0
- data/app/views/raif/admin/agents/show.html.erb +3 -1
- data/app/views/raif/admin/conversations/_conversation.html.erb +1 -1
- data/app/views/raif/admin/conversations/show.html.erb +3 -1
- data/app/views/raif/admin/model_completions/_model_completion.html.erb +1 -0
- data/app/views/raif/admin/model_completions/index.html.erb +1 -0
- data/app/views/raif/admin/model_completions/show.html.erb +30 -3
- data/app/views/raif/admin/stats/index.html.erb +128 -0
- data/app/views/raif/admin/stats/tasks/index.html.erb +45 -0
- data/app/views/raif/admin/tasks/_task.html.erb +5 -4
- data/app/views/raif/admin/tasks/index.html.erb +20 -2
- data/app/views/raif/admin/tasks/show.html.erb +3 -1
- data/app/views/raif/conversation_entries/_conversation_entry.html.erb +18 -14
- data/app/views/raif/conversation_entries/_form.html.erb +1 -1
- data/app/views/raif/conversation_entries/_form_with_available_tools.html.erb +4 -4
- data/app/views/raif/conversation_entries/_message.html.erb +10 -3
- data/config/locales/admin.en.yml +14 -0
- data/config/locales/en.yml +25 -3
- data/config/routes.rb +6 -0
- data/db/migrate/20250421202149_add_response_format_to_raif_conversations.rb +7 -0
- data/db/migrate/20250424200755_add_cost_columns_to_raif_model_completions.rb +14 -0
- data/db/migrate/20250424232946_add_created_at_indexes.rb +11 -0
- data/db/migrate/20250502155330_add_status_indexes_to_raif_tasks.rb +14 -0
- data/db/migrate/20250507155314_add_retry_count_to_raif_model_completions.rb +7 -0
- data/lib/generators/raif/agent/agent_generator.rb +22 -12
- data/lib/generators/raif/agent/templates/agent.rb.tt +3 -3
- data/lib/generators/raif/agent/templates/application_agent.rb.tt +7 -0
- data/lib/generators/raif/conversation/conversation_generator.rb +10 -0
- data/lib/generators/raif/conversation/templates/application_conversation.rb.tt +7 -0
- data/lib/generators/raif/conversation/templates/conversation.rb.tt +13 -11
- data/lib/generators/raif/install/templates/initializer.rb +50 -6
- data/lib/generators/raif/model_tool/model_tool_generator.rb +0 -5
- data/lib/generators/raif/model_tool/templates/model_tool.rb.tt +69 -56
- data/lib/generators/raif/task/templates/task.rb.tt +34 -23
- data/lib/raif/configuration.rb +40 -3
- data/lib/raif/embedding_model_registry.rb +83 -0
- data/lib/raif/engine.rb +34 -1
- data/lib/raif/errors/{open_ai/api_error.rb → invalid_model_file_input_error.rb} +1 -3
- data/lib/raif/errors/{anthropic/api_error.rb → invalid_model_image_input_error.rb} +1 -3
- data/lib/raif/errors/unsupported_feature_error.rb +8 -0
- data/lib/raif/errors.rb +3 -2
- data/lib/raif/json_schema_builder.rb +104 -0
- data/lib/raif/llm_registry.rb +205 -0
- data/lib/raif/version.rb +1 -1
- data/lib/raif.rb +5 -32
- data/lib/tasks/raif_tasks.rake +9 -4
- metadata +32 -19
- data/lib/raif/default_llms.rb +0 -37
@@ -0,0 +1,45 @@
|
|
1
|
+
<%= link_to raif.admin_stats_path do %>
|
2
|
+
« <%= t("raif.admin.stats.tasks.back_to_stats") %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<div class="d-flex justify-content-between align-items-center my-4">
|
6
|
+
<h1 class="mb-0"><%= t("raif.admin.stats.tasks.title") %></h1>
|
7
|
+
|
8
|
+
<div class="period-filter">
|
9
|
+
<%= form_tag raif.admin_stats_tasks_path, method: :get, id: "period_filter_form", class: "d-flex align-items-center" do %>
|
10
|
+
<%= select_tag :period,
|
11
|
+
options_for_select(
|
12
|
+
[
|
13
|
+
[t("raif.admin.common.period_day"), "day"],
|
14
|
+
[t("raif.admin.common.period_week"), "week"],
|
15
|
+
[t("raif.admin.common.period_month"), "month"],
|
16
|
+
[t("raif.admin.common.period_all"), "all"]
|
17
|
+
],
|
18
|
+
@selected_period
|
19
|
+
),
|
20
|
+
class: "form-select form-select-sm me-2" %>
|
21
|
+
<%= submit_tag t("raif.admin.common.update"), class: "btn btn-sm btn-primary" %>
|
22
|
+
<% end %>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
<div class="table-responsive">
|
27
|
+
<table class="table table-striped table-hover">
|
28
|
+
<thead class="table-light">
|
29
|
+
<tr>
|
30
|
+
<th><%= t("raif.admin.common.type") %></th>
|
31
|
+
<th><%= t("raif.admin.common.count") %></th>
|
32
|
+
<th><%= t("raif.admin.common.est_cost") %></th>
|
33
|
+
</tr>
|
34
|
+
</thead>
|
35
|
+
<tbody>
|
36
|
+
<% @task_counts_by_type.each do |type, count| %>
|
37
|
+
<tr>
|
38
|
+
<td><%= type %></td>
|
39
|
+
<td><%= number_with_delimiter(count) %></td>
|
40
|
+
<td><%= number_to_currency(@task_costs_by_type[type] || 0, precision: 6) %></td>
|
41
|
+
</tr>
|
42
|
+
<% end %>
|
43
|
+
</tbody>
|
44
|
+
</table>
|
45
|
+
</div>
|
@@ -2,14 +2,15 @@
|
|
2
2
|
<td><%= link_to "##{task.id}", raif.admin_task_path(task) %></td>
|
3
3
|
<td><%= task.type %></td>
|
4
4
|
<td><small class="text-muted"><%= task.created_at.rfc822 %></small></td>
|
5
|
-
<td><%= task.
|
5
|
+
<td><%= task.creator.try(:raif_display_name) || "#{task.creator_type} ##{task.creator_id}" %></td>
|
6
6
|
<td><%= task.llm_model_key %></td>
|
7
7
|
<td>
|
8
|
-
<%
|
8
|
+
<% case task.status %>
|
9
|
+
<% when :completed %>
|
9
10
|
<span class="badge bg-success"><%= t("raif.admin.common.completed") %></span>
|
10
|
-
<%
|
11
|
+
<% when :failed %>
|
11
12
|
<span class="badge bg-danger"><%= t("raif.admin.common.failed") %></span>
|
12
|
-
<%
|
13
|
+
<% when :in_progress %>
|
13
14
|
<span class="badge bg-warning text-dark"><%= t("raif.admin.common.in_progress") %></span>
|
14
15
|
<% else %>
|
15
16
|
<span class="badge bg-secondary"><%= t("raif.admin.common.pending") %></span>
|
@@ -4,10 +4,28 @@
|
|
4
4
|
<div class="col-12">
|
5
5
|
<%= form_tag raif.admin_tasks_path, method: :get, class: "mb-4" do %>
|
6
6
|
<div class="row align-items-end">
|
7
|
-
<div class="col-md-
|
7
|
+
<div class="col-md-4">
|
8
8
|
<div class="form-group">
|
9
|
+
<label for="task_types"><%= t("raif.admin.common.type") %></label>
|
9
10
|
<%= select_tag :task_types,
|
10
|
-
options_for_select(@task_types.map{|type| [type, type] }, @
|
11
|
+
options_for_select([["All", "all"]] + @task_types.map{|type| [type, type] }, @selected_type),
|
12
|
+
{ class: "form-select" } %>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
<div class="col-md-4">
|
16
|
+
<div class="form-group">
|
17
|
+
<label for="task_statuses"><%= t("raif.admin.common.status") %></label>
|
18
|
+
<%= select_tag :task_statuses,
|
19
|
+
options_for_select(
|
20
|
+
[
|
21
|
+
[t("raif.admin.common.all"), :all],
|
22
|
+
[t("raif.admin.common.completed"), :completed],
|
23
|
+
[t("raif.admin.common.failed"), :failed],
|
24
|
+
[t("raif.admin.common.in_progress"), :in_progress],
|
25
|
+
[t("raif.admin.common.pending"), :pending]
|
26
|
+
],
|
27
|
+
@selected_statuses
|
28
|
+
),
|
11
29
|
{ class: "form-select" } %>
|
12
30
|
</div>
|
13
31
|
</div>
|
@@ -14,7 +14,9 @@
|
|
14
14
|
</div>
|
15
15
|
<div class="row mb-3">
|
16
16
|
<div class="col-md-3"><strong><%= t("raif.admin.common.creator") %>:</strong></div>
|
17
|
-
<div class="col-md-9"
|
17
|
+
<div class="col-md-9">
|
18
|
+
<%= @task.creator.try(:raif_display_name) || "#{@task.creator_type} ##{@task.creator_id}" %>
|
19
|
+
</div>
|
18
20
|
</div>
|
19
21
|
<div class="row mb-3">
|
20
22
|
<div class="col-md-3"><strong><%= t("raif.admin.common.model") %>:</strong></div>
|
@@ -1,26 +1,30 @@
|
|
1
|
-
<div id="<%= dom_id(conversation_entry) %>" class="my-2">
|
1
|
+
<div id="<%= dom_id(conversation_entry) %>" class="my-2 conversation-entry">
|
2
2
|
<%= render "raif/conversation_entries/message",
|
3
3
|
conversation_entry: conversation_entry,
|
4
4
|
content: conversation_entry.user_message,
|
5
|
-
message_type: :user %>
|
5
|
+
message_type: :user if conversation_entry.user_message.present? %>
|
6
6
|
|
7
|
-
<% if conversation_entry.
|
8
|
-
<%= render "raif/conversation_entries/message",
|
9
|
-
conversation_entry: conversation_entry,
|
10
|
-
content: conversation_entry.generating_response? ? content_tag(:span, "", class: "raif-loader") : conversation_entry.model_response_message,
|
11
|
-
message_type: :model_response %>
|
12
|
-
|
13
|
-
<% conversation_entry.raif_model_tool_invocations.select(&:renderable?).each do |ti| %>
|
14
|
-
<div class="mb-4 container">
|
15
|
-
<%= render ti, conversation_entry: conversation_entry %>
|
16
|
-
</div>
|
17
|
-
<% end %>
|
18
|
-
<% elsif conversation_entry.failed? %>
|
7
|
+
<% if conversation_entry.failed? %>
|
19
8
|
<div class="mb-4 container">
|
20
9
|
<%= render "raif/conversation_entries/message",
|
21
10
|
conversation_entry: conversation_entry,
|
22
11
|
content: t("raif.common.there_was_an_error_generating_this_response"),
|
23
12
|
message_type: :model_response %>
|
24
13
|
</div>
|
14
|
+
<% elsif conversation_entry.generating_response? %>
|
15
|
+
<%= render "raif/conversation_entries/message",
|
16
|
+
conversation_entry: conversation_entry,
|
17
|
+
content: content_tag(:span, "", class: "raif-loader"),
|
18
|
+
message_type: :model_response %>
|
19
|
+
|
20
|
+
<% elsif conversation_entry.completed? %>
|
21
|
+
<%= render "raif/conversation_entries/message",
|
22
|
+
conversation_entry: conversation_entry,
|
23
|
+
content: conversation_entry.model_response_message,
|
24
|
+
message_type: :model_response if conversation_entry.model_response_message.present? %>
|
25
|
+
|
26
|
+
<% conversation_entry.raif_model_tool_invocations.select(&:renderable?).each do |ti| %>
|
27
|
+
<%= render ti, conversation_entry: conversation_entry %>
|
28
|
+
<% end %>
|
25
29
|
<% end %>
|
26
30
|
</div>
|
@@ -10,7 +10,7 @@
|
|
10
10
|
<% end %>
|
11
11
|
<% end %>
|
12
12
|
|
13
|
-
<div class="d-flex">
|
13
|
+
<div class="d-flex px-2">
|
14
14
|
<%= f.text_field :user_message,
|
15
15
|
class: "form-control me-2",
|
16
16
|
placeholder: conversation_entry.raif_user_tool_invocation&.message_input_placeholder.presence || t("raif.common.type_your_message"),
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<
|
2
|
-
|
3
|
-
<%= render "raif/
|
4
|
-
|
1
|
+
<div class="border-top pt-2">
|
2
|
+
<%= render "raif/conversations/available_user_tools", conversation: conversation %>
|
3
|
+
<%= render "raif/conversation_entries/form", conversation: conversation, conversation_entry: conversation_entry %>
|
4
|
+
</div>
|
@@ -1,12 +1,19 @@
|
|
1
|
-
<div class="d-flex
|
2
|
-
<div class="d-flex
|
1
|
+
<div class="d-flex my-2 px-3 <%= "justify-content-end" if message_type == :user %>">
|
2
|
+
<div class="d-flex <%= "chat-message-content" if message_type == :user %> <%= "received-message-content" if message_type == :model_response %>">
|
3
3
|
<% if message_type == :model_response %>
|
4
4
|
<%= render "raif/conversation_entries/model_response_avatar", conversation_entry: local_assigns[:conversation_entry] %>
|
5
5
|
<% end %>
|
6
6
|
|
7
7
|
<% if content.present? %>
|
8
8
|
<div class="mb-1 rounded-2 p-3 <%= message_type == :user ? "bg-primary text-white" : "border" %>">
|
9
|
-
|
9
|
+
<% case local_assigns[:conversation_entry]&.response_format %>
|
10
|
+
<% when "text" %>
|
11
|
+
<%= simple_format content %>
|
12
|
+
<% when "html" %>
|
13
|
+
<%= sanitize content %>
|
14
|
+
<% else %>
|
15
|
+
<%= content %>
|
16
|
+
<% end %>
|
10
17
|
</div>
|
11
18
|
<% end %>
|
12
19
|
|
data/config/locales/admin.en.yml
CHANGED
@@ -8,6 +8,7 @@ en:
|
|
8
8
|
title: 'Agent #%{id}'
|
9
9
|
common:
|
10
10
|
agents: Agents
|
11
|
+
all: All
|
11
12
|
arguments: Arguments
|
12
13
|
at: at
|
13
14
|
completed: Completed
|
@@ -16,11 +17,13 @@ en:
|
|
16
17
|
conversation_entries: Conversation Entries
|
17
18
|
conversation_history: Conversation History
|
18
19
|
conversations: Conversations
|
20
|
+
count: Count
|
19
21
|
created_at: Created At
|
20
22
|
creator: Creator
|
21
23
|
details: Details
|
22
24
|
entries_count: Entries Count
|
23
25
|
entry: Entry
|
26
|
+
est_cost: est. cost
|
24
27
|
failed: Failed
|
25
28
|
failed_at: Failed At
|
26
29
|
filter: Filter
|
@@ -44,6 +47,10 @@ en:
|
|
44
47
|
no_tasks: No tasks found.
|
45
48
|
no_tool_calls: No tool calls
|
46
49
|
pending: Pending
|
50
|
+
period_all: All time
|
51
|
+
period_day: Past 24 hours
|
52
|
+
period_month: Past month
|
53
|
+
period_week: Past week
|
47
54
|
prettified: Prettified
|
48
55
|
prompt: Prompt
|
49
56
|
prompt_tokens: Prompt Tokens
|
@@ -58,6 +65,7 @@ en:
|
|
58
65
|
since: Since
|
59
66
|
source: Source
|
60
67
|
started_at: Started At
|
68
|
+
stats: Stats
|
61
69
|
status: Status
|
62
70
|
system_prompt: System Prompt
|
63
71
|
task: Task
|
@@ -67,8 +75,10 @@ en:
|
|
67
75
|
tool_invocations: Tool Invocations
|
68
76
|
tool_name: Tool Name
|
69
77
|
tool_type: Tool Type
|
78
|
+
total_cost: Total Cost
|
70
79
|
total_tokens: Total Tokens
|
71
80
|
type: Type
|
81
|
+
update: Update
|
72
82
|
user_message: User Message
|
73
83
|
conversations:
|
74
84
|
show:
|
@@ -85,6 +95,10 @@ en:
|
|
85
95
|
show:
|
86
96
|
back_to_model_tool_invocations: Back to Model Tool Invocations
|
87
97
|
title: 'Model Tool Invocation #%{id}'
|
98
|
+
stats:
|
99
|
+
tasks:
|
100
|
+
back_to_stats: Back to Stats
|
101
|
+
title: Task Stats
|
88
102
|
tasks:
|
89
103
|
show:
|
90
104
|
back_to_tasks: Back to Tasks
|
data/config/locales/en.yml
CHANGED
@@ -2,9 +2,14 @@
|
|
2
2
|
en:
|
3
3
|
raif:
|
4
4
|
agents:
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
native_tool_calling_agent:
|
6
|
+
errors:
|
7
|
+
available_model_tools:
|
8
|
+
too_short: must have at least 1 tool in addition to the agent_final_answer tool
|
9
|
+
re_act_agent:
|
10
|
+
errors:
|
11
|
+
available_model_tools:
|
12
|
+
too_short: must have at least 1 tool
|
8
13
|
common:
|
9
14
|
send: Send
|
10
15
|
there_was_an_error_generating_this_response: There was an error generating this response
|
@@ -12,6 +17,11 @@ en:
|
|
12
17
|
type_your_message: Type your message...
|
13
18
|
conversation:
|
14
19
|
initial_chat_message: Hello, how can I help you today?
|
20
|
+
embedding_model_names:
|
21
|
+
bedrock_titan_embed_text_v2: AWS Bedrock Titan Text Embeddings v2
|
22
|
+
open_ai_text_embedding_3_large: OpenAI Text Embedding 3 Large
|
23
|
+
open_ai_text_embedding_3_small: OpenAI Text Embedding 3 Small
|
24
|
+
open_ai_text_embedding_ada_002: OpenAI Text Embedding Ada 002
|
15
25
|
languages:
|
16
26
|
ar: Arabic
|
17
27
|
da: Danish
|
@@ -40,11 +50,23 @@ en:
|
|
40
50
|
anthropic_claude_3_5_sonnet: Anthropic Claude 3.5 Sonnet
|
41
51
|
anthropic_claude_3_7_sonnet: Anthropic Claude 3.7 Sonnet
|
42
52
|
anthropic_claude_3_opus: Anthropic Claude 3 Opus
|
53
|
+
anthropic_claude_4_opus: Anthropic Claude 4 Opus
|
54
|
+
anthropic_claude_4_sonnet: Anthropic Claude 4 Sonnet
|
43
55
|
bedrock_claude_3_5_haiku: Anthropic Claude 3.5 Haiku (via AWS Bedrock)
|
44
56
|
bedrock_claude_3_5_sonnet: Anthropic Claude 3.5 Sonnet (via AWS Bedrock)
|
45
57
|
bedrock_claude_3_7_sonnet: Anthropic Claude 3.7 Sonnet (via AWS Bedrock)
|
46
58
|
bedrock_claude_3_opus: Anthropic Claude 3 Opus (via AWS Bedrock)
|
59
|
+
bedrock_claude_4_opus: Anthropic Claude 4 Opus (via AWS Bedrock)
|
60
|
+
bedrock_claude_4_sonnet: Anthropic Claude 4 Sonnet (via AWS Bedrock)
|
47
61
|
open_ai_gpt_3_5_turbo: OpenAI GPT-3.5 Turbo
|
62
|
+
open_ai_gpt_4_1: OpenAI GPT-4.1
|
63
|
+
open_ai_gpt_4_1_mini: OpenAI GPT-4.1 Mini
|
64
|
+
open_ai_gpt_4_1_nano: OpenAI GPT-4.1 Nano
|
48
65
|
open_ai_gpt_4o: OpenAI GPT-4o
|
49
66
|
open_ai_gpt_4o_mini: OpenAI GPT-4o Mini
|
67
|
+
open_router_claude_3_7_sonnet: Anthropic Claude 3.7 Sonnet (via OpenRouter)
|
68
|
+
open_router_deepseek_chat_v3: DeepSeek Chat v3 (via OpenRouter)
|
69
|
+
open_router_gemini_2_0_flash: Google Gemini 2.0 Flash (via OpenRouter)
|
70
|
+
open_router_llama_3_1_8b_instruct: Meta Llama 3.1 8B Instruct (via OpenRouter)
|
71
|
+
open_router_llama_3_3_70b_instruct: Meta Llama 3.3 70B Instruct (via OpenRouter)
|
50
72
|
raif_test_llm: Raif Test LLM
|
data/config/routes.rb
CHANGED
@@ -13,6 +13,12 @@ Raif::Engine.routes.draw do
|
|
13
13
|
|
14
14
|
namespace :admin do
|
15
15
|
root to: redirect("admin/model_completions")
|
16
|
+
resources :stats, only: [:index]
|
17
|
+
|
18
|
+
namespace :stats do
|
19
|
+
resources :tasks, only: [:index]
|
20
|
+
end
|
21
|
+
|
16
22
|
resources :tasks, only: [:index, :show]
|
17
23
|
resources :conversations, only: [:index, :show]
|
18
24
|
resources :model_completions, only: [:index, :show]
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddCostColumnsToRaifModelCompletions < ActiveRecord::Migration[8.0]
|
4
|
+
# If you need to backfill cost columns for existing records:
|
5
|
+
# Raif::ModelCompletion.find_each do |model_completion|
|
6
|
+
# model_completion.calculate_costs
|
7
|
+
# model_completion.save(validate: false)
|
8
|
+
# end
|
9
|
+
def change
|
10
|
+
add_column :raif_model_completions, :prompt_token_cost, :decimal, precision: 10, scale: 6
|
11
|
+
add_column :raif_model_completions, :output_token_cost, :decimal, precision: 10, scale: 6
|
12
|
+
add_column :raif_model_completions, :total_cost, :decimal, precision: 10, scale: 6
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddCreatedAtIndexes < ActiveRecord::Migration[8.0]
|
4
|
+
def change
|
5
|
+
add_index :raif_model_completions, :created_at
|
6
|
+
add_index :raif_tasks, :created_at
|
7
|
+
add_index :raif_conversations, :created_at
|
8
|
+
add_index :raif_conversation_entries, :created_at
|
9
|
+
add_index :raif_agents, :created_at
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddStatusIndexesToRaifTasks < ActiveRecord::Migration[8.0]
|
4
|
+
def change
|
5
|
+
add_index :raif_tasks, :completed_at
|
6
|
+
add_index :raif_tasks, :failed_at
|
7
|
+
add_index :raif_tasks, :started_at
|
8
|
+
|
9
|
+
# Index for type + status combinations which will be common in the admin interface
|
10
|
+
add_index :raif_tasks, [:type, :completed_at]
|
11
|
+
add_index :raif_tasks, [:type, :failed_at]
|
12
|
+
add_index :raif_tasks, [:type, :started_at]
|
13
|
+
end
|
14
|
+
end
|
@@ -1,22 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Raif
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
module Generators
|
5
|
+
class AgentGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
7
|
+
desc "Creates a new Raif::Agent subclass in app/models/raif/agents"
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
def create_application_agent
|
10
|
+
template "application_agent.rb.tt", "app/models/raif/application_agent.rb" unless File.exist?("app/models/raif/application_agent.rb")
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
+
def create_agent
|
14
|
+
template "agent.rb.tt", "app/models/raif/agents/#{file_name}.rb"
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
def create_directory
|
18
|
+
empty_directory "app/models/raif/agents" unless File.directory?("app/models/raif/agents")
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def class_name
|
24
|
+
name.classify
|
25
|
+
end
|
17
26
|
|
18
|
-
|
19
|
-
|
27
|
+
def file_name
|
28
|
+
name.underscore
|
29
|
+
end
|
20
30
|
end
|
21
31
|
end
|
22
32
|
end
|
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
module Raif
|
4
4
|
module Agents
|
5
|
-
class <%= class_name %> < Raif::
|
5
|
+
class <%= class_name %> < Raif::ApplicationAgent
|
6
6
|
# If you want to always include a certain set of model tools with this agent type,
|
7
7
|
# uncomment this callback to populate the available_model_tools attribute with your desired model tools.
|
8
|
-
#
|
8
|
+
# def populate_default_model_tools
|
9
9
|
# self.available_model_tools ||= [
|
10
10
|
# Raif::ModelTools::WikipediaSearchTool,
|
11
11
|
# Raif::ModelTools::FetchUrlTool
|
12
12
|
# ]
|
13
|
-
#
|
13
|
+
# end
|
14
14
|
|
15
15
|
# Enter your agent's system prompt here. Alternatively, you can change your agent's superclass
|
16
16
|
# to an existing agent types (like Raif::Agents::ReActAgent) to utilize an existing system prompt.
|
@@ -7,6 +7,16 @@ module Raif
|
|
7
7
|
|
8
8
|
desc "Creates a new conversation type in the app/models/raif/conversations directory"
|
9
9
|
|
10
|
+
class_option :response_format,
|
11
|
+
type: :string,
|
12
|
+
default: "text",
|
13
|
+
desc: "Response format for the task (text, html, or json)"
|
14
|
+
|
15
|
+
def create_application_conversation
|
16
|
+
template "application_conversation.rb.tt",
|
17
|
+
"app/models/raif/application_conversation.rb" unless File.exist?("app/models/raif/application_conversation.rb")
|
18
|
+
end
|
19
|
+
|
10
20
|
def create_conversation_file
|
11
21
|
template "conversation.rb.tt", File.join("app/models/raif/conversations", "#{file_name}.rb")
|
12
22
|
end
|
@@ -2,28 +2,23 @@
|
|
2
2
|
|
3
3
|
module Raif
|
4
4
|
module Conversations
|
5
|
-
class <%= class_name %> < Raif::
|
5
|
+
class <%= class_name %> < Raif::ApplicationConversation
|
6
|
+
# Set the response format for the task. Options are :html, :text, or :json.
|
7
|
+
# If you set this to something other than :text, make sure to include instructions to the model in your system prompt
|
8
|
+
llm_response_format :<%= options[:response_format] %>
|
9
|
+
|
6
10
|
# If you want to always include a certain set of model tools with this conversation type,
|
7
11
|
# uncomment this callback to populate the available_model_tools attribute with your desired model tools.
|
8
12
|
# before_create -> { self.available_model_tools = ["Raif::ModelTools::Example"] }
|
9
13
|
|
10
14
|
# 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
15
|
# def system_prompt_intro
|
13
16
|
# Raif.config.conversation_system_prompt_intro
|
14
17
|
# end
|
15
|
-
|
18
|
+
|
16
19
|
# def build_system_prompt
|
17
20
|
# <<~PROMPT
|
18
21
|
# #{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
22
|
# #{system_prompt_language_preference}
|
28
23
|
# PROMPT
|
29
24
|
# end
|
@@ -32,6 +27,13 @@ module Raif
|
|
32
27
|
# def initial_chat_message
|
33
28
|
# I18n.t("#{self.class.name.underscore.gsub("/", ".")}.initial_chat_message")
|
34
29
|
# end
|
30
|
+
|
31
|
+
# This method will be called when receing a model response to a Raif::ConversationEntry
|
32
|
+
# By default, it just passes the model response message through, but you can override
|
33
|
+
# for custom response message processing
|
34
|
+
# def process_model_response_message(message:, entry:)
|
35
|
+
# message
|
36
|
+
# end
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
@@ -4,23 +4,47 @@ Raif.configure do |config|
|
|
4
4
|
# Your OpenAI API key. Defaults to ENV["OPENAI_API_KEY"]
|
5
5
|
# config.open_ai_api_key = ENV["OPENAI_API_KEY"]
|
6
6
|
|
7
|
-
# Whether OpenAI models are enabled.
|
8
|
-
# config.open_ai_models_enabled =
|
7
|
+
# Whether OpenAI models are enabled.
|
8
|
+
# config.open_ai_models_enabled = ENV["OPENAI_API_KEY"].present?
|
9
|
+
|
10
|
+
# Whether OpenAI embedding models are enabled.
|
11
|
+
# config.open_ai_embedding_models_enabled = ENV["OPENAI_API_KEY"].present?
|
9
12
|
|
10
13
|
# Your Anthropic API key. Defaults to ENV["ANTHROPIC_API_KEY"]
|
11
14
|
# config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
|
12
15
|
|
13
|
-
# Whether Anthropic models are enabled.
|
14
|
-
# config.anthropic_models_enabled =
|
16
|
+
# Whether Anthropic models are enabled.
|
17
|
+
# config.anthropic_models_enabled = ENV["ANTHROPIC_API_KEY"].present?
|
15
18
|
|
16
|
-
# Whether Anthropic models via AWS Bedrock are enabled. Defaults to
|
17
|
-
# config.anthropic_bedrock_models_enabled =
|
19
|
+
# Whether Anthropic models via AWS Bedrock are enabled. Defaults to false
|
20
|
+
# config.anthropic_bedrock_models_enabled = false
|
18
21
|
|
19
22
|
# The AWS Bedrock region to use. Defaults to "us-east-1"
|
20
23
|
# config.aws_bedrock_region = "us-east-1"
|
21
24
|
|
25
|
+
# Prefix to apply to the model name in AWS Bedrock API calls (e.g. us.anthropic.claude-3-5-haiku-20241022-v1:0)
|
26
|
+
# config.aws_bedrock_model_name_prefix = "us"
|
27
|
+
|
28
|
+
# Whether Titan embedding models are enabled. Defaults to false
|
29
|
+
# config.aws_bedrock_titan_embedding_models_enabled = false
|
30
|
+
|
31
|
+
# Your OpenRouter API key. Defaults to ENV["OPENROUTER_API_KEY"]
|
32
|
+
# config.open_router_api_key = ENV["OPENROUTER_API_KEY"]
|
33
|
+
|
34
|
+
# Whether OpenRouter models are enabled.
|
35
|
+
# config.open_router_models_enabled = ENV["OPENROUTER_API_KEY"].present?
|
36
|
+
|
37
|
+
# The app name to include in OpenRouter API requests headers. Optional.
|
38
|
+
# config.open_router_app_name = "My App"
|
39
|
+
|
40
|
+
# The site URL to include in OpenRouter API requests headers. Optional.
|
41
|
+
# config.open_router_site_url = "https://myapp.com"
|
42
|
+
|
22
43
|
# The default LLM model to use. Defaults to "open_ai_gpt_4o"
|
23
44
|
# Available keys:
|
45
|
+
# open_ai_gpt_4_1
|
46
|
+
# open_ai_gpt_4_1_mini
|
47
|
+
# open_ai_gpt_4_1_nano
|
24
48
|
# open_ai_gpt_4o_mini
|
25
49
|
# open_ai_gpt_4o
|
26
50
|
# open_ai_gpt_3_5_turbo
|
@@ -32,8 +56,24 @@ Raif.configure do |config|
|
|
32
56
|
# bedrock_claude_3_7_sonnet
|
33
57
|
# bedrock_claude_3_5_haiku
|
34
58
|
# bedrock_claude_3_opus
|
59
|
+
# open_router_claude_3_7_sonnet
|
60
|
+
# open_router_llama_3_3_70b_instruct
|
61
|
+
# open_router_llama_3_1_8b_instruct
|
62
|
+
# open_router_gemini_2_0_flash
|
63
|
+
# open_router_deepseek_chat_v3
|
64
|
+
#
|
35
65
|
# config.default_llm_model_key = "open_ai_gpt_4o"
|
36
66
|
|
67
|
+
# The default embedding model to use when calling Raif.generate_embedding!
|
68
|
+
# Defaults to "open_ai_text_embedding_3_small"
|
69
|
+
# Available keys:
|
70
|
+
# open_ai_text_embedding_3_small
|
71
|
+
# open_ai_text_embedding_3_large
|
72
|
+
# open_ai_text_embedding_ada_002
|
73
|
+
# bedrock_titan_embed_text_v2
|
74
|
+
#
|
75
|
+
# config.default_embedding_model_key = "open_ai_text_embedding_3_small"
|
76
|
+
|
37
77
|
# A lambda that returns true if the current user is authorized to access admin controllers.
|
38
78
|
# By default it returns false, so you must implement this in your application to use the admin controllers.
|
39
79
|
# If your application's user model has an admin? method, you could use something like this:
|
@@ -46,9 +86,13 @@ Raif.configure do |config|
|
|
46
86
|
|
47
87
|
# The system prompt intro for Raif::Task instances. Defaults to "You are a helpful assistant."
|
48
88
|
# config.task_system_prompt_intro = "You are a helpful assistant."
|
89
|
+
# Or you can use a lambda to return a dynamic system prompt intro:
|
90
|
+
# config.task_system_prompt_intro = ->(task){ "You are a helpful assistant. Today's date is #{Date.today.strftime('%B %d, %Y')}." }
|
49
91
|
|
50
92
|
# The system prompt intro for Raif::Conversation instances. Defaults to "You are a helpful assistant who is collaborating with a teammate."
|
51
93
|
# config.conversation_system_prompt_intro = "You are a helpful assistant who is collaborating with a teammate."
|
94
|
+
# Or you can use a lambda to return a dynamic system prompt intro:
|
95
|
+
# config.conversation_system_prompt_intro = ->(conversation){ "You are a helpful assistant talking to #{conversation.creator.email}. Today's date is #{Date.today.strftime('%B %d, %Y')}." }
|
52
96
|
|
53
97
|
# The conversation types that are available. Defaults to ["Raif::Conversation"]
|
54
98
|
# If you want to use custom conversation types that inherits from Raif::Conversation, you can add them here.
|
@@ -15,11 +15,6 @@ module Raif
|
|
15
15
|
say_status :success, "Model tool created successfully", :green
|
16
16
|
say "\nYou can now implement your model tool in:"
|
17
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
18
|
end
|
24
19
|
|
25
20
|
end
|