feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
.ui-kit-onboarding {
|
||||
// figma 此处为 70px 时机 dom 为 safe area 24px + 此处 46px = 70px
|
||||
margin-top: 46px;
|
||||
padding: 0 24px
|
||||
}
|
||||
|
||||
.message {
|
||||
align-self: flex-start;
|
||||
max-width: 100%;
|
||||
margin-bottom: 8px;
|
||||
padding: 0 1px;
|
||||
}
|
||||
|
||||
.message-selectable {
|
||||
margin-left: 29px;
|
||||
}
|
||||
|
||||
.onboarding-message-content {
|
||||
word-break: break-word;
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function */
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import classNames from 'classnames';
|
||||
import { useDebounce, useSize, useUpdateEffect } from 'ahooks';
|
||||
import { userStoreService } from '@coze-studio/user-store';
|
||||
import { useReportTti } from '@coze-arch/report-tti';
|
||||
import {
|
||||
BotMode,
|
||||
SuggestedQuestionsShowMode,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
import { useBotSkillStore } from '@coze-studio/bot-detail-store/bot-skill';
|
||||
import { useBotInfoStore } from '@coze-studio/bot-detail-store/bot-info';
|
||||
import { useChatBackgroundState } from '@coze-studio/bot-detail-store';
|
||||
import {
|
||||
CozeImageWithPreview,
|
||||
CozeLink,
|
||||
LazyCozeMdBox,
|
||||
MessageBox,
|
||||
NO_MESSAGE_ID_MARK,
|
||||
OnBoarding as UIKitOnBoarding,
|
||||
} from '@coze-common/chat-uikit';
|
||||
import {
|
||||
type ComponentTypesMap,
|
||||
useOnboardingCenterOffset,
|
||||
} from '@coze-common/chat-area';
|
||||
import {
|
||||
ONBOARDING_PREVIEW_DELAY,
|
||||
OnboardingVariable,
|
||||
useRenderVariable,
|
||||
} from '@coze-agent-ide/onboarding';
|
||||
|
||||
import s from './index.module.less';
|
||||
/**
|
||||
* 当有无开场白的状态变化时, 会依次一次 reflow 同时高度发生变化, useSize 监听变化后, marginTop 改变触发一次 repaint, 导致会有两次渲染, 产生抖动
|
||||
* 现在需要调和这两次渲染
|
||||
* 需要优化 onboarding dom 结构, 使得 onboarding 的居中能力是 css 实现的, 解决这个问题
|
||||
* not-needed
|
||||
* |
|
||||
* |
|
||||
* ready-empty-onboarding <--+--> ready-onboarding
|
||||
* | |
|
||||
* | v
|
||||
* harmonized-empty-onboarding harmonized-onboarding
|
||||
* | |
|
||||
* v |
|
||||
* not-needed <------------------------+
|
||||
*/
|
||||
type HarmonizeOnboardingRender =
|
||||
| 'not-needed'
|
||||
| 'ready-empty-onboarding'
|
||||
| 'ready-onboarding'
|
||||
| 'harmonized-onboarding'
|
||||
| 'harmonized-empty-onboarding';
|
||||
|
||||
const getHarmonizedOnboardingHeight = ({
|
||||
onboardingHeight = 0,
|
||||
status,
|
||||
}: {
|
||||
onboardingHeight?: number;
|
||||
status: HarmonizeOnboardingRender;
|
||||
}) => {
|
||||
const emptyOnboardingHeight = 56;
|
||||
const contentOnboardingHeight = 118;
|
||||
switch (status) {
|
||||
case 'not-needed':
|
||||
return onboardingHeight;
|
||||
case 'ready-onboarding':
|
||||
case 'harmonized-onboarding':
|
||||
return contentOnboardingHeight;
|
||||
default:
|
||||
return emptyOnboardingHeight;
|
||||
}
|
||||
};
|
||||
|
||||
export const OnboardingMessagePop: ComponentTypesMap['onboarding'] = ({
|
||||
prologue,
|
||||
suggestions,
|
||||
sendTextMessage,
|
||||
hasMessages,
|
||||
enableImageAutoSize,
|
||||
imageAutoSizeContainerWidth,
|
||||
showBackground: showBackgroundProp,
|
||||
eventCallbacks,
|
||||
}) => {
|
||||
const [harmonizeRenders, setHarmonizeRenders] =
|
||||
useState<HarmonizeOnboardingRender>('not-needed');
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const onboardingSize = useSize(ref);
|
||||
const {
|
||||
avatar,
|
||||
name,
|
||||
mode,
|
||||
id = '',
|
||||
} = useBotInfoStore(
|
||||
useShallow(state => ({
|
||||
mode: state.mode,
|
||||
avatar: state.icon_url,
|
||||
name: state.name,
|
||||
id: state.botId,
|
||||
})),
|
||||
);
|
||||
const { onBoardingSuggestionWrap } = useBotSkillStore(
|
||||
useShallow(state => ({
|
||||
onBoardingSuggestionWrap:
|
||||
state.onboardingContent.suggested_questions_show_mode ===
|
||||
SuggestedQuestionsShowMode.All,
|
||||
})),
|
||||
);
|
||||
const debouncedPrologue = useDebounce(prologue, {
|
||||
wait: ONBOARDING_PREVIEW_DELAY,
|
||||
});
|
||||
const userInfo = userStoreService.useUserInfo();
|
||||
const { showBackground: showBackgroundFromChatBackgroundState } =
|
||||
useChatBackgroundState();
|
||||
const showBackground =
|
||||
showBackgroundProp ?? showBackgroundFromChatBackgroundState;
|
||||
|
||||
const renderVariable = useRenderVariable({
|
||||
[OnboardingVariable.USER_NAME]: userInfo?.name ?? '',
|
||||
});
|
||||
|
||||
// TTI
|
||||
useReportTti({
|
||||
isLive: mode === BotMode.SingleMode,
|
||||
extra: {
|
||||
mode: 'single-agent',
|
||||
},
|
||||
});
|
||||
const harmonizedHeight = getHarmonizedOnboardingHeight({
|
||||
onboardingHeight: onboardingSize?.height,
|
||||
status: harmonizeRenders,
|
||||
});
|
||||
const marginTop = useOnboardingCenterOffset({
|
||||
onboardingHeight: harmonizedHeight,
|
||||
});
|
||||
|
||||
const isOnboardingEmpty = !debouncedPrologue && !suggestions.length;
|
||||
|
||||
useUpdateEffect(() => {
|
||||
if (isOnboardingEmpty) {
|
||||
setHarmonizeRenders('ready-empty-onboarding');
|
||||
return;
|
||||
}
|
||||
setHarmonizeRenders('ready-onboarding');
|
||||
}, [isOnboardingEmpty]);
|
||||
|
||||
useEffect(() => {
|
||||
if (harmonizeRenders === 'not-needed') {
|
||||
return;
|
||||
}
|
||||
if (harmonizeRenders === 'ready-onboarding') {
|
||||
setHarmonizeRenders('harmonized-onboarding');
|
||||
return;
|
||||
}
|
||||
if (harmonizeRenders === 'ready-empty-onboarding') {
|
||||
setHarmonizeRenders('harmonized-empty-onboarding');
|
||||
return;
|
||||
}
|
||||
setHarmonizeRenders('not-needed');
|
||||
}, [onboardingSize?.height]);
|
||||
|
||||
if (hasMessages && !prologue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (hasMessages && prologue) {
|
||||
return (
|
||||
<div className={classNames(s.message)}>
|
||||
<MessageBox
|
||||
messageId={null}
|
||||
senderInfo={{ url: avatar, nickname: name, id }}
|
||||
showUserInfo={true}
|
||||
theme="grey"
|
||||
getBotInfo={() => undefined}
|
||||
showBackground={showBackground}
|
||||
enableImageAutoSize={enableImageAutoSize}
|
||||
imageAutoSizeContainerWidth={imageAutoSizeContainerWidth}
|
||||
eventCallbacks={eventCallbacks}
|
||||
>
|
||||
<div
|
||||
className={s['onboarding-message-content']}
|
||||
data-grab-mark={NO_MESSAGE_ID_MARK}
|
||||
>
|
||||
<LazyCozeMdBox
|
||||
insertedElements={renderVariable(prologue)}
|
||||
markDown={prologue}
|
||||
autoFixSyntax={{ autoFixEnding: false }}
|
||||
slots={{
|
||||
Image: CozeImageWithPreview,
|
||||
Link: CozeLink,
|
||||
}}
|
||||
></LazyCozeMdBox>
|
||||
</div>
|
||||
</MessageBox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<UIKitOnBoarding
|
||||
ref={ref}
|
||||
style={{ marginTop }}
|
||||
className={s['ui-kit-onboarding']}
|
||||
name={name}
|
||||
avatar={avatar}
|
||||
prologue={debouncedPrologue}
|
||||
suggestionListWithString={suggestions.map(sug => sug.content)}
|
||||
onSuggestionClick={sendTextMessage}
|
||||
showBackground={showBackground}
|
||||
suggestionsWithStringWrap={onBoardingSuggestionWrap}
|
||||
mdBoxProps={{
|
||||
insertedElements: renderVariable(prologue),
|
||||
slots: {
|
||||
Image: CozeImageWithPreview,
|
||||
Link: CozeLink,
|
||||
},
|
||||
}}
|
||||
enableAutoSizeImage={enableImageAutoSize}
|
||||
imageAutoSizeContainerWidth={imageAutoSizeContainerWidth}
|
||||
eventCallbacks={eventCallbacks}
|
||||
suggestionItemColor="white"
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
.more-btn-tooltip {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
letter-spacing: -0.3px;
|
||||
|
||||
.tool-text {
|
||||
cursor: pointer;
|
||||
color: var(--light-color-brand-brand-3, #9197f1);
|
||||
text-decoration: underline dotted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 classnames from 'classnames';
|
||||
import { useBotInfoStore } from '@coze-studio/bot-detail-store/bot-info';
|
||||
import { useBotDetailIsReadonly } from '@coze-studio/bot-detail-store';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { OpenModalEvent, emitEvent } from '@coze-arch/bot-utils';
|
||||
import { BotMode } from '@coze-arch/bot-api/playground_api';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
export const UploadTooltipsContent = () => {
|
||||
const isReadonly = useBotDetailIsReadonly();
|
||||
|
||||
const mode = useBotInfoStore(state => state.mode);
|
||||
const isMulti = mode === BotMode.MultiMode;
|
||||
const isWorkflow = mode === BotMode.WorkflowMode;
|
||||
|
||||
const botPreviewAttachI18nKey = 'bot_preview_attach_0319';
|
||||
|
||||
const addApi = () => {
|
||||
if (isReadonly) {
|
||||
return;
|
||||
}
|
||||
emitEvent(OpenModalEvent.PLUGIN_API_MODAL_OPEN, { type: 1 });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={s['more-btn-tooltip']} onClick={e => e.stopPropagation()}>
|
||||
{I18n.t(botPreviewAttachI18nKey, {
|
||||
placeholder:
|
||||
isMulti || isWorkflow ? (
|
||||
I18n.t('bot_preview_attach_select')
|
||||
) : (
|
||||
<span className={classnames(s['tool-text'])} onClick={addApi}>
|
||||
{I18n.t('bot_preview_attach_select')}
|
||||
</span>
|
||||
),
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 { createContext, useContext } from 'react';
|
||||
|
||||
import { type ComponentTypesMap } from '@coze-common/chat-area';
|
||||
|
||||
export const BotDebugChatAreaComponentContext = createContext<
|
||||
Partial<ComponentTypesMap>
|
||||
>({});
|
||||
|
||||
export const useBotDebugChatAreaComponent = () =>
|
||||
useContext(BotDebugChatAreaComponentContext);
|
||||
|
||||
export const BotDebugChatAreaComponentProvider =
|
||||
BotDebugChatAreaComponentContext.Provider;
|
||||
@@ -0,0 +1,26 @@
|
||||
.chat-input-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.preview-not-save {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #a7abb0;
|
||||
}
|
||||
|
||||
.coz-debug-shortcut-bar-wrapper {
|
||||
width: calc(100% - 92px);
|
||||
margin-right: 24px;
|
||||
margin-left: 68px;
|
||||
}
|
||||
|
||||
.chat-area-message-group-list {
|
||||
padding: 0;
|
||||
}
|
||||
176
frontend/packages/agent-ide/chat-debug-area/src/index.tsx
Normal file
176
frontend/packages/agent-ide/chat-debug-area/src/index.tsx
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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 ReactNode, useEffect, useState } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { merge } from 'lodash-es';
|
||||
import classNames from 'classnames';
|
||||
import { IconAlertCircle } from '@douyinfe/semi-icons';
|
||||
import { usePageRuntimeStore } from '@coze-studio/bot-detail-store/page-runtime';
|
||||
import { WorkflowRender } from '@coze-common/chat-workflow-render';
|
||||
import {
|
||||
ChatArea,
|
||||
type ComponentTypesMap,
|
||||
useChatArea,
|
||||
useInitStatus,
|
||||
useLatestSectionMessage,
|
||||
} from '@coze-common/chat-area';
|
||||
import { getSlardarInstance } from '@coze-arch/logger';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Spin, Toast } from '@coze-arch/bot-semi';
|
||||
import { CustomError } from '@coze-arch/bot-error';
|
||||
import { SendType } from '@coze-arch/bot-api/developer_api';
|
||||
import { ReceiveMessageBox } from '@coze-agent-ide/chat-components-adapter';
|
||||
import { MessageBoxActionBarAdapter } from '@coze-agent-ide/chat-answer-action-adapter';
|
||||
|
||||
import { ShortcutBarRender } from './plugins/shortcut';
|
||||
import { useBotDebugChatAreaComponent } from './context';
|
||||
import { UploadTooltipsContent } from './components/upload-tooltips-content';
|
||||
import { OnboardingMessagePop } from './components/onboarding-message-pop';
|
||||
|
||||
import retryStyles from './retry.module.less';
|
||||
import s from './index.module.less';
|
||||
|
||||
export { BotDebugChatAreaComponentProvider } from './context';
|
||||
|
||||
export const BotDebugChatArea = ({
|
||||
readOnly = false,
|
||||
headerNode,
|
||||
}: {
|
||||
readOnly?: boolean;
|
||||
headerNode?: ReactNode;
|
||||
}) => {
|
||||
const [enableSendMultimodalMessage, setEnableSendMultimodalMessage] =
|
||||
useState<boolean>(true);
|
||||
|
||||
const initStatus = useInitStatus();
|
||||
|
||||
const { savingInfo } = usePageRuntimeStore(
|
||||
useShallow(state => ({
|
||||
savingInfo: state.savingInfo,
|
||||
})),
|
||||
);
|
||||
|
||||
const interceptSend = savingInfo.saving;
|
||||
|
||||
const onBeforeSubmit = () => {
|
||||
if (interceptSend) {
|
||||
Toast.warning({
|
||||
content: I18n.t('bot_execute_by_autosave'),
|
||||
showClose: false,
|
||||
});
|
||||
}
|
||||
|
||||
return !interceptSend;
|
||||
};
|
||||
const { latestSectionMessageLength } = useLatestSectionMessage();
|
||||
const injectComponents = useBotDebugChatAreaComponent();
|
||||
const userHasSentMessage = latestSectionMessageLength > 0;
|
||||
|
||||
if (initStatus === 'unInit' || initStatus === 'loading') {
|
||||
return (
|
||||
<div className={retryStyles['home-state']}>
|
||||
<Spin size="middle" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (initStatus === 'initFail') {
|
||||
return <InitFail />;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 请勿新增或修改,review 不会通过
|
||||
* 请使用插件化方案实现
|
||||
*/
|
||||
const chatAreaComponentTypes: Partial<ComponentTypesMap> = {
|
||||
messageActionBarFooter: MessageBoxActionBarAdapter,
|
||||
messageActionBarHoverContent: () => null,
|
||||
contentBox: WorkflowRender,
|
||||
onboarding: OnboardingMessagePop,
|
||||
receiveMessageBox: ReceiveMessageBox,
|
||||
chatInputIntegration: {
|
||||
renderChatInputTopSlot: controller =>
|
||||
ShortcutBarRender({
|
||||
controller,
|
||||
onShortcutActive: shortcut => {
|
||||
const isTemplateShortcutActive =
|
||||
shortcut?.send_type === SendType.SendTypePanel;
|
||||
const enableMultimodalArea = !isTemplateShortcutActive;
|
||||
setEnableSendMultimodalMessage(enableMultimodalArea);
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<ChatArea
|
||||
readonly={readOnly}
|
||||
componentTypes={merge(chatAreaComponentTypes, injectComponents)}
|
||||
enableMessageBoxActionBar
|
||||
messageGroupListClassName={s['chat-area-message-group-list']}
|
||||
enableMultimodalUpload={enableSendMultimodalMessage}
|
||||
enableLegacyUpload={!enableSendMultimodalMessage}
|
||||
textareaBottomTips={I18n.t('chat_GenAI_tips')}
|
||||
chatInputProps={{
|
||||
wrapperClassName: classNames(s['chat-input-wrapper']),
|
||||
onBeforeSubmit,
|
||||
uploadButtonTooltipContent: <UploadTooltipsContent />,
|
||||
submitClearInput: !interceptSend,
|
||||
}}
|
||||
textareaPlaceholder={
|
||||
userHasSentMessage
|
||||
? I18n.t('store_chat_placeholder_continue')
|
||||
: I18n.t('store_chat_placeholder_blank')
|
||||
}
|
||||
isOnboardingCentered
|
||||
headerNode={headerNode}
|
||||
fileLimit={10}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const InitFail = () => {
|
||||
const { refreshMessageList } = useChatArea();
|
||||
const [sessionId] = useState(() => getSlardarInstance()?.config()?.sessionId);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
await Promise.resolve();
|
||||
throw new CustomError('BotDebugAreaInitFail', '');
|
||||
})();
|
||||
}, []);
|
||||
return (
|
||||
<div className={retryStyles['home-state']}>
|
||||
<IconAlertCircle className={retryStyles['fail-page-icon']} />
|
||||
<div className={retryStyles['fail-page-text']}>
|
||||
<span>{I18n.t('coze_home_page_fail_text')}</span>
|
||||
<span
|
||||
className={retryStyles['fail-page-retry']}
|
||||
onClick={refreshMessageList}
|
||||
>
|
||||
{I18n.t('coze_home_page_fail_btn_retry')}
|
||||
</span>
|
||||
</div>
|
||||
{!!sessionId && (
|
||||
<div className="leading-[12px] mt-[8px] text-[12px] text-gray-400">
|
||||
{sessionId}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 { useRef } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { BotMode } from '@coze-arch/bot-api/playground_api';
|
||||
import { useBotSkillStore } from '@coze-studio/bot-detail-store/bot-skill';
|
||||
import { useBotInfoStore } from '@coze-studio/bot-detail-store/bot-info';
|
||||
import { manuallySwitchAgent } from '@coze-studio/bot-detail-store';
|
||||
import {
|
||||
ShortcutBar,
|
||||
getUIModeByBizScene,
|
||||
type ShortCutCommand,
|
||||
} from '@coze-common/chat-area-plugins-chat-shortcuts';
|
||||
import { useShowBackGround } from '@coze-common/chat-area/hooks/public/use-show-bgackground';
|
||||
import { type ChatInputIntegrationController } from '@coze-common/chat-area';
|
||||
|
||||
import s from '../../index.module.less';
|
||||
|
||||
export const ShortcutBarRender = ({
|
||||
controller,
|
||||
onShortcutActive,
|
||||
}: {
|
||||
controller: ChatInputIntegrationController;
|
||||
onShortcutActive?: (shortcut: ShortCutCommand | undefined) => void;
|
||||
}) => (
|
||||
<ShortcutBarRenderImpl
|
||||
controller={controller}
|
||||
onShortcutActive={onShortcutActive}
|
||||
/>
|
||||
);
|
||||
|
||||
const ShortcutBarRenderImpl: React.FC<{
|
||||
controller: ChatInputIntegrationController;
|
||||
onShortcutActive?: (shortcut: ShortCutCommand | undefined) => void;
|
||||
}> = ({ controller, onShortcutActive }) => {
|
||||
const activeShortcutRef = useRef<ShortCutCommand | undefined>(undefined);
|
||||
const showBackground = useShowBackGround();
|
||||
|
||||
const { mode, botName, botUrl } = useBotInfoStore(
|
||||
useShallow(state => ({
|
||||
botUrl: state.icon_url,
|
||||
botName: state.name,
|
||||
mode: state.mode,
|
||||
})),
|
||||
);
|
||||
const { chatShortcuts } = useBotSkillStore(
|
||||
useShallow(state => ({
|
||||
chatShortcuts: state.shortcut,
|
||||
})),
|
||||
);
|
||||
|
||||
const chatShortcutsWithBotInfo = chatShortcuts.shortcut_list?.map(
|
||||
shortcut => ({
|
||||
...shortcut,
|
||||
bot_info: {
|
||||
icon_url: botUrl,
|
||||
name: botName,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const singleModeShortcuts = chatShortcutsWithBotInfo?.filter(
|
||||
shortcut => !shortcut.agent_id,
|
||||
);
|
||||
|
||||
const showShortcuts = {
|
||||
[BotMode.SingleMode]: singleModeShortcuts,
|
||||
[BotMode.WorkflowMode]: [],
|
||||
[BotMode.MultiMode]: chatShortcutsWithBotInfo,
|
||||
}[mode];
|
||||
|
||||
const defaultId = showShortcuts?.at(0)?.command_id;
|
||||
|
||||
if (mode === BotMode.WorkflowMode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ShortcutBar
|
||||
shortcuts={showShortcuts ?? []}
|
||||
defaultId={defaultId}
|
||||
wrapperClassName={s['coz-debug-shortcut-bar-wrapper']}
|
||||
uiMode={getUIModeByBizScene({
|
||||
bizScene: 'debug',
|
||||
showBackground,
|
||||
})}
|
||||
onActiveShortcutChange={(shortcutInfo, isTemplateShortcutActive) => {
|
||||
activeShortcutRef.current = shortcutInfo;
|
||||
// 开启template快捷指令时,隐藏输入框&快捷指令bar
|
||||
const chatInputSlotVisible = !isTemplateShortcutActive;
|
||||
controller.setChatInputSlotVisible(chatInputSlotVisible);
|
||||
// 当template快捷指令激活时,禁用发送多模态消息
|
||||
onShortcutActive?.(shortcutInfo);
|
||||
// 如果指定了agent,切换到指定的agent
|
||||
if (mode === BotMode.MultiMode) {
|
||||
shortcutInfo?.agent_id && manuallySwitchAgent(shortcutInfo.agent_id);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
.home-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 100%;
|
||||
|
||||
:global(.semi-spin-children) {
|
||||
background: white !important;
|
||||
}
|
||||
|
||||
.fail-page-icon {
|
||||
font-size: 32px;
|
||||
color: #FF2710;
|
||||
}
|
||||
|
||||
.fail-page-text {
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.fail-page-retry {
|
||||
cursor: pointer;
|
||||
color: #4D53E8;
|
||||
}
|
||||
}
|
||||
17
frontend/packages/agent-ide/chat-debug-area/src/typings.d.ts
vendored
Normal file
17
frontend/packages/agent-ide/chat-debug-area/src/typings.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/// <reference types='@coze-arch/bot-typings' />
|
||||
Reference in New Issue
Block a user