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.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +67 -0
  4. data/Rakefile +22 -0
  5. data/app/assets/stylesheets/prompt_engine/application.css +22 -0
  6. data/app/assets/stylesheets/prompt_engine/buttons.css +124 -0
  7. data/app/assets/stylesheets/prompt_engine/cards.css +63 -0
  8. data/app/assets/stylesheets/prompt_engine/comparison.css +244 -0
  9. data/app/assets/stylesheets/prompt_engine/components/_test_runs.css +144 -0
  10. data/app/assets/stylesheets/prompt_engine/dashboard.css +343 -0
  11. data/app/assets/stylesheets/prompt_engine/evaluations.css +124 -0
  12. data/app/assets/stylesheets/prompt_engine/forms.css +198 -0
  13. data/app/assets/stylesheets/prompt_engine/foundation.css +182 -0
  14. data/app/assets/stylesheets/prompt_engine/layout.css +75 -0
  15. data/app/assets/stylesheets/prompt_engine/loading.css +229 -0
  16. data/app/assets/stylesheets/prompt_engine/notifications.css +78 -0
  17. data/app/assets/stylesheets/prompt_engine/overrides.css +42 -0
  18. data/app/assets/stylesheets/prompt_engine/prompts.css +237 -0
  19. data/app/assets/stylesheets/prompt_engine/sidebar.css +90 -0
  20. data/app/assets/stylesheets/prompt_engine/tables.css +250 -0
  21. data/app/assets/stylesheets/prompt_engine/utilities.css +52 -0
  22. data/app/assets/stylesheets/prompt_engine/versions.css +370 -0
  23. data/app/clients/prompt_engine/open_ai_evals_client.rb +135 -0
  24. data/app/controllers/prompt_engine/admin/base_controller.rb +7 -0
  25. data/app/controllers/prompt_engine/application_controller.rb +4 -0
  26. data/app/controllers/prompt_engine/dashboard_controller.rb +24 -0
  27. data/app/controllers/prompt_engine/eval_runs_controller.rb +23 -0
  28. data/app/controllers/prompt_engine/eval_sets_controller.rb +200 -0
  29. data/app/controllers/prompt_engine/evaluations_controller.rb +32 -0
  30. data/app/controllers/prompt_engine/playground_controller.rb +57 -0
  31. data/app/controllers/prompt_engine/playground_run_results_controller.rb +41 -0
  32. data/app/controllers/prompt_engine/prompts_controller.rb +70 -0
  33. data/app/controllers/prompt_engine/settings_controller.rb +28 -0
  34. data/app/controllers/prompt_engine/test_cases_controller.rb +231 -0
  35. data/app/controllers/prompt_engine/versions_controller.rb +90 -0
  36. data/app/helpers/prompt_engine/application_helper.rb +4 -0
  37. data/app/jobs/prompt_engine/application_job.rb +4 -0
  38. data/app/mailers/prompt_engine/application_mailer.rb +6 -0
  39. data/app/models/prompt_engine/application_record.rb +5 -0
  40. data/app/models/prompt_engine/eval_result.rb +19 -0
  41. data/app/models/prompt_engine/eval_run.rb +40 -0
  42. data/app/models/prompt_engine/eval_set.rb +97 -0
  43. data/app/models/prompt_engine/parameter.rb +126 -0
  44. data/app/models/prompt_engine/parameter_parser.rb +39 -0
  45. data/app/models/prompt_engine/playground_run_result.rb +20 -0
  46. data/app/models/prompt_engine/prompt.rb +192 -0
  47. data/app/models/prompt_engine/prompt_version.rb +72 -0
  48. data/app/models/prompt_engine/setting.rb +45 -0
  49. data/app/models/prompt_engine/test_case.rb +29 -0
  50. data/app/services/prompt_engine/evaluation_runner.rb +258 -0
  51. data/app/services/prompt_engine/playground_executor.rb +124 -0
  52. data/app/services/prompt_engine/variable_detector.rb +97 -0
  53. data/app/views/layouts/prompt_engine/admin.html.erb +65 -0
  54. data/app/views/layouts/prompt_engine/application.html.erb +17 -0
  55. data/app/views/prompt_engine/dashboard/index.html.erb +230 -0
  56. data/app/views/prompt_engine/eval_runs/show.html.erb +204 -0
  57. data/app/views/prompt_engine/eval_sets/compare.html.erb +229 -0
  58. data/app/views/prompt_engine/eval_sets/edit.html.erb +111 -0
  59. data/app/views/prompt_engine/eval_sets/index.html.erb +63 -0
  60. data/app/views/prompt_engine/eval_sets/metrics.html.erb +371 -0
  61. data/app/views/prompt_engine/eval_sets/new.html.erb +113 -0
  62. data/app/views/prompt_engine/eval_sets/show.html.erb +235 -0
  63. data/app/views/prompt_engine/evaluations/index.html.erb +194 -0
  64. data/app/views/prompt_engine/playground/result.html.erb +58 -0
  65. data/app/views/prompt_engine/playground/show.html.erb +129 -0
  66. data/app/views/prompt_engine/playground_run_results/index.html.erb +99 -0
  67. data/app/views/prompt_engine/playground_run_results/show.html.erb +123 -0
  68. data/app/views/prompt_engine/prompts/_form.html.erb +224 -0
  69. data/app/views/prompt_engine/prompts/edit.html.erb +9 -0
  70. data/app/views/prompt_engine/prompts/index.html.erb +80 -0
  71. data/app/views/prompt_engine/prompts/new.html.erb +9 -0
  72. data/app/views/prompt_engine/prompts/show.html.erb +297 -0
  73. data/app/views/prompt_engine/settings/edit.html.erb +93 -0
  74. data/app/views/prompt_engine/shared/_form_errors.html.erb +16 -0
  75. data/app/views/prompt_engine/test_cases/edit.html.erb +72 -0
  76. data/app/views/prompt_engine/test_cases/import.html.erb +92 -0
  77. data/app/views/prompt_engine/test_cases/import_preview.html.erb +103 -0
  78. data/app/views/prompt_engine/test_cases/new.html.erb +79 -0
  79. data/app/views/prompt_engine/versions/_version_card.html.erb +56 -0
  80. data/app/views/prompt_engine/versions/compare.html.erb +82 -0
  81. data/app/views/prompt_engine/versions/index.html.erb +96 -0
  82. data/app/views/prompt_engine/versions/show.html.erb +98 -0
  83. data/config/routes.rb +61 -0
  84. data/db/migrate/20250124000001_create_eval_tables.rb +43 -0
  85. data/db/migrate/20250124000002_add_open_ai_fields_to_evals.rb +11 -0
  86. data/db/migrate/20250125000001_add_grader_fields_to_eval_sets.rb +8 -0
  87. data/db/migrate/20250723161909_create_prompts.rb +17 -0
  88. data/db/migrate/20250723184757_create_prompt_engine_versions.rb +24 -0
  89. data/db/migrate/20250723203838_create_prompt_engine_parameters.rb +20 -0
  90. data/db/migrate/20250724160623_create_prompt_engine_playground_run_results.rb +30 -0
  91. data/db/migrate/20250724165118_create_prompt_engine_settings.rb +14 -0
  92. data/lib/prompt_engine/engine.rb +25 -0
  93. data/lib/prompt_engine/version.rb +3 -0
  94. data/lib/prompt_engine.rb +33 -0
  95. data/lib/tasks/active_prompt_tasks.rake +32 -0
  96. data/lib/tasks/eval_demo.rake +149 -0
  97. 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