completion-kit 0.4.8 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/app/assets/stylesheets/completion_kit/application.css +375 -0
- data/app/controllers/completion_kit/api/v1/datasets_controller.rb +2 -2
- data/app/controllers/completion_kit/api/v1/metric_groups_controller.rb +2 -2
- data/app/controllers/completion_kit/api/v1/metrics_controller.rb +3 -2
- data/app/controllers/completion_kit/api/v1/prompts_controller.rb +5 -4
- data/app/controllers/completion_kit/api/v1/runs_controller.rb +3 -2
- data/app/controllers/completion_kit/api/v1/tags_controller.rb +51 -0
- data/app/controllers/completion_kit/datasets_controller.rb +3 -2
- data/app/controllers/completion_kit/metric_groups_controller.rb +7 -6
- data/app/controllers/completion_kit/metrics_controller.rb +4 -2
- data/app/controllers/completion_kit/prompts_controller.rb +7 -4
- data/app/controllers/completion_kit/runs_controller.rb +4 -3
- data/app/controllers/completion_kit/tags_controller.rb +50 -0
- data/app/controllers/concerns/completion_kit/tag_filtering.rb +22 -0
- data/app/helpers/completion_kit/application_helper.rb +11 -0
- data/app/models/completion_kit/dataset.rb +5 -2
- data/app/models/completion_kit/metric.rb +4 -1
- data/app/models/completion_kit/metric_group.rb +4 -1
- data/app/models/completion_kit/prompt.rb +4 -1
- data/app/models/completion_kit/run.rb +3 -1
- data/app/models/completion_kit/tag.rb +39 -0
- data/app/models/completion_kit/tagging.rb +12 -0
- data/app/models/concerns/completion_kit/taggable.rb +24 -0
- data/app/services/completion_kit/mcp_dispatcher.rb +3 -1
- data/app/services/completion_kit/mcp_tools/datasets.rb +6 -4
- data/app/services/completion_kit/mcp_tools/metric_groups.rb +6 -2
- data/app/services/completion_kit/mcp_tools/metrics.rb +8 -4
- data/app/services/completion_kit/mcp_tools/prompts.rb +10 -5
- data/app/services/completion_kit/mcp_tools/runs.rb +7 -3
- data/app/services/completion_kit/mcp_tools/tags.rb +74 -0
- data/app/views/completion_kit/api_reference/index.html.erb +38 -0
- data/app/views/completion_kit/datasets/_form.html.erb +20 -1
- data/app/views/completion_kit/datasets/index.html.erb +17 -1
- data/app/views/completion_kit/datasets/show.html.erb +6 -0
- data/app/views/completion_kit/metric_groups/_form.html.erb +74 -19
- data/app/views/completion_kit/metric_groups/index.html.erb +30 -4
- data/app/views/completion_kit/metrics/_form.html.erb +19 -1
- data/app/views/completion_kit/metrics/index.html.erb +18 -2
- data/app/views/completion_kit/metrics/show.html.erb +6 -0
- data/app/views/completion_kit/prompts/_form.html.erb +20 -1
- data/app/views/completion_kit/prompts/index.html.erb +17 -1
- data/app/views/completion_kit/prompts/show.html.erb +6 -0
- data/app/views/completion_kit/provider_credentials/_form.html.erb +1 -1
- data/app/views/completion_kit/provider_credentials/index.html.erb +3 -1
- data/app/views/completion_kit/runs/_form.html.erb +25 -3
- data/app/views/completion_kit/runs/_row.html.erb +5 -0
- data/app/views/completion_kit/runs/index.html.erb +9 -0
- data/app/views/completion_kit/runs/show.html.erb +6 -0
- data/app/views/completion_kit/shared/_settings_nav.html.erb +9 -0
- data/app/views/completion_kit/tags/_filter_bar.html.erb +15 -0
- data/app/views/completion_kit/tags/_form.html.erb +39 -0
- data/app/views/completion_kit/tags/_marks.html.erb +3 -0
- data/app/views/completion_kit/tags/_picker.html.erb +20 -0
- data/app/views/completion_kit/tags/edit.html.erb +20 -0
- data/app/views/completion_kit/tags/index.html.erb +45 -0
- data/app/views/completion_kit/tags/new.html.erb +20 -0
- data/app/views/layouts/completion_kit/application.html.erb +38 -1
- data/config/routes.rb +2 -0
- data/db/migrate/20260509000001_create_completion_kit_tags.rb +10 -0
- data/db/migrate/20260509000002_create_completion_kit_taggings.rb +16 -0
- data/lib/completion_kit/version.rb +1 -1
- metadata +18 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
module CompletionKit
|
|
2
2
|
class PromptsController < ApplicationController
|
|
3
|
+
include CompletionKit::TagFiltering
|
|
3
4
|
before_action :set_prompt, only: [:show, :edit, :update, :destroy, :publish]
|
|
4
|
-
|
|
5
|
+
|
|
5
6
|
def index
|
|
6
|
-
@prompts = Prompt.current_versions.includes(:runs).order(created_at: :desc)
|
|
7
|
+
@prompts = apply_tag_filter(Prompt.current_versions.includes(:runs, :tags).order(created_at: :desc))
|
|
7
8
|
end
|
|
8
9
|
|
|
9
10
|
def show
|
|
@@ -31,8 +32,9 @@ module CompletionKit
|
|
|
31
32
|
|
|
32
33
|
def update
|
|
33
34
|
if @prompt.runs.exists?
|
|
34
|
-
new_prompt = @prompt.clone_as_new_version(prompt_params.to_h)
|
|
35
|
+
new_prompt = @prompt.clone_as_new_version(prompt_params.except(:tag_names).to_h)
|
|
35
36
|
new_prompt.publish!
|
|
37
|
+
new_prompt.update!(tag_names: prompt_params[:tag_names]) if prompt_params.key?(:tag_names)
|
|
36
38
|
redirect_to prompt_path(new_prompt), notice: "Saved as #{new_prompt.version_label}."
|
|
37
39
|
elsif @prompt.update(prompt_params)
|
|
38
40
|
redirect_to prompt_path(@prompt), notice: "Prompt saved."
|
|
@@ -62,7 +64,8 @@ module CompletionKit
|
|
|
62
64
|
:name,
|
|
63
65
|
:description,
|
|
64
66
|
:template,
|
|
65
|
-
:llm_model
|
|
67
|
+
:llm_model,
|
|
68
|
+
tag_names: []
|
|
66
69
|
)
|
|
67
70
|
end
|
|
68
71
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
module CompletionKit
|
|
2
2
|
class RunsController < ApplicationController
|
|
3
|
+
include CompletionKit::TagFiltering
|
|
3
4
|
before_action :set_run, only: [:show, :edit, :update, :destroy, :generate, :suggest, :retry_failures, :rerun, :refresh_status]
|
|
4
5
|
before_action :load_form_collections, only: [:new, :edit, :create, :update]
|
|
5
6
|
|
|
6
7
|
def index
|
|
7
|
-
@runs = Run.includes(:prompt, :dataset, responses: :reviews).order(created_at: :desc)
|
|
8
|
+
@runs = apply_tag_filter(Run.includes(:prompt, :dataset, :tags, responses: :reviews).order(created_at: :desc))
|
|
8
9
|
end
|
|
9
10
|
|
|
10
11
|
def show
|
|
@@ -148,11 +149,11 @@ module CompletionKit
|
|
|
148
149
|
@prompts = Prompt.order(:name)
|
|
149
150
|
@datasets = Dataset.order(:name)
|
|
150
151
|
@metric_groups = MetricGroup.includes(:metrics).order(:name)
|
|
151
|
-
@all_metrics = Metric.order(:name)
|
|
152
|
+
@all_metrics = Metric.includes(:tags).order(:name)
|
|
152
153
|
end
|
|
153
154
|
|
|
154
155
|
def run_params
|
|
155
|
-
params.require(:run).permit(:name, :prompt_id, :dataset_id, :judge_model, :temperature, metric_ids: [])
|
|
156
|
+
params.require(:run).permit(:name, :prompt_id, :dataset_id, :judge_model, :temperature, metric_ids: [], tag_names: [])
|
|
156
157
|
end
|
|
157
158
|
|
|
158
159
|
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
class TagsController < ApplicationController
|
|
3
|
+
before_action :set_tag, only: [:edit, :update, :destroy]
|
|
4
|
+
|
|
5
|
+
def index
|
|
6
|
+
@tags = Tag.order(:name)
|
|
7
|
+
@tagging_counts = Tagging.group(:tag_id).count
|
|
8
|
+
@tagging_by_type = Tagging.group(:tag_id, :taggable_type).count
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def new
|
|
12
|
+
@tag = Tag.new(color: Tag::COLORS.sample)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def edit
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create
|
|
19
|
+
@tag = Tag.new(tag_params)
|
|
20
|
+
if @tag.save
|
|
21
|
+
redirect_to tags_path, notice: "Tag was successfully created."
|
|
22
|
+
else
|
|
23
|
+
render :new, status: :unprocessable_entity
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def update
|
|
28
|
+
if @tag.update(tag_params)
|
|
29
|
+
redirect_to tags_path, notice: "Tag was successfully updated."
|
|
30
|
+
else
|
|
31
|
+
render :edit, status: :unprocessable_entity
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def destroy
|
|
36
|
+
@tag.destroy
|
|
37
|
+
redirect_to tags_path, notice: "Tag was successfully destroyed."
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def set_tag
|
|
43
|
+
@tag = Tag.find(params[:id])
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def tag_params
|
|
47
|
+
params.require(:tag).permit(:name)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
module TagFiltering
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
def apply_tag_filter(scope)
|
|
8
|
+
@available_tags = CompletionKit::Tag.order(:name)
|
|
9
|
+
@selected_tags = filter_tags_from_params
|
|
10
|
+
return scope if @selected_tags.empty?
|
|
11
|
+
scope.joins(:tags).where(tags: { id: @selected_tags.map(&:id) }).distinct
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def filter_tags_from_params
|
|
15
|
+
names = Array(params[:tag])
|
|
16
|
+
.map { |n| n.to_s.strip.downcase }
|
|
17
|
+
.reject(&:blank?)
|
|
18
|
+
return [] if names.empty?
|
|
19
|
+
CompletionKit::Tag.where(name: names).to_a
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -116,6 +116,17 @@ module CompletionKit
|
|
|
116
116
|
diff_tokens(old_text, new_text, :new)
|
|
117
117
|
end
|
|
118
118
|
|
|
119
|
+
def tag_pill_class(tag, outline: false)
|
|
120
|
+
["tag", "tag-#{tag.color}", ("tag-outline" if outline)].compact.join(" ")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def tag_filter_url(base_path, selected, toggling)
|
|
124
|
+
remaining = selected.reject { |t| t.id == toggling.id }
|
|
125
|
+
next_set = selected.include?(toggling) ? remaining : remaining + [toggling]
|
|
126
|
+
return base_path if next_set.empty?
|
|
127
|
+
"#{base_path}?#{{ tag: next_set.map(&:name) }.to_query}"
|
|
128
|
+
end
|
|
129
|
+
|
|
119
130
|
private
|
|
120
131
|
|
|
121
132
|
def diff_tokens(old_text, new_text, side)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module CompletionKit
|
|
2
2
|
class Dataset < ApplicationRecord
|
|
3
|
-
|
|
3
|
+
include CompletionKit::Taggable
|
|
4
|
+
|
|
5
|
+
has_many :runs, dependent: :destroy
|
|
4
6
|
|
|
5
7
|
validates :name, presence: true
|
|
6
8
|
validates :csv_data, presence: true
|
|
@@ -8,7 +10,8 @@ module CompletionKit
|
|
|
8
10
|
def as_json(options = {})
|
|
9
11
|
{
|
|
10
12
|
id: id, name: name, csv_data: csv_data,
|
|
11
|
-
created_at: created_at, updated_at: updated_at
|
|
13
|
+
created_at: created_at, updated_at: updated_at,
|
|
14
|
+
tags: tags.as_json
|
|
12
15
|
}
|
|
13
16
|
end
|
|
14
17
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module CompletionKit
|
|
2
2
|
class Metric < ApplicationRecord
|
|
3
|
+
include CompletionKit::Taggable
|
|
4
|
+
|
|
3
5
|
DEFAULT_RUBRIC_BANDS = [
|
|
4
6
|
{ "stars" => 5, "description" => "Fully meets or exceeds all criteria. No meaningful issues." },
|
|
5
7
|
{ "stars" => 4, "description" => "Meets criteria well. Minor issues only." },
|
|
@@ -74,7 +76,8 @@ module CompletionKit
|
|
|
74
76
|
{
|
|
75
77
|
id: id, name: name, key: key, instruction: instruction,
|
|
76
78
|
rubric_bands: rubric_bands,
|
|
77
|
-
created_at: created_at, updated_at: updated_at
|
|
79
|
+
created_at: created_at, updated_at: updated_at,
|
|
80
|
+
tags: tags.as_json
|
|
78
81
|
}
|
|
79
82
|
end
|
|
80
83
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module CompletionKit
|
|
2
2
|
class MetricGroup < ApplicationRecord
|
|
3
|
+
include CompletionKit::Taggable
|
|
4
|
+
|
|
3
5
|
self.table_name = "completion_kit_metric_groups"
|
|
4
6
|
|
|
5
7
|
has_many :metric_group_memberships, -> { order(:position, :id) }, dependent: :destroy
|
|
@@ -23,7 +25,8 @@ module CompletionKit
|
|
|
23
25
|
{
|
|
24
26
|
id: id, name: name, description: description,
|
|
25
27
|
created_at: created_at, updated_at: updated_at,
|
|
26
|
-
metric_ids: metric_ids
|
|
28
|
+
metric_ids: metric_ids,
|
|
29
|
+
tags: tags.as_json
|
|
27
30
|
}
|
|
28
31
|
end
|
|
29
32
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module CompletionKit
|
|
2
2
|
class Prompt < ApplicationRecord
|
|
3
|
+
include CompletionKit::Taggable
|
|
4
|
+
|
|
3
5
|
has_many :runs, dependent: :destroy
|
|
4
6
|
has_many :responses, through: :runs
|
|
5
7
|
|
|
@@ -77,7 +79,8 @@ module CompletionKit
|
|
|
77
79
|
{
|
|
78
80
|
id: id, name: name, description: description, template: template,
|
|
79
81
|
llm_model: llm_model, family_key: family_key, version_number: version_number,
|
|
80
|
-
current: current, created_at: created_at, updated_at: updated_at
|
|
82
|
+
current: current, created_at: created_at, updated_at: updated_at,
|
|
83
|
+
tags: tags.as_json
|
|
81
84
|
}
|
|
82
85
|
end
|
|
83
86
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module CompletionKit
|
|
2
2
|
class Run < ApplicationRecord
|
|
3
3
|
include Turbo::Broadcastable
|
|
4
|
+
include CompletionKit::Taggable
|
|
4
5
|
|
|
5
6
|
STATUSES = %w[pending running completed failed].freeze
|
|
6
7
|
|
|
@@ -178,7 +179,8 @@ module CompletionKit
|
|
|
178
179
|
failed_response_ids: responses.where(status: "failed").pluck(:id),
|
|
179
180
|
failure_summary: failure_summary,
|
|
180
181
|
error_message: error_message,
|
|
181
|
-
metric_ids: metric_ids
|
|
182
|
+
metric_ids: metric_ids,
|
|
183
|
+
tags: tags.as_json
|
|
182
184
|
}
|
|
183
185
|
end
|
|
184
186
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
class Tag < ApplicationRecord
|
|
3
|
+
self.table_name = "completion_kit_tags"
|
|
4
|
+
|
|
5
|
+
COLORS = %w[
|
|
6
|
+
crimson burnt-orange amber mint deep-emerald
|
|
7
|
+
electric-cyan cobalt-blue deep-indigo amethyst rose
|
|
8
|
+
].freeze
|
|
9
|
+
|
|
10
|
+
has_many :taggings, dependent: :destroy
|
|
11
|
+
|
|
12
|
+
before_validation :normalize_name
|
|
13
|
+
before_validation :assign_color, on: :create
|
|
14
|
+
|
|
15
|
+
validates :name, presence: true,
|
|
16
|
+
length: { maximum: 64 },
|
|
17
|
+
format: { with: /\A[\w\s\-]+\z/ },
|
|
18
|
+
tenant_scoped_uniqueness: true
|
|
19
|
+
validates :color, inclusion: { in: COLORS }
|
|
20
|
+
|
|
21
|
+
def as_json(options = {})
|
|
22
|
+
{
|
|
23
|
+
id: id, name: name, color: color,
|
|
24
|
+
created_at: created_at, updated_at: updated_at
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def normalize_name
|
|
31
|
+
self.name = name.to_s.strip.downcase if name.present?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def assign_color
|
|
35
|
+
return if color.present?
|
|
36
|
+
self.color = COLORS[CompletionKit::Tag.count % COLORS.size]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
class Tagging < ApplicationRecord
|
|
3
|
+
self.table_name = "completion_kit_taggings"
|
|
4
|
+
|
|
5
|
+
belongs_to :tag, class_name: "CompletionKit::Tag"
|
|
6
|
+
belongs_to :taggable, polymorphic: true
|
|
7
|
+
|
|
8
|
+
validates :tag, presence: true
|
|
9
|
+
validates :taggable, presence: true
|
|
10
|
+
validates :tag_id, uniqueness: { scope: [:taggable_type, :taggable_id] }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
module Taggable
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
has_many :taggings, as: :taggable,
|
|
7
|
+
class_name: "CompletionKit::Tagging",
|
|
8
|
+
dependent: :destroy
|
|
9
|
+
has_many :tags, through: :taggings, class_name: "CompletionKit::Tag"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def tag_names
|
|
13
|
+
tags.pluck(:name)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def tag_names=(names)
|
|
17
|
+
resolved = Array(names)
|
|
18
|
+
.map { |n| n.to_s.strip.downcase }
|
|
19
|
+
.reject(&:blank?)
|
|
20
|
+
.uniq
|
|
21
|
+
self.tags = resolved.map { |name| CompletionKit::Tag.find_or_create_by!(name: name) }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -34,7 +34,8 @@ module CompletionKit
|
|
|
34
34
|
McpTools::Datasets.definitions +
|
|
35
35
|
McpTools::Metrics.definitions +
|
|
36
36
|
McpTools::MetricGroups.definitions +
|
|
37
|
-
McpTools::ProviderCredentials.definitions
|
|
37
|
+
McpTools::ProviderCredentials.definitions +
|
|
38
|
+
McpTools::Tags.definitions
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
def self.call_tool(name, arguments)
|
|
@@ -46,6 +47,7 @@ module CompletionKit
|
|
|
46
47
|
when /\Ametrics_/ then McpTools::Metrics.call(name, arguments)
|
|
47
48
|
when /\Ametric_groups_/ then McpTools::MetricGroups.call(name, arguments)
|
|
48
49
|
when /\Aprovider_credentials_/ then McpTools::ProviderCredentials.call(name, arguments)
|
|
50
|
+
when /\Atags_/ then McpTools::Tags.call(name, arguments)
|
|
49
51
|
else raise MethodNotFound, "Unknown tool: #{name}"
|
|
50
52
|
end
|
|
51
53
|
end
|
|
@@ -18,7 +18,7 @@ module CompletionKit
|
|
|
18
18
|
description: "Create a dataset with CSV data",
|
|
19
19
|
inputSchema: {
|
|
20
20
|
type: "object",
|
|
21
|
-
properties: {name: {type: "string"}, csv_data: {type: "string"}},
|
|
21
|
+
properties: {name: {type: "string"}, csv_data: {type: "string"}, tag_names: {type: "array", items: {type: "string"}}},
|
|
22
22
|
required: ["name", "csv_data"]
|
|
23
23
|
},
|
|
24
24
|
handler: :create
|
|
@@ -27,7 +27,7 @@ module CompletionKit
|
|
|
27
27
|
description: "Update a dataset",
|
|
28
28
|
inputSchema: {
|
|
29
29
|
type: "object",
|
|
30
|
-
properties: {id: {type: "integer"}, name: {type: "string"}, csv_data: {type: "string"}},
|
|
30
|
+
properties: {id: {type: "integer"}, name: {type: "string"}, csv_data: {type: "string"}, tag_names: {type: "array", items: {type: "string"}}},
|
|
31
31
|
required: ["id"]
|
|
32
32
|
},
|
|
33
33
|
handler: :update
|
|
@@ -49,8 +49,9 @@ module CompletionKit
|
|
|
49
49
|
|
|
50
50
|
def self.create(args)
|
|
51
51
|
dataset = Dataset.new(args.slice("name", "csv_data"))
|
|
52
|
+
dataset.tag_names = args["tag_names"] if args.key?("tag_names")
|
|
52
53
|
if dataset.save
|
|
53
|
-
text_result(dataset.as_json)
|
|
54
|
+
text_result(dataset.reload.as_json)
|
|
54
55
|
else
|
|
55
56
|
error_result(dataset.errors.full_messages.join(", "))
|
|
56
57
|
end
|
|
@@ -59,7 +60,8 @@ module CompletionKit
|
|
|
59
60
|
def self.update(args)
|
|
60
61
|
dataset = Dataset.find(args["id"])
|
|
61
62
|
if dataset.update(args.except("id").slice("name", "csv_data"))
|
|
62
|
-
|
|
63
|
+
dataset.update!(tag_names: args["tag_names"]) if args.key?("tag_names")
|
|
64
|
+
text_result(dataset.reload.as_json)
|
|
63
65
|
else
|
|
64
66
|
error_result(dataset.errors.full_messages.join(", "))
|
|
65
67
|
end
|
|
@@ -20,7 +20,8 @@ module CompletionKit
|
|
|
20
20
|
type: "object",
|
|
21
21
|
properties: {
|
|
22
22
|
name: {type: "string"}, description: {type: "string"},
|
|
23
|
-
metric_ids: {type: "array", items: {type: "integer"}}
|
|
23
|
+
metric_ids: {type: "array", items: {type: "integer"}},
|
|
24
|
+
tag_names: {type: "array", items: {type: "string"}}
|
|
24
25
|
},
|
|
25
26
|
required: ["name"]
|
|
26
27
|
},
|
|
@@ -32,7 +33,8 @@ module CompletionKit
|
|
|
32
33
|
type: "object",
|
|
33
34
|
properties: {
|
|
34
35
|
id: {type: "integer"}, name: {type: "string"}, description: {type: "string"},
|
|
35
|
-
metric_ids: {type: "array", items: {type: "integer"}}
|
|
36
|
+
metric_ids: {type: "array", items: {type: "integer"}},
|
|
37
|
+
tag_names: {type: "array", items: {type: "string"}}
|
|
36
38
|
},
|
|
37
39
|
required: ["id"]
|
|
38
40
|
},
|
|
@@ -55,6 +57,7 @@ module CompletionKit
|
|
|
55
57
|
|
|
56
58
|
def self.create(args)
|
|
57
59
|
metric_group = CompletionKit::MetricGroup.new(args.slice("name", "description"))
|
|
60
|
+
metric_group.tag_names = args["tag_names"] if args.key?("tag_names")
|
|
58
61
|
if metric_group.save
|
|
59
62
|
metric_group.replace_metrics!(args["metric_ids"])
|
|
60
63
|
text_result(metric_group.reload.as_json)
|
|
@@ -67,6 +70,7 @@ module CompletionKit
|
|
|
67
70
|
metric_group = CompletionKit::MetricGroup.find(args["id"])
|
|
68
71
|
if metric_group.update(args.except("id", "metric_ids").slice("name", "description"))
|
|
69
72
|
metric_group.replace_metrics!(args["metric_ids"]) if args.key?("metric_ids")
|
|
73
|
+
metric_group.update!(tag_names: args["tag_names"]) if args.key?("tag_names")
|
|
70
74
|
text_result(metric_group.reload.as_json)
|
|
71
75
|
else
|
|
72
76
|
error_result(metric_group.errors.full_messages.join(", "))
|
|
@@ -20,7 +20,8 @@ module CompletionKit
|
|
|
20
20
|
type: "object",
|
|
21
21
|
properties: {
|
|
22
22
|
name: {type: "string"}, instruction: {type: "string"},
|
|
23
|
-
rubric_bands: {type: "array", items: {type: "object", properties: {stars: {type: "integer"}, description: {type: "string"}}}}
|
|
23
|
+
rubric_bands: {type: "array", items: {type: "object", properties: {stars: {type: "integer"}, description: {type: "string"}}}},
|
|
24
|
+
tag_names: {type: "array", items: {type: "string"}}
|
|
24
25
|
},
|
|
25
26
|
required: ["name"]
|
|
26
27
|
},
|
|
@@ -32,7 +33,8 @@ module CompletionKit
|
|
|
32
33
|
type: "object",
|
|
33
34
|
properties: {
|
|
34
35
|
id: {type: "integer"}, name: {type: "string"}, instruction: {type: "string"},
|
|
35
|
-
rubric_bands: {type: "array", items: {type: "object", properties: {stars: {type: "integer"}, description: {type: "string"}}}}
|
|
36
|
+
rubric_bands: {type: "array", items: {type: "object", properties: {stars: {type: "integer"}, description: {type: "string"}}}},
|
|
37
|
+
tag_names: {type: "array", items: {type: "string"}}
|
|
36
38
|
},
|
|
37
39
|
required: ["id"]
|
|
38
40
|
},
|
|
@@ -55,8 +57,9 @@ module CompletionKit
|
|
|
55
57
|
|
|
56
58
|
def self.create(args)
|
|
57
59
|
metric = Metric.new(args.slice("name", "instruction", "rubric_bands"))
|
|
60
|
+
metric.tag_names = args["tag_names"] if args.key?("tag_names")
|
|
58
61
|
if metric.save
|
|
59
|
-
text_result(metric.as_json)
|
|
62
|
+
text_result(metric.reload.as_json)
|
|
60
63
|
else
|
|
61
64
|
error_result(metric.errors.full_messages.join(", "))
|
|
62
65
|
end
|
|
@@ -65,7 +68,8 @@ module CompletionKit
|
|
|
65
68
|
def self.update(args)
|
|
66
69
|
metric = Metric.find(args["id"])
|
|
67
70
|
if metric.update(args.except("id").slice("name", "instruction", "rubric_bands"))
|
|
68
|
-
|
|
71
|
+
metric.update!(tag_names: args["tag_names"]) if args.key?("tag_names")
|
|
72
|
+
text_result(metric.reload.as_json)
|
|
69
73
|
else
|
|
70
74
|
error_result(metric.errors.full_messages.join(", "))
|
|
71
75
|
end
|
|
@@ -20,7 +20,8 @@ module CompletionKit
|
|
|
20
20
|
type: "object",
|
|
21
21
|
properties: {
|
|
22
22
|
name: {type: "string"}, description: {type: "string"},
|
|
23
|
-
template: {type: "string"}, llm_model: {type: "string"}
|
|
23
|
+
template: {type: "string"}, llm_model: {type: "string"},
|
|
24
|
+
tag_names: {type: "array", items: {type: "string"}}
|
|
24
25
|
},
|
|
25
26
|
required: ["name", "template", "llm_model"]
|
|
26
27
|
},
|
|
@@ -32,7 +33,8 @@ module CompletionKit
|
|
|
32
33
|
type: "object",
|
|
33
34
|
properties: {
|
|
34
35
|
id: {type: "integer"}, name: {type: "string"}, description: {type: "string"},
|
|
35
|
-
template: {type: "string"}, llm_model: {type: "string"}
|
|
36
|
+
template: {type: "string"}, llm_model: {type: "string"},
|
|
37
|
+
tag_names: {type: "array", items: {type: "string"}}
|
|
36
38
|
},
|
|
37
39
|
required: ["id"]
|
|
38
40
|
},
|
|
@@ -60,8 +62,9 @@ module CompletionKit
|
|
|
60
62
|
|
|
61
63
|
def self.create(args)
|
|
62
64
|
prompt = Prompt.new(args.slice("name", "description", "template", "llm_model"))
|
|
65
|
+
prompt.tag_names = args["tag_names"] if args.key?("tag_names")
|
|
63
66
|
if prompt.save
|
|
64
|
-
text_result(prompt.as_json)
|
|
67
|
+
text_result(prompt.reload.as_json)
|
|
65
68
|
else
|
|
66
69
|
error_result(prompt.errors.full_messages.join(", "))
|
|
67
70
|
end
|
|
@@ -73,9 +76,11 @@ module CompletionKit
|
|
|
73
76
|
if prompt.runs.exists?
|
|
74
77
|
new_prompt = prompt.clone_as_new_version(attrs)
|
|
75
78
|
new_prompt.publish!
|
|
76
|
-
|
|
79
|
+
new_prompt.update!(tag_names: args["tag_names"]) if args.key?("tag_names")
|
|
80
|
+
text_result(new_prompt.reload.as_json)
|
|
77
81
|
elsif prompt.update(attrs)
|
|
78
|
-
|
|
82
|
+
prompt.update!(tag_names: args["tag_names"]) if args.key?("tag_names")
|
|
83
|
+
text_result(prompt.reload.as_json)
|
|
79
84
|
else
|
|
80
85
|
error_result(prompt.errors.full_messages.join(", "))
|
|
81
86
|
end
|
|
@@ -21,7 +21,8 @@ module CompletionKit
|
|
|
21
21
|
properties: {
|
|
22
22
|
name: {type: "string"}, prompt_id: {type: "integer"},
|
|
23
23
|
dataset_id: {type: "integer"}, judge_model: {type: "string"},
|
|
24
|
-
metric_ids: {type: "array", items: {type: "integer"}}
|
|
24
|
+
metric_ids: {type: "array", items: {type: "integer"}},
|
|
25
|
+
tag_names: {type: "array", items: {type: "string"}}
|
|
25
26
|
},
|
|
26
27
|
required: ["name", "prompt_id"]
|
|
27
28
|
},
|
|
@@ -34,7 +35,8 @@ module CompletionKit
|
|
|
34
35
|
properties: {
|
|
35
36
|
id: {type: "integer"}, name: {type: "string"},
|
|
36
37
|
dataset_id: {type: "integer"}, judge_model: {type: "string"},
|
|
37
|
-
metric_ids: {type: "array", items: {type: "integer"}}
|
|
38
|
+
metric_ids: {type: "array", items: {type: "integer"}},
|
|
39
|
+
tag_names: {type: "array", items: {type: "string"}}
|
|
38
40
|
},
|
|
39
41
|
required: ["id"]
|
|
40
42
|
},
|
|
@@ -64,6 +66,7 @@ module CompletionKit
|
|
|
64
66
|
run = Run.new(args.slice("name", "prompt_id", "dataset_id", "judge_model"))
|
|
65
67
|
if run.save
|
|
66
68
|
run.replace_metrics!(args["metric_ids"])
|
|
69
|
+
run.update!(tag_names: args["tag_names"]) if args.key?("tag_names")
|
|
67
70
|
text_result(run.reload.as_json)
|
|
68
71
|
else
|
|
69
72
|
error_result(run.errors.full_messages.join(", "))
|
|
@@ -72,8 +75,9 @@ module CompletionKit
|
|
|
72
75
|
|
|
73
76
|
def self.update(args)
|
|
74
77
|
run = Run.find(args["id"])
|
|
75
|
-
if run.update(args.except("id", "metric_ids").slice("name", "dataset_id", "judge_model"))
|
|
78
|
+
if run.update(args.except("id", "metric_ids", "tag_names").slice("name", "dataset_id", "judge_model"))
|
|
76
79
|
run.replace_metrics!(args["metric_ids"]) if args.key?("metric_ids")
|
|
80
|
+
run.update!(tag_names: args["tag_names"]) if args.key?("tag_names")
|
|
77
81
|
text_result(run.reload.as_json)
|
|
78
82
|
else
|
|
79
83
|
error_result(run.errors.full_messages.join(", "))
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module CompletionKit
|
|
2
|
+
module McpTools
|
|
3
|
+
module Tags
|
|
4
|
+
extend Base
|
|
5
|
+
|
|
6
|
+
TOOLS = {
|
|
7
|
+
"tags_list" => {
|
|
8
|
+
description: "List all tags",
|
|
9
|
+
inputSchema: {type: "object", properties: {}, required: []},
|
|
10
|
+
handler: :list
|
|
11
|
+
},
|
|
12
|
+
"tags_get" => {
|
|
13
|
+
description: "Get a tag by ID",
|
|
14
|
+
inputSchema: {type: "object", properties: {id: {type: "integer"}}, required: ["id"]},
|
|
15
|
+
handler: :get
|
|
16
|
+
},
|
|
17
|
+
"tags_create" => {
|
|
18
|
+
description: "Create a tag. Color is auto-assigned.",
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {name: {type: "string"}},
|
|
22
|
+
required: ["name"]
|
|
23
|
+
},
|
|
24
|
+
handler: :create
|
|
25
|
+
},
|
|
26
|
+
"tags_update" => {
|
|
27
|
+
description: "Rename a tag.",
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {id: {type: "integer"}, name: {type: "string"}},
|
|
31
|
+
required: ["id"]
|
|
32
|
+
},
|
|
33
|
+
handler: :update
|
|
34
|
+
},
|
|
35
|
+
"tags_delete" => {
|
|
36
|
+
description: "Delete a tag. Removes the tag from every linked metric, prompt, run, and dataset.",
|
|
37
|
+
inputSchema: {type: "object", properties: {id: {type: "integer"}}, required: ["id"]},
|
|
38
|
+
handler: :delete
|
|
39
|
+
}
|
|
40
|
+
}.freeze
|
|
41
|
+
|
|
42
|
+
def self.list(_args)
|
|
43
|
+
text_result(CompletionKit::Tag.order(:name).map(&:as_json))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.get(args)
|
|
47
|
+
text_result(CompletionKit::Tag.find(args["id"]).as_json)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.create(args)
|
|
51
|
+
tag = CompletionKit::Tag.new(name: args["name"])
|
|
52
|
+
if tag.save
|
|
53
|
+
text_result(tag.as_json)
|
|
54
|
+
else
|
|
55
|
+
error_result(tag.errors.full_messages.join(", "))
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.update(args)
|
|
60
|
+
tag = CompletionKit::Tag.find(args["id"])
|
|
61
|
+
if tag.update(name: args["name"])
|
|
62
|
+
text_result(tag.as_json)
|
|
63
|
+
else
|
|
64
|
+
error_result(tag.errors.full_messages.join(", "))
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.delete(args)
|
|
69
|
+
CompletionKit::Tag.find(args["id"]).destroy!
|
|
70
|
+
text_result("Tag #{args["id"]} deleted")
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|