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.
Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -5
  3. data/app/assets/builds/raif.css +4 -1
  4. data/app/assets/builds/raif_admin.css +13 -1
  5. data/app/assets/javascript/raif/controllers/conversations_controller.js +1 -1
  6. data/app/assets/stylesheets/raif/admin/conversation.scss +16 -0
  7. data/app/assets/stylesheets/raif/conversations.scss +3 -0
  8. data/app/assets/stylesheets/raif.scss +2 -1
  9. data/app/controllers/raif/admin/application_controller.rb +16 -0
  10. data/app/controllers/raif/admin/configs_controller.rb +94 -0
  11. data/app/controllers/raif/admin/model_completions_controller.rb +18 -1
  12. data/app/controllers/raif/admin/model_tool_invocations_controller.rb +7 -1
  13. data/app/controllers/raif/admin/stats/model_tool_invocations_controller.rb +21 -0
  14. data/app/controllers/raif/admin/stats/tasks_controller.rb +15 -6
  15. data/app/controllers/raif/admin/stats_controller.rb +32 -3
  16. data/app/controllers/raif/conversation_entries_controller.rb +1 -0
  17. data/app/controllers/raif/conversations_controller.rb +10 -2
  18. data/app/jobs/raif/conversation_entry_job.rb +8 -6
  19. data/app/models/raif/admin/task_stat.rb +7 -0
  20. data/app/models/raif/agent.rb +63 -2
  21. data/app/models/raif/agents/native_tool_calling_agent.rb +101 -56
  22. data/app/models/raif/application_record.rb +18 -0
  23. data/app/models/raif/concerns/agent_inference_stats.rb +35 -0
  24. data/app/models/raif/concerns/has_llm.rb +1 -1
  25. data/app/models/raif/concerns/json_schema_definition.rb +40 -5
  26. data/app/models/raif/concerns/llms/anthropic/message_formatting.rb +28 -0
  27. data/app/models/raif/concerns/llms/anthropic/response_tool_calls.rb +24 -0
  28. data/app/models/raif/concerns/llms/anthropic/tool_formatting.rb +4 -0
  29. data/app/models/raif/concerns/llms/bedrock/message_formatting.rb +36 -0
  30. data/app/models/raif/concerns/llms/bedrock/response_tool_calls.rb +26 -0
  31. data/app/models/raif/concerns/llms/bedrock/tool_formatting.rb +4 -0
  32. data/app/models/raif/concerns/llms/google/message_formatting.rb +109 -0
  33. data/app/models/raif/concerns/llms/google/response_tool_calls.rb +32 -0
  34. data/app/models/raif/concerns/llms/google/tool_formatting.rb +72 -0
  35. data/app/models/raif/concerns/llms/message_formatting.rb +11 -5
  36. data/app/models/raif/concerns/llms/open_ai/json_schema_validation.rb +3 -3
  37. data/app/models/raif/concerns/llms/open_ai_completions/message_formatting.rb +22 -0
  38. data/app/models/raif/concerns/llms/open_ai_completions/response_tool_calls.rb +22 -0
  39. data/app/models/raif/concerns/llms/open_ai_completions/tool_formatting.rb +4 -0
  40. data/app/models/raif/concerns/llms/open_ai_responses/message_formatting.rb +17 -0
  41. data/app/models/raif/concerns/llms/open_ai_responses/response_tool_calls.rb +26 -0
  42. data/app/models/raif/concerns/llms/open_ai_responses/tool_formatting.rb +4 -0
  43. data/app/models/raif/concerns/run_with.rb +127 -0
  44. data/app/models/raif/conversation.rb +96 -9
  45. data/app/models/raif/conversation_entry.rb +37 -8
  46. data/app/models/raif/embedding_model.rb +2 -1
  47. data/app/models/raif/embedding_models/open_ai.rb +1 -1
  48. data/app/models/raif/llm.rb +28 -3
  49. data/app/models/raif/llms/anthropic.rb +7 -19
  50. data/app/models/raif/llms/bedrock.rb +6 -20
  51. data/app/models/raif/llms/google.rb +140 -0
  52. data/app/models/raif/llms/open_ai_base.rb +19 -5
  53. data/app/models/raif/llms/open_ai_completions.rb +6 -11
  54. data/app/models/raif/llms/open_ai_responses.rb +6 -16
  55. data/app/models/raif/llms/open_router.rb +10 -14
  56. data/app/models/raif/model_completion.rb +61 -0
  57. data/app/models/raif/model_tool.rb +10 -2
  58. data/app/models/raif/model_tool_invocation.rb +38 -6
  59. data/app/models/raif/model_tools/agent_final_answer.rb +2 -7
  60. data/app/models/raif/model_tools/provider_managed/code_execution.rb +4 -0
  61. data/app/models/raif/model_tools/provider_managed/image_generation.rb +4 -0
  62. data/app/models/raif/model_tools/provider_managed/web_search.rb +4 -0
  63. data/app/models/raif/streaming_responses/google.rb +71 -0
  64. data/app/models/raif/task.rb +74 -18
  65. data/app/models/raif/user_tool_invocation.rb +19 -0
  66. data/app/views/layouts/raif/admin.html.erb +12 -1
  67. data/app/views/raif/admin/agents/_agent.html.erb +8 -0
  68. data/app/views/raif/admin/agents/_conversation_message.html.erb +28 -6
  69. data/app/views/raif/admin/agents/index.html.erb +2 -0
  70. data/app/views/raif/admin/agents/show.html.erb +46 -1
  71. data/app/views/raif/admin/configs/show.html.erb +117 -0
  72. data/app/views/raif/admin/conversations/_conversation_entry.html.erb +29 -34
  73. data/app/views/raif/admin/conversations/show.html.erb +2 -0
  74. data/app/views/raif/admin/model_completions/_model_completion.html.erb +9 -0
  75. data/app/views/raif/admin/model_completions/index.html.erb +26 -0
  76. data/app/views/raif/admin/model_completions/show.html.erb +124 -61
  77. data/app/views/raif/admin/model_tool_invocations/index.html.erb +22 -1
  78. data/app/views/raif/admin/model_tools/_list.html.erb +16 -0
  79. data/app/views/raif/admin/model_tools/_model_tool.html.erb +36 -0
  80. data/app/views/raif/admin/stats/_stats_tile.html.erb +34 -0
  81. data/app/views/raif/admin/stats/index.html.erb +71 -88
  82. data/app/views/raif/admin/stats/model_tool_invocations/index.html.erb +43 -0
  83. data/app/views/raif/admin/stats/tasks/index.html.erb +20 -6
  84. data/app/views/raif/admin/tasks/index.html.erb +6 -1
  85. data/app/views/raif/admin/tasks/show.html.erb +36 -3
  86. data/app/views/raif/conversation_entries/_form.html.erb +4 -1
  87. data/app/views/raif/conversations/_conversation.html.erb +10 -0
  88. data/app/views/raif/conversations/_entry_processed.turbo_stream.erb +12 -0
  89. data/app/views/raif/conversations/_full_conversation.html.erb +3 -6
  90. data/app/views/raif/conversations/_initial_chat_message.html.erb +5 -0
  91. data/app/views/raif/conversations/index.html.erb +23 -0
  92. data/config/locales/admin.en.yml +33 -1
  93. data/config/locales/en.yml +41 -4
  94. data/config/routes.rb +2 -0
  95. data/db/migrate/20250804013843_add_task_run_args_to_raif_tasks.rb +13 -0
  96. data/db/migrate/20250811171150_make_raif_task_creator_optional.rb +8 -0
  97. data/db/migrate/20250904194456_add_generating_entry_response_to_raif_conversations.rb +7 -0
  98. data/db/migrate/20250911125234_add_source_to_raif_tasks.rb +7 -0
  99. data/db/migrate/20251020005853_add_source_to_raif_agents.rb +7 -0
  100. data/db/migrate/20251020011346_rename_task_run_args_to_run_with.rb +7 -0
  101. data/db/migrate/20251020011405_add_run_with_to_raif_agents.rb +13 -0
  102. data/db/migrate/20251024160119_add_llm_messages_max_length_to_raif_conversations.rb +14 -0
  103. data/db/migrate/20251124185033_add_provider_tool_call_id_to_raif_model_tool_invocations.rb +7 -0
  104. data/db/migrate/20251128202941_add_tool_choice_to_raif_model_completions.rb +7 -0
  105. data/db/migrate/20260118144846_add_source_to_raif_conversations.rb +7 -0
  106. data/db/migrate/20260119000000_add_failure_tracking_to_raif_model_completions.rb +10 -0
  107. data/db/migrate/20260119000001_add_completed_at_to_raif_model_completions.rb +8 -0
  108. data/db/migrate/20260119000002_add_started_at_to_raif_model_completions.rb +8 -0
  109. data/exe/raif +7 -0
  110. data/lib/generators/raif/agent/agent_generator.rb +22 -7
  111. data/lib/generators/raif/agent/templates/agent.rb.tt +20 -24
  112. data/lib/generators/raif/agent/templates/agent_eval_set.rb.tt +48 -0
  113. data/lib/generators/raif/agent/templates/application_agent.rb.tt +1 -3
  114. data/lib/generators/raif/base_generator.rb +19 -0
  115. data/lib/generators/raif/conversation/conversation_generator.rb +21 -2
  116. data/lib/generators/raif/conversation/templates/application_conversation.rb.tt +0 -2
  117. data/lib/generators/raif/conversation/templates/conversation.rb.tt +34 -32
  118. data/lib/generators/raif/conversation/templates/conversation_eval_set.rb.tt +70 -0
  119. data/lib/generators/raif/eval_set/eval_set_generator.rb +28 -0
  120. data/lib/generators/raif/eval_set/templates/eval_set.rb.tt +21 -0
  121. data/lib/generators/raif/evals/setup/setup_generator.rb +47 -0
  122. data/lib/generators/raif/install/install_generator.rb +15 -0
  123. data/lib/generators/raif/install/templates/initializer.rb +89 -10
  124. data/lib/generators/raif/model_tool/model_tool_generator.rb +5 -5
  125. data/lib/generators/raif/model_tool/templates/model_tool.rb.tt +78 -78
  126. data/lib/generators/raif/model_tool/templates/model_tool_invocation_partial.html.erb.tt +1 -1
  127. data/lib/generators/raif/task/task_generator.rb +22 -3
  128. data/lib/generators/raif/task/templates/application_task.rb.tt +0 -2
  129. data/lib/generators/raif/task/templates/task.rb.tt +55 -59
  130. data/lib/generators/raif/task/templates/task_eval_set.rb.tt +54 -0
  131. data/lib/raif/cli/base.rb +39 -0
  132. data/lib/raif/cli/evals.rb +47 -0
  133. data/lib/raif/cli/evals_setup.rb +27 -0
  134. data/lib/raif/cli.rb +67 -0
  135. data/lib/raif/configuration.rb +57 -8
  136. data/lib/raif/engine.rb +8 -0
  137. data/lib/raif/errors/instance_dependent_schema_error.rb +8 -0
  138. data/lib/raif/errors/streaming_error.rb +6 -3
  139. data/lib/raif/errors.rb +1 -0
  140. data/lib/raif/evals/eval.rb +30 -0
  141. data/lib/raif/evals/eval_set.rb +111 -0
  142. data/lib/raif/evals/eval_sets/expectations.rb +53 -0
  143. data/lib/raif/evals/eval_sets/llm_judge_expectations.rb +255 -0
  144. data/lib/raif/evals/expectation_result.rb +39 -0
  145. data/lib/raif/evals/llm_judge.rb +32 -0
  146. data/lib/raif/evals/llm_judges/binary.rb +94 -0
  147. data/lib/raif/evals/llm_judges/comparative.rb +89 -0
  148. data/lib/raif/evals/llm_judges/scored.rb +63 -0
  149. data/lib/raif/evals/llm_judges/summarization.rb +166 -0
  150. data/lib/raif/evals/run.rb +202 -0
  151. data/lib/raif/evals/scoring_rubric.rb +174 -0
  152. data/lib/raif/evals.rb +26 -0
  153. data/lib/raif/json_schema_builder.rb +14 -0
  154. data/lib/raif/llm_registry.rb +218 -15
  155. data/lib/raif/messages.rb +180 -0
  156. data/lib/raif/migration_checker.rb +3 -3
  157. data/lib/raif/utils/colors.rb +23 -0
  158. data/lib/raif/utils.rb +1 -0
  159. data/lib/raif/version.rb +1 -1
  160. data/lib/raif.rb +13 -0
  161. data/lib/tasks/annotate_rb.rake +10 -0
  162. data/spec/support/current_temperature_test_tool.rb +34 -0
  163. data/spec/support/rspec_helpers.rb +8 -8
  164. data/spec/support/test_conversation.rb +1 -1
  165. metadata +77 -10
  166. data/app/models/raif/agents/re_act_agent.rb +0 -127
  167. data/app/models/raif/agents/re_act_step.rb +0 -33
@@ -36,45 +36,40 @@
36
36
  <% if entry.raif_model_tool_invocations.any? %>
37
37
  <div class="mb-3">
38
38
  <strong><%= t("raif.admin.common.model_tool_invocations") %>:</strong>
39
- <div class="ms-3 mt-2">
39
+ <div class="conversation-history ms-3 mt-2">
40
40
  <% entry.raif_model_tool_invocations.each do |invocation| %>
41
- <div class="card mb-2">
42
- <div class="card-body p-3">
43
- <div class="d-flex w-100 justify-content-between align-items-start">
44
- <div>
45
- <h6 class="mb-1">
46
- <%= link_to invocation.tool_name, raif.admin_model_tool_invocation_path(invocation) %>
47
- </h6>
48
- <% if invocation.completed_at? %>
49
- <span class="badge bg-success"><%= t("raif.admin.common.completed") %></span>
50
- <% elsif invocation.failed_at? %>
51
- <span class="badge bg-danger"><%= t("raif.admin.common.failed") %></span>
52
- <% else %>
53
- <span class="badge bg-secondary"><%= t("raif.admin.common.pending") %></span>
54
- <% end %>
55
- </div>
56
- <small class="text-muted"><%= invocation.created_at.rfc822 %></small>
57
- </div>
58
- <div class="mt-2">
41
+ <div class="message tool_call mb-3">
42
+ <div class="message-header d-flex justify-content-between align-items-center mb-2 px-2">
43
+ <strong class="text-warning">
44
+ <%= t("raif.admin.common.tool_call") %>: <%= link_to invocation.tool_name, raif.admin_model_tool_invocation_path(invocation) %>
45
+ <% if invocation.completed_at? %>
46
+ <span class="badge bg-success ms-2"><%= t("raif.admin.common.completed") %></span>
47
+ <% elsif invocation.failed_at? %>
48
+ <span class="badge bg-danger ms-2"><%= t("raif.admin.common.failed") %></span>
49
+ <% else %>
50
+ <span class="badge bg-secondary ms-2"><%= t("raif.admin.common.pending") %></span>
51
+ <% end %>
52
+ </strong>
53
+ <small class="text-muted"><%= invocation.created_at.rfc822 %></small>
54
+ </div>
55
+ <div class="message-content px-3 py-2">
56
+ <div>
59
57
  <strong><%= t("raif.admin.common.arguments") %>:</strong>
