From 348ee5821e90fbe1c5c5bc3eacccc7f7371bc9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CPraneeth?= Date: Wed, 11 Jun 2025 22:55:07 +0530 Subject: [PATCH] bugfix: Enhance Agent and AgentCategory schemas with new fields for category, support contact, and promotion status --- api/models/Agent.js | 76 +------------------- api/models/AgentCategory.js | 44 ++++++------ api/server/controllers/agents/marketplace.js | 2 +- packages/data-schemas/src/schema/agent.ts | 29 ++++++++ packages/data-schemas/src/types/agent.ts | 6 ++ 5 files changed, 57 insertions(+), 100 deletions(-) diff --git a/api/models/Agent.js b/api/models/Agent.js index c8be3af3be..ce6d41b76e 100644 --- a/api/models/Agent.js +++ b/api/models/Agent.js @@ -5,7 +5,6 @@ const { SystemRoles, Tools, actionDelimiter } = require('librechat-data-provider const { GLOBAL_PROJECT_NAME, EPHEMERAL_AGENT_ID, mcp_delimiter } = require('librechat-data-provider').Constants; // Default category value for new agents -const AgentCategory = require('./AgentCategory'); const { getProjectByName, addAgentIdsToProject, @@ -15,80 +14,7 @@ const { const { getCachedTools } = require('~/server/services/Config'); // Category values are now imported from shared constants - -// Add category field to the Agent schema if it doesn't already exist -if (!agentSchema.paths.category) { - agentSchema.add({ - category: { - type: String, - trim: true, - validate: { - validator: async function (value) { - if (!value) return true; // Allow empty values (will use default) - - // Check if category exists in database - const validCategories = await AgentCategory.getValidCategoryValues(); - return validCategories.includes(value); - }, - message: function (props) { - return `"${props.value}" is not a valid agent category. Please check available categories.`; - }, - }, - index: true, - default: 'general', - }, - }); -} - -// Add support_contact field to the Agent schema if it doesn't already exist -if (!agentSchema.paths.support_contact) { - agentSchema.add({ - support_contact: { - type: Object, - default: {}, - name: { - type: String, - minlength: [3, 'Support contact name must be at least 3 characters.'], - trim: true, - }, - email: { - type: String, - match: [ - /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, - 'Please enter a valid email address.', - ], - trim: true, - }, - }, - }); -} - -// Add promotion field to the Agent schema if it doesn't already exist -if (!agentSchema.paths.is_promoted) { - agentSchema.add({ - is_promoted: { - type: Boolean, - default: false, - index: true, // Index for efficient promoted agent queries - }, - }); -} - -// Add additional indexes for marketplace functionality -agentSchema.index({ projectIds: 1, is_promoted: 1, updatedAt: -1 }); // Optimize promoted agents query -agentSchema.index({ category: 1, projectIds: 1, updatedAt: -1 }); // Optimize category filtering -agentSchema.index({ projectIds: 1, category: 1 }); // Optimize aggregation pipeline - -// Text indexes for search functionality -agentSchema.index( - { name: 'text', description: 'text' }, - { - weights: { - name: 3, // Name matches are 3x more important than description matches - description: 1, - }, - }, -); +// Schema fields (category, support_contact, is_promoted) are defined in @librechat/data-schemas const { getActions } = require('./Action'); const { Agent } = require('~/db/models'); diff --git a/api/models/AgentCategory.js b/api/models/AgentCategory.js index c4265228dd..e26e7f3f07 100644 --- a/api/models/AgentCategory.js +++ b/api/models/AgentCategory.js @@ -15,28 +15,28 @@ const agentCategorySchema = new mongoose.Schema( lowercase: true, index: true, }, - + // Display label for the category label: { type: String, required: true, trim: true, }, - + // Description of the category description: { type: String, trim: true, default: '', }, - + // Display order for sorting categories order: { type: Number, default: 0, index: true, }, - + // Whether the category is active and should be displayed isActive: { type: Boolean, @@ -46,7 +46,7 @@ const agentCategorySchema = new mongoose.Schema( }, { timestamps: true, - } + }, ); // Indexes for performance @@ -56,32 +56,30 @@ agentCategorySchema.index({ isActive: 1, order: 1 }); * Get all active categories sorted by order * @returns {Promise} Array of active categories */ -agentCategorySchema.statics.getActiveCategories = function() { - return this.find({ isActive: true }) - .sort({ order: 1, label: 1 }) - .lean(); +agentCategorySchema.statics.getActiveCategories = function () { + return this.find({ isActive: true }).sort({ order: 1, label: 1 }).lean(); }; /** * Get categories with agent counts * @returns {Promise} Categories with agent counts */ -agentCategorySchema.statics.getCategoriesWithCounts = async function() { - const Agent = mongoose.model('agent'); - +agentCategorySchema.statics.getCategoriesWithCounts = async function () { + const Agent = mongoose.model('Agent'); + // Aggregate to get agent counts per category const categoryCounts = await Agent.aggregate([ { $match: { category: { $exists: true, $ne: null } } }, { $group: { _id: '$category', count: { $sum: 1 } } }, ]); - + // Create a map for quick lookup - const countMap = new Map(categoryCounts.map(c => [c._id, c.count])); - + const countMap = new Map(categoryCounts.map((c) => [c._id, c.count])); + // Get all active categories and add counts const categories = await this.getActiveCategories(); - - return categories.map(category => ({ + + return categories.map((category) => ({ ...category, agentCount: countMap.get(category.value) || 0, })); @@ -91,16 +89,14 @@ agentCategorySchema.statics.getCategoriesWithCounts = async function() { * Get valid category values for Agent model validation * @returns {Promise} Array of valid category values */ -agentCategorySchema.statics.getValidCategoryValues = function() { - return this.find({ isActive: true }) - .distinct('value') - .lean(); +agentCategorySchema.statics.getValidCategoryValues = function () { + return this.find({ isActive: true }).distinct('value').lean(); }; /** * Seed initial categories from existing constants */ -agentCategorySchema.statics.seedCategories = async function(categories) { +agentCategorySchema.statics.seedCategories = async function (categories) { const operations = categories.map((category, index) => ({ updateOne: { filter: { value: category.value }, @@ -116,10 +112,10 @@ agentCategorySchema.statics.seedCategories = async function(categories) { upsert: true, }, })); - + return this.bulkWrite(operations); }; const AgentCategory = mongoose.model('AgentCategory', agentCategorySchema); -module.exports = AgentCategory; \ No newline at end of file +module.exports = AgentCategory; diff --git a/api/server/controllers/agents/marketplace.js b/api/server/controllers/agents/marketplace.js index bee6bd3d97..a4d12f3263 100644 --- a/api/server/controllers/agents/marketplace.js +++ b/api/server/controllers/agents/marketplace.js @@ -3,7 +3,7 @@ const mongoose = require('mongoose'); const { logger } = require('~/config'); // Get the Agent model -const Agent = mongoose.model('agent'); +const Agent = mongoose.model('Agent'); // Default page size for agent browsing const DEFAULT_PAGE_SIZE = 6; diff --git a/packages/data-schemas/src/schema/agent.ts b/packages/data-schemas/src/schema/agent.ts index 9deda176cd..d6c2607e31 100644 --- a/packages/data-schemas/src/schema/agent.ts +++ b/packages/data-schemas/src/schema/agent.ts @@ -92,6 +92,35 @@ const agentSchema = new Schema( type: [Schema.Types.Mixed], default: [], }, + category: { + type: String, + trim: true, + index: true, + default: 'general', + }, + support_contact: { + type: { + name: { + type: String, + minlength: [3, 'Support contact name must be at least 3 characters.'], + trim: true, + }, + email: { + type: String, + match: [ + /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, + 'Please enter a valid email address.', + ], + trim: true, + }, + }, + default: {}, + }, + is_promoted: { + type: Boolean, + default: false, + index: true, + }, }, { timestamps: true, diff --git a/packages/data-schemas/src/types/agent.ts b/packages/data-schemas/src/types/agent.ts index 95a9953ed0..74161b3c65 100644 --- a/packages/data-schemas/src/types/agent.ts +++ b/packages/data-schemas/src/types/agent.ts @@ -36,4 +36,10 @@ export interface IAgent extends Omit { versions?: Omit[]; category: string; support_contact?: ISupportContact; + category: string; + support_contact?: { + name?: string; + email?: string; + }; + is_promoted?: boolean; }