prompt_engine 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +67 -0
- data/Rakefile +22 -0
- data/app/assets/stylesheets/prompt_engine/application.css +22 -0
- data/app/assets/stylesheets/prompt_engine/buttons.css +124 -0
- data/app/assets/stylesheets/prompt_engine/cards.css +63 -0
- data/app/assets/stylesheets/prompt_engine/comparison.css +244 -0
- data/app/assets/stylesheets/prompt_engine/components/_test_runs.css +144 -0
- data/app/assets/stylesheets/prompt_engine/dashboard.css +343 -0
- data/app/assets/stylesheets/prompt_engine/evaluations.css +124 -0
- data/app/assets/stylesheets/prompt_engine/forms.css +198 -0
- data/app/assets/stylesheets/prompt_engine/foundation.css +182 -0
- data/app/assets/stylesheets/prompt_engine/layout.css +75 -0
- data/app/assets/stylesheets/prompt_engine/loading.css +229 -0
- data/app/assets/stylesheets/prompt_engine/notifications.css +78 -0
- data/app/assets/stylesheets/prompt_engine/overrides.css +42 -0
- data/app/assets/stylesheets/prompt_engine/prompts.css +237 -0
- data/app/assets/stylesheets/prompt_engine/sidebar.css +90 -0
- data/app/assets/stylesheets/prompt_engine/tables.css +250 -0
- data/app/assets/stylesheets/prompt_engine/utilities.css +52 -0
- data/app/assets/stylesheets/prompt_engine/versions.css +370 -0
- data/app/clients/prompt_engine/open_ai_evals_client.rb +135 -0
- data/app/controllers/prompt_engine/admin/base_controller.rb +7 -0
- data/app/controllers/prompt_engine/application_controller.rb +4 -0
- data/app/controllers/prompt_engine/dashboard_controller.rb +24 -0
- data/app/controllers/prompt_engine/eval_runs_controller.rb +23 -0
- data/app/controllers/prompt_engine/eval_sets_controller.rb +200 -0
- data/app/controllers/prompt_engine/evaluations_controller.rb +32 -0
- data/app/controllers/prompt_engine/playground_controller.rb +57 -0
- data/app/controllers/prompt_engine/playground_run_results_controller.rb +41 -0
- data/app/controllers/prompt_engine/prompts_controller.rb +70 -0
- data/app/controllers/prompt_engine/settings_controller.rb +28 -0
- data/app/controllers/prompt_engine/test_cases_controller.rb +231 -0
- data/app/controllers/prompt_engine/versions_controller.rb +90 -0
- data/app/helpers/prompt_engine/application_helper.rb +4 -0
- data/app/jobs/prompt_engine/application_job.rb +4 -0
- data/app/mailers/prompt_engine/application_mailer.rb +6 -0
- data/app/models/prompt_engine/application_record.rb +5 -0
- data/app/models/prompt_engine/eval_result.rb +19 -0
- data/app/models/prompt_engine/eval_run.rb +40 -0
- data/app/models/prompt_engine/eval_set.rb +97 -0
- data/app/models/prompt_engine/parameter.rb +126 -0
- data/app/models/prompt_engine/parameter_parser.rb +39 -0
- data/app/models/prompt_engine/playground_run_result.rb +20 -0
- data/app/models/prompt_engine/prompt.rb +192 -0
- data/app/models/prompt_engine/prompt_version.rb +72 -0
- data/app/models/prompt_engine/setting.rb +45 -0
- data/app/models/prompt_engine/test_case.rb +29 -0
- data/app/services/prompt_engine/evaluation_runner.rb +258 -0
- data/app/services/prompt_engine/playground_executor.rb +124 -0
- data/app/services/prompt_engine/variable_detector.rb +97 -0
- data/app/views/layouts/prompt_engine/admin.html.erb +65 -0
- data/app/views/layouts/prompt_engine/application.html.erb +17 -0
- data/app/views/prompt_engine/dashboard/index.html.erb +230 -0
- data/app/views/prompt_engine/eval_runs/show.html.erb +204 -0
- data/app/views/prompt_engine/eval_sets/compare.html.erb +229 -0
- data/app/views/prompt_engine/eval_sets/edit.html.erb +111 -0
- data/app/views/prompt_engine/eval_sets/index.html.erb +63 -0
- data/app/views/prompt_engine/eval_sets/metrics.html.erb +371 -0
- data/app/views/prompt_engine/eval_sets/new.html.erb +113 -0
- data/app/views/prompt_engine/eval_sets/show.html.erb +235 -0
- data/app/views/prompt_engine/evaluations/index.html.erb +194 -0
- data/app/views/prompt_engine/playground/result.html.erb +58 -0
- data/app/views/prompt_engine/playground/show.html.erb +129 -0
- data/app/views/prompt_engine/playground_run_results/index.html.erb +99 -0
- data/app/views/prompt_engine/playground_run_results/show.html.erb +123 -0
- data/app/views/prompt_engine/prompts/_form.html.erb +224 -0
- data/app/views/prompt_engine/prompts/edit.html.erb +9 -0
- data/app/views/prompt_engine/prompts/index.html.erb +80 -0
- data/app/views/prompt_engine/prompts/new.html.erb +9 -0
- data/app/views/prompt_engine/prompts/show.html.erb +297 -0
- data/app/views/prompt_engine/settings/edit.html.erb +93 -0
- data/app/views/prompt_engine/shared/_form_errors.html.erb +16 -0
- data/app/views/prompt_engine/test_cases/edit.html.erb +72 -0
- data/app/views/prompt_engine/test_cases/import.html.erb +92 -0
- data/app/views/prompt_engine/test_cases/import_preview.html.erb +103 -0
- data/app/views/prompt_engine/test_cases/new.html.erb +79 -0
- data/app/views/prompt_engine/versions/_version_card.html.erb +56 -0
- data/app/views/prompt_engine/versions/compare.html.erb +82 -0
- data/app/views/prompt_engine/versions/index.html.erb +96 -0
- data/app/views/prompt_engine/versions/show.html.erb +98 -0
- data/config/routes.rb +61 -0
- data/db/migrate/20250124000001_create_eval_tables.rb +43 -0
- data/db/migrate/20250124000002_add_open_ai_fields_to_evals.rb +11 -0
- data/db/migrate/20250125000001_add_grader_fields_to_eval_sets.rb +8 -0
- data/db/migrate/20250723161909_create_prompts.rb +17 -0
- data/db/migrate/20250723184757_create_prompt_engine_versions.rb +24 -0
- data/db/migrate/20250723203838_create_prompt_engine_parameters.rb +20 -0
- data/db/migrate/20250724160623_create_prompt_engine_playground_run_results.rb +30 -0
- data/db/migrate/20250724165118_create_prompt_engine_settings.rb +14 -0
- data/lib/prompt_engine/engine.rb +25 -0
- data/lib/prompt_engine/version.rb +3 -0
- data/lib/prompt_engine.rb +33 -0
- data/lib/tasks/active_prompt_tasks.rake +32 -0
- data/lib/tasks/eval_demo.rake +149 -0
- metadata +293 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
<div class="admin-header">
|
2
|
+
<div>
|
3
|
+
<h1>New Test Case</h1>
|
4
|
+
<p class="text-muted">Add a test case to <%= @eval_set.name %></p>
|
5
|
+
</div>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<div class="card">
|
9
|
+
<div class="card__body">
|
10
|
+
<%= form_with model: [@prompt, @eval_set, @test_case],
|
11
|
+
url: prompt_eval_set_test_cases_path(@prompt, @eval_set), local: true do |form| %>
|
12
|
+
<%= render 'prompt_engine/shared/form_errors', object: @test_case %>
|
13
|
+
|
14
|
+
<div class="form__group">
|
15
|
+
<%= form.label :description, class: "form__label" %>
|
16
|
+
<%= form.text_field :description, class: "form__input",
|
17
|
+
placeholder: "e.g., Test response to angry customer complaint" %>
|
18
|
+
<p class="form__help">Brief description of what this test case validates</p>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<div class="form__section">
|
22
|
+
<h3 class="form__section-title">Input Variables</h3>
|
23
|
+
<p class="form__help mb-md">Set values for each variable in the prompt template</p>
|
24
|
+
|
25
|
+
<% @prompt.parameters.ordered.each do |parameter| %>
|
26
|
+
<div class="form__group">
|
27
|
+
<%= label_tag "test_case[input_variables][#{parameter.name}]", parameter.name, class: "form__label" %>
|
28
|
+
|
29
|
+
<% case parameter.parameter_type %>
|
30
|
+
<% when 'boolean' %>
|
31
|
+
<%= select_tag "test_case[input_variables][#{parameter.name}]",
|
32
|
+
options_for_select([['true', true], ['false', false]],
|
33
|
+
@test_case.input_variables&.dig(parameter.name) || parameter.default_value),
|
34
|
+
class: "form__input" %>
|
35
|
+
<% when 'integer', 'decimal' %>
|
36
|
+
<%= number_field_tag "test_case[input_variables][#{parameter.name}]",
|
37
|
+
@test_case.input_variables&.dig(parameter.name) || parameter.default_value,
|
38
|
+
class: "form__input",
|
39
|
+
step: parameter.parameter_type == 'decimal' ? '0.01' : '1' %>
|
40
|
+
<% when 'json', 'array' %>
|
41
|
+
<%= text_area_tag "test_case[input_variables][#{parameter.name}]",
|
42
|
+
@test_case.input_variables&.dig(parameter.name)&.to_json || parameter.default_value,
|
43
|
+
class: "form__input",
|
44
|
+
rows: 3,
|
45
|
+
placeholder: parameter.parameter_type == 'array' ? '["item1", "item2"]' : '{"key": "value"}' %>
|
46
|
+
<% else %>
|
47
|
+
<%= text_area_tag "test_case[input_variables][#{parameter.name}]",
|
48
|
+
@test_case.input_variables&.dig(parameter.name) || parameter.default_value,
|
49
|
+
class: "form__input",
|
50
|
+
rows: 2 %>
|
51
|
+
<% end %>
|
52
|
+
|
53
|
+
<% if parameter.description.present? %>
|
54
|
+
<p class="form__help"><%= parameter.description %></p>
|
55
|
+
<% end %>
|
56
|
+
</div>
|
57
|
+
<% end %>
|
58
|
+
</div>
|
59
|
+
|
60
|
+
<div class="form__group">
|
61
|
+
<%= form.label :expected_output, class: "form__label" %>
|
62
|
+
<span class="form__required">*</span>
|
63
|
+
<%= form.text_area :expected_output,
|
64
|
+
class: "form__input",
|
65
|
+
rows: 5,
|
66
|
+
required: true,
|
67
|
+
minlength: 1,
|
68
|
+
placeholder: "The exact output you expect the prompt to generate with these inputs" %>
|
69
|
+
<p class="form__help">The expected output will be compared exactly with the actual output</p>
|
70
|
+
</div>
|
71
|
+
|
72
|
+
<div class="form__actions">
|
73
|
+
<%= form.submit "Create Test Case", class: "btn btn--primary btn--medium",
|
74
|
+
data: { disable_with: "Creating..." } %>
|
75
|
+
<%= link_to "Cancel", prompt_eval_set_path(@prompt, @eval_set), class: "btn btn--secondary btn--medium" %>
|
76
|
+
</div>
|
77
|
+
<% end %>
|
78
|
+
</div>
|
79
|
+
</div>
|
@@ -0,0 +1,56 @@
|
|
1
|
+
<div class="version-card">
|
2
|
+
<div class="version-card__header">
|
3
|
+
<div class="version-card__header-main">
|
4
|
+
<h3 class="version-card__title">
|
5
|
+
Version <%= version.version_number %>
|
6
|
+
<% if version.version_number == prompt.versions.maximum(:version_number) %>
|
7
|
+
<span class="badge badge--primary">Current</span>
|
8
|
+
<% end %>
|
9
|
+
</h3>
|
10
|
+
<p class="version-card__summary">
|
11
|
+
<%= version.change_description.presence || "No summary provided" %>
|
12
|
+
</p>
|
13
|
+
</div>
|
14
|
+
<div class="version-card__header-actions">
|
15
|
+
<%= link_to "View", prompt_version_path(prompt, version), class: "button button--small button--secondary" %>
|
16
|
+
<% unless version.version_number == prompt.versions.maximum(:version_number) %>
|
17
|
+
<%= link_to "Compare", compare_prompt_version_path(prompt, version), class: "button button--small button--secondary" %>
|
18
|
+
<%= button_to "Restore", restore_prompt_version_path(prompt, version),
|
19
|
+
method: :post,
|
20
|
+
class: "button button--small button--secondary",
|
21
|
+
data: { turbo_confirm: "Are you sure you want to restore this version?" } %>
|
22
|
+
<% end %>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
<div class="version-card__metadata">
|
27
|
+
<div class="version-card__metadata-item">
|
28
|
+
<span class="version-card__metadata-label">Created</span>
|
29
|
+
<span class="version-card__metadata-value">
|
30
|
+
<%= version.created_at.strftime("%b %d, %Y at %I:%M %p") %>
|
31
|
+
</span>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<div class="version-card__metadata-item">
|
35
|
+
<span class="version-card__metadata-label">Model</span>
|
36
|
+
<span class="version-card__metadata-value"><%= version.model %></span>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
<div class="version-card__metadata-item">
|
40
|
+
<span class="version-card__metadata-label">Temperature</span>
|
41
|
+
<span class="version-card__metadata-value"><%= version.temperature %></span>
|
42
|
+
</div>
|
43
|
+
|
44
|
+
<div class="version-card__metadata-item">
|
45
|
+
<span class="version-card__metadata-label">Max Tokens</span>
|
46
|
+
<span class="version-card__metadata-value"><%= version.max_tokens || "Default" %></span>
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
|
50
|
+
<% if show_preview && version.content.present? %>
|
51
|
+
<div class="version-card__preview">
|
52
|
+
<span class="version-card__preview-label">Content Preview:</span>
|
53
|
+
<pre class="version-card__preview-content"><%= truncate(version.content, length: 200) %></pre>
|
54
|
+
</div>
|
55
|
+
<% end %>
|
56
|
+
</div>
|
@@ -0,0 +1,82 @@
|
|
1
|
+
<% content_for :page_title, "Compare Versions" %>
|
2
|
+
<% content_for :page_subtitle, @prompt.name %>
|
3
|
+
|
4
|
+
<div class="page-header">
|
5
|
+
<div class="page-header__content">
|
6
|
+
<h1 class="page-header__title">Compare Versions</h1>
|
7
|
+
<p class="page-header__subtitle">
|
8
|
+
Version <%= @version_a.version_number %> → Version <%= @version_b.version_number %>
|
9
|
+
</p>
|
10
|
+
</div>
|
11
|
+
<div class="page-header__actions">
|
12
|
+
<%= link_to "Back to History", prompt_versions_path(@prompt), class: "button button--secondary" %>
|
13
|
+
<%= link_to "Back to Prompt", @prompt, class: "button button--secondary" %>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<div class="version-compare">
|
18
|
+
<div class="version-compare__header">
|
19
|
+
<div class="version-compare__version version-compare__version--old">
|
20
|
+
<h3>Version <%= @version_a.version_number %></h3>
|
21
|
+
<p class="text-muted"><%= @version_a.created_at.strftime("%B %d, %Y at %I:%M %p") %></p>
|
22
|
+
</div>
|
23
|
+
<div class="version-compare__arrow">→</div>
|
24
|
+
<div class="version-compare__version version-compare__version--new">
|
25
|
+
<h3>Version <%= @version_b.version_number %></h3>
|
26
|
+
<p class="text-muted"><%= @version_b.created_at.strftime("%B %d, %Y at %I:%M %p") %></p>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<% @changes.each do |field, change| %>
|
31
|
+
<% if change[:changed] %>
|
32
|
+
<div class="card version-compare__section">
|
33
|
+
<div class="card__header">
|
34
|
+
<h2 class="card__title"><%= field.to_s.humanize %></h2>
|
35
|
+
</div>
|
36
|
+
<div class="card__content">
|
37
|
+
<div class="version-compare__diff">
|
38
|
+
<div class="version-compare__diff-side version-compare__diff-side--old">
|
39
|
+
<div class="version-compare__diff-label">Old Value</div>
|
40
|
+
<% if field == :content || field == :system_message %>
|
41
|
+
<pre class="version-compare__diff-content version-compare__diff-content--old"><%= change[:old].presence || "(empty)" %></pre>
|
42
|
+
<% else %>
|
43
|
+
<div class="version-compare__diff-value version-compare__diff-value--old">
|
44
|
+
<%= change[:old].presence || "(not set)" %>
|
45
|
+
</div>
|
46
|
+
<% end %>
|
47
|
+
</div>
|
48
|
+
|
49
|
+
<div class="version-compare__diff-side version-compare__diff-side--new">
|
50
|
+
<div class="version-compare__diff-label">New Value</div>
|
51
|
+
<% if field == :content || field == :system_message %>
|
52
|
+
<pre class="version-compare__diff-content version-compare__diff-content--new"><%= change[:new].presence || "(empty)" %></pre>
|
53
|
+
<% else %>
|
54
|
+
<div class="version-compare__diff-value version-compare__diff-value--new">
|
55
|
+
<%= change[:new].presence || "(not set)" %>
|
56
|
+
</div>
|
57
|
+
<% end %>
|
58
|
+
</div>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
</div>
|
62
|
+
<% end %>
|
63
|
+
<% end %>
|
64
|
+
|
65
|
+
<div class="card">
|
66
|
+
<div class="card__header">
|
67
|
+
<h2 class="card__title">Change Description</h2>
|
68
|
+
</div>
|
69
|
+
<div class="card__content">
|
70
|
+
<div class="version-compare__summary">
|
71
|
+
<div class="version-compare__summary-item">
|
72
|
+
<strong>Version <%= @version_a.version_number %> Summary:</strong>
|
73
|
+
<%= @version_a.change_description.presence || content_tag(:em, "No summary provided", class: "text-muted") %>
|
74
|
+
</div>
|
75
|
+
<div class="version-compare__summary-item">
|
76
|
+
<strong>Version <%= @version_b.version_number %> Summary:</strong>
|
77
|
+
<%= @version_b.change_description.presence || content_tag(:em, "No summary provided", class: "text-muted") %>
|
78
|
+
</div>
|
79
|
+
</div>
|
80
|
+
</div>
|
81
|
+
</div>
|
82
|
+
</div>
|
@@ -0,0 +1,96 @@
|
|
1
|
+
<% content_for :page_title, "Version History" %>
|
2
|
+
<% content_for :page_subtitle, @prompt.name %>
|
3
|
+
|
4
|
+
<div class="page-header">
|
5
|
+
<div class="page-header__content">
|
6
|
+
<h1 class="page-header__title">Version History</h1>
|
7
|
+
<p class="page-header__subtitle"><%= @prompt.name %></p>
|
8
|
+
</div>
|
9
|
+
<div class="page-header__actions">
|
10
|
+
<%= link_to "Back to Prompt", @prompt, class: "button button--secondary" %>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<div class="versions-timeline">
|
15
|
+
<% if @versions.any? %>
|
16
|
+
<% @versions.each_with_index do |version, index| %>
|
17
|
+
<div class="version-item <%= 'version-item--current' if index == 0 %>">
|
18
|
+
<div class="version-item__marker">
|
19
|
+
<div class="version-item__marker-dot"></div>
|
20
|
+
<% if index < @versions.length - 1 %>
|
21
|
+
<div class="version-item__marker-line"></div>
|
22
|
+
<% end %>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<div class="version-item__content">
|
26
|
+
<div class="version-card">
|
27
|
+
<div class="version-card__header">
|
28
|
+
<div class="version-card__header-main">
|
29
|
+
<h3 class="version-card__title">
|
30
|
+
Version <%= version.version_number %>
|
31
|
+
<% if index == 0 %>
|
32
|
+
<span class="badge badge--primary">Current</span>
|
33
|
+
<% end %>
|
34
|
+
</h3>
|
35
|
+
<p class="version-card__summary">
|
36
|
+
<%= version.change_description.presence || "No summary provided" %>
|
37
|
+
</p>
|
38
|
+
</div>
|
39
|
+
<div class="version-card__header-actions">
|
40
|
+
<%= link_to "View", prompt_version_path(@prompt, version), class: "button button--small button--secondary" %>
|
41
|
+
<% if index > 0 %>
|
42
|
+
<%= link_to "Compare", compare_prompt_version_path(@prompt, version), class: "button button--small button--secondary" %>
|
43
|
+
<%= button_to "Restore", restore_prompt_version_path(@prompt, version),
|
44
|
+
method: :post,
|
45
|
+
class: "button button--small button--secondary",
|
46
|
+
data: { turbo_confirm: "Are you sure you want to restore this version?" } %>
|
47
|
+
<% end %>
|
48
|
+
</div>
|
49
|
+
</div>
|
50
|
+
|
51
|
+
<div class="version-card__metadata">
|
52
|
+
<div class="version-card__metadata-item">
|
53
|
+
<span class="version-card__metadata-label">Created</span>
|
54
|
+
<span class="version-card__metadata-value">
|
55
|
+
<%= version.created_at.strftime("%b %d, %Y at %I:%M %p") %>
|
56
|
+
</span>
|
57
|
+
</div>
|
58
|
+
|
59
|
+
<div class="version-card__metadata-item">
|
60
|
+
<span class="version-card__metadata-label">Model</span>
|
61
|
+
<span class="version-card__metadata-value"><%= version.model %></span>
|
62
|
+
</div>
|
63
|
+
|
64
|
+
<div class="version-card__metadata-item">
|
65
|
+
<span class="version-card__metadata-label">Temperature</span>
|
66
|
+
<span class="version-card__metadata-value"><%= version.temperature %></span>
|
67
|
+
</div>
|
68
|
+
|
69
|
+
<div class="version-card__metadata-item">
|
70
|
+
<span class="version-card__metadata-label">Max Tokens</span>
|
71
|
+
<span class="version-card__metadata-value"><%= version.max_tokens || "Default" %></span>
|
72
|
+
</div>
|
73
|
+
</div>
|
74
|
+
|
75
|
+
<% if version.content.present? %>
|
76
|
+
<div class="version-card__preview">
|
77
|
+
<span class="version-card__preview-label">Content Preview:</span>
|
78
|
+
<pre class="version-card__preview-content"><%= truncate(version.content, length: 200) %></pre>
|
79
|
+
</div>
|
80
|
+
<% end %>
|
81
|
+
</div>
|
82
|
+
</div>
|
83
|
+
</div>
|
84
|
+
<% end %>
|
85
|
+
<% else %>
|
86
|
+
<div class="empty-state">
|
87
|
+
<div class="empty-state__icon">
|
88
|
+
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
89
|
+
<path d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
90
|
+
</svg>
|
91
|
+
</div>
|
92
|
+
<h3 class="empty-state__title">No version history</h3>
|
93
|
+
<p class="empty-state__description">This prompt doesn't have any previous versions yet.</p>
|
94
|
+
</div>
|
95
|
+
<% end %>
|
96
|
+
</div>
|
@@ -0,0 +1,98 @@
|
|
1
|
+
<% content_for :page_title, "Version #{@version.version_number}" %>
|
2
|
+
<% content_for :page_subtitle, @prompt.name %>
|
3
|
+
|
4
|
+
<div class="page-header">
|
5
|
+
<div class="page-header__content">
|
6
|
+
<h1 class="page-header__title">Version <%= @version.version_number %></h1>
|
7
|
+
<p class="page-header__subtitle"><%= @prompt.name %></p>
|
8
|
+
</div>
|
9
|
+
<div class="page-header__actions">
|
10
|
+
<%= link_to "Test Run History", prompt_version_playground_run_results_path(@prompt, @version), class: "button button--secondary" %>
|
11
|
+
<%= link_to "Back to History", prompt_versions_path(@prompt), class: "button button--secondary" %>
|
12
|
+
<%= link_to "Back to Prompt", @prompt, class: "button button--secondary" %>
|
13
|
+
<% unless @version.version_number == @prompt.versions.maximum(:version_number) %>
|
14
|
+
<%= button_to "Restore This Version", restore_prompt_version_path(@prompt, @version),
|
15
|
+
method: :post,
|
16
|
+
class: "button button--primary",
|
17
|
+
data: { turbo_confirm: "Are you sure you want to restore this version?" } %>
|
18
|
+
<% end %>
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<div class="version-details">
|
23
|
+
<div class="card">
|
24
|
+
<div class="card__header">
|
25
|
+
<h2 class="card__title">Version Information</h2>
|
26
|
+
</div>
|
27
|
+
<div class="card__content">
|
28
|
+
<dl class="metadata-list">
|
29
|
+
<div class="metadata-list__item">
|
30
|
+
<dt class="metadata-list__label">Version Number</dt>
|
31
|
+
<dd class="metadata-list__value"><%= @version.version_number %></dd>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<div class="metadata-list__item">
|
35
|
+
<dt class="metadata-list__label">Created At</dt>
|
36
|
+
<dd class="metadata-list__value"><%= @version.created_at.strftime("%B %d, %Y at %I:%M %p") %></dd>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
<div class="metadata-list__item">
|
40
|
+
<dt class="metadata-list__label">Change Description</dt>
|
41
|
+
<dd class="metadata-list__value">
|
42
|
+
<%= @version.change_description.presence || content_tag(:em, "No summary provided", class: "text-muted") %>
|
43
|
+
</dd>
|
44
|
+
</div>
|
45
|
+
</dl>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
|
49
|
+
<div class="card">
|
50
|
+
<div class="card__header">
|
51
|
+
<h2 class="card__title">Prompt Content</h2>
|
52
|
+
</div>
|
53
|
+
<div class="card__content">
|
54
|
+
<% if @version.content.present? %>
|
55
|
+
<pre class="prompt-content"><%= @version.content %></pre>
|
56
|
+
<% else %>
|
57
|
+
<p class="text-muted">No content provided</p>
|
58
|
+
<% end %>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div class="card">
|
63
|
+
<div class="card__header">
|
64
|
+
<h2 class="card__title">System Message</h2>
|
65
|
+
</div>
|
66
|
+
<div class="card__content">
|
67
|
+
<% if @version.system_message.present? %>
|
68
|
+
<pre class="prompt-content"><%= @version.system_message %></pre>
|
69
|
+
<% else %>
|
70
|
+
<p class="text-muted">No system message provided</p>
|
71
|
+
<% end %>
|
72
|
+
</div>
|
73
|
+
</div>
|
74
|
+
|
75
|
+
<div class="card">
|
76
|
+
<div class="card__header">
|
77
|
+
<h2 class="card__title">Model Settings</h2>
|
78
|
+
</div>
|
79
|
+
<div class="card__content">
|
80
|
+
<dl class="metadata-list">
|
81
|
+
<div class="metadata-list__item">
|
82
|
+
<dt class="metadata-list__label">Model</dt>
|
83
|
+
<dd class="metadata-list__value"><%= @version.model %></dd>
|
84
|
+
</div>
|
85
|
+
|
86
|
+
<div class="metadata-list__item">
|
87
|
+
<dt class="metadata-list__label">Temperature</dt>
|
88
|
+
<dd class="metadata-list__value"><%= @version.temperature %></dd>
|
89
|
+
</div>
|
90
|
+
|
91
|
+
<div class="metadata-list__item">
|
92
|
+
<dt class="metadata-list__label">Max Tokens</dt>
|
93
|
+
<dd class="metadata-list__value"><%= @version.max_tokens || "Default" %></dd>
|
94
|
+
</div>
|
95
|
+
</dl>
|
96
|
+
</div>
|
97
|
+
</div>
|
98
|
+
</div>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
PromptEngine::Engine.routes.draw do
|
2
|
+
root to: "dashboard#index"
|
3
|
+
|
4
|
+
get "dashboard", to: "dashboard#index", as: :dashboard
|
5
|
+
|
6
|
+
resources :prompts do
|
7
|
+
member do
|
8
|
+
post :test
|
9
|
+
post :duplicate
|
10
|
+
get :playground, to: "playground#show"
|
11
|
+
post :playground, to: "playground#execute"
|
12
|
+
end
|
13
|
+
collection do
|
14
|
+
get :search
|
15
|
+
end
|
16
|
+
|
17
|
+
resources :versions, only: [ :index, :show ] do
|
18
|
+
member do
|
19
|
+
post :restore
|
20
|
+
get :compare
|
21
|
+
end
|
22
|
+
resources :playground_run_results, only: [ :index ]
|
23
|
+
end
|
24
|
+
|
25
|
+
resources :playground_run_results, only: [ :index ]
|
26
|
+
|
27
|
+
resources :eval_sets do
|
28
|
+
member do
|
29
|
+
post :run
|
30
|
+
get :compare
|
31
|
+
get :metrics
|
32
|
+
end
|
33
|
+
resources :test_cases, except: [ :index, :show ] do
|
34
|
+
collection do
|
35
|
+
get :import
|
36
|
+
post :import_preview
|
37
|
+
post :import_create
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
resources :eval_runs, only: [ :show ]
|
42
|
+
end
|
43
|
+
|
44
|
+
resources :playground_run_results, only: [ :index, :show ]
|
45
|
+
|
46
|
+
resource :settings, only: [ :edit, :update ]
|
47
|
+
|
48
|
+
# Evaluations index - shows all eval sets across all prompts
|
49
|
+
get "evaluations", to: "evaluations#index", as: :evaluations
|
50
|
+
|
51
|
+
# API endpoints for integration
|
52
|
+
namespace :api do
|
53
|
+
namespace :v1 do
|
54
|
+
resources :prompts, only: [ :index, :show ] do
|
55
|
+
member do
|
56
|
+
post :execute
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class CreateEvalTables < ActiveRecord::Migration[7.1]
|
2
|
+
def change
|
3
|
+
create_table :prompt_engine_eval_sets do |t|
|
4
|
+
t.string :name, null: false
|
5
|
+
t.text :description
|
6
|
+
t.references :prompt, null: false, foreign_key: { to_table: :prompt_engine_prompts }
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table :prompt_engine_test_cases do |t|
|
11
|
+
t.references :eval_set, null: false, foreign_key: { to_table: :prompt_engine_eval_sets }
|
12
|
+
t.json :input_variables, null: false, default: {}
|
13
|
+
t.text :expected_output, null: false
|
14
|
+
t.text :description
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
|
18
|
+
create_table :prompt_engine_eval_runs do |t|
|
19
|
+
t.references :eval_set, null: false, foreign_key: { to_table: :prompt_engine_eval_sets }
|
20
|
+
t.references :prompt_version, null: false, foreign_key: { to_table: :prompt_engine_prompt_versions }
|
21
|
+
t.integer :status, default: 0, null: false
|
22
|
+
t.datetime :started_at
|
23
|
+
t.datetime :completed_at
|
24
|
+
t.integer :total_count, default: 0
|
25
|
+
t.integer :passed_count, default: 0
|
26
|
+
t.integer :failed_count, default: 0
|
27
|
+
t.text :error_message
|
28
|
+
t.timestamps
|
29
|
+
end
|
30
|
+
|
31
|
+
create_table :prompt_engine_eval_results do |t|
|
32
|
+
t.references :eval_run, null: false, foreign_key: { to_table: :prompt_engine_eval_runs }
|
33
|
+
t.references :test_case, null: false, foreign_key: { to_table: :prompt_engine_test_cases }
|
34
|
+
t.text :actual_output
|
35
|
+
t.boolean :passed, default: false
|
36
|
+
t.integer :execution_time_ms
|
37
|
+
t.text :error_message
|
38
|
+
t.timestamps
|
39
|
+
end
|
40
|
+
|
41
|
+
add_index :prompt_engine_eval_sets, [ :prompt_id, :name ], unique: true
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class AddOpenAiFieldsToEvals < ActiveRecord::Migration[7.1]
|
2
|
+
def change
|
3
|
+
add_column :prompt_engine_eval_sets, :openai_eval_id, :string
|
4
|
+
add_column :prompt_engine_eval_runs, :openai_run_id, :string
|
5
|
+
add_column :prompt_engine_eval_runs, :openai_file_id, :string
|
6
|
+
add_column :prompt_engine_eval_runs, :report_url, :string
|
7
|
+
|
8
|
+
add_index :prompt_engine_eval_sets, :openai_eval_id
|
9
|
+
add_index :prompt_engine_eval_runs, :openai_run_id
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class AddGraderFieldsToEvalSets < ActiveRecord::Migration[7.1]
|
2
|
+
def change
|
3
|
+
add_column :prompt_engine_eval_sets, :grader_type, :string, default: 'exact_match', null: false
|
4
|
+
add_column :prompt_engine_eval_sets, :grader_config, :json, default: {}
|
5
|
+
|
6
|
+
add_index :prompt_engine_eval_sets, :grader_type
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class CreatePrompts < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :prompt_engine_prompts do |t|
|
4
|
+
t.string :name
|
5
|
+
t.text :description
|
6
|
+
t.text :content
|
7
|
+
t.text :system_message
|
8
|
+
t.string :model
|
9
|
+
t.float :temperature
|
10
|
+
t.integer :max_tokens
|
11
|
+
t.string :status
|
12
|
+
t.json :metadata
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class CreatePromptEngineVersions < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :prompt_engine_prompt_versions do |t|
|
4
|
+
t.references :prompt, null: false, foreign_key: { to_table: :prompt_engine_prompts }
|
5
|
+
t.integer :version_number, null: false
|
6
|
+
t.text :content, null: false
|
7
|
+
t.text :system_message
|
8
|
+
t.string :model
|
9
|
+
t.float :temperature
|
10
|
+
t.integer :max_tokens
|
11
|
+
t.json :metadata
|
12
|
+
t.string :created_by
|
13
|
+
t.text :change_description
|
14
|
+
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
|
18
|
+
add_index :prompt_engine_prompt_versions, [ :prompt_id, :version_number ], unique: true, name: 'index_prompt_versions_on_prompt_and_version'
|
19
|
+
add_index :prompt_engine_prompt_versions, :version_number
|
20
|
+
|
21
|
+
# Add version_count counter cache to prompts table
|
22
|
+
add_column :prompt_engine_prompts, :versions_count, :integer, default: 0, null: false
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class CreatePromptEngineParameters < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :prompt_engine_parameters do |t|
|
4
|
+
t.references :prompt, null: false, foreign_key: { to_table: :prompt_engine_prompts }
|
5
|
+
t.string :name, null: false
|
6
|
+
t.text :description
|
7
|
+
t.string :parameter_type, null: false, default: 'string'
|
8
|
+
t.boolean :required, null: false, default: true
|
9
|
+
t.string :default_value
|
10
|
+
t.json :validation_rules
|
11
|
+
t.string :example_value
|
12
|
+
t.integer :position
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
|
17
|
+
add_index :prompt_engine_parameters, [ :prompt_id, :name ], unique: true
|
18
|
+
add_index :prompt_engine_parameters, :position
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class CreatePromptEnginePlaygroundRunResults < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :prompt_engine_playground_run_results do |t|
|
4
|
+
t.references :prompt_version, null: false, foreign_key: { to_table: :prompt_engine_prompt_versions }
|
5
|
+
|
6
|
+
# API Provider and Model Info
|
7
|
+
t.string :provider, null: false
|
8
|
+
t.string :model, null: false
|
9
|
+
|
10
|
+
# Prompt Details
|
11
|
+
t.text :rendered_prompt, null: false
|
12
|
+
t.text :system_message
|
13
|
+
t.text :parameters
|
14
|
+
|
15
|
+
# Response Details
|
16
|
+
t.text :response, null: false
|
17
|
+
t.float :execution_time, null: false
|
18
|
+
t.integer :token_count
|
19
|
+
|
20
|
+
# Settings Used
|
21
|
+
t.float :temperature
|
22
|
+
t.integer :max_tokens
|
23
|
+
|
24
|
+
t.timestamps
|
25
|
+
end
|
26
|
+
|
27
|
+
add_index :prompt_engine_playground_run_results, :provider
|
28
|
+
add_index :prompt_engine_playground_run_results, :created_at
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreatePromptEngineSettings < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :prompt_engine_settings do |t|
|
4
|
+
# Encrypted API keys
|
5
|
+
t.text :openai_api_key
|
6
|
+
t.text :anthropic_api_key
|
7
|
+
|
8
|
+
# Other settings can be added here in the future
|
9
|
+
t.json :preferences, default: {}
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|