60
- <pre class="pre-wrap mt-1"><%= begin
61
- JSON.pretty_generate(invocation.tool_arguments)
62
- rescue StandardError
63
- invocation.tool_arguments
64
- end %></pre>
58
+ <code><%= invocation.tool_arguments.to_json %></code>
65
59
  </div>
66
- <% if invocation.result.present? %>
67
- <div class="mt-2">
68
- <strong><%= t("raif.admin.common.result") %>:</strong>
69
- <pre class="pre-wrap mt-1"><%= begin
70
- JSON.pretty_generate(invocation.result)
71
- rescue StandardError
72
- invocation.result
73
- end %></pre>
74
- </div>
75
- <% end %>
76
60
  </div>
77
61
  </div>
62
+
63
+ <% if invocation.result.present? %>
64
+ <div class="message tool_call_result mb-3">
65
+ <div class="message-header d-flex justify-content-between align-items-center mb-2 px-2">
66
+ <strong class="text-success"><%= t("raif.admin.common.tool_result") %></strong>
67
+ </div>
68
+ <div class="message-content px-3 py-2">
69
+ <code><%= invocation.result.is_a?(String) ? invocation.result : JSON.pretty_generate(invocation.result) %></code>
70
+ </div>
71
+ </div>
72
+ <% end %>
78
73
  <% end %>
