completion-kit 0.4.8 → 0.5.1

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -0
  3. data/app/assets/config/completion_kit_manifest.js +1 -0
  4. data/app/assets/javascripts/completion_kit/application.js +157 -0
  5. data/app/assets/stylesheets/completion_kit/application.css +382 -0
  6. data/app/controllers/completion_kit/api/v1/datasets_controller.rb +2 -2
  7. data/app/controllers/completion_kit/api/v1/metric_groups_controller.rb +2 -2
  8. data/app/controllers/completion_kit/api/v1/metrics_controller.rb +3 -2
  9. data/app/controllers/completion_kit/api/v1/prompts_controller.rb +5 -4
  10. data/app/controllers/completion_kit/api/v1/runs_controller.rb +3 -2
  11. data/app/controllers/completion_kit/api/v1/tags_controller.rb +51 -0
  12. data/app/controllers/completion_kit/datasets_controller.rb +3 -2
  13. data/app/controllers/completion_kit/metric_groups_controller.rb +7 -6
  14. data/app/controllers/completion_kit/metrics_controller.rb +4 -2
  15. data/app/controllers/completion_kit/prompts_controller.rb +7 -4
  16. data/app/controllers/completion_kit/runs_controller.rb +4 -3
  17. data/app/controllers/completion_kit/tags_controller.rb +50 -0
  18. data/app/controllers/concerns/completion_kit/tag_filtering.rb +22 -0
  19. data/app/helpers/completion_kit/application_helper.rb +11 -0
  20. data/app/models/completion_kit/dataset.rb +5 -2
  21. data/app/models/completion_kit/metric.rb +4 -1
  22. data/app/models/completion_kit/metric_group.rb +4 -1
  23. data/app/models/completion_kit/prompt.rb +4 -1
  24. data/app/models/completion_kit/run.rb +3 -1
  25. data/app/models/completion_kit/tag.rb +39 -0
  26. data/app/models/completion_kit/tagging.rb +12 -0
  27. data/app/models/concerns/completion_kit/taggable.rb +24 -0
  28. data/app/services/completion_kit/mcp_dispatcher.rb +3 -1
  29. data/app/services/completion_kit/mcp_tools/datasets.rb +6 -4
  30. data/app/services/completion_kit/mcp_tools/metric_groups.rb +6 -2
  31. data/app/services/completion_kit/mcp_tools/metrics.rb +8 -4
  32. data/app/services/completion_kit/mcp_tools/prompts.rb +10 -5
  33. data/app/services/completion_kit/mcp_tools/runs.rb +7 -3
  34. data/app/services/completion_kit/mcp_tools/tags.rb +74 -0
  35. data/app/views/completion_kit/api_reference/index.html.erb +38 -0
  36. data/app/views/completion_kit/datasets/_form.html.erb +20 -1
  37. data/app/views/completion_kit/datasets/index.html.erb +17 -1
  38. data/app/views/completion_kit/datasets/show.html.erb +6 -0
  39. data/app/views/completion_kit/metric_groups/_form.html.erb +74 -19
  40. data/app/views/completion_kit/metric_groups/index.html.erb +30 -4
  41. data/app/views/completion_kit/metrics/_form.html.erb +19 -1
  42. data/app/views/completion_kit/metrics/index.html.erb +18 -2
  43. data/app/views/completion_kit/metrics/show.html.erb +6 -0
  44. data/app/views/completion_kit/prompts/_form.html.erb +20 -1
  45. data/app/views/completion_kit/prompts/index.html.erb +17 -1
  46. data/app/views/completion_kit/prompts/show.html.erb +6 -0
  47. data/app/views/completion_kit/provider_credentials/_form.html.erb +1 -1
  48. data/app/views/completion_kit/provider_credentials/index.html.erb +3 -1
  49. data/app/views/completion_kit/runs/_form.html.erb +25 -3
  50. data/app/views/completion_kit/runs/_row.html.erb +5 -0
  51. data/app/views/completion_kit/runs/index.html.erb +9 -0
  52. data/app/views/completion_kit/runs/show.html.erb +6 -0
  53. data/app/views/completion_kit/shared/_settings_nav.html.erb +9 -0
  54. data/app/views/completion_kit/tags/_filter_bar.html.erb +15 -0
  55. data/app/views/completion_kit/tags/_form.html.erb +40 -0
  56. data/app/views/completion_kit/tags/_marks.html.erb +3 -0
  57. data/app/views/completion_kit/tags/_picker.html.erb +20 -0
  58. data/app/views/completion_kit/tags/edit.html.erb +20 -0
  59. data/app/views/completion_kit/tags/index.html.erb +45 -0
  60. data/app/views/completion_kit/tags/new.html.erb +20 -0
  61. data/app/views/layouts/completion_kit/application.html.erb +11 -132
  62. data/config/routes.rb +2 -0
  63. data/db/migrate/20260509000001_create_completion_kit_tags.rb +10 -0
  64. data/db/migrate/20260509000002_create_completion_kit_taggings.rb +16 -0
  65. data/lib/completion_kit/engine.rb +5 -1
  66. data/lib/completion_kit/version.rb +1 -1
  67. metadata +19 -1
