Files
sure/app/models/assistant/function/create_category.rb
Blaž Dular 974f1d8e44 feat(mcp): add get/create/update tools for tags and categories (#2374)
* feat(mcp): add get/create/update tools for tags and categories

* test(mcp): add tests for tag and category assistant functions

* fix(mcp): harden category/tag assistant functions against bad tool input

* refactor(mcp): use UuidFormat.valid? instead of local UUID_PATTERN

* chore(mcp): remove account_filter component files that don't belong in this branch
2026-06-21 12:01:39 +02:00

82 lines
2.7 KiB
Ruby

class Assistant::Function::CreateCategory < Assistant::Function
class << self
def name
"create_category"
end
def description
<<~INSTRUCTIONS
Creates a new category for the user's family.
Categories support two levels of hierarchy: a top-level category can have subcategories,
but subcategories cannot have children. Provide parent_id (from get_categories) to make
a subcategory — it will inherit the parent's color automatically.
If icon is omitted it is suggested from the name. If color is omitted a palette color is used
(ignored for subcategories since color is inherited). Category names must be unique.
INSTRUCTIONS
end
end
def strict_mode?
false
end
def params_schema
build_schema(
required: [ "name" ],
properties: {
name: {
type: "string",
description: "Category name (must be unique within the family)"
},
color: {
type: "string",
description: "Hex color code (e.g. #e99537). Ignored for subcategories. Defaults to a palette color."
},
icon: {
type: "string",
description: "Lucide icon name (e.g. 'shopping-cart'). Suggested from name if omitted."
},
parent_id: {
type: "string",
description: "ID of an existing top-level category to nest under (makes this a subcategory). Use get_categories to find ids."
}
}
)
end
def call(params = {})
name = params["name"].to_s.strip
return error("name_required", "Please provide a name for the category.") if name.blank?
color = params["color"].presence || Category::COLORS.sample
icon = params["icon"].presence || Category.suggested_icon(name)
attrs = { name: name, color: color, lucide_icon: icon }
if params["parent_id"].present?
return error("parent_not_found", "Parent category with id '#{params["parent_id"]}' not found.") unless valid_uuid?(params["parent_id"])
parent = family.categories.find_by(id: params["parent_id"])
return error("parent_not_found", "Parent category with id '#{params["parent_id"]}' not found.") unless parent
attrs[:parent] = parent
end
category = family.categories.new(attrs)
if category.save
{ success: true, category: serialize(category), message: "Category '#{category.name_with_parent}' created." }
else
error("validation_failed", category.errors.full_messages.join("; "))
end
end
private
def serialize(c)
{ id: c.id, name: c.name, name_with_parent: c.name_with_parent, color: c.color, icon: c.lucide_icon, parent_id: c.parent_id }
end
def error(key, message)
{ success: false, error: key, message: message }
end
end