Compare commits
6 Commits
copilot/ad
...
chore/agen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9449f36ead | ||
|
|
9495520f6f | ||
|
|
87d7ee4b0e | ||
|
|
d8d5d59d92 | ||
|
|
e3d33fed8d | ||
|
|
cbf52eabe3 |
233
AGENTS.md
Normal file
233
AGENTS.md
Normal file
@@ -0,0 +1,233 @@
|
||||
# LibreChat AGENTS.md
|
||||
|
||||
LibreChat is a multi-provider AI chat platform featuring agents, tools, and multimodal interactions. This file provides guidance for AI coding agents working on the codebase.
|
||||
|
||||
## Project Overview
|
||||
|
||||
LibreChat is a monorepo-based full-stack application providing a unified interface for multiple AI models and providers (OpenAI, Anthropic, Google Gemini, Azure, AWS Bedrock, Groq, Mistral, and more).
|
||||
|
||||
## Workspace Structure
|
||||
|
||||
LibreChat uses npm workspaces to organize code into distinct packages with clear responsibilities:
|
||||
|
||||
```
|
||||
LibreChat/
|
||||
├── api/ # Express.js backend (CJS, transitioning to TypeScript)
|
||||
├── client/ # React/Vite frontend application
|
||||
└── packages/
|
||||
├── api/ # @librechat/api - Backend TypeScript package
|
||||
├── client/ # @librechat/client - Frontend shared components
|
||||
├── data-provider/ # librechat-data-provider - Shared frontend/backend
|
||||
└── data-schemas/ # @librechat/data-schemas - Backend schemas & models
|
||||
```
|
||||
|
||||
### Workspace Responsibilities
|
||||
|
||||
#### `/api` - Express.js Backend
|
||||
- **Language**: CommonJS JavaScript (transitioning to TypeScript via shared packages)
|
||||
- **Purpose**: Main Express.js server, routes, middleware, legacy services
|
||||
- **Note**: Legacy workspace; **new backend logic should go in `packages/api` instead**
|
||||
- **Uses**: `librechat-data-provider`, `@librechat/api`, `@librechat/data-schemas`
|
||||
|
||||
#### `/client` - React Frontend Application
|
||||
- **Language**: TypeScript + React
|
||||
- **Purpose**: Main web application UI
|
||||
- **Uses**: `librechat-data-provider`, `@librechat/client`
|
||||
|
||||
#### `/packages/api` - `@librechat/api`
|
||||
- **Language**: TypeScript (full support)
|
||||
- **Purpose**: Backend-only package for all new backend logic
|
||||
- **Used by**: `/api` workspace and potentially other backend projects
|
||||
- **Key Modules**: Agents, MCP, tools, file handling, endpoints, authentication, caching, middleware
|
||||
- **Critical**: **All new backend logic should be coded here first and foremost for full TypeScript support**
|
||||
- **Depends on**: `@librechat/data-schemas`
|
||||
|
||||
#### `/packages/client` - `@librechat/client`
|
||||
- **Language**: TypeScript + React
|
||||
- **Purpose**: Reusable React components, hooks, and utilities
|
||||
- **Used by**: `/client` workspace and other LibreChat team frontend repositories
|
||||
- **Exports**: Common components, hooks, SVG icons, theme utilities, localization
|
||||
|
||||
#### `/packages/data-provider` - `librechat-data-provider`
|
||||
- **Language**: TypeScript
|
||||
- **Purpose**: **App-wide shared package** used by both frontend and backend
|
||||
- **Scope**: Universal - used everywhere
|
||||
- **Exports**: Data services, API endpoints, type definitions, utilities, React Query hooks
|
||||
- **Note**: Foundation package that all other workspaces depend on
|
||||
|
||||
#### `/packages/data-schemas` - `@librechat/data-schemas`
|
||||
- **Language**: TypeScript
|
||||
- **Purpose**: Backend-only schemas, models, and data validation
|
||||
- **Used by**: Backend workspaces only (`@librechat/api`, `/api`)
|
||||
- **Exports**: Mongoose models, Zod schemas, database utilities, configuration schemas
|
||||
|
||||
## Build System & Dependencies
|
||||
|
||||
### Build Order
|
||||
|
||||
The build system has a specific dependency chain that must be followed:
|
||||
|
||||
```bash
|
||||
# Full frontend build command:
|
||||
npm run frontend
|
||||
```
|
||||
|
||||
**Execution order:**
|
||||
1. `librechat-data-provider` - Foundation package (all depend on this)
|
||||
2. `@librechat/data-schemas` - Required by `@librechat/api`
|
||||
3. `@librechat/api` - Backend TypeScript package
|
||||
4. `@librechat/client` - Frontend shared components
|
||||
5. `/client` - Final frontend compilation
|
||||
|
||||
### Individual Build Commands
|
||||
|
||||
Packages can be built separately as needed:
|
||||
|
||||
```bash
|
||||
npm run build:data-provider # Build librechat-data-provider
|
||||
npm run build:data-schemas # Build @librechat/data-schemas
|
||||
npm run build:api # Build @librechat/api
|
||||
npm run build:client-package # Build @librechat/client
|
||||
npm run build:client # Build /client frontend app
|
||||
npm run build:packages # Build all packages (excludes /client app)
|
||||
```
|
||||
|
||||
**Note**: Not all packages need rebuilding for every change - only rebuild when files in that specific workspace are modified.
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Running Development Servers
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
npm run backend:dev # Runs /api workspace with nodemon
|
||||
|
||||
# Frontend
|
||||
npm run frontend:dev # Runs /client with Vite dev server
|
||||
|
||||
# Both (not recommended for active development)
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Where to Place New Code
|
||||
|
||||
#### Backend Logic
|
||||
- **Primary location**: `/packages/api/src/` - Full TypeScript support
|
||||
- **Legacy location**: `/api/` - Only for modifying existing CJS code
|
||||
- **Strategy**: Prefer `@librechat/api` for all new features, utilities, and services
|
||||
|
||||
#### Frontend Components
|
||||
- **Reusable components**: `/packages/client/src/components/`
|
||||
- **App-specific components**: `/client/src/components/`
|
||||
- **Strategy**: If it could be reused in other frontend projects, put it in `@librechat/client`
|
||||
|
||||
#### Shared Types & Utilities
|
||||
- **Universal (frontend + backend)**: `/packages/data-provider/src/`
|
||||
- **Backend-only**: `/packages/data-schemas/src/` or `/packages/api/src/`
|
||||
- **Frontend-only**: `/packages/client/src/`
|
||||
|
||||
#### Database Models & Schemas
|
||||
- **Always**: `/packages/data-schemas/src/models/` or `/packages/data-schemas/src/schema/`
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Backend
|
||||
- **Runtime**: Node.js
|
||||
- **Framework**: Express.js
|
||||
- **Database**: MongoDB with Mongoose ODM
|
||||
- **Authentication**: Passport.js (OAuth2, OpenID, LDAP, SAML, JWT)
|
||||
- **AI Integration**: LangChain, direct SDK integrations
|
||||
- **Streaming**: Server-Sent Events (SSE)
|
||||
|
||||
### Frontend
|
||||
- **Framework**: React 18
|
||||
- **Build Tool**: Vite
|
||||
- **State Management**: Recoil
|
||||
- **Styling**: TailwindCSS
|
||||
- **UI Components**: Radix UI, Headless UI
|
||||
- **Data Fetching**: TanStack Query (React Query)
|
||||
- **HTTP Client**: Axios
|
||||
|
||||
### Package Manager
|
||||
- **Primary**: npm (workspaces)
|
||||
- **Alternative**: pnpm (compatible), bun (experimental scripts available)
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
- `.env` - Local development (never commit)
|
||||
- `docker-compose.override.yml.example` - Example for Docker environment configuration
|
||||
- Validate on server startup
|
||||
|
||||
### librechat.yaml
|
||||
Main configuration for:
|
||||
- AI provider endpoints
|
||||
- Model configurations
|
||||
- Agent and tool settings
|
||||
- Authentication options
|
||||
|
||||
## Code Quality & Standards
|
||||
|
||||
### General Guidelines
|
||||
- Use TypeScript for all new code (especially in `packages/`)
|
||||
- Follow existing ESLint/Prettier configurations (formatting issues will be fixed manually)
|
||||
- Keep functions focused and modular
|
||||
- Handle errors appropriately with proper HTTP status codes
|
||||
|
||||
### File Naming
|
||||
- React components: `PascalCase.tsx` (e.g., `ChatInterface.tsx`)
|
||||
- Utilities: `camelCase.ts` (e.g., `formatMessage.ts`)
|
||||
- Test files: `*.spec.ts` or `*.test.ts`
|
||||
|
||||
## Key Architectural Patterns
|
||||
|
||||
### Multi-Provider Pattern
|
||||
Abstract AI provider implementations to support multiple services uniformly:
|
||||
- Provider services implement common interfaces
|
||||
- Handle streaming via SSE
|
||||
- Support both completion and chat endpoints
|
||||
|
||||
### Agent System
|
||||
- Built on LangChain
|
||||
- Agent definitions in `packages/api/src/agents/`
|
||||
- Tools in `packages/api/src/tools/`
|
||||
- MCP (Model Context Protocol) support in `packages/api/src/mcp/`
|
||||
|
||||
### Data Layer
|
||||
- `librechat-data-provider` provides unified data access
|
||||
- React Query for frontend data fetching
|
||||
- Backend services use Mongoose models from `@librechat/data-schemas`
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
npm run test:api # Backend tests
|
||||
npm run test:client # Frontend tests
|
||||
npm run e2e # Playwright E2E tests
|
||||
```
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Wrong workspace for backend code**: New backend logic belongs in `/packages/api`, not `/api`
|
||||
- The `/api` workspace is still necessary as it's used to run the Express.js server, but all new logic should be written in TypeScript in `/packages/api` as much as possible. Existing logic should also be converted to TypeScript if possible.
|
||||
2. **Build order matters**: Can't build `@librechat/api` before `@librechat/data-schemas`
|
||||
3. **Unnecessary rebuilds**: Only rebuild packages when their source files change
|
||||
4. **Import paths**: Use package names (`@librechat/api`) not relative paths across workspaces
|
||||
5. **TypeScript vs CJS**: `/api` is still CJS; use `packages/api` for TypeScript
|
||||
|
||||
## Getting Help
|
||||
|
||||
- **Documentation**: https://docs.librechat.ai
|
||||
- **Discord**: Active community support
|
||||
- **GitHub Issues**: Bug reports and feature requests
|
||||
- **Discussions**: General questions and ideas
|
||||
|
||||
---
|
||||
|
||||
**Remember**: The monorepo structure exists to enforce separation of concerns. Respect workspace boundaries and build dependencies. When in doubt about where code should live, consider:
|
||||
- Is it backend logic? → `packages/api/src/`
|
||||
- Is it a database model? → `packages/data-schemas/src/`
|
||||
- Is it shared between frontend/backend? → `packages/data-provider/src/`
|
||||
- Is it a reusable React component? → `packages/client/src/`
|
||||
- Is it app-specific UI? → `client/src/`
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"@langchain/google-genai": "^0.2.13",
|
||||
"@langchain/google-vertexai": "^0.2.13",
|
||||
"@langchain/textsplitters": "^0.1.0",
|
||||
"@librechat/agents": "^2.4.85",
|
||||
"@librechat/agents": "^2.4.86",
|
||||
"@librechat/api": "*",
|
||||
"@librechat/data-schemas": "*",
|
||||
"@microsoft/microsoft-graph-client": "^3.0.7",
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
"tailwindcss": "^3.4.1",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^6.3.6",
|
||||
"vite": "^6.4.1",
|
||||
"vite-plugin-compression2": "^2.2.1",
|
||||
"vite-plugin-node-polyfills": "^0.23.0",
|
||||
"vite-plugin-pwa": "^0.21.2"
|
||||
|
||||
@@ -11,9 +11,9 @@ import {
|
||||
AgentListResponse,
|
||||
} from 'librechat-data-provider';
|
||||
import type t from 'librechat-data-provider';
|
||||
import { renderAgentAvatar, clearMessagesCache } from '~/utils';
|
||||
import { useLocalize, useDefaultConvo } from '~/hooks';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import { renderAgentAvatar } from '~/utils';
|
||||
|
||||
interface SupportContact {
|
||||
name?: string;
|
||||
@@ -56,10 +56,7 @@ const AgentDetail: React.FC<AgentDetailProps> = ({ agent, isOpen, onClose }) =>
|
||||
|
||||
localStorage.setItem(`${LocalStorageKeys.AGENT_ID_PREFIX}0`, agent.id);
|
||||
|
||||
queryClient.setQueryData<t.TMessage[]>(
|
||||
[QueryKeys.messages, conversation?.conversationId ?? Constants.NEW_CONVO],
|
||||
[],
|
||||
);
|
||||
clearMessagesCache(queryClient, conversation?.conversationId);
|
||||
queryClient.invalidateQueries([QueryKeys.messages]);
|
||||
|
||||
/** Template with agent configuration */
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useOutletContext } from 'react-router-dom';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useSearchParams, useParams, useNavigate } from 'react-router-dom';
|
||||
import { TooltipAnchor, Button, NewChatIcon, useMediaQuery } from '@librechat/client';
|
||||
import { PermissionTypes, Permissions, QueryKeys, Constants } from 'librechat-data-provider';
|
||||
import { PermissionTypes, Permissions, QueryKeys } from 'librechat-data-provider';
|
||||
import type t from 'librechat-data-provider';
|
||||
import type { ContextType } from '~/common';
|
||||
import { useDocumentTitle, useHasAccess, useLocalize, TranslationKeys } from '~/hooks';
|
||||
@@ -13,11 +13,11 @@ import MarketplaceAdminSettings from './MarketplaceAdminSettings';
|
||||
import { SidePanelProvider, useChatContext } from '~/Providers';
|
||||
import { SidePanelGroup } from '~/components/SidePanel';
|
||||
import { OpenSidebar } from '~/components/Chat/Menus';
|
||||
import { cn, clearMessagesCache } from '~/utils';
|
||||
import CategoryTabs from './CategoryTabs';
|
||||
import AgentDetail from './AgentDetail';
|
||||
import SearchBar from './SearchBar';
|
||||
import AgentGrid from './AgentGrid';
|
||||
import { cn } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
interface AgentMarketplaceProps {
|
||||
@@ -224,10 +224,7 @@ const AgentMarketplace: React.FC<AgentMarketplaceProps> = ({ className = '' }) =
|
||||
window.open('/c/new', '_blank');
|
||||
return;
|
||||
}
|
||||
queryClient.setQueryData<t.TMessage[]>(
|
||||
[QueryKeys.messages, conversation?.conversationId ?? Constants.NEW_CONVO],
|
||||
[],
|
||||
);
|
||||
clearMessagesCache(queryClient, conversation?.conversationId);
|
||||
queryClient.invalidateQueries([QueryKeys.messages]);
|
||||
newConversation();
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { QueryKeys } from 'librechat-data-provider';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { QueryKeys, Constants } from 'librechat-data-provider';
|
||||
import { TooltipAnchor, Button, NewChatIcon } from '@librechat/client';
|
||||
import type { TMessage } from 'librechat-data-provider';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import { clearMessagesCache } from '~/utils';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
export default function HeaderNewChat() {
|
||||
@@ -15,10 +15,7 @@ export default function HeaderNewChat() {
|
||||
window.open('/c/new', '_blank');
|
||||
return;
|
||||
}
|
||||
queryClient.setQueryData<TMessage[]>(
|
||||
[QueryKeys.messages, conversation?.conversationId ?? Constants.NEW_CONVO],
|
||||
[],
|
||||
);
|
||||
clearMessagesCache(queryClient, conversation?.conversationId);
|
||||
queryClient.invalidateQueries([QueryKeys.messages]);
|
||||
newConversation();
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import { QueryKeys, Constants } from 'librechat-data-provider';
|
||||
import type { TMessage } from 'librechat-data-provider';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import { useLocalize, useNewConvo } from '~/hooks';
|
||||
import { clearMessagesCache } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
export default function MobileNav({
|
||||
@@ -57,10 +58,7 @@ export default function MobileNav({
|
||||
aria-label={localize('com_ui_new_chat')}
|
||||
className="m-1 inline-flex size-10 items-center justify-center rounded-full hover:bg-surface-hover"
|
||||
onClick={() => {
|
||||
queryClient.setQueryData<TMessage[]>(
|
||||
[QueryKeys.messages, conversation?.conversationId ?? Constants.NEW_CONVO],
|
||||
[],
|
||||
);
|
||||
clearMessagesCache(queryClient, conversation?.conversationId);
|
||||
queryClient.invalidateQueries([QueryKeys.messages]);
|
||||
newConversation();
|
||||
}}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { QueryKeys, Constants } from 'librechat-data-provider';
|
||||
import { TooltipAnchor, NewChatIcon, MobileSidebar, Sidebar, Button } from '@librechat/client';
|
||||
import type { TMessage } from 'librechat-data-provider';
|
||||
import { useLocalize, useNewConvo } from '~/hooks';
|
||||
import { clearMessagesCache } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
export default function NewChat({
|
||||
@@ -33,10 +34,7 @@ export default function NewChat({
|
||||
window.open('/c/new', '_blank');
|
||||
return;
|
||||
}
|
||||
queryClient.setQueryData<TMessage[]>(
|
||||
[QueryKeys.messages, conversation?.conversationId ?? Constants.NEW_CONVO],
|
||||
[],
|
||||
);
|
||||
clearMessagesCache(queryClient, conversation?.conversationId);
|
||||
queryClient.invalidateQueries([QueryKeys.messages]);
|
||||
newConvo();
|
||||
navigate('/c/new', { state: { focusChat: true } });
|
||||
|
||||
@@ -3,7 +3,13 @@ import { useNavigate } from 'react-router-dom';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { QueryKeys, Constants, dataService } from 'librechat-data-provider';
|
||||
import type { TConversation, TEndpointsConfig, TModelsConfig } from 'librechat-data-provider';
|
||||
import { buildDefaultConvo, getDefaultEndpoint, getEndpointField, logger } from '~/utils';
|
||||
import {
|
||||
getDefaultEndpoint,
|
||||
clearMessagesCache,
|
||||
buildDefaultConvo,
|
||||
getEndpointField,
|
||||
logger,
|
||||
} from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
const useNavigateToConvo = (index = 0) => {
|
||||
@@ -80,7 +86,7 @@ const useNavigateToConvo = (index = 0) => {
|
||||
});
|
||||
}
|
||||
clearAllConversations(true);
|
||||
queryClient.setQueryData([QueryKeys.messages, currentConvoId], []);
|
||||
clearMessagesCache(queryClient, currentConvoId);
|
||||
if (convo.conversationId !== Constants.NEW_CONVO && convo.conversationId) {
|
||||
queryClient.invalidateQueries([QueryKeys.conversation, convo.conversationId]);
|
||||
fetchFreshData(convo);
|
||||
|
||||
@@ -365,6 +365,7 @@
|
||||
"com_error_files_process": "处理文件时发生错误",
|
||||
"com_error_files_upload": "上传文件时发生错误",
|
||||
"com_error_files_upload_canceled": "文件上传请求已取消。注意:文件上传可能仍在进行中,需要手动删除。",
|
||||
"com_error_files_upload_too_large": "文件过大,请上传小于 {{0}} MB 的文件",
|
||||
"com_error_files_validation": "验证文件时出错。",
|
||||
"com_error_google_tool_conflict": "内置的 Google 工具与外部工具不兼容。请禁用内置工具或外部工具。",
|
||||
"com_error_heic_conversion": "将 HEIC 图片转换为 JPEG 失败。请尝试手动转换图像或使用其他格式。",
|
||||
@@ -560,6 +561,7 @@
|
||||
"com_nav_setting_balance": "余额",
|
||||
"com_nav_setting_chat": "对话",
|
||||
"com_nav_setting_data": "数据管理",
|
||||
"com_nav_setting_delay": "延迟(秒)",
|
||||
"com_nav_setting_general": "通用",
|
||||
"com_nav_setting_mcp": "MCP 设置",
|
||||
"com_nav_setting_personalization": "个性化",
|
||||
@@ -759,6 +761,7 @@
|
||||
"com_ui_client_secret": "Client Secret",
|
||||
"com_ui_close": "关闭",
|
||||
"com_ui_close_menu": "关闭菜单",
|
||||
"com_ui_close_settings": "关闭设置",
|
||||
"com_ui_close_window": "关闭窗口",
|
||||
"com_ui_code": "代码",
|
||||
"com_ui_collapse_chat": "收起对话",
|
||||
@@ -857,6 +860,7 @@
|
||||
"com_ui_edit_editing_image": "编辑图片",
|
||||
"com_ui_edit_mcp_server": "编辑 MCP 服务器",
|
||||
"com_ui_edit_memory": "编辑记忆",
|
||||
"com_ui_editor_instructions": "拖动图片调整位置 • 使用缩放滑块或按钮调整大小",
|
||||
"com_ui_empty_category": "-",
|
||||
"com_ui_endpoint": "端点",
|
||||
"com_ui_endpoint_menu": "LLM 端点菜单",
|
||||
@@ -891,6 +895,7 @@
|
||||
"com_ui_feedback_tag_unjustified_refusal": "无故拒绝回答",
|
||||
"com_ui_field_max_length": "{{field}} 最多 {{length}} 个字符",
|
||||
"com_ui_field_required": "此字段为必填项",
|
||||
"com_ui_file_input_avatar_label": "上传文件用作头像",
|
||||
"com_ui_file_size": "文件大小",
|
||||
"com_ui_file_token_limit": "文件词元数限制",
|
||||
"com_ui_file_token_limit_desc": "为文件处理设定最大词元数限制,以控制成本和资源使用",
|
||||
@@ -953,11 +958,13 @@
|
||||
"com_ui_import_conversation_file_type_error": "不支持的导入类型",
|
||||
"com_ui_import_conversation_info": "从 JSON 文件导入对话",
|
||||
"com_ui_import_conversation_success": "对话导入成功",
|
||||
"com_ui_import_conversation_upload_error": "上传文件时出错,请重试。",
|
||||
"com_ui_include_shadcnui": "包含 shadcn/ui 组件指令",
|
||||
"com_ui_initializing": "初始化中...",
|
||||
"com_ui_input": "输入",
|
||||
"com_ui_instructions": "指令",
|
||||
"com_ui_key": "键",
|
||||
"com_ui_key_required": "API Key 为必填项",
|
||||
"com_ui_late_night": "夜深了",
|
||||
"com_ui_latest_footer": "Every AI for Everyone.",
|
||||
"com_ui_latest_production_version": "最新在用版本",
|
||||
@@ -972,6 +979,7 @@
|
||||
"com_ui_manage": "管理",
|
||||
"com_ui_marketplace": "市场",
|
||||
"com_ui_marketplace_allow_use": "允许使用市场",
|
||||
"com_ui_max_file_size": "PNG、JPG 或 JPEG(最大 {{0}})",
|
||||
"com_ui_max_tags": "最多允许 {{0}} 个,用最新值。",
|
||||
"com_ui_mcp_authenticated_success": "MCP 服务器 “{{0}}” 认证成功",
|
||||
"com_ui_mcp_configure_server": "配置 {{0}}",
|
||||
@@ -1066,6 +1074,7 @@
|
||||
"com_ui_privacy_policy": "隐私政策",
|
||||
"com_ui_privacy_policy_url": "隐私政策链接",
|
||||
"com_ui_prompt": "提示词",
|
||||
"com_ui_prompt_groups": "提示词组列表",
|
||||
"com_ui_prompt_name": "提示词名称",
|
||||
"com_ui_prompt_name_required": "提示词名称为必填项",
|
||||
"com_ui_prompt_preview_not_shared": "作者未允许对此提示词进行协作。",
|
||||
@@ -1095,6 +1104,8 @@
|
||||
"com_ui_rename_failed": "重命名对话失败",
|
||||
"com_ui_rename_prompt": "重命名 Prompt",
|
||||
"com_ui_requires_auth": "需要认证",
|
||||
"com_ui_reset": "重置",
|
||||
"com_ui_reset_adjustments": "重置调整",
|
||||
"com_ui_reset_var": "重置 {{0}}",
|
||||
"com_ui_reset_zoom": "重置缩放",
|
||||
"com_ui_resource": "资源",
|
||||
@@ -1103,6 +1114,8 @@
|
||||
"com_ui_revoke_info": "撤销所有用户提供的凭据",
|
||||
"com_ui_revoke_key_confirm": "您确定要撤销此密钥吗?",
|
||||
"com_ui_revoke_key_endpoint": "撤销 {{0}} 的密钥",
|
||||
"com_ui_revoke_key_error": "撤销 API Key 失败,请重试。",
|
||||
"com_ui_revoke_key_success": "API Key 撤销成功",
|
||||
"com_ui_revoke_keys": "撤销密钥",
|
||||
"com_ui_revoke_keys_confirm": "您确定要撤销所有密钥吗?",
|
||||
"com_ui_role": "角色",
|
||||
@@ -1116,11 +1129,15 @@
|
||||
"com_ui_role_viewer": "查看者",
|
||||
"com_ui_role_viewer_desc": "可以查看和使用智能体,但无法修改智能体",
|
||||
"com_ui_roleplay": "角色扮演",
|
||||
"com_ui_rotate": "旋转",
|
||||
"com_ui_rotate_90": "旋转 90 度",
|
||||
"com_ui_run_code": "运行代码",
|
||||
"com_ui_run_code_error": "代码运行出错",
|
||||
"com_ui_save": "保存",
|
||||
"com_ui_save_badge_changes": "保存徽章更改?",
|
||||
"com_ui_save_changes": "保存修改",
|
||||
"com_ui_save_key_error": "保存 API Key 失败,请重试。",
|
||||
"com_ui_save_key_success": "API Key 保存成功",
|
||||
"com_ui_save_submit": "保存并提交",
|
||||
"com_ui_saved": "保存成功!",
|
||||
"com_ui_saving": "保存中...",
|
||||
@@ -1217,6 +1234,7 @@
|
||||
"com_ui_update_mcp_success": "已成功创建或更新 MCP",
|
||||
"com_ui_upload": "上传",
|
||||
"com_ui_upload_agent_avatar": "成功更新智能体头像",
|
||||
"com_ui_upload_avatar_label": "上传头像图片",
|
||||
"com_ui_upload_code_files": "上传代码解释器文件",
|
||||
"com_ui_upload_delay": "上传 “{{0}}” 时比预期花了更长时间。文件正在进行检索索引,请稍候。",
|
||||
"com_ui_upload_error": "上传文件错误",
|
||||
@@ -1228,6 +1246,7 @@
|
||||
"com_ui_upload_invalid": "上传的文件无效。必须是图片,且不得超过大小限制",
|
||||
"com_ui_upload_invalid_var": "上传的文件无效。必须是图片,且不得超过 {{0}} MB。",
|
||||
"com_ui_upload_ocr_text": "作为文本上传",
|
||||
"com_ui_upload_provider": "上传至提供商",
|
||||
"com_ui_upload_success": "上传文件成功",
|
||||
"com_ui_upload_type": "选择上传类型",
|
||||
"com_ui_usage": "用量",
|
||||
@@ -1267,6 +1286,8 @@
|
||||
"com_ui_web_search_scraper": "抓取器",
|
||||
"com_ui_web_search_scraper_firecrawl": "Firecrawl API",
|
||||
"com_ui_web_search_scraper_firecrawl_key": "获取您的 Firecrawl API Key",
|
||||
"com_ui_web_search_scraper_serper": "Serper Scrape API",
|
||||
"com_ui_web_search_scraper_serper_key": "获取您的 Serper API Key",
|
||||
"com_ui_web_search_searxng_api_key": "输入 SearXNG API Key(可选)",
|
||||
"com_ui_web_search_searxng_instance_url": "SearXNG 实例 URL",
|
||||
"com_ui_web_searching": "正在搜索网络",
|
||||
@@ -1276,5 +1297,8 @@
|
||||
"com_ui_x_selected": "{{0}} 已选择",
|
||||
"com_ui_yes": "是的",
|
||||
"com_ui_zoom": "缩放",
|
||||
"com_ui_zoom_in": "放大",
|
||||
"com_ui_zoom_level": "缩放级别",
|
||||
"com_ui_zoom_out": "缩小",
|
||||
"com_user_message": "您"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ContentTypes } from 'librechat-data-provider';
|
||||
import { ContentTypes, QueryKeys, Constants } from 'librechat-data-provider';
|
||||
import type { TMessage, TMessageContentParts } from 'librechat-data-provider';
|
||||
import type { QueryClient } from '@tanstack/react-query';
|
||||
|
||||
export const TEXT_KEY_DIVIDER = '|||';
|
||||
|
||||
@@ -146,3 +147,26 @@ export const scrollToEnd = (callback?: () => void) => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears messages for both the specified conversation ID and the NEW_CONVO query key.
|
||||
* This ensures that messages are properly cleared in all contexts, preventing stale data
|
||||
* from persisting in the NEW_CONVO cache.
|
||||
*
|
||||
* @param queryClient - The React Query client instance
|
||||
* @param conversationId - The conversation ID to clear messages for
|
||||
*/
|
||||
export const clearMessagesCache = (
|
||||
queryClient: QueryClient,
|
||||
conversationId: string | undefined | null,
|
||||
): void => {
|
||||
const convoId = conversationId ?? Constants.NEW_CONVO;
|
||||
|
||||
// Clear messages for the current conversation
|
||||
queryClient.setQueryData<TMessage[]>([QueryKeys.messages, convoId], []);
|
||||
|
||||
// Also clear NEW_CONVO messages if we're not already on NEW_CONVO
|
||||
if (convoId !== Constants.NEW_CONVO) {
|
||||
queryClient.setQueryData<TMessage[]>([QueryKeys.messages, Constants.NEW_CONVO], []);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import react from '@vitejs/plugin-react';
|
||||
// @ts-ignore
|
||||
import path from 'path';
|
||||
import type { Plugin } from 'vite';
|
||||
import { defineConfig } from 'vite';
|
||||
@@ -7,19 +8,23 @@ import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
||||
import { VitePWA } from 'vite-plugin-pwa';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
const backendPort = process.env.BACKEND_PORT && Number(process.env.BACKEND_PORT) || 3080;
|
||||
const backendURL = process.env.HOST ? `http://${process.env.HOST}:${backendPort}` : `http://localhost:${backendPort}`;
|
||||
|
||||
export default defineConfig(({ command }) => ({
|
||||
base: '',
|
||||
server: {
|
||||
host: 'localhost',
|
||||
port: 3090,
|
||||
allowedHosts: process.env.VITE_ALLOWED_HOSTS && process.env.VITE_ALLOWED_HOSTS.split(',') || [],
|
||||
host: process.env.HOST || 'localhost',
|
||||
port: process.env.PORT && Number(process.env.PORT) || 3090,
|
||||
strictPort: false,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:3080',
|
||||
target: backendURL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/oauth': {
|
||||
target: 'http://localhost:3080',
|
||||
target: backendURL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
@@ -259,6 +264,7 @@ export default defineConfig(({ command }) => ({
|
||||
interface SourcemapExclude {
|
||||
excludeNodeModules?: boolean;
|
||||
}
|
||||
|
||||
export function sourcemapExclude(opts?: SourcemapExclude): Plugin {
|
||||
return {
|
||||
name: 'sourcemap-exclude',
|
||||
|
||||
145
package-lock.json
generated
145
package-lock.json
generated
@@ -19,7 +19,7 @@
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.20.0",
|
||||
"@microsoft/eslint-formatter-sarif": "^3.1.0",
|
||||
"@playwright/test": "^1.50.1",
|
||||
"@playwright/test": "^1.56.1",
|
||||
"@types/react-virtualized": "^9.22.0",
|
||||
"caniuse-lite": "^1.0.30001741",
|
||||
"cross-env": "^7.0.3",
|
||||
@@ -64,7 +64,7 @@
|
||||
"@langchain/google-genai": "^0.2.13",
|
||||
"@langchain/google-vertexai": "^0.2.13",
|
||||
"@langchain/textsplitters": "^0.1.0",
|
||||
"@librechat/agents": "^2.4.85",
|
||||
"@librechat/agents": "^2.4.86",
|
||||
"@librechat/api": "*",
|
||||
"@librechat/data-schemas": "*",
|
||||
"@microsoft/microsoft-graph-client": "^3.0.7",
|
||||
@@ -2768,7 +2768,7 @@
|
||||
"tailwindcss": "^3.4.1",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^6.3.6",
|
||||
"vite": "^6.4.1",
|
||||
"vite-plugin-compression2": "^2.2.1",
|
||||
"vite-plugin-node-polyfills": "^0.23.0",
|
||||
"vite-plugin-pwa": "^0.21.2"
|
||||
@@ -4305,6 +4305,24 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"client/node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"client/node_modules/framer-motion": {
|
||||
"version": "11.18.2",
|
||||
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz",
|
||||
@@ -4358,6 +4376,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"client/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"client/node_modules/react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
@@ -4453,6 +4484,81 @@
|
||||
"browserslist": ">= 4.21.0"
|
||||
}
|
||||
},
|
||||
"client/node_modules/vite": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
|
||||
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2",
|
||||
"postcss": "^8.5.3",
|
||||
"rollup": "^4.34.9",
|
||||
"tinyglobby": "^0.2.13"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
|
||||
"jiti": ">=1.21.0",
|
||||
"less": "*",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"sass-embedded": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"terser": "^5.16.0",
|
||||
"tsx": "^4.8.1",
|
||||
"yaml": "^2.4.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"jiti": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"lightningcss": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"sass-embedded": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
},
|
||||
"tsx": {
|
||||
"optional": true
|
||||
},
|
||||
"yaml": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"client/node_modules/vite-plugin-pwa": {
|
||||
"version": "0.21.2",
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.21.2.tgz",
|
||||
@@ -21531,9 +21637,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@librechat/agents": {
|
||||
"version": "2.4.85",
|
||||
"resolved": "https://registry.npmjs.org/@librechat/agents/-/agents-2.4.85.tgz",
|
||||
"integrity": "sha512-t6h5f6ApnoEC+x8kqBlke1RR6BPzT+9BvlkA8VxvQVJtYIt5Ey4BOTRDGjdilDoXUcLui11PbjCd17EbjPkTcA==",
|
||||
"version": "2.4.86",
|
||||
"resolved": "https://registry.npmjs.org/@librechat/agents/-/agents-2.4.86.tgz",
|
||||
"integrity": "sha512-Z3v+vMfFEyrDWrlPvgY9dUlhzYvtLXYYULEzkxUM1QpITuI3DsXr3xb1kXHAYOx3NmBGxiN9R/gjZN0tGBEo1g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@langchain/anthropic": "^0.3.26",
|
||||
@@ -22902,12 +23008,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz",
|
||||
"integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==",
|
||||
"version": "1.56.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz",
|
||||
"integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright": "1.50.1"
|
||||
"playwright": "1.56.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -43042,12 +43148,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.50.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz",
|
||||
"integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==",
|
||||
"version": "1.56.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
|
||||
"integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.50.1"
|
||||
"playwright-core": "1.56.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -43060,9 +43166,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.50.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz",
|
||||
"integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==",
|
||||
"version": "1.56.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
|
||||
"integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
@@ -49973,6 +50079,7 @@
|
||||
"integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
@@ -50076,6 +50183,7 @@
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
@@ -50094,6 +50202,7 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -51337,7 +51446,7 @@
|
||||
"@azure/storage-blob": "^12.27.0",
|
||||
"@keyv/redis": "^4.3.3",
|
||||
"@langchain/core": "^0.3.62",
|
||||
"@librechat/agents": "^2.4.85",
|
||||
"@librechat/agents": "^2.4.86",
|
||||
"@librechat/data-schemas": "*",
|
||||
"@modelcontextprotocol/sdk": "^1.17.1",
|
||||
"axios": "^1.12.1",
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.20.0",
|
||||
"@microsoft/eslint-formatter-sarif": "^3.1.0",
|
||||
"@playwright/test": "^1.50.1",
|
||||
"@playwright/test": "^1.56.1",
|
||||
"@types/react-virtualized": "^9.22.0",
|
||||
"caniuse-lite": "^1.0.30001741",
|
||||
"cross-env": "^7.0.3",
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
"@azure/storage-blob": "^12.27.0",
|
||||
"@keyv/redis": "^4.3.3",
|
||||
"@langchain/core": "^0.3.62",
|
||||
"@librechat/agents": "^2.4.85",
|
||||
"@librechat/agents": "^2.4.86",
|
||||
"@librechat/data-schemas": "*",
|
||||
"@modelcontextprotocol/sdk": "^1.17.1",
|
||||
"axios": "^1.12.1",
|
||||
|
||||
Reference in New Issue
Block a user