feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
const { defineConfig } = require('@coze-arch/stylelint-config');
module.exports = defineConfig({
extends: [],
});

View File

@@ -0,0 +1,16 @@
# @coze-agent-ide/chat-debug-area
> Project template for react component with storybook.
## Features
- [x] eslint & ts
- [x] esm bundle
- [x] umd bundle
- [x] storybook
## Commands
- init: `rush update`
- dev: `npm run dev`
- build: `npm run build`

View File

@@ -0,0 +1,12 @@
{
"operationSettings": [
{
"operationName": "test:cov",
"outputFolderNames": ["coverage"]
},
{
"operationName": "ts-check",
"outputFolderNames": ["./dist"]
}
]
}

View File

@@ -0,0 +1,7 @@
const { defineConfig } = require('@coze-arch/eslint-config');
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'web',
rules: {},
});

View File

@@ -0,0 +1,103 @@
{
"name": "@coze-agent-ide/chat-debug-area",
"version": "0.0.1",
"description": "bot编辑页调试对话区",
"license": "Apache-2.0",
"author": "meixuliang.3@bytedance.com",
"maintainers": [],
"exports": {
".": "./src/index.tsx",
"./onboarding": "./src/components/onboarding-message-pop/index.tsx"
},
"main": "src/index.tsx",
"typesVersions": {
"*": {
"./onboarding": [
"./src/components/onboarding-message-pop/index.tsx"
]
}
},
"scripts": {
"build": "exit 0",
"lint": "eslint ./ --cache",
"test": "vitest --run --passWithNoTests",
"test:cov": "npm run test -- --coverage"
},
"dependencies": {
"@coze-agent-ide/chat-answer-action-adapter": "workspace:*",
"@coze-agent-ide/chat-area-plugin-debug-common": "workspace:*",
"@coze-agent-ide/chat-components-adapter": "workspace:*",
"@coze-agent-ide/onboarding": "workspace:*",
"@coze-arch/bot-api": "workspace:*",
"@coze-arch/bot-error": "workspace:*",
"@coze-arch/bot-flags": "workspace:*",
"@coze-arch/bot-hooks": "workspace:*",
"@coze-arch/bot-semi": "workspace:*",
"@coze-arch/bot-studio-store": "workspace:*",
"@coze-arch/bot-tea": "workspace:*",
"@coze-arch/bot-utils": "workspace:*",
"@coze-arch/coze-design": "0.0.6-alpha.346d77",
"@coze-arch/i18n": "workspace:*",
"@coze-arch/idl": "workspace:*",
"@coze-arch/logger": "workspace:*",
"@coze-arch/report-events": "workspace:*",
"@coze-arch/report-tti": "workspace:*",
"@coze-common/chat-answer-action": "workspace:*",
"@coze-common/chat-area": "workspace:*",
"@coze-common/chat-area-plugin-chat-background": "workspace:*",
"@coze-common/chat-area-plugin-message-grab": "workspace:*",
"@coze-common/chat-area-plugin-reasoning": "workspace:*",
"@coze-common/chat-area-plugin-resume": "workspace:*",
"@coze-common/chat-area-plugins-chat-shortcuts": "workspace:*",
"@coze-common/chat-core": "workspace:*",
"@coze-common/chat-uikit": "workspace:*",
"@coze-common/chat-workflow-render": "workspace:*",
"@coze-studio/user-store": "workspace:*",
"@douyinfe/semi-icons": "^2.36.0",
"ahooks": "^3.7.8",
"classnames": "^2.3.2",
"copy-to-clipboard": "^3.3.3",
"dayjs": "^1.11.7",
"immer": "^10.0.3",
"lodash-es": "^4.17.21",
"nanoid": "^4.0.2",
"use-event-callback": "~0.1.0",
"zustand": "^4.4.7"
},
"devDependencies": {
"@coze-agent-ide/space-bot": "workspace:*",
"@coze-arch/bot-env": "workspace:*",
"@coze-arch/bot-typings": "workspace:*",
"@coze-arch/eslint-config": "workspace:*",
"@coze-arch/stylelint-config": "workspace:*",
"@coze-arch/ts-config": "workspace:*",
"@coze-arch/vitest-config": "workspace:*",
"@coze-studio/bot-detail-store": "workspace:*",
"@rsbuild/core": "1.1.13",
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.1.2",
"@testing-library/react-hooks": "^8.0.1",
"@types/lodash-es": "^4.17.10",
"@types/node": "18.18.9",
"@types/react": "18.2.37",
"@types/react-dom": "18.2.15",
"@vitest/coverage-v8": "~3.0.5",
"react": "~18.2.0",
"react-dom": "~18.2.0",
"react-is": ">= 16.8.0",
"react-router-dom": "^6.22.0",
"styled-components": ">= 2",
"stylelint": "^15.11.0",
"typescript": "~5.8.2",
"vite": "^4.3.9",
"vite-plugin-svgr": "~3.3.0",
"vitest": "~3.0.5",
"webpack": "~5.91.0"
},
"peerDependencies": {
"react": ">=18.2.0",
"react-dom": ">=18.2.0"
},
"// deps": "immer@^10.0.3 为脚本自动补齐,请勿改动"
}