@@ -5,7 +5,7 @@ module CompletionKit
5
5
  before_action :set_prompt, only: [:show, :update, :destroy, :publish]
6
6
 
7
7
  def index
8
- render json: Prompt.order(created_at: :desc)
8
+ render json: Prompt.includes(:tags).order(created_at: :desc)
9
9
  end
10
10
 
11
11
  def show
@@ -23,9 +23,10 @@ module CompletionKit
23
23
 
24
24
  def update
25
25
  if @prompt.runs.exists?
26
- new_prompt = @prompt.clone_as_new_version(prompt_params.to_h)
26
+ new_prompt = @prompt.clone_as_new_version(prompt_params.except(:tag_names).to_h)
27
27
  new_prompt.publish!
28
- render json: new_prompt
28
+ new_prompt.update!(tag_names: prompt_params[:tag_names]) if prompt_params.key?(:tag_names)
29
+ render json: new_prompt.reload
29
30
  elsif @prompt.update(prompt_params)
30
31
  render json: @prompt
31
32
  else
@@ -56,7 +57,7 @@ module CompletionKit
56
57
  end
57
58
 
58
59
  def prompt_params
59
- params.permit(:name, :description, :template, :llm_model)
60
+ params.permit(:name, :description, :template, :llm_model, tag_names: [])
60
61
  end
61
62
  end
62
63
  end
@@ -5,7 +5,7 @@ module CompletionKit
5
5
  before_action :set_run, only: [:show, :update, :destroy, :generate, :retry_failures]
6
6
 
7
7
  def index
8
- render json: Run.order(created_at: :desc)
8
+ render json: Run.includes(:tags).order(created_at: :desc)
9
9
  end
10
10
 
11
11
  def show
@@ -76,7 +76,8 @@ module CompletionKit
76
76
  end
77
77
 
78
78
  def run_params
79
- params.permit(:name, :prompt_id, :dataset_id, :judge_model, :temperature, metric_ids: [])
79
+ params.permit(:name, :prompt_id, :dataset_id, :judge_model, :temperature,
80
+ metric_ids: [], tag_names: [])
80
81
  end
81
82
  end
82
83
  end
@@ -0,0 +1,51 @@
1
+ module CompletionKit
2
+ module Api
3
+ module V1
4
+ class TagsController < BaseController
5
+ before_action :set_tag, only: [:show, :update, :destroy]
6
+
7
+ def index
8
+ render json: Tag.order(:name)
9
+ end
10
+
11
+ def show
12
+ render json: @tag
13
+ end
14
+
15
+ def create
16
+ tag = Tag.new(tag_params)
17
+ if tag.save
18
+ render json: tag, status: :created
19
+ else
20
+ render json: {errors: tag.errors}, status: :unprocessable_entity
21
+ end
22
+ end
23
+
24
+ def update
25
+ if @tag.update(tag_params)
26
+ render json: @tag
27
+ else
28
+ render json: {errors: @tag.errors}, status: :unprocessable_entity
29
+ end
30
+ end
31
+
32
+ def destroy
33
+ @tag.destroy!
34
+ head :no_content
35
+ end
36
+
37
+ private
38
+
39
+ def set_tag
40
+ @tag = Tag.find(params[:id])
41
+ rescue ActiveRecord::RecordNotFound
42
+ not_found
43
+ end
44
+
45
+ def tag_params
46
+ params.permit(:name)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,9 +1,10 @@
1
1
  module CompletionKit