79
74
  </div>
80
75
  </div>
@@ -33,6 +33,8 @@
33
33
  </div>
34
34
  </div>
35
35
 
36
+ <%= render "raif/admin/model_tools/list", model_tools: @conversation.available_model_tools_map %>
37
+
36
38
  <div class="card mb-4">
37
39
  <div class="card-header">
38
40
  <h5 class="mb-0"><%= t("raif.admin.common.system_prompt") %></h5>
@@ -4,6 +4,15 @@
4
4
  <td><%= model_completion.source_type %> #<%= model_completion.source_id %></td>
5
5
  <td><%= model_completion.llm_model_key %></td>
6
6
  <td><%= model_completion.response_format %></td>
7
+ <td>
8
+ <% if model_completion.failed? %>
9
+ <span class="badge bg-danger"><%= t("raif.admin.common.failed") %></span>
10
+ <% elsif model_completion.completed? %>
11
+ <span class="badge bg-success"><%= t("raif.admin.common.completed") %></span>
12
+ <% else %>
13
+ <span class="badge bg-secondary"><%= t("raif.admin.common.pending") %></span>
14
+ <% end %>
15
+ </td>
7
16
  <td><%= model_completion.total_tokens ? number_with_delimiter(model_completion.total_tokens) : "-" %></td>
8
17
  <td><%= model_completion.total_cost ? number_to_currency(model_completion.total_cost, precision: 6) : "-" %></td>
9
18
  <td>
@@ -2,6 +2,31 @@
2
2
 
3
3
  <div class="row">
4
4
  <div class="col-12">
