Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/gitnexus-index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,5 @@ jobs:
|| github.ref_name
}}
path: .gitnexus/
include-hidden-files: true
retention-days: 30
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# v0.8.4
# v0.8.5-rc1

# Base node image
FROM node:20-alpine AS node
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.multi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Dockerfile.multi
# v0.8.4
# v0.8.5-rc1

# Set configurable max-old-space-size with default
ARG NODE_MAX_OLD_SPACE_SIZE=6144
Expand Down
6 changes: 3 additions & 3 deletions api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@librechat/backend",
"version": "v0.8.4",
"version": "v0.8.5-rc1",
"description": "",
"scripts": {
"start": "echo 'please run this from the root directory'",
Expand Down Expand Up @@ -44,15 +44,15 @@
"@google/genai": "^1.19.0",
"@keyv/redis": "^4.3.3",
"@langchain/core": "^0.3.80",
"@librechat/agents": "^3.1.63",
"@librechat/agents": "^3.1.64",
"@librechat/api": "*",
"@librechat/data-schemas": "*",
"@microsoft/microsoft-graph-client": "^3.0.7",
"@modelcontextprotocol/sdk": "^1.27.1",
"@node-saml/passport-saml": "^5.1.0",
"@smithy/node-http-handler": "^4.4.5",
"ai-tokenizer": "^1.0.6",
"axios": "1.13.6",
"axios": "^1.15.0",
"bcryptjs": "^2.4.3",
"compression": "^1.8.1",
"connect-redis": "^8.1.0",
Expand Down
45 changes: 37 additions & 8 deletions api/server/controllers/FavoritesController.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const updateFavoritesController = async (req, res) => {
for (const fav of favorites) {
const hasAgent = !!fav.agentId;
const hasModel = !!(fav.model && fav.endpoint);
const hasSpec = !!fav.spec;

if (fav.agentId && fav.agentId.length > MAX_STRING_LENGTH) {
return res
Expand All @@ -43,18 +44,46 @@ const updateFavoritesController = async (req, res) => {
.status(400)
.json({ message: `endpoint exceeds maximum length of ${MAX_STRING_LENGTH}` });
}
if (fav.spec !== undefined && fav.spec !== null) {
if (typeof fav.spec !== 'string' || fav.spec.length === 0) {
return res.status(400).json({ message: 'spec must be a non-empty string' });
}
if (fav.spec.length > MAX_STRING_LENGTH) {
return res
.status(400)
.json({ message: `spec exceeds maximum length of ${MAX_STRING_LENGTH}` });
}
}

const hasPartialModel = !hasModel && !!(fav.model || fav.endpoint);

if (hasPartialModel && !hasAgent && !hasSpec) {
return res.status(400).json({ message: 'model and endpoint must be provided together' });
}

if (!hasAgent && !hasModel) {
const typeCount = [hasAgent, hasModel, hasSpec].filter(Boolean).length;
if (typeCount === 0) {
return res.status(400).json({
message: 'Each favorite must have either agentId or model+endpoint',
message: 'Each favorite must have either agentId, model+endpoint, or spec',
});
}

if (hasAgent && hasModel) {
if (typeCount > 1) {
return res.status(400).json({
message: 'Favorite cannot have both agentId and model/endpoint',
message: 'Favorite cannot have multiple types (agentId, model/endpoint, or spec)',
});
}

if (hasSpec && (fav.agentId || fav.model || fav.endpoint)) {
return res
.status(400)
.json({ message: 'spec cannot be combined with agentId, model, or endpoint' });
}
if (hasAgent && (fav.model || fav.endpoint)) {
return res
.status(400)
.json({ message: 'agentId cannot be combined with model or endpoint' });
}
}

const user = await updateUser(userId, { favorites });
Expand All @@ -63,10 +92,10 @@ const updateFavoritesController = async (req, res) => {
return res.status(404).json({ message: 'User not found' });
}

res.status(200).json(user.favorites);
return res.status(200).json(user.favorites);
} catch (error) {
console.error('Error updating favorites:', error);
res.status(500).json({ message: 'Internal server error' });
return res.status(500).json({ message: 'Internal server error' });
}
};

Expand All @@ -86,10 +115,10 @@ const getFavoritesController = async (req, res) => {
await updateUser(userId, { favorites: [] });
}

res.status(200).json(favorites);
return res.status(200).json(favorites);
} catch (error) {
console.error('Error fetching favorites:', error);
res.status(500).json({ message: 'Internal server error' });
return res.status(500).json({ message: 'Internal server error' });
}
};

Expand Down
Loading
Loading