feat: Support for Chat Flow & Agent Support for binding a single chat flow (#765)
Co-authored-by: Yu Yang <72337138+tomasyu985@users.noreply.github.com> Co-authored-by: zengxiaohui <csu.zengxiaohui@gmail.com> Co-authored-by: lijunwen.gigoo <lijunwen.gigoo@bytedance.com> Co-authored-by: lvxinyu.1117 <lvxinyu.1117@bytedance.com> Co-authored-by: liuyunchao.0510 <liuyunchao.0510@bytedance.com> Co-authored-by: haozhenfei <37089575+haozhenfei@users.noreply.github.com> Co-authored-by: July <jiangxujin@bytedance.com> Co-authored-by: tecvan-fe <fanwenjie.fe@bytedance.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type PropsWithChildren } from 'react';
|
||||
import { forwardRef, type PropsWithChildren } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
@@ -25,14 +25,16 @@ interface ActionBarHoverContainerProps {
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export const ActionBarHoverContainer: React.FC<
|
||||
export const ActionBarHoverContainer = forwardRef<
|
||||
HTMLDivElement,
|
||||
PropsWithChildren<ActionBarHoverContainerProps>
|
||||
> = ({ children, style }) => (
|
||||
>(({ children, style }, ref) => (
|
||||
<div
|
||||
data-testid="chat-area.answer-action.hover-action-bar"
|
||||
className={classNames(s.container, ['coz-stroke-primary', 'coz-bg-max'])}
|
||||
style={style}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
));
|
||||
|
||||
@@ -34,15 +34,27 @@ import { useTooltipTrigger } from '../../hooks/use-tooltip-trigger';
|
||||
type CopyTextMessageProps = Omit<
|
||||
ComponentProps<typeof IconButton>,
|
||||
'icon' | 'iconSize' | 'onClick'
|
||||
>;
|
||||
> & {
|
||||
isMustGroupLastAnswerMessage?: boolean;
|
||||
isUseExternalContent?: boolean;
|
||||
externalContent?: string;
|
||||
};
|
||||
|
||||
export const CopyTextMessage: React.FC<
|
||||
PropsWithChildren<CopyTextMessageProps>
|
||||
> = ({ className, ...props }) => {
|
||||
> = ({
|
||||
className,
|
||||
isMustGroupLastAnswerMessage = true,
|
||||
isUseExternalContent = false,
|
||||
externalContent,
|
||||
...props
|
||||
}) => {
|
||||
const { reporter } = useChatArea();
|
||||
const { message, meta } = useMessageBoxContext();
|
||||
|
||||
const { content } = message;
|
||||
const content = isUseExternalContent
|
||||
? externalContent || ''
|
||||
: message.content;
|
||||
|
||||
const [isCopySuccessful, setIsCopySuccessful] = useState<boolean>(false);
|
||||
const trigger = useTooltipTrigger('hover');
|
||||
@@ -87,7 +99,7 @@ export const CopyTextMessage: React.FC<
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!meta.isGroupLastAnswerMessage) {
|
||||
if (!meta.isGroupLastAnswerMessage && isMustGroupLastAnswerMessage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./tsconfig.build.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"declaration": false,
|
||||
"declarationMap": false,
|
||||
"sourceMap": false,
|
||||
"outDir": null,
|
||||
"tsBuildInfoFile": null
|
||||
},
|
||||
"exclude": ["dist", "node_modules", "__tests__"]
|
||||
}
|
||||
@@ -9,6 +9,9 @@
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.misc.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.dev.json"
|
||||
}
|
||||
],
|
||||
"exclude": ["**/*"]
|
||||
|
||||
@@ -222,6 +222,7 @@ export const ChatArea = forwardRef<ChatAreaRef, ChatAreaProps>((props, ref) => {
|
||||
selectable,
|
||||
showClearContextDivider,
|
||||
messageWidth,
|
||||
messageMaxWidth,
|
||||
readonly,
|
||||
uiKitChatInputButtonConfig,
|
||||
uikitChatInputButtonStatus,
|
||||
@@ -237,6 +238,7 @@ export const ChatArea = forwardRef<ChatAreaRef, ChatAreaProps>((props, ref) => {
|
||||
isOnboardingCentered,
|
||||
fileLimit,
|
||||
stopRespondOverrideWaiting,
|
||||
isMiniScreen,
|
||||
} = props;
|
||||
const getScrollViewRef = useRef<() => ScrollViewController>(null);
|
||||
const {
|
||||
@@ -278,6 +280,7 @@ export const ChatArea = forwardRef<ChatAreaRef, ChatAreaProps>((props, ref) => {
|
||||
enableSelectOnboarding,
|
||||
showClearContextDivider,
|
||||
messageWidth,
|
||||
messageMaxWidth,
|
||||
readonly: readonly || isClearMessageHistoryLock,
|
||||
uiKitChatInputButtonConfig,
|
||||
theme,
|
||||
@@ -304,6 +307,7 @@ export const ChatArea = forwardRef<ChatAreaRef, ChatAreaProps>((props, ref) => {
|
||||
onboardingSuggestionsShowMode,
|
||||
showBackground,
|
||||
stopRespondOverrideWaiting,
|
||||
isMiniScreen,
|
||||
}}
|
||||
>
|
||||
<ChatAreaMain
|
||||
|
||||
@@ -28,13 +28,6 @@ import {
|
||||
|
||||
import { nanoid } from 'nanoid';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
useUIKitCustomComponent,
|
||||
ChatInput as UIKitChatInput,
|
||||
type InputRefObject,
|
||||
} from '@coze-common/chat-uikit';
|
||||
import { safeAsyncThrow } from '@coze-common/chat-area-utils';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
type IChatInputProps,
|
||||
UploadType,
|
||||
@@ -42,6 +35,13 @@ import {
|
||||
MAX_FILE_MBYTE,
|
||||
Layout,
|
||||
} from '@coze-common/chat-uikit-shared';
|
||||
import {
|
||||
useUIKitCustomComponent,
|
||||
ChatInput as UIKitChatInput,
|
||||
type InputRefObject,
|
||||
} from '@coze-common/chat-uikit';
|
||||
import { safeAsyncThrow } from '@coze-common/chat-area-utils';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { BatchUploadFileList } from '../batch-upload-file-list';
|
||||
import { getSendMultimodalMessageStrategy } from '../../utils/message';
|
||||
@@ -158,6 +158,7 @@ export const ChatInput: <T extends OverrideProps>(
|
||||
wrapperClassName,
|
||||
inputNativeCallbacks,
|
||||
safeAreaClassName,
|
||||
...restInputProps
|
||||
} = useChatInputProps();
|
||||
|
||||
const showBackground = useShowBackGround();
|
||||
@@ -395,6 +396,7 @@ export const ChatInput: <T extends OverrideProps>(
|
||||
showBackground={showBackground}
|
||||
limitFileCount={fileLimit}
|
||||
onPaste={handlePaste}
|
||||
{...restInputProps}
|
||||
{...componentProps}
|
||||
/>
|
||||
<div
|
||||
|
||||
@@ -39,6 +39,7 @@ import { usePreference } from '../../../context/preference';
|
||||
import s from './index.module.less';
|
||||
|
||||
import './index.less';
|
||||
import { usePluginCustomComponents } from '../../../plugin/hooks/use-plugin-custom-components';
|
||||
|
||||
const BuiltinMessageGroupWrapper: ComponentTypesMap['messageGroupWrapper'] = ({
|
||||
children,
|
||||
@@ -135,6 +136,18 @@ export const MessageGroupWrapper: React.FC<
|
||||
|
||||
const showContextDividerWithOnboarding =
|
||||
showClearContextDividerByPreference && showContextDivider;
|
||||
const customMessageGroupFooterPlugin =
|
||||
usePluginCustomComponents('MessageGroupFooter').at(0);
|
||||
const renderFooter = () => {
|
||||
const usedFooter = customMessageGroupFooterPlugin;
|
||||
|
||||
if (!usedFooter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { Component } = usedFooter;
|
||||
return <Component messageGroup={messageGroup} />;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -152,6 +165,7 @@ export const MessageGroupWrapper: React.FC<
|
||||
isSendingMessage={isSendingMessage}
|
||||
messageGroup={messageGroup}
|
||||
>
|
||||
{renderFooter?.()}
|
||||
{isLatest ? (
|
||||
<>
|
||||
{!showContextDividerWithOnboarding && <SuggestionInChat />}
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
import { type MouseEvent } from 'react';
|
||||
|
||||
import {
|
||||
type IEventCallbacks,
|
||||
type IOnLinkClickParams,
|
||||
} from '@coze-common/chat-uikit-shared';
|
||||
import { type MessageBoxTheme } from '@coze-common/chat-uikit';
|
||||
import {
|
||||
type ClearMessageContextParams,
|
||||
@@ -25,7 +29,6 @@ import {
|
||||
type ChatCoreError,
|
||||
type GetHistoryMessageResponse,
|
||||
} from '@coze-common/chat-core';
|
||||
import { type IOnLinkClickParams } from '@coze-common/chat-uikit-shared';
|
||||
|
||||
import {
|
||||
type Message as BuiltInMessage,
|
||||
@@ -150,6 +153,7 @@ export interface ChatAreaMessageEventMap {
|
||||
event: MouseEvent<Element, globalThis.MouseEvent>,
|
||||
) => void;
|
||||
onBeforeStopResponding: () => void;
|
||||
onCopyUpload: IEventCallbacks['onCopyUpload'];
|
||||
}
|
||||
|
||||
export type ChatAreaEventCallback = Partial<ChatAreaLifeCycleEventMap> &
|
||||
|
||||
@@ -22,4 +22,5 @@ export const defaultConfigs: ChatAreaConfigs = {
|
||||
ignoreMessageConfigList: [],
|
||||
groupUserMessage: false,
|
||||
uploadPlugin: UploadPlugin,
|
||||
isShowFunctionCallBox: true,
|
||||
};
|
||||
|
||||
@@ -106,6 +106,7 @@ export const allIgnorableMessageTypes = [
|
||||
export interface ChatAreaConfigs {
|
||||
ignoreMessageConfigList: IgnoreMessageType[];
|
||||
showFunctionCallDetail: boolean;
|
||||
isShowFunctionCallBox: boolean;
|
||||
// Whether to group user messages (merge avatars)
|
||||
groupUserMessage: boolean;
|
||||
uploadPlugin: typeof UploadPlugin;
|
||||
|
||||
@@ -23,7 +23,8 @@ import {
|
||||
|
||||
type OnBeforeSubmit = IChatInputProps['onBeforeSubmit'];
|
||||
|
||||
export interface ChatInputProps {
|
||||
export interface ChatInputProps
|
||||
extends Pick<IChatInputProps, 'leftActions' | 'rightSlot'> {
|
||||
/**
|
||||
* {@link OnBeforeSubmit}
|
||||
*/
|
||||
|
||||
@@ -26,6 +26,7 @@ const getDefaultCopywriting = (): CopywritingContextInterface => ({
|
||||
textareaBottomTips: '',
|
||||
clearContextDividerText: '',
|
||||
clearContextTooltipContent: '',
|
||||
audioButtonTooltipContent: '',
|
||||
});
|
||||
|
||||
export const CopywritingContext = createContext<CopywritingContextInterface>(
|
||||
|
||||
@@ -19,4 +19,5 @@ export interface CopywritingContextInterface {
|
||||
textareaBottomTips: string;
|
||||
clearContextDividerText: string;
|
||||
clearContextTooltipContent: string;
|
||||
audioButtonTooltipContent: string;
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
import { createContext, type PropsWithChildren, useContext } from 'react';
|
||||
|
||||
import { isUndefined, merge, omitBy } from 'lodash-es';
|
||||
import { Layout } from '@coze-common/chat-uikit-shared';
|
||||
import { type MakeValueUndefinable } from '@coze-common/chat-area-utils';
|
||||
import { SuggestedQuestionsShowMode } from '@coze-arch/bot-api/developer_api';
|
||||
import { Layout } from '@coze-common/chat-uikit-shared';
|
||||
|
||||
import {
|
||||
type PreferenceContextInterface,
|
||||
@@ -49,6 +49,7 @@ const getDefaultPreference = (): Required<PreferenceContextInterface> => ({
|
||||
selectable: false,
|
||||
showClearContextDivider: true,
|
||||
messageWidth: '100%',
|
||||
messageMaxWidth: '',
|
||||
readonly: false,
|
||||
uiKitChatInputButtonConfig: {
|
||||
isSendButtonVisible: true,
|
||||
@@ -68,6 +69,7 @@ const getDefaultPreference = (): Required<PreferenceContextInterface> => ({
|
||||
forceShowOnboardingMessage: false,
|
||||
showStopRespond: true,
|
||||
layout: Layout.PC,
|
||||
isMiniScreen: false,
|
||||
isOnboardingCentered: false,
|
||||
stopRespondOverrideWaiting: undefined,
|
||||
});
|
||||
|
||||
@@ -96,6 +96,10 @@ export interface PreferenceContextInterface {
|
||||
* message list width
|
||||
*/
|
||||
messageWidth: string;
|
||||
/**
|
||||
* message list max width
|
||||
*/
|
||||
messageMaxWidth: string;
|
||||
/**
|
||||
* Is it read-only?
|
||||
*/
|
||||
@@ -156,6 +160,11 @@ export interface PreferenceContextInterface {
|
||||
*/
|
||||
layout: Layout;
|
||||
|
||||
/**
|
||||
* Whether to enable mini screen mode
|
||||
*/
|
||||
isMiniScreen: boolean;
|
||||
|
||||
/**
|
||||
* Whether to force the stop reply button to be displayed
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import { type PropsWithChildren, useRef, useEffect } from 'react';
|
||||
|
||||
import { UploadController } from '../../service/upload-controller';
|
||||
import { useChatAreaContext } from '../../hooks/context/use-chat-area-context';
|
||||
import {
|
||||
UploadControllerContext,
|
||||
type UploadControllerContextProps,
|
||||
@@ -25,12 +26,16 @@ import {
|
||||
export const UploadControllerProvider: React.FC<PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { configs } = useChatAreaContext();
|
||||
const uploadControllerMap = useRef<
|
||||
UploadControllerContextProps['uploadControllerMap']
|
||||
>({});
|
||||
const createControllerAndUpload: UploadControllerContextProps['createControllerAndUpload'] =
|
||||
param => {
|
||||
uploadControllerMap.current[param.fileId] = new UploadController(param);
|
||||
uploadControllerMap.current[param.fileId] = new UploadController({
|
||||
...param,
|
||||
multiUploadPlugin: configs.uploadPlugin,
|
||||
});
|
||||
};
|
||||
const cancelUploadById: UploadControllerContextProps['cancelUploadById'] =
|
||||
id => {
|
||||
|
||||
@@ -301,3 +301,5 @@ export {
|
||||
} from '@coze-common/chat-core';
|
||||
export { type OnboardingSelectChangeCallback } from './context/chat-area-context/chat-area-callback';
|
||||
export { ChatInputArea } from './components/chat-input';
|
||||
export { type ChatMessage } from '@coze-arch/bot-api/developer_api';
|
||||
export { useBuiltinButtonStatus } from './hooks/uikit/use-builtin-button-status';
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import { type ComponentType } from 'react';
|
||||
|
||||
import { type MessageGroup } from '../../../store/types';
|
||||
import { type MessageBoxProps } from '../../../components/types';
|
||||
import {
|
||||
type CustomSendMessageBox,
|
||||
@@ -44,6 +45,8 @@ export interface CustomComponent {
|
||||
MessageBox: ComponentType<MessageBoxProps>;
|
||||
MessageBoxFooter: CustomMessageBoxFooter;
|
||||
MessageBoxHoverSlot: ComponentType;
|
||||
MessageGroupFooter: ComponentType<{ messageGroup: MessageGroup }>;
|
||||
|
||||
UIKitMessageBoxPlugin: ComponentType<CustomUiKitMessageBoxProps>;
|
||||
UIKitOnBoardingPlugin: ComponentType;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export interface UploadControllerProps {
|
||||
fileId: string;
|
||||
file: File;
|
||||
userId: string;
|
||||
multiUploadPlugin?: typeof UploadPlugin;
|
||||
onProgress: (event: EventPayloadMap['progress'], fileId: string) => void;
|
||||
onComplete: (event: EventPayloadMap['complete'], fileId: string) => void;
|
||||
onError: (event: EventPayloadMap['error'], fileId: string) => void;
|
||||
@@ -39,9 +40,10 @@ export class UploadController {
|
||||
onComplete,
|
||||
onError,
|
||||
onReady,
|
||||
multiUploadPlugin = UploadPlugin,
|
||||
}: UploadControllerProps) {
|
||||
this.fileId = fileId;
|
||||
this.uploadPlugin = new UploadPlugin({
|
||||
this.uploadPlugin = new multiUploadPlugin({
|
||||
file,
|
||||
userId,
|
||||
type: isImage(file) ? 'image' : 'object',
|
||||
|
||||
@@ -42,7 +42,6 @@ import { MessageManager } from '@/message/message-manager';
|
||||
import { ChunkProcessor, PreSendLocalMessageFactory } from '@/message';
|
||||
import { HttpChunk } from '@/channel/http-chunk';
|
||||
|
||||
import { type TokenManager } from '../credential';
|
||||
import {
|
||||
type ChatASRParams,
|
||||
type BreakMessageParams,
|
||||
@@ -70,6 +69,7 @@ import { MessageManagerService } from './services/message-manager-service';
|
||||
import { HttpChunkService } from './services/http-chunk-service';
|
||||
import { CreateMessageService } from './services/create-message-service';
|
||||
import { ReportEventsTracer, SlardarEvents } from './events/slardar-events';
|
||||
import { type TokenManager } from '../credential';
|
||||
|
||||
export default class ChatSDK {
|
||||
private static instances: Map<string, ChatSDK> = new Map();
|
||||
@@ -523,4 +523,10 @@ export default class ChatSDK {
|
||||
}
|
||||
return this.messageManagerService.chatASR(params);
|
||||
}
|
||||
|
||||
updateConversationId(conversationId: string) {
|
||||
this.conversation_id = conversationId;
|
||||
this.messageManagerService.conversation_id = conversationId;
|
||||
this.preSendLocalMessageFactory.conversation_id = conversationId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ export class RequestManager {
|
||||
// Execute incoming unified hooks
|
||||
const onCommonAfterResponse = async (
|
||||
response: AxiosResponse,
|
||||
hooksName: 'onAfterResponse' | 'onErrrorResponse' = 'onAfterResponse',
|
||||
hooksName: 'onAfterResponse' | 'onErrorResponse' = 'onAfterResponse',
|
||||
): Promise<AxiosResponse> => {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- temporary variable, quite normal
|
||||
let _response: AxiosResponse | Promise<AxiosResponse> = response;
|
||||
@@ -154,7 +154,7 @@ export class RequestManager {
|
||||
// Execute hooks for each scene
|
||||
const onSceneAfterResponse = async (
|
||||
response: AxiosResponse,
|
||||
hooksName: 'onAfterResponse' | 'onErrrorResponse' = 'onAfterResponse',
|
||||
hooksName: 'onAfterResponse' | 'onErrorResponse' = 'onAfterResponse',
|
||||
): Promise<AxiosResponse> => {
|
||||
const { scenes } = this.mergedBaseOptions;
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- temporary variable, quite normal
|
||||
@@ -188,9 +188,9 @@ export class RequestManager {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- temporary variable, quite normal
|
||||
const _response = await onCommonAfterResponse(
|
||||
response,
|
||||
'onErrrorResponse',
|
||||
'onErrorResponse',
|
||||
);
|
||||
return await onSceneAfterResponse(_response, 'onErrrorResponse');
|
||||
return await onSceneAfterResponse(_response, 'onErrorResponse');
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ interface Hooks {
|
||||
onGetMessageStreamParser?: (
|
||||
requestMessageRawBody: Record<string, unknown>,
|
||||
) => FetchSteamConfig<ParsedEvent>['streamParser'];
|
||||
onErrrorResponse?: Array<(response: AxiosResponse) => Promise<AxiosResponse>>;
|
||||
onErrorResponse?: Array<(response: AxiosResponse) => Promise<AxiosResponse>>;
|
||||
}
|
||||
|
||||
export enum RequestScene {
|
||||
|
||||
@@ -127,10 +127,15 @@ export interface IChatInputProps {
|
||||
leftActions?: ReactNode;
|
||||
|
||||
/**
|
||||
* Right Slot
|
||||
* Right Actions
|
||||
*/
|
||||
rightActions?: ReactNode;
|
||||
|
||||
/**
|
||||
* right slot
|
||||
*/
|
||||
rightSlot?: ReactNode;
|
||||
|
||||
/**
|
||||
* Custom send button
|
||||
*/
|
||||
|
||||
@@ -16,16 +16,16 @@
|
||||
|
||||
import { type FC } from 'react';
|
||||
|
||||
import {
|
||||
FILE_TYPE_CONFIG,
|
||||
FileTypeEnum,
|
||||
} from '@coze-common/chat-core/shared/const';
|
||||
import { Toast, Upload } from '@coze-arch/coze-design';
|
||||
import {
|
||||
type IChatUploadCopywritingConfig,
|
||||
DEFAULT_MAX_FILE_SIZE,
|
||||
UploadType,
|
||||
} from '@coze-common/chat-uikit-shared';
|
||||
import {
|
||||
FILE_TYPE_CONFIG,
|
||||
FileTypeEnum,
|
||||
} from '@coze-common/chat-core/shared/const';
|
||||
import { Toast, Upload } from '@coze-arch/coze-design';
|
||||
|
||||
interface IChatUploadProps {
|
||||
/**
|
||||
@@ -132,6 +132,7 @@ export const ChatUpload: FC<IChatUploadProps> = props => {
|
||||
onFileChange={handleUpload}
|
||||
disabled={isDisabled}
|
||||
multiple={limitFileCount > 1}
|
||||
uploadTrigger={'custom'}
|
||||
>
|
||||
{children}
|
||||
</Upload>
|
||||
|
||||
@@ -40,7 +40,8 @@ export const MessageBox: FC<
|
||||
|
||||
messageBubbleClassname,
|
||||
messageBubbleWrapperClassname,
|
||||
messageBoxWraperClassname,
|
||||
messageBoxWrapperClassname,
|
||||
messageHoverWrapperClassName,
|
||||
messageErrorWrapperClassname,
|
||||
isHoverShowUserInfo,
|
||||
|
||||
@@ -69,7 +70,8 @@ export const MessageBox: FC<
|
||||
classname={classname}
|
||||
messageBubbleWrapperClassname={messageBubbleWrapperClassname}
|
||||
messageBubbleClassname={messageBubbleClassname}
|
||||
messageBoxWraperClassname={messageBoxWraperClassname}
|
||||
messageBoxWrapperClassname={messageBoxWrapperClassname}
|
||||
messageHoverWrapperClassName={messageHoverWrapperClassName}
|
||||
messageErrorWrapperClassname={messageErrorWrapperClassname}
|
||||
isHoverShowUserInfo={isHoverShowUserInfo}
|
||||
layout={layout}
|
||||
|
||||
@@ -24,13 +24,13 @@ import {
|
||||
|
||||
import classnames from 'classnames';
|
||||
import { useClickAway, useHover, useUpdateEffect } from 'ahooks';
|
||||
import { ErrorBoundary } from '@coze-arch/logger';
|
||||
import {
|
||||
Layout,
|
||||
UIKitEvents,
|
||||
useUiKitEventCenter,
|
||||
} from '@coze-common/chat-uikit-shared';
|
||||
import { useEventCallback } from '@coze-common/chat-hooks';
|
||||
import { ErrorBoundary } from '@coze-arch/logger';
|
||||
import { Avatar, Typography } from '@coze-arch/coze-design';
|
||||
|
||||
import { UserLabel, UserName } from '../user-label';
|
||||
@@ -67,7 +67,8 @@ export const MessageBoxWrap: FC<
|
||||
classname,
|
||||
messageBubbleClassname,
|
||||
messageBubbleWrapperClassname,
|
||||
messageBoxWraperClassname,
|
||||
messageBoxWrapperClassname,
|
||||
messageHoverWrapperClassName,
|
||||
messageErrorWrapperClassname,
|
||||
isHoverShowUserInfo = true,
|
||||
layout,
|
||||
@@ -165,7 +166,7 @@ export const MessageBoxWrap: FC<
|
||||
// chat-uikit-message-box-container chat-uikit-message-box-container-pc
|
||||
className={classnames(
|
||||
messageBoxContainerVariants({ isMobileLayout }),
|
||||
messageBoxWraperClassname,
|
||||
messageBoxWrapperClassname,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
@@ -292,6 +293,17 @@ export const MessageBoxWrap: FC<
|
||||
>
|
||||
{right}
|
||||
</div>
|
||||
{isHovering || hoverContentVisible ? (
|
||||
<div
|
||||
// chat-uikit-message-box-container__message__message-box__hover-container
|
||||
className={classnames(
|
||||
'absolute right-[-12px] bottom-[-20px]',
|
||||
messageHoverWrapperClassName,
|
||||
)}
|
||||
>
|
||||
{hoverContent}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{/* Please read the refreshContainerWidthConditionally above before changing the style of this dom */}
|
||||
<div
|
||||
@@ -301,14 +313,6 @@ export const MessageBoxWrap: FC<
|
||||
>
|
||||
{renderFooter?.(refreshContainerWidthConditionally)}
|
||||
</div>
|
||||
{isHovering || hoverContentVisible ? (
|
||||
<div
|
||||
// chat-uikit-message-box-container__message__message-box__hover-container
|
||||
className="absolute right-[-12px] bottom-[-20px]"
|
||||
>
|
||||
{hoverContent}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -91,7 +91,8 @@ interface MessageBoxBasicProps {
|
||||
classname?: string;
|
||||
|
||||
messageBubbleWrapperClassname?: string;
|
||||
messageBoxWraperClassname?: string; // Direct father style of message box
|
||||
messageBoxWrapperClassname?: string; // Direct father style of message box
|
||||
messageHoverWrapperClassName?: string; // Direct hover style of message box
|
||||
messageBubbleClassname?: string; // Message The style of the message bubble
|
||||
messageErrorWrapperClassname?: string; // Message wrong father style
|
||||
isHoverShowUserInfo?: boolean; // Whether to display user details when hovering
|
||||
@@ -160,7 +161,9 @@ export interface MessageBoxWrapProps {
|
||||
contentTime: number | undefined;
|
||||
classname?: string;
|
||||
|
||||
messageBoxWraperClassname?: string; // Direct father style of message box
|
||||
messageBoxWrapperClassname?: string; // Direct father style of message box
|
||||
messageHoverWrapperClassName?: string; // Direct hover style of message box
|
||||
|
||||
messageBubbleClassname?: string; // Message The style of the message bubble
|
||||
messageBubbleWrapperClassname?: string; // Message message bubble father style
|
||||
messageErrorWrapperClassname?: string; // Message wrong father style
|
||||
|
||||
@@ -54,7 +54,6 @@ export const TextContent: FC<IMessageContentProps> = props => {
|
||||
} = props;
|
||||
const MdBoxLazy = LazyCozeMdBox;
|
||||
const contentRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const { content } = message;
|
||||
|
||||
if (!isText(content)) {
|
||||
@@ -63,7 +62,6 @@ export const TextContent: FC<IMessageContentProps> = props => {
|
||||
|
||||
const isStreaming = !message.is_finish;
|
||||
const text = content.slice(0, message.broken_pos ?? Infinity);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="chat-uikit-text-content"
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { memo, useMemo } from 'react';
|
||||
|
||||
import { isEqual, isFunction, omitBy } from 'lodash-es';
|
||||
|
||||
import { extractChatflowMessage } from './utils';
|
||||
import { type ChatflowNodeData, type RenderNodeEntryProps } from './type';
|
||||
import { QuestionNodeRender } from './question-node-render';
|
||||
import { InputNodeRender } from './input-node-render';
|
||||
|
||||
const BaseComponent: React.FC<RenderNodeEntryProps> = ({
|
||||
message,
|
||||
...restProps
|
||||
}) => {
|
||||
const chatflowNodeData: ChatflowNodeData | undefined = useMemo(
|
||||
() => extractChatflowMessage(message),
|
||||
[message],
|
||||
);
|
||||
if (!chatflowNodeData) {
|
||||
return null;
|
||||
}
|
||||
if (chatflowNodeData.card_type === 'INPUT') {
|
||||
return (
|
||||
<InputNodeRender
|
||||
data={chatflowNodeData}
|
||||
message={message}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
} else if (chatflowNodeData.card_type === 'QUESTION') {
|
||||
return (
|
||||
<QuestionNodeRender
|
||||
data={chatflowNodeData}
|
||||
message={message}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return 'content type is not supported';
|
||||
}
|
||||
};
|
||||
|
||||
export const WorkflowRenderEntry = memo(BaseComponent, (prevProps, nextProps) =>
|
||||
isEqual(omitBy(prevProps, isFunction), omitBy(nextProps, isFunction)),
|
||||
);
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import { produce } from 'immer';
|
||||
import {
|
||||
type IEventCallbacks,
|
||||
type IMessage,
|
||||
} from '@coze-common/chat-uikit-shared';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Button, Input, Space, Typography } from '@coze-arch/coze-design';
|
||||
|
||||
import { type ChatflowNodeData } from './type';
|
||||
import { NodeWrapperUI } from './node-wrapper-ui';
|
||||
|
||||
export const InputNodeRender = ({
|
||||
data,
|
||||
onCardSendMsg,
|
||||
readonly,
|
||||
isDisable,
|
||||
message,
|
||||
}: {
|
||||
data: ChatflowNodeData;
|
||||
onCardSendMsg?: IEventCallbacks['onCardSendMsg'];
|
||||
readonly?: boolean;
|
||||
isDisable?: boolean;
|
||||
message: IMessage;
|
||||
}) => {
|
||||
const [inputData, setInputData] = useState<Record<string, string>>({});
|
||||
const [hasSend, setHasSend] = useState(false);
|
||||
const disabled = readonly || isDisable || hasSend;
|
||||
|
||||
return (
|
||||
<NodeWrapperUI>
|
||||
<Space spacing={12} vertical className="w-full">
|
||||
{data.input_card_data?.map((item, index) => (
|
||||
<Space
|
||||
align="start"
|
||||
className="w-full"
|
||||
spacing={6}
|
||||
vertical
|
||||
key={item?.name + index}
|
||||
>
|
||||
<Typography.Text ellipsis className="text-lg !font-medium">
|
||||
{item?.name}
|
||||
</Typography.Text>
|
||||
<Input
|
||||
disabled={disabled || hasSend}
|
||||
value={inputData[item.name]}
|
||||
onChange={value => {
|
||||
setInputData(
|
||||
produce(draft => {
|
||||
draft[item.name] = value;
|
||||
}),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
))}
|
||||
|
||||
<Button
|
||||
className="w-full"
|
||||
disabled={disabled}
|
||||
onClick={() => {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
setHasSend(true);
|
||||
onCardSendMsg?.({
|
||||
message,
|
||||
extra: {
|
||||
msg:
|
||||
data.input_card_data
|
||||
?.map(item => `${item.name}:${inputData[item.name] || ''}`)
|
||||
.join('\n') || '',
|
||||
mentionList: message.sender_id
|
||||
? [{ id: message.sender_id }]
|
||||
: [],
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
{I18n.t('workflow_detail_title_testrun_submit')}
|
||||
</Button>
|
||||
</Space>
|
||||
</NodeWrapperUI>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type PropsWithChildren } from 'react';
|
||||
|
||||
export const NodeWrapperUI: React.FC<PropsWithChildren> = ({ children }) => (
|
||||
<div className="overflow-hidden w-full min-w-[282px] max-w-[546px] p-[16px] coz-bg-primary">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
type IEventCallbacks,
|
||||
type IMessage,
|
||||
} from '@coze-common/chat-uikit-shared';
|
||||
import { Button, Space, Typography } from '@coze-arch/coze-design';
|
||||
|
||||
import { type ChatflowNodeData } from './type';
|
||||
import { NodeWrapperUI } from './node-wrapper-ui';
|
||||
|
||||
export const QuestionNodeRender = ({
|
||||
data,
|
||||
onCardSendMsg,
|
||||
readonly,
|
||||
isDisable,
|
||||
message,
|
||||
}: {
|
||||
data: ChatflowNodeData;
|
||||
onCardSendMsg?: IEventCallbacks['onCardSendMsg'];
|
||||
readonly?: boolean;
|
||||
isDisable?: boolean;
|
||||
message: IMessage;
|
||||
}) => {
|
||||
const disabled = readonly || isDisable;
|
||||
return (
|
||||
<NodeWrapperUI>
|
||||
<Space className="w-full" vertical spacing={12} align="start">
|
||||
<Typography.Text ellipsis className="text-18px">
|
||||
{data.question_card_data?.Title}
|
||||
</Typography.Text>
|
||||
<Space className="w-full" vertical spacing={16}>
|
||||
{data.question_card_data?.Options?.map((option, index) => (
|
||||
<Button
|
||||
key={option.name + index}
|
||||
className="w-full"
|
||||
color="primary"
|
||||
disabled={disabled}
|
||||
onClick={() =>
|
||||
onCardSendMsg?.({
|
||||
message,
|
||||
extra: { msg: option.name, mentionList: [] },
|
||||
})
|
||||
}
|
||||
>
|
||||
{option.name}
|
||||
</Button>
|
||||
))}
|
||||
</Space>
|
||||
</Space>
|
||||
</NodeWrapperUI>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
type IEventCallbacks,
|
||||
type IMessage,
|
||||
} from '@coze-common/chat-uikit-shared';
|
||||
|
||||
interface RenderNodeBaseProps extends Pick<IEventCallbacks, 'onCardSendMsg'> {
|
||||
isDisable: boolean | undefined;
|
||||
readonly: boolean | undefined;
|
||||
}
|
||||
export interface RenderNodeEntryProps extends RenderNodeBaseProps {
|
||||
message: IMessage;
|
||||
}
|
||||
export interface ChatflowNodeData {
|
||||
card_type: 'QUESTION' | 'INPUT';
|
||||
input_card_data?: {
|
||||
type: string;
|
||||
name: string;
|
||||
}[];
|
||||
question_card_data?: {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
Title: string;
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
Options: { name: string }[];
|
||||
};
|
||||
}
|
||||
export interface ChatflowNodeData {
|
||||
card_type: 'QUESTION' | 'INPUT';
|
||||
input_card_data?: {
|
||||
type: string;
|
||||
name: string;
|
||||
}[];
|
||||
question_card_data?: {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
Title: string;
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
Options: { name: string }[];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type IMessage } from '@coze-common/chat-uikit-shared';
|
||||
import { safeJSONParse } from '@coze-common/chat-uikit';
|
||||
|
||||
import { type ChatflowNodeData } from './type';
|
||||
|
||||
export const extractChatflowMessage = (message: IMessage) => {
|
||||
if (message.content_type === 'card') {
|
||||
const contentStruct = safeJSONParse(message.content) as {
|
||||
x_properties: {
|
||||
workflow_card_info: string;
|
||||
};
|
||||
};
|
||||
const workflowDataStr = contentStruct?.x_properties?.workflow_card_info;
|
||||
if (workflowDataStr) {
|
||||
const cardData = safeJSONParse(workflowDataStr) as ChatflowNodeData;
|
||||
if (cardData?.card_type === 'QUESTION' && cardData?.question_card_data) {
|
||||
return cardData;
|
||||
}
|
||||
if (cardData?.card_type === 'INPUT' && cardData?.input_card_data) {
|
||||
return cardData;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ContentBoxType } from '@coze-common/chat-uikit-shared';
|
||||
import {
|
||||
ContentBox,
|
||||
type EnhancedContentConfig,
|
||||
ContentType,
|
||||
} from '@coze-common/chat-uikit';
|
||||
import {
|
||||
PluginScopeContextProvider,
|
||||
usePluginCustomComponents,
|
||||
type ComponentTypesMap,
|
||||
} from '@coze-common/chat-area';
|
||||
|
||||
import { WorkflowRenderEntry } from './components';
|
||||
|
||||
const defaultEnable = (value?: boolean) => {
|
||||
if (typeof value === 'undefined') {
|
||||
return true;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
export const ChatFlowRender: ComponentTypesMap['contentBox'] = props => {
|
||||
const customTextMessageInnerTopSlotList = usePluginCustomComponents(
|
||||
'TextMessageInnerTopSlot',
|
||||
);
|
||||
const enhancedContentConfigList: EnhancedContentConfig[] = [
|
||||
{
|
||||
rule: ({ contentType, contentConfigs }) => {
|
||||
const isCardEnable = defaultEnable(
|
||||
contentConfigs?.[ContentBoxType.CARD]?.enable,
|
||||
);
|
||||
return contentType === ContentType.Card && isCardEnable;
|
||||
},
|
||||
render: ({ message, eventCallbacks, options }) => {
|
||||
const { isCardDisabled, readonly } = options;
|
||||
|
||||
const { onCardSendMsg } = eventCallbacks ?? {};
|
||||
|
||||
return (
|
||||
<WorkflowRenderEntry
|
||||
message={message}
|
||||
onCardSendMsg={onCardSendMsg}
|
||||
readonly={readonly}
|
||||
isDisable={isCardDisabled}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
return (
|
||||
<ContentBox
|
||||
enhancedContentConfigList={enhancedContentConfigList}
|
||||
multimodalTextContentAddonTop={
|
||||
<>
|
||||
{customTextMessageInnerTopSlotList.map(
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- matches the expected naming
|
||||
({ pluginName, Component }, index) => (
|
||||
<PluginScopeContextProvider
|
||||
pluginName={pluginName}
|
||||
key={pluginName}
|
||||
>
|
||||
<Component key={index} message={props.message} />
|
||||
</PluginScopeContextProvider>
|
||||
),
|
||||
)}
|
||||
</>
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -15,3 +15,4 @@
|
||||
*/
|
||||
|
||||
export { WorkflowRender } from './components/workflow-render';
|
||||
export { ChatFlowRender } from './components/chat-flow-render';
|
||||
|
||||
@@ -48,5 +48,6 @@ export const createChatBackgroundPlugin = () => {
|
||||
};
|
||||
return {
|
||||
ChatBackgroundPlugin,
|
||||
chatBackgroundEvent,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -117,7 +117,9 @@ export const useSendUseToolMessage = () => {
|
||||
componentsFormValues: Record<string, TValue>;
|
||||
options?: SendMessageOptions;
|
||||
onBeforeSendTemplateShortcut?: (
|
||||
params: OnBeforeSendTemplateShortcutParams,
|
||||
params: OnBeforeSendTemplateShortcutParams & {
|
||||
shortcut: ShortCutCommand;
|
||||
},
|
||||
) => OnBeforeSendTemplateShortcutParams;
|
||||
withoutComponentsList?: boolean;
|
||||
}) => {
|
||||
@@ -170,6 +172,7 @@ export const useSendUseToolMessage = () => {
|
||||
const handledParams = onBeforeSendTemplateShortcut?.({
|
||||
message: cloneDeep(message),
|
||||
options: cloneDeep(options),
|
||||
shortcut,
|
||||
}) || {
|
||||
message,
|
||||
options,
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
import { type CSSProperties, type FC, useRef, useState } from 'react';
|
||||
|
||||
import cls from 'classnames';
|
||||
import { type ShortCutCommand } from '@coze-agent-ide/tool-config';
|
||||
import { useMessageWidth } from '@coze-common/chat-area';
|
||||
import { OverflowList, Popover } from '@coze-arch/bot-semi';
|
||||
import { SendType } from '@coze-arch/bot-api/playground_api';
|
||||
import { type ShortCutCommand } from '@coze-agent-ide/tool-config';
|
||||
|
||||
import {
|
||||
enableSendTypePanelHideTemplate,
|
||||
@@ -53,7 +53,9 @@ interface ChatShortCutBarProps {
|
||||
wrapperStyle?: CSSProperties;
|
||||
toolTipFooterSlot?: React.ReactNode;
|
||||
onBeforeSendTemplateShortcut?: (
|
||||
params: OnBeforeSendTemplateShortcutParams,
|
||||
params: OnBeforeSendTemplateShortcutParams & {
|
||||
shortcut: ShortCutCommand;
|
||||
},
|
||||
) => OnBeforeSendTemplateShortcutParams;
|
||||
onBeforeSendTextMessage?: (
|
||||
params: OnBeforeSendQueryShortcutParams,
|
||||
|
||||
@@ -19,7 +19,7 @@ import { exhaustiveCheckSimple } from '@coze-common/chat-area-utils';
|
||||
import { type UIMode } from '../shortcut-bar/types';
|
||||
|
||||
export const getUIModeByBizScene: (props: {
|
||||
bizScene: 'debug' | 'store' | 'home' | 'agentApp';
|
||||
bizScene: 'debug' | 'store' | 'home' | 'agentApp' | 'websdk';
|
||||
showBackground: boolean;
|
||||
}) => UIMode = ({ bizScene, showBackground }) => {
|
||||
if (bizScene === 'agentApp') {
|
||||
@@ -32,7 +32,7 @@ export const getUIModeByBizScene: (props: {
|
||||
return 'white';
|
||||
}
|
||||
|
||||
if (bizScene === 'store' || bizScene === 'debug') {
|
||||
if (bizScene === 'store' || bizScene === 'debug' || bizScene === 'websdk') {
|
||||
if (showBackground) {
|
||||
return 'blur';
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ export const EditorFullInputInner = forwardRef<EditorHandle, EditorInputProps>(
|
||||
...restProps
|
||||
} = props;
|
||||
const [value, setValue] = useState(propsValue);
|
||||
const [isComposing, setIsComposing] = useState(false);
|
||||
|
||||
// Create a mutable reference to store the latest value
|
||||
const valueRef = useRef(value);
|
||||
@@ -104,8 +105,16 @@ export const EditorFullInputInner = forwardRef<EditorHandle, EditorInputProps>(
|
||||
value={value}
|
||||
onChange={v => {
|
||||
setValue(v);
|
||||
if (isComposing) {
|
||||
return;
|
||||
}
|
||||
propsOnChange?.(v);
|
||||
}}
|
||||
onCompositionStart={() => setIsComposing(true)}
|
||||
onCompositionEnd={e => {
|
||||
setIsComposing(false);
|
||||
propsOnChange?.(e.currentTarget.value);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user