5
+ <%= form_tag raif.admin_model_completions_path, method: :get, class: "mb-4" do %>
6
+ <div class="row align-items-end">
7
+ <div class="col-md-4">
8
+ <div class="form-group">
9
+ <label for="status"><%= t("raif.admin.common.status") %></label>
10
+ <%= select_tag :status,
11
+ options_for_select(
12
+ [
13
+ [t("raif.admin.common.all"), :all],
14
+ [t("raif.admin.common.completed"), :completed],
15
+ [t("raif.admin.common.failed"), :failed],
16
+ [t("raif.admin.common.in_progress"), :started],
17
+ [t("raif.admin.common.pending"), :pending]
18
+ ],
19
+ @selected_status
20
+ ),
21
+ { class: "form-select" } %>
22
+ </div>
23
+ </div>
24
+ <div class="col-md-2">
25
+ <%= submit_tag t("raif.admin.common.filter"), class: "btn btn-primary" %>
26
+ </div>
27
+ </div>
28
+ <% end %>
29
+
5
30
  <% if @model_completions.any? %>
6
31
  <div class="table-responsive">
7
32
  <table class="table table-striped table-hover">
@@ -12,6 +37,7 @@
12
37
  <th><%= t("raif.admin.common.source") %></th>
13
38
  <th><%= t("raif.admin.common.model") %></th>
14
39
  <th><%= t("raif.admin.common.response_format") %></th>
40
+ <th><%= t("raif.admin.common.status") %></th>
15
41
  <th><%= t("raif.admin.common.total_tokens") %></th>
16
42
  <th><%= t("raif.admin.common.total_cost") %></th>
17
43
  <th><%= t("raif.admin.common.citations") %></th>
@@ -8,69 +8,112 @@
8
8
  <h5 class="mb-0"><%= t("raif.admin.common.details") %></h5>
9
9
  </div>
10
10
  <div class="card-body">
11
- <div class="row mb-3">
12
- <div class="col-md-3"><strong><%= t("raif.admin.common.id") %>:</strong></div>
13
- <div class="col-md-9"><%= @model_completion.id %></div>
14
- </div>
15
- <div class="row mb-3">
16
- <div class="col-md-3"><strong><%= t("raif.admin.common.source") %>:</strong></div>
17
- <div class="col-md-9"><%= @model_completion.source_type %> #<%= @model_completion.source_id %></div>
18
- </div>
19
- <div class="row mb-3">
20
- <div class="col-md-3"><strong><%= t("raif.admin.common.model") %>:</strong></div>
21
- <div class="col-md-9"><%= @model_completion.llm_model_key %></div>
22
- </div>
23
- <div class="row mb-3">
24
- <div class="col-md-3"><strong><%= t("raif.admin.common.response_format") %>:</strong></div>
25
- <div class="col-md-9"><%= @model_completion.response_format %></div>
26
- </div>
27
- <div class="row mb-3">
28
- <div class="col-md-3"><strong><%= t("raif.admin.common.response_format_parameter") %>:</strong></div>
29
- <div class="col-md-9"><%= @model_completion.response_format_parameter %></div>
30
- </div>
31
- <div class="row mb-3">
32
- <div class="col-md-3"><strong><%= t("raif.admin.common.created_at") %>:</strong></div>
33
- <div class="col-md-9"><%= @model_completion.created_at.rfc822 %></div>
34
- </div>
35
- <div class="row mb-3">
36
- <div class="col-md-3"><strong><%= t("raif.admin.common.prompt_tokens") %>:</strong></div>
37
- <div class="col-md-9">
38
- <% if @model_completion.prompt_tokens %>
39
- <%= number_with_delimiter(@model_completion.prompt_tokens) %>
40
- <% if @model_completion.prompt_token_cost %>
41
- <small>(<%= t("raif.admin.common.est_cost") %>: <%= "$" %><%= number_with_precision(@model_completion.prompt_token_cost, precision: 6) %>)</small>
42
- <% end %>
43
- <% else %>
44
- -
45
- <% end %>
11
+ <div class="row">
12
+ <div class="col-md-6">
13
+ <div class="row mb-2">
14
+ <div class="col-5"><strong><%= t("raif.admin.common.id") %>:</strong></div>
15
+ <div class="col-7"><%= @model_completion.id %></div>
16
+ </div>
17
+ <div class="row mb-2">
18
+ <div class="col-5"><strong><%= t("raif.admin.common.source") %>:</strong></div>
19
+ <div class="col-7"><%= @model_completion.source_type %> #<%= @model_completion.source_id %></div>
20
+ </div>
21
+ <div class="row mb-2">
22
+ <div class="col-5"><strong><%= t("raif.admin.common.model") %>:</strong></div>
23
+ <div class="col-7"><%= @model_completion.llm_model_key %></div>
24
+ </div>
25
+ <div class="row mb-2">
26
+ <div class="col-5"><strong><%= t("raif.admin.common.response_format") %>:</strong></div>
27
+ <div class="col-7"><%= @model_completion.response_format %><%= " (#{@model_completion.response_format_parameter})" if @model_completion.response_format_parameter.present? %></div>
28
+ </div>
29
+ <div class="row mb-2">
30
+ <div class="col-5"><strong><%= t("raif.admin.common.status") %>:</strong></div>
31
+ <div class="col-7">
32
+ <% if @model_completion.failed? %>
33
+ <span class="badge bg-danger"><%= t("raif.admin.common.failed") %></span>
34
+ <% elsif @model_completion.completed? %>
35
+ <span class="badge bg-success"><%= t("raif.admin.common.completed") %></span>
36
+ <% elsif @model_completion.started? %>
37
+ <span class="badge bg-warning text-dark"><%= t("raif.admin.common.in_progress") %></span>
38
+ <% else %>
39
+ <span class="badge bg-secondary"><%= t("raif.admin.common.pending") %></span>
40
+ <% end %>
41
+ </div>
42
+ </div>
43
+ <div class="row mb-2">
44
+ <div class="col-5"><strong><%= t("raif.admin.common.retry_count") %>:</strong></div>
45
+ <div class="col-7"><%= @model_completion.retry_count %></div>
46
+ </div>
46
47
  </div>
47
- </div>
48
- <div class="row mb-3">
49
- <div class="col-md-3"><strong><%= t("raif.admin.common.completion_tokens") %>:</strong></div>
50
- <div class="col-md-9">
51
- <% if @model_completion.completion_tokens %>
52
- <%= number_with_delimiter(@model_completion.completion_tokens) %>
53
- <% if @model_completion.output_token_cost %>
54
- <small>(<%= t("raif.admin.common.est_cost") %>: <%= "$" %><%= number_with_precision(@model_completion.output_token_cost, precision: 6) %>)</small>
55
- <% end %>
56
- <% else %>
57
- -
58
- <% end %>
48
+ <div class="col-md-6">
49
+ <div class="row mb-2">
50
+ <div class="col-5"><strong><%= t("raif.admin.common.created_at") %>:</strong></div>
51
+ <div class="col-7"><small><%= @model_completion.created_at.rfc822 %></small></div>
52
+ </div>
53
+ <div class="row mb-2">
54
+ <div class="col-5"><strong><%= t("raif.admin.common.started_at") %>:</strong></div>
55
+ <div class="col-7"><small><%= @model_completion.started_at&.rfc822 || "-" %></small></div>
56
+ </div>
57
+ <div class="row mb-2">
58
+ <div class="col-5"><strong><%= t("raif.admin.common.completed_at") %>:</strong></div>
59
+ <div class="col-7"><small><%= @model_completion.completed_at&.rfc822 || "-" %></small></div>
60
+ </div>
61
+ <div class="row mb-2">
62
+ <div class="col-5"><strong><%= t("raif.admin.common.prompt_tokens") %>:</strong></div>
63
+ <div class="col-7">
64
+ <% if @model_completion.prompt_tokens %>
65
+ <%= number_with_delimiter(@model_completion.prompt_tokens) %>
66
+ <% if @model_completion.prompt_token_cost %>
67
+ <small>(<%= t("raif.admin.common.est_cost") %>: <%= number_to_currency(@model_completion.prompt_token_cost, precision: 6) %>)</small>
68
+ <% end %>
69
+ <% else %>
70
+ -
71
+ <% end %>
72
+ </div>
73
+ </div>
74
+ <div class="row mb-2">
75
+ <div class="col-5"><strong><%= t("raif.admin.common.completion_tokens") %>:</strong></div>
76
+ <div class="col-7">
77
+ <% if @model_completion.completion_tokens %>
78
+ <%= number_with_delimiter(@model_completion.completion_tokens) %>
79
+ <% if @model_completion.output_token_cost %>
80
+ <small>(<%= t("raif.admin.common.est_cost") %>: <%= number_to_currency(@model_completion.output_token_cost, precision: 6) %>)</small>
81
+ <% end %>
82
+ <% else %>
83
+ -
84
+ <% end %>
85
+ </div>
86
+ </div>
87
+ <div class="row mb-2">
88
+ <div class="col-5"><strong><%= t("raif.admin.common.total_tokens") %>:</strong></div>
89
+ <div class="col-7">
90
+ <% if @model_completion.total_tokens %>
91
+ <%= number_with_delimiter(@model_completion.total_tokens) %>
92
+ <% if @model_completion.total_cost %>
93
+ <small>(<%= t("raif.admin.common.est_cost") %>: <%= "$" %><%= number_with_precision(@model_completion.total_cost, precision: 6) %>)</small>
94
+ <% end %>
95
+ <% else %>
96
+ -
97
+ <% end %>
98
+ </div>
99
+ </div>
59
100
  </div>
60
101
  </div>
61
- <div class="row mb-3">
62
- <div class="col-md-3"><strong><%= t("raif.admin.common.total_tokens") %>:</strong></div>
63
- <div class="col-md-9">
64
- <% if @model_completion.total_tokens %>
65
- <%= number_with_delimiter(@model_completion.total_tokens) %>
66
- <% if @model_completion.total_cost %>
67
- <small>(<%= t("raif.admin.common.est_cost") %>: <%= "$" %><%= number_with_precision(@model_completion.total_cost, precision: 6) %>)</small>
68
- <% end %>
69
- <% else %>
70
- -
71
- <% end %>
72
- </div>
102
+ <% if @model_completion.failed? %>
103
+ <hr>
104
+ <div class="row mb-2">
105
+ <div class="col-md-2"><strong><%= t("raif.admin.common.failed_at") %>:</strong></div>
106
+ <div class="col-md-10"><small><%= @model_completion.failed_at&.rfc822 || "-" %></small></div>
73
107
  </div>
108
+ <div class="row mb-2">
109
+ <div class="col-md-2"><strong><%= t("raif.admin.common.failure_error") %>:</strong></div>
110
+ <div class="col-md-10"><code><%= @model_completion.failure_error %></code></div>
111
+ </div>
112
+ <div class="row mb-2">
113
+ <div class="col-md-2"><strong><%= t("raif.admin.common.failure_reason") %>:</strong></div>
114
+ <div class="col-md-10"><%= @model_completion.failure_reason %></div>
115
+ </div>
116
+ <% end %>
74
117
  </div>
75
118
  </div>
76
119
 
@@ -82,8 +125,28 @@
82
125
  <div class="card-body">
83
126
  <% @model_completion.messages.each do |message| %>
84
127
  <div class="mb-3">
85
- <strong><%= message["role"].titleize %>:</strong>
86
- <pre class="mt-2"><%= message["content"] %></pre>
128
+ <% if message["role"].present? %>
129
+ <strong><%= message["role"].titleize %>:</strong>
130
+ <% end %>
131
+ <% if message["content"].present? %>
132
+ <pre class="mt-2"><%= message["content"] %></pre>
133
+ <% end %>
134
+
135
+ <% if message["tool_calls"].present? %>
136
+ <div class="mt-2">
137
+ <% message["tool_calls"].each do |tool_call| %>
138
+ <div class="border rounded p-2 mb-2 bg-light">
139
+ <div><strong><%= t("raif.admin.common.tool_name") %>:</strong> <%= tool_call.dig("function", "name") %></div>
140
+ <div><strong><%= t("raif.admin.common.arguments") %>:</strong></div>
141
+ <pre class="mb-0 mt-1"><%= begin
142
+ JSON.pretty_generate(JSON.parse(tool_call.dig("function", "arguments")))
143
+ rescue StandardError
144
+ tool_call.dig("function", "arguments")
145
+ end %></pre>
146
+ </div>
147
+ <% end %>
148
+ </div>
149
+ <% end %>
87
150
  </div>
88
151
  <% end %>
89
152
  </div>
@@ -1,7 +1,28 @@
1
- <h1 class="my-4"><%= t("raif.admin.common.model_tool_invocations") %></h1>
1
+ <div class="d-flex justify-content-between align-items-center my-4">
2
+ <h1 class="mb-0"><%= t("raif.admin.common.model_tool_invocations") %></h1>
3
+ <%= link_to raif.admin_stats_model_tool_invocations_path, class: "btn btn-outline-primary" do %>
4
+ <%= t("raif.admin.common.stats") %> &raquo;
5
+ <% end %>
6
+ </div>
2
7
 
3
8
  <div class="row">
4
9
  <div class="col-12">
10
+ <%= form_tag raif.admin_model_tool_invocations_path, method: :get, class: "mb-4" do %>
11
+ <div class="row align-items-end">
12
+ <div class="col-md-4">
13
+ <div class="form-group">
14
+ <label for="tool_types"><%= t("raif.admin.common.tool_type") %></label>
15
+ <%= select_tag :tool_types,
16
+ options_for_select([[t("raif.admin.common.all"), "all"]] + @tool_types.map{|type| [type, type] }, @selected_type),
17
+ { class: "form-select" } %>
18
+ </div>
19
+ </div>
20
+ <div class="col-md-2">
21
+ <%= submit_tag t("raif.admin.common.filter"), class: "btn btn-primary" %>
22
+ </div>
23
+ </div>
24
+ <% end %>
25
+
5
26
  <% if @model_tool_invocations.any? %>
6
27
  <div class="table-responsive">
7
28
  <table class="table table-striped table-hover">
