feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { produce } from 'immer';
|
||||
import { type AuditInfo } from '@coze-arch/idl/playground_api';
|
||||
import { type GetDraftBotInfoAgwData } from '@coze-arch/bot-api/playground_api';
|
||||
|
||||
import {
|
||||
type SetterAction,
|
||||
setterActionFactory,
|
||||
} from '../utils/setter-factory';
|
||||
|
||||
export const getDefaultAuditInfoStore = (): AuditInfoStore => ({
|
||||
audit_status: 1,
|
||||
});
|
||||
|
||||
export type AuditInfoStore = AuditInfo;
|
||||
|
||||
export interface AuditInfoAction {
|
||||
setAuditInfo: SetterAction<AuditInfoStore>;
|
||||
setAuditInfoByImmer: (update: (state: AuditInfoStore) => void) => void;
|
||||
initStore: (botData: GetDraftBotInfoAgwData) => void;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const useAuditInfoStore = create<AuditInfoStore & AuditInfoAction>()(
|
||||
devtools(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
...getDefaultAuditInfoStore(),
|
||||
setAuditInfo: setterActionFactory<AuditInfoStore>(set),
|
||||
setAuditInfoByImmer: update =>
|
||||
set(produce<AuditInfoStore>(auditInfo => update(auditInfo))),
|
||||
initStore: botData => {
|
||||
const { setAuditInfo } = get();
|
||||
botData && setAuditInfo(botData?.latest_audit_info ?? {});
|
||||
},
|
||||
clear: () => {
|
||||
set({ ...getDefaultAuditInfoStore() });
|
||||
},
|
||||
})),
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'botStudio.botDetail.auditInfo',
|
||||
},
|
||||
),
|
||||
);
|
||||
160
frontend/packages/studio/stores/bot-detail/src/store/bot-info.ts
Normal file
160
frontend/packages/studio/stores/bot-detail/src/store/bot-info.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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 { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { produce } from 'immer';
|
||||
import {
|
||||
type BotInfo,
|
||||
type GetDraftBotInfoAgwData,
|
||||
type UserInfo,
|
||||
type BusinessType,
|
||||
} from '@coze-arch/idl/playground_api';
|
||||
import {
|
||||
BotMarketStatus,
|
||||
BotMode,
|
||||
type ConnectorInfo,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import {
|
||||
type SetterAction,
|
||||
setterActionFactory,
|
||||
} from '../utils/setter-factory';
|
||||
|
||||
export const getDefaultBotInfoStore = (): BotInfoStore => ({
|
||||
botId: '',
|
||||
mode: BotMode.SingleMode,
|
||||
botMarketStatus: BotMarketStatus.Offline,
|
||||
name: '',
|
||||
description: '',
|
||||
icon_uri: '',
|
||||
icon_url: '',
|
||||
create_time: '',
|
||||
creator_id: '',
|
||||
update_time: '',
|
||||
connector_id: '',
|
||||
publisher: {},
|
||||
has_publish: false,
|
||||
connectors: [],
|
||||
publish_time: '',
|
||||
space_id: '',
|
||||
version: '',
|
||||
raw: {},
|
||||
});
|
||||
|
||||
/** 定义bot的基础信息*/
|
||||
export interface BotInfoStore {
|
||||
botId: string;
|
||||
/** 发布的业务线详情 */
|
||||
connectors: Array<ConnectorInfo>;
|
||||
/** for前端,发布时间 */
|
||||
publish_time: string;
|
||||
/** 空间id */
|
||||
space_id: string;
|
||||
/** 是否已发布 */
|
||||
has_publish: boolean;
|
||||
mode: BotMode;
|
||||
/** 最新发布版本时传发布人 */
|
||||
publisher: UserInfo;
|
||||
/** bot上架后的商品状态 */
|
||||
botMarketStatus: BotMarketStatus;
|
||||
/** bot名称 */
|
||||
name: string;
|
||||
/** bot描述 */
|
||||
description: string;
|
||||
/** bot 图标uri */
|
||||
icon_uri: string;
|
||||
/** bot 图标url */
|
||||
icon_url: string;
|
||||
/** 创建时间 */
|
||||
create_time: string;
|
||||
/** 创建人id */
|
||||
creator_id: string;
|
||||
/** 更新时间 */
|
||||
update_time: string;
|
||||
/** 业务线 */
|
||||
connector_id: string;
|
||||
/** multi agent mode agent信息 */
|
||||
// agents?: Array<Agent>;
|
||||
/** 版本,毫秒 */
|
||||
version: string;
|
||||
/** multi_agent结构体 */
|
||||
// multi_agent_info?: MultiAgentInfo;
|
||||
/** @ 保存了原始bot数据, readonly **/
|
||||
raw: BotInfo;
|
||||
/** 抖音分身应用id */
|
||||
appId?: string;
|
||||
/** 业务类型 默认0 分身业务1 */
|
||||
businessType?: BusinessType;
|
||||
}
|
||||
|
||||
export interface BotInfoAction {
|
||||
setBotInfo: SetterAction<BotInfoStore>;
|
||||
setBotInfoByImmer: (update: (state: BotInfoStore) => void) => void;
|
||||
transformVo2Dto: (data: GetDraftBotInfoAgwData) => BotInfoStore;
|
||||
initStore: (data: GetDraftBotInfoAgwData) => void;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const useBotInfoStore = create<BotInfoStore & BotInfoAction>()(
|
||||
devtools(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
...getDefaultBotInfoStore(),
|
||||
setBotInfo: setterActionFactory<BotInfoStore>(set),
|
||||
setBotInfoByImmer: update =>
|
||||
set(produce<BotInfoStore>(state => update(state))),
|
||||
// eslint-disable-next-line complexity
|
||||
transformVo2Dto: data => {
|
||||
// 将botData转化为botInfoStore, 只取BotInfoStore中的固定字段
|
||||
const botInfo = data.bot_info ?? {};
|
||||
return {
|
||||
botId: botInfo?.bot_id ?? '',
|
||||
mode: botInfo?.bot_mode ?? BotMode.SingleMode,
|
||||
botMarketStatus: data.bot_market_status ?? BotMarketStatus.Offline,
|
||||
name: botInfo.name ?? '',
|
||||
description: botInfo.description ?? '',
|
||||
icon_uri: botInfo.icon_uri ?? '',
|
||||
icon_url: botInfo.icon_url ?? '',
|
||||
create_time: botInfo.create_time ?? '',
|
||||
creator_id: botInfo.creator_id ?? '',
|
||||
update_time: botInfo.update_time ?? '',
|
||||
connector_id: botInfo.connector_id ?? '',
|
||||
version: botInfo.version ?? '',
|
||||
publisher: data.publisher ?? {},
|
||||
has_publish: data.has_publish ?? false,
|
||||
connectors: data.connectors ?? [],
|
||||
publish_time: data.publish_time ?? '',
|
||||
space_id: data.space_id ?? '',
|
||||
businessType: botInfo.business_type,
|
||||
appId: data.app_id ?? '',
|
||||
raw: botInfo,
|
||||
};
|
||||
},
|
||||
initStore: data => {
|
||||
const { transformVo2Dto } = get();
|
||||
const transformedData = transformVo2Dto(data);
|
||||
set(transformedData);
|
||||
},
|
||||
clear: () => {
|
||||
set({ ...getDefaultBotInfoStore() });
|
||||
},
|
||||
})),
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'botStudio.botDetail.botInfo',
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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 { I18n } from '@coze-arch/i18n';
|
||||
import { BotTableRWMode } from '@coze-arch/bot-api/memory';
|
||||
import {
|
||||
type BackgroundImageInfo,
|
||||
SuggestedQuestionsShowMode,
|
||||
SuggestReplyMode,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import {
|
||||
type VoicesInfo,
|
||||
type BotSuggestionConfig,
|
||||
type DatabaseInfo,
|
||||
type ExtendOnboardingContent,
|
||||
type TimeCapsuleConfig,
|
||||
type TTSInfo,
|
||||
} from '../../types/skill';
|
||||
|
||||
export const DEFAULT_KNOWLEDGE_CONFIG = () => {
|
||||
const baseConfig = {
|
||||
top_k: 3,
|
||||
min_score: 0.5,
|
||||
auto: true,
|
||||
search_strategy: 0,
|
||||
show_source: false,
|
||||
};
|
||||
return baseConfig;
|
||||
};
|
||||
|
||||
export const DEFAULT_BOT_NODE_SUGGESTION_CONFIG = (): BotSuggestionConfig => ({
|
||||
suggest_reply_mode: SuggestReplyMode.UseOriginBotMode,
|
||||
customized_suggest_prompt: '',
|
||||
});
|
||||
|
||||
export const DEFAULT_SUGGESTION_PROMPT = () =>
|
||||
IS_OVERSEA
|
||||
? I18n.t('bot_suggestion_customize_default_gpt')
|
||||
: I18n.t('bot_suggestion_customize_default_seed');
|
||||
|
||||
export const DEFAULT_ONBOARDING_CONFIG = (): ExtendOnboardingContent => ({
|
||||
prologue: '',
|
||||
suggested_questions: [],
|
||||
suggested_questions_show_mode: SuggestedQuestionsShowMode.Random,
|
||||
});
|
||||
|
||||
export const DEFAULT_SUGGESTION_CONFIG = (): BotSuggestionConfig => ({
|
||||
suggest_reply_mode: SuggestReplyMode.WithDefaultPrompt,
|
||||
customized_suggest_prompt: '',
|
||||
});
|
||||
|
||||
export const DEFAULT_BACKGROUND_IMAGE_LIST = (): BackgroundImageInfo[] => [];
|
||||
export const DEFAULT_DATABASE = (): DatabaseInfo => ({
|
||||
tableId: '',
|
||||
name: '',
|
||||
desc: '',
|
||||
icon_uri: '',
|
||||
readAndWriteMode: BotTableRWMode.LimitedReadWrite,
|
||||
tableMemoryList: [],
|
||||
});
|
||||
export const DEFAULT_TTS_CONFIG = (): TTSInfo => ({
|
||||
muted: false,
|
||||
close_voice_call: false,
|
||||
i18n_lang_voice: {},
|
||||
autoplay: false,
|
||||
autoplay_voice: {},
|
||||
tag_list: [],
|
||||
debugVoice: [],
|
||||
i18n_lang_voice_str: {},
|
||||
});
|
||||
|
||||
export const DEFAULT_TIME_CAPSULE_CONFIG = (): TimeCapsuleConfig => ({
|
||||
time_capsule_mode: 0,
|
||||
disable_prompt_calling: 0, // 默认支持在prompt调用
|
||||
time_capsule_time_to_live: '0',
|
||||
});
|
||||
|
||||
export const DEFAULT_SHORTCUT_CONFIG = () => ({
|
||||
shortcut_list: [],
|
||||
shortcut_sort: [],
|
||||
});
|
||||
|
||||
export const DEFAULT_VOICES_INFO: () => VoicesInfo = () => ({
|
||||
defaultUserInputType: undefined,
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export {
|
||||
useBotSkillStore,
|
||||
getDefaultBotSkillStore,
|
||||
type BotSkillStore,
|
||||
type BotSkillAction,
|
||||
} from './store';
|
||||
export {
|
||||
DEFAULT_SUGGESTION_PROMPT,
|
||||
DEFAULT_KNOWLEDGE_CONFIG,
|
||||
} from './defaults';
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* 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 { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { isFunction } from 'lodash-es';
|
||||
import { produce } from 'immer';
|
||||
import { type ShortCutStruct } from '@coze-agent-ide/tool-config';
|
||||
import {
|
||||
type HookInfo,
|
||||
type LayoutInfo,
|
||||
type BackgroundImageInfo,
|
||||
type GetDraftBotInfoAgwData,
|
||||
} from '@coze-arch/bot-api/playground_api';
|
||||
import {
|
||||
type DefaultUserInputType,
|
||||
FileboxInfoMode,
|
||||
type PluginApi,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
import { botInputLengthService } from '@coze-agent-ide/bot-input-length-limit';
|
||||
|
||||
import {
|
||||
type SetterAction,
|
||||
setterActionFactory,
|
||||
} from '../../utils/setter-factory';
|
||||
import { getPluginApisFilterExample } from '../../utils/plugin-apis';
|
||||
import {
|
||||
type VoicesInfo,
|
||||
type BotSuggestionConfig,
|
||||
type DatabaseInfo,
|
||||
type DatabaseList,
|
||||
type EnabledPluginApi,
|
||||
type ExtendOnboardingContent,
|
||||
type FileboxConfig,
|
||||
type KnowledgeConfig,
|
||||
type TaskManageInfo,
|
||||
type TimeCapsuleConfig,
|
||||
type TTSInfo,
|
||||
type VariableItem,
|
||||
type WorkFlowItemType,
|
||||
} from '../../types/skill';
|
||||
import { transformDto2Vo, transformVo2Dto } from './transform';
|
||||
import {
|
||||
DEFAULT_BACKGROUND_IMAGE_LIST,
|
||||
DEFAULT_DATABASE,
|
||||
DEFAULT_KNOWLEDGE_CONFIG,
|
||||
DEFAULT_ONBOARDING_CONFIG,
|
||||
DEFAULT_SHORTCUT_CONFIG,
|
||||
DEFAULT_SUGGESTION_CONFIG,
|
||||
DEFAULT_TIME_CAPSULE_CONFIG,
|
||||
DEFAULT_TTS_CONFIG,
|
||||
DEFAULT_VOICES_INFO,
|
||||
} from './defaults';
|
||||
|
||||
export const getDefaultBotSkillStore = (): BotSkillStore => ({
|
||||
pluginApis: [],
|
||||
workflows: [],
|
||||
knowledge: {
|
||||
dataSetList: [],
|
||||
dataSetInfo: DEFAULT_KNOWLEDGE_CONFIG(),
|
||||
},
|
||||
|
||||
taskInfo: {
|
||||
user_task_allowed: false,
|
||||
data: [],
|
||||
task_list: [],
|
||||
loading: false,
|
||||
},
|
||||
variables: [],
|
||||
database: DEFAULT_DATABASE(),
|
||||
databaseList: [],
|
||||
onboardingContent: DEFAULT_ONBOARDING_CONFIG(),
|
||||
suggestionConfig: DEFAULT_SUGGESTION_CONFIG(),
|
||||
tts: DEFAULT_TTS_CONFIG(),
|
||||
voicesInfo: DEFAULT_VOICES_INFO(),
|
||||
timeCapsule: DEFAULT_TIME_CAPSULE_CONFIG(),
|
||||
filebox: {
|
||||
mode: FileboxInfoMode.Off,
|
||||
},
|
||||
backgroundImageInfoList: DEFAULT_BACKGROUND_IMAGE_LIST(),
|
||||
shortcut: DEFAULT_SHORTCUT_CONFIG(),
|
||||
layoutInfo: {},
|
||||
devHooks: {},
|
||||
});
|
||||
|
||||
/** Persona & Prompt 区域 */
|
||||
export interface BotSkillStore {
|
||||
// region Bot 和 Agent 维度共有 skills
|
||||
/** 已选的 plugin api */
|
||||
pluginApis: EnabledPluginApi[];
|
||||
/** 已选 workflow */
|
||||
workflows: WorkFlowItemType[];
|
||||
/** Knowledge 配置 */
|
||||
knowledge: KnowledgeConfig;
|
||||
// endregion
|
||||
|
||||
// region Bot 维度独有 skills
|
||||
/**
|
||||
* task 配置
|
||||
*
|
||||
* 不含已添加的 task,已添加的在组件内独立管理
|
||||
*/
|
||||
taskInfo: TaskManageInfo;
|
||||
/**
|
||||
* variable 默认值配置
|
||||
*
|
||||
* 不含右上角现值,现值为打开弹窗后请求获得的组件状态
|
||||
*/
|
||||
variables: VariableItem[];
|
||||
/**
|
||||
* database 默认值配置
|
||||
*
|
||||
* 不含右上角现值,现值为打开弹窗后请求获得的组件状态
|
||||
*/
|
||||
database: DatabaseInfo;
|
||||
/**
|
||||
* database 多表默认值配置
|
||||
*
|
||||
* 不含右上角现值,现值为打开弹窗后请求获得的组件状态
|
||||
*/
|
||||
databaseList: DatabaseList;
|
||||
/** 开场白配置 */
|
||||
onboardingContent: ExtendOnboardingContent;
|
||||
/** 用户问题建议配置 */
|
||||
suggestionConfig: BotSuggestionConfig;
|
||||
// endregion
|
||||
/** 文字转语音 */
|
||||
tts: TTSInfo;
|
||||
/** 语音设置 上面 tts 在命名和含义划分上已经不准确了 但是牵扯甚广 */
|
||||
voicesInfo: VoicesInfo;
|
||||
// 时间胶囊
|
||||
timeCapsule: TimeCapsuleConfig;
|
||||
filebox: FileboxConfig;
|
||||
// 聊天背景图
|
||||
backgroundImageInfoList: BackgroundImageInfo[];
|
||||
// 快捷指令
|
||||
shortcut: ShortCutStruct;
|
||||
// hooks
|
||||
devHooks?: HookInfo;
|
||||
layoutInfo: LayoutInfo;
|
||||
}
|
||||
|
||||
export interface BotSkillAction {
|
||||
setBotSkill: SetterAction<BotSkillStore>;
|
||||
setBotSkillByImmer: (update: (state: BotSkillStore) => void) => void;
|
||||
updateSkillPluginApis: (pluginApis: PluginApi[]) => void;
|
||||
updateSkillWorkflows: (workflows: WorkFlowItemType[]) => void;
|
||||
updateSkillKnowledgeDatasetList: (
|
||||
dataSetList: KnowledgeConfig['dataSetList'],
|
||||
) => void;
|
||||
updateSkillKnowledgeDatasetInfo: (
|
||||
dataSetInfo: KnowledgeConfig['dataSetInfo'],
|
||||
) => void;
|
||||
updateSkillTaskInfo: (taskInfo: Partial<TaskManageInfo>) => void;
|
||||
updateSkillDatabase: (database: Partial<DatabaseInfo>) => void;
|
||||
updateSkillDatabaseList: (database: DatabaseList) => void;
|
||||
updateSkillOnboarding: (
|
||||
onboarding:
|
||||
| Partial<ExtendOnboardingContent>
|
||||
| ((prev: ExtendOnboardingContent) => Partial<ExtendOnboardingContent>),
|
||||
) => void;
|
||||
updateSkillLayoutInfo: (layoutInfo: LayoutInfo) => void;
|
||||
setBackgroundImageInfoList: (params: BackgroundImageInfo[]) => void;
|
||||
setSuggestionConfig: (config: Partial<BotSuggestionConfig>) => void;
|
||||
setDefaultUserInputType: (type: DefaultUserInputType) => void;
|
||||
transformDto2Vo: typeof transformDto2Vo;
|
||||
transformVo2Dto: typeof transformVo2Dto;
|
||||
initStore: (botData: GetDraftBotInfoAgwData) => void;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const useBotSkillStore = create<BotSkillStore & BotSkillAction>()(
|
||||
devtools(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
...getDefaultBotSkillStore(),
|
||||
|
||||
setBotSkill: setterActionFactory<BotSkillStore>(set),
|
||||
setBotSkillByImmer: update =>
|
||||
set(produce<BotSkillStore>(botSkill => update(botSkill))),
|
||||
updateSkillPluginApis: (pluginApis: PluginApi[]) => {
|
||||
set(s => ({
|
||||
...s,
|
||||
pluginApis: getPluginApisFilterExample(pluginApis),
|
||||
}));
|
||||
},
|
||||
updateSkillWorkflows: workflows => set(s => ({ ...s, workflows })),
|
||||
updateSkillKnowledgeDatasetList: dataSetList =>
|
||||
set(
|
||||
produce<BotSkillStore>(s => {
|
||||
s.knowledge.dataSetList = dataSetList;
|
||||
}),
|
||||
),
|
||||
updateSkillKnowledgeDatasetInfo: dataSetInfo =>
|
||||
set(
|
||||
produce<BotSkillStore>(s => {
|
||||
s.knowledge.dataSetInfo = dataSetInfo;
|
||||
}),
|
||||
),
|
||||
updateSkillTaskInfo: taskInfo =>
|
||||
set(s => ({
|
||||
...s,
|
||||
taskInfo: { ...s.taskInfo, ...taskInfo },
|
||||
})),
|
||||
updateSkillDatabase: database =>
|
||||
set(s => ({
|
||||
...s,
|
||||
database: { ...s.database, ...database },
|
||||
})),
|
||||
updateSkillDatabaseList: databaseList =>
|
||||
set(
|
||||
produce<BotSkillStore>(s => {
|
||||
s.databaseList = databaseList;
|
||||
}),
|
||||
),
|
||||
updateSkillOnboarding: update =>
|
||||
set(s => ({
|
||||
...s,
|
||||
onboardingContent: {
|
||||
...s.onboardingContent,
|
||||
...(isFunction(update) ? update(s.onboardingContent) : update),
|
||||
},
|
||||
})),
|
||||
updateSkillLayoutInfo: layoutInfo => {
|
||||
set(s => ({
|
||||
...s,
|
||||
layoutInfo,
|
||||
}));
|
||||
},
|
||||
setSuggestionConfig: config =>
|
||||
set(s => ({
|
||||
...s,
|
||||
suggestionConfig: { ...s.suggestionConfig, ...config },
|
||||
})),
|
||||
setBackgroundImageInfoList: config =>
|
||||
set(s => ({
|
||||
...s,
|
||||
backgroundImageInfoList: [...config],
|
||||
})),
|
||||
setDefaultUserInputType: inputType =>
|
||||
set(
|
||||
state =>
|
||||
produce(state, draft => {
|
||||
draft.voicesInfo.defaultUserInputType = inputType;
|
||||
}),
|
||||
false,
|
||||
'setDefaultUserInputType',
|
||||
),
|
||||
transformDto2Vo,
|
||||
transformVo2Dto,
|
||||
initStore: botData => {
|
||||
const { bot_info: botInfo, bot_option_data: optionData } = botData;
|
||||
set({
|
||||
pluginApis: transformDto2Vo.plugin(
|
||||
botInfo?.plugin_info_list,
|
||||
optionData?.plugin_detail_map,
|
||||
optionData?.plugin_api_detail_map,
|
||||
),
|
||||
workflows: transformDto2Vo.workflow(
|
||||
botInfo?.workflow_info_list,
|
||||
optionData?.workflow_detail_map,
|
||||
),
|
||||
knowledge: transformDto2Vo.knowledge(
|
||||
botInfo?.knowledge,
|
||||
optionData?.knowledge_detail_map,
|
||||
),
|
||||
taskInfo: transformDto2Vo.task(botInfo?.task_info),
|
||||
variables: transformDto2Vo.variables(botInfo?.variable_list),
|
||||
databaseList: transformDto2Vo.databaseList(botInfo?.database_list),
|
||||
timeCapsule: transformDto2Vo.timeCapsule(
|
||||
botInfo?.bot_tag_info?.time_capsule_info,
|
||||
),
|
||||
filebox: transformDto2Vo.filebox(botInfo?.filebox_info),
|
||||
|
||||
onboardingContent:
|
||||
botInputLengthService.sliceWorkInfoOnboardingByMaxLength(
|
||||
transformDto2Vo.onboarding(botInfo?.onboarding_info),
|
||||
),
|
||||
suggestionConfig: transformDto2Vo.suggestionConfig(
|
||||
botInfo?.suggest_reply_info,
|
||||
),
|
||||
tts: transformDto2Vo.tts(botInfo?.voices_info),
|
||||
voicesInfo: transformDto2Vo.voicesInfo(botInfo.voices_info),
|
||||
backgroundImageInfoList: botInfo?.background_image_info_list ?? [],
|
||||
shortcut: transformDto2Vo.shortcut(
|
||||
botInfo?.shortcut_sort ?? [],
|
||||
optionData?.shortcut_command_list,
|
||||
),
|
||||
devHooks: transformDto2Vo.hookInfo(botInfo?.hook_info),
|
||||
layoutInfo: transformDto2Vo.layoutInfo(botInfo?.layout_info),
|
||||
});
|
||||
},
|
||||
clear: () => {
|
||||
set({ ...getDefaultBotSkillStore() });
|
||||
},
|
||||
})),
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'botStudio.botDetail.botSkill',
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* 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 { nanoid } from 'nanoid';
|
||||
import { isNumber, mapValues } from 'lodash-es';
|
||||
import { type ShortCutStruct } from '@coze-agent-ide/tool-config';
|
||||
import {
|
||||
type PluginStatus,
|
||||
type PluginType,
|
||||
} from '@coze-arch/idl/plugin_develop';
|
||||
import { BotTableRWMode } from '@coze-arch/idl/memory';
|
||||
import {
|
||||
type Int64,
|
||||
type PluginInfo,
|
||||
type PluginDetal,
|
||||
type PluginAPIDetal,
|
||||
type WorkflowInfo,
|
||||
type WorkflowDetail,
|
||||
type Knowledge,
|
||||
type KnowledgeDetail,
|
||||
type TaskInfo,
|
||||
type Variable,
|
||||
type Database,
|
||||
type TimeCapsuleInfo,
|
||||
type OnboardingInfo,
|
||||
type SuggestReplyInfo,
|
||||
type VoicesInfo as IDLVoicesInfo,
|
||||
type FileboxInfo,
|
||||
FileboxInfoMode,
|
||||
TimeCapsuleMode,
|
||||
type ShortcutCommand,
|
||||
type BotInfoForUpdate,
|
||||
type SuggestReplyMode as SuggestReplyModeFromPlayground,
|
||||
type HookInfo,
|
||||
SuggestedQuestionsShowMode,
|
||||
type LayoutInfo,
|
||||
DisablePromptCalling,
|
||||
} from '@coze-arch/bot-api/playground_api';
|
||||
import { SuggestReplyMode } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import {
|
||||
type WorkFlowItemType,
|
||||
type EnabledPluginApi,
|
||||
type KnowledgeConfig,
|
||||
type TaskManageInfo,
|
||||
type VariableItem,
|
||||
type TimeCapsuleConfig,
|
||||
type ExtendOnboardingContent,
|
||||
type BotSuggestionConfig,
|
||||
type TTSInfo,
|
||||
type FileboxConfig,
|
||||
type DatabaseList,
|
||||
type TableMemoryItem,
|
||||
type VoicesInfo,
|
||||
} from '../../types/skill';
|
||||
import {
|
||||
DEFAULT_BOT_NODE_SUGGESTION_CONFIG,
|
||||
DEFAULT_KNOWLEDGE_CONFIG,
|
||||
DEFAULT_SUGGESTION_CONFIG,
|
||||
DEFAULT_SUGGESTION_PROMPT,
|
||||
DEFAULT_TTS_CONFIG,
|
||||
} from './defaults';
|
||||
|
||||
// 结构化 BotInfo 接口后的 数据转换
|
||||
export const transformDto2Vo = {
|
||||
plugin: (
|
||||
data?: PluginInfo[],
|
||||
plugins?: Record<Int64, PluginDetal>,
|
||||
pluginsAPIs?: Record<Int64, PluginAPIDetal>,
|
||||
): EnabledPluginApi[] =>
|
||||
data
|
||||
?.filter(i => i.plugin_id && i.api_id && plugins?.[i.plugin_id as string])
|
||||
?.map(item => {
|
||||
const plugin = plugins?.[item.plugin_id as string];
|
||||
const api = pluginsAPIs?.[item.api_id as string];
|
||||
return {
|
||||
plugin_icon: plugin?.icon_url,
|
||||
name: api?.name,
|
||||
desc: api?.description,
|
||||
plugin_id: item.plugin_id,
|
||||
plugin_name: plugin?.name,
|
||||
api_id: item.api_id,
|
||||
parameters:
|
||||
api?.parameters?.map(i => ({
|
||||
...i,
|
||||
// 兼容开源页接口字段命名不同
|
||||
desc: i.description,
|
||||
required: i.is_required,
|
||||
})) || [],
|
||||
is_official: plugin?.is_official,
|
||||
// 这个类型历史原因 在服务端侧各服务不统一,实际业务使用为 枚举类型
|
||||
plugin_type: plugin?.plugin_type as unknown as PluginType,
|
||||
status: plugin?.plugin_status as unknown as PluginStatus,
|
||||
};
|
||||
}) ?? [],
|
||||
|
||||
workflow: (
|
||||
data?: WorkflowInfo[],
|
||||
config?: Record<Int64, WorkflowDetail>,
|
||||
): WorkFlowItemType[] =>
|
||||
data
|
||||
?.filter(i => i.workflow_id && config?.[i.workflow_id])
|
||||
?.map(item => {
|
||||
const w = config?.[item.workflow_id as string];
|
||||
return {
|
||||
workflow_id: w?.id ?? '',
|
||||
plugin_id: w?.plugin_id ?? '',
|
||||
name: w?.name ?? '',
|
||||
desc: w?.description ?? '',
|
||||
plugin_icon: w?.icon_url ?? '',
|
||||
flow_mode: item?.flow_mode,
|
||||
parameters:
|
||||
w?.api_detail?.parameters?.map(i => ({
|
||||
...i,
|
||||
desc: i.description,
|
||||
required: i.is_required,
|
||||
})) || [],
|
||||
};
|
||||
}) ?? [],
|
||||
// 知识库
|
||||
knowledge: (
|
||||
data?: Knowledge,
|
||||
config?: Record<string, KnowledgeDetail>,
|
||||
): KnowledgeConfig => {
|
||||
if (!data) {
|
||||
return {
|
||||
dataSetList: [],
|
||||
dataSetInfo: DEFAULT_KNOWLEDGE_CONFIG(),
|
||||
};
|
||||
} else {
|
||||
const dataSetList =
|
||||
data?.knowledge_info
|
||||
?.filter(i => i.id && config?.[i.id as string])
|
||||
?.map(item => {
|
||||
const k = config?.[item.id as string];
|
||||
return {
|
||||
id: k?.id,
|
||||
name: k?.name,
|
||||
avatar_url: k?.icon_url,
|
||||
icon_url: k?.icon_url,
|
||||
dataset_id: k?.id,
|
||||
};
|
||||
}) ?? [];
|
||||
|
||||
return {
|
||||
dataSetList,
|
||||
dataSetInfo: {
|
||||
min_score: data?.min_score ?? 0,
|
||||
top_k: Number(data?.top_k ?? 0),
|
||||
auto: Boolean(data?.auto),
|
||||
|
||||
search_strategy: data?.search_strategy,
|
||||
no_recall_reply_mode: data?.no_recall_reply_mode,
|
||||
no_recall_reply_customize_prompt:
|
||||
data?.no_recall_reply_customize_prompt,
|
||||
show_source: data?.show_source,
|
||||
show_source_mode: data?.show_source_mode,
|
||||
recall_strategy: data.recall_strategy,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
task: (data?: TaskInfo): TaskManageInfo => ({
|
||||
user_task_allowed: Boolean(data?.user_task_allowed),
|
||||
task_list: [],
|
||||
loading: false,
|
||||
data: [],
|
||||
}),
|
||||
|
||||
variables: (data?: Variable[]): VariableItem[] =>
|
||||
data?.map(item => ({
|
||||
id: nanoid(),
|
||||
key: item.key ?? '',
|
||||
description: item.description,
|
||||
default_value: item.default_value,
|
||||
is_system: !!item.is_system,
|
||||
prompt_disabled: !!item.prompt_disabled,
|
||||
is_disabled: !!item.is_disabled,
|
||||
})) ?? [],
|
||||
|
||||
databaseList: (data?: Database[]): DatabaseList => {
|
||||
const res: DatabaseList = [];
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
data.forEach(target => {
|
||||
if (target?.table_id && target.field_list?.length) {
|
||||
res.push({
|
||||
tableId: target.table_id as string,
|
||||
name: target.table_name as string,
|
||||
desc: target.table_desc as string,
|
||||
extra_info: {
|
||||
prompt_disabled: String(target.prompt_disabled),
|
||||
},
|
||||
readAndWriteMode:
|
||||
(target.rw_mode as BotTableRWMode) ||
|
||||
BotTableRWMode.LimitedReadWrite,
|
||||
tableMemoryList: (target.field_list as TableMemoryItem[])?.map(
|
||||
i => ({
|
||||
...i,
|
||||
nanoid: nanoid(),
|
||||
// 服务端 rpc 已使用 string 的 id 难以修改,这里兼容一下后续链路需要的 number
|
||||
id: Number(i.id),
|
||||
}),
|
||||
),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return res;
|
||||
},
|
||||
|
||||
timeCapsule: (data?: TimeCapsuleInfo): TimeCapsuleConfig => ({
|
||||
//@ts-expect-error 接口枚举类型取值重定义
|
||||
time_capsule_mode: data?.time_capsule_mode ?? TimeCapsuleMode.Off,
|
||||
disable_prompt_calling:
|
||||
data?.disable_prompt_calling ?? DisablePromptCalling.Off,
|
||||
time_capsule_time_to_live: data?.time_capsule_time_to_live ?? '0',
|
||||
}),
|
||||
|
||||
filebox: (data?: FileboxInfo): FileboxConfig => ({
|
||||
mode: data?.Mode ?? FileboxInfoMode.Off,
|
||||
}),
|
||||
|
||||
onboarding: (data?: OnboardingInfo): ExtendOnboardingContent => ({
|
||||
prologue: data?.prologue ?? '',
|
||||
suggested_questions_show_mode:
|
||||
data?.suggested_questions_show_mode ?? SuggestedQuestionsShowMode.Random,
|
||||
suggested_questions:
|
||||
data?.suggested_questions?.map(item => ({
|
||||
id: item,
|
||||
content: item,
|
||||
})) ?? [],
|
||||
}),
|
||||
|
||||
suggestionConfig: (
|
||||
data?: SuggestReplyInfo,
|
||||
isBotNode = false,
|
||||
): BotSuggestionConfig => {
|
||||
const defaultSuggestionConfig: BotSuggestionConfig = isBotNode
|
||||
? DEFAULT_BOT_NODE_SUGGESTION_CONFIG()
|
||||
: DEFAULT_SUGGESTION_CONFIG();
|
||||
//@ts-expect-error xxxxxxxxxxxxx SuggestReplyMode 两个文件定义不一致
|
||||
const suggestionConfig: BotSuggestionConfig = isNumber(
|
||||
data?.suggest_reply_mode,
|
||||
)
|
||||
? {
|
||||
suggest_reply_mode: data?.suggest_reply_mode,
|
||||
customized_suggest_prompt: data?.customized_suggest_prompt,
|
||||
}
|
||||
: defaultSuggestionConfig;
|
||||
|
||||
if (
|
||||
!suggestionConfig.customized_suggest_prompt &&
|
||||
suggestionConfig.suggest_reply_mode ===
|
||||
SuggestReplyMode.WithCustomizedPrompt
|
||||
) {
|
||||
suggestionConfig.customized_suggest_prompt = DEFAULT_SUGGESTION_PROMPT();
|
||||
}
|
||||
return suggestionConfig;
|
||||
},
|
||||
|
||||
tts: (ttsConfig?: IDLVoicesInfo): TTSInfo => {
|
||||
if (!ttsConfig || typeof ttsConfig !== 'object') {
|
||||
return DEFAULT_TTS_CONFIG();
|
||||
}
|
||||
if (!('muted' in ttsConfig && 'i18n_lang_voice' in ttsConfig)) {
|
||||
return DEFAULT_TTS_CONFIG();
|
||||
}
|
||||
const isValidObject = (obj: unknown): Record<string, number> =>
|
||||
obj && typeof obj === 'object' ? (obj as Record<string, number>) : {};
|
||||
|
||||
return {
|
||||
muted: !!ttsConfig.muted,
|
||||
close_voice_call: !!ttsConfig.voice_call,
|
||||
i18n_lang_voice: isValidObject(ttsConfig?.i18n_lang_voice),
|
||||
i18n_lang_voice_str: ttsConfig.i18n_lang_voice_str ?? {},
|
||||
autoplay: !!ttsConfig.autoplay,
|
||||
autoplay_voice: isValidObject(ttsConfig?.autoplay_voice),
|
||||
debugVoice: [],
|
||||
};
|
||||
},
|
||||
voicesInfo: (idlVoicesInfo: IDLVoicesInfo | undefined): VoicesInfo => ({
|
||||
defaultUserInputType: idlVoicesInfo?.default_user_input_type,
|
||||
}),
|
||||
shortcut: (
|
||||
shortcutSortList: string[],
|
||||
config?: ShortcutCommand[],
|
||||
): ShortCutStruct => ({
|
||||
shortcut_sort: shortcutSortList,
|
||||
//@ts-expect-error ShortCutCommand 前后端定义不一致,前端分化做了类型约束
|
||||
shortcut_list: config,
|
||||
}),
|
||||
|
||||
hookInfo: (data?: HookInfo): HookInfo | undefined => data,
|
||||
layoutInfo: (layoutInfoFromService?: LayoutInfo): LayoutInfo => ({
|
||||
workflow_id: layoutInfoFromService?.workflow_id,
|
||||
plugin_id: layoutInfoFromService?.plugin_id,
|
||||
}),
|
||||
};
|
||||
|
||||
export const transformVo2Dto = {
|
||||
plugin: (plugins: EnabledPluginApi[]): BotInfoForUpdate['plugin_info_list'] =>
|
||||
plugins.map(plugin => ({
|
||||
api_id: plugin.api_id,
|
||||
plugin_id: plugin.plugin_id,
|
||||
api_name: plugin.name,
|
||||
})),
|
||||
|
||||
workflow: (
|
||||
workflows: WorkFlowItemType[],
|
||||
): BotInfoForUpdate['workflow_info_list'] =>
|
||||
workflows.map(
|
||||
w =>
|
||||
({
|
||||
workflow_id: w.workflow_id,
|
||||
plugin_id: w.plugin_id,
|
||||
flow_mode: w.flow_mode,
|
||||
workflow_name: w.name,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
}) as any,
|
||||
),
|
||||
|
||||
knowledge: (knowledge: KnowledgeConfig): BotInfoForUpdate['knowledge'] => ({
|
||||
...knowledge.dataSetInfo,
|
||||
knowledge_info: knowledge.dataSetList
|
||||
.filter(i => !!i.dataset_id)
|
||||
.map(dataset => ({
|
||||
id: dataset.dataset_id,
|
||||
name: dataset.name,
|
||||
})),
|
||||
}),
|
||||
|
||||
task: (task: Partial<TaskManageInfo>): BotInfoForUpdate['task_info'] => ({
|
||||
user_task_allowed: task.user_task_allowed,
|
||||
}),
|
||||
|
||||
suggestionConfig: (
|
||||
suggestion: BotSuggestionConfig,
|
||||
): BotInfoForUpdate['suggest_reply_info'] => ({
|
||||
suggest_reply_mode:
|
||||
suggestion.suggest_reply_mode as unknown as SuggestReplyModeFromPlayground,
|
||||
customized_suggest_prompt: suggestion.customized_suggest_prompt,
|
||||
}),
|
||||
|
||||
variables: (variables: VariableItem[]): BotInfoForUpdate['variable_list'] =>
|
||||
variables.map(v => ({
|
||||
key: v.key,
|
||||
description: v.description,
|
||||
default_value: v.default_value,
|
||||
is_system: v.is_system,
|
||||
prompt_disabled: v.prompt_disabled,
|
||||
is_disabled: v.is_disabled,
|
||||
})),
|
||||
|
||||
databaseList: (
|
||||
databaseList: DatabaseList,
|
||||
): BotInfoForUpdate['database_list'] =>
|
||||
databaseList.map(d => ({
|
||||
table_id: d.tableId,
|
||||
table_name: d.name,
|
||||
table_desc: d.desc,
|
||||
rw_mode: d.readAndWriteMode,
|
||||
field_list: d.tableMemoryList.map(f => ({
|
||||
name: f.name,
|
||||
desc: f.desc,
|
||||
type: f.type,
|
||||
must_required: f.must_required,
|
||||
id: f.id?.toString(),
|
||||
})),
|
||||
})),
|
||||
|
||||
timeCapsule: (
|
||||
timeCapsule: TimeCapsuleConfig,
|
||||
): BotInfoForUpdate['bot_tag_info'] => ({
|
||||
time_capsule_info: {
|
||||
time_capsule_mode:
|
||||
timeCapsule.time_capsule_mode as unknown as TimeCapsuleMode,
|
||||
disable_prompt_calling:
|
||||
timeCapsule.disable_prompt_calling as unknown as DisablePromptCalling,
|
||||
time_capsule_time_to_live: timeCapsule.time_capsule_time_to_live,
|
||||
},
|
||||
}),
|
||||
|
||||
filebox: (filebox: FileboxConfig): BotInfoForUpdate['filebox_info'] => ({
|
||||
Mode: filebox.mode,
|
||||
}),
|
||||
|
||||
onboarding: (
|
||||
data: ExtendOnboardingContent,
|
||||
): BotInfoForUpdate['onboarding_info'] => ({
|
||||
prologue: data.prologue,
|
||||
suggested_questions_show_mode: data.suggested_questions_show_mode,
|
||||
suggested_questions: data.suggested_questions
|
||||
.map(i => i.content?.trim())
|
||||
.filter(c => !!c),
|
||||
}),
|
||||
|
||||
tts: (tts: Partial<TTSInfo>) => ({
|
||||
muted: tts.muted,
|
||||
i18n_lang_voice: tts.i18n_lang_voice,
|
||||
autoplay: tts.autoplay,
|
||||
autoplay_voice: tts.autoplay_voice,
|
||||
voice_call: tts.close_voice_call,
|
||||
i18n_lang_voice_str: tts.i18n_lang_voice_str,
|
||||
}),
|
||||
|
||||
voicesInfo: (voicesInfo: VoicesInfo) => ({
|
||||
default_user_input_type: voicesInfo.defaultUserInputType,
|
||||
}),
|
||||
|
||||
shortcut: (shortcut: ShortCutStruct): BotInfoForUpdate['shortcut_sort'] =>
|
||||
shortcut.shortcut_sort,
|
||||
|
||||
layoutInfo: (info: LayoutInfo): BotInfoForUpdate['layout_info'] =>
|
||||
// undefined 会被 axios 过滤,这里后端需要有 key
|
||||
mapValues(info, (val?: string) => val ?? ''),
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 { logger } from '@coze-arch/logger';
|
||||
import { useSpaceStore } from '@coze-arch/bot-studio-store';
|
||||
import { SpaceType } from '@coze-arch/bot-api/developer_api';
|
||||
import { PlaygroundApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { getBotDetailIsReadonly } from '../utils/get-read-only';
|
||||
import { useBotInfoStore } from '../store/bot-info';
|
||||
import { useCollaborationStore } from './collaboration';
|
||||
|
||||
export const collaborateQuota = async () => {
|
||||
try {
|
||||
const { botId } = useBotInfoStore.getState();
|
||||
const { inCollaboration, setCollaboration } =
|
||||
useCollaborationStore.getState();
|
||||
const {
|
||||
space: { space_type },
|
||||
} = useSpaceStore.getState();
|
||||
const isPersonal = space_type === SpaceType.Personal;
|
||||
|
||||
const isReadOnly = getBotDetailIsReadonly();
|
||||
if (isReadOnly || isPersonal) {
|
||||
return;
|
||||
}
|
||||
const { data: collaborationQuota } =
|
||||
await PlaygroundApi.GetBotCollaborationQuota({
|
||||
bot_id: botId,
|
||||
});
|
||||
setCollaboration({
|
||||
// 多人协作模式,或非多人协作模式有额度时可启用
|
||||
openCollaboratorsEnable:
|
||||
(!inCollaboration && collaborationQuota?.open_collaborators_enable) ||
|
||||
inCollaboration,
|
||||
// 非多人协作模式 && 可以升级套餐,则展示升级套餐按钮
|
||||
canUpgrade: collaborationQuota?.can_upgrade || false,
|
||||
// 用户最大开启多人协作bot的数量限制
|
||||
maxCollaborationBotCount:
|
||||
collaborationQuota?.max_collaboration_bot_count || 0,
|
||||
maxCollaboratorsCount: collaborationQuota?.max_collaborators_count || 0,
|
||||
currentCollaborationBotCount:
|
||||
collaborationQuota.current_collaboration_bot_count || 0,
|
||||
});
|
||||
} catch (error) {
|
||||
const e = error instanceof Error ? error : new Error(error as string);
|
||||
logger.error({ error: e });
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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 { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { produce } from 'immer';
|
||||
import {
|
||||
Branch,
|
||||
type GetDraftBotInfoAgwData,
|
||||
} from '@coze-arch/idl/playground_api';
|
||||
import { type BotCollaboratorStatus } from '@coze-arch/idl/developer_api';
|
||||
|
||||
import {
|
||||
type SetterAction,
|
||||
setterActionFactory,
|
||||
} from '../utils/setter-factory';
|
||||
|
||||
export const getDefaultCollaborationStore = (): CollaborationStore => ({
|
||||
inCollaboration: false,
|
||||
sameWithOnline: false,
|
||||
committer_name: '',
|
||||
editLockStatus: EditLockStatus.Offline,
|
||||
collaboratorStatus: {
|
||||
commitable: false,
|
||||
operateable: false,
|
||||
manageable: false,
|
||||
},
|
||||
baseVersion: '',
|
||||
branch: Branch.Base,
|
||||
commit_time: '',
|
||||
commit_version: '',
|
||||
openCollaboratorsEnable: false,
|
||||
canUpgrade: false,
|
||||
currentCollaborationBotCount: 0,
|
||||
maxCollaborationBotCount: 0,
|
||||
maxCollaboratorsCount: 0,
|
||||
});
|
||||
export enum EditLockStatus {
|
||||
Lose, // 无编辑锁
|
||||
Holder, // 有编辑锁
|
||||
Offline, // 断网状态,可编辑,但是不可保存。避免联网后覆盖掉断网期间其他页面的编辑
|
||||
}
|
||||
/**多人协作*/
|
||||
export interface CollaborationStore {
|
||||
editLockStatus: EditLockStatus;
|
||||
inCollaboration: boolean;
|
||||
collaboratorStatus: BotCollaboratorStatus;
|
||||
sameWithOnline: boolean;
|
||||
baseVersion: string;
|
||||
/** for前端,最近一次的提交人 */
|
||||
committer_name: string;
|
||||
/** 获取的是什么分支的内容 */
|
||||
branch?: Branch;
|
||||
/** for前端,提交时间 */
|
||||
commit_time: string;
|
||||
commit_version: string;
|
||||
/** 能否开启协作开关 false不可开启 */
|
||||
openCollaboratorsEnable: boolean;
|
||||
/** 是否可升级套餐 顶级付费账号不可升级 */
|
||||
canUpgrade: boolean;
|
||||
// 当前开启的协作bot数量
|
||||
currentCollaborationBotCount: number;
|
||||
/** 用户最大开启多人协作bot的数量限制 */
|
||||
maxCollaborationBotCount: number;
|
||||
/** 协作者数量上限 */
|
||||
maxCollaboratorsCount: number;
|
||||
}
|
||||
|
||||
export interface CollaborationAction {
|
||||
setCollaboration: SetterAction<CollaborationStore>;
|
||||
setCollaborationByImmer: (
|
||||
update: (state: CollaborationStore) => void,
|
||||
) => void;
|
||||
getBaseVersion: () => string | undefined;
|
||||
initStore: (data: GetDraftBotInfoAgwData) => void;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const useCollaborationStore = create<
|
||||
CollaborationStore & CollaborationAction
|
||||
>()(
|
||||
devtools(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
...getDefaultCollaborationStore(),
|
||||
setCollaboration: setterActionFactory<CollaborationStore>(set),
|
||||
setCollaborationByImmer: update =>
|
||||
set(produce<CollaborationStore>(state => update(state))),
|
||||
getBaseVersion: () => {
|
||||
const { baseVersion, inCollaboration } = get();
|
||||
// FG开启且单人模式下,不提供 base_version
|
||||
if (!inCollaboration) {
|
||||
return undefined;
|
||||
}
|
||||
return baseVersion;
|
||||
},
|
||||
initStore: info => {
|
||||
set({
|
||||
collaboratorStatus: info?.collaborator_status,
|
||||
inCollaboration: info.in_collaboration,
|
||||
baseVersion: info.commit_version,
|
||||
sameWithOnline: info?.same_with_online,
|
||||
committer_name: info?.committer_name,
|
||||
commit_version: info?.commit_version,
|
||||
branch: info?.branch,
|
||||
commit_time: info?.commit_time,
|
||||
});
|
||||
},
|
||||
clear: () => {
|
||||
set({ ...getDefaultCollaborationStore() });
|
||||
},
|
||||
})),
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'botStudio.botDetail.collaboration',
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { produce } from 'immer';
|
||||
|
||||
import {
|
||||
type SetterAction,
|
||||
setterActionFactory,
|
||||
} from '../utils/setter-factory';
|
||||
|
||||
export type DiffTaskType = 'prompt' | 'model' | '';
|
||||
|
||||
export const getDefaultDiffTaskStore = (): DiffTaskStore => ({
|
||||
diffTask: '',
|
||||
hasContinueTask: false,
|
||||
continueTask: '',
|
||||
promptDiffInfo: {
|
||||
diffPromptResourceId: '',
|
||||
diffMode: 'draft',
|
||||
diffPrompt: '',
|
||||
},
|
||||
});
|
||||
|
||||
/** diff任务相关信息 */
|
||||
export interface DiffTaskStore {
|
||||
/** 当前diff任务类型 */
|
||||
diffTask: DiffTaskType;
|
||||
/** 是否有继续任务 */
|
||||
hasContinueTask: boolean;
|
||||
/** 继续任务信息 */
|
||||
continueTask: DiffTaskType;
|
||||
/** 当前diff任务信息 */
|
||||
promptDiffInfo: {
|
||||
diffPromptResourceId: string;
|
||||
diffPrompt: string;
|
||||
diffMode: 'draft' | 'new-diff';
|
||||
};
|
||||
}
|
||||
|
||||
export interface DiffTaskAction {
|
||||
setDiffTask: SetterAction<DiffTaskStore>;
|
||||
setDiffTaskByImmer: (update: (state: DiffTaskStore) => void) => void;
|
||||
enterDiffMode: (props: {
|
||||
diffTask: DiffTaskType;
|
||||
promptDiffInfo?: {
|
||||
diffPromptResourceId: string;
|
||||
diffMode: 'draft' | 'new-diff';
|
||||
diffPrompt: string;
|
||||
};
|
||||
}) => void;
|
||||
exitDiffMode: () => void;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const useDiffTaskStore = create<DiffTaskStore & DiffTaskAction>()(
|
||||
devtools(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
...getDefaultDiffTaskStore(),
|
||||
setDiffTask: setterActionFactory<DiffTaskStore>(set),
|
||||
setDiffTaskByImmer: update =>
|
||||
set(produce<DiffTaskStore>(state => update(state))),
|
||||
enterDiffMode: ({ diffTask, promptDiffInfo }) => {
|
||||
set(
|
||||
produce<DiffTaskStore>(state => {
|
||||
state.diffTask = diffTask;
|
||||
}),
|
||||
false,
|
||||
'enterDiffMode',
|
||||
);
|
||||
if (diffTask === 'prompt' && promptDiffInfo) {
|
||||
get().setDiffTaskByImmer(state => {
|
||||
state.promptDiffInfo = promptDiffInfo;
|
||||
});
|
||||
}
|
||||
},
|
||||
exitDiffMode: () => {
|
||||
get().clear();
|
||||
},
|
||||
clear: () => {
|
||||
set({ ...getDefaultDiffTaskStore() }, false, 'clear');
|
||||
},
|
||||
})),
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'botStudio.botDetail.diffTask',
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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 { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { produce } from 'immer';
|
||||
import { type TaskNotice, type PicTask } from '@coze-arch/idl/playground_api';
|
||||
|
||||
import {
|
||||
type GenerateImageState,
|
||||
type GenerateImageAction,
|
||||
type GenerateAvatarModal,
|
||||
GenerateType,
|
||||
DotStatus,
|
||||
type GenerateBackGroundModal,
|
||||
} from '../types/generate-image';
|
||||
|
||||
export const DEFAULT_BOT_GENERATE_AVATAR_MODAL = (): GenerateAvatarModal => ({
|
||||
visible: false,
|
||||
activeKey: GenerateType.Static,
|
||||
selectedImage: { id: '', img_info: {} },
|
||||
gif: {
|
||||
loading: false,
|
||||
dotStatus: DotStatus.None,
|
||||
text: '',
|
||||
image: { id: '', img_info: {} },
|
||||
},
|
||||
image: {
|
||||
loading: false,
|
||||
dotStatus: DotStatus.None,
|
||||
text: '',
|
||||
textCustomizable: false,
|
||||
},
|
||||
});
|
||||
|
||||
export const DEFAULT_BOT_GENERATE_BACKGROUND_MODAL =
|
||||
(): GenerateBackGroundModal => ({
|
||||
activeKey: GenerateType.Static,
|
||||
selectedImage: { id: '', img_info: {} },
|
||||
gif: {
|
||||
loading: false,
|
||||
dotStatus: DotStatus.None,
|
||||
text: '',
|
||||
image: { id: '', img_info: {} },
|
||||
},
|
||||
image: {
|
||||
loading: false,
|
||||
dotStatus: DotStatus.None,
|
||||
promptInfo: {},
|
||||
},
|
||||
});
|
||||
|
||||
export const useGenerateImageStore = create<
|
||||
GenerateImageState & GenerateImageAction
|
||||
>()(
|
||||
devtools(
|
||||
subscribeWithSelector(set => ({
|
||||
imageList: [],
|
||||
noticeList: [],
|
||||
generateAvatarModal: DEFAULT_BOT_GENERATE_AVATAR_MODAL(),
|
||||
generateBackGroundModal: DEFAULT_BOT_GENERATE_BACKGROUND_MODAL(),
|
||||
clearGenerateImageStore: () => {
|
||||
set({
|
||||
imageList: [],
|
||||
noticeList: [],
|
||||
generateAvatarModal: DEFAULT_BOT_GENERATE_AVATAR_MODAL(),
|
||||
generateBackGroundModal: DEFAULT_BOT_GENERATE_BACKGROUND_MODAL(),
|
||||
});
|
||||
},
|
||||
updateImageList: (imageList: PicTask[]) => {
|
||||
set(s => ({
|
||||
...s,
|
||||
imageList,
|
||||
}));
|
||||
},
|
||||
pushImageList: (image: PicTask) => {
|
||||
set(s => ({
|
||||
...s,
|
||||
imageList: [...s.imageList, image],
|
||||
}));
|
||||
},
|
||||
updateNoticeList: (notices: TaskNotice[]) => {
|
||||
set(s => ({ ...s, notices }));
|
||||
},
|
||||
setGenerateAvatarModal: generateAvatarModal => {
|
||||
set({ generateAvatarModal });
|
||||
},
|
||||
resetGenerateAvatarModal: () => {
|
||||
set({ generateAvatarModal: DEFAULT_BOT_GENERATE_AVATAR_MODAL() });
|
||||
},
|
||||
setGenerateAvatarModalByImmer: update =>
|
||||
set(
|
||||
produce<GenerateImageState>(({ generateAvatarModal }) =>
|
||||
update(generateAvatarModal),
|
||||
),
|
||||
),
|
||||
setGenerateBackgroundModalByImmer: update =>
|
||||
set(
|
||||
produce<GenerateImageState>(({ generateBackGroundModal }) =>
|
||||
update(generateBackGroundModal),
|
||||
),
|
||||
),
|
||||
})),
|
||||
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'botStudio.botDetail.botGenerateImage',
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 { useAuditInfoStore } from '@/store/audit-info';
|
||||
|
||||
import { useQueryCollectStore } from './query-collect';
|
||||
import { usePersonaStore } from './persona';
|
||||
import { usePageRuntimeStore } from './page-runtime';
|
||||
import { useMultiAgentStore } from './multi-agent';
|
||||
import { useMonetizeConfigStore } from './monetize-config-store';
|
||||
import { useModelStore } from './model';
|
||||
import { useManuallySwitchAgentStore } from './manually-switch-agent-store';
|
||||
import { useDiffTaskStore } from './diff-task';
|
||||
import { useCollaborationStore } from './collaboration';
|
||||
import { useBotSkillStore } from './bot-skill';
|
||||
import { useBotInfoStore } from './bot-info';
|
||||
|
||||
export interface BotDetailStoreSet {
|
||||
usePersonaStore: typeof usePersonaStore;
|
||||
useQueryCollectStore: typeof useQueryCollectStore;
|
||||
useMultiAgentStore: typeof useMultiAgentStore;
|
||||
useModelStore: typeof useModelStore;
|
||||
useBotSkillStore: typeof useBotSkillStore;
|
||||
useBotInfoStore: typeof useBotInfoStore;
|
||||
useCollaborationStore: typeof useCollaborationStore;
|
||||
usePageRuntimeStore: typeof usePageRuntimeStore;
|
||||
useMonetizeConfigStore: typeof useMonetizeConfigStore;
|
||||
useManuallySwitchAgentStore: typeof useManuallySwitchAgentStore;
|
||||
useDiffTaskStore: typeof useDiffTaskStore;
|
||||
}
|
||||
|
||||
interface UseBotDetailStoreSet {
|
||||
getStore: () => BotDetailStoreSet;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const useBotDetailStoreSet: UseBotDetailStoreSet = {
|
||||
getStore() {
|
||||
return {
|
||||
usePersonaStore,
|
||||
useQueryCollectStore,
|
||||
useMultiAgentStore,
|
||||
useModelStore,
|
||||
useBotSkillStore,
|
||||
useBotInfoStore,
|
||||
useCollaborationStore,
|
||||
usePageRuntimeStore,
|
||||
useMonetizeConfigStore,
|
||||
useManuallySwitchAgentStore,
|
||||
useAuditInfoStore,
|
||||
useDiffTaskStore,
|
||||
};
|
||||
},
|
||||
clear() {
|
||||
usePersonaStore.getState().clear();
|
||||
useQueryCollectStore.getState().clear();
|
||||
useMultiAgentStore.getState().clear();
|
||||
useModelStore.getState().clear();
|
||||
useBotSkillStore.getState().clear();
|
||||
useBotInfoStore.getState().clear();
|
||||
useCollaborationStore.getState().clear();
|
||||
usePageRuntimeStore.getState().clear();
|
||||
useMonetizeConfigStore.getState().reset();
|
||||
useManuallySwitchAgentStore.getState().clearAgentId();
|
||||
useAuditInfoStore.getState().clear();
|
||||
useDiffTaskStore.getState().clear();
|
||||
},
|
||||
};
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 用来满足一个神奇的功能
|
||||
* multi agent 模式下 正在回复中
|
||||
* 用户手动切换了 agent
|
||||
* 基于新的 agent 重新生成对话
|
||||
* 需要记录 agent 的切换是「手动」|「自动」
|
||||
*/
|
||||
|
||||
/**
|
||||
* !! 不和 Bot Detail 搅合在一起了。
|
||||
*/
|
||||
|
||||
import { devtools } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
|
||||
export interface ManuallySwitchAgentState {
|
||||
agentId: string | null;
|
||||
}
|
||||
|
||||
export interface ManuallySwitchAgentAction {
|
||||
recordAgentIdOnManuallySwitchAgent: (agentId: string) => void;
|
||||
clearAgentId: () => void;
|
||||
}
|
||||
|
||||
export const useManuallySwitchAgentStore = create<
|
||||
ManuallySwitchAgentAction & ManuallySwitchAgentState
|
||||
>()(
|
||||
devtools(
|
||||
set => ({
|
||||
agentId: null,
|
||||
recordAgentIdOnManuallySwitchAgent: agentId => {
|
||||
set({ agentId }, false, 'recordAgentIdOnManuallySwitchAgent');
|
||||
},
|
||||
clearAgentId: () => {
|
||||
set({ agentId: null }, false, 'clearAgentId');
|
||||
},
|
||||
}),
|
||||
{ enabled: IS_DEV_MODE, name: 'botStudio.manuallySwitchAgentStore' },
|
||||
),
|
||||
);
|
||||
158
frontend/packages/studio/stores/bot-detail/src/store/model.ts
Normal file
158
frontend/packages/studio/stores/bot-detail/src/store/model.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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 { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { produce } from 'immer';
|
||||
import {
|
||||
type BotInfoForUpdate,
|
||||
type ContextMode,
|
||||
type GetDraftBotInfoAgwData,
|
||||
} from '@coze-arch/idl/playground_api';
|
||||
import {
|
||||
ContextContentType,
|
||||
type Model,
|
||||
type ModelInfo,
|
||||
type ModelInfo as ModelInfoConfig,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import {
|
||||
type SetterAction,
|
||||
setterActionFactory,
|
||||
} from '../utils/setter-factory';
|
||||
import type { BotDetailModel } from '../types/model';
|
||||
export const DEFAULT_MODEL_INFO = (): ModelInfo => ({
|
||||
model: '',
|
||||
temperature: 0,
|
||||
max_tokens: 4096,
|
||||
top_p: 0,
|
||||
frequency_penalty: 0,
|
||||
presence_penalty: 0,
|
||||
prompt_id: 0,
|
||||
ShortMemPolicy: {
|
||||
ContextContentType: ContextContentType.USER_RES,
|
||||
},
|
||||
card_ids: [],
|
||||
});
|
||||
export const getDefaultModelStore = (): ModelStore => ({
|
||||
config: {
|
||||
model: '',
|
||||
temperature: 0,
|
||||
max_tokens: 4096,
|
||||
top_p: 0,
|
||||
frequency_penalty: 0,
|
||||
presence_penalty: 0,
|
||||
prompt_id: 0,
|
||||
ShortMemPolicy: {
|
||||
ContextContentType: ContextContentType.USER_RES,
|
||||
},
|
||||
card_ids: [],
|
||||
},
|
||||
modelList: [],
|
||||
});
|
||||
|
||||
/** Persona & Prompt 区域 */
|
||||
export interface ModelStore {
|
||||
config: ModelInfoConfig;
|
||||
/** 全部可选模型 */
|
||||
modelList: Model[];
|
||||
}
|
||||
|
||||
export interface ModelAction {
|
||||
setModel: SetterAction<ModelStore>;
|
||||
setModelByImmer: (update: (state: ModelStore) => void) => void;
|
||||
transformDto2Vo: (
|
||||
botData: GetDraftBotInfoAgwData,
|
||||
) => BotDetailModel['config'];
|
||||
transformVo2Dto: (
|
||||
model: BotDetailModel['config'],
|
||||
) => BotInfoForUpdate['model_info'];
|
||||
initStore: (botData: GetDraftBotInfoAgwData) => void;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const useModelStore = create<ModelStore & ModelAction>()(
|
||||
devtools(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
...getDefaultModelStore(),
|
||||
setModel: setterActionFactory<ModelStore>(set),
|
||||
setModelByImmer: update =>
|
||||
set(
|
||||
produce<ModelStore>(model => update(model)),
|
||||
false,
|
||||
'setModelByImmer',
|
||||
),
|
||||
transformDto2Vo: botData => {
|
||||
const modelInfo = botData.bot_info.model_info;
|
||||
const config = botData.bot_option_data?.model_detail_map;
|
||||
return {
|
||||
model: modelInfo?.model_id,
|
||||
temperature: modelInfo?.temperature,
|
||||
max_tokens: modelInfo?.max_tokens,
|
||||
top_p: modelInfo?.top_p,
|
||||
frequency_penalty: modelInfo?.frequency_penalty,
|
||||
presence_penalty: modelInfo?.presence_penalty,
|
||||
ShortMemPolicy: {
|
||||
ContextContentType: modelInfo?.short_memory_policy
|
||||
?.context_mode as unknown as ContextContentType,
|
||||
HistoryRound: modelInfo?.short_memory_policy?.history_round,
|
||||
},
|
||||
model_name:
|
||||
modelInfo?.model_id && config
|
||||
? config[modelInfo.model_id]?.model_name
|
||||
: '',
|
||||
|
||||
model_style: modelInfo?.model_style,
|
||||
response_format: modelInfo?.response_format,
|
||||
};
|
||||
},
|
||||
transformVo2Dto: model =>
|
||||
model?.model
|
||||
? {
|
||||
model_id: model.model,
|
||||
temperature: model.temperature,
|
||||
max_tokens: model.max_tokens,
|
||||
top_p: model.top_p,
|
||||
presence_penalty: model.presence_penalty,
|
||||
frequency_penalty: model.frequency_penalty,
|
||||
short_memory_policy: {
|
||||
history_round: model?.ShortMemPolicy?.HistoryRound,
|
||||
context_mode: model?.ShortMemPolicy
|
||||
?.ContextContentType as unknown as ContextMode,
|
||||
},
|
||||
response_format: model.response_format,
|
||||
model_style: model.model_style,
|
||||
}
|
||||
: {},
|
||||
initStore: botData => {
|
||||
const { transformDto2Vo } = get();
|
||||
const { bot_info, bot_option_data } = botData;
|
||||
bot_info?.model_info && bot_option_data?.model_detail_map
|
||||
? set({
|
||||
config: transformDto2Vo(botData),
|
||||
})
|
||||
: set({ config: DEFAULT_MODEL_INFO() });
|
||||
},
|
||||
clear: () => {
|
||||
set({ ...getDefaultModelStore() });
|
||||
},
|
||||
})),
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'botStudio.botDetail.model',
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 { devtools } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { isNil } from 'lodash-es';
|
||||
import {
|
||||
type BotMonetizationConfigData,
|
||||
BotMonetizationRefreshPeriod,
|
||||
} from '@coze-arch/idl/benefit';
|
||||
|
||||
export interface MonetizeConfigState {
|
||||
/** 是否开启付费 */
|
||||
isOn: boolean;
|
||||
/** 开启付费后,用户免费体验的次数 */
|
||||
freeCount: number;
|
||||
/** 刷新周期 */
|
||||
refreshCycle: BotMonetizationRefreshPeriod;
|
||||
}
|
||||
|
||||
export interface MonetizeConfigAction {
|
||||
setIsOn: (isOn: boolean) => void;
|
||||
setFreeCount: (freeCount: number) => void;
|
||||
setRefreshCycle: (refreshCycle: BotMonetizationRefreshPeriod) => void;
|
||||
initStore: (data: BotMonetizationConfigData) => void;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
const DEFAULT_STATE: () => MonetizeConfigState = () => ({
|
||||
isOn: false,
|
||||
freeCount: 0,
|
||||
refreshCycle: 1,
|
||||
});
|
||||
|
||||
export type MonetizeConfigStore = MonetizeConfigState & MonetizeConfigAction;
|
||||
|
||||
export const useMonetizeConfigStore = create<MonetizeConfigStore>()(
|
||||
devtools(
|
||||
(set, get) => ({
|
||||
...DEFAULT_STATE(),
|
||||
|
||||
setIsOn: isOn => set({ isOn }),
|
||||
setFreeCount: freeCount => set({ freeCount }),
|
||||
setRefreshCycle: refreshCycle => set({ refreshCycle }),
|
||||
initStore: data => {
|
||||
const { setIsOn, setFreeCount, setRefreshCycle } = get();
|
||||
setIsOn(isNil(data?.is_enable) ? true : data.is_enable);
|
||||
setFreeCount(
|
||||
isNil(data?.free_chat_allowance_count)
|
||||
? 0
|
||||
: data.free_chat_allowance_count,
|
||||
);
|
||||
setRefreshCycle(
|
||||
data?.refresh_period ?? BotMonetizationRefreshPeriod.Never,
|
||||
);
|
||||
},
|
||||
reset: () => set(DEFAULT_STATE()),
|
||||
}),
|
||||
{ enabled: IS_DEV_MODE, name: 'botStudio.monetizeConfig' },
|
||||
),
|
||||
);
|
||||
@@ -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 { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import type { AgentBizInfo } from '../../types/agent';
|
||||
|
||||
export const DEFAULT_AGENT_BIZ_INFO = (): AgentBizInfo => ({});
|
||||
export const DEFAULT_AGENT_DESCRIPTION = () =>
|
||||
I18n.t('multiagent_node_scenarios_context_default');
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { useMultiAgentStore, type MultiAgentStore } from './store';
|
||||
export { DEFAULT_AGENT_BIZ_INFO } from './defaults';
|
||||
@@ -0,0 +1,573 @@
|
||||
/*
|
||||
* 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 { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { isEqual, uniqWith } from 'lodash-es';
|
||||
import { produce } from 'immer';
|
||||
import { withSlardarIdButton } from '@coze-studio/bot-utils';
|
||||
import {
|
||||
type BotOptionData,
|
||||
type bot_common,
|
||||
type AgentReferenceInfo,
|
||||
type Agent as AgentFromPlayground,
|
||||
BotMode,
|
||||
type GetDraftBotInfoAgwData,
|
||||
} from '@coze-arch/idl/playground_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { useSpaceStore } from '@coze-arch/bot-studio-store';
|
||||
import { SpaceApiV2 } from '@coze-arch/bot-space-api';
|
||||
import { UIToast } from '@coze-arch/bot-semi';
|
||||
import {
|
||||
AgentType,
|
||||
AgentVersionCompat,
|
||||
MultiAgentSessionType,
|
||||
type PluginApi,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
import { PlaygroundApi } from '@coze-arch/bot-api';
|
||||
import { LineType } from '@flowgram-adapter/free-layout-editor';
|
||||
import type { WorkflowEdgeJSON } from '@flowgram-adapter/free-layout-editor';
|
||||
import type { IPoint } from '@flowgram-adapter/common';
|
||||
|
||||
import { type SetterAction, setterActionFactory } from '@/utils/setter-factory';
|
||||
import { getPluginApisFilterExample } from '@/utils/plugin-apis';
|
||||
import {
|
||||
findAgentByNextIntentID,
|
||||
findFirstAgent,
|
||||
findFirstAgentId,
|
||||
findTargetAgent,
|
||||
} from '@/utils/find-agent';
|
||||
import type { BotDetailSkill, KnowledgeConfig } from '@/types/skill';
|
||||
|
||||
import { useManuallySwitchAgentStore } from '../manually-switch-agent-store';
|
||||
import { useCollaborationStore } from '../collaboration';
|
||||
import { useBotInfoStore } from '../bot-info';
|
||||
import {
|
||||
type Agent,
|
||||
type ChatModeConfig,
|
||||
type DraftBotVo,
|
||||
type MultiSheetViewOpenState,
|
||||
} from '../../types/agent';
|
||||
import { transformDto2Vo, transformVo2Dto } from './transform';
|
||||
|
||||
export interface MultiAgentStore {
|
||||
agents: Agent[];
|
||||
edges: WorkflowEdgeJSON[];
|
||||
connector_type: LineType;
|
||||
/** 用于保存 bot 类型节点的 bot 信息 */
|
||||
botAgentInfos: DraftBotVo[];
|
||||
/**
|
||||
* 会话接管方式配置
|
||||
* 默认为 flow 模式
|
||||
*/
|
||||
chatModeConfig: ChatModeConfig;
|
||||
/** 当前agent id **/
|
||||
currentAgentID: string;
|
||||
/**muti 左右展开状态**/
|
||||
multiSheetViewOpen: MultiSheetViewOpenState;
|
||||
}
|
||||
|
||||
export const getDefaultMultiAgentStore = (): MultiAgentStore => ({
|
||||
agents: [],
|
||||
edges: [],
|
||||
connector_type: LineType.BEZIER,
|
||||
currentAgentID: '',
|
||||
botAgentInfos: [],
|
||||
multiSheetViewOpen: {
|
||||
left: true,
|
||||
right: true,
|
||||
},
|
||||
chatModeConfig: {
|
||||
type: MultiAgentSessionType.Host,
|
||||
currentHostId: '',
|
||||
},
|
||||
});
|
||||
|
||||
export interface MultiAgentAction {
|
||||
setMultiAgent: SetterAction<MultiAgentStore>;
|
||||
setMultiAgentByImmer: (update: (state: MultiAgentStore) => void) => void;
|
||||
setMultiSheetViewOpen: (state: Partial<MultiSheetViewOpenState>) => void;
|
||||
updatedCurrentAgentIdWithConnectStart: () => void;
|
||||
/** 重置 host 节点为 start 相连的节点 */
|
||||
resetHostAgent: () => void;
|
||||
/**
|
||||
* 设置sourceAgentId的portId的intent的next_agent_id为nextAgentId
|
||||
*
|
||||
* @deprecated 这是旧版画布的方法,新版为 addAgentIntent
|
||||
*/
|
||||
setAgentIntentNextID: (
|
||||
sourceAgentId?: string,
|
||||
portId?: string,
|
||||
agentId?: string,
|
||||
) => void;
|
||||
addAgentIntent: (sourceAgentId: string, targetAgentId: string) => void;
|
||||
deleteAgentIntent: (sourceAgentId: string, targetAgentId: string) => void;
|
||||
/**
|
||||
* 根据agentId找到当前agent的source的agent,也就是上游agent
|
||||
* 将上游agent中找到某个intent,next_agent_id === agentId。将该intent的next_agent_id清空
|
||||
*/
|
||||
clearEdgesByTargetAgentId: (agentId?: string) => void;
|
||||
updateAgentSkillKnowledgeDatasetInfo: (
|
||||
agentId: string,
|
||||
dataSetInfo: KnowledgeConfig['dataSetInfo'],
|
||||
) => void;
|
||||
updateAgentSkillPluginApis: (
|
||||
agentId: string,
|
||||
pluginApis: Array<PluginApi>,
|
||||
) => void;
|
||||
addAgent2Store: (
|
||||
agentInfo: bot_common.Agent,
|
||||
optionData?: BotOptionData,
|
||||
) => Agent;
|
||||
addAgent: (config: {
|
||||
/** @default AgentType.LLM_Agent */
|
||||
type?: AgentType;
|
||||
position?: IPoint;
|
||||
/** 是否使用struct版本 - 便于写单测即将删除*/
|
||||
structFlag?: boolean;
|
||||
}) => Promise<Agent | undefined>;
|
||||
batchAddBotAgent: (config: {
|
||||
bots: AgentReferenceInfo[];
|
||||
positions: IPoint[];
|
||||
/** 是否使用struct版本 - 便于写单测即将删除*/
|
||||
structFlag?: boolean;
|
||||
}) => Promise<Agent[]>;
|
||||
updateBotNodeInfo: (
|
||||
agents: AgentFromPlayground[],
|
||||
) => Promise<void> | undefined;
|
||||
copyAgent: (agentId: string) => Promise<Agent | undefined>;
|
||||
removeAgentSkillItem: (
|
||||
agentId: string,
|
||||
type: keyof Pick<BotDetailSkill, 'pluginApis' | 'workflows' | 'knowledge'>,
|
||||
apiId?: string,
|
||||
) => void;
|
||||
/**
|
||||
* 清除一条 intent 的 next_id(也就是 edge)
|
||||
*
|
||||
* - Q1:为什么不直接使用 intent id 来找 intent?
|
||||
* - A1:将一条已有的连线拖拽连接到另一个节点时,SDK 会先触发这个 intent 的 addEdge 事件,随后再触发 deleteEdge 事件。
|
||||
* 导致 deleteEdge 事件会通过 intent id 覆盖 addEdge 刚刚更新过的 intent。
|
||||
*
|
||||
* - Q2:那通过 targetAgentId 来找 intent 不够吗,为什么还需要 intent id?
|
||||
* - A2:当同一个节点的两个 intent 都指向同一个目标,这时删除其中一条连线,无法确定删除的是哪条,必须配合 intent id 来判断
|
||||
*
|
||||
* @deprecated 旧版画布的方法,新版为 deleteAgentIntent
|
||||
*/
|
||||
clearIntentNextId: (
|
||||
sourceAgentId: string,
|
||||
targetAgentId: string,
|
||||
intentId: string,
|
||||
) => void;
|
||||
transformDto2Vo: typeof transformDto2Vo;
|
||||
transformVo2Dto: typeof transformVo2Dto;
|
||||
initStore: (botData: GetDraftBotInfoAgwData) => void;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const useMultiAgentStore = create<MultiAgentStore & MultiAgentAction>()(
|
||||
devtools(
|
||||
// eslint-disable-next-line @coze-arch/max-line-per-function
|
||||
subscribeWithSelector((set, get) => ({
|
||||
...getDefaultMultiAgentStore(),
|
||||
setMultiAgent: setterActionFactory<MultiAgentStore>(set),
|
||||
setMultiAgentByImmer: update =>
|
||||
set(produce<MultiAgentStore>(multiAgent => update(multiAgent))),
|
||||
setMultiSheetViewOpen: (state: Partial<MultiSheetViewOpenState>) => {
|
||||
set(s => ({
|
||||
...s,
|
||||
multiSheetViewOpen: {
|
||||
...s.multiSheetViewOpen,
|
||||
...state,
|
||||
},
|
||||
}));
|
||||
},
|
||||
updatedCurrentAgentIdWithConnectStart: () => {
|
||||
const firstAgent = findFirstAgent(get());
|
||||
const newAgentId = firstAgent?.id;
|
||||
useManuallySwitchAgentStore.getState().clearAgentId();
|
||||
if (newAgentId) {
|
||||
set(
|
||||
produce<MultiAgentStore>(state => {
|
||||
state.currentAgentID = newAgentId;
|
||||
}),
|
||||
);
|
||||
}
|
||||
},
|
||||
resetHostAgent: () => {
|
||||
const firstAgentId = findFirstAgentId(get());
|
||||
if (!firstAgentId) {
|
||||
return;
|
||||
}
|
||||
set(
|
||||
produce<MultiAgentStore>(multiAgent => {
|
||||
if (multiAgent.chatModeConfig.type !== MultiAgentSessionType.Host) {
|
||||
return;
|
||||
}
|
||||
multiAgent.chatModeConfig.currentHostId = firstAgentId;
|
||||
}),
|
||||
);
|
||||
},
|
||||
setAgentIntentNextID: (
|
||||
sourceAgentId?: string,
|
||||
portId?: string,
|
||||
agentId?: string,
|
||||
) => {
|
||||
set(
|
||||
produce<MultiAgentStore>(state => {
|
||||
const { agents } = state;
|
||||
const sourceAgent = findTargetAgent(agents, sourceAgentId);
|
||||
if (sourceAgent) {
|
||||
const targetIntent = sourceAgent.intents?.find(
|
||||
item => item.intent_id === portId,
|
||||
);
|
||||
if (targetIntent && agentId) {
|
||||
targetIntent.next_agent_id = agentId;
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
},
|
||||
clearIntentNextId: (
|
||||
sourceAgentId: string,
|
||||
targetAgentId: string,
|
||||
intentId: string,
|
||||
) => {
|
||||
set(
|
||||
produce<MultiAgentStore>(state => {
|
||||
const sourceAgent = findTargetAgent(state.agents, sourceAgentId);
|
||||
const sourceIntent = sourceAgent?.intents?.find(
|
||||
i =>
|
||||
i.next_agent_id === targetAgentId && i.intent_id === intentId,
|
||||
);
|
||||
if (!sourceIntent) {
|
||||
return;
|
||||
}
|
||||
sourceIntent.next_agent_id = undefined;
|
||||
}),
|
||||
);
|
||||
},
|
||||
addAgentIntent: (sourceAgentId, targetAgentId) => {
|
||||
set(
|
||||
produce<MultiAgentStore>(({ agents }) => {
|
||||
const sourceAgent = findTargetAgent(agents, sourceAgentId);
|
||||
if (!sourceAgent) {
|
||||
return;
|
||||
}
|
||||
const newIntent = {
|
||||
intent_id: nanoid(),
|
||||
next_agent_id: targetAgentId,
|
||||
};
|
||||
switch (sourceAgent.agent_type) {
|
||||
case AgentType.Global_Agent:
|
||||
if (sourceAgent.intents?.[0]) {
|
||||
sourceAgent.intents[0].next_agent_id = targetAgentId;
|
||||
} else {
|
||||
sourceAgent.intents = [newIntent];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (sourceAgent.intents) {
|
||||
sourceAgent.intents.push(newIntent);
|
||||
} else {
|
||||
sourceAgent.intents = [newIntent];
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
},
|
||||
deleteAgentIntent: (sourceAgentId, targetAgentId) =>
|
||||
set(
|
||||
produce<MultiAgentStore>(({ agents }) => {
|
||||
const sourceAgent = findTargetAgent(agents, sourceAgentId);
|
||||
if (!sourceAgent) {
|
||||
return;
|
||||
}
|
||||
switch (sourceAgent.agent_type) {
|
||||
case AgentType.Global_Agent:
|
||||
if (sourceAgent.intents?.[0]) {
|
||||
sourceAgent.intents[0].next_agent_id = undefined;
|
||||
} else {
|
||||
sourceAgent.intents = [{ intent_id: nanoid() }];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sourceAgent.intents =
|
||||
sourceAgent.intents?.filter(
|
||||
intent => intent.next_agent_id !== targetAgentId,
|
||||
) || [];
|
||||
}
|
||||
}),
|
||||
),
|
||||
clearEdgesByTargetAgentId: (targetAgentId?: string) => {
|
||||
set(
|
||||
produce<MultiAgentStore>(state => {
|
||||
const { agents } = state;
|
||||
const sourceAgent = findAgentByNextIntentID(agents, targetAgentId);
|
||||
|
||||
if (sourceAgent) {
|
||||
const { intents } = sourceAgent;
|
||||
|
||||
// 执行第一步指令。将上游agent的next_agent_id清空
|
||||
intents?.forEach(item => {
|
||||
if (item.next_agent_id === targetAgentId) {
|
||||
item.next_agent_id = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
}),
|
||||
);
|
||||
},
|
||||
updateAgentSkillKnowledgeDatasetInfo: (agentId, dataSetInfo) => {
|
||||
set(
|
||||
produce<MultiAgentStore>(state => {
|
||||
const findAgent = findTargetAgent(state.agents, agentId);
|
||||
if (findAgent) {
|
||||
findAgent.skills.knowledge.dataSetInfo = dataSetInfo;
|
||||
}
|
||||
}),
|
||||
);
|
||||
},
|
||||
updateAgentSkillPluginApis: (agentId, pluginApis) => {
|
||||
set(
|
||||
produce<MultiAgentStore>(state => {
|
||||
const findAgent = findTargetAgent(state.agents, agentId);
|
||||
if (findAgent) {
|
||||
findAgent.skills.pluginApis =
|
||||
getPluginApisFilterExample(pluginApis);
|
||||
}
|
||||
}),
|
||||
);
|
||||
},
|
||||
addAgent2Store: (
|
||||
agentInfo: bot_common.Agent,
|
||||
optionData?: BotOptionData,
|
||||
) => {
|
||||
const agent = transformDto2Vo.agent(optionData, agentInfo);
|
||||
set(
|
||||
produce<MultiAgentStore>(state => {
|
||||
state.agents.push(agent);
|
||||
}),
|
||||
);
|
||||
return agent;
|
||||
},
|
||||
addAgent: async ({ type = AgentType.LLM_Agent, position }) => {
|
||||
const { botId } = useBotInfoStore.getState();
|
||||
const { getBaseVersion, setCollaborationByImmer } =
|
||||
useCollaborationStore.getState();
|
||||
const createAgentParams = {
|
||||
agent_type: type,
|
||||
bot_id: botId,
|
||||
position,
|
||||
base_commit_version: getBaseVersion(),
|
||||
version_compat: AgentVersionCompat.NewVersion,
|
||||
};
|
||||
const { data, same_with_online, branch } =
|
||||
await PlaygroundApi.CreateAgentV2(createAgentParams);
|
||||
if (!data) {
|
||||
UIToast.error({
|
||||
content: withSlardarIdButton(
|
||||
I18n.t('chatflow_error_create_failed'),
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
setCollaborationByImmer(state => {
|
||||
state.sameWithOnline = same_with_online ?? false;
|
||||
state.branch = branch;
|
||||
});
|
||||
return get().addAgent2Store(data);
|
||||
},
|
||||
batchAddBotAgent: async ({ bots, positions }) => {
|
||||
const spaceId = useSpaceStore.getState().space.id as string;
|
||||
const { botId } = useBotInfoStore.getState();
|
||||
const { getBaseVersion, setCollaborationByImmer } =
|
||||
useCollaborationStore.getState();
|
||||
const { botAgentInfos } = get();
|
||||
const batchCreateAgentParams = {
|
||||
bot_id: botId,
|
||||
agent_type: AgentType.Bot_Agent,
|
||||
position: positions,
|
||||
references: bots,
|
||||
agent_cnt: bots.length,
|
||||
base_commit_version: getBaseVersion(),
|
||||
};
|
||||
const [
|
||||
{ data: agentInfos, same_with_online, branch },
|
||||
{ data: botInfos },
|
||||
] = await Promise.all([
|
||||
PlaygroundApi.BatchCreateAgentV2(batchCreateAgentParams),
|
||||
PlaygroundApi.MGetBotByVersion({
|
||||
space_id: spaceId,
|
||||
bot_versions: bots?.map(e => ({
|
||||
bot_id: e.ReferenceId,
|
||||
version: e.Version,
|
||||
})),
|
||||
}),
|
||||
]);
|
||||
|
||||
if (
|
||||
!Array.isArray(agentInfos) ||
|
||||
agentInfos.length === 0 ||
|
||||
!Array.isArray(botInfos) ||
|
||||
botInfos.length === 0
|
||||
) {
|
||||
UIToast.error({
|
||||
content: withSlardarIdButton(
|
||||
I18n.t('chatflow_error_create_failed'),
|
||||
),
|
||||
});
|
||||
return [] as Agent[];
|
||||
}
|
||||
const botInfosVo = botInfos.map(transformDto2Vo.botNodeInfo);
|
||||
setCollaborationByImmer(store => {
|
||||
store.sameWithOnline = same_with_online ?? false;
|
||||
store.branch = branch;
|
||||
});
|
||||
set(
|
||||
produce<MultiAgentStore>(store => {
|
||||
store.botAgentInfos = uniqWith(
|
||||
[...botAgentInfos, ...botInfosVo],
|
||||
isEqual,
|
||||
);
|
||||
}),
|
||||
);
|
||||
return agentInfos.map(e => {
|
||||
const botInfo = botInfosVo.find(b => b.id === e.reference_id);
|
||||
return get().addAgent2Store({
|
||||
...e,
|
||||
agent_name: botInfo?.name,
|
||||
icon_uri: botInfo?.icon_url,
|
||||
});
|
||||
});
|
||||
},
|
||||
copyAgent: async (agentId: string) => {
|
||||
const { botId } = useBotInfoStore.getState();
|
||||
const { getBaseVersion } = useCollaborationStore.getState();
|
||||
const copyAgentParams = {
|
||||
space_id: useSpaceStore.getState().getSpaceId(),
|
||||
bot_id: botId,
|
||||
base_commit_version: getBaseVersion(),
|
||||
agent_id: agentId,
|
||||
};
|
||||
const { data, bot_option_data = {} } = await PlaygroundApi.CopyAgentV2(
|
||||
copyAgentParams,
|
||||
);
|
||||
if (!data) {
|
||||
UIToast.error({
|
||||
content: withSlardarIdButton(
|
||||
I18n.t('chatflow_error_create_failed'),
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
return get().addAgent2Store(data, bot_option_data);
|
||||
},
|
||||
removeAgentSkillItem: (agentId, type, apiId) => {
|
||||
set(
|
||||
produce<MultiAgentStore>(s => {
|
||||
const findAgent = findTargetAgent(s.agents, agentId);
|
||||
if (findAgent?.skills) {
|
||||
switch (type) {
|
||||
case 'pluginApis': {
|
||||
findAgent.skills.pluginApis =
|
||||
findAgent.skills.pluginApis.filter(
|
||||
item => item.api_id !== apiId,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'workflows': {
|
||||
findAgent.skills.workflows =
|
||||
findAgent.skills.workflows.filter(
|
||||
item => item.workflow_id !== apiId,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'knowledge': {
|
||||
findAgent.skills.knowledge.dataSetList =
|
||||
findAgent.skills.knowledge.dataSetList.filter(
|
||||
item => item.dataset_id !== apiId,
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.warn('[removeAgentSkillItem]: ?');
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
},
|
||||
updateBotNodeInfo: agents => {
|
||||
const { setMultiAgentByImmer } = get();
|
||||
const botAgents = agents.filter(
|
||||
e => e.agent_type === AgentType.Bot_Agent,
|
||||
);
|
||||
if (Array.isArray(botAgents) && botAgents.length > 0) {
|
||||
return SpaceApiV2.MGetBotByVersion({
|
||||
bot_versions: botAgents?.map(e => ({
|
||||
bot_id: e.reference_id,
|
||||
version: e.current_version,
|
||||
})),
|
||||
}).then(botInfos => {
|
||||
setMultiAgentByImmer(s => {
|
||||
s.botAgentInfos = (botInfos.data ?? []).map(
|
||||
transformDto2Vo.botNodeInfo,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
transformDto2Vo,
|
||||
transformVo2Dto,
|
||||
initStore: botData => {
|
||||
const { bot_info: botInfo } = botData;
|
||||
const {
|
||||
transformDto2Vo: transformDto2Vo4Multi,
|
||||
updatedCurrentAgentIdWithConnectStart,
|
||||
updateBotNodeInfo,
|
||||
} = get();
|
||||
|
||||
const {
|
||||
bot_info: { agents, multi_agent_info: multiInfo },
|
||||
bot_option_data: botOpts,
|
||||
} = botData;
|
||||
|
||||
set(
|
||||
transformDto2Vo4Multi.multiAgent({
|
||||
agents,
|
||||
multiInfo,
|
||||
botOpts,
|
||||
}),
|
||||
);
|
||||
const isMultiAgent = botInfo?.bot_mode === BotMode.MultiMode;
|
||||
if (isMultiAgent) {
|
||||
// 设置初始的对话agent id
|
||||
updatedCurrentAgentIdWithConnectStart();
|
||||
// 获取agent节点为子bot的子bot信息,并赋值入store
|
||||
updateBotNodeInfo(botInfo?.agents || []);
|
||||
}
|
||||
},
|
||||
clear: () => {
|
||||
// eslint-disable-next-line max-lines
|
||||
set({ ...getDefaultMultiAgentStore() });
|
||||
},
|
||||
})),
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'botStudio.botDetail.multiAgent',
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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 { nanoid } from 'nanoid';
|
||||
import { omit } from 'lodash-es';
|
||||
import {
|
||||
type Agent as AgentFromPlayground,
|
||||
type BotOptionData,
|
||||
AgentType,
|
||||
type DraftBotApi,
|
||||
type MultiAgentInfo,
|
||||
MultiAgentSessionType,
|
||||
type UpdateAgentV2Request,
|
||||
ReferenceUpdateType,
|
||||
} from '@coze-arch/bot-api/playground_api';
|
||||
import { LineType } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { useModelStore } from '../model';
|
||||
import { useBotSkillStore } from '../bot-skill';
|
||||
import { findFirstAgentId } from '../../utils/find-agent';
|
||||
import type { BotSuggestionConfig } from '../../types/skill';
|
||||
import type { Agent, BotMultiAgent, DraftBotVo } from '../../types/agent';
|
||||
import { DEFAULT_AGENT_BIZ_INFO, DEFAULT_AGENT_DESCRIPTION } from './defaults';
|
||||
export const transformDto2Vo = {
|
||||
agent: (botOpts?: BotOptionData, data?: AgentFromPlayground): Agent => {
|
||||
const { transformDto2Vo: transformDto2Vo4BotSkill } =
|
||||
useBotSkillStore.getState();
|
||||
const { transformDto2Vo: transformDto2Vo4Model } = useModelStore.getState();
|
||||
const model = transformDto2Vo4Model({
|
||||
bot_info: {
|
||||
model_info: data?.model_info,
|
||||
},
|
||||
bot_option_data: botOpts,
|
||||
});
|
||||
|
||||
const prompt = data?.prompt_info?.prompt ?? '';
|
||||
|
||||
const pluginApis = transformDto2Vo4BotSkill.plugin(
|
||||
data?.plugin_info_list,
|
||||
botOpts?.plugin_detail_map,
|
||||
botOpts?.plugin_api_detail_map,
|
||||
);
|
||||
|
||||
const workflows = transformDto2Vo4BotSkill.workflow(
|
||||
data?.workflow_info_list,
|
||||
botOpts?.workflow_detail_map,
|
||||
);
|
||||
const knowledge = transformDto2Vo4BotSkill.knowledge(
|
||||
data?.knowledge,
|
||||
botOpts?.knowledge_detail_map,
|
||||
);
|
||||
|
||||
const devHooks = transformDto2Vo4BotSkill.hookInfo(data?.hook_info);
|
||||
|
||||
return {
|
||||
id: data?.agent_id ?? '',
|
||||
reference_id: data?.reference_id,
|
||||
reference_info_status: data?.reference_info_status,
|
||||
update_type: data?.update_type,
|
||||
agent_type: data?.agent_type,
|
||||
name: data?.agent_name,
|
||||
position: data?.agent_position,
|
||||
model,
|
||||
prompt,
|
||||
description: data?.description || DEFAULT_AGENT_DESCRIPTION(),
|
||||
// 默认的业务状态bizInfo
|
||||
bizInfo: DEFAULT_AGENT_BIZ_INFO(),
|
||||
system_info_all: [],
|
||||
skills: {
|
||||
pluginApis,
|
||||
workflows,
|
||||
knowledge,
|
||||
...(devHooks ? { devHooks } : {}),
|
||||
},
|
||||
current_version: data?.current_version,
|
||||
suggestion: data?.suggest_reply_info as unknown as BotSuggestionConfig,
|
||||
intents: data?.intents || [],
|
||||
jump_config: data?.jump_config || {},
|
||||
...(data?.agent_type === AgentType.Global_Agent && {
|
||||
intents: data.intents?.length
|
||||
? data.intents
|
||||
: [{ intent_id: nanoid() }],
|
||||
}),
|
||||
};
|
||||
},
|
||||
botNodeInfo: (bot: DraftBotApi): DraftBotVo => {
|
||||
const { transformDto2Vo: transformDto2Vo4BotSkill } =
|
||||
useBotSkillStore.getState();
|
||||
return {
|
||||
...bot,
|
||||
work_info: {
|
||||
suggest_reply: transformDto2Vo4BotSkill.suggestionConfig(
|
||||
bot.suggest_reply,
|
||||
true,
|
||||
),
|
||||
},
|
||||
};
|
||||
},
|
||||
multiAgent: ({
|
||||
agents,
|
||||
multiInfo,
|
||||
botOpts,
|
||||
}: {
|
||||
agents?: AgentFromPlayground[];
|
||||
multiInfo?: MultiAgentInfo;
|
||||
botOpts?: BotOptionData;
|
||||
}): BotMultiAgent => {
|
||||
const transformedAgents =
|
||||
agents?.map(item => transformDto2Vo.agent(botOpts, item)) || [];
|
||||
|
||||
const tempEdges = transformedAgents?.flatMap(
|
||||
agent =>
|
||||
agent.intents?.map(intent => ({
|
||||
sourceNodeID: agent.id,
|
||||
targetNodeID: intent.next_agent_id || '',
|
||||
sourcePortID: intent.intent_id,
|
||||
})) || [],
|
||||
);
|
||||
|
||||
return {
|
||||
edges: tempEdges,
|
||||
connector_type: (multiInfo?.connector_type ??
|
||||
LineType.BEZIER) as LineType,
|
||||
agents: transformedAgents,
|
||||
botAgentInfos: [],
|
||||
chatModeConfig:
|
||||
multiInfo?.session_type === MultiAgentSessionType.Host
|
||||
? {
|
||||
type: multiInfo.session_type,
|
||||
currentHostId:
|
||||
findFirstAgentId({
|
||||
agents: transformedAgents,
|
||||
}) || '',
|
||||
}
|
||||
: { type: MultiAgentSessionType.Flow },
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export const transformVo2Dto = {
|
||||
agent: (targetAgent: Agent): Omit<UpdateAgentV2Request, 'bot_id'> => {
|
||||
const { transformVo2Dto: transformVo2Dto4BotSkill } =
|
||||
useBotSkillStore.getState();
|
||||
const { transformVo2Dto: transformVo2Dto4Model } = useModelStore.getState();
|
||||
|
||||
return {
|
||||
...omit(targetAgent, [
|
||||
'skills',
|
||||
'system_info_all',
|
||||
'prompt',
|
||||
'bizInfo',
|
||||
'jump_config',
|
||||
'model',
|
||||
'suggestion',
|
||||
]),
|
||||
|
||||
plugin_info_list: transformVo2Dto4BotSkill.plugin(
|
||||
targetAgent?.skills?.pluginApis,
|
||||
),
|
||||
workflow_info_list: transformVo2Dto4BotSkill.workflow(
|
||||
targetAgent?.skills?.workflows,
|
||||
),
|
||||
knowledge: transformVo2Dto4BotSkill.knowledge(
|
||||
targetAgent?.skills?.knowledge,
|
||||
),
|
||||
suggest_reply_info: transformVo2Dto4BotSkill.suggestionConfig(
|
||||
targetAgent?.suggestion,
|
||||
),
|
||||
hook_info: targetAgent?.skills?.devHooks,
|
||||
model_info: transformVo2Dto4Model(targetAgent?.model),
|
||||
prompt_info: {
|
||||
prompt: targetAgent.prompt,
|
||||
},
|
||||
jump_config: targetAgent.jump_config,
|
||||
|
||||
current_version:
|
||||
targetAgent.update_type === ReferenceUpdateType.AutoUpdate
|
||||
? // 如果当前agent是自动更新,则将current_version置为"0"
|
||||
'0'
|
||||
: targetAgent.current_version,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 TabDisplayItems, TabStatus } from '@coze-arch/idl/developer_api';
|
||||
|
||||
export const DEFAULT_BOT_SKILL_BLOCK_COLLAPSIBLE_STATE =
|
||||
(): TabDisplayItems => ({
|
||||
plugin_tab_status: TabStatus.Default,
|
||||
workflow_tab_status: TabStatus.Default,
|
||||
imageflow_tab_status: TabStatus.Default,
|
||||
knowledge_tab_status: TabStatus.Default,
|
||||
database_tab_status: TabStatus.Default,
|
||||
variable_tab_status: TabStatus.Default,
|
||||
opening_dialog_tab_status: TabStatus.Default,
|
||||
scheduled_task_tab_status: TabStatus.Default,
|
||||
suggestion_tab_status: TabStatus.Default,
|
||||
tts_tab_status: TabStatus.Default,
|
||||
filebox_tab_status: TabStatus.Default,
|
||||
background_image_tab_status: TabStatus.Default,
|
||||
shortcut_tab_status: TabStatus.Default,
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { usePageRuntimeStore, type PageRuntime } from './store';
|
||||
export { DEFAULT_BOT_SKILL_BLOCK_COLLAPSIBLE_STATE } from './defaults';
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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 { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { size } from 'lodash-es';
|
||||
import { produce } from 'immer';
|
||||
import dayjs from 'dayjs';
|
||||
import { type GetDraftBotInfoAgwData } from '@coze-arch/idl/playground_api';
|
||||
import { type BotPageFromEnum } from '@coze-arch/bot-typings/common';
|
||||
import { SpaceApi } from '@coze-arch/bot-space-api';
|
||||
import {
|
||||
type GetDraftBotDisplayInfoResponse,
|
||||
type TabDisplayItems,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
import { DeveloperApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { useBotInfoStore } from '../bot-info';
|
||||
import {
|
||||
type SetterAction,
|
||||
setterActionFactory,
|
||||
} from '../../utils/setter-factory';
|
||||
import { DEFAULT_BOT_SKILL_BLOCK_COLLAPSIBLE_STATE } from './defaults';
|
||||
|
||||
interface SavingInfo {
|
||||
saving: boolean;
|
||||
time: string;
|
||||
debouncing?: boolean;
|
||||
scopeKey?: string;
|
||||
triggerType?: string;
|
||||
}
|
||||
export const getDefaultPageRuntimeStore = (): PageRuntime => ({
|
||||
init: false,
|
||||
isSelf: false,
|
||||
isPreview: false,
|
||||
editable: false,
|
||||
savingInfo: {
|
||||
saving: false,
|
||||
time: dayjs().format('HH:mm:ss'),
|
||||
debouncing: false,
|
||||
scopeKey: '',
|
||||
triggerType: '',
|
||||
},
|
||||
historyVisible: false,
|
||||
botSkillBlockCollapsibleState: {},
|
||||
grabPluginId: '',
|
||||
hasUnpublishChange: false,
|
||||
});
|
||||
|
||||
// bot的编辑器状态控制
|
||||
export interface PageRuntime {
|
||||
/** 初始化 **/
|
||||
init: boolean;
|
||||
/** 当前用户是否是bot的创建者 **/
|
||||
isSelf: boolean;
|
||||
/** 是否是预览状态isPreview = typeof version !== 'undefined'; **/
|
||||
isPreview: boolean;
|
||||
/** 服务端透传 **/
|
||||
editable: boolean;
|
||||
/**控制bot 历史版本展示 **/
|
||||
historyVisible?: boolean;
|
||||
|
||||
/** 记录用户主动展开/收起bot能力模块的状态 **/
|
||||
botSkillBlockCollapsibleState: TabDisplayItems;
|
||||
/** 页面来源 **/
|
||||
pageFrom?: BotPageFromEnum;
|
||||
/** 保存信息 **/
|
||||
savingInfo: SavingInfo;
|
||||
/** 划词插件id, 一个chat-area一个 **/
|
||||
grabPluginId: string;
|
||||
/** 是否有未发布的修改, header头部展示**/
|
||||
hasUnpublishChange: boolean;
|
||||
}
|
||||
|
||||
export type InitStoreData = GetDraftBotInfoAgwData & { customVersion?: string };
|
||||
export interface PageRuntimeAction {
|
||||
setPageRuntimeBotInfo: SetterAction<PageRuntime>;
|
||||
setPageRuntimeByImmer: (update: (state: PageRuntime) => void) => void;
|
||||
getBotSkillBlockCollapsibleState: () => Promise<void>;
|
||||
setBotSkillBlockCollapsibleState: (
|
||||
$params: TabDisplayItems,
|
||||
disableUpdateService?: boolean,
|
||||
) => void;
|
||||
getIsPreview: (version?: string) => boolean;
|
||||
initStore: (data: InitStoreData) => void;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const usePageRuntimeStore = create<PageRuntime & PageRuntimeAction>()(
|
||||
devtools(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
...getDefaultPageRuntimeStore(),
|
||||
setPageRuntimeBotInfo: setterActionFactory<PageRuntime>(set),
|
||||
setPageRuntimeByImmer: update =>
|
||||
set(produce<PageRuntime>(state => update(state))),
|
||||
|
||||
/**
|
||||
* 获取用户主动展开/收起bot能力模块的状态
|
||||
* ⚠️ 仅在首次打开本人 bot 编辑页时调用
|
||||
* @see
|
||||
*/
|
||||
getBotSkillBlockCollapsibleState: async () => {
|
||||
try {
|
||||
const resp: GetDraftBotDisplayInfoResponse =
|
||||
await SpaceApi.GetDraftBotDisplayInfo({
|
||||
bot_id: useBotInfoStore.getState().botId,
|
||||
});
|
||||
const botSkillBlockCollapsibleState =
|
||||
resp.data?.tab_display_info ??
|
||||
DEFAULT_BOT_SKILL_BLOCK_COLLAPSIBLE_STATE();
|
||||
|
||||
set(prevState => ({
|
||||
...prevState,
|
||||
botSkillBlockCollapsibleState,
|
||||
}));
|
||||
} catch (error) {
|
||||
set(prevState => ({
|
||||
...prevState,
|
||||
botSkillBlockCollapsibleState:
|
||||
DEFAULT_BOT_SKILL_BLOCK_COLLAPSIBLE_STATE(),
|
||||
}));
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 存储用户主动展开/收起bot能力模块的状态
|
||||
* ⚠️ 仅限主动操作时记录
|
||||
* @see
|
||||
*/
|
||||
setBotSkillBlockCollapsibleState: (
|
||||
$params: TabDisplayItems,
|
||||
disableUpdateService?: boolean,
|
||||
) => {
|
||||
if (size($params) > 0) {
|
||||
// 记录到本地状态机
|
||||
set({
|
||||
...get(),
|
||||
botSkillBlockCollapsibleState: {
|
||||
...get().botSkillBlockCollapsibleState,
|
||||
...$params,
|
||||
},
|
||||
});
|
||||
|
||||
if (disableUpdateService) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 同步到服务端
|
||||
DeveloperApi.UpdateDraftBotDisplayInfo({
|
||||
bot_id: useBotInfoStore.getState().botId,
|
||||
display_info: { tab_display_info: $params },
|
||||
space_id: useBotInfoStore.getState().space_id,
|
||||
});
|
||||
}
|
||||
},
|
||||
getIsPreview: version => typeof version !== 'undefined',
|
||||
initStore: info => {
|
||||
const { getIsPreview } = get();
|
||||
set({
|
||||
init: true,
|
||||
isPreview: getIsPreview(info?.customVersion),
|
||||
editable: info?.editable,
|
||||
savingInfo: { saving: false, time: dayjs().format('HH:mm:ss') },
|
||||
hasUnpublishChange: Boolean(info.has_unpublished_change),
|
||||
});
|
||||
},
|
||||
clear: () => {
|
||||
set({ ...getDefaultPageRuntimeStore() });
|
||||
},
|
||||
})),
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'botStudio.botDetail.pageRuntime',
|
||||
},
|
||||
),
|
||||
);
|
||||
103
frontend/packages/studio/stores/bot-detail/src/store/persona.ts
Normal file
103
frontend/packages/studio/stores/bot-detail/src/store/persona.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { produce } from 'immer';
|
||||
import {
|
||||
type BotInfoForUpdate,
|
||||
type GetDraftBotInfoAgwData,
|
||||
} from '@coze-arch/bot-api/playground_api';
|
||||
import { type BotPrompt, PromptType } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import {
|
||||
type SetterAction,
|
||||
setterActionFactory,
|
||||
} from '../utils/setter-factory';
|
||||
|
||||
export const getDefaultPersonaStore = (): PersonaStore => ({
|
||||
systemMessage: {
|
||||
data: '',
|
||||
prompt_type: PromptType.SYSTEM,
|
||||
isOptimize: false,
|
||||
record_id: '',
|
||||
},
|
||||
optimizePrompt: '',
|
||||
promptOptimizeUuid: '',
|
||||
promptOptimizeStatus: 'waitForRespond',
|
||||
});
|
||||
|
||||
export interface RequiredBotPrompt extends BotPrompt {
|
||||
prompt_type: PromptType;
|
||||
data: string;
|
||||
isOptimize: boolean;
|
||||
record_id?: string;
|
||||
}
|
||||
|
||||
/** Persona & Prompt 区域 */
|
||||
export interface PersonaStore {
|
||||
systemMessage: RequiredBotPrompt;
|
||||
optimizePrompt: string;
|
||||
promptOptimizeUuid: string;
|
||||
promptOptimizeStatus: 'responding' | 'waitForRespond' | 'endResponse';
|
||||
}
|
||||
|
||||
export interface PersonaAction {
|
||||
setPersona: SetterAction<PersonaStore>;
|
||||
setPersonaByImmer: (update: (state: PersonaStore) => void) => void;
|
||||
transformDto2Vo: (data: GetDraftBotInfoAgwData) => RequiredBotPrompt;
|
||||
transformVo2Dto: (
|
||||
persona: Partial<RequiredBotPrompt>,
|
||||
) => BotInfoForUpdate['prompt_info'];
|
||||
initStore: (botData: GetDraftBotInfoAgwData) => void;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const usePersonaStore = create<PersonaStore & PersonaAction>()(
|
||||
devtools(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
...getDefaultPersonaStore(),
|
||||
setPersona: setterActionFactory<PersonaStore>(set),
|
||||
setPersonaByImmer: update =>
|
||||
set(produce<PersonaStore>(persona => update(persona))),
|
||||
transformDto2Vo: botData =>
|
||||
({
|
||||
data: botData.bot_info?.prompt_info?.prompt ?? '',
|
||||
prompt_type: PromptType.SYSTEM,
|
||||
isOptimize: false,
|
||||
record_id: '',
|
||||
}) as unknown as RequiredBotPrompt,
|
||||
transformVo2Dto: persona =>
|
||||
({
|
||||
prompt: persona?.data || '',
|
||||
}) as unknown as BotInfoForUpdate['prompt_info'],
|
||||
initStore: botData => {
|
||||
const { setPersonaByImmer, transformDto2Vo } = get();
|
||||
botData &&
|
||||
setPersonaByImmer(store => {
|
||||
store.systemMessage = transformDto2Vo(botData);
|
||||
});
|
||||
},
|
||||
clear: () => {
|
||||
set({ ...getDefaultPersonaStore() });
|
||||
},
|
||||
})),
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'botStudio.botDetail.persona',
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import {
|
||||
type BotInfoForUpdate,
|
||||
type GetDraftBotInfoAgwData,
|
||||
type UserQueryCollectConf,
|
||||
} from '@coze-arch/idl/playground_api';
|
||||
|
||||
import {
|
||||
type SetterAction,
|
||||
setterActionFactory,
|
||||
} from '../utils/setter-factory';
|
||||
export interface QueryCollectStore {
|
||||
is_collected: boolean;
|
||||
private_policy: string;
|
||||
}
|
||||
|
||||
export const getDefaultQueryCollectStore = (): QueryCollectStore => ({
|
||||
is_collected: false,
|
||||
private_policy: '',
|
||||
});
|
||||
|
||||
export interface QueryCollectAction {
|
||||
setQueryCollect: SetterAction<QueryCollectStore>;
|
||||
transformDto2Vo: (data: GetDraftBotInfoAgwData) => UserQueryCollectConf;
|
||||
transformVo2Dto: (
|
||||
queryCollectConf: UserQueryCollectConf,
|
||||
) => BotInfoForUpdate['user_query_collect_conf'];
|
||||
initStore: (data: GetDraftBotInfoAgwData) => void;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const useQueryCollectStore = create<
|
||||
QueryCollectStore & QueryCollectAction
|
||||
>()(
|
||||
devtools(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
...getDefaultQueryCollectStore(),
|
||||
setQueryCollect: setterActionFactory<QueryCollectStore>(set),
|
||||
transformDto2Vo: botData => {
|
||||
const data = botData.bot_info?.user_query_collect_conf;
|
||||
return {
|
||||
is_collected: data?.is_collected,
|
||||
private_policy: data?.private_policy,
|
||||
};
|
||||
},
|
||||
transformVo2Dto: info => info,
|
||||
initStore: botData => {
|
||||
const { transformDto2Vo } = get();
|
||||
set(transformDto2Vo(botData));
|
||||
},
|
||||
clear: () => {
|
||||
set({ ...getDefaultQueryCollectStore() });
|
||||
},
|
||||
})),
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'botStudio.botDetail.queryCollect',
|
||||
},
|
||||
),
|
||||
);
|
||||
Reference in New Issue
Block a user