2
2
  class DatasetsController < ApplicationController
3
+ include CompletionKit::TagFiltering
3
4
  before_action :set_dataset, only: [:show, :edit, :update, :destroy]
4
5
 
5
6
  def index
6
- @datasets = Dataset.includes(:runs).order(created_at: :desc)
7
+ @datasets = apply_tag_filter(Dataset.includes(:runs, :tags).order(created_at: :desc))
7
8
  end
8
9
 
9
10
  def show
@@ -47,7 +48,7 @@ module CompletionKit
47
48
  end
48
49
 
49
50
  def dataset_params
50
- params.require(:dataset).permit(:name, :csv_data)
51
+ params.require(:dataset).permit(:name, :csv_data, tag_names: [])
51
52
  end
52
53
  end
53
54
  end
@@ -1,9 +1,10 @@
1
1
  module CompletionKit
2
2
  class MetricGroupsController < ApplicationController
3
+ include CompletionKit::TagFiltering
3
4
  before_action :set_metric_group, only: [:show, :edit, :update, :destroy]
4
5
 
5
6
  def index
6
- @metric_groups = MetricGroup.includes(:metrics).order(:name)
7
+ @metric_groups = apply_tag_filter(MetricGroup.includes(:metrics, :tags).order(:name))
7
8
  end
8
9
 
9
10
  def show
@@ -11,16 +12,16 @@ module CompletionKit
11
12
 
12
13
  def new
13
14
  @metric_group = MetricGroup.new
14
- @metrics = Metric.order(:name)
15
+ @metrics = Metric.includes(:tags).order(:name)
15
16
  end
16
17
 
17
18
  def edit
18
- @metrics = Metric.order(:name)
19
+ @metrics = Metric.includes(:tags).order(:name)
19
20
  end
20
21
 
21
22
  def create
22
23
  @metric_group = MetricGroup.new(metric_group_params.except(:metric_ids))
23
- @metrics = Metric.order(:name)
24
+ @metrics = Metric.includes(:tags).order(:name)
24
25
 
25
26
  if @metric_group.save
26
27
  @metric_group.replace_metrics!(metric_group_params[:metric_ids])
@@ -31,7 +32,7 @@ module CompletionKit
31
32
  end
32
33
 
33
34
  def update
34
- @metrics = Metric.order(:name)
35
+ @metrics = Metric.includes(:tags).order(:name)
35
36
 
36
37
  if @metric_group.update(metric_group_params.except(:metric_ids))
37
38
  @metric_group.replace_metrics!(metric_group_params[:metric_ids])
@@ -53,7 +54,7 @@ module CompletionKit
53
54
  end
54
55
 
55
56
  def metric_group_params
56
- params.require(:metric_group).permit(:name, :description, metric_ids: [])
57
+ params.require(:metric_group).permit(:name, :description, metric_ids: [], tag_names: [])
57
58
  end
58
59
  end
59
60
  end
@@ -1,9 +1,10 @@
1
1
  module CompletionKit
2
2
  class MetricsController < ApplicationController
3
+ include CompletionKit::TagFiltering
3
4
  before_action :set_metric, only: [:show, :edit, :update, :destroy]
4
5
 
5
6
  def index
6
- @metrics = Metric.includes(:metric_groups).order(:name)
7
+ @metrics = apply_tag_filter(Metric.includes(:metric_groups, :tags).order(:name))
7
8
  end
8
9
 
9
10
  def show
@@ -46,7 +47,8 @@ module CompletionKit
46
47
  end
47
48
 
48
49
  def metric_params
49
- params.require(:metric).permit(:name, :instruction, rubric_bands: [:stars, :description])
50
+ params.require(:metric).permit(:name, :instruction,
51
+ rubric_bands: [:stars, :description], tag_names: [])
50
52
  end
51
53
  end
52
54
  end
@@ -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
- has_many :runs, dependent: :restrict_with_error
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
- text_result(dataset.as_json)
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
- text_result(metric.as_json)
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