mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-03-11 02:22:37 +01:00
* chore: move database model methods to /packages/data-schemas * chore: add TypeScript ESLint rule to warn on unused variables * refactor: model imports to streamline access - Consolidated model imports across various files to improve code organization and reduce redundancy. - Updated imports for models such as Assistant, Message, Conversation, and others to a unified import path. - Adjusted middleware and service files to reflect the new import structure, ensuring functionality remains intact. - Enhanced test files to align with the new import paths, maintaining test coverage and integrity. * chore: migrate database models to packages/data-schemas and refactor all direct Mongoose Model usage outside of data-schemas * test: update agent model mocks in unit tests - Added `getAgent` mock to `client.test.js` to enhance test coverage for agent-related functionality. - Removed redundant `getAgent` and `getAgents` mocks from `openai.spec.js` and `responses.unit.spec.js` to streamline test setup and reduce duplication. - Ensured consistency in agent mock implementations across test files. * fix: update types in data-schemas * refactor: enhance type definitions in transaction and spending methods - Updated type definitions in `checkBalance.ts` to use specific request and response types. - Refined `spendTokens.ts` to utilize a new `SpendTxData` interface for better clarity and type safety. - Improved transaction handling in `transaction.ts` by introducing `TransactionResult` and `TxData` interfaces, ensuring consistent data structures across methods. - Adjusted unit tests in `transaction.spec.ts` to accommodate new type definitions and enhance robustness. * refactor: streamline model imports and enhance code organization - Consolidated model imports across various controllers and services to a unified import path, improving code clarity and reducing redundancy. - Updated multiple files to reflect the new import structure, ensuring all functionalities remain intact. - Enhanced overall code organization by removing duplicate import statements and optimizing the usage of model methods. * feat: implement loadAddedAgent and refactor agent loading logic - Introduced `loadAddedAgent` function to handle loading agents from added conversations, supporting multi-convo parallel execution. - Created a new `load.ts` file to encapsulate agent loading functionalities, including `loadEphemeralAgent` and `loadAgent`. - Updated the `index.ts` file to export the new `load` module instead of the deprecated `loadAgent`. - Enhanced type definitions and improved error handling in the agent loading process. - Adjusted unit tests to reflect changes in the agent loading structure and ensure comprehensive coverage. * refactor: enhance balance handling with new update interface - Introduced `IBalanceUpdate` interface to streamline balance update operations across the codebase. - Updated `upsertBalanceFields` method signatures in `balance.ts`, `transaction.ts`, and related tests to utilize the new interface for improved type safety. - Adjusted type imports in `balance.spec.ts` to include `IBalanceUpdate`, ensuring consistency in balance management functionalities. - Enhanced overall code clarity and maintainability by refining type definitions related to balance operations. * feat: add unit tests for loadAgent functionality and enhance agent loading logic - Introduced comprehensive unit tests for the `loadAgent` function, covering various scenarios including null and empty agent IDs, loading of ephemeral agents, and permission checks. - Enhanced the `initializeClient` function by moving `getConvoFiles` to the correct position in the database method exports, ensuring proper functionality. - Improved test coverage for agent loading, including handling of non-existent agents and user permissions. * chore: reorder memory method exports for consistency - Moved `deleteAllUserMemories` to the correct position in the exported memory methods, ensuring a consistent and logical order of method exports in `memory.ts`.
186 lines
5.1 KiB
TypeScript
186 lines
5.1 KiB
TypeScript
import { Types } from 'mongoose';
|
|
import logger from '~/config/winston';
|
|
import type * as t from '~/types';
|
|
|
|
/**
|
|
* Formats a date in YYYY-MM-DD format
|
|
*/
|
|
const formatDate = (date: Date): string => {
|
|
return date.toISOString().split('T')[0];
|
|
};
|
|
|
|
// Factory function that takes mongoose instance and returns the methods
|
|
export function createMemoryMethods(mongoose: typeof import('mongoose')) {
|
|
/**
|
|
* Creates a new memory entry for a user
|
|
* Throws an error if a memory with the same key already exists
|
|
*/
|
|
async function createMemory({
|
|
userId,
|
|
key,
|
|
value,
|
|
tokenCount = 0,
|
|
}: t.SetMemoryParams): Promise<t.MemoryResult> {
|
|
try {
|
|
if (key?.toLowerCase() === 'nothing') {
|
|
return { ok: false };
|
|
}
|
|
|
|
const MemoryEntry = mongoose.models.MemoryEntry;
|
|
const existingMemory = await MemoryEntry.findOne({ userId, key });
|
|
if (existingMemory) {
|
|
throw new Error('Memory with this key already exists');
|
|
}
|
|
|
|
await MemoryEntry.create({
|
|
userId,
|
|
key,
|
|
value,
|
|
tokenCount,
|
|
updated_at: new Date(),
|
|
});
|
|
|
|
return { ok: true };
|
|
} catch (error) {
|
|
throw new Error(
|
|
`Failed to create memory: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets or updates a memory entry for a user
|
|
*/
|
|
async function setMemory({
|
|
userId,
|
|
key,
|
|
value,
|
|
tokenCount = 0,
|
|
}: t.SetMemoryParams): Promise<t.MemoryResult> {
|
|
try {
|
|
if (key?.toLowerCase() === 'nothing') {
|
|
return { ok: false };
|
|
}
|
|
|
|
const MemoryEntry = mongoose.models.MemoryEntry;
|
|
await MemoryEntry.findOneAndUpdate(
|
|
{ userId, key },
|
|
{
|
|
value,
|
|
tokenCount,
|
|
updated_at: new Date(),
|
|
},
|
|
{
|
|
upsert: true,
|
|
new: true,
|
|
},
|
|
);
|
|
|
|
return { ok: true };
|
|
} catch (error) {
|
|
throw new Error(
|
|
`Failed to set memory: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes a specific memory entry for a user
|
|
*/
|
|
async function deleteMemory({ userId, key }: t.DeleteMemoryParams): Promise<t.MemoryResult> {
|
|
try {
|
|
const MemoryEntry = mongoose.models.MemoryEntry;
|
|
const result = await MemoryEntry.findOneAndDelete({ userId, key });
|
|
return { ok: !!result };
|
|
} catch (error) {
|
|
throw new Error(
|
|
`Failed to delete memory: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets all memory entries for a user
|
|
*/
|
|
async function getAllUserMemories(
|
|
userId: string | Types.ObjectId,
|
|
): Promise<t.IMemoryEntryLean[]> {
|
|
try {
|
|
const MemoryEntry = mongoose.models.MemoryEntry;
|
|
return (await MemoryEntry.find({ userId }).lean()) as t.IMemoryEntryLean[];
|
|
} catch (error) {
|
|
throw new Error(
|
|
`Failed to get all memories: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets and formats all memories for a user in two different formats
|
|
*/
|
|
async function getFormattedMemories({
|
|
userId,
|
|
}: t.GetFormattedMemoriesParams): Promise<t.FormattedMemoriesResult> {
|
|
try {
|
|
const memories = await getAllUserMemories(userId);
|
|
|
|
if (!memories || memories.length === 0) {
|
|
return { withKeys: '', withoutKeys: '', totalTokens: 0 };
|
|
}
|
|
|
|
const sortedMemories = memories.sort(
|
|
(a, b) => new Date(a.updated_at!).getTime() - new Date(b.updated_at!).getTime(),
|
|
);
|
|
|
|
const totalTokens = sortedMemories.reduce((sum, memory) => {
|
|
return sum + (memory.tokenCount || 0);
|
|
}, 0);
|
|
|
|
const withKeys = sortedMemories
|
|
.map((memory, index) => {
|
|
const date = formatDate(new Date(memory.updated_at!));
|
|
const tokenInfo = memory.tokenCount ? ` [${memory.tokenCount} tokens]` : '';
|
|
return `${index + 1}. [${date}]. ["key": "${memory.key}"]${tokenInfo}. ["value": "${memory.value}"]`;
|
|
})
|
|
.join('\n\n');
|
|
|
|
const withoutKeys = sortedMemories
|
|
.map((memory, index) => {
|
|
const date = formatDate(new Date(memory.updated_at!));
|
|
return `${index + 1}. [${date}]. ${memory.value}`;
|
|
})
|
|
.join('\n\n');
|
|
|
|
return { withKeys, withoutKeys, totalTokens };
|
|
} catch (error) {
|
|
logger.error('Failed to get formatted memories:', error);
|
|
return { withKeys: '', withoutKeys: '', totalTokens: 0 };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes all memory entries for a user
|
|
*/
|
|
async function deleteAllUserMemories(userId: string | Types.ObjectId): Promise<number> {
|
|
try {
|
|
const MemoryEntry = mongoose.models.MemoryEntry;
|
|
const result = await MemoryEntry.deleteMany({ userId });
|
|
return result.deletedCount;
|
|
} catch (error) {
|
|
throw new Error(
|
|
`Failed to delete all user memories: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
return {
|
|
setMemory,
|
|
createMemory,
|
|
deleteMemory,
|
|
getAllUserMemories,
|
|
getFormattedMemories,
|
|
deleteAllUserMemories,
|
|
};
|
|
}
|
|
|
|
export type MemoryMethods = ReturnType<typeof createMemoryMethods>;
|