mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 08:50:15 +01:00
bugfix: Enhance Agent and AgentCategory schemas with new fields for category, support contact, and promotion status
This commit is contained in:
parent
f55cdc9b7f
commit
348ee5821e
5 changed files with 57 additions and 100 deletions
|
|
@ -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');
|
||||
|
||||
|
|
|
|||
|
|
@ -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<AgentCategory[]>} 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<AgentCategory[]>} 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<string[]>} 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;
|
||||
module.exports = AgentCategory;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -92,6 +92,35 @@ const agentSchema = new Schema<IAgent>(
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -36,4 +36,10 @@ export interface IAgent extends Omit<Document, 'model'> {
|
|||
versions?: Omit<IAgent, 'versions'>[];
|
||||
category: string;
|
||||
support_contact?: ISupportContact;
|
||||
category: string;
|
||||
support_contact?: {
|
||||
name?: string;
|
||||
email?: string;
|
||||
};
|
||||
is_promoted?: boolean;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue