mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 06:00:56 +02:00
✨ v0.7.5-rc2 (#3976)
* ✨ v0.7.5-rc2
* docs: update README
* refactor(settings): Update rememberForkOption default value
* a11y: proper screen reader announcements for content blocks
* Update version to 0.7.423 in package-lock.json and packages/data-provider/package.json
* chore: rename rememberForkOption -> rememberDefaultFork to apply new default value
* fix: headlessui menu stealing focus from Settings Dialog when pressing Enter
This commit is contained in:
parent
d6c0121b19
commit
020995514e
23 changed files with 92 additions and 43 deletions
|
@ -1,4 +1,4 @@
|
|||
# v0.7.5-rc1
|
||||
# v0.7.5-rc2
|
||||
|
||||
# Base node image
|
||||
FROM node:20-alpine AS node
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Dockerfile.multi
|
||||
# v0.7.5-rc1
|
||||
# v0.7.5-rc2
|
||||
|
||||
# Base for all builds
|
||||
FROM node:20-alpine AS base
|
||||
|
|
|
@ -42,10 +42,10 @@
|
|||
|
||||
- 🖥️ UI matching ChatGPT, including Dark mode, Streaming, and latest updates
|
||||
- 🤖 AI model selection:
|
||||
- OpenAI, Azure OpenAI, BingAI, ChatGPT, Google Vertex AI, Anthropic (Claude), Plugins, Assistants API (including Azure Assistants)
|
||||
- Anthropic (Claude), AWS Bedrock, OpenAI, Azure OpenAI, BingAI, ChatGPT, Google Vertex AI, Plugins, Assistants API (including Azure Assistants)
|
||||
- ✅ Compatible across both **[Remote & Local AI services](https://www.librechat.ai/docs/configuration/librechat_yaml/ai_endpoints):**
|
||||
- groq, Ollama, Cohere, Mistral AI, Apple MLX, koboldcpp, OpenRouter, together.ai, Perplexity, ShuttleAI, and more
|
||||
- 🪄 Generative UI with [Code Artifacts](https://youtu.be/GfTj7O4gmd0?si=WJbdnemZpJzBrJo3)
|
||||
- 🪄 Generative UI with **[Code Artifacts](https://youtu.be/GfTj7O4gmd0?si=WJbdnemZpJzBrJo3)**
|
||||
- Create React, HTML code, and Mermaid diagrams right in chat
|
||||
- 💾 Create, Save, & Share Custom Presets
|
||||
- 🔀 Switch between AI Endpoints and Presets, mid-chat
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@librechat/backend",
|
||||
"version": "v0.7.5-rc1",
|
||||
"version": "v0.7.5-rc2",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"start": "echo 'please run this from the root directory'",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@librechat/frontend",
|
||||
"version": "v0.7.5-rc1",
|
||||
"version": "v0.7.5-rc2",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
// AnnouncerContext.tsx
|
||||
import React from 'react';
|
||||
|
||||
export interface AnnounceOptions {
|
||||
message: string;
|
||||
isStatus?: boolean;
|
||||
}
|
||||
import type { AnnounceOptions } from '~/common';
|
||||
|
||||
interface AnnouncerContextType {
|
||||
announceAssertive: (options: AnnounceOptions) => void;
|
||||
|
|
6
client/src/common/a11y.ts
Normal file
6
client/src/common/a11y.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
export interface AnnounceOptions {
|
||||
message: string;
|
||||
isStatus?: boolean;
|
||||
}
|
||||
|
||||
export const MESSAGE_UPDATE_INTERVAL = 7000;
|
|
@ -1,3 +1,4 @@
|
|||
export * from './a11y';
|
||||
export * from './artifacts';
|
||||
export * from './types';
|
||||
export * from './assistants-types';
|
||||
|
|
|
@ -116,7 +116,7 @@ export default function Fork({
|
|||
const [forkSetting, setForkSetting] = useRecoilState(store.forkSetting);
|
||||
const [activeSetting, setActiveSetting] = useState(optionLabels.default);
|
||||
const [splitAtTarget, setSplitAtTarget] = useRecoilState(store.splitAtTarget);
|
||||
const [rememberGlobal, setRememberGlobal] = useRecoilState(store.rememberForkOption);
|
||||
const [rememberGlobal, setRememberGlobal] = useRecoilState(store.rememberDefaultFork);
|
||||
const forkConvo = useForkConvoMutation({
|
||||
onSuccess: (data) => {
|
||||
if (data) {
|
||||
|
|
|
@ -120,7 +120,9 @@ function AccountSettings() {
|
|||
className={focus ? 'bg-surface-hover' : ''}
|
||||
svg={() => <GearIcon className="icon-md" />}
|
||||
text={localize('com_nav_settings')}
|
||||
clickHandler={() => setShowSettings(true)}
|
||||
clickHandler={() => {
|
||||
setTimeout(() => setShowSettings(true), 50);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</MenuItem>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { FC, forwardRef } from 'react';
|
||||
import React, { FC, forwardRef } from 'react';
|
||||
import { cn } from '~/utils/';
|
||||
|
||||
interface Props {
|
||||
svg: () => JSX.Element;
|
||||
text: string;
|
||||
clickHandler?: () => void;
|
||||
clickHandler?: React.MouseEventHandler<HTMLButtonElement>;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ const NavLink: FC<Props> = forwardRef<HTMLButtonElement, Props>((props, ref) =>
|
|||
const { svg, text, clickHandler, disabled, className = '' } = props;
|
||||
const defaultProps: {
|
||||
className: string;
|
||||
onClick?: () => void;
|
||||
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
||||
} = {
|
||||
className: cn(
|
||||
'w-full flex gap-2 rounded p-2.5 text-sm cursor-pointer group items-center transition-colors duration-200 text-text-primary hover:bg-surface-hover',
|
||||
|
|
|
@ -9,7 +9,7 @@ export const ForkSettings = () => {
|
|||
const localize = useLocalize();
|
||||
const [forkSetting, setForkSetting] = useRecoilState(store.forkSetting);
|
||||
const [splitAtTarget, setSplitAtTarget] = useRecoilState(store.splitAtTarget);
|
||||
const [remember, setRemember] = useRecoilState<boolean>(store.rememberForkOption);
|
||||
const [remember, setRemember] = useRecoilState<boolean>(store.rememberDefaultFork);
|
||||
|
||||
const forkOptions = [
|
||||
{ value: ForkOptions.DIRECT_PATH, label: localize('com_ui_fork_visible') },
|
||||
|
@ -39,11 +39,11 @@ export const ForkSettings = () => {
|
|||
<div className="flex items-center justify-between">
|
||||
<div> {localize('com_ui_fork_default')} </div>
|
||||
<Switch
|
||||
id="rememberForkOption"
|
||||
id="rememberDefaultFork"
|
||||
checked={remember}
|
||||
onCheckedChange={setRemember}
|
||||
className="ml-4 mt-2"
|
||||
data-testid="rememberForkOption"
|
||||
data-testid="rememberDefaultFork"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -23,6 +23,7 @@ import type { TGenTitleMutation } from '~/data-provider';
|
|||
import {
|
||||
scrollToEnd,
|
||||
addConversation,
|
||||
getAllContentText,
|
||||
deleteConversation,
|
||||
updateConversation,
|
||||
getConversationById,
|
||||
|
@ -30,6 +31,7 @@ import {
|
|||
import useContentHandler from '~/hooks/SSE/useContentHandler';
|
||||
import useStepHandler from '~/hooks/SSE/useStepHandler';
|
||||
import { useAuthContext } from '~/hooks/AuthContext';
|
||||
import { MESSAGE_UPDATE_INTERVAL } from '~/common';
|
||||
import { useLiveAnnouncer } from '~/Providers';
|
||||
import store from '~/store';
|
||||
|
||||
|
@ -55,8 +57,6 @@ export type EventHandlerParams = {
|
|||
resetLatestMessage?: Resetter;
|
||||
};
|
||||
|
||||
const MESSAGE_UPDATE_INTERVAL = 7000;
|
||||
|
||||
export default function useEventHandlers({
|
||||
genTitle,
|
||||
setMessages,
|
||||
|
@ -78,7 +78,13 @@ export default function useEventHandlers({
|
|||
const { token } = useAuthContext();
|
||||
|
||||
const contentHandler = useContentHandler({ setMessages, getMessages });
|
||||
const stepHandler = useStepHandler({ setMessages, getMessages });
|
||||
const stepHandler = useStepHandler({
|
||||
setMessages,
|
||||
getMessages,
|
||||
announcePolite,
|
||||
setIsSubmitting,
|
||||
lastAnnouncementTimeRef,
|
||||
});
|
||||
|
||||
const messageHandler = useCallback(
|
||||
(data: string | undefined, submission: EventSubmission) => {
|
||||
|
@ -356,7 +362,7 @@ export default function useEventHandlers({
|
|||
});
|
||||
|
||||
announcePolite({
|
||||
message: responseMessage?.text ?? '',
|
||||
message: getAllContentText(responseMessage),
|
||||
});
|
||||
|
||||
/* Update messages; if assistants endpoint, client doesn't receive responseMessage */
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
import { useCallback, useRef } from 'react';
|
||||
import { StepTypes, ContentTypes, ToolCallTypes } from 'librechat-data-provider';
|
||||
import { StepTypes, ContentTypes, ToolCallTypes, getNonEmptyValue } from 'librechat-data-provider';
|
||||
import type {
|
||||
Agents,
|
||||
PartMetadata,
|
||||
TMessage,
|
||||
TMessageContentParts,
|
||||
PartMetadata,
|
||||
EventSubmission,
|
||||
TMessageContentParts,
|
||||
} from 'librechat-data-provider';
|
||||
import { getNonEmptyValue } from 'librechat-data-provider';
|
||||
import type { SetterOrUpdater } from 'recoil';
|
||||
import type { AnnounceOptions } from '~/common';
|
||||
import { MESSAGE_UPDATE_INTERVAL } from '~/common';
|
||||
|
||||
type TUseStepHandler = {
|
||||
announcePolite: (options: AnnounceOptions) => void;
|
||||
setMessages: (messages: TMessage[]) => void;
|
||||
getMessages: () => TMessage[] | undefined;
|
||||
setIsSubmitting: SetterOrUpdater<boolean>;
|
||||
lastAnnouncementTimeRef: React.MutableRefObject<number>;
|
||||
};
|
||||
|
||||
type TStepEvent = {
|
||||
|
@ -28,7 +33,13 @@ type AllContentTypes =
|
|||
| ContentTypes.IMAGE_URL
|
||||
| ContentTypes.ERROR;
|
||||
|
||||
export default function useStepHandler({ setMessages, getMessages }: TUseStepHandler) {
|
||||
export default function useStepHandler({
|
||||
setMessages,
|
||||
getMessages,
|
||||
setIsSubmitting,
|
||||
announcePolite,
|
||||
lastAnnouncementTimeRef,
|
||||
}: TUseStepHandler) {
|
||||
const toolCallIdMap = useRef(new Map<string, string | undefined>());
|
||||
const messageMap = useRef(new Map<string, TMessage>());
|
||||
const stepMap = useRef(new Map<string, Agents.RunStep>());
|
||||
|
@ -112,6 +123,13 @@ export default function useStepHandler({ setMessages, getMessages }: TUseStepHan
|
|||
({ event, data }: TStepEvent, submission: EventSubmission) => {
|
||||
const messages = getMessages() || [];
|
||||
const { userMessage } = submission;
|
||||
setIsSubmitting(true);
|
||||
|
||||
const currentTime = Date.now();
|
||||
if (currentTime - lastAnnouncementTimeRef.current > MESSAGE_UPDATE_INTERVAL) {
|
||||
announcePolite({ message: 'composing', isStatus: true });
|
||||
lastAnnouncementTimeRef.current = currentTime;
|
||||
}
|
||||
|
||||
if (event === 'on_run_step') {
|
||||
const runStep = data as Agents.RunStep;
|
||||
|
@ -249,6 +267,6 @@ export default function useStepHandler({ setMessages, getMessages }: TUseStepHan
|
|||
stepMap.current.clear();
|
||||
};
|
||||
},
|
||||
[getMessages, stepMap, messageMap, setMessages, toolCallIdMap],
|
||||
[getMessages, setIsSubmitting, lastAnnouncementTimeRef, announcePolite, setMessages],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { atom } from 'recoil';
|
||||
import { SettingsViews } from 'librechat-data-provider';
|
||||
import { SettingsViews, LocalStorageKeys } from 'librechat-data-provider';
|
||||
import { atomWithLocalStorage } from '~/store/utils';
|
||||
import type { TOptionSettings } from '~/common';
|
||||
|
||||
|
@ -32,7 +32,7 @@ const localStorageAtoms = {
|
|||
forkSetting: atomWithLocalStorage('forkSetting', ''),
|
||||
splitAtTarget: atomWithLocalStorage('splitAtTarget', false),
|
||||
|
||||
rememberForkOption: atomWithLocalStorage('rememberForkOption', true),
|
||||
rememberDefaultFork: atomWithLocalStorage(LocalStorageKeys.REMEMBER_FORK_OPTION, false),
|
||||
|
||||
// Beta features settings
|
||||
modularChat: atomWithLocalStorage('modularChat', true),
|
||||
|
|
|
@ -40,6 +40,26 @@ export const getLatestText = (message?: TMessage | null, includeIndex?: boolean)
|
|||
return '';
|
||||
};
|
||||
|
||||
export const getAllContentText = (message?: TMessage | null): string => {
|
||||
if (!message) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (message.text) {
|
||||
return message.text;
|
||||
}
|
||||
|
||||
if (message.content && message.content.length > 0) {
|
||||
return message.content
|
||||
.filter((part) => part.type === ContentTypes.TEXT)
|
||||
.map((part) => (typeof part.text === 'string' ? part.text : part.text.value) ?? '')
|
||||
.filter((text) => text.length > 0)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
export const getTextKey = (message?: TMessage | null, convoId?: string | null) => {
|
||||
if (!message) {
|
||||
return '';
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
// v0.7.5-rc1
|
||||
// v0.7.5-rc2
|
||||
// See .env.test.example for an example of the '.env.test' file.
|
||||
require('dotenv').config({ path: './e2e/.env.test' });
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<!-- v0.7.5-rc1 -->
|
||||
<!-- v0.7.5-rc2 -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
|
10
package-lock.json
generated
10
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "LibreChat",
|
||||
"version": "v0.7.5-rc1",
|
||||
"version": "v0.7.5-rc2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "LibreChat",
|
||||
"version": "v0.7.5-rc1",
|
||||
"version": "v0.7.5-rc2",
|
||||
"license": "ISC",
|
||||
"workspaces": [
|
||||
"api",
|
||||
|
@ -40,7 +40,7 @@
|
|||
},
|
||||
"api": {
|
||||
"name": "@librechat/backend",
|
||||
"version": "v0.7.5-rc1",
|
||||
"version": "v0.7.5-rc2",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.16.1",
|
||||
|
@ -1220,7 +1220,7 @@
|
|||
},
|
||||
"client": {
|
||||
"name": "@librechat/frontend",
|
||||
"version": "v0.7.5-rc1",
|
||||
"version": "v0.7.5-rc2",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@ariakit/react": "^0.4.8",
|
||||
|
@ -36399,7 +36399,7 @@
|
|||
},
|
||||
"packages/data-provider": {
|
||||
"name": "librechat-data-provider",
|
||||
"version": "0.7.422",
|
||||
"version": "0.7.423",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "LibreChat",
|
||||
"version": "v0.7.5-rc1",
|
||||
"version": "v0.7.5-rc2",
|
||||
"description": "",
|
||||
"workspaces": [
|
||||
"api",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "librechat-data-provider",
|
||||
"version": "0.7.422",
|
||||
"version": "0.7.423",
|
||||
"description": "data services for librechat apps",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.es.js",
|
||||
|
|
|
@ -1060,7 +1060,7 @@ export enum TTSProviders {
|
|||
/** Enum for app-wide constants */
|
||||
export enum Constants {
|
||||
/** Key for the app's version. */
|
||||
VERSION = 'v0.7.5-rc1',
|
||||
VERSION = 'v0.7.5-rc2',
|
||||
/** Key for the Custom Config's version (librechat.yaml). */
|
||||
CONFIG_VERSION = '1.1.7',
|
||||
/** Standard value for the first message's `parentMessageId` value, to indicate no parent exists. */
|
||||
|
@ -1107,7 +1107,7 @@ export enum LocalStorageKeys {
|
|||
/** Key for the last selected fork setting */
|
||||
FORK_SETTING = 'forkSetting',
|
||||
/** Key for remembering the last selected option, instead of manually selecting */
|
||||
REMEMBER_FORK_OPTION = 'rememberForkOption',
|
||||
REMEMBER_FORK_OPTION = 'rememberDefaultFork',
|
||||
/** Key for remembering the split at target fork option modifier */
|
||||
FORK_SPLIT_AT_TARGET = 'splitAtTarget',
|
||||
/** Key for saving text drafts */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// v0.7.5-rc1
|
||||
// v0.7.5-rc2
|
||||
module.exports = {
|
||||
tailwindConfig: './client/tailwind.config.cjs',
|
||||
printWidth: 100,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue