completion-kit 0.1.0.rc1
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 +192 -0
- data/Rakefile +12 -0
- data/app/assets/config/completion_kit_manifest.js +1 -0
- data/app/assets/config/manifest.js +3 -0
- data/app/assets/images/completion_kit/logo.svg +6 -0
- data/app/assets/javascripts/completion_kit/evaluation_steps_controller.js +25 -0
- data/app/assets/stylesheets/completion_kit/application.css +2214 -0
- data/app/controllers/completion_kit/api/v1/base_controller.rb +29 -0
- data/app/controllers/completion_kit/api/v1/criteria_controller.rb +62 -0
- data/app/controllers/completion_kit/api/v1/datasets_controller.rb +51 -0
- data/app/controllers/completion_kit/api/v1/metrics_controller.rb +51 -0
- data/app/controllers/completion_kit/api/v1/prompts_controller.rb +64 -0
- data/app/controllers/completion_kit/api/v1/provider_credentials_controller.rb +51 -0
- data/app/controllers/completion_kit/api/v1/responses_controller.rb +32 -0
- data/app/controllers/completion_kit/api/v1/runs_controller.rb +71 -0
- data/app/controllers/completion_kit/api_reference_controller.rb +9 -0
- data/app/controllers/completion_kit/application_controller.rb +31 -0
- data/app/controllers/completion_kit/criteria_controller.rb +67 -0
- data/app/controllers/completion_kit/datasets_controller.rb +53 -0
- data/app/controllers/completion_kit/mcp_controller.rb +57 -0
- data/app/controllers/completion_kit/metrics_controller.rb +52 -0
- data/app/controllers/completion_kit/prompts_controller.rb +69 -0
- data/app/controllers/completion_kit/provider_credentials_controller.rb +63 -0
- data/app/controllers/completion_kit/responses_controller.rb +44 -0
- data/app/controllers/completion_kit/runs_controller.rb +131 -0
- data/app/helpers/completion_kit/application_helper.rb +193 -0
- data/app/jobs/completion_kit/application_job.rb +4 -0
- data/app/jobs/completion_kit/generate_job.rb +12 -0
- data/app/jobs/completion_kit/judge_job.rb +12 -0
- data/app/jobs/completion_kit/model_discovery_job.rb +29 -0
- data/app/mailers/completion_kit/application_mailer.rb +6 -0
- data/app/models/completion_kit/application_record.rb +5 -0
- data/app/models/completion_kit/criteria.rb +22 -0
- data/app/models/completion_kit/criteria_membership.rb +20 -0
- data/app/models/completion_kit/dataset.rb +24 -0
- data/app/models/completion_kit/metric.rb +97 -0
- data/app/models/completion_kit/model.rb +13 -0
- data/app/models/completion_kit/prompt.rb +99 -0
- data/app/models/completion_kit/provider_credential.rb +114 -0
- data/app/models/completion_kit/response.rb +30 -0
- data/app/models/completion_kit/review.rb +28 -0
- data/app/models/completion_kit/run.rb +253 -0
- data/app/models/completion_kit/run_metric.rb +6 -0
- data/app/models/completion_kit/suggestion.rb +8 -0
- data/app/services/completion_kit/anthropic_client.rb +86 -0
- data/app/services/completion_kit/api_config.rb +80 -0
- data/app/services/completion_kit/csv_processor.rb +65 -0
- data/app/services/completion_kit/judge_service.rb +87 -0
- data/app/services/completion_kit/llm_client.rb +45 -0
- data/app/services/completion_kit/mcp_dispatcher.rb +53 -0
- data/app/services/completion_kit/mcp_tools/criteria.rb +106 -0
- data/app/services/completion_kit/mcp_tools/datasets.rb +90 -0
- data/app/services/completion_kit/mcp_tools/metrics.rb +98 -0
- data/app/services/completion_kit/mcp_tools/prompts.rb +112 -0
- data/app/services/completion_kit/mcp_tools/provider_credentials.rb +97 -0
- data/app/services/completion_kit/mcp_tools/responses.rb +45 -0
- data/app/services/completion_kit/mcp_tools/runs.rb +130 -0
- data/app/services/completion_kit/model_discovery_service.rb +223 -0
- data/app/services/completion_kit/ollama_client.rb +80 -0
- data/app/services/completion_kit/open_ai_client.rb +71 -0
- data/app/services/completion_kit/open_router_client.rb +69 -0
- data/app/services/completion_kit/prompt_improvement_service.rb +81 -0
- data/app/views/completion_kit/api_reference/_example.html.erb +6 -0
- data/app/views/completion_kit/api_reference/index.html.erb +308 -0
- data/app/views/completion_kit/criteria/_form.html.erb +46 -0
- data/app/views/completion_kit/criteria/edit.html.erb +14 -0
- data/app/views/completion_kit/criteria/index.html.erb +37 -0
- data/app/views/completion_kit/criteria/new.html.erb +13 -0
- data/app/views/completion_kit/criteria/show.html.erb +37 -0
- data/app/views/completion_kit/datasets/_form.html.erb +29 -0
- data/app/views/completion_kit/datasets/edit.html.erb +13 -0
- data/app/views/completion_kit/datasets/index.html.erb +38 -0
- data/app/views/completion_kit/datasets/new.html.erb +12 -0
- data/app/views/completion_kit/datasets/show.html.erb +45 -0
- data/app/views/completion_kit/metrics/_form.html.erb +72 -0
- data/app/views/completion_kit/metrics/edit.html.erb +13 -0
- data/app/views/completion_kit/metrics/index.html.erb +34 -0
- data/app/views/completion_kit/metrics/new.html.erb +12 -0
- data/app/views/completion_kit/metrics/show.html.erb +49 -0
- data/app/views/completion_kit/prompts/_form.html.erb +52 -0
- data/app/views/completion_kit/prompts/edit.html.erb +13 -0
- data/app/views/completion_kit/prompts/index.html.erb +46 -0
- data/app/views/completion_kit/prompts/new.html.erb +12 -0
- data/app/views/completion_kit/prompts/show.html.erb +156 -0
- data/app/views/completion_kit/provider_credentials/_discovery_status.html.erb +30 -0
- data/app/views/completion_kit/provider_credentials/_form.html.erb +71 -0
- data/app/views/completion_kit/provider_credentials/edit.html.erb +12 -0
- data/app/views/completion_kit/provider_credentials/index.html.erb +41 -0
- data/app/views/completion_kit/provider_credentials/new.html.erb +12 -0
- data/app/views/completion_kit/responses/show.html.erb +87 -0
- data/app/views/completion_kit/runs/_actions.html.erb +14 -0
- data/app/views/completion_kit/runs/_form.html.erb +159 -0
- data/app/views/completion_kit/runs/_progress.html.erb +18 -0
- data/app/views/completion_kit/runs/_response_row.html.erb +13 -0
- data/app/views/completion_kit/runs/_sort_toolbar.html.erb +8 -0
- data/app/views/completion_kit/runs/_status_header.html.erb +15 -0
- data/app/views/completion_kit/runs/edit.html.erb +14 -0
- data/app/views/completion_kit/runs/index.html.erb +43 -0
- data/app/views/completion_kit/runs/new.html.erb +12 -0
- data/app/views/completion_kit/runs/show.html.erb +79 -0
- data/app/views/completion_kit/runs/suggestion.html.erb +47 -0
- data/app/views/layouts/completion_kit/application.html.erb +77 -0
- data/config/routes.rb +55 -0
- data/db/migrate/20260311000001_create_completion_kit_tables.rb +87 -0
- data/db/migrate/20260326000001_rename_criteria_to_instruction_on_metrics_and_reviews.rb +6 -0
- data/db/migrate/20260327000001_add_progress_to_runs.rb +6 -0
- data/db/migrate/20260327100001_replace_criteria_with_direct_metrics_on_runs.rb +12 -0
- data/db/migrate/20260328000001_add_error_message_to_runs.rb +5 -0
- data/db/migrate/20260329000001_create_completion_kit_models.rb +20 -0
- data/db/migrate/20260401170001_add_discovery_columns_to_completion_kit_provider_credentials.rb +7 -0
- data/db/migrate/20260403000001_add_temperature_to_completion_kit_runs.rb +5 -0
- data/db/migrate/20260403000002_create_completion_kit_suggestions.rb +13 -0
- data/db/migrate/20260403000003_add_applied_at_to_completion_kit_suggestions.rb +5 -0
- data/lib/completion-kit.rb +1 -0
- data/lib/completion_kit/engine.rb +35 -0
- data/lib/completion_kit/version.rb +3 -0
- data/lib/completion_kit.rb +55 -0
- data/lib/generators/completion_kit/install_generator.rb +21 -0
- data/lib/generators/completion_kit/templates/README +20 -0
- data/lib/generators/completion_kit/templates/initializer.rb +43 -0
- metadata +361 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
module Api
|
|
3
|
+
module V1
|
|
4
|
+
class BaseController < ActionController::API
|
|
5
|
+
before_action :authenticate_api!
|
|
6
|
+
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def authenticate_api!
|
|
10
|
+
token = CompletionKit.config.api_token
|
|
11
|
+
unless token
|
|
12
|
+
render json: {error: "API token not configured"}, status: :unauthorized
|
|
13
|
+
return
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
provided = request.headers["Authorization"]&.match(/\ABearer (.+)\z/)&.[](1)
|
|
17
|
+
unless provided && ActiveSupport::SecurityUtils.secure_compare(provided, token)
|
|
18
|
+
render json: {error: "Unauthorized"}, status: :unauthorized
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def not_found
|
|
23
|
+
render json: {error: "Record not found"}, status: :not_found
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
module Api
|
|
3
|
+
module V1
|
|
4
|
+
class CriteriaController < BaseController
|
|
5
|
+
before_action :set_criteria, only: [:show, :update, :destroy]
|
|
6
|
+
|
|
7
|
+
def index
|
|
8
|
+
render json: Criteria.order(created_at: :desc)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def show
|
|
12
|
+
render json: @criteria
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create
|
|
16
|
+
criteria = Criteria.new(criteria_params.except(:metric_ids))
|
|
17
|
+
if criteria.save
|
|
18
|
+
replace_metric_memberships(criteria, params[:metric_ids]) if params.key?(:metric_ids)
|
|
19
|
+
render json: criteria.reload, status: :created
|
|
20
|
+
else
|
|
21
|
+
render json: {errors: criteria.errors}, status: :unprocessable_entity
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def update
|
|
26
|
+
if @criteria.update(criteria_params.except(:metric_ids))
|
|
27
|
+
replace_metric_memberships(@criteria, params[:metric_ids]) if params.key?(:metric_ids)
|
|
28
|
+
render json: @criteria.reload
|
|
29
|
+
else
|
|
30
|
+
render json: {errors: @criteria.errors}, status: :unprocessable_entity
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def destroy
|
|
35
|
+
@criteria.destroy!
|
|
36
|
+
head :no_content
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def set_criteria
|
|
42
|
+
@criteria = Criteria.find(params[:id])
|
|
43
|
+
rescue ActiveRecord::RecordNotFound
|
|
44
|
+
not_found
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def criteria_params
|
|
48
|
+
params.permit(:name, :description, metric_ids: [])
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def replace_metric_memberships(criteria, metric_ids)
|
|
52
|
+
return unless metric_ids
|
|
53
|
+
|
|
54
|
+
criteria.criteria_memberships.delete_all
|
|
55
|
+
Array(metric_ids).reject(&:blank?).each_with_index do |metric_id, index|
|
|
56
|
+
criteria.criteria_memberships.create!(metric_id: metric_id, position: index + 1)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
module Api
|
|
3
|
+
module V1
|
|
4
|
+
class DatasetsController < BaseController
|
|
5
|
+
before_action :set_dataset, only: [:show, :update, :destroy]
|
|
6
|
+
|
|
7
|
+
def index
|
|
8
|
+
render json: Dataset.order(created_at: :desc)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def show
|
|
12
|
+
render json: @dataset
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create
|
|
16
|
+
dataset = Dataset.new(dataset_params)
|
|
17
|
+
if dataset.save
|
|
18
|
+
render json: dataset, status: :created
|
|
19
|
+
else
|
|
20
|
+
render json: {errors: dataset.errors}, status: :unprocessable_entity
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def update
|
|
25
|
+
if @dataset.update(dataset_params)
|
|
26
|
+
render json: @dataset
|
|
27
|
+
else
|
|
28
|
+
render json: {errors: @dataset.errors}, status: :unprocessable_entity
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def destroy
|
|
33
|
+
@dataset.destroy!
|
|
34
|
+
head :no_content
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def set_dataset
|
|
40
|
+
@dataset = Dataset.find(params[:id])
|
|
41
|
+
rescue ActiveRecord::RecordNotFound
|
|
42
|
+
not_found
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def dataset_params
|
|
46
|
+
params.permit(:name, :csv_data)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
module Api
|
|
3
|
+
module V1
|
|
4
|
+
class MetricsController < BaseController
|
|
5
|
+
before_action :set_metric, only: [:show, :update, :destroy]
|
|
6
|
+
|
|
7
|
+
def index
|
|
8
|
+
render json: Metric.order(created_at: :desc)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def show
|
|
12
|
+
render json: @metric
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create
|
|
16
|
+
metric = Metric.new(metric_params)
|
|
17
|
+
if metric.save
|
|
18
|
+
render json: metric, status: :created
|
|
19
|
+
else
|
|
20
|
+
render json: {errors: metric.errors}, status: :unprocessable_entity
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def update
|
|
25
|
+
if @metric.update(metric_params)
|
|
26
|
+
render json: @metric
|
|
27
|
+
else
|
|
28
|
+
render json: {errors: @metric.errors}, status: :unprocessable_entity
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def destroy
|
|
33
|
+
@metric.destroy!
|
|
34
|
+
head :no_content
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def set_metric
|
|
40
|
+
@metric = Metric.find(params[:id])
|
|
41
|
+
rescue ActiveRecord::RecordNotFound
|
|
42
|
+
not_found
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def metric_params
|
|
46
|
+
params.permit(:name, :instruction, evaluation_steps: [], rubric_bands: [:stars, :description])
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
module Api
|
|
3
|
+
module V1
|
|
4
|
+
class PromptsController < BaseController
|
|
5
|
+
before_action :set_prompt, only: [:show, :update, :destroy, :publish]
|
|
6
|
+
|
|
7
|
+
def index
|
|
8
|
+
render json: Prompt.order(created_at: :desc)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def show
|
|
12
|
+
render json: @prompt
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create
|
|
16
|
+
prompt = Prompt.new(prompt_params)
|
|
17
|
+
if prompt.save
|
|
18
|
+
render json: prompt, status: :created
|
|
19
|
+
else
|
|
20
|
+
render json: {errors: prompt.errors}, status: :unprocessable_entity
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def update
|
|
25
|
+
if @prompt.runs.exists?
|
|
26
|
+
new_prompt = @prompt.clone_as_new_version(prompt_params.to_h)
|
|
27
|
+
new_prompt.publish!
|
|
28
|
+
render json: new_prompt
|
|
29
|
+
elsif @prompt.update(prompt_params)
|
|
30
|
+
render json: @prompt
|
|
31
|
+
else
|
|
32
|
+
render json: {errors: @prompt.errors}, status: :unprocessable_entity
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def destroy
|
|
37
|
+
@prompt.destroy!
|
|
38
|
+
head :no_content
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def publish
|
|
42
|
+
@prompt.publish!
|
|
43
|
+
render json: @prompt.reload
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def set_prompt
|
|
49
|
+
@prompt = if params[:id].to_s.match?(/\A\d+\z/)
|
|
50
|
+
Prompt.find(params[:id])
|
|
51
|
+
else
|
|
52
|
+
Prompt.current_for(params[:id])
|
|
53
|
+
end
|
|
54
|
+
rescue ActiveRecord::RecordNotFound
|
|
55
|
+
not_found
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def prompt_params
|
|
59
|
+
params.permit(:name, :description, :template, :llm_model)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
module Api
|
|
3
|
+
module V1
|
|
4
|
+
class ProviderCredentialsController < BaseController
|
|
5
|
+
before_action :set_credential, only: [:show, :update, :destroy]
|
|
6
|
+
|
|
7
|
+
def index
|
|
8
|
+
render json: ProviderCredential.order(created_at: :desc)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def show
|
|
12
|
+
render json: @credential
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create
|
|
16
|
+
credential = ProviderCredential.new(credential_params)
|
|
17
|
+
if credential.save
|
|
18
|
+
render json: credential, status: :created
|
|
19
|
+
else
|
|
20
|
+
render json: {errors: credential.errors}, status: :unprocessable_entity
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def update
|
|
25
|
+
if @credential.update(credential_params)
|
|
26
|
+
render json: @credential
|
|
27
|
+
else
|
|
28
|
+
render json: {errors: @credential.errors}, status: :unprocessable_entity
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def destroy
|
|
33
|
+
@credential.destroy!
|
|
34
|
+
head :no_content
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def set_credential
|
|
40
|
+
@credential = ProviderCredential.find(params[:id])
|
|
41
|
+
rescue ActiveRecord::RecordNotFound
|
|
42
|
+
not_found
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def credential_params
|
|
46
|
+
params.permit(:provider, :api_key, :api_endpoint)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
module Api
|
|
3
|
+
module V1
|
|
4
|
+
class ResponsesController < BaseController
|
|
5
|
+
before_action :set_run
|
|
6
|
+
before_action :set_response, only: [:show]
|
|
7
|
+
|
|
8
|
+
def index
|
|
9
|
+
render json: @run.responses.includes(:reviews)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def show
|
|
13
|
+
render json: @response
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def set_run
|
|
19
|
+
@run = Run.find(params[:run_id])
|
|
20
|
+
rescue ActiveRecord::RecordNotFound
|
|
21
|
+
not_found
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def set_response
|
|
25
|
+
@response = @run.responses.find(params[:id])
|
|
26
|
+
rescue ActiveRecord::RecordNotFound
|
|
27
|
+
not_found
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
module Api
|
|
3
|
+
module V1
|
|
4
|
+
class RunsController < BaseController
|
|
5
|
+
before_action :set_run, only: [:show, :update, :destroy, :generate, :judge]
|
|
6
|
+
|
|
7
|
+
def index
|
|
8
|
+
render json: Run.order(created_at: :desc)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def show
|
|
12
|
+
render json: @run
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create
|
|
16
|
+
run = Run.new(run_params.except(:metric_ids))
|
|
17
|
+
if run.save
|
|
18
|
+
replace_run_metrics(run, params[:metric_ids])
|
|
19
|
+
render json: run.reload, status: :created
|
|
20
|
+
else
|
|
21
|
+
render json: {errors: run.errors}, status: :unprocessable_entity
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def update
|
|
26
|
+
if @run.update(run_params.except(:metric_ids))
|
|
27
|
+
replace_run_metrics(@run, params[:metric_ids]) if params.key?(:metric_ids)
|
|
28
|
+
render json: @run.reload
|
|
29
|
+
else
|
|
30
|
+
render json: {errors: @run.errors}, status: :unprocessable_entity
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def destroy
|
|
35
|
+
@run.destroy!
|
|
36
|
+
head :no_content
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def generate
|
|
40
|
+
GenerateJob.perform_later(@run.id)
|
|
41
|
+
render json: @run.reload, status: :accepted
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def judge
|
|
45
|
+
JudgeJob.perform_later(@run.id)
|
|
46
|
+
render json: @run.reload, status: :accepted
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def set_run
|
|
52
|
+
@run = Run.find(params[:id])
|
|
53
|
+
rescue ActiveRecord::RecordNotFound
|
|
54
|
+
not_found
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def run_params
|
|
58
|
+
params.permit(:name, :prompt_id, :dataset_id, :judge_model, :temperature, metric_ids: [])
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def replace_run_metrics(run, metric_ids)
|
|
62
|
+
return unless metric_ids
|
|
63
|
+
run.run_metrics.delete_all
|
|
64
|
+
Array(metric_ids).reject(&:blank?).each_with_index do |metric_id, index|
|
|
65
|
+
run.run_metrics.create!(metric_id: metric_id, position: index + 1)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
class ApiReferenceController < ApplicationController
|
|
3
|
+
def index
|
|
4
|
+
@published_prompts = Prompt.current_versions.order(name: :asc)
|
|
5
|
+
@token = CompletionKit.config.api_token
|
|
6
|
+
@base_url = request.base_url + request.script_name
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
class ApplicationController < ActionController::Base
|
|
3
|
+
helper Heroicons::IconsHelper
|
|
4
|
+
layout "completion_kit/application"
|
|
5
|
+
|
|
6
|
+
before_action :authenticate_completion_kit!
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def authenticate_completion_kit!
|
|
11
|
+
cfg = CompletionKit.config
|
|
12
|
+
|
|
13
|
+
if (cfg.username && !cfg.password) || (cfg.password && !cfg.username)
|
|
14
|
+
raise CompletionKit::ConfigurationError,
|
|
15
|
+
"Both username and password are required for built-in auth."
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
if cfg.auth_strategy
|
|
19
|
+
cfg.auth_strategy.call(self)
|
|
20
|
+
elsif cfg.username && cfg.password
|
|
21
|
+
authenticate_or_request_with_http_basic("CompletionKit") do |u, p|
|
|
22
|
+
ActiveSupport::SecurityUtils.secure_compare(u, cfg.username) &
|
|
23
|
+
ActiveSupport::SecurityUtils.secure_compare(p, cfg.password)
|
|
24
|
+
end
|
|
25
|
+
elsif Rails.env.production?
|
|
26
|
+
render plain: "CompletionKit authentication not configured. See README for setup instructions.",
|
|
27
|
+
status: :forbidden
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
class CriteriaController < ApplicationController
|
|
3
|
+
before_action :set_criteria, only: [:show, :edit, :update, :destroy]
|
|
4
|
+
|
|
5
|
+
def index
|
|
6
|
+
@criterias = Criteria.includes(:metrics).order(:name)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def show
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def new
|
|
13
|
+
@criteria = Criteria.new
|
|
14
|
+
@metrics = Metric.order(:name)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def edit
|
|
18
|
+
@metrics = Metric.order(:name)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def create
|
|
22
|
+
@criteria = Criteria.new(criteria_params.except(:metric_ids))
|
|
23
|
+
@metrics = Metric.order(:name)
|
|
24
|
+
|
|
25
|
+
if @criteria.save
|
|
26
|
+
replace_metric_memberships
|
|
27
|
+
redirect_to criterion_path(@criteria), notice: "Criteria was successfully created."
|
|
28
|
+
else
|
|
29
|
+
render :new, status: :unprocessable_entity
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def update
|
|
34
|
+
@metrics = Metric.order(:name)
|
|
35
|
+
|
|
36
|
+
if @criteria.update(criteria_params.except(:metric_ids))
|
|
37
|
+
replace_metric_memberships
|
|
38
|
+
redirect_to criterion_path(@criteria), notice: "Criteria was successfully updated."
|
|
39
|
+
else
|
|
40
|
+
render :edit, status: :unprocessable_entity
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def destroy
|
|
45
|
+
@criteria.destroy
|
|
46
|
+
redirect_to criteria_path, notice: "Criteria was successfully destroyed."
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def set_criteria
|
|
52
|
+
@criteria = Criteria.find(params[:id])
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def criteria_params
|
|
56
|
+
params.require(:criteria).permit(:name, :description, metric_ids: [])
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def replace_metric_memberships
|
|
60
|
+
metric_ids = Array(criteria_params[:metric_ids]).reject(&:blank?)
|
|
61
|
+
@criteria.criteria_memberships.delete_all
|
|
62
|
+
metric_ids.each_with_index do |metric_id, index|
|
|
63
|
+
@criteria.criteria_memberships.create!(metric_id: metric_id, position: index + 1)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
class DatasetsController < ApplicationController
|
|
3
|
+
before_action :set_dataset, only: [:show, :edit, :update, :destroy]
|
|
4
|
+
|
|
5
|
+
def index
|
|
6
|
+
@datasets = Dataset.includes(:runs).order(created_at: :desc)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def show
|
|
10
|
+
@runs = @dataset.runs.includes(:prompt, :responses).order(created_at: :desc)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def new
|
|
14
|
+
@dataset = Dataset.new
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def edit
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def create
|
|
21
|
+
@dataset = Dataset.new(dataset_params)
|
|
22
|
+
|
|
23
|
+
if @dataset.save
|
|
24
|
+
redirect_to datasets_path, notice: "Dataset was successfully created."
|
|
25
|
+
else
|
|
26
|
+
render :new, status: :unprocessable_entity
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def update
|
|
31
|
+
if @dataset.update(dataset_params)
|
|
32
|
+
redirect_to @dataset, notice: "Dataset was successfully updated."
|
|
33
|
+
else
|
|
34
|
+
render :edit, status: :unprocessable_entity
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def destroy
|
|
39
|
+
@dataset.destroy
|
|
40
|
+
redirect_to datasets_path, notice: "Dataset was successfully destroyed."
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def set_dataset
|
|
46
|
+
@dataset = Dataset.find(params[:id])
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def dataset_params
|
|
50
|
+
params.require(:dataset).permit(:name, :csv_data)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
class McpController < Api::V1::BaseController
|
|
3
|
+
def handle
|
|
4
|
+
request_body = JSON.parse(request.body.read)
|
|
5
|
+
|
|
6
|
+
if request_body["method"] == "initialize"
|
|
7
|
+
result = McpDispatcher.initialize_session
|
|
8
|
+
session_id = result.delete(:session_id)
|
|
9
|
+
response.headers["Mcp-Session-Id"] = session_id
|
|
10
|
+
render json: jsonrpc_response(request_body["id"], result)
|
|
11
|
+
return
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
if request_body["method"] == "notifications/initialized"
|
|
15
|
+
head :ok
|
|
16
|
+
return
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
session_id = request.headers["Mcp-Session-Id"]
|
|
20
|
+
unless session_id && Rails.cache.exist?("mcp_session:#{session_id}")
|
|
21
|
+
render json: jsonrpc_error(request_body["id"], -32000, "Session not initialized. Send initialize first."), status: :bad_request
|
|
22
|
+
return
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
result = McpDispatcher.dispatch(request_body["method"], request_body["params"])
|
|
26
|
+
render json: jsonrpc_response(request_body["id"], result)
|
|
27
|
+
rescue JSON::ParserError
|
|
28
|
+
render json: jsonrpc_error(nil, -32700, "Parse error"), status: :bad_request
|
|
29
|
+
rescue McpDispatcher::MethodNotFound => e
|
|
30
|
+
render json: jsonrpc_error(request_body.dig("id"), -32601, e.message), status: :ok
|
|
31
|
+
rescue McpDispatcher::InvalidParams => e
|
|
32
|
+
render json: jsonrpc_error(request_body.dig("id"), -32602, e.message), status: :ok
|
|
33
|
+
rescue ActiveRecord::RecordNotFound => e
|
|
34
|
+
render json: jsonrpc_error(request_body.dig("id"), -32602, e.message), status: :ok
|
|
35
|
+
rescue ActiveRecord::RecordInvalid, ActiveRecord::InvalidForeignKey => e
|
|
36
|
+
render json: jsonrpc_error(request_body.dig("id"), -32602, e.message), status: :ok
|
|
37
|
+
rescue StandardError => e
|
|
38
|
+
render json: jsonrpc_error(request_body.dig("id"), -32603, e.message), status: :ok
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def destroy
|
|
42
|
+
session_id = request.headers["Mcp-Session-Id"]
|
|
43
|
+
Rails.cache.delete("mcp_session:#{session_id}") if session_id
|
|
44
|
+
head :ok
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def jsonrpc_response(id, result)
|
|
50
|
+
{jsonrpc: "2.0", id: id, result: result}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def jsonrpc_error(id, code, message)
|
|
54
|
+
{jsonrpc: "2.0", id: id, error: {code: code, message: message}}
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
class MetricsController < ApplicationController
|
|
3
|
+
before_action :set_metric, only: [:show, :edit, :update, :destroy]
|
|
4
|
+
|
|
5
|
+
def index
|
|
6
|
+
@metrics = Metric.order(:name)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def show
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def new
|
|
13
|
+
@metric = Metric.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def edit
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def create
|
|
20
|
+
@metric = Metric.new(metric_params)
|
|
21
|
+
|
|
22
|
+
if @metric.save
|
|
23
|
+
redirect_to metric_path(@metric), notice: "Metric was successfully created."
|
|
24
|
+
else
|
|
25
|
+
render :new, status: :unprocessable_entity
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def update
|
|
30
|
+
if @metric.update(metric_params)
|
|
31
|
+
redirect_to metric_path(@metric), notice: "Metric was successfully updated."
|
|
32
|
+
else
|
|
33
|
+
render :edit, status: :unprocessable_entity
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def destroy
|
|
38
|
+
@metric.destroy
|
|
39
|
+
redirect_to metrics_path, notice: "Metric was successfully destroyed."
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def set_metric
|
|
45
|
+
@metric = Metric.find(params[:id])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def metric_params
|
|
49
|
+
params.require(:metric).permit(:name, :instruction, evaluation_steps: [], rubric_bands: [:stars, :description])
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|