View File

@@ -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;
}

View File

@@ -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"
/>
);
};

View File

@@ -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;
}
}

View File

@@ -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>
);
};

View File

@@ -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;

View File

@@ -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;
}

View 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>
);
};

View File

@@ -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);
}
}}
/>
);
};

View File

@@ -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;
}
}

View 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' />

View File

@@ -0,0 +1,123 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@coze-arch/ts-config/tsconfig.web.json",
"compilerOptions": {
"types": [],
"strictNullChecks": true,
"noImplicitAny": true,
"rootDir": "./src",
"outDir": "./dist",
"tsBuildInfoFile": "./dist/tsconfig.build.tsbuildinfo"
},
"include": ["src"],
"references": [
{
"path": "../../arch/bot-api/tsconfig.build.json"
},
{
"path": "../../arch/bot-env/tsconfig.build.json"
},
{
"path": "../../arch/bot-error/tsconfig.build.json"
},
{
"path": "../../arch/bot-flags/tsconfig.build.json"
},
{
"path": "../../arch/bot-hooks/tsconfig.build.json"
},
{
"path": "../../arch/bot-store/tsconfig.build.json"
},
{
"path": "../../arch/bot-tea/tsconfig.build.json"
},
{
"path": "../../arch/bot-typings/tsconfig.build.json"
},
{
"path": "../../arch/bot-utils/tsconfig.build.json"
},
{
"path": "../../arch/i18n/tsconfig.build.json"
},
{
"path": "../../arch/idl/tsconfig.build.json"
},
{
"path": "../../arch/logger/tsconfig.build.json"
},
{
"path": "../../arch/report-events/tsconfig.build.json"
},
{
"path": "../../arch/report-tti/tsconfig.build.json"
},
{
"path": "../chat-answer-action-adapter/tsconfig.build.json"
},
{
"path": "../chat-area-plugin-debug-common/tsconfig.build.json"
},
{
"path": "../chat-components-adapter/tsconfig.build.json"
},
{
"path": "../../common/chat-area/chat-answer-action/tsconfig.build.json"
},
{
"path": "../../common/chat-area/chat-area-plugin-reasoning/tsconfig.build.json"
},
{
"path": "../../common/chat-area/chat-area/tsconfig.build.json"
},
{
"path": "../../common/chat-area/chat-core/tsconfig.build.json"
},
{
"path": "../../common/chat-area/chat-uikit/tsconfig.build.json"
},
{
"path": "../../common/chat-area/chat-workflow-render/tsconfig.build.json"
},
{
"path": "../../common/chat-area/plugin-chat-background/tsconfig.build.json"
},
{
"path": "../../common/chat-area/plugin-chat-shortcuts/tsconfig.build.json"
},
{
"path": "../../common/chat-area/plugin-message-grab/tsconfig.build.json"
},
{
"path": "../../common/chat-area/plugin-resume/tsconfig.build.json"
},
{
"path": "../../components/bot-semi/tsconfig.build.json"
},
{
"path": "../../../config/eslint-config/tsconfig.build.json"
},
{
"path": "../../../config/stylelint-config/tsconfig.build.json"
},
{
"path": "../../../config/ts-config/tsconfig.build.json"
},
{
"path": "../../../config/vitest-config/tsconfig.build.json"
},
{
"path": "../onboarding/tsconfig.build.json"
},
{
"path": "../space-bot/tsconfig.build.json"
},
{
"path": "../../studio/stores/bot-detail/tsconfig.build.json"
},
{
"path": "../../studio/user-store/tsconfig.build.json"
}
]
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"composite": true
},
"references": [
{
"path": "./tsconfig.build.json"
},
{
"path": "./tsconfig.misc.json"
}
],
"exclude": ["**/*"]
}

View File

@@ -0,0 +1,18 @@
{
"extends": "@coze-arch/ts-config/tsconfig.web.json",
"$schema": "https://json.schemastore.org/tsconfig",
"include": ["__tests__", "stories", "vitest.config.ts", "tailwind.config.ts"],
"exclude": ["./dist"],
"references": [
{
"path": "./tsconfig.build.json"
}
],
"compilerOptions": {
"rootDir": "./",
"outDir": "./dist",
"types": ["vitest/globals"],
"strictNullChecks": true,
"noImplicitAny": true
}
}

View File

@@ -0,0 +1,22 @@
/*
* 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 { defineConfig } from '@coze-arch/vitest-config';
export default defineConfig({
dirname: __dirname,
preset: 'web',
});