@@ -0,0 +1,16 @@
1
+ <div class="card mb-4">
2
+ <div class="card-header">
3
+ <h5 class="mb-0"><%= t("raif.admin.common.available_tools") %></h5>
4
+ </div>
5
+ <div class="card-body">
6
+ <% if model_tools.blank? %>
7
+ <%= t("raif.admin.common.none") %>
8
+ <% else %>
9
+ <div class="accordion" id="modelToolsAccordion">
10
+ <% model_tools.each_with_index do |(tool_name, tool_class), index| %>
11
+ <%= render partial: "raif/admin/model_tools/model_tool", locals: { tool_name: tool_name, tool_class: tool_class, index: index } %>
12
+ <% end %>
13
+ </div>
14
+ <% end %>
15
+ </div>
16
+ </div>
@@ -0,0 +1,36 @@
1
+ <div class="accordion-item">
2
+ <h2 class="accordion-header" id="heading-<%= index %>">
3
+ <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-<%= index %>" aria-expanded="false" aria-controls="collapse-<%= index %>">
4
+ <strong><%= tool_name %></strong>
5
+ </button>
6
+ </h2>
7
+ <div id="collapse-<%= index %>" class="accordion-collapse collapse" aria-labelledby="heading-<%= index %>" data-bs-parent="#modelToolsAccordion">
8
+ <div class="accordion-body">
9
+ <div class="row mb-3">
10
+ <div class="col-md-2"><strong><%= t("raif.admin.common.tool_name") %>:</strong></div>
11
+ <div class="col-md-10"><code><%= tool_class.tool_name %></code></div>
12
+ </div>
13
+ <div class="row mb-3">
14
+ <div class="col-md-2"><strong><%= t("raif.admin.common.description") %>:</strong></div>
15
+ <div class="col-md-10"><%= tool_class.tool_description %></div>
16
+ </div>
17
+ <% if tool_class.respond_to?(:tool_arguments_schema) %>
18
+ <% if tool_class.schema_defined?(:tool_arguments) %>
19
+ <div class="row mb-3">
20
+ <div class="col-md-2"><strong><%= t("raif.admin.common.arguments_schema") %>:</strong></div>
21
+ <div class="col-md-10">
22
+ <pre class="pre-wrap"><%= JSON.pretty_generate(tool_class.tool_arguments_schema) %></pre>
23
+ </div>
24
+ </div>
25
+ <% else %>
26
+ <div class="row mb-3">
27
+ <div class="col-md-2"><strong><%= t("raif.admin.common.arguments_schema") %>:</strong></div>
28
+ <div class="col-md-10">
29
+ <em><%= t("raif.admin.common.none") %></em>
30
+ </div>
31
+ </div>
32
+ <% end %>
33
+ <% end %>
34
+ </div>
35
+ </div>
36
+ </div>
@@ -0,0 +1,34 @@
1
+ <div class="col-md-4 col-lg-4">
2
+ <div class="stats-card p-3 border rounded shadow-sm h-100 d-flex flex-column justify-content-between">
3
+ <div class="d-flex justify-content-between align-items-start<%= " mb-2" if local_assigns[:show_costs] %>">
4
+ <div class="d-flex align-items-center<%= " mb-2" unless local_assigns[:show_costs] %>">
5
+ <span class="stats-icon bg-<%= icon_color %>-subtle text-<%= icon_color %> rounded p-2 me-3">
6
+ <%= yield %>
7
+ </span>
8
+ <h6 class="mb-0 text-muted"><%= title %></h6>
9
+ </div>
10
+
11
+ <% if local_assigns[:details_link] %>
12
+ <div class="text-end">
13
+ <h3 class="fw-bold mb-0"><%= number_with_delimiter(count) %></h3>
14
+ <%= link_to details_link do %>
15
+ <small><%= t("raif.admin.common.details") %> &raquo;</small>
16
+ <% end %>
17
+ </div>
18
+ <% else %>
19
+ <h3 class="fw-bold mb-0"><%= number_with_delimiter(count) %></h3>
20
+ <% end %>
21
+ </div>
22
+
23
+ <% if local_assigns[:show_costs] %>
24
+ <div class="d-flex justify-content-between align-items-end text-muted">
25
+ <div>
26
+ <div><small><%= t("raif.admin.common.est_costs") %></small></div>
27
+ <div><small><%= t("raif.admin.common.input").downcase %>: <%= number_to_currency(input_cost, precision: 2) %></small></div>
28
+ </div>
29
+ <div><small><%= t("raif.admin.common.output").downcase %>: <%= number_to_currency(output_cost, precision: 2) %></small></div>
30
+ <div><strong><small><%= t("raif.admin.common.total").downcase %>: <%= number_to_currency(total_cost, precision: 2) %></small></strong></div>
31
+ </div>
32
+ <% end %>
33
+ </div>
34
